@php $audioUrl = route('videos.stream', $video) . '?v=' . $video->updated_at->timestamp; $coverUrl = $video->thumbnail ? route('media.thumbnail', $video->thumbnail) : asset('storage/images/logo.png'); $nextUrl = isset($nextVideo, $playlist) ? route('videos.show', $nextVideo).'?playlist='.$playlist->share_token : null; $prevUrl = isset($previousVideo, $playlist) ? route('videos.show', $previousVideo).'?playlist='.$playlist->share_token : null; // Per-track slide URL map. Key "0" = primary, other keys = audio_track_id. // Slide sharing rule: if a track has no slides, fall back to primary, then to any // other track that has them (Video::slidesForTrack handles the resolution). $slideMap = ['0' => $video->slidesForTrack(null) ->map(fn($s) => route('media.thumbnail', $s->filename))->values()->all()]; foreach ($video->audioTracks as $_t) { $slideMap[(string) $_t->id] = $video->slidesForTrack($_t->id) ->map(fn($s) => route('media.thumbnail', $s->filename))->values()->all(); } // Initial set (primary) β used for first paint before JS runs. $slideUrls = $slideMap['0'] ?? []; // Build all-tracks list: primary first, then extra language tracks (skip extras that duplicate primary language) $primaryLang = $video->language ?? 'default'; $allLangData = \App\Data\Languages::all(); $primaryFlag = $allLangData[$primaryLang]['flag'] ?? null; $allAudioTracks = collect([[ 'id' => 0, 'language' => $primaryLang, 'label' => $video->language ? strtoupper($video->language) : 'Default', 'name' => $video->language ? ($allLangData[$primaryLang]['name'] ?? strtoupper($video->language)) : 'Default', 'flag' => $primaryFlag, 'stream_url' => $audioUrl, 'title' => $video->title, 'description' => $video->description ?? '', 'dl_url' => route('videos.downloadMp3', $video), ]])->concat($video->audioTracks->map(fn($t) => [ 'id' => $t->id, 'language' => $t->language, 'label' => $t->label, 'name' => $allLangData[$t->language]['name'] ?? strtoupper($t->language), 'flag' => $allLangData[$t->language]['flag'] ?? null, 'stream_url' => route('videos.audio-track', ['video' => $video, 'track' => $t->id]) . '?v=' . $t->updated_at->timestamp, 'title' => $t->title ?? '', 'description' => $t->description ?? '', 'dl_url' => route('videos.audio-track', ['video' => $video, 'track' => $t->id]) . '?download=1&v=' . $t->updated_at->timestamp, ])); $hasMultipleTracks = $allAudioTracks->count() > 1; // Synced lyrics, embedded inline (no separate request). Keyed by track id; "0" = primary. // Local mirror only β must not block page render on NAS I/O. $lyricsSvc = app(\App\Services\NasSyncService::class); $inlineLyrics = ['0' => $lyricsSvc->getLocalLyrics($video, null)]; foreach ($video->audioTracks as $lt) { $inlineLyrics[(string) $lt->id] = $lyricsSvc->getLocalLyrics($video, $lt); } $lyricsOwner = \Illuminate\Support\Facades\Auth::id() === $video->user_id; $lyricsAllowed = \App\Models\Setting::get('lyrics_enabled', 'true') === 'true'; @endphp