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 token = 'YOURAPIKEYHERE'; // Your Jellyfin API key
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 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 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 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 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 currentLocation = window.top.location.href;
let movieList = [], currentMovieIndex = 0;
let previousMovies = [];
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
//function fetchSponsorBlockOutro(videoId) {
const fetchSponsorBlockOutro = (videoId) => {
// @deprecated
const fetchSponsorBlockOutroOLD = (videoId) => {
return fetch(`https://sponsor.ajay.app/api/skipSegments?videoID=${videoId}&category=outro`)
.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 => {
console.error('Error fetching SponsorBlock data:', error);
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
let monitorOutroInterval = null; // Global interval variable
function monitorOutro(player, outroSegment) {
const interval = setInterval(() => {
if (monitorOutroInterval) { // Clear the interval if it's already running
clearInterval(monitorOutroInterval);
}
monitorOutroInterval = setInterval(() => {
if (!outroSegment || !player) {
clearInterval(interval);
console.log('Invalid outro segment or player not initialized');
clearInterval(monitorOutroInterval);
return;
}
const currentTime = player.getCurrentTime();
if (currentTime >= outroSegment[0] && currentTime < outroSegment[1]) {
clearInterval(interval);
clearInterval(monitorOutroInterval);
player.stopVideo(); // stop video
setTimeout(fetchRandomMovie, 100); // fetch next movie
}
@@ -247,13 +292,11 @@ const createSlideElement = (movie, hasVideo = false) => {
width: '100%',
videoId,
playerVars: {
mute: 0, // Change to start the video muted MARK: set muted, not officaly refreneced by youtube API, but working...
controls: 0, // Hide the controls
mute: isMuted ? 1 : 0, // CHeck if the video should start muted
controls: disableTrailerControls ? 0 : 1, // Hide the controls
disablekb: 1, // Disable keyboard controls
fs: 1, // Enavle fullscreen
rel: 0, // Disable related videos
modestbranding: 1, // Hide the YouTube logo
showinfo: 0, // Hide the video title
iv_load_policy: 3, // Disable annotations
},
events: {
'onReady': event => {
@@ -266,7 +309,7 @@ const createSlideElement = (movie, hasVideo = false) => {
console.log('No outro segment found/provided');
}
}).catch(error => {
console.error('Error fetching SponsorBlock outro segment:', error);
console.error('Error reading SponsorBlock outro segment:', error);
});
}
if (trailerMaxLength > 0) {
@@ -283,7 +326,7 @@ const createSlideElement = (movie, hasVideo = false) => {
if (isMuted) {
event.target.setVolume(0); // Mute the video if the setting is MuteOn
} else {
event.target.setVolume(4);
event.target.setVolume(unmutedVolume); // Set the volume, value between 0 and 100
}
event.target.playVideo();
},
@@ -320,6 +363,7 @@ const createSlideElement = (movie, hasVideo = false) => {
'onError': () => {
console.error(`YouTube prevented playback of '${movie.Name}'`);
if (player) {
clearInterval(monitorOutroInterval);
player.destroy();
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 {
console.log(`Trailer disabled for '${movie.Name}'`);
startSlideChangeTimer();
}

View File

@@ -1,21 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<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>
<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" href="styles.css">
<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" href="styles.css">
</head>
<body>
<div id="slides-container"></div>
<div id="video-overlay" style="display: none;">
<div id="slides-container"></div>
<div id="video-overlay" style="display: none;">
<div id="video-overlay-content">
<span id="close-overlay" class="fas fa-times"></span>
<iframe id="trailer-video" width="100%" height="100%" frameborder="0" allowfullscreen></iframe>
</div>
</div>
<script src="script.js"></script>
<script src="script.js"></script>
<script src="https://www.youtube.com/iframe_api"></script>
</body>
</html>

View File

@@ -208,6 +208,7 @@ body {
max-width: 96vw;
opacity: 1;
-webkit-line-clamp: 2;
line-clamp: 2;
max-height: 7.8em;
text-align: center;
}
@@ -307,17 +308,17 @@ body {
transform: scale(1);
}
.slide:hover .clickable-overlay {}
/*.slide:hover .clickable-overlay {}*/
.slide:hover .clickable-overlay::before {
opacity: 0;
backdrop-filter: blur(0px);
}
/*
.slide:hover .logo {}
.slide:hover .plot {}
*/
.slide:hover .lorem-ipsum::before {
opacity: 1;
backdrop-filter: blur(2px);
@@ -362,6 +363,7 @@ body {
font-size: 90%;
bottom: 0.5em;
-webkit-line-clamp: 2;
line-clamp: 2;
max-height: 3.3em;
overflow: hidden;
width: 98vw !important;
@@ -641,8 +643,8 @@ body {
display: inline-flex;
justify-content: center;
align-items: center;
width: 1em;
height: 1em;
width: 1.2em;
height: 1.2em;
border-radius: 50%;
overflow: hidden;
transition: background 0.3s, color 0.3s;
@@ -655,8 +657,8 @@ body {
display: inline-flex;
justify-content: center;
align-items: center;
width: 1em;
height: 1em;
width: 1.2em;
height: 1.2em;
border-radius: 50%;
overflow: hidden;
transition: background 0.3s, color 0.3s;
@@ -678,6 +680,7 @@ body {
border-top-right-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%);
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 {
@@ -693,6 +696,7 @@ body {
opacity: 1;
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%);
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;
}
@@ -885,6 +889,7 @@ body {
font-size: 133%;
}
/*
.backdrop {}
.age-rating {}
@@ -896,6 +901,7 @@ body {
.genres {}
.lorem-ipsum {}
*/
}
@media (min-width: 3000px) {
@@ -903,6 +909,7 @@ body {
font-size: 200%;
}
/*
.age-rating {}
.skip-button {}
@@ -914,6 +921,7 @@ body {
.genres {}
.lorem-ipsum {}
*/
}
#video-overlay {