This commit is contained in:
MLH
2024-12-27 00:32:26 +01:00
parent d9e638ec9e
commit 8018010aae
3 changed files with 87 additions and 45 deletions

View File

@@ -1,4 +1,4 @@
let title = 'Spotlight'; // Title of the slideshow let title = 'Spotlight'; // Title of the slideshow TBD
let listFileName = 'list.txt'; // Name of the file containing the list of movie IDs let listFileName = 'list.txt'; // Name of the file containing the list of movie IDs
let token = 'YOURAPIKEYHERE'; // Your Jellyfin API key let token = 'YOURAPIKEYHERE'; // Your Jellyfin API key
let moviesSeriesBoth = 3; // 1 for movies, 2 for series, 3 for both let moviesSeriesBoth = 3; // 1 for movies, 2 for series, 3 for both
@@ -6,43 +6,88 @@ let shuffleInterval = 15000; // Time in milliseconds before the next slide is sh
let useTrailers = true; // Set to false to disable trailers let useTrailers = true; // Set to false to disable trailers
let setRandomMovie = true; // Set to false to disable random movie selection from the list let setRandomMovie = true; // Set to false to disable random movie selection from the list
let showOnOtherPages = false; // Set to true to show the slideshow on all pages eg. favorites tab, requests tab, etc. let showOnOtherPages = false; // Set to true to show the slideshow on all pages eg. favorites tab, requests tab, etc.
//let showTitle = false; // Set to false to hide the title //let showTitle = false; // Set to false to hide the title TBD
let disableTrailerControls = true; // Set to false to enable trailer controls
let setMuted = true; // Set to false to disable unmuting the video on hover
let umuteOnHover = true; // Set to false to disable unmuting the video on hover let umuteOnHover = true; // Set to false to disable unmuting the video on hover
let isMuted = true; // Set to false to start with sound let unmutedVolume = 20; // Set the volume level when the video is unmuted
let useSponsorBlock = true; // Set to true to use SponsorBlock data to skip intro/outro segments of trailers let useSponsorBlock = true; // Set to true to use SponsorBlock data to skip intro/outro segments of trailers
let plotMaxLength = 550; // Maximum number of characters in the plot let plotMaxLength = 550; // Maximum number of characters in the plot
let trailerMaxLength = 0; // Default value 0; length measured in ms let trailerMaxLength = 0; // Default value 0; length measured in ms, set to 0 to disable, could be used instead of SponsorBlock
let isMuted = true; // Default value true; set to false to start the video unmuted
// variables
let isChangingSlide = false, player = null, slideChangeTimeout = null, isHomePageActive = false; let isChangingSlide = false, player = null, slideChangeTimeout = null, isHomePageActive = false;
let currentLocation = window.top.location.href; let currentLocation = window.top.location.href;
let movieList = [], currentMovieIndex = 0; let movieList = [], currentMovieIndex = 0;
let previousMovies = []; let previousMovies = [];
let forwardMovies = []; let forwardMovies = [];
if (setMuted) {
const slidesContainer = document.getElementById('slides-container');
slidesContainer.addEventListener('mouseenter', () => {
if (player) {
player.unMute();
isMuted = false;
}
});
slidesContainer.addEventListener('mouseleave', () => {
if (player) {
player.mute();
isMuted = true;
}
});
}
// Get SponsorBlock-Data for the outro segment of the trailer // Get SponsorBlock-Data for the outro segment of the trailer
//function fetchSponsorBlockOutro(videoId) { //function fetchSponsorBlockOutro(videoId) {
const fetchSponsorBlockOutro = (videoId) => { // @deprecated
const fetchSponsorBlockOutroOLD = (videoId) => {
return fetch(`https://sponsor.ajay.app/api/skipSegments?videoID=${videoId}&category=outro`) return fetch(`https://sponsor.ajay.app/api/skipSegments?videoID=${videoId}&category=outro`)
.then(response => response.json()) .then(response => response.json())
.then(segments => { segments.length > 0 ? segments[0].segment : null; }) .then(segments => {
return segments.length > 0 ? segments[0].segment : null;
})
.catch(error => { .catch(error => {
console.error('Error fetching SponsorBlock data:', error); console.error('Error fetching SponsorBlock data:', error);
return null; return null;
}); });
}; };
const fetchSponsorBlockOutro = async (videoId) => {
try {
const response = await fetch(`https://sponsor.ajay.app/api/skipSegments?videoID=${videoId}&category=outro`);
const segments = await response.json();
if (segments.length > 0 && Array.isArray(segments[0].segment)) {
return segments[0].segment; // returns array: [start, end]
}
return null;
} catch (error) {
console.error('Error fetching SponsorBlock data:', error);
return null;
}
};
// Monitor the video player for the outro segment // Monitor the video player for the outro segment
let monitorOutroInterval = null; // Global interval variable
function monitorOutro(player, outroSegment) { function monitorOutro(player, outroSegment) {
const interval = setInterval(() => { if (monitorOutroInterval) { // Clear the interval if it's already running
clearInterval(monitorOutroInterval);
}
monitorOutroInterval = setInterval(() => {
if (!outroSegment || !player) { if (!outroSegment || !player) {
clearInterval(interval); console.log('Invalid outro segment or player not initialized');
clearInterval(monitorOutroInterval);
return; return;
} }
const currentTime = player.getCurrentTime(); const currentTime = player.getCurrentTime();
if (currentTime >= outroSegment[0] && currentTime < outroSegment[1]) { if (currentTime >= outroSegment[0] && currentTime < outroSegment[1]) {
clearInterval(interval); clearInterval(monitorOutroInterval);
player.stopVideo(); // stop video player.stopVideo(); // stop video
setTimeout(fetchRandomMovie, 100); // fetch next movie setTimeout(fetchRandomMovie, 100); // fetch next movie
} }
@@ -247,16 +292,14 @@ const createSlideElement = (movie, hasVideo = false) => {
width: '100%', width: '100%',
videoId, videoId,
playerVars: { playerVars: {
mute: 0, // Change to start the video muted MARK: set muted, not officaly refreneced by youtube API, but working... mute: isMuted ? 1 : 0, // CHeck if the video should start muted
controls: 0, // Hide the controls controls: disableTrailerControls ? 0 : 1, // Hide the controls
disablekb: 1, // Disable keyboard controls disablekb: 1, // Disable keyboard controls
fs: 1, // Enavle fullscreen fs: 1, // Enavle fullscreen
rel: 0, // Disable related videos iv_load_policy: 3, // Disable annotations
modestbranding: 1, // Hide the YouTube logo
showinfo: 0, // Hide the video title
}, },
events: { events: {
'onReady': event => { 'onReady': event => {
if (useSponsorBlock) { if (useSponsorBlock) {
fetchSponsorBlockOutro(videoId).then(outroSegment => { fetchSponsorBlockOutro(videoId).then(outroSegment => {
if (outroSegment) { if (outroSegment) {
@@ -266,7 +309,7 @@ const createSlideElement = (movie, hasVideo = false) => {
console.log('No outro segment found/provided'); console.log('No outro segment found/provided');
} }
}).catch(error => { }).catch(error => {
console.error('Error fetching SponsorBlock outro segment:', error); console.error('Error reading SponsorBlock outro segment:', error);
}); });
} }
if (trailerMaxLength > 0) { if (trailerMaxLength > 0) {
@@ -283,7 +326,7 @@ const createSlideElement = (movie, hasVideo = false) => {
if (isMuted) { if (isMuted) {
event.target.setVolume(0); // Mute the video if the setting is MuteOn event.target.setVolume(0); // Mute the video if the setting is MuteOn
} else { } else {
event.target.setVolume(4); event.target.setVolume(unmutedVolume); // Set the volume, value between 0 and 100
} }
event.target.playVideo(); event.target.playVideo();
}, },
@@ -320,6 +363,7 @@ const createSlideElement = (movie, hasVideo = false) => {
'onError': () => { 'onError': () => {
console.error(`YouTube prevented playback of '${movie.Name}'`); console.error(`YouTube prevented playback of '${movie.Name}'`);
if (player) { if (player) {
clearInterval(monitorOutroInterval);
player.destroy(); player.destroy();
player = null; player = null;
} }
@@ -344,21 +388,7 @@ const createSlideElement = (movie, hasVideo = false) => {
} }
}); });
videoContainer.addEventListener('mouseenter', () => {
if (player && umuteOnHover) {
player.unMute();
isMuted = false;
}
});
videoContainer.addEventListener('mouseleave', () => {
if (player && umuteOnHover) {
player.mute();
isMuted = true;
}
});
} else { } else {
console.log(`Trailer disabled for '${movie.Name}'`);
startSlideChangeTimer(); startSlideChangeTimer();
} }

View File

@@ -1,21 +1,25 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.1/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.1/css/all.min.css">
<title>Jellyfin Spotlight v2.5.0 Fork v1.2</title> <title>Jellyfin Spotlight v2.5.0 Fork v1.2</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" /> <link rel="stylesheet"
<link rel="stylesheet" href="styles.css"> href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
<link rel="stylesheet" href="styles.css">
</head> </head>
<body> <body>
<div id="slides-container"></div> <div id="slides-container"></div>
<div id="video-overlay" style="display: none;"> <div id="video-overlay" style="display: none;">
<div id="video-overlay-content"> <div id="video-overlay-content">
<span id="close-overlay" class="fas fa-times"></span> <span id="close-overlay" class="fas fa-times"></span>
<iframe id="trailer-video" width="100%" height="100%" frameborder="0" allowfullscreen></iframe> <iframe id="trailer-video" width="100%" height="100%" frameborder="0" allowfullscreen></iframe>
</div> </div>
</div> </div>
<script src="script.js"></script> <script src="script.js"></script>
<script src="https://www.youtube.com/iframe_api"></script> <script src="https://www.youtube.com/iframe_api"></script>
</body> </body>
</html>
</html>

View File

@@ -208,6 +208,7 @@ body {
max-width: 96vw; max-width: 96vw;
opacity: 1; opacity: 1;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
line-clamp: 2;
max-height: 7.8em; max-height: 7.8em;
text-align: center; text-align: center;
} }
@@ -307,17 +308,17 @@ body {
transform: scale(1); transform: scale(1);
} }
.slide:hover .clickable-overlay {} /*.slide:hover .clickable-overlay {}*/
.slide:hover .clickable-overlay::before { .slide:hover .clickable-overlay::before {
opacity: 0; opacity: 0;
backdrop-filter: blur(0px); backdrop-filter: blur(0px);
} }
/*
.slide:hover .logo {} .slide:hover .logo {}
.slide:hover .plot {} .slide:hover .plot {}
*/
.slide:hover .lorem-ipsum::before { .slide:hover .lorem-ipsum::before {
opacity: 1; opacity: 1;
backdrop-filter: blur(2px); backdrop-filter: blur(2px);
@@ -362,6 +363,7 @@ body {
font-size: 90%; font-size: 90%;
bottom: 0.5em; bottom: 0.5em;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
line-clamp: 2;
max-height: 3.3em; max-height: 3.3em;
overflow: hidden; overflow: hidden;
width: 98vw !important; width: 98vw !important;
@@ -641,8 +643,8 @@ body {
display: inline-flex; display: inline-flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
width: 1em; width: 1.2em;
height: 1em; height: 1.2em;
border-radius: 50%; border-radius: 50%;
overflow: hidden; overflow: hidden;
transition: background 0.3s, color 0.3s; transition: background 0.3s, color 0.3s;
@@ -655,8 +657,8 @@ body {
display: inline-flex; display: inline-flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
width: 1em; width: 1.2em;
height: 1em; height: 1.2em;
border-radius: 50%; border-radius: 50%;
overflow: hidden; overflow: hidden;
transition: background 0.3s, color 0.3s; transition: background 0.3s, color 0.3s;
@@ -678,6 +680,7 @@ body {
border-top-right-radius: 1em; border-top-right-radius: 1em;
border-top-left-radius: 1em; border-top-left-radius: 1em;
-webkit-mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.25) 3%, rgba(0, 0, 0, 0.5) 7%, rgba(0, 0, 0, 0.75) 15%, rgba(0, 0, 0, 0.9) 25%, rgba(0, 0, 0, 1) 35%, rgba(0, 0, 0, 1) 100%); -webkit-mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.25) 3%, rgba(0, 0, 0, 0.5) 7%, rgba(0, 0, 0, 0.75) 15%, rgba(0, 0, 0, 0.9) 25%, rgba(0, 0, 0, 1) 35%, rgba(0, 0, 0, 1) 100%);
mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.25) 3%, rgba(0, 0, 0, 0.5) 7%, rgba(0, 0, 0, 0.75) 15%, rgba(0, 0, 0, 0.9) 25%, rgba(0, 0, 0, 1) 35%, rgba(0, 0, 0, 1) 100%);
} }
.text-container::after { .text-container::after {
@@ -693,6 +696,7 @@ body {
opacity: 1; opacity: 1;
backdrop-filter: blur(0px); backdrop-filter: blur(0px);
-webkit-mask-image: linear-gradient(0deg, rgb(0% 0% 0% / 0.98) 0%, rgb(0% 0% 0% / 0.9705847873975829) 6.25%, rgb(0% 0% 0% / 0.9427009709305305) 12.5%, rgb(0% 0% 0% / 0.8974201100282472) 18.75%, rgb(0% 0% 0% / 0.8364823227814083) 25%, rgb(0% 0% 0% / 0.7622294141796051) 31.25%, rgb(0% 0% 0% / 0.6775148818588941) 37.5%, rgb(0% 0% 0% / 0.5855942577879029) 43.75%, rgb(0% 0% 0% / 0.49000000000000005) 50%, rgb(0% 0% 0% / 0.39440574221209723) 56.25%, rgb(0% 0% 0% / 0.3024851181411061) 62.5%, rgb(0% 0% 0% / 0.217770585820395) 68.75%, rgb(0% 0% 0% / 0.14351767721859177) 75%, rgb(0% 0% 0% / 0.0825798899717528) 81.25%, rgb(0% 0% 0% / 0.03729902906946947) 87.5%, rgb(0% 0% 0% / 0.009415212602417067) 93.75%, rgb(0% 0% 0% / 0) 100%); -webkit-mask-image: linear-gradient(0deg, rgb(0% 0% 0% / 0.98) 0%, rgb(0% 0% 0% / 0.9705847873975829) 6.25%, rgb(0% 0% 0% / 0.9427009709305305) 12.5%, rgb(0% 0% 0% / 0.8974201100282472) 18.75%, rgb(0% 0% 0% / 0.8364823227814083) 25%, rgb(0% 0% 0% / 0.7622294141796051) 31.25%, rgb(0% 0% 0% / 0.6775148818588941) 37.5%, rgb(0% 0% 0% / 0.5855942577879029) 43.75%, rgb(0% 0% 0% / 0.49000000000000005) 50%, rgb(0% 0% 0% / 0.39440574221209723) 56.25%, rgb(0% 0% 0% / 0.3024851181411061) 62.5%, rgb(0% 0% 0% / 0.217770585820395) 68.75%, rgb(0% 0% 0% / 0.14351767721859177) 75%, rgb(0% 0% 0% / 0.0825798899717528) 81.25%, rgb(0% 0% 0% / 0.03729902906946947) 87.5%, rgb(0% 0% 0% / 0.009415212602417067) 93.75%, rgb(0% 0% 0% / 0) 100%);
mask-image: linear-gradient(0deg, rgb(0% 0% 0% / 0.98) 0%, rgb(0% 0% 0% / 0.9705847873975829) 6.25%, rgb(0% 0% 0% / 0.9427009709305305) 12.5%, rgb(0% 0% 0% / 0.8974201100282472) 18.75%, rgb(0% 0% 0% / 0.8364823227814083) 25%, rgb(0% 0% 0% / 0.7622294141796051) 31.25%, rgb(0% 0% 0% / 0.6775148818588941) 37.5%, rgb(0% 0% 0% / 0.5855942577879029) 43.75%, rgb(0% 0% 0% / 0.49000000000000005) 50%, rgb(0% 0% 0% / 0.39440574221209723) 56.25%, rgb(0% 0% 0% / 0.3024851181411061) 62.5%, rgb(0% 0% 0% / 0.217770585820395) 68.75%, rgb(0% 0% 0% / 0.14351767721859177) 75%, rgb(0% 0% 0% / 0.0825798899717528) 81.25%, rgb(0% 0% 0% / 0.03729902906946947) 87.5%, rgb(0% 0% 0% / 0.009415212602417067) 93.75%, rgb(0% 0% 0% / 0) 100%);
pointer-events: none; pointer-events: none;
} }
@@ -885,6 +889,7 @@ body {
font-size: 133%; font-size: 133%;
} }
/*
.backdrop {} .backdrop {}
.age-rating {} .age-rating {}
@@ -896,6 +901,7 @@ body {
.genres {} .genres {}
.lorem-ipsum {} .lorem-ipsum {}
*/
} }
@media (min-width: 3000px) { @media (min-width: 3000px) {
@@ -903,6 +909,7 @@ body {
font-size: 200%; font-size: 200%;
} }
/*
.age-rating {} .age-rating {}
.skip-button {} .skip-button {}
@@ -914,6 +921,7 @@ body {
.genres {} .genres {}
.lorem-ipsum {} .lorem-ipsum {}
*/
} }
#video-overlay { #video-overlay {