fix: restore waveform status coherence, drop dead GetGenreSummaries, restore track info tooltip
This commit is contained in:
@@ -120,6 +120,9 @@ else
|
|||||||
live here. *@
|
live here. *@
|
||||||
<MudTh Style="width: 1%; white-space: nowrap;">Profile</MudTh>
|
<MudTh Style="width: 1%; white-space: nowrap;">Profile</MudTh>
|
||||||
<MudTh Style="width: 1%; white-space: nowrap;">High-res</MudTh>
|
<MudTh Style="width: 1%; white-space: nowrap;">High-res</MudTh>
|
||||||
|
@* Info column: per-track EntryKey + OriginalFileName tooltip (migrated
|
||||||
|
from the retired CmsTrackGrid's .cms-track-info monospace block). *@
|
||||||
|
<MudTh Style="width: 1%;"></MudTh>
|
||||||
</HeaderContent>
|
</HeaderContent>
|
||||||
<RowTemplate>
|
<RowTemplate>
|
||||||
<MudTd DataLabel="#">@track.TrackNumber</MudTd>
|
<MudTd DataLabel="#">@track.TrackNumber</MudTd>
|
||||||
@@ -156,6 +159,24 @@ else
|
|||||||
</MudTooltip>
|
</MudTooltip>
|
||||||
}
|
}
|
||||||
</MudTd>
|
</MudTd>
|
||||||
|
@* Per-track info tooltip (restored from the retired CmsTrackGrid's
|
||||||
|
.cms-track-info monospace block): EntryKey + OriginalFileName. *@
|
||||||
|
<MudTd>
|
||||||
|
<MudTooltip Placement="Placement.Left">
|
||||||
|
<TooltipContent>
|
||||||
|
<MudText Typo="Typo.caption" Style="font-family: monospace;">@track.EntryKey</MudText>
|
||||||
|
@if (!string.IsNullOrWhiteSpace(track.OriginalFileName))
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.caption" Style="font-family: monospace;">@track.OriginalFileName</MudText>
|
||||||
|
}
|
||||||
|
</TooltipContent>
|
||||||
|
<ChildContent>
|
||||||
|
<MudIconButton Icon="@Icons.Material.Outlined.Info"
|
||||||
|
Size="Size.Small"
|
||||||
|
Color="Color.Default" />
|
||||||
|
</ChildContent>
|
||||||
|
</MudTooltip>
|
||||||
|
</MudTd>
|
||||||
</RowTemplate>
|
</RowTemplate>
|
||||||
</MudTable>
|
</MudTable>
|
||||||
}
|
}
|
||||||
@@ -171,6 +192,26 @@ else
|
|||||||
[Parameter] public bool IsLoading { get; set; }
|
[Parameter] public bool IsLoading { get; set; }
|
||||||
[Parameter] public EventCallback OnReleasesChanged { get; set; }
|
[Parameter] public EventCallback OnReleasesChanged { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fires after any per-row waveform generate (profile or high-res) succeeds. The parent page
|
||||||
|
/// wires this to its own <c>RefreshWaveformStatusAsync</c> so its missing-count badges stay
|
||||||
|
/// current after an individual-row generate inside an expanded album row.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter] public EventCallback OnWaveformGenerated { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the cached per-track waveform status so the next row expand re-fetches fresh data
|
||||||
|
/// from the API. Called by the parent page after a catalogue-wide bulk run so already-expanded
|
||||||
|
/// rows reflect the new state on the next expand interaction.
|
||||||
|
/// </summary>
|
||||||
|
public Task InvalidateWaveformStatusAsync()
|
||||||
|
{
|
||||||
|
_profileStatus = null;
|
||||||
|
_highResStatus = null;
|
||||||
|
StateHasChanged();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
// Zero or more dedicated, header-labelled special-action columns (Session hero upload, Mix waveform
|
// Zero or more dedicated, header-labelled special-action columns (Session hero upload, Mix waveform
|
||||||
// generate), each rendered as its own header cell + per-row cell between the Tracks and Actions
|
// generate), each rendered as its own header cell + per-row cell between the Tracks and Actions
|
||||||
// columns. The ALL and Cut tabs leave this empty and render exactly as before — only the standard
|
// columns. The ALL and Cut tabs leave this empty and render exactly as before — only the standard
|
||||||
@@ -265,6 +306,7 @@ else
|
|||||||
{
|
{
|
||||||
(_profileStatus ??= new())[track.EntryKey] = true;
|
(_profileStatus ??= new())[track.EntryKey] = true;
|
||||||
Snackbar.Add($"Generated profile for '{track.TrackName}'.", Severity.Success);
|
Snackbar.Add($"Generated profile for '{track.TrackName}'.", Severity.Success);
|
||||||
|
await OnWaveformGenerated.InvokeAsync();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -295,6 +337,7 @@ else
|
|||||||
{
|
{
|
||||||
(_highResStatus ??= new())[track.EntryKey] = true;
|
(_highResStatus ??= new())[track.EntryKey] = true;
|
||||||
Snackbar.Add($"Generated high-res datum for '{track.TrackName}'.", Severity.Success);
|
Snackbar.Add($"Generated high-res datum for '{track.TrackName}'.", Severity.Success);
|
||||||
|
await OnWaveformGenerated.InvokeAsync();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,9 +8,11 @@
|
|||||||
own data load so a host (TrackList today, the 8.A tab strip later) renders it with no parameters and
|
own data load so a host (TrackList today, the 8.A tab strip later) renders it with no parameters and
|
||||||
no VM plumbing. Re-loads on first render and re-fetches after a row mutation so the list stays in
|
no VM plumbing. Re-loads on first render and re-fetches after a row mutation so the list stays in
|
||||||
sync with the catalogue. *@
|
sync with the catalogue. *@
|
||||||
<CmsAlbumBrowser Releases="_releases"
|
<CmsAlbumBrowser @ref="_albumBrowser"
|
||||||
|
Releases="_releases"
|
||||||
IsLoading="_loading"
|
IsLoading="_loading"
|
||||||
OnReleasesChanged="OnGridReleasesChanged" />
|
OnReleasesChanged="OnGridReleasesChanged"
|
||||||
|
OnWaveformGenerated="OnWaveformGenerated" />
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
// Fires after a row mutation (delete) so a host can invalidate sibling caches derived from the same
|
// Fires after a row mutation (delete) so a host can invalidate sibling caches derived from the same
|
||||||
@@ -18,9 +20,23 @@
|
|||||||
// notification, not the data source. Optional: an embed that has no sibling state leaves it unset.
|
// notification, not the data source. Optional: an embed that has no sibling state leaves it unset.
|
||||||
[Parameter] public EventCallback OnReleasesChanged { get; set; }
|
[Parameter] public EventCallback OnReleasesChanged { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forwarded from the inner <see cref="CmsAlbumBrowser"/>: fires after any per-row waveform
|
||||||
|
/// generate succeeds so the parent page can refresh its catalogue-wide missing-count badges.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter] public EventCallback OnWaveformGenerated { get; set; }
|
||||||
|
|
||||||
|
private CmsAlbumBrowser? _albumBrowser;
|
||||||
private IReadOnlyList<ReleaseDto> _releases = Array.Empty<ReleaseDto>();
|
private IReadOnlyList<ReleaseDto> _releases = Array.Empty<ReleaseDto>();
|
||||||
private bool _loading = true;
|
private bool _loading = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the inner grid's cached per-track waveform status so the next row expand re-fetches.
|
||||||
|
/// Called by the parent page after a catalogue-wide bulk run.
|
||||||
|
/// </summary>
|
||||||
|
public Task InvalidateWaveformStatusAsync() =>
|
||||||
|
_albumBrowser?.InvalidateWaveformStatusAsync() ?? Task.CompletedTask;
|
||||||
|
|
||||||
protected override Task OnInitializedAsync() => ReloadAsync();
|
protected override Task OnInitializedAsync() => ReloadAsync();
|
||||||
|
|
||||||
private async Task OnGridReleasesChanged()
|
private async Task OnGridReleasesChanged()
|
||||||
|
|||||||
@@ -6,17 +6,34 @@
|
|||||||
tab carries expand-tracks, delete, the Type chip, and per-row edit identically to the ALL tab — no
|
tab carries expand-tracks, delete, the Type chip, and per-row edit identically to the ALL tab — no
|
||||||
forked grid. Cuts have no medium-specific action, so no SpecialColumns are supplied; the grid renders
|
forked grid. Cuts have no medium-specific action, so no SpecialColumns are supplied; the grid renders
|
||||||
its shared edit/delete only. Embedded as tab content only; no standalone @page route. *@
|
its shared edit/delete only. Embedded as tab content only; no standalone @page route. *@
|
||||||
<CmsAlbumBrowser Releases="Releases"
|
<CmsAlbumBrowser @ref="_albumBrowser"
|
||||||
|
Releases="Releases"
|
||||||
IsLoading="Loading"
|
IsLoading="Loading"
|
||||||
OnReleasesChanged="ReloadAsync" />
|
OnReleasesChanged="ReloadAsync"
|
||||||
|
OnWaveformGenerated="OnWaveformGenerated" />
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
/// <summary>
|
||||||
|
/// Forwarded from the inner <see cref="CmsAlbumBrowser"/>: fires after any per-row waveform
|
||||||
|
/// generate succeeds so the parent page can refresh its catalogue-wide missing-count badges.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter] public EventCallback OnWaveformGenerated { get; set; }
|
||||||
|
|
||||||
|
private CmsAlbumBrowser? _albumBrowser;
|
||||||
|
|
||||||
protected override ReleaseMedium Medium => ReleaseMedium.Cut;
|
protected override ReleaseMedium Medium => ReleaseMedium.Cut;
|
||||||
protected override string MediumNoun => "cuts";
|
protected override string MediumNoun => "cuts";
|
||||||
|
|
||||||
protected override CutRow ToRow(ReleaseDto release) => new() { Release = release };
|
protected override CutRow ToRow(ReleaseDto release) => new() { Release = release };
|
||||||
protected override ReleaseDto ReleaseOf(CutRow row) => row.Release;
|
protected override ReleaseDto ReleaseOf(CutRow row) => row.Release;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the inner grid's cached per-track waveform status so the next row expand re-fetches.
|
||||||
|
/// Called by the parent page after a catalogue-wide bulk run.
|
||||||
|
/// </summary>
|
||||||
|
public Task InvalidateWaveformStatusAsync() =>
|
||||||
|
_albumBrowser?.InvalidateWaveformStatusAsync() ?? Task.CompletedTask;
|
||||||
|
|
||||||
public sealed class CutRow
|
public sealed class CutRow
|
||||||
{
|
{
|
||||||
public required ReleaseDto Release { get; set; }
|
public required ReleaseDto Release { get; set; }
|
||||||
|
|||||||
@@ -41,9 +41,24 @@ else
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter] public bool Embedded { get; set; }
|
[Parameter] public bool Embedded { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forwarded from the inner <see cref="CmsAlbumBrowser"/>: fires after any per-row waveform
|
||||||
|
/// generate succeeds so the parent page can refresh its catalogue-wide missing-count badges.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter] public EventCallback OnWaveformGenerated { get; set; }
|
||||||
|
|
||||||
|
private CmsAlbumBrowser? _albumBrowser;
|
||||||
|
|
||||||
protected override ReleaseMedium Medium => ReleaseMedium.Mix;
|
protected override ReleaseMedium Medium => ReleaseMedium.Mix;
|
||||||
protected override string MediumNoun => "mixes";
|
protected override string MediumNoun => "mixes";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the inner grid's cached per-track waveform status so the next row expand re-fetches.
|
||||||
|
/// Called by the parent page after a catalogue-wide bulk run.
|
||||||
|
/// </summary>
|
||||||
|
public Task InvalidateWaveformStatusAsync() =>
|
||||||
|
_albumBrowser?.InvalidateWaveformStatusAsync() ?? Task.CompletedTask;
|
||||||
|
|
||||||
protected override MixRow ToRow(ReleaseDto release) => new()
|
protected override MixRow ToRow(ReleaseDto release) => new()
|
||||||
{
|
{
|
||||||
Release = release,
|
Release = release,
|
||||||
@@ -56,9 +71,11 @@ else
|
|||||||
// both branches above render the same markup without duplication. The Mix declares one dedicated
|
// both branches above render the same markup without duplication. The Mix declares one dedicated
|
||||||
// "Waveform" special-action column; the grid renders it between Tracks and Actions, handing the cell
|
// "Waveform" special-action column; the grid renders it between Tracks and Actions, handing the cell
|
||||||
// each release, and RowFor recovers the matching MixRow's generate state.
|
// each release, and RowFor recovers the matching MixRow's generate state.
|
||||||
private RenderFragment GridContent => @<CmsAlbumBrowser Releases="Releases"
|
private RenderFragment GridContent => @<CmsAlbumBrowser @ref="_albumBrowser"
|
||||||
|
Releases="Releases"
|
||||||
IsLoading="Loading"
|
IsLoading="Loading"
|
||||||
OnReleasesChanged="ReloadAsync"
|
OnReleasesChanged="ReloadAsync"
|
||||||
|
OnWaveformGenerated="OnWaveformGenerated"
|
||||||
SpecialColumns="_specialColumns" />;
|
SpecialColumns="_specialColumns" />;
|
||||||
|
|
||||||
// Allocated once per component instance in OnInitialized (field initializers cannot reference
|
// Allocated once per component instance in OnInitialized (field initializers cannot reference
|
||||||
|
|||||||
@@ -42,9 +42,24 @@ else
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter] public bool Embedded { get; set; }
|
[Parameter] public bool Embedded { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forwarded from the inner <see cref="CmsAlbumBrowser"/>: fires after any per-row waveform
|
||||||
|
/// generate succeeds so the parent page can refresh its catalogue-wide missing-count badges.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter] public EventCallback OnWaveformGenerated { get; set; }
|
||||||
|
|
||||||
|
private CmsAlbumBrowser? _albumBrowser;
|
||||||
|
|
||||||
protected override ReleaseMedium Medium => ReleaseMedium.Session;
|
protected override ReleaseMedium Medium => ReleaseMedium.Session;
|
||||||
protected override string MediumNoun => "sessions";
|
protected override string MediumNoun => "sessions";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the inner grid's cached per-track waveform status so the next row expand re-fetches.
|
||||||
|
/// Called by the parent page after a catalogue-wide bulk run.
|
||||||
|
/// </summary>
|
||||||
|
public Task InvalidateWaveformStatusAsync() =>
|
||||||
|
_albumBrowser?.InvalidateWaveformStatusAsync() ?? Task.CompletedTask;
|
||||||
|
|
||||||
protected override SessionRow ToRow(ReleaseDto release) => new()
|
protected override SessionRow ToRow(ReleaseDto release) => new()
|
||||||
{
|
{
|
||||||
Release = release,
|
Release = release,
|
||||||
@@ -57,9 +72,11 @@ else
|
|||||||
// both branches above render the same markup without duplication. The Session declares one dedicated
|
// both branches above render the same markup without duplication. The Session declares one dedicated
|
||||||
// "Hero" special-action column; the grid renders it between Tracks and Actions, handing the cell each
|
// "Hero" special-action column; the grid renders it between Tracks and Actions, handing the cell each
|
||||||
// release, and RowFor recovers the matching SessionRow's upload state.
|
// release, and RowFor recovers the matching SessionRow's upload state.
|
||||||
private RenderFragment GridContent => @<CmsAlbumBrowser Releases="Releases"
|
private RenderFragment GridContent => @<CmsAlbumBrowser @ref="_albumBrowser"
|
||||||
|
Releases="Releases"
|
||||||
IsLoading="Loading"
|
IsLoading="Loading"
|
||||||
OnReleasesChanged="ReloadAsync"
|
OnReleasesChanged="ReloadAsync"
|
||||||
|
OnWaveformGenerated="OnWaveformGenerated"
|
||||||
SpecialColumns="_specialColumns" />;
|
SpecialColumns="_specialColumns" />;
|
||||||
|
|
||||||
// Allocated once per component instance in OnInitialized (field initializers cannot reference
|
// Allocated once per component instance in OnInitialized (field initializers cannot reference
|
||||||
|
|||||||
@@ -73,14 +73,23 @@
|
|||||||
<MudTabs Elevation="0" Rounded="true" ApplyEffectsToContainer="true" PanelClass="pt-4"
|
<MudTabs Elevation="0" Rounded="true" ApplyEffectsToContainer="true" PanelClass="pt-4"
|
||||||
@bind-ActivePanelIndex="_activeTabIndex">
|
@bind-ActivePanelIndex="_activeTabIndex">
|
||||||
<MudTabPanel Text="ALL">
|
<MudTabPanel Text="ALL">
|
||||||
<CmsAllReleasesGrid />
|
<CmsAllReleasesGrid @ref="_allGrid"
|
||||||
|
OnWaveformGenerated="RefreshWaveformStatusAsync" />
|
||||||
|
</MudTabPanel>
|
||||||
|
<MudTabPanel Text="@MediumTabLabels[ReleaseMedium.Cut]">
|
||||||
|
<CmsCutBrowser @ref="_cutBrowser"
|
||||||
|
OnWaveformGenerated="RefreshWaveformStatusAsync" />
|
||||||
|
</MudTabPanel>
|
||||||
|
<MudTabPanel Text="@MediumTabLabels[ReleaseMedium.Session]">
|
||||||
|
<CmsSessionBrowser @ref="_sessionBrowser"
|
||||||
|
Embedded="true"
|
||||||
|
OnWaveformGenerated="RefreshWaveformStatusAsync" />
|
||||||
|
</MudTabPanel>
|
||||||
|
<MudTabPanel Text="@MediumTabLabels[ReleaseMedium.Mix]">
|
||||||
|
<CmsMixBrowser @ref="_mixBrowser"
|
||||||
|
Embedded="true"
|
||||||
|
OnWaveformGenerated="RefreshWaveformStatusAsync" />
|
||||||
</MudTabPanel>
|
</MudTabPanel>
|
||||||
@foreach (var medium in Enum.GetValues<ReleaseMedium>())
|
|
||||||
{
|
|
||||||
<MudTabPanel Text="@MediumTabLabels[medium]">
|
|
||||||
@MediumGrid(medium)
|
|
||||||
</MudTabPanel>
|
|
||||||
}
|
|
||||||
</MudTabs>
|
</MudTabs>
|
||||||
</MudContainer>
|
</MudContainer>
|
||||||
|
|
||||||
@@ -104,9 +113,8 @@
|
|||||||
private static string AddTrackHref(ReleaseMedium medium) =>
|
private static string AddTrackHref(ReleaseMedium medium) =>
|
||||||
$"/tracks/upload?medium={medium.ToString().ToLowerInvariant()}";
|
$"/tracks/upload?medium={medium.ToString().ToLowerInvariant()}";
|
||||||
|
|
||||||
// Medium → tab label. The one place medium display text lives for the tab strip; a future medium adds
|
// Medium → tab label. The one place medium display text lives for the tab strip. The ALL tab is
|
||||||
// one entry here and surfaces a tab automatically. The ALL tab is rendered separately (it is not a
|
// rendered separately (it is not a medium). Tabs are explicit markup so @ref captures work.
|
||||||
// medium).
|
|
||||||
private static readonly IReadOnlyDictionary<ReleaseMedium, string> MediumTabLabels =
|
private static readonly IReadOnlyDictionary<ReleaseMedium, string> MediumTabLabels =
|
||||||
new Dictionary<ReleaseMedium, string>
|
new Dictionary<ReleaseMedium, string>
|
||||||
{
|
{
|
||||||
@@ -115,17 +123,14 @@
|
|||||||
[ReleaseMedium.Mix] = "MIXES",
|
[ReleaseMedium.Mix] = "MIXES",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Medium → embedded grid. Each medium's grid is its own component (Cut has no per-row action; Session
|
// @ref handles for the per-tab grids. Used to (a) invalidate their cached per-track waveform status
|
||||||
// carries hero upload; Mix carries waveform generation), so the content dispatch is a per-medium
|
// after a page-level bulk run, and (b) to wire OnWaveformGenerated so per-row generates bubble up
|
||||||
// mapping by nature — but it is a single switch returning a fragment, not a markup fork. The browsers
|
// and refresh the page-level missing-count badges. Tabs are now explicit markup rather than the
|
||||||
// render Embedded so their standalone page chrome (container, title, back button) is suppressed here.
|
// former enum-driven MediumGrid() switch so @ref captures are possible.
|
||||||
private RenderFragment MediumGrid(ReleaseMedium medium) => medium switch
|
private CmsAllReleasesGrid? _allGrid;
|
||||||
{
|
private CmsCutBrowser? _cutBrowser;
|
||||||
ReleaseMedium.Cut => @<CmsCutBrowser />,
|
private CmsSessionBrowser? _sessionBrowser;
|
||||||
ReleaseMedium.Session => @<CmsSessionBrowser Embedded="true" />,
|
private CmsMixBrowser? _mixBrowser;
|
||||||
ReleaseMedium.Mix => @<CmsMixBrowser Embedded="true" />,
|
|
||||||
_ => @<MudText Typo="Typo.body1" Class="mt-4">No grid for this medium.</MudText>
|
|
||||||
};
|
|
||||||
|
|
||||||
// EntryKey → HasProfile / HasHighRes, loaded once on init so the bulk buttons can show accurate missing
|
// EntryKey → HasProfile / HasHighRes, loaded once on init so the bulk buttons can show accurate missing
|
||||||
// counts without depending on any rendered grid. Re-fetched after each bulk run so the counts settle.
|
// counts without depending on any rendered grid. Re-fetched after each bulk run so the counts settle.
|
||||||
@@ -167,6 +172,21 @@
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidates the cached per-track waveform status on all embedded grids so the next row expand
|
||||||
|
// re-fetches fresh data. Called after each catalogue-wide bulk run so already-expanded rows
|
||||||
|
// reflect the new waveform state on the next expand interaction.
|
||||||
|
private async Task InvalidateAllGridsAsync()
|
||||||
|
{
|
||||||
|
var tasks = new[]
|
||||||
|
{
|
||||||
|
_allGrid?.InvalidateWaveformStatusAsync() ?? Task.CompletedTask,
|
||||||
|
_cutBrowser?.InvalidateWaveformStatusAsync() ?? Task.CompletedTask,
|
||||||
|
_sessionBrowser?.InvalidateWaveformStatusAsync() ?? Task.CompletedTask,
|
||||||
|
_mixBrowser?.InvalidateWaveformStatusAsync() ?? Task.CompletedTask,
|
||||||
|
};
|
||||||
|
await Task.WhenAll(tasks);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Backfill every track missing a waveform profile, one request at a time so a large backfill does not
|
/// Backfill every track missing a waveform profile, one request at a time so a large backfill does not
|
||||||
/// flood the API with concurrent WAV decodes. On completion, re-reads the status map so the missing
|
/// flood the API with concurrent WAV decodes. On completion, re-reads the status map so the missing
|
||||||
@@ -206,6 +226,7 @@
|
|||||||
|
|
||||||
_bulkRunning = false;
|
_bulkRunning = false;
|
||||||
await RefreshWaveformStatusAsync();
|
await RefreshWaveformStatusAsync();
|
||||||
|
await InvalidateAllGridsAsync();
|
||||||
|
|
||||||
var succeeded = missing.Count - failures;
|
var succeeded = missing.Count - failures;
|
||||||
if (failures == 0)
|
if (failures == 0)
|
||||||
@@ -257,6 +278,7 @@
|
|||||||
|
|
||||||
_highResBulkRunning = false;
|
_highResBulkRunning = false;
|
||||||
await RefreshWaveformStatusAsync();
|
await RefreshWaveformStatusAsync();
|
||||||
|
await InvalidateAllGridsAsync();
|
||||||
|
|
||||||
var succeeded = missing.Count - failures;
|
var succeeded = missing.Count - failures;
|
||||||
if (failures == 0)
|
if (failures == 0)
|
||||||
|
|||||||
@@ -661,50 +661,6 @@ public class CmsTrackService : ICmsTrackService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ResultContainer<List<GenreSummaryDto>>> GetGenreSummariesAsync(CancellationToken ct = default)
|
|
||||||
{
|
|
||||||
var client = _httpClientFactory.CreateClient(ContentCmsClientName);
|
|
||||||
|
|
||||||
HttpResponseMessage response;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
response = await client.GetAsync("api/track/genres", ct);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Content API call failed for genre summaries");
|
|
||||||
return ResultContainer<List<GenreSummaryDto>>.CreateFailResult("Content API is unreachable.");
|
|
||||||
}
|
|
||||||
|
|
||||||
using (response)
|
|
||||||
{
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
_logger.LogError("Content API genre summaries failed: {Status}", (int)response.StatusCode);
|
|
||||||
return ResultContainer<List<GenreSummaryDto>>.CreateFailResult("Failed to load genres.");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<GenreSummaryDto>? genres;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
genres = await response.Content.ReadFromJsonAsync<List<GenreSummaryDto>>(ct);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Failed to deserialize genre summaries from Content API response");
|
|
||||||
return ResultContainer<List<GenreSummaryDto>>.CreateFailResult("Content API returned an unexpected response.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (genres is null)
|
|
||||||
{
|
|
||||||
_logger.LogError("Content API returned a null genre summaries list");
|
|
||||||
return ResultContainer<List<GenreSummaryDto>>.CreateFailResult("Content API returned an empty response.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultContainer<List<GenreSummaryDto>>.CreatePassResult(genres);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ResultContainer<int>> GetTrackCountAsync(CancellationToken ct = default)
|
public async Task<ResultContainer<int>> GetTrackCountAsync(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// Re-use the paged endpoint: a single-item page carries the full TotalCount, so no
|
// Re-use the paged endpoint: a single-item page carries the full TotalCount, so no
|
||||||
|
|||||||
@@ -122,9 +122,6 @@ public interface ICmsTrackService
|
|||||||
/// <summary>Returns all releases with track counts from GET api/track/albums.</summary>
|
/// <summary>Returns all releases with track counts from GET api/track/albums.</summary>
|
||||||
Task<ResultContainer<List<ReleaseDto>>> GetReleasesAsync(CancellationToken ct = default);
|
Task<ResultContainer<List<ReleaseDto>>> GetReleasesAsync(CancellationToken ct = default);
|
||||||
|
|
||||||
/// <summary>Returns all distinct genres with track counts from GET api/track/genres.</summary>
|
|
||||||
Task<ResultContainer<List<GenreSummaryDto>>> GetGenreSummariesAsync(CancellationToken ct = default);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the total track count by calling GET api/track/page with pageSize=1 and reading TotalCount.
|
/// Returns the total track count by calling GET api/track/page with pageSize=1 and reading TotalCount.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user