From da02425aeb77dc3fbc149835bfa33833e57eb3c8 Mon Sep 17 00:00:00 2001 From: ghassan Date: Sat, 16 May 2026 12:12:22 +0300 Subject: [PATCH] =?UTF-8?q?SPA=20playlist=20transitions=20=E2=80=94=20no?= =?UTF-8?q?=20page=20refresh=20on=20track=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add GET /videos/{video}/player-data JSON endpoint returning stream URL, cover, slides, title, duration (used by client-side SPA transitions) - Replace music playlist JS with full SPA system: plTransitionTo() swaps audio.src in-place (preserving browser autoplay permission), updates cover art, resets progress bar, then background-fetches the new page to swap #vdbWrap (description) and #ytcSection (comments) via DOMParser - plSwapContent() re-runs the YTC comments IIFE after swapping innerHTML so comments load correctly for the new video - Prev/next/shuffle/loop/autoplay controls now computed dynamically from PL_VIDEOS array — buttons stay correct after each SPA transition - Sidebar shows ALL playlist tracks (removed @if filter); current track highlighted in red; clicking any card triggers SPA transition - Browser back/forward handled via popstate + history.pushState Co-Authored-By: Claude Sonnet 4.6 --- app/Http/Controllers/VideoController.php | 27 +++ resources/views/videos/types/music.blade.php | 206 ++++++++++++++----- routes/web.php | 1 + 3 files changed, 186 insertions(+), 48 deletions(-) diff --git a/app/Http/Controllers/VideoController.php b/app/Http/Controllers/VideoController.php index d85a98a..fc2f129 100644 --- a/app/Http/Controllers/VideoController.php +++ b/app/Http/Controllers/VideoController.php @@ -465,6 +465,33 @@ class VideoController extends Controller ->withCookie(cookie('_did', $did, 60 * 24 * 365 * 5)); } + public function playerData(Video $video, Request $request) + { + if (! $video->canView(Auth::user())) { + abort(403); + } + + $coverUrl = $video->thumbnail + ? route('media.thumbnail', $video->thumbnail) + : asset('storage/images/logo.png'); + + $slides = $video->slides->count() > 1 + ? $video->slides->map(fn ($s) => route('media.thumbnail', $s->filename))->values()->all() + : []; + + return response()->json([ + 'id' => $video->id, + 'key' => $video->getRouteKey(), + 'type' => $video->type, + 'stream_url' => route('videos.stream', $video), + 'cover_url' => $coverUrl, + 'slides' => $slides, + 'title' => $video->title, + 'author' => $video->user->name ?? '', + 'duration' => $video->duration, + ]); + } + public function matchData(Video $video) { if (! $video->canView(Auth::user())) { diff --git a/resources/views/videos/types/music.blade.php b/resources/views/videos/types/music.blade.php index 8527aa3..2144ca1 100644 --- a/resources/views/videos/types/music.blade.php +++ b/resources/views/videos/types/music.blade.php @@ -299,6 +299,14 @@ gap: 8px; margin-bottom: 8px; cursor: pointer; + border-radius: 8px; + padding: 4px; + transition: background .15s; + } + + .sidebar-video-card.current-video { + background: rgba(239,68,68,.12); + border-left: 3px solid #ef4444; } .sidebar-thumb { @@ -479,12 +487,10 @@ {{-- Playlist controls --}}
- -
@@ -502,49 +508,142 @@