Add auto-advance to next media by default

- Videos/audio: auto-advance when media ends
- Images: auto-advance after 60 seconds
- PDFs: auto-advance after 60 seconds, cancelled if user scrolls
- Detect scroll via wheel/scroll events to cancel auto-advance
- Works in PiP mode, pop-out player, and floating audio player
- Seamless playlist-like experience through all media in shop
This commit is contained in:
russell@unturf.com 2026-01-21 10:56:17 -05:00
parent f0b23ec0ff
commit 2dc817e3d1
3 changed files with 98 additions and 1 deletions

View file

@ -8,9 +8,11 @@
// State management
let focusInterval = null;
let autoAdvanceTimer = null;
const loadTime = Date.now();
const EXPIRATION_TIME = 900000; // 15 minutes in ms
const WARNING_TIME = 780000; // 13 minutes (warn 2 min before expiration)
const AUTO_ADVANCE_DELAY = 60000; // 60 seconds for images/PDFs
// Get media element
const media = document.getElementById('media');
@ -190,6 +192,36 @@
}
}
/**
* Start auto-advance timer for images and PDFs
*/
function startAutoAdvance() {
// Clear any existing timer
stopAutoAdvance();
// Only auto-advance if there's a next product
if (!window.playerData || !window.playerData.nextProductId) {
return;
}
// Set timer to advance after delay
autoAdvanceTimer = setTimeout(() => {
if (window.playerData && window.playerData.nextProductId) {
navigate(window.playerData.nextProductId);
}
}, AUTO_ADVANCE_DELAY);
}
/**
* Stop auto-advance timer
*/
function stopAutoAdvance() {
if (autoAdvanceTimer) {
clearTimeout(autoAdvanceTimer);
autoAdvanceTimer = null;
}
}
/**
* Resize window to match media aspect ratio
*/
@ -360,6 +392,17 @@
// Set up keyboard event listener
document.addEventListener('keydown', handleKeydown);
// Cancel auto-advance on scroll (user is reading the PDF)
document.addEventListener('wheel', () => {
// User is scrolling, they're reading, cancel auto-advance
stopAutoAdvance();
});
// Cancel auto-advance on scroll events
window.addEventListener('scroll', () => {
stopAutoAdvance();
});
// Set up fullscreen change listener
document.addEventListener('fullscreenchange', updateFullscreenButton);
@ -373,10 +416,36 @@
// Update play/pause button when media state changes
media.addEventListener('play', updatePlayPauseButton);
media.addEventListener('pause', updatePlayPauseButton);
// Auto-advance when video/audio ends
media.addEventListener('ended', () => {
if (window.playerData && window.playerData.nextProductId) {
navigate(window.playerData.nextProductId);
}
});
// Initial update
updatePlayPauseButton();
} else if (media.tagName === 'IMG') {
media.addEventListener('load', resizeWindowToMedia);
media.addEventListener('load', () => {
resizeWindowToMedia();
// Auto-advance after 60 seconds for images
startAutoAdvance();
});
} else if (media.tagName === 'IFRAME') {
// For PDFs
resizeWindowToMedia();
// Auto-advance after 60 seconds for PDFs
startAutoAdvance();
// Try to detect scrolling in iframe (may not work due to CORS)
try {
media.contentWindow.addEventListener('scroll', () => {
// User scrolled the PDF, cancel auto-advance
stopAutoAdvance();
});
} catch (err) {
// CORS blocked, can't detect scroll
console.log('Cannot detect PDF scroll due to CORS');
}
}
}

View file

@ -185,6 +185,13 @@ async function openMediaPlayer(productId) {
await media.play();
await media.requestPictureInPicture();
// Auto-advance when video ends
media.addEventListener('ended', async () => {
if (currentPlayerData && currentPlayerData.nextProductId) {
await loadMedia(media, currentPlayerData.nextProductId);
}
});
// Set up Media Session API for prev/next controls
if ('mediaSession' in navigator) {
navigator.mediaSession.setActionHandler('previoustrack', async () => {
@ -207,6 +214,13 @@ async function openMediaPlayer(productId) {
} else if (media.tagName === 'AUDIO') {
// Audio: keep small floating player on page
media.play();
// Auto-advance when audio ends
media.addEventListener('ended', async () => {
if (currentPlayerData && currentPlayerData.nextProductId) {
await loadMedia(media, currentPlayerData.nextProductId);
}
});
} else {
// For non-media (PDFs, images), open in pop-out player window
document.body.removeChild(media);

View file

@ -263,6 +263,13 @@ async function openMediaPlayer(productId) {
await media.play();
await media.requestPictureInPicture();
// Auto-advance when video ends
media.addEventListener('ended', async () => {
if (currentPlayerData && currentPlayerData.nextProductId) {
await loadMedia(media, currentPlayerData.nextProductId);
}
});
// Set up Media Session API for prev/next controls
if ('mediaSession' in navigator) {
navigator.mediaSession.setActionHandler('previoustrack', async () => {
@ -285,6 +292,13 @@ async function openMediaPlayer(productId) {
} else if (media.tagName === 'AUDIO') {
// Audio: keep small floating player on page
media.play();
// Auto-advance when audio ends
media.addEventListener('ended', async () => {
if (currentPlayerData && currentPlayerData.nextProductId) {
await loadMedia(media, currentPlayerData.nextProductId);
}
});
} else {
// For non-media (PDFs, images), open in pop-out player window
document.body.removeChild(media);