From 0a5f0f41b6409aa15131634dafa66e3749e5667f Mon Sep 17 00:00:00 2001
From: brys0 <35676267+brys0@users.noreply.github.com>
Date: Tue, 11 Feb 2025 12:35:22 -0600
Subject: [PATCH 1/8] lint: Add basic jsdoc for credential grabbing
---
slideshowpure.js | 94 +++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 81 insertions(+), 13 deletions(-)
diff --git a/slideshowpure.js b/slideshowpure.js
index 8f98520..f9c6bfe 100644
--- a/slideshowpure.js
+++ b/slideshowpure.js
@@ -1,23 +1,57 @@
+
+/**
+ * Credentials for a given server
+ * @typedef {Object} ServerCredentials
+ * @property {string} Id
+ * @property {string} AccessToken
+ */
+
+/**
+ * Credentials
+ * @typedef {Object} Credentials
+ * @property {ServerCredentials[]} Servers
+ */
+
+/**
+ * Fetches the credentials inside of localstorage
+ * @returns {{token: string, userId: string}} Credential resource
+ */
+const getJellyfinCredentials = () => {
+ const jellyfinCreds = localStorage.getItem('jellyfin_credentials');
+
+ try {
+ /**
+ * @type {Credentials}
+ */
+ const serverCredentials = JSON.parse(jellyfinCreds);
+
+ const firstServer = serverCredentials.Servers[0];
+
+ if (!firstServer) {
+ console.error('Could not find credentials for the client');
+ return
+ }
+
+ return firstServer.AccessToken;
+ } catch (e) {
+ console.error('Could not parse jellyfin credentials', e);
+ }
+}
+
const slidesInit = () => {
const shuffleInterval = 8000;
let isTransitioning = false;
const listFileName = `${window.location.origin}/web/avatars/list.txt`;
- const jsonCredentials = sessionStorage.getItem("json-credentials");
- 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 { token, userId } = getJellyfinCredentials();
+
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";
@@ -46,33 +80,43 @@ const slidesInit = () => {
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();
@@ -83,8 +127,10 @@ const slidesInit = () => {
} 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 =
@@ -93,6 +139,7 @@ const slidesInit = () => {
imdbLogo.style.width = "30px";
imdbLogo.style.height = "30px";
ratingTest.appendChild(imdbLogo);
+
if (typeof rating === "number") {
const formattedRating = rating.toFixed(1);
ratingTest.innerHTML += `${formattedRating} ⭐`;
@@ -101,21 +148,25 @@ const slidesInit = () => {
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";
+ tomatoLogo.src =
+ "https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Rotten_Tomatoes_positive_audience.svg/1920px-Rotten_Tomatoes_positive_audience.svg.png";
+
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";
@@ -128,22 +179,28 @@ const slidesInit = () => {
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);
@@ -151,6 +208,7 @@ const slidesInit = () => {
ratingTest.appendChild(ageRatingDiv);
ratingTest.appendChild(createSeparator());
ratingTest.appendChild(runTimeElement);
+
const genresArray = item.Genres;
function parseGenres(genresArray) {
if (genresArray && genresArray.length > 0) {
@@ -159,29 +217,36 @@ const slidesInit = () => {
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 = `
Play Now
`;
+
playButton.onclick = async () => {
if (!window.ApiClient) {
console.error("Jellyfin API client is not available.");
return;
}
+
const apiClient = window.ApiClient;
const userId = apiClient.getCurrentUserId();
+
if (!userId) {
console.error("User not found.");
return;
}
+
try {
const sessions = await apiClient.getJSON(
apiClient.serverAddress() + "/Sessions"
@@ -209,15 +274,18 @@ const slidesInit = () => {
console.error("Error fetching sessions:", error);
}
};
+
const detailButton = document.createElement("button");
detailButton.className = "detail-button";
detailButton.innerHTML = `
More Details
`;
+
detailButton.onclick = () => {
window.top.location.href = `/#!/details?id=${itemId}`;
};
+
slide.append(
logoContainer,
backdropContainer,
From 69b5b3416cf2c3c8a5778c2d642c6f864e863b80 Mon Sep 17 00:00:00 2001
From: brys0 <35676267+brys0@users.noreply.github.com>
Date: Tue, 11 Feb 2025 12:39:35 -0600
Subject: [PATCH 2/8] fix duplication of genres and criticRating
---
slideshowpure.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/slideshowpure.js b/slideshowpure.js
index 4bde05f..2028767 100644
--- a/slideshowpure.js
+++ b/slideshowpure.js
@@ -56,13 +56,14 @@ const slidesInit = () => {
const itemId = item.Id;
const plot = item.Overview || "No overview available";
const rating = item.CommunityRating;
- const tomato = item.CriticRating;
+ const criticRating = item.CriticRating;
const runtime = item.RunTimeTicks;
- const genre = item.Genres;
+ const genresArray = item.Genres;
const youtube = item.RemoteTrailers;
const age = item.OfficialRating;
const date = item.PremiereDate;
const season = item.ChildCount;
+
function createSeparator() {
const separatorHtml =
'';
@@ -209,7 +210,6 @@ const slidesInit = () => {
ratingTest.appendChild(createSeparator());
ratingTest.appendChild(runTimeElement);
- const genresArray = item.Genres;
function parseGenres(genresArray) {
if (genresArray && genresArray.length > 0) {
return genresArray.slice(0, 3).join(" 🔹 ");
From d7ba06356af592d29af7e83f583fb78b8c397e7e Mon Sep 17 00:00:00 2001
From: brys0 <35676267+brys0@users.noreply.github.com>
Date: Tue, 11 Feb 2025 12:41:20 -0600
Subject: [PATCH 3/8] return token and userid inside object in
jellyfinCredentials
---
slideshowpure.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/slideshowpure.js b/slideshowpure.js
index 2028767..0b6e207 100644
--- a/slideshowpure.js
+++ b/slideshowpure.js
@@ -32,7 +32,7 @@ const getJellyfinCredentials = () => {
return
}
- return firstServer.AccessToken;
+ return { token: firstServer.AccessToken, userId: firstServer.AccessToken };
} catch (e) {
console.error('Could not parse jellyfin credentials', e);
}
From 50fae42dbf34f18171a016278877935d322a6346 Mon Sep 17 00:00:00 2001
From: M0RPH3US
Date: Wed, 12 Feb 2025 01:58:02 +0530
Subject: [PATCH 4/8] Fix Typo
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index d8ef209..7baaf49 100644
--- a/README.md
+++ b/README.md
@@ -121,8 +121,8 @@ Here I present my version of the same with some code improvements, loading optim
main.jellyfin.bundle.js
1. Similarly, search for `main.jellyfin.bundle.js` in the `jellyfin-web` directory. Open it with any code editor with administrator privileges.
-2. Search for `this.playbackManager = e;`
-3. Right after the `;`, paste the code block `window.PlaybackManager = this.playbackManager;console.log("PlaybackManager is now globally available:", window.PlaybackManager);`
+2. Search for `this.playbackManager = e,`
+3. Right after the `,`, paste the code block `window.PlaybackManager = this.playbackManager;console.log("PlaybackManager is now globally available:", window.PlaybackManager);`
From b47051831445404af0878d1d74790e40752d414b Mon Sep 17 00:00:00 2001
From: M0RPH3US
Date: Wed, 12 Feb 2025 17:12:23 +0530
Subject: [PATCH 5/8] Update slideshowpure.js
Fixed Typo
---
slideshowpure.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/slideshowpure.js b/slideshowpure.js
index 0b6e207..e436b45 100644
--- a/slideshowpure.js
+++ b/slideshowpure.js
@@ -32,7 +32,7 @@ const getJellyfinCredentials = () => {
return
}
- return { token: firstServer.AccessToken, userId: firstServer.AccessToken };
+ return { token: firstServer.AccessToken, userId: firstServer.UserId };
} catch (e) {
console.error('Could not parse jellyfin credentials', e);
}
From 48ebb488ed833e5b66413df54c566cdaaeb19834 Mon Sep 17 00:00:00 2001
From: M0RPH3US
Date: Wed, 12 Feb 2025 17:14:16 +0530
Subject: [PATCH 6/8] Update README.md
Removed Session storage code from index.html
---
README.md | 57 -------------------------------------------------------
1 file changed, 57 deletions(-)
diff --git a/README.md b/README.md
index 7baaf49..761e003 100644
--- a/README.md
+++ b/README.md
@@ -43,63 +43,6 @@ Here I present my version of the same with some code improvements, loading optim
2. Search for `