From 1b05d4f8636ac66266cb62cdb611cb8ce13cda7f Mon Sep 17 00:00:00 2001 From: CodeDevMLH <145071728+CodeDevMLH@users.noreply.github.com> Date: Sat, 27 Sep 2025 02:19:09 +0200 Subject: [PATCH] add auto seasonal lists --- SEASONAL_LISTS.md | 52 +++++++++++++++++++++++++++ list.txt | 2 +- script.js | 91 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 SEASONAL_LISTS.md diff --git a/SEASONAL_LISTS.md b/SEASONAL_LISTS.md new file mode 100644 index 0000000..d15d8d1 --- /dev/null +++ b/SEASONAL_LISTS.md @@ -0,0 +1,52 @@ +# Seasonal Lists Documentation + +This document explains how to use seasonal lists with the Jellyfin Spotlight system. + +## Configuration + +To enable seasonal lists, set `useSeasonalLists = true` in the main script.js file. + +## Seasonal Periods + +The system automatically detects the following periods: + +### Special Events (take precedence over seasons) +- **New Year**: January 1-7 → `newyear_list.txt` +- **Valentine's day**: February 10-20 → `valentine_list.txt` +- **Easter**: 1 week around Easter Sunday → `easter_list.txt` +- **Halloween**: October 20-31 → `halloween_list.txt` + +### Regular Seasons +- **Spring**: March-May → `spring_list.txt` +- **Summer**: June-August → `summer_list.txt` +- **Autumn**: September-November → `autumn_list.txt` +- **Winter**: December-February → `winter_list.txt` + +## List Files + +Create the following files in your `featured` directory: + +- `spring_list.txt` - Spring movies/shows +- `summer_list.txt` - Summer movies/shows +- `autumn_list.txt` - Autumn movies/shows +- `winter_list.txt` - Winter movies/shows +- `newyear_list.txt` - New Year themed content +- `valentine_list.txt` - Romance/Valentine themed content +- `easter_list.txt` - Easter/Family themed content +- `halloween_list.txt` - Horror/Halloween themed content + +## File Format + +Each seasonal list file follows the same format as the main `list.txt`: + +``` +Title of List [muteon/muteoff] +movie_id_1 +movie_id_2 +series_id_1 +... +``` + +## Fallback + +If seasonal lists are disabled or a seasonal file doesn't exist, the system will fall back to using the default `list.txt` file. \ No newline at end of file diff --git a/list.txt b/list.txt index 3c0c9d3..6c064ae 100644 --- a/list.txt +++ b/list.txt @@ -1,4 +1,4 @@ -Spotlight MuteOn +Title of List [muteon/muteoff] f81c9b854e3edc62fb049e252c488115 Hunger Games 7d515072462d6cedd74de8e2df71888f Interstellar df4f3da3066455404e6b874d22ba86aa Fast X diff --git a/script.js b/script.js index d5e9e74..2892816 100644 --- a/script.js +++ b/script.js @@ -15,6 +15,19 @@ let plotMaxLength = 550; // Maximum number of characters in the plot let trailerMaxLength = 0; // Default value 0; length measured in ms, set to 0 to disable, could be used instead of SponsorBlock let startTrailerMuted = true; // Default value true; set to false to start the video unmuted +// Seasonal lists configuration +let useSeasonalLists = false; // Set to true to enable automatic seasonal list switching +const seasonalLists = { + spring: 'spring_list.txt', // spring (march-may) + summer: 'summer_list.txt', // summer (june-august) + autumn: 'autumn_list.txt', // autumn (september-november) + winter: 'winter_list.txt', // winter (december-february) + newyear: 'newyear_list.txt', // new year (1.-7. januar) + valentine: 'valentine_list.txt', // valentines day (10.-20. februar) + easter: 'easter_list.txt', // easter (variable dates, March-April) + halloween: 'halloween_list.txt' // halloween (20.-31. october) +}; + // Language specific strings // currently implemented: en, de, fr, es, it, pl, nl @@ -91,6 +104,78 @@ const setLanguage = (language) => { const languageIndex = setLanguage(browserLanguage); +// Seasonal list detection +const getCurrentSeason = () => { + if (!useSeasonalLists) { + return null; + } + + const now = new Date(); + const month = now.getMonth() + 1; // 1-12 + const day = now.getDate(); + + // Special events (take precedence over seasons) + // new year: 1-7 january + if (month === 1 && day <= 7) return 'newyear'; + + // valentines day: 10-20 february + if (month === 2 && day >= 10 && day <= 20) return 'valentine'; + + // halloween: 20-31 cotober + if (month === 10 && day >= 20) return 'halloween'; + + // Easter calculation (simplified - around March-April) + const easterStart = getEasterPeriod(now.getFullYear()); + if (isInEasterPeriod(now, easterStart)) return 'easter'; + + // Regular seasons + if (month >= 3 && month <= 5) return 'spring'; // march-may + if (month >= 6 && month <= 8) return 'summer'; // june-august + if (month >= 9 && month <= 11) return 'autumn'; // september-november + if (month === 12 || month <= 2) return 'winter'; // december-february + + return null; +}; + +// Simplified Easter calculation (Western Easter) +const getEasterPeriod = (year) => { + const a = year % 19; + const b = Math.floor(year / 100); + const c = year % 100; + const d = Math.floor(b / 4); + const e = b % 4; + const f = Math.floor((b + 8) / 25); + const g = Math.floor((b - f + 1) / 3); + const h = (19 * a + b - d - g + 15) % 30; + const i = Math.floor(c / 4); + const k = c % 4; + const l = (32 + 2 * e + 2 * i - h - k) % 7; + const m = Math.floor((a + 11 * h + 22 * l) / 451); + const month = Math.floor((h + l - 7 * m + 114) / 31); + const day = ((h + l - 7 * m + 114) % 31) + 1; + + return { month, day }; +}; + +// Check if current date is in Easter period (2 weeks around Easter) +const isInEasterPeriod = (currentDate, easter) => { + const easterDate = new Date(currentDate.getFullYear(), easter.month - 1, easter.day); + const timeDiff = Math.abs(currentDate.getTime() - easterDate.getTime()); + const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24)); + return daysDiff <= 7; // 1 week before and after Easter +}; + +// Get the appropriate list filename based on season +const getSeasonalListFileName = () => { + const season = getCurrentSeason(); + if (!season || !seasonalLists[season]) { + console.log('Using default list:', listFileName); + return listFileName; + } + console.log(`Using seasonal list for ${season}:`, seasonalLists[season]); + return seasonalLists[season]; +}; + // Get SponsorBlock-Data for the outro/intro segment of the trailer const fetchSponsorBlockData = async (videoId) => { try { @@ -679,8 +764,9 @@ const checkBackdropAndLogo = movie => { ).catch(() => fetchRandomMovie()); }; -const readCustomList = () => - fetch(listFileName + '?' + new Date().getTime()) +const readCustomList = () => { + const currentListFile = getSeasonalListFileName(); + return fetch(currentListFile + '?' + new Date().getTime()) .then(response => response.ok ? response.text() : null) .then(text => { if (!text || !text.trim()) { @@ -723,6 +809,7 @@ const readCustomList = () => console.error('Error reading List.txt. Falling back to random selection.'); return null; }); +}; const fetchRandomMovie = () => {