From 68844307bd852393371d2ee4670d4e223e11dcce Mon Sep 17 00:00:00 2001 From: M0RPH3US Date: Wed, 5 Feb 2025 18:37:39 +0530 Subject: [PATCH] Initial Release --- slideshowpure.css | 685 ++++++++++++++++++++++++++++++++++++++++++++++ slideshowpure.js | 427 +++++++++++++++++++++++++++++ 2 files changed, 1112 insertions(+) create mode 100644 slideshowpure.css create mode 100644 slideshowpure.js diff --git a/slideshowpure.css b/slideshowpure.css new file mode 100644 index 0000000..d7614b9 --- /dev/null +++ b/slideshowpure.css @@ -0,0 +1,685 @@ +@import url("https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap"); + +@media only screen and (min-width: 767px) { + div[data-role="page"].page { + overflow-y: scroll; /* Keeps vertical scrolling active */ + scrollbar-width: none; /* For Firefox */ + -ms-overflow-style: none; /* For Internet Explorer & Edge */ + } + + div[data-role="page"].page::-webkit-scrollbar { + display: none; /* Hides scrollbar in Webkit browsers */ + } + + .backdrop, + .slide { + position: absolute; + } + + .featured-content, + .plot-container { + font-family: "Titillium Web", sans-serif; + left: 0; + } + + .plot, + body { + overflow: hidden; + } + + .arrow { + position: absolute; + top: 50%; + transform: translateY(-50%); + font-size: 24px; + cursor: pointer; + color: white; + z-index: 3; + display: flex; + justify-content: center; + align-items: center; + } + + .arrow::before { + content: ""; /* Creates an empty element */ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 40px; /* Size of the circle */ + height: 40px; /* Size of the circle */ + background-color: rgba(12, 110, 162, 0.7); /* Translucent background */ + border-radius: 50%; /* Makes it a circle */ + z-index: -1; /* Places the circle behind the arrow */ + } + + .left-arrow { + left: 10px; /* Position to the left */ + } + + .right-arrow { + right: 10px; /* Position to the right */ + } + + .dots-container { + position: absolute; + bottom: 5%; + left: 0; + right: 0; + z-index: 2; + display: flex; + justify-content: center; /* Centers the dots horizontally */ + align-items: center; + width: 100vw; /* Full screen width */ + height: 22px; + background-color: #ffffff00; + gap: 2vw; /* Evenly space the rectangles with a gap of 2vw */ + } + + .dot { + width: 15vw; /* Each rectangle takes 18% of the viewport width */ + height: 4px; /* Thin rectangle height */ + background-color: #cecece; + border-radius: 2px; /* Slightly rounded corners */ + cursor: pointer; + transition: background-color 0.3s; + } + + .dot.active { + background-color: rgba(12, 110, 162, 0.7) !important; + } + + body { + margin: 0; + padding: 0; + } + + .fade-in { + opacity: 1 !important; + } + + .fade-out { + opacity: 0 !important; + } + + #slides-container { + position: relative; + width: 100vw; + height: 750px; + overflow: hidden; + margin: 0 auto; + border-radius: 7px; + top: -5em; + } + + .slide { + transition: opacity 0.5s ease-in-out; /* Smooth fade transition */ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: block; + } + + .slide.active { + opacity: 1; + display: block; + } + + .slide:focus { + outline: #fff solid 2px; + } + + .backdrop-container { + position: relative; + top: -40%; + right: -35%; + width: 70%; + height: 100%; + } + + .backdrop { + right: 0; + width: 100%; + height: 100%; + object-fit: cover; + object-position: center 20%; + border-radius: 5px; + z-index: 1; + mask-image: linear-gradient( + to top, + rgba(0, 0, 0, 0) 10%, + rgba(0, 0, 0, 0.5) 15%, + rgba(0, 0, 0, 1) 30% + ); + -webkit-mask-image: linear-gradient( + to top, + rgba(0, 0, 0, 0) 10%, + rgba(0, 0, 0, 0.5) 15%, + rgba(0, 0, 0, 1) 30% + ); + } + + .backdrop-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.6); /* Adjust the alpha for dimness */ + border-radius: 5px; + z-index: 2; + mask-image: linear-gradient( + to top, + rgba(0, 0, 0, 0) 10%, + rgba(0, 0, 0, 0.5) 15%, + rgba(0, 0, 0, 1) 30% + ); + -webkit-mask-image: linear-gradient( + to top, + rgba(0, 0, 0, 0) 10%, + rgba(0, 0, 0, 0.5) 15%, + rgba(0, 0, 0, 1) 30% + ); + } + + .logo-container { + width: 45%; + height: 40%; + position: relative; + display: flex; + justify-content: left; + align-items: left; + } + + .logo { + position: relative; + max-height: 100%; + max-width: 100%; + width: auto; + z-index: 3; + top: 5em; + left: 8em; + } + + .featured-content { + position: absolute; + top: 0; + width: 100%; + height: 50px; + background-color: transparent; + color: #d3d3d3; + font-size: 22px; + display: none; + align-items: center; + justify-content: flex-start; + z-index: 2; + } + + .plot-container { + position: absolute; + bottom: 0; + color: #fff; + width: 50%; + height: 60%; + font-size: 15px; + padding: 10px 0 25px 15px; + border-radius: 5px; + z-index: 3; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + text-align: justify; + } + + .plot { + display: -webkit-box; + line-clamp: 4; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + left: 7.9em; + position: absolute; + top: 190px; + } + + .gradient-overlay { + position: absolute; + top: 0; + left: 0; + width: 70%; + height: 100%; + background: linear-gradient(to right, #000 49%, rgba(0, 0, 0, 0) 70%); + z-index: 2; + mask-image: linear-gradient( + to top, + rgba(0, 0, 0, 0) 8%, + rgba(0, 0, 0, 0.5) 10%, + rgba(0, 0, 0, 1) 12% + ); + -webkit-mask-image: linear-gradient( + to top, + rgba(0, 0, 0, 0) 8%, + rgba(0, 0, 0, 0.5) 10%, + rgba(0, 0, 0, 1) 12% + ); + } + .genre { + position: absolute; + top: calc(50% + 75px); + left: 8.4em; + text-align: center; + color: #fff; + font-family: "Titillium Web", sans-serif; + font-size: 14px; + z-index: 4; + } + .info-container { + position: absolute; + top: calc(50% + 0px); + display: flex; + align-items: center; + justify-content: center; + left: 2em !important; + color: #fff; + z-index: 4; + } + .rating-value { + font-family: "Titillium Web", sans-serif; + display: flex; + align-items: center; + margin: 0 6em; + z-index: 5; + position: relative; + top: 1.5em; + } + .runTime { + font-family: "Titillium Web", sans-serif; + font-weight: 500; + display: flex; + align-items: center; + margin: 0 8px; + margin-right: -3px; + } + .rating-value img { + margin-right: 6px; + } + .tomato-rating { + display: flex; + align-items: center; + margin-left: 0; + } + .tomato-rating img { + margin-left: 5px; + } + .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; + border: none; + font-weight: 600; + white-space: nowrap; + padding: 0 0.6em; + } + .date { + font-family: "Titillium Web", sans-serif; + font-weight: 500; + display: flex; + align-items: center; + margin-right: 5px; + margin-left: 2px; + } + .separator-icon { + margin-left: 5px; + margin-right: 5px; + font-size: 10px; + color: aquamarine; + } + .play-button { + position: absolute; + display: flex; + align-items: center; /* Center vertically */ + justify-content: center; /* Keep content aligned horizontally */ + padding: 10px 20px; + color: #fff; + background-color: rgba(255, 255, 255, 0); + border: none; + border-radius: 50px; /* Round the edges */ + cursor: pointer; + font-size: 14px; + font-weight: 300; + transition: background-color 0.3s; + z-index: 4; + top: calc(50% + 190px); + left: 6.8em; + } + + .play-icon { + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; /* Adjust the size of the play icon */ + width: 30px; /* Ensure the icon area is circular */ + height: 30px; + background-color: rgba( + 12, + 110, + 162, + 0.7 + ); /* Same as the button's background */ + border: 3px solid rgba(12, 110, 162, 1); + border-radius: 50%; /* Make the icon a perfect circle */ + } + + .play-text { + font-family: "Titillium Web", sans-serif; + margin-left: 10px; /* Space between icon and text */ + font-size: 14px; + color: #fff; + } +} + +@media only screen and (max-width: 767px) { + .backdrop, + .slide { + position: absolute; + } + + .arrow { + position: absolute; + /*top: 50%; + transform: translateY(-50%);*/ + bottom: 25px; + font-size: 24px; + cursor: pointer; + color: rgba(255, 255, 255, 0.6); + z-index: 4; + -webkit-tap-highlight-color: transparent; /* Disable blue tap highlight */ + } + + .left-arrow { + left: 10px; /* Position to the left */ + } + + .right-arrow { + right: 10px; /* Position to the right */ + } + + .featured-content, + .plot-container { + font-family: "Titillium Web", sans-serif; + left: 0; + } + + .plot, + body { + overflow: hidden; + } + + body { + margin: 0; + padding: 0; + } + + .fade-in { + opacity: 1 !important; + } + + .fade-out { + opacity: 0 !important; + } + + .dots-container { + position: absolute; + bottom: 11%; + left: 50%; + transform: translateX(-50%) scale(0.6); + z-index: 2; + display: flex; + gap: 5px; + background-color: #ffffff00; + border-radius: 50px; + justify-content: center; + align-items: center; + width: 140px; + height: 22px; + transition: opacity 0.5s ease-in-out; + } + + .dot { + display: inline-block; + width: 9px; + height: 9px; + margin: 0 5px; + background-color: #cecece; + border-radius: 50%; + transition: background-color 0.3s; + } + + .dot.active { + width: 32px; + height: 12px; + background-color: rgba(12, 110, 162, 0.7); + border-radius: 10px; /* Rounded rectangle shape */ + } + + #slides-container { + position: relative; + width: 92vw; + height: 650px; + overflow: hidden; + margin: 0 auto; + border-radius: 10px; + } + + .slide { + transition: opacity 0.5s ease-in-out; /* Smooth fade transition */ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: block; + } + + .slide.active { + opacity: 1; + display: block; + } + + .slide:focus { + outline: #fff solid 2px; + } + .logo { + position: absolute; + bottom: 28%; + left: 50%; + transform: translateX(-50%); + max-height: 60%; + max-width: 80%; + width: auto; + z-index: 3; + } + + .backdrop { + position: absolute; + top: 45px; + left: 0; + width: 100%; + height: calc(100% - 50px); + object-fit: cover; + object-position: center 20%; + z-index: 1; + border-radius: 13px; + mask-image: linear-gradient( + to top, + rgba(0, 0, 0, 0) 10%, + rgba(0, 0, 0, 0.5) 15%, + rgba(0, 0, 0, 1) 30% + ); + -webkit-mask-image: linear-gradient( + to top, + rgba(0, 0, 0, 0) 10%, + rgba(0, 0, 0, 0.5) 15%, + rgba(0, 0, 0, 1) 30% + ); + } + + .gradient-overlay { + position: absolute; + top: 45px; + left: 0; + width: 100%; + height: calc(100% - 50px); + background: rgba(0, 0, 0, 0.55); /* Semi-transparent overlay color */ + z-index: 2; + border-radius: 13px; + pointer-events: none; + mask-image: linear-gradient( + to top, + rgba(0, 0, 0, 0) 10%, + rgba(0, 0, 0, 0.5) 15%, + rgba(0, 0, 0, 1) 30% + ); + -webkit-mask-image: linear-gradient( + to top, + rgba(0, 0, 0, 0) 10%, + rgba(0, 0, 0, 0.5) 15%, + rgba(0, 0, 0, 1) 30% + ); + } + + .genre { + position: absolute; + bottom: 16%; + left: 50%; + transform: translateX(-50%); + text-align: center; + color: #fff; + width: 90%; + max-width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-family: "Titillium Web", sans-serif; + font-size: 1.1em; + font-weight: 500; + z-index: 4; + box-sizing: border-box; + } + .info-container { + position: absolute; + display: flex; + align-items: center; + justify-content: center; + bottom: 20%; + left: 50%; + transform: translateX(-50%); + font-size: 1.1em; + color: #fff; + z-index: 5; + width: 100%; + } + .rating-value { + font-family: "Titillium Web", sans-serif; + font-weight: 500; + display: flex; + align-items: center; + } + .date { + font-family: "Titillium Web", sans-serif; + font-weight: 500; + display: flex; + align-items: center; + margin-left: 2px; + } + .tomato-rating { + display: flex; + align-items: center; + } + .tomato-logo { + margin-right: 3px; + } + .critic-logo { + margin-left: 3px; + } + .imdb-logo { + margin-right: 3px; + } + .age-rating { + display: flex; + align-items: center; + border-radius: 5px; + background: rgb(255 255 255 / 0.8); + color: #000; + border: none; + font-weight: 600; + white-space: nowrap; + padding: 0 0.4em; + } + .separator-icon { + margin-left: 5px; + margin-right: 5px; + font-size: 1px; + color: aquamarine; + } + .featured-content, + .plot { + display: none; + } + + .play-button { + position: absolute; + display: flex; + align-items: center; /* Center vertically */ + justify-content: flex-start; /* Keep content aligned horizontally */ + padding: 10px 20px; + color: #fff; + background-color: rgba(255, 255, 255, 0); + border: none; + border-radius: 50px; /* Round the edges */ + cursor: pointer; + font-size: 14px; + font-weight: 300; + transition: background-color 0.3s; + z-index: 4; + bottom: 20px; + /*right: 0%;*/ + left: 50%; + transform: translateX(-50%) scale(1.2); + outline: none; /* Remove the default blue focus outline */ + -webkit-tap-highlight-color: transparent; /* Disable blue tap highlight */ + } + + .play-icon { + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; /* Adjust the size of the play icon */ + width: 20px; /* Ensure the icon area is circular */ + height: 20px; + background-color: rgba( + 12, + 110, + 162, + 0.7 + ); /* Same as the button's background */ + border: 1.5px solid rgba(12, 110, 162, 1); + border-radius: 50%; /* Make the icon a perfect circle */ + outline: none; /* Remove the default blue focus outline */ + -webkit-tap-highlight-color: transparent; /* Disable blue tap highlight */ + } + + .play-text { + display: block; + font-family: "Titillium Web", sans-serif; + margin-left: 5px; /* Space between icon and text */ + font-size: 14px; + color: #fff; + } +} diff --git a/slideshowpure.js b/slideshowpure.js new file mode 100644 index 0000000..819ceff --- /dev/null +++ b/slideshowpure.js @@ -0,0 +1,427 @@ +const slidesInit = () => { + const shuffleInterval = 8000; + let isTransitioning = false; + const listFileName = `${window.location.origin}/web/avatars/list.txt`; + const jsonCredentials = sessionStorage.getItem("json-credentials"); + const apiKey = sessionStorage.getItem("api-key"); + const serverId = '4810878e0ca94ff0b08cd0df6e483c4f'; + let userId = null; + let token = null; + const deviceId = localStorage.getItem("_deviceId2"); + console.log(deviceId); + if (jsonCredentials) { + const credentials = JSON.parse(jsonCredentials); + userId = credentials.Servers[0].UserId; + token = credentials.Servers[0].AccessToken; + } + const shuffleArray = (array) => array.sort(() => Math.random() - 0.5); + const truncateText = (element, maxLength) => { + let text = element.innerText; + if (text.length > maxLength) + element.innerText = text.substring(0, maxLength) + "..."; + }; + const createSlideElement = (item, title) => { + const itemId = item.Id; + const plot = item.Overview || "No overview available"; + const rating = item.CommunityRating; + const tomato = item.CriticRating; + const runtime = item.RunTimeTicks; + const genre = item.Genres; + const youtube = item.RemoteTrailers; + const age = item.OfficialRating; + const date = item.PremiereDate; + const season = item.ChildCount; + function createSeparator() { + const separatorHtml = + ''; + const tempDiv = document.createElement("div"); + tempDiv.innerHTML = separatorHtml; + return tempDiv.firstChild; + } + const slide = document.createElement("a"); + slide.className = "slide"; + slide.target = "_top"; + slide.rel = "noreferrer"; + slide.tabIndex = 0; + slide.style.display = "none"; + const backdrop = document.createElement("img"); + backdrop.className = "backdrop"; + backdrop.src = `${window.location.origin}/Items/${itemId}/Images/Backdrop/0`; + backdrop.alt = "Backdrop"; + const backdropOverlay = document.createElement("div"); + backdropOverlay.className = "backdrop-overlay"; + const backdropContainer = document.createElement("div"); + backdropContainer.className = "backdrop-container"; + backdropContainer.appendChild(backdrop); + backdropContainer.appendChild(backdropOverlay); + const logo = document.createElement("img"); + logo.className = "logo"; + logo.src = `${window.location.origin}/Items/${itemId}/Images/Logo`; + logo.alt = "Logo"; + const logoContainer = document.createElement("div"); + logoContainer.className = "logo-container"; + logoContainer.appendChild(logo); + const featuredContent = document.createElement("div"); + featuredContent.className = "featured-content"; + featuredContent.textContent = title; + const plotElement = document.createElement("div"); + plotElement.className = "plot"; + plotElement.textContent = plot; + truncateText(plotElement, 360); + const plotContainer = document.createElement("div"); + plotContainer.className = "plot-container"; + plotContainer.appendChild(plotElement); + const gradientOverlay = document.createElement("div"); + gradientOverlay.className = "gradient-overlay"; + const runTimeElement = document.createElement("div"); + runTimeElement.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: !0 }; + const formattedEndTime = endTime.toLocaleTimeString([], options); + runTimeElement.textContent = `Ends at ${formattedEndTime}`; + } else { + runTimeElement.textContent = `${season} Season${season > 1 ? "s" : ""}`; + } + const ratingTest = document.createElement("div"); + ratingTest.className = "rating-value"; + const imdbLogo = document.createElement("img"); + imdbLogo.className = "imdb-logo"; + imdbLogo.src = + "https://upload.wikimedia.org/wikipedia/commons/6/69/IMDB_Logo_2016.svg"; + imdbLogo.alt = "IMDb Logo"; + imdbLogo.style.width = "30px"; + imdbLogo.style.height = "30px"; + ratingTest.appendChild(imdbLogo); + if (typeof rating === "number") { + const formattedRating = rating.toFixed(1); + ratingTest.innerHTML += `${formattedRating} ⭐`; + } else { + console.error("Rating is undefined or not a number:", rating); + ratingTest.innerHTML += `N/A ⭐`; + } + ratingTest.appendChild(createSeparator()); + const tomatoRatingDiv = document.createElement("div"); + tomatoRatingDiv.className = "tomato-rating"; + const criticRating = item.CriticRating; + const tomatoLogo = document.createElement("img"); + tomatoLogo.className = "tomato-logo"; + const criticLogo = document.createElement("img"); + criticLogo.className = "critic-logo"; + tomatoLogo.src = + "https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Rotten_Tomatoes_positive_audience.svg/1920px-Rotten_Tomatoes_positive_audience.svg.png"; + let valueElement; + if (typeof criticRating === "number") { + valueElement = document.createTextNode(`${criticRating}% `); + } else { + valueElement = document.createTextNode(`N/A `); + } + if (criticRating === undefined || criticRating <= 59) { + criticLogo.src = + "https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Rotten_Tomatoes_rotten.svg/1024px-Rotten_Tomatoes_rotten.svg.png"; + criticLogo.alt = "Rotten Tomato"; + } else { + criticLogo.src = "https://i.imgur.com/iMfwDk7.png"; + criticLogo.alt = "Fresh Tomato"; + } + tomatoLogo.style.width = "15px"; + tomatoLogo.style.height = "17px"; + criticLogo.style.width = "15px"; + criticLogo.style.height = "15px"; + tomatoRatingDiv.appendChild(tomatoLogo); + tomatoRatingDiv.appendChild(valueElement); + tomatoRatingDiv.appendChild(criticLogo); + tomatoRatingDiv.appendChild(createSeparator()); + const ageRatingDiv = document.createElement("div"); + ageRatingDiv.className = "age-rating"; + if (item.OfficialRating) { + ageRatingDiv.innerHTML = `${item.OfficialRating}`; + } else { + ageRatingDiv.innerHTML = `N/A`; + } + const calender = "📅"; + const premiereDate = document.createElement("div"); + premiereDate.className = "date"; + const year = date ? new Date(date).getFullYear() : "N/A"; + premiereDate.textContent = isNaN(year) ? "N/A" : year; + ratingTest.appendChild(tomatoRatingDiv); + ratingTest.appendChild(document.createTextNode(calender)); + ratingTest.appendChild(premiereDate); + ratingTest.appendChild(createSeparator()); + ratingTest.appendChild(ageRatingDiv); + ratingTest.appendChild(createSeparator()); + ratingTest.appendChild(runTimeElement); + const genresArray = item.Genres; + function parseGenres(genresArray) { + if (genresArray && genresArray.length > 0) { + return genresArray.slice(0, 3).join(" 🔹 "); + } else { + return "No Genre Available"; + } + } + const genreElement = document.createElement("div"); + genreElement.className = "genre"; + genreElement.innerHTML = parseGenres(genresArray); + const infoContainer = document.createElement("div"); + infoContainer.className = "info-container"; + infoContainer.appendChild(ratingTest); + const playButton = document.createElement("button"); + playButton.className = "play-button"; + playButton.innerHTML = ` + + Details + `; + playButton.onclick = () => { + window.top.location.href = `/#!/details?id=${itemId}`; + //window.location.href = `/Videos/${itemId}/stream.mp4?Static=true&mediaSourceId=${itemId}&deviceId=${deviceId}&api_key=${apiKey}`; + //window.top.location.href = streamUrl; + }; + slide.append( + logoContainer, + backdropContainer, + gradientOverlay, + featuredContent, + plotContainer, + infoContainer, + genreElement, + playButton + ); + return slide; + }; + const createSlideForItem = async (item, title) => { + const container = document.getElementById("slides-container"); + const itemId = item.Id; + const backdropUrl = `${window.location.origin}/Items/${itemId}/Images/Backdrop/0`; + const logoUrl = `${window.location.origin}/Items/${itemId}/Images/Logo`; + const [backdropExists, logoExists] = await Promise.all([ + fetch(backdropUrl, { method: "HEAD" }).then((res) => res.ok), + fetch(logoUrl, { method: "HEAD" }).then((res) => res.ok), + ]); + if (backdropExists && logoExists) { + const slideElement = createSlideElement(item, title); + container.appendChild(slideElement); + console.log(`Added slide for item ${itemId}`); + if (container.children.length === 1) { + showSlide(0); + } + } else { + console.warn(`Skipping item ${itemId}: Missing backdrop or logo.`); + } + }; + const fetchItemDetails = async (itemId) => { + const response = await fetch( + `${window.location.origin}/Users/${userId}/Items/${itemId}`, + { + headers: { + Authorization: `MediaBrowser Client="Jellyfin Web", Device="YourDeviceName", DeviceId="YourDeviceId", Version="YourClientVersion", Token="${token}"`, + }, + } + ); + const item = await response.json(); + console.log("Item Title:", item.Name); + return item; + }; + const fetchItemIdsFromList = async () => { + try { + const response = await fetch(listFileName); + if (!response.ok) { + throw new Error("Failed to fetch list.txt"); + } + const text = await response.text(); + return text + .split("\n") + .map((id) => id.trim()) + .filter((id) => id); + } catch (error) { + console.error("Error fetching list.txt:", error); + return []; + } + }; + const fetchItemsFromServer = async () => { + try { + const response = await fetch( + `${window.location.origin}/Users/${userId}/Items?IncludeItemTypes=Movie,Series&Recursive=true&hasOverview=true&imageTypes=Logo,Backdrop&isPlayed=False&Limit=150`, + { + headers: { + Authorization: `MediaBrowser Client="Jellyfin Web", Device="YourDeviceName", DeviceId="YourDeviceId", Version="YourClientVersion", Token="${token}"`, + }, + } + ); + const data = await response.json(); + const items = data.Items; + const movies = items.filter((item) => item.Type === "Movie"); + const tvShows = items.filter((item) => item.Type === "Series"); + const shuffledMovies = shuffleArray(movies); + const shuffledTvShows = shuffleArray(tvShows); + const selectedMovies = shuffledMovies.slice(0, 15); + const selectedTvShows = shuffledTvShows.slice(0, 15); + const allItems = []; + const maxLength = Math.max(selectedMovies.length, selectedTvShows.length); + for (let i = 0; i < maxLength; i++) { + if (i < selectedMovies.length) allItems.push(selectedMovies[i]); + if (i < selectedTvShows.length) allItems.push(selectedTvShows[i]); + } + return allItems; + } catch (error) { + console.error("Error fetching items:", error); + return []; + } + }; + const createSlidesForItems = async (items) => { + await Promise.all( + items.map((item) => + createSlideForItem(item, item.Type === "Movie" ? "Movie" : "TV Show") + ) + ); + }; + const createPaginationDots = () => { + const dotsContainer = document.createElement("div"); + dotsContainer.className = "dots-container"; + for (let i = 0; i < 5; i++) { + const dot = document.createElement("span"); + dot.className = "dot"; + dotsContainer.appendChild(dot); + } + const container = document.getElementById("slides-container"); + container.appendChild(dotsContainer); + }; + const showSlide = (index) => { + const slides = document.querySelectorAll(".slide"); + const dots = document.querySelectorAll(".dot"); + slides.forEach((slide, i) => { + if (i === index) { + slide.style.display = "block"; + slide.offsetHeight; + slide.style.opacity = "1"; + slide.classList.add("active"); + } else { + slide.style.opacity = "0"; + slide.classList.remove("active"); + setTimeout(() => { + slide.style.display = "none"; + }, 500); + } + }); + dots.forEach((dot, i) => { + dot.classList.toggle("active", i === index % 5); + }); + }; + const initializeSlideshow = () => { + const slides = document.querySelectorAll(".slide"); + createPaginationDots(); + const container = document.getElementById("slides-container"); + let currentSlideIndex = 0; + let focusedSlide = null; + let containerFocused = !1; + const updateCurrentSlide = (index) => { + if (isTransitioning) return; // Skip if already transitioning + isTransitioning = true; // Set transitioning to true at the start + currentSlideIndex = (index + slides.length) % slides.length; + showSlide(currentSlideIndex); + // Re-enable arrows after a short delay to prevent rapid clicking + setTimeout(() => { + isTransitioning = false; // Reset after transition completes + }, 500); // Adjust the delay as needed (500ms is a reasonable starting point) + }; + const openActiveSlide = () => { + if (focusedSlide) { + window.location.href = focusedSlide.href; + } + }; + if (slides.length > 0) { + showSlide(currentSlideIndex); + container.style.display = "block"; + setTimeout(() => { + setInterval(() => { + updateCurrentSlide(currentSlideIndex + 1); + }, shuffleInterval); + }, 8000); + } + slides.forEach((slide) => { + slide.addEventListener( + "focus", + () => { + focusedSlide = slide; + container.classList.remove("disable-interaction"); + }, + !0 + ); + slide.addEventListener( + "blur", + () => { + if (focusedSlide === slide) { + focusedSlide = null; + } + }, + !0 + ); + }); + document.addEventListener("keydown", (event) => { + if (containerFocused) { + switch (event.keyCode) { + case 37: + updateCurrentSlide(currentSlideIndex - 1); + break; + case 39: + updateCurrentSlide(currentSlideIndex + 1); + break; + case 13: + case 32: + openActiveSlide(); + break; + } + } + }); + + const leftArrow = document.createElement("div"); + const rightArrow = document.createElement("div"); + leftArrow.classList.add("arrow", "left-arrow"); + rightArrow.classList.add("arrow", "right-arrow"); + leftArrow.innerHTML = ''; + rightArrow.innerHTML = ''; + container.appendChild(leftArrow); + container.appendChild(rightArrow); + leftArrow.addEventListener("click", () => + updateCurrentSlide(currentSlideIndex - 1) + ); + rightArrow.addEventListener("click", () => + updateCurrentSlide(currentSlideIndex + 1) + ); + container.addEventListener("focus", () => { + containerFocused = !0; + }); + container.addEventListener("blur", () => { + containerFocused = !1; + }); + }; + const initializeSlides = async () => { + const itemIds = await fetchItemIdsFromList(); + let items; + if (itemIds.length > 0) { + const itemPromises = itemIds.map((id) => fetchItemDetails(id)); + items = await Promise.all(itemPromises); + } else { + const allItems = await fetchItemsFromServer(); + const itemPromises = allItems.map((item) => fetchItemDetails(item.Id)); + items = await Promise.all(itemPromises); + } + items = shuffleArray(items); + await createSlidesForItems(items); + initializeSlideshow(); + }; + initializeSlides(); +}; +document.addEventListener("DOMContentLoaded", () => { + document.body.addEventListener("click", (event) => { + const homeButton = event.target.matches( + ".headerHomeButton, .css-17c09up, .mainDrawer-scrollContainer > a:nth-child(2)" + ); + if (homeButton) { + event.preventDefault(); + window.location.href = "/web/index.html#/home.html"; + setTimeout(handleHomeNavigation, 300); // Delay for UI update + } + }); +});