@using DeepDrftModels.DTOs @using DeepDrftPublic.Client.Controls.AudioPlayerBar @using DeepDrftPublic.Client.Layout @using DeepDrftPublic.Client.Services @using DeepDrftPublic.Client.ViewModels @page "/FramePlayer" @layout EmbedLayout @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. } }