912256d99a
The queue gains an armed-but-idle state (Arm/Start) so a release embed stages track 0 prerender-safe, then queues the full release on first play and auto-advances.
76 lines
3.1 KiB
Plaintext
76 lines
3.1 KiB
Plaintext
@using DeepDrftModels.DTOs
|
|
@using DeepDrftPublic.Client.Controls.AudioPlayerBar
|
|
@using DeepDrftPublic.Client.Layout
|
|
@using DeepDrftPublic.Client.Services
|
|
@using DeepDrftPublic.Client.ViewModels
|
|
|
|
@page "/FramePlayer"
|
|
@layout EmbedLayout
|
|
|
|
<AudioPlayerBar Fixed />
|
|
|
|
@code {
|
|
[CascadingParameter] public IStreamingPlayerService? PlayerService { get; set; }
|
|
[CascadingParameter] public IQueueService? Queue { get; set; }
|
|
|
|
// Two mutually-exclusive embed targets. ReleaseEntryKey wins if both are somehow supplied — a
|
|
// release embed is the richer surface, and the single-track path would otherwise mask it.
|
|
[SupplyParameterFromQuery] public string? ReleaseEntryKey { get; set; }
|
|
[SupplyParameterFromQuery] public string? TrackEntryKey { get; set; }
|
|
|
|
[Inject] public required ITrackDataService TrackDataService { get; set; }
|
|
[Inject] public required FramePlayerViewModel ViewModel { get; set; }
|
|
|
|
private string? _stagedKey;
|
|
|
|
protected override async Task OnParametersSetAsync()
|
|
{
|
|
if (PlayerService is null) return;
|
|
|
|
if (!string.IsNullOrWhiteSpace(ReleaseEntryKey))
|
|
{
|
|
await StageRelease(ReleaseEntryKey);
|
|
}
|
|
else if (!string.IsNullOrWhiteSpace(TrackEntryKey))
|
|
{
|
|
await StageSingleTrack(TrackEntryKey);
|
|
}
|
|
}
|
|
|
|
// Release embed: resolve the release's ordered tracks, stage the first so the bar shows the release
|
|
// ready, and arm the queue with the whole list. No JS interop here (StageTrack and Arm are both
|
|
// interop-free), so this runs identically during prerender and after WASM boot. The first play
|
|
// click (handled in AudioPlayerBar) routes through Queue.PlayRelease, queueing the full release.
|
|
private async Task StageRelease(string releaseEntryKey)
|
|
{
|
|
// OnParametersSetAsync can fire repeatedly; only act when the key actually changes.
|
|
if (releaseEntryKey == _stagedKey) return;
|
|
_stagedKey = releaseEntryKey;
|
|
|
|
await ViewModel.Load(releaseEntryKey);
|
|
if (ViewModel.Tracks.Count == 0) return; // No tracks: leave the bar idle.
|
|
|
|
await PlayerService!.StageTrack(ViewModel.Tracks[0]);
|
|
Queue?.Arm(ViewModel.Tracks);
|
|
}
|
|
|
|
// Single-track embed: unchanged behaviour — stage exactly the requested track. The first play
|
|
// click streams it directly (the queue stays empty/disarmed).
|
|
private async Task StageSingleTrack(string trackEntryKey)
|
|
{
|
|
if (trackEntryKey == _stagedKey) return;
|
|
_stagedKey = trackEntryKey;
|
|
|
|
var result = await TrackDataService.GetTrack(trackEntryKey);
|
|
if (result.Success && result.Value is not null)
|
|
{
|
|
// Stage only — no audio context, no streaming. The browser blocks audio until a user
|
|
// gesture, so the embed shows the track ready and the first play click calls
|
|
// SelectTrackStreaming. This keeps this pass free of JS interop, so it works whether it
|
|
// runs during prerender or after WASM is interactive.
|
|
await PlayerService!.StageTrack(result.Value);
|
|
}
|
|
// On failure, leave the bar idle; a stream-level error surfaces via PlayerService.ErrorMessage.
|
|
}
|
|
}
|