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 @@