SPA playlist transitions for generic (video) type
- Add _ytpLoadSource(hlsUrl, mp4Url) to video-player component:
destroys old HLS instance, creates a new one with the new source,
then plays — browser retains autoplay permission since the <video>
element never leaves the page
- Add _ytpNavOverride hook: playlist overlay can replace navigateNext/
navigatePrev without modifying the component internals
- Add _plOnVideoEnd hook to 'ended' handler so the playlist overlay
can control autoplay/loop behavior independently
- Expose window._ytpHls for HLS instance lifecycle management
- Add hls_url + has_hls to /videos/{video}/player-data JSON endpoint
- Replace generic.blade.php playlist controls with full SPA system
identical in structure to music type: plTransitionTo, plSwapContent,
plAdj, plRender, plHighlight — no page refresh on track change
- Sidebar shows all playlist tracks; current track highlighted in red
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
1 parent
da02425aeb
commit
77e7b950be
3 files changed
+200
-41
No files matched your search
@@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user