6e25ad3085
GET api/track/waveform-status and POST api/track/{id}/waveform (ApiKey);
CmsTrackService methods; TrackPreProcessing page with per-row and
sequential bulk generation; nav links from TrackList and Index.
136 lines
4.1 KiB
C#
136 lines
4.1 KiB
C#
using DeepDrftManager.Services;
|
|
using DeepDrftModels.DTOs;
|
|
using Microsoft.AspNetCore.Components;
|
|
using MudBlazor;
|
|
|
|
namespace DeepDrftManager.Components.Pages.Tracks;
|
|
|
|
public partial class TrackPreProcessing : ComponentBase
|
|
{
|
|
private List<WaveformStatusDto> _rows = new();
|
|
private readonly HashSet<string> _generating = new();
|
|
private bool _loading = true;
|
|
private bool _bulkRunning;
|
|
private int _bulkTotal;
|
|
private int _bulkDone;
|
|
|
|
private int _missingCount => _rows.Count(r => !r.HasProfile);
|
|
|
|
[Inject] private ICmsTrackService CmsTrackService { get; set; } = default!;
|
|
[Inject] private ISnackbar Snackbar { get; set; } = default!;
|
|
[Inject] private ILogger<TrackPreProcessing> Logger { get; set; } = default!;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await LoadStatus();
|
|
}
|
|
|
|
private async Task LoadStatus()
|
|
{
|
|
_loading = true;
|
|
var result = await CmsTrackService.GetWaveformStatusAsync();
|
|
_loading = false;
|
|
|
|
if (!result.Success || result.Value is null)
|
|
{
|
|
var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error";
|
|
Snackbar.Add($"Failed to load waveform status: {error}", Severity.Error);
|
|
_rows = new List<WaveformStatusDto>();
|
|
return;
|
|
}
|
|
|
|
_rows = result.Value.OrderBy(r => r.HasProfile).ThenBy(r => r.TrackName).ToList();
|
|
}
|
|
|
|
private bool IsGenerating(string entryKey) => _generating.Contains(entryKey);
|
|
|
|
private async Task GenerateOne(WaveformStatusDto row)
|
|
{
|
|
if (!await GenerateForRow(row))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Snackbar.Add($"Generated profile for '{row.TrackName}'.", Severity.Success);
|
|
}
|
|
|
|
private async Task GenerateAllMissing()
|
|
{
|
|
var missing = _rows.Where(r => !r.HasProfile).ToList();
|
|
if (missing.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_bulkRunning = true;
|
|
_bulkTotal = missing.Count;
|
|
_bulkDone = 0;
|
|
var failures = 0;
|
|
|
|
// Sequential by design: one request at a time so a large backfill does not flood the API
|
|
// with concurrent WAV decodes.
|
|
foreach (var row in missing)
|
|
{
|
|
if (!await GenerateForRow(row))
|
|
{
|
|
failures++;
|
|
}
|
|
_bulkDone++;
|
|
StateHasChanged();
|
|
}
|
|
|
|
_bulkRunning = false;
|
|
|
|
var succeeded = missing.Count - failures;
|
|
if (failures == 0)
|
|
{
|
|
Snackbar.Add($"Generated {succeeded} profile(s).", Severity.Success);
|
|
}
|
|
else
|
|
{
|
|
Snackbar.Add($"Generated {succeeded} profile(s); {failures} failed.", Severity.Warning);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runs generation for a single row, flipping its status on success. Returns false on failure
|
|
/// (a snackbar is raised here for the per-row path; the bulk path aggregates a summary). Marks
|
|
/// the row busy for the duration so its button shows a spinner and stays disabled.
|
|
/// </summary>
|
|
private async Task<bool> GenerateForRow(WaveformStatusDto row)
|
|
{
|
|
_generating.Add(row.EntryKey);
|
|
StateHasChanged();
|
|
try
|
|
{
|
|
var result = await CmsTrackService.GenerateWaveformProfileAsync(row.EntryKey);
|
|
if (result.Success)
|
|
{
|
|
row.HasProfile = true;
|
|
return true;
|
|
}
|
|
|
|
var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error";
|
|
if (!_bulkRunning)
|
|
{
|
|
Snackbar.Add($"Generate failed for '{row.TrackName}': {error}", Severity.Error);
|
|
}
|
|
return false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex, "Waveform generation failed for {EntryKey}", row.EntryKey);
|
|
if (!_bulkRunning)
|
|
{
|
|
Snackbar.Add($"Generate failed for '{row.TrackName}' — please try again.", Severity.Error);
|
|
}
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
_generating.Remove(row.EntryKey);
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
}
|