diff --git a/Jellyfin.Plugin.Seasonals/Web/seasonals.js b/Jellyfin.Plugin.Seasonals/Web/seasonals.js
index 5aed126..f349d73 100644
--- a/Jellyfin.Plugin.Seasonals/Web/seasonals.js
+++ b/Jellyfin.Plugin.Seasonals/Web/seasonals.js
@@ -1,7 +1,8 @@
-// theme-configs.js
+/**
+ * Seasonals Plugin (Client Side Manager Logic)
+ */
-// theme configurations
-const themeConfigs = {
+const ThemeConfigs = {
snowflakes: {
css: '/Seasonals/Resources/snowflakes.css',
js: '/Seasonals/Resources/snowflakes.js',
@@ -67,227 +68,100 @@ const themeConfigs = {
},
};
-// determine current theme based on the current month
-function determineCurrentTheme() {
- const date = new Date();
- const month = date.getMonth(); // 0-11
- const day = date.getDate(); // 1-31
+const SettingsManager = {
+ initialized: false,
+ config: null,
- if ((month === 11 && day >= 28) || (month === 0 && day <= 5)) return 'fireworks'; //new year fireworks december 28 - january 5
+ init(config) {
+ if (this.initialized) return;
+ this.config = config;
- if (month === 1 && day >= 10 && day <= 18) return 'hearts'; // valentine's day february 10 - 18
-
- if (month === 11 && day >= 22 && day <= 27) return 'santa'; // christmas december 22 - 27
- // if (month === 11 && day >= 22 && day <= 27) return 'christmas'; // christmas december 22 - 27
-
- if (month === 11) return 'snowflakes'; // snowflakes december
- if (month === 0 || month === 1) return 'snowfall'; // snow january, february
- // if (month === 0 || month === 1) return 'snowstorm'; // snow january, february
-
- if ((month === 2 && day >= 25) || (month === 3 && day <= 25)) return 'easter'; // easter march 25 - april 25
-
- //NOT IMPLEMENTED YET
- //if (month >= 2 && month <= 4) return 'spring'; // spring march, april, may
-
- //NOT IMPLEMENTED YET
- //if (month >= 5 && month <= 7) return 'summer'; // summer june, july, august
-
- if ((month === 9 && day >= 24) || (month === 10 && day <= 5)) return 'halloween'; // halloween october 24 - november 5
-
- if (month >= 8 && month <= 10) return 'autumn'; // autumn september, october, november
-
- return 'none'; // Fallback (nothing)
-}
-
-// helper to resolve paths for local testing vs production
-function resolvePath(path) {
- if (window.location.protocol === 'file:' || window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
- return path.replace('/Seasonals/Resources/', './');
- }
- return path;
-}
-
-// load theme csss
-function loadThemeCSS(cssPath) {
- if (!cssPath) return;
-
- const link = document.createElement('link');
- link.rel = 'stylesheet';
- // link.href = resolvePath(cssPath);
- link.href = cssPath;
-
- link.onerror = () => {
- console.error(`Failed to load CSS: ${cssPath}`);
- };
-
- document.body.appendChild(link);
- console.log(`CSS file "${cssPath}" loaded.`);
-}
-
-// load theme js
-function loadThemeJS(jsPath) {
- if (!jsPath) return;
-
- const script = document.createElement('script');
- script.src = jsPath;
- // script.src = resolvePath(jsPath);
- script.defer = true;
-
- script.onerror = () => {
- console.error(`Failed to load JS: ${jsPath}`);
- };
-
- document.body.appendChild(script);
- console.log(`JS file "${jsPath}" loaded.`);
-}
-
-// update theme container class name
-function updateThemeContainer(containerClass) {
- // Create container if it doesn't exist
- let container = document.querySelector('.seasonals-container');
- if (!container) {
- container = document.createElement('div');
- container.className = 'seasonals-container';
- document.body.appendChild(container);
- }
-
- container.className = `seasonals-container ${containerClass}`;
- console.log(`Seasonals-Container class updated to "${containerClass}".`);
-}
-
-// function removeSelf() {
-// const script = document.currentScript;
-// if (script) script.parentNode.removeChild(script);
-// console.log('External script removed:', script);
-// }
-
-// initialize theme
-async function initializeTheme() {
-
- // Check local user preference
- const isEnabled = getSavedSetting('seasonals-enabled', 'true') === 'true';
- if (!isEnabled) {
- console.log('Seasonals disabled by user preference.');
- return;
- }
-
- const forcedTheme = getSavedSetting('seasonals-theme', 'auto');
-
- let automateThemeSelection = true;
- let defaultTheme = 'none';
-
- try {
- const response = await fetch('/Seasonals/Config');
- if (response.ok) {
- const config = await response.json();
- automateThemeSelection = config.AutomateSeasonSelection;
- defaultTheme = config.SelectedSeason;
- window.SeasonalsPluginConfig = config;
- console.log('Seasonals Config loaded:', config);
- } else {
- console.error('Failed to fetch Seasonals config');
+ // Only inject settings if enabled on server by admin
+ if (this.config && this.config.EnableClientSideToggle !== false) {
+ this.injectSettingsIcon();
+ this.initialized = true;
+ console.log("Seasonals: Client-Side Settings Manager initialized.");
}
- } catch (error) {
- console.error('Error fetching Seasonals config:', error);
- }
+ },
- let currentTheme;
+ getSetting(key, defaultValue) {
+ const value = localStorage.getItem(`seasonals-${key}`);
+ return value !== null ? value : defaultValue;
+ },
- if (forcedTheme !== 'auto') {
- currentTheme = forcedTheme;
- console.log(`User forced theme: ${currentTheme}`);
- } else if (automateThemeSelection === false) {
- currentTheme = defaultTheme;
- } else {
- currentTheme = determineCurrentTheme();
- }
+ setSetting(key, value) {
+ localStorage.setItem(`seasonals-${key}`, value);
+ },
- console.log(`Selected theme: ${currentTheme}`);
+ createIcon() {
+ const button = document.createElement('button');
+ button.type = 'button';
+ button.className = 'paper-icon-button-light headerButton seasonal-settings-button';
+ button.title = 'Seasonal Settings';
+ // button.innerHTML = '';
+ // button.innerHTML = '';
+ button.innerHTML = '
';
+ button.style.verticalAlign = 'middle';
- if (!currentTheme || currentTheme === 'none') {
- console.log('No theme selected.');
- return;
- }
+ button.addEventListener('click', (e) => {
+ e.stopPropagation();
+ this.toggleSettingsPopup(button);
+ });
- const theme = themeConfigs[currentTheme];
+ return button;
+ },
- if (!theme) {
- console.error(`Theme "${currentTheme}" not found.`);
- return;
- }
- updateThemeContainer(theme.containerClass);
+ injectSettingsIcon() {
+ const observer = new MutationObserver((mutations, obs) => {
+ const headerRight = document.querySelector('.headerRight');
+ if (headerRight && !document.querySelector('.seasonal-settings-button')) {
+ const icon = this.createIcon();
+ headerRight.prepend(icon);
+ }
+ });
- if (theme.css) loadThemeCSS(theme.css);
- if (theme.js) loadThemeJS(theme.js);
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true
+ });
+ },
- console.log(`Theme "${currentTheme}" loaded.`);
-}
+ createPopup(anchorElement) {
+ const existing = document.querySelector('.seasonal-settings-popup');
+ if (existing) existing.remove();
+ const popup = document.createElement('div');
+ popup.className = 'seasonal-settings-popup dialog';
-initializeTheme();
+ Object.assign(popup.style, {
+ position: 'fixed',
+ zIndex: '10000',
+ backgroundColor: '#202020',
+ padding: '1em',
+ borderRadius: '0.3em',
+ boxShadow: '0 0 20px rgba(0,0,0,0.5)',
+ minWidth: '200px',
+ color: '#fff',
+ maxWidth: '250px'
+ });
+ const rect = anchorElement.getBoundingClientRect();
+
+ // Positioning logic
+ let rightPos = window.innerWidth - rect.right;
+ if (window.innerWidth < 450 || (window.innerWidth - rightPos) < 260) {
+ popup.style.right = '1rem';
+ popup.style.left = 'auto';
+ } else {
+ popup.style.right = `${rightPos}px`;
+ popup.style.left = 'auto';
+ }
+ popup.style.top = `${rect.bottom + 10}px`;
-// User UI Seasonal Settings
-
-function getSavedSetting(key, defaultValue) {
- const value = localStorage.getItem(`seasonals-${key}`);
- return value !== null ? value : defaultValue;
-}
-
-function setSavedSetting(key, value) {
- localStorage.setItem(`seasonals-${key}`, value);
-}
-
-function createSettingsIcon() {
- const button = document.createElement('button');
- button.type = 'button';
- button.className = 'paper-icon-button-light headerButton seasonal-settings-button';
- button.title = 'Seasonal Settings';
- // button.innerHTML = '';
- button.innerHTML = '
';
- button.style.verticalAlign = 'middle';
-
- button.addEventListener('click', (e) => {
- e.stopPropagation();
- toggleSettingsPopup(button);
- });
-
- return button;
-}
-
-function createSettingsPopup(anchorElement) {
- const existing = document.querySelector('.seasonal-settings-popup');
- if (existing) existing.remove();
-
- const popup = document.createElement('div');
- popup.className = 'seasonal-settings-popup dialog';
-
- Object.assign(popup.style, {
- position: 'fixed',
- zIndex: '10000',
- backgroundColor: '#202020',
- padding: '1em',
- borderRadius: '0.3em',
- boxShadow: '0 0 20px rgba(0,0,0,0.5)',
- minWidth: '200px',
- color: '#fff',
- maxWidth: '250px'
- });
-
- const rect = anchorElement.getBoundingClientRect();
-
- let rightPos = window.innerWidth - rect.right;
- if (window.innerWidth < 450 || (window.innerWidth - rightPos) < 260) {
- popup.style.right = '1rem';
- popup.style.left = 'auto';
- } else {
- popup.style.right = `${rightPos}px`;
- popup.style.left = 'auto';
- }
-
- popup.style.top = `${rect.bottom + 10}px`;
-
- popup.innerHTML = `
+ // Popup HTML
+ let html = `
+