diff --git a/slideshowpure.css b/slideshowpure.css index d4a037c..04ff110 100644 --- a/slideshowpure.css +++ b/slideshowpure.css @@ -1,5 +1,5 @@ /* - * Jellyfin Slideshow by M0RPH3US v4.0.4 + * Jellyfin Slideshow by M0RPH3US v4.0.6 */ @import url(https://fonts.googleapis.com/css2?family=Archivo+Narrow:ital,wght@0,400..700;1,400..700&display=swap); diff --git a/slideshowpure.js b/slideshowpure.js index f289a8a..2b82ce2 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -1,5 +1,5 @@ /* - * Jellyfin Slideshow by M0RPH3US v4.0.4 + * Jellyfin Slideshow by M0RPH3US v4.0.6 */ //Core Module Configuration @@ -17,8 +17,8 @@ const CONFIG = { maxPlotLength: 360, maxMovies: 15, maxTvShows: 15, - maxItems: 500, - preloadCount: 3, + maxItems: 50, + preloadCount: 1, fadeTransitionDuration: 500, slideAnimationEnabled: true, enableTrailers: true, @@ -188,12 +188,12 @@ const initLocalization = async () => { */ const initLoadingScreen = () => { - const currentPath = window.location.href.toLowerCase().replace(window.location.origin, ""); + const currentPath = window.location.href.toLowerCase(); const isHomePage = currentPath.includes("/web/#/home.html") || currentPath.includes("/web/#/home") || currentPath.includes("/web/index.html#/home.html") || - currentPath === "/web/index.html#/home" || + currentPath.endsWith("/web/index.html#/home") || currentPath.endsWith("/web/"); if (!isHomePage) return; @@ -760,6 +760,12 @@ const ApiUtils = { return STATE.slideshow.loadedItems[itemId]; } + const MAX_CACHED_ITEMS = 20; + const cacheKeys = Object.keys(STATE.slideshow.loadedItems); + if (cacheKeys.length >= MAX_CACHED_ITEMS) { + delete STATE.slideshow.loadedItems[cacheKeys[0]]; + } + const response = await fetch( `${STATE.jellyfinData.serverAddress}/Items/${itemId}`, { @@ -1056,60 +1062,31 @@ const VisibilityObserver = { if (!container) return; const isVisible = - (window.location.hash === "#/home.html" || - window.location.hash === "#/home") && - activeTab.getAttribute("data-index") === "0"; + (window.location.hash === "#/home.html" || + window.location.hash === "#/home") && + (activeTab ? activeTab.getAttribute("data-index") === "0" : false); container.style.display = isVisible ? "block" : "none"; if (isVisible && !this.wasVisible) { - const currentItemId = - STATE.slideshow.itemIds[STATE.slideshow.currentSlideIndex]; - const currentSlide = document.querySelector( - `.slide[data-item-id="${currentItemId}"]`, - ); - const player = STATE.slideshow.players[currentItemId]; - - if (currentSlide && player) { - const trailerContainer = currentSlide.querySelector(".video-container"); - const backdrop = currentSlide.querySelector(".backdrop"); - const plotContainer = currentSlide.querySelector(".plot-container"); - if (trailerContainer) trailerContainer.classList.remove("active"); - if (backdrop) backdrop.classList.remove("with-video"); - if (plotContainer) plotContainer.classList.remove("with-video"); - - try { - if (typeof player.pauseVideo === "function") { - player.pauseVideo(); - } - if (typeof player.seekTo === "function") { - player.seekTo(0); - } - } catch (e) { - console.warn(`Failed to reset player for ${currentItemId}:`, e); - } - } - - if (STATE.slideshow.slideInterval && !STATE.slideshow.isPaused) { - STATE.slideshow.slideInterval.start(); - } + SlideshowManager.updateCurrentSlide(STATE.slideshow.currentSlideIndex); } else if (!isVisible && this.wasVisible) { - // Transitioning FROM visible TO hidden if (STATE.slideshow.slideInterval) { STATE.slideshow.slideInterval.stop(); } - Object.keys(STATE.slideshow.players).forEach((itemId) => { const player = STATE.slideshow.players[itemId]; - if (player && typeof player.pauseVideo === "function") { + if (player && typeof player.destroy === "function") { try { - player.pauseVideo(); - } catch (e) { - console.warn(`Failed to pause player for ${itemId}:`, e); - } + player.destroy(); + } catch (e) {} } }); + STATE.slideshow.players = {}; + container.querySelectorAll(".slide").forEach((slide) => slide.remove()); + STATE.slideshow.createdSlides = {}; } + this.wasVisible = isVisible; }, @@ -1221,11 +1198,6 @@ const SlideCreator = { } catch (e) {} if (videoId) { - // trailerContainer = SlideUtils.createElement("div", { - // className: "video-container", - // id: `trailer-${item.Id}`, - // style: { width: `calc(100vh * 1.777)` }, - // }); trailerContainer = SlideUtils.createElement("div", { className: "video-container", id: `trailer-${item.Id}`, @@ -1542,36 +1514,6 @@ const SlideCreator = { container.appendChild(slide); STATE.slideshow.createdSlides[itemId] = true; - // if (videoId) { - // loadYouTubeAPI().then((YT) => { - // if (!document.getElementById(`trailer-${itemId}`)) return; - - // STATE.slideshow.players[itemId] = new YT.Player( - // `yt-player-${itemId}`, - // { - // videoId: videoId, - // playerVars: { - // autoplay: 0, - // controls: 0, - // rel: 0, - // fs: 0, - // showinfo: 0, - // modestbranding: 1, - // }, - // events: { - // onStateChange: (e) => - // SlideshowManager.onPlayerStateChange( - // e, - // itemId, - // trailerContainer, - // ), - // onReady: (e) => e.target.mute(), - // }, - // }, - // ); - // }); - // } - if (videoId) { const startTime = await ApiUtils.getSkipSegments(videoId); @@ -1753,6 +1695,7 @@ const SlideshowManager = { STATE.slideshow.currentSlideIndex = index; this.updateDots(); this.preloadAdjacentSlides(index); + this.pruneSlideCache(); const itemData = STATE.slideshow.loadedItems[currentItemId]; const hasTrailerData = @@ -1765,7 +1708,8 @@ const SlideshowManager = { setTimeout(() => { if ( STATE.slideshow.currentSlideIndex === index && - !STATE.slideshow.isPaused + !STATE.slideshow.isPaused && + VisibilityObserver.wasVisible ) { const player = STATE.slideshow.players[currentItemId]; @@ -1856,15 +1800,9 @@ const SlideshowManager = { }, nextSlide() { - // if (STATE.slideshow.isVideoPlaying) { - // return; - // } - const currentIndex = STATE.slideshow.currentSlideIndex; const totalItems = STATE.slideshow.totalItems; - const nextIndex = (currentIndex + 1) % totalItems; - this.updateCurrentSlide(nextIndex); }, @@ -1883,7 +1821,7 @@ const SlideshowManager = { */ pruneSlideCache() { const currentIndex = STATE.slideshow.currentSlideIndex; - const keepRange = 5; + const keepRange = 2; Object.keys(STATE.slideshow.createdSlides).forEach((itemId) => { const index = STATE.slideshow.itemIds.indexOf(itemId); @@ -2105,7 +2043,7 @@ const SlideshowManager = { await this.updateCurrentSlide(0); STATE.slideshow.slideInterval = new SlideTimer(() => { - if (!STATE.slideshow.isPaused) { + if (!STATE.slideshow.isPaused && VisibilityObserver.wasVisible) { this.nextSlide(); } }, CONFIG.shuffleInterval); @@ -2357,7 +2295,7 @@ const initPageVisibilityHandler = () => { } } else { console.log("Tab active - resuming slideshow"); - if (!STATE.slideshow.isPaused) { + if (!STATE.slideshow.isPaused && VisibilityObserver.wasVisible) { const currentItemId = STATE.slideshow.itemIds[STATE.slideshow.currentSlideIndex]; if (