diff --git a/make_post_sell/static/js/player.js b/make_post_sell/static/js/player.js index e4c12ce..c901308 100644 --- a/make_post_sell/static/js/player.js +++ b/make_post_sell/static/js/player.js @@ -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'); + } } } diff --git a/make_post_sell/templates/content.j2 b/make_post_sell/templates/content.j2 index 4379151..f4f11cc 100644 --- a/make_post_sell/templates/content.j2 +++ b/make_post_sell/templates/content.j2 @@ -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); diff --git a/make_post_sell/templates/product.j2 b/make_post_sell/templates/product.j2 index b4a430a..a018130 100644 --- a/make_post_sell/templates/product.j2 +++ b/make_post_sell/templates/product.j2 @@ -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);