diff --git a/Jellyfin.Plugin.MediaBarEnhanced/Web/mediaBarEnhanced.js b/Jellyfin.Plugin.MediaBarEnhanced/Web/mediaBarEnhanced.js index 0384813..2faf690 100644 --- a/Jellyfin.Plugin.MediaBarEnhanced/Web/mediaBarEnhanced.js +++ b/Jellyfin.Plugin.MediaBarEnhanced/Web/mediaBarEnhanced.js @@ -1749,8 +1749,8 @@ const SlideCreator = { // Fetch SponsorBlock data ApiUtils.fetchSponsorBlockData(videoId).then(segments => { const playerVars = { - autoplay: 0, - mute: STATE.slideshow.isMuted ? 1 : 0, + autoplay: 1, + mute: 1, // need to be muted for Safari, because apple makes life difficult... controls: 0, disablekb: 1, fs: 0, @@ -1808,9 +1808,8 @@ const SlideCreator = { // Store reference to wrapper for fading event.target._wrapperDiv = videoBackdrop; - if (STATE.slideshow.isMuted) { - event.target.mute(); - } else { + // Unmute now if user wants sound. + if (!STATE.slideshow.isMuted) { event.target.unMute(); event.target.setVolume(40); } @@ -1819,28 +1818,34 @@ const SlideCreator = { event.target.setPlaybackQuality(quality); } - // Only play if this is the active slide + // Stop playback if slide was navigated away from const slide = document.querySelector(`.slide[data-item-id="${itemId}"]`); const isVideoPlayerOpen = document.querySelector('.videoPlayerContainer') || document.querySelector('.youtubePlayerContainer'); - if (slide && slide.classList.contains('active') && !document.hidden && (!isVideoPlayerOpen || isVideoPlayerOpen.classList.contains('hide'))) { - event.target.playVideo(); - - // Check if it actually started playing after a short delay (handling autoplay blocks) + if (!slide || !slide.classList.contains('active') || document.hidden || (isVideoPlayerOpen && !isVideoPlayerOpen.classList.contains('hide'))) { + event.target.stopVideo(); + } else { + // Pause slideshow timer when video starts if configured + if (CONFIG.waitForTrailerToEnd && STATE.slideshow.slideInterval) { + STATE.slideshow.slideInterval.stop(); + } + + // Safety check after 1s: handle navigation-away during the window, + // and fallback to muted play if autoplay failed for any reason. const timeoutId = setTimeout(() => { - // Re-check conditions before processing fallback const isVideoPlayerOpenNow = document.querySelector('.videoPlayerContainer') || document.querySelector('.youtubePlayerContainer'); if (document.hidden || (isVideoPlayerOpenNow && !isVideoPlayerOpenNow.classList.contains('hide')) || !slide.classList.contains('active')) { - console.log(`Navigation detected during autoplay check for ${itemId}, stopping video.`); - try { - event.target.stopVideo(); - } catch (e) { console.warn("Error stopping video in timeout:", e); } - return; + console.log(`Navigation detected during autoplay check for ${itemId}, stopping video.`); + try { + event.target.stopVideo(); + } catch (e) { console.warn("Error stopping video:", e); } + return; } - if (event.target.getPlayerState() !== YT.PlayerState.PLAYING && - event.target.getPlayerState() !== YT.PlayerState.BUFFERING) { - console.warn(`Autoplay blocked for ${itemId}, attempting muted fallback`); + // If somehow not playing/buffering yet, force muted fallback + const state = event.target.getPlayerState(); + if (state !== YT.PlayerState.PLAYING && state !== YT.PlayerState.BUFFERING) { + console.warn(`Autoplay stalled for ${itemId}, attempting muted fallback`); event.target.mute(); event.target.playVideo(); } @@ -1848,11 +1853,6 @@ const SlideCreator = { if (!STATE.slideshow.autoplayTimeouts) STATE.slideshow.autoplayTimeouts = []; STATE.slideshow.autoplayTimeouts.push(timeoutId); - - // Pause slideshow timer when video starts if configured - if (CONFIG.waitForTrailerToEnd && STATE.slideshow.slideInterval) { - STATE.slideshow.slideInterval.stop(); - } } }, 'onStateChange': (event) => { @@ -1896,6 +1896,7 @@ const SlideCreator = { }; videoAttributes.muted = ""; + videoAttributes.playsinline = ""; // again Safari needs extra treatment... videoBackdrop = SlideUtils.createElement("video", videoAttributes); videoBackdrop.volume = 0.4; @@ -2468,6 +2469,7 @@ const SlideshowManager = { const lazySrc = videoBackdrop.getAttribute('data-src'); if (lazySrc && !videoBackdrop.src) { videoBackdrop.src = lazySrc; + videoBackdrop.load(); } videoBackdrop.currentTime = 0; @@ -2491,17 +2493,21 @@ const SlideshowManager = { const player = STATE.slideshow.videoPlayers[currentItemId]; if (player && typeof player.loadVideoById === 'function' && player._videoId) { // Use loadVideoById to enforce start and end times + // load always starts muted first, then unmute if needed player.loadVideoById({ videoId: player._videoId, startSeconds: player._startTime || 0, endSeconds: player._endTime }); - - if (STATE.slideshow.isMuted) { - player.mute(); - } else { - player.unMute(); - player.setVolume(40); + player.mute(); + if (!STATE.slideshow.isMuted) { + setTimeout(() => { + // Only unmute if still on the same slide + if (currentSlide.classList.contains('active')) { + player.unMute(); + player.setVolume(40); + } + }, 600); } // Check if playback successfully started, otherwise fallback to muted