a19a734757
Add GET api/track/{trackEntryKey}/waveform/high-res (+ proxy), ITrackDataService.GetTrackWaveform; rewire visualizer to resolve the current track's EntryKey and re-fetch on track change. Retire the client mix-waveform read path.
176 lines
6.6 KiB
C#
176 lines
6.6 KiB
C#
using DeepDrftModels.DTOs;
|
|
using Models.Common;
|
|
using NetBlocks.Models;
|
|
using System.Text.Json;
|
|
using System.Web;
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
namespace DeepDrftPublic.Client.Clients;
|
|
|
|
public class TrackClient
|
|
{
|
|
private readonly HttpClient _http;
|
|
|
|
public TrackClient(IHttpClientFactory httpClientFactory)
|
|
{
|
|
_http = httpClientFactory.CreateClient("DeepDrft.API");
|
|
}
|
|
|
|
public async Task<ApiResult<PagedResult<TrackDto>>> GetPage(
|
|
int pageNumber,
|
|
int pageSize,
|
|
string? sortColumn = null,
|
|
bool sortDescending = false,
|
|
string? searchText = null,
|
|
string? album = null,
|
|
string? genre = null,
|
|
long? releaseId = null)
|
|
{
|
|
var queryArgs = new Dictionary<string, string?>(){
|
|
["page"] = pageNumber.ToString(),
|
|
["pageSize"] = pageSize.ToString()
|
|
};
|
|
|
|
if (!string.IsNullOrEmpty(sortColumn))
|
|
queryArgs["sortColumn"] = sortColumn;
|
|
|
|
if (sortDescending)
|
|
queryArgs["sortDescending"] = "true";
|
|
|
|
if (!string.IsNullOrEmpty(searchText))
|
|
queryArgs["q"] = searchText;
|
|
|
|
if (!string.IsNullOrEmpty(album))
|
|
queryArgs["album"] = album;
|
|
|
|
if (!string.IsNullOrEmpty(genre))
|
|
queryArgs["genre"] = genre;
|
|
|
|
if (releaseId is { } id)
|
|
queryArgs["releaseId"] = id.ToString();
|
|
|
|
string query = QueryString.Create(queryArgs).ToString();
|
|
|
|
var response = await _http.GetAsync($"api/track/page{query}");
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
return ApiResult<PagedResult<TrackDto>>.CreateFailResult($"HTTP {(int)response.StatusCode}");
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var paged = JsonSerializer.Deserialize<PagedResult<TrackDto>>(json, new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
});
|
|
|
|
return paged is not null
|
|
? ApiResult<PagedResult<TrackDto>>.CreatePassResult(paged)
|
|
: ApiResult<PagedResult<TrackDto>>.CreateFailResult("Failed to deserialize response");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches a random track from the public library. A 404 means the library is empty — a valid
|
|
/// state, not an error — so it returns a pass result with a null value. Any other non-success
|
|
/// status is a genuine failure.
|
|
/// </summary>
|
|
public async Task<ApiResult<TrackDto?>> GetRandom()
|
|
{
|
|
var response = await _http.GetAsync("api/track/random");
|
|
|
|
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
return ApiResult<TrackDto?>.CreatePassResult(null);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
return ApiResult<TrackDto?>.CreateFailResult($"HTTP {(int)response.StatusCode}");
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var track = JsonSerializer.Deserialize<TrackDto>(json, new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
});
|
|
|
|
return track is not null
|
|
? ApiResult<TrackDto?>.CreatePassResult(track)
|
|
: ApiResult<TrackDto?>.CreateFailResult("Failed to deserialize response");
|
|
}
|
|
|
|
public async Task<ApiResult<List<ReleaseDto>>> GetAlbums()
|
|
{
|
|
var response = await _http.GetAsync("api/track/albums");
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
return ApiResult<List<ReleaseDto>>.CreateFailResult($"HTTP {(int)response.StatusCode}");
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var releases = JsonSerializer.Deserialize<List<ReleaseDto>>(json, new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
});
|
|
|
|
return releases is not null
|
|
? ApiResult<List<ReleaseDto>>.CreatePassResult(releases)
|
|
: ApiResult<List<ReleaseDto>>.CreateFailResult("Failed to deserialize response");
|
|
}
|
|
|
|
public async Task<ApiResult<List<GenreSummaryDto>>> GetGenres()
|
|
{
|
|
var response = await _http.GetAsync("api/track/genres");
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
return ApiResult<List<GenreSummaryDto>>.CreateFailResult($"HTTP {(int)response.StatusCode}");
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var genres = JsonSerializer.Deserialize<List<GenreSummaryDto>>(json, new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
});
|
|
|
|
return genres is not null
|
|
? ApiResult<List<GenreSummaryDto>>.CreatePassResult(genres)
|
|
: ApiResult<List<GenreSummaryDto>>.CreateFailResult("Failed to deserialize response");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the per-track high-res waveform datum, addressed by the track's EntryKey (phase-12 §5b).
|
|
/// A 404 means no high-res datum is stored (a track not yet backfilled) — a valid state, so it
|
|
/// returns a pass result with a null value and the visualizer blanks gracefully. Any other
|
|
/// non-success status is a genuine failure.
|
|
/// </summary>
|
|
public async Task<ApiResult<WaveformProfileDto?>> GetTrackWaveform(string trackEntryKey)
|
|
{
|
|
var response = await _http.GetAsync($"api/track/{Uri.EscapeDataString(trackEntryKey)}/waveform/high-res");
|
|
|
|
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
return ApiResult<WaveformProfileDto?>.CreatePassResult(null);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
return ApiResult<WaveformProfileDto?>.CreateFailResult($"HTTP {(int)response.StatusCode}");
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var profile = JsonSerializer.Deserialize<WaveformProfileDto>(json, new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
});
|
|
|
|
return profile is not null
|
|
? ApiResult<WaveformProfileDto?>.CreatePassResult(profile)
|
|
: ApiResult<WaveformProfileDto?>.CreateFailResult("Failed to deserialize response");
|
|
}
|
|
|
|
public async Task<ApiResult<TrackDto>> GetTrack(string entryKey)
|
|
{
|
|
var response = await _http.GetAsync($"api/track/meta/by-key/{Uri.EscapeDataString(entryKey)}");
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
return ApiResult<TrackDto>.CreateFailResult($"HTTP {(int)response.StatusCode}");
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var track = JsonSerializer.Deserialize<TrackDto>(json, new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
});
|
|
|
|
return track is not null
|
|
? ApiResult<TrackDto>.CreatePassResult(track)
|
|
: ApiResult<TrackDto>.CreateFailResult("Failed to deserialize response");
|
|
}
|
|
} |