diff --git a/app/Http/Controllers/VideoController.php b/app/Http/Controllers/VideoController.php index fc2f129..211707c 100644 --- a/app/Http/Controllers/VideoController.php +++ b/app/Http/Controllers/VideoController.php @@ -483,6 +483,8 @@ class VideoController extends Controller 'id' => $video->id, 'key' => $video->getRouteKey(), 'type' => $video->type, + 'has_hls' => (bool) $video->has_hls, + 'hls_url' => $video->has_hls ? route('videos.hls', ['video' => $video, 'file' => 'master.m3u8']) : null, 'stream_url' => route('videos.stream', $video), 'cover_url' => $coverUrl, 'slides' => $slides, diff --git a/resources/views/components/video-player.blade.php b/resources/views/components/video-player.blade.php index db4c46b..ecf6d0d 100644 --- a/resources/views/components/video-player.blade.php +++ b/resources/views/components/video-player.blade.php @@ -806,18 +806,38 @@ function getShuffledPrevUrl() { return vids[order[posPrev]]?.showUrl ?? PREV_URL; } +window._ytpHls = null; + function initSource() { if (HLS_URL && window.Hls && Hls.isSupported()) { - const hls = new Hls({ startLevel: -1 }); - hls.loadSource(HLS_URL); - hls.attachMedia(video); + window._ytpHls = new Hls({ startLevel: -1 }); + window._ytpHls.loadSource(HLS_URL); + window._ytpHls.attachMedia(video); } else if (HLS_URL && video.canPlayType('application/vnd.apple.mpegurl')) { - video.src = HLS_URL; // Safari native HLS + video.src = HLS_URL; } else { video.src = MP4_URL; } } +// Reinitialize source after SPA transition — called by playlist overlay scripts +window._ytpLoadSource = function(hlsUrl, mp4Url) { + if (window._ytpHls) { window._ytpHls.destroy(); window._ytpHls = null; } + if (hlsUrl && window.Hls && Hls.isSupported()) { + window._ytpHls = new Hls({ startLevel: -1 }); + window._ytpHls.loadSource(hlsUrl); + window._ytpHls.attachMedia(video); + } else if (hlsUrl && video.canPlayType('application/vnd.apple.mpegurl')) { + video.src = hlsUrl; + video.load(); + } else { + video.src = mp4Url; + video.load(); + } + video.muted = false; + video.play().catch(function(){}); +}; + // Load HLS.js from CDN then init function loadHlsJs(cb) { if (window.Hls) { cb(); return; } @@ -1169,10 +1189,12 @@ video.addEventListener('playing', () => spinner.classList.remove('active')); video.addEventListener('canplay', () => spinner.classList.remove('active')); function navigateNext() { const url = shuffleOn ? getShuffledNextUrl() : NEXT_URL; + if (window._ytpNavOverride?.next) { window._ytpNavOverride.next(url); return; } if (url) window.location.href = url; } function navigatePrev() { const url = shuffleOn ? getShuffledPrevUrl() : PREV_URL; + if (window._ytpNavOverride?.prev) { window._ytpNavOverride.prev(url); return; } if (url) window.location.href = url; } window._ytpNav = { next: navigateNext, prev: navigatePrev }; @@ -1182,7 +1204,9 @@ video.addEventListener('ended', () => { largePlay.classList.add('visible'); clearTimeout(hideTimer); releaseWakeLock(); - if (autoplayOn || isLooping) { + if (window._plOnVideoEnd) { + window._plOnVideoEnd(); + } else if (autoplayOn || isLooping) { navigateNext(); } }); diff --git a/resources/views/videos/types/generic.blade.php b/resources/views/videos/types/generic.blade.php index 2746ecd..98b4338 100644 --- a/resources/views/videos/types/generic.blade.php +++ b/resources/views/videos/types/generic.blade.php @@ -253,6 +253,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 { @@ -428,15 +436,6 @@ -
@@ -451,52 +450,187 @@ {{-- Playlist controls --}}
- -
- - -