From 246317212087c055c8e34d1e932f04e8c0768780 Mon Sep 17 00:00:00 2001 From: Pavan Thanuj Upadrasta Date: Thu, 16 Oct 2025 10:29:00 +0530 Subject: [PATCH 01/17] Add pause functionality to slideshow Introduces an isPaused state to control slideshow pausing. Adds a pause button to the UI, updates logic to prevent slide transitions when paused, and allows toggling pause via the space bar or button. Also improves homepage detection and ensures interval restarts only when not paused. --- slideshowpure.css | 16 ++++++++++++++++ slideshowpure.js | 47 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/slideshowpure.css b/slideshowpure.css index ab5e657..309b9aa 100644 --- a/slideshowpure.css +++ b/slideshowpure.css @@ -174,6 +174,22 @@ font-size: 12px; } +.pause-button { + position: absolute; + bottom: 10vh; + right: 20px; + font-size: 24px; + cursor: pointer; + color: white; + z-index: 10; + opacity: 0.3; + transition: opacity 0.3s ease; +} + +.pause-button:hover { + opacity: 0.9; +} + .dots-container { position: absolute; top: calc(50% + 18vh); diff --git a/slideshowpure.js b/slideshowpure.js index 3f08201..d8b51f4 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -1,5 +1,5 @@ /* - * Jellyfin Slideshow by M0RPH3US v3.0.1 + * Jellyfin Slideshow by M0RPH3US v3.0.2 */ //Core Module Configuration @@ -41,6 +41,7 @@ const STATE = { slideshow: { hasInitialized: false, isTransitioning: false, + isPaused: false, currentSlideIndex: 0, focusedSlide: null, containerFocused: false, @@ -157,6 +158,7 @@ const initLoadingScreen = () => { 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.endsWith("/web/"); @@ -250,6 +252,7 @@ const resetSlideshowState = () => { STATE.slideshow.hasInitialized = false; STATE.slideshow.isTransitioning = false; + STATE.slideshow.isPaused = false; STATE.slideshow.currentSlideIndex = 0; STATE.slideshow.focusedSlide = null; STATE.slideshow.containerFocused = false; @@ -733,13 +736,14 @@ const VisibilityObserver = { if (!container) return; const isVisible = - window.location.hash.includes("#/home.html") && + (window.location.hash === "#/home.html" || + window.location.hash === "#/home") && activeTab.getAttribute("data-index") === "0"; container.style.display = isVisible ? "block" : "none"; if (isVisible) { - if (STATE.slideshow.slideInterval) { + if (STATE.slideshow.slideInterval && !STATE.slideshow.isPaused) { STATE.slideshow.slideInterval.start(); } } else { @@ -1073,7 +1077,7 @@ const SlideCreator = { createFavoriteButton(item) { const isFavorite = item.UserData && item.UserData.IsFavorite === true; - + const button = SlideUtils.createElement("button", { className: `favorite-button ${isFavorite ? "favorited" : ""}`, tabIndex: "0", @@ -1263,7 +1267,7 @@ const SlideshowManager = { this.preloadAdjacentSlides(index); this.updateDots(); - if (STATE.slideshow.slideInterval) { + if (STATE.slideshow.slideInterval && !STATE.slideshow.isPaused) { STATE.slideshow.slideInterval.restart(); } @@ -1374,6 +1378,18 @@ const SlideshowManager = { }); }, + togglePause() { + STATE.slideshow.isPaused = !STATE.slideshow.isPaused; + const pauseButton = document.querySelector('.pause-button'); + if (STATE.slideshow.isPaused) { + STATE.slideshow.slideInterval.stop(); + pauseButton.innerHTML = 'play_arrow'; + } else { + STATE.slideshow.slideInterval.start(); + pauseButton.innerHTML = 'pause'; + } + }, + /** * Initializes touch events for swiping */ @@ -1447,6 +1463,11 @@ const SlideshowManager = { e.preventDefault(); break; + case " ": // Space bar + this.togglePause(); + e.preventDefault(); + break; + case "Enter": focusElement.click(); e.preventDefault(); @@ -1488,7 +1509,9 @@ const SlideshowManager = { await this.updateCurrentSlide(0); STATE.slideshow.slideInterval = new SlideTimer(() => { - this.nextSlide(); + if (!STATE.slideshow.isPaused) { + this.nextSlide(); + } }, CONFIG.shuffleInterval); } catch (error) { console.error("Error loading slideshow data:", error); @@ -1536,8 +1559,20 @@ const initArrowNavigation = () => { }, }); + const pauseButton = SlideUtils.createElement("div", { + className: "pause-button", + innerHTML: 'pause', + tabIndex: "0", + onclick: (e) => { + e.preventDefault(); + e.stopPropagation(); + SlideshowManager.togglePause(); + } + }); + container.appendChild(leftArrow); container.appendChild(rightArrow); + container.appendChild(pauseButton); const showArrows = () => { leftArrow.style.display = "block"; From 6596af075b2a27cac6a74a8bc4931efdc26337c6 Mon Sep 17 00:00:00 2001 From: M0RPH3US Date: Fri, 17 Oct 2025 01:44:23 +0530 Subject: [PATCH 02/17] Update version number in CSS comment --- slideshowpure.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slideshowpure.css b/slideshowpure.css index 309b9aa..9b0a2c8 100644 --- a/slideshowpure.css +++ b/slideshowpure.css @@ -1,5 +1,5 @@ /* - * Jellyfin Slideshow by M0RPH3US v3.0.0 + * Jellyfin Slideshow by M0RPH3US v3.0.3 */ @import url(https://fonts.googleapis.com/css2?family=Archivo+Narrow:ital,wght@0,400..700;1,400..700&display=swap); From 313e2557dcd4aa828ba2ab95b9caa7d5b2a32bab Mon Sep 17 00:00:00 2001 From: M0RPH3US Date: Fri, 17 Oct 2025 01:44:51 +0530 Subject: [PATCH 03/17] Update version number to 3.0.3 --- slideshowpure.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slideshowpure.js b/slideshowpure.js index d8b51f4..ea6e167 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -1,5 +1,5 @@ /* - * Jellyfin Slideshow by M0RPH3US v3.0.2 + * Jellyfin Slideshow by M0RPH3US v3.0.3 */ //Core Module Configuration From dcb58ad4cefa445e356e15142fb6501f82d19da3 Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 22 Oct 2025 22:05:20 +0100 Subject: [PATCH 04/17] feat: implement new styling for elements Adds styling for new rating elements, following similar standards for other parts of jellyfin --- slideshowpure.css | 77 ++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/slideshowpure.css b/slideshowpure.css index 9b0a2c8..29c8206 100644 --- a/slideshowpure.css +++ b/slideshowpure.css @@ -5,7 +5,8 @@ @import url(https://fonts.googleapis.com/css2?family=Archivo+Narrow:ital,wght@0,400..700;1,400..700&display=swap); .backdrop.animate { - animation: frostedGlass 1.2s cubic-bezier(0.4, 0, 0.2, 1), + animation: + frostedGlass 1.2s cubic-bezier(0.4, 0, 0.2, 1), kenBurnsZoomIn 10s ease-out forwards; } @@ -117,13 +118,17 @@ .backdrop.low-quality { filter: blur(0.5px); transform: scale(1.01); - transition: filter 0.3s ease-in-out, transform 0.3s ease-in-out; + transition: + filter 0.3s ease-in-out, + transform 0.3s ease-in-out; } .backdrop.high-quality { filter: blur(0); transform: scale(1); - transition: filter 0.3s ease-in-out, transform 0.3s ease-in-out; + transition: + filter 0.3s ease-in-out, + transform 0.3s ease-in-out; } .logo.low-quality { @@ -175,19 +180,19 @@ } .pause-button { - position: absolute; - bottom: 10vh; - right: 20px; - font-size: 24px; - cursor: pointer; - color: white; - z-index: 10; - opacity: 0.3; - transition: opacity 0.3s ease; + position: absolute; + bottom: 10vh; + right: 20px; + font-size: 24px; + cursor: pointer; + color: white; + z-index: 10; + opacity: 0.3; + transition: opacity 0.3s ease; } .pause-button:hover { - opacity: 0.9; + opacity: 0.9; } .dots-container { @@ -211,7 +216,8 @@ background-color: #cecece99; border-radius: 50%; transform-origin: center; - transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1), + transition: + transform 0.5s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.5s ease-in-out; } @@ -406,6 +412,7 @@ font-weight: 700; gap: 6px; -webkit-tap-highlight-color: #fff0; + border-radius: 8px; } .detail-button { @@ -487,7 +494,7 @@ font-weight: 500; } -.rating-value { +.misc-info { font-family: "Archivo Narrow", sans-serif; display: flex; align-items: center; @@ -507,37 +514,25 @@ font-weight: 500; } -.tomato-rating { - display: flex; - align-items: center; - margin-left: 0; +/* Star Icon Styling */ +.community-rating-star { + color: #f2b01e; + font-size: 1.4em; + height: auto !important; + margin-right: 0.125em; + width: auto !important; } -.imdb-logo { - margin-right: 1px; - display: flex; - flex-wrap: wrap; - align-content: center; - justify-content: center; +/* Rotten Tomatoes Critic Rating Styles */ + +.critic-rating { + -webkit-align-items: center; align-items: center; + display: flex; + min-height: 1.2em; } -.tomato-logo { - flex-wrap: wrap; - align-content: center; - display: flex; - justify-content: center; - align-items: center; - margin-left: 5px; -} - -.critic-logo { - margin-right: 5px; - display: flex; - flex-wrap: wrap; - align-content: center; - justify-content: center; -} +/**/ .age-rating { display: flex; From 11f72488dd0c2c9d79373d64b92a561550f65847 Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 22 Oct 2025 23:09:39 +0100 Subject: [PATCH 05/17] fix: use jellyfin svg over asset which has been removed in 10.11.0 --- slideshowpure.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/slideshowpure.js b/slideshowpure.js index ea6e167..74ba9aa 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -5,10 +5,7 @@ //Core Module Configuration const CONFIG = { IMAGE_SVG: { - imdbLogo: - '', - tomatoLogo: - '', + jellyfin: '', freshTomato: 'image/svg+xml', rottenTomato: @@ -170,7 +167,7 @@ const initLoadingScreen = () => { loadingDiv.innerHTML = `

- Server Logo + ${CONFIG.IMAGE_SVG.jellyfin}

From f9aa6ada64b1d4277d69cfb174e1659da085fd7b Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 22 Oct 2025 23:10:07 +0100 Subject: [PATCH 06/17] feat: use seperator element for genre seperator --- slideshowpure.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slideshowpure.js b/slideshowpure.js index 74ba9aa..da2da14 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -429,7 +429,7 @@ const SlideUtils = { */ parseGenres(genresArray) { if (Array.isArray(genresArray) && genresArray.length > 0) { - return genresArray.slice(0, 3).join(" ▫️ "); //🔹 + return genresArray.slice(0, 3).join(this.createSeparator().outerHTML); } return "No Genre Available"; }, From 4c77f7e545b26f9760a5529f0d6f99a70946d466 Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 22 Oct 2025 23:10:27 +0100 Subject: [PATCH 07/17] chore: tidy genre element --- slideshowpure.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slideshowpure.js b/slideshowpure.js index da2da14..4bb4d72 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -733,8 +733,8 @@ const VisibilityObserver = { if (!container) return; const isVisible = - (window.location.hash === "#/home.html" || - window.location.hash === "#/home") && + (window.location.hash === "#/home.html" || + window.location.hash === "#/home") && activeTab.getAttribute("data-index") === "0"; container.style.display = isVisible ? "block" : "none"; @@ -855,8 +855,8 @@ const SlideCreator = { const genreElement = SlideUtils.createElement("div", { className: "genre", + innerHTML: SlideUtils.parseGenres(item.Genres) }); - genreElement.innerHTML = SlideUtils.parseGenres(item.Genres); const buttonContainer = SlideUtils.createElement("div", { className: "button-container", From ecce883a3ed5efa3d2ff6810602bbe82c12c0bae Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 22 Oct 2025 23:11:40 +0100 Subject: [PATCH 08/17] refactor(misc-info): restructure misc info to use standard jellyifn icons, and display correctly and no longer show N/A --- slideshowpure.js | 186 ++++++++++++++++------------------------------- 1 file changed, 64 insertions(+), 122 deletions(-) diff --git a/slideshowpure.js b/slideshowpure.js index 4bb4d72..3ec7e42 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -888,139 +888,81 @@ const SlideCreator = { */ createRatingInfo(item) { const { - CommunityRating: rating, + CommunityRating: communityRating, CriticRating: criticRating, - OfficialRating: age, - PremiereDate: date, + OfficialRating: ageRating, + PremiereDate: premiereDate, RunTimeTicks: runtime, - ChildCount: season, + ChildCount: seasonCount, } = item; - const ratingTest = SlideUtils.createElement("div", { - className: "rating-value", + const miscInfo = SlideUtils.createElement("div", { + className: "misc-info itemMiscInfo", }); - const imdbLogo = SlideUtils.createElement("div", { - className: "imdb-logo", - innerHTML: CONFIG.IMAGE_SVG.imdbLogo, - style: { - width: "30px", - height: "30px", - }, - }); - - ratingTest.appendChild(imdbLogo); - - if (typeof rating === "number") { - const ratingSpan = document.createElement("span"); - ratingSpan.textContent = rating.toFixed(1); - ratingSpan.style.marginRight = "5px"; - ratingSpan.style.marginLeft = "5px"; - ratingTest.appendChild(ratingSpan); - } else { - const naSpan = document.createElement("span"); - naSpan.innerHTML = "N/A"; - naSpan.style.color = "#fff9"; - naSpan.style.marginRight = "5px"; - naSpan.style.marginLeft = "5px"; - ratingTest.appendChild(naSpan); + // Community Rating Section (IMDb) + if (typeof communityRating === "number") { + const container = SlideUtils.createElement("div", { + className: "star-rating-container", + innerHTML: `${communityRating.toFixed(1)}`, + }); + miscInfo.appendChild(container); + miscInfo.appendChild(SlideUtils.createSeparator()); } - ratingTest.appendChild(SlideUtils.createSeparator()); - - const tomatoRatingDiv = SlideUtils.createElement("div", { - className: "tomato-rating", - }); - - const tomatoLogo = SlideUtils.createElement("div", { - className: "tomato-logo", - innerHTML: CONFIG.IMAGE_SVG.tomatoLogo, - style: { - width: "18px", - height: "20px", - }, - }); - - let valueElement = SlideUtils.createElement("span", { - style: { - marginLeft: "5px", - marginRight: "5px", - }, - }); - + // Critic Rating Section (Rotten Tomatoes) if (typeof criticRating === "number") { - valueElement.textContent = `${criticRating}% `; - } else { - valueElement.style.color = "#fff9"; - valueElement.textContent = "N/A "; + const svgIcon = criticRating < 60 ? CONFIG.IMAGE_SVG.rottenTomato : CONFIG.IMAGE_SVG.freshTomato; + const container = SlideUtils.createElement("div", { + className: "critic-rating", + innerHTML: `${svgIcon}${criticRating.toFixed(0)}%`, + }) + miscInfo.appendChild(container); + miscInfo.appendChild(SlideUtils.createSeparator()); + }; + + // Year Section + if (typeof premiereDate === "string" && !isNaN(new Date(premiereDate))) { + const container = SlideUtils.createElement("div", { + className: "date", + innerHTML: new Date(premiereDate).getFullYear(), + }); + miscInfo.appendChild(container); + miscInfo.appendChild(SlideUtils.createSeparator()); + }; + + // Age Rating Section + if (typeof ageRating === "string") { + const container = SlideUtils.createElement("div", { + className: "age-rating mediaInfoOfficialRating", + rating: ageRating, + ariaLabel: `Content rated ${ageRating}`, + title: `Rating: ${ageRating}`, + innerHTML: ageRating, + }); + miscInfo.appendChild(container); + miscInfo.appendChild(SlideUtils.createSeparator()); + }; + + // Runtime / Seasons Section + if (seasonCount !== undefined || runtime !== undefined) { + const container = SlideUtils.createElement("div", { + className: "runTime", + }); + if (seasonCount) { + container.innerHTML = `${seasonCount} Season${seasonCount > 1 ? "s" : ""}`; + } else { + const milliseconds = runtime / 10000; + const currentTime = new Date(); + const endTime = new Date(currentTime.getTime() + milliseconds); + const options = { hour: "2-digit", minute: "2-digit", hour12: false }; + const formattedEndTime = endTime.toLocaleTimeString([], options); + container.innerText = `Ends at ${formattedEndTime}`; + } + miscInfo.appendChild(container); } - const criticLogo = SlideUtils.createElement("span", { - className: "critic-logo", - style: { - display: "flex", - width: "18", - height: "20", - }, - }); - criticLogo.innerHTML = - criticRating > 59 - ? CONFIG.IMAGE_SVG.freshTomato - : CONFIG.IMAGE_SVG.rottenTomato; - - tomatoRatingDiv.append(tomatoLogo, valueElement, criticLogo); - tomatoRatingDiv.appendChild(SlideUtils.createSeparator()); - - const ageRatingDiv = SlideUtils.createElement("div", { - className: "age-rating", - }); - const ageSpan = document.createElement("span"); - ageSpan.textContent = age || "N/A"; - ageRatingDiv.appendChild(ageSpan); - - const premiereDate = SlideUtils.createElement("div", { - className: "date", - }); - - const year = date ? new Date(date).getFullYear() : NaN; - if (isNaN(year)) { - const naSpan = SlideUtils.createElement( - "span", - { - style: { color: "#fff9" }, - }, - "N/A" - ); - premiereDate.appendChild(naSpan); - } else { - premiereDate.textContent = year; - } - - const runTimeElement = SlideUtils.createElement("div", { - className: "runTime", - }); - - if (season === undefined) { - const milliseconds = runtime / 10000; - const currentTime = new Date(); - const endTime = new Date(currentTime.getTime() + milliseconds); - const options = { hour: "2-digit", minute: "2-digit", hour12: false }; - const formattedEndTime = endTime.toLocaleTimeString([], options); - runTimeElement.textContent = `Ends at ${formattedEndTime}`; - } else { - runTimeElement.textContent = `${season} Season${season > 1 ? "s" : ""}`; - } - - ratingTest.append( - tomatoRatingDiv, - premiereDate, - SlideUtils.createSeparator(), - ageRatingDiv, - SlideUtils.createSeparator(), - runTimeElement - ); - - return ratingTest; + return miscInfo; }, /** From 311e4c0f5a4e57e6517910fa7d0e37068ee5df8a Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 22 Oct 2025 23:11:58 +0100 Subject: [PATCH 09/17] chore: opinionated formatting --- slideshowpure.js | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/slideshowpure.js b/slideshowpure.js index 3ec7e42..6b3c298 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -1318,15 +1318,15 @@ const SlideshowManager = { }, togglePause() { - STATE.slideshow.isPaused = !STATE.slideshow.isPaused; - const pauseButton = document.querySelector('.pause-button'); - if (STATE.slideshow.isPaused) { - STATE.slideshow.slideInterval.stop(); - pauseButton.innerHTML = 'play_arrow'; - } else { - STATE.slideshow.slideInterval.start(); - pauseButton.innerHTML = 'pause'; - } + STATE.slideshow.isPaused = !STATE.slideshow.isPaused; + const pauseButton = document.querySelector('.pause-button'); + if (STATE.slideshow.isPaused) { + STATE.slideshow.slideInterval.stop(); + pauseButton.innerHTML = 'play_arrow'; + } else { + STATE.slideshow.slideInterval.start(); + pauseButton.innerHTML = 'pause'; + } }, /** @@ -1403,9 +1403,9 @@ const SlideshowManager = { break; case " ": // Space bar - this.togglePause(); - e.preventDefault(); - break; + this.togglePause(); + e.preventDefault(); + break; case "Enter": focusElement.click(); @@ -1449,7 +1449,7 @@ const SlideshowManager = { STATE.slideshow.slideInterval = new SlideTimer(() => { if (!STATE.slideshow.isPaused) { - this.nextSlide(); + this.nextSlide(); } }, CONFIG.shuffleInterval); } catch (error) { @@ -1499,14 +1499,14 @@ const initArrowNavigation = () => { }); const pauseButton = SlideUtils.createElement("div", { - className: "pause-button", - innerHTML: 'pause', - tabIndex: "0", - onclick: (e) => { - e.preventDefault(); - e.stopPropagation(); - SlideshowManager.togglePause(); - } + className: "pause-button", + innerHTML: 'pause', + tabIndex: "0", + onclick: (e) => { + e.preventDefault(); + e.stopPropagation(); + SlideshowManager.togglePause(); + } }); container.appendChild(leftArrow); From e07b2e40c48aa89a3440b70515f092cb691c3339 Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 22 Oct 2025 23:12:22 +0100 Subject: [PATCH 10/17] fix: optimise css for ratings --- slideshowpure.css | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/slideshowpure.css b/slideshowpure.css index 29c8206..9651b9a 100644 --- a/slideshowpure.css +++ b/slideshowpure.css @@ -378,6 +378,9 @@ } .genre { + display: flex; + gap: 5px; + align-items: center; position: absolute; top: calc(50% + 4vh); left: 4vw; @@ -500,14 +503,13 @@ align-items: center; z-index: 5; position: relative; + gap: 10px; } .runTime { font-family: "Archivo Narrow", sans-serif; display: flex; align-items: center; - margin-left: 5px; - margin-right: 5px; align-content: center; justify-content: center; flex-wrap: wrap; @@ -523,6 +525,11 @@ width: auto !important; } +.star-rating-container { + display: flex; + align-items: center; +} + /* Rotten Tomatoes Critic Rating Styles */ .critic-rating { @@ -530,6 +537,7 @@ align-items: center; display: flex; min-height: 1.2em; + gap: 0.25em; } /**/ @@ -537,8 +545,6 @@ .age-rating { display: flex; align-items: center; - margin-left: 5px; - margin-right: 5px; border-radius: 5px; background: rgb(255 255 255 / 0.8); color: #000; @@ -553,16 +559,12 @@ font-weight: 500; display: flex; align-items: center; - margin-left: 5px; - margin-right: 5px; flex-wrap: wrap; align-content: center; justify-content: center; } .separator-icon { - margin-left: 5px; - margin-right: 5px; font-size: 10px; color: aquamarine; } From 2abeafb889733480e16f015977dc84add1ec0119 Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 22 Oct 2025 23:36:27 +0100 Subject: [PATCH 11/17] chore: version bump --- slideshowpure.css | 2 +- slideshowpure.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/slideshowpure.css b/slideshowpure.css index 9651b9a..5e51e99 100644 --- a/slideshowpure.css +++ b/slideshowpure.css @@ -1,5 +1,5 @@ /* - * Jellyfin Slideshow by M0RPH3US v3.0.3 + * Jellyfin Slideshow by M0RPH3US v3.0.4 */ @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 6b3c298..5b1967d 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -1,5 +1,5 @@ /* - * Jellyfin Slideshow by M0RPH3US v3.0.3 + * Jellyfin Slideshow by M0RPH3US v3.0.4 */ //Core Module Configuration From 4f61038aaa307f81814233f633a592de7ed273b7 Mon Sep 17 00:00:00 2001 From: Core Date: Thu, 23 Oct 2025 00:04:52 +0100 Subject: [PATCH 12/17] fix: enable centering and wrapping for better responsiveness --- slideshowpure.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slideshowpure.css b/slideshowpure.css index 5e51e99..63c0a86 100644 --- a/slideshowpure.css +++ b/slideshowpure.css @@ -381,6 +381,7 @@ display: flex; gap: 5px; align-items: center; + justify-content: center; position: absolute; top: calc(50% + 4vh); left: 4vw; @@ -388,6 +389,7 @@ color: #fff; font-family: "Archivo Narrow", sans-serif; z-index: 5; + flex-wrap: wrap; } .button-container { From 93c1a54ac40bbdfe3c6190d2e36ce7cc10b8b1b0 Mon Sep 17 00:00:00 2001 From: Core Date: Thu, 23 Oct 2025 00:56:02 +0100 Subject: [PATCH 13/17] fix: remove itemMiscInfo to prevent theme breaking --- slideshowpure.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slideshowpure.js b/slideshowpure.js index 5b1967d..4b2c30e 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -897,7 +897,7 @@ const SlideCreator = { } = item; const miscInfo = SlideUtils.createElement("div", { - className: "misc-info itemMiscInfo", + className: "misc-info", }); // Community Rating Section (IMDb) From 21eab1deddc7bee13608f2790f1bc17a9a59ecb1 Mon Sep 17 00:00:00 2001 From: Core Date: Thu, 23 Oct 2025 22:21:07 +0100 Subject: [PATCH 14/17] fix(pause-button): reposition to top-right and improve responsiveness This will prevent the button being hidden underneath media cards and will improve its sizing and visibility across all background and interfaces. --- slideshowpure.css | 26 +++++++++++++++++++++++--- slideshowpure.js | 6 ++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/slideshowpure.css b/slideshowpure.css index 63c0a86..1a2b268 100644 --- a/slideshowpure.css +++ b/slideshowpure.css @@ -181,20 +181,40 @@ .pause-button { position: absolute; - bottom: 10vh; - right: 20px; - font-size: 24px; + top: 5rem; + right: 0.8rem; cursor: pointer; color: white; z-index: 10; opacity: 0.3; transition: opacity 0.3s ease; + text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.8); +} + +.pause-button i { + font-size: 1.5rem; } .pause-button:hover { opacity: 0.9; } +@media (max-width: 1599px) { + .pause-button { + top: 8rem; + } + + .pause-button i { + font-size: 2rem; + } +} + +@media (max-width: 768px) { + .pause-button i { + font-size: 2.5rem; + } +} + .dots-container { position: absolute; top: calc(50% + 18vh); diff --git a/slideshowpure.js b/slideshowpure.js index 4b2c30e..5dd6059 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -1323,9 +1323,13 @@ const SlideshowManager = { if (STATE.slideshow.isPaused) { STATE.slideshow.slideInterval.stop(); pauseButton.innerHTML = 'play_arrow'; + pauseButton.setAttribute("aria-label", "Play slideshow"); + pauseButton.setAttribute("title", "Play slideshow"); } else { STATE.slideshow.slideInterval.start(); pauseButton.innerHTML = 'pause'; + pauseButton.setAttribute("aria-label", "Pause slideshow"); + pauseButton.setAttribute("title", "Pause slideshow"); } }, @@ -1502,6 +1506,8 @@ const initArrowNavigation = () => { className: "pause-button", innerHTML: 'pause', tabIndex: "0", + "aria-label": "Pause slideshow", + title: "Pause slideshow", onclick: (e) => { e.preventDefault(); e.stopPropagation(); From a4dde6bf5189828d30bd99a9d401ff1822a0516e Mon Sep 17 00:00:00 2001 From: Core Date: Thu, 23 Oct 2025 23:43:51 +0100 Subject: [PATCH 15/17] fix: use splashLogo class over svg Didn't realise they used this --- slideshowpure.css | 2 +- slideshowpure.js | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/slideshowpure.css b/slideshowpure.css index 1a2b268..0eb476c 100644 --- a/slideshowpure.css +++ b/slideshowpure.css @@ -76,7 +76,7 @@ align-items: center; } -.bar-loading h1 img { +.bar-loading h1 div { width: 250px; max-height: 250px; display: block; diff --git a/slideshowpure.js b/slideshowpure.js index 5dd6059..966e73c 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -5,7 +5,6 @@ //Core Module Configuration const CONFIG = { IMAGE_SVG: { - jellyfin: '', freshTomato: 'image/svg+xml', rottenTomato: @@ -167,7 +166,7 @@ const initLoadingScreen = () => { loadingDiv.innerHTML = `

- ${CONFIG.IMAGE_SVG.jellyfin} +

@@ -179,7 +178,7 @@ const initLoadingScreen = () => { document.body.appendChild(loadingDiv); requestAnimationFrame(() => { - document.querySelector(".bar-loading h1 img").style.opacity = "1"; + document.querySelector(".bar-loading h1 div").style.opacity = "1"; }); const progressBar = document.getElementById("progress-bar"); From 98ce372afb49d95b08f763a7c974e99d4839e0b4 Mon Sep 17 00:00:00 2001 From: Core Date: Fri, 24 Oct 2025 00:20:46 +0100 Subject: [PATCH 16/17] fix: show item name when no logo is present --- slideshowpure.css | 1 + slideshowpure.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/slideshowpure.css b/slideshowpure.css index 0eb476c..c21474d 100644 --- a/slideshowpure.css +++ b/slideshowpure.css @@ -372,6 +372,7 @@ width: auto; object-fit: contain; filter: brightness(1.5); + font-size: 4rem; } .plot-container { diff --git a/slideshowpure.js b/slideshowpure.js index 966e73c..2b3262c 100644 --- a/slideshowpure.js +++ b/slideshowpure.js @@ -809,7 +809,7 @@ const SlideCreator = { const logo = SlideUtils.createElement("img", { className: "logo high-quality", src: `${serverAddress}/Items/${itemId}/Images/Logo?quality=40`, - alt: "logo", + alt: item.Name, loading: "eager", }); From e7b4fed2fb99c32c1a83fd45467254b2af72cf94 Mon Sep 17 00:00:00 2001 From: M0RPH3US Date: Tue, 28 Oct 2025 18:52:41 +0530 Subject: [PATCH 17/17] Update README with compatibility notes and update delay Added notes about Jellyfin 10.11.x compatibility and update delays. --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index fb90013..8a7beef 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # Jellyfin-Media-Bar - Now with Play Now Function +> [!NOTE] +> The Media Bar is currently partly compatible with the Jellyfin 10.11.x update. We’re aware of the changes required to make it fully compatible and will be addressing them soon. +> +> I’ll be away on vacation for a short while, so there will be a temporary delay in releasing the next update. I kindly ask that you refrain from opening new bug reports related to 10.11.x compatibility during this period — we’ve got it on our radar. +> +> Thank you for your patience and understanding! The fixes will be rolled out shortly after I return. + + **IMP UPDATE — We have dropped support for the normal CSS version (for now). _(It still works, but there will be no further updates till the fullscreen mode is stabilized)_** The fullscreen version has a new look (in beta), and support for different screen sizes has been added. For any visual goof-ups, please open a bug report, including the device being used and whether it is encountered in portrait or landscape mode.