diff --git a/tmp.js b/tmp.js
new file mode 100644
index 0000000..5da2a48
--- /dev/null
+++ b/tmp.js
@@ -0,0 +1,3607 @@
+/*
+ * Jellyfin Slideshow by M0RPH3US v4.0.1
+ * Modified by CodeDevMLH
+ *
+ * New features:
+ * - optional Trailer background video support
+ * - option to make video backdrops full width
+ * - SponsorBlock support to skip intro/outro segments
+ * - option to always show arrows
+ * - option to disable/enable keyboard controls
+ * - option to show/hide trailer button if trailer as backdrop is disabled (opens in a modal)
+ * - option to wait for trailer to end before loading next slide
+ * - option to set a maximum for the pagination dots (will turn into a counter style if exceeded)
+ * - option to disable loading screen
+ * - option to put collection (boxsets) IDs into the slideshow to display their items
+ * - option to enable client-side settings (allow users to override settings locally on their device)
+ * - option to enable seasonal content (only show items that are relevant to the current season/holiday)
+ * - option to prefer local trailers (from the media item) over online sources
+ * - options to sort the content by various criteria (PremiereDate, ProductionYear, Random, Original order, etc.)
+ */
+
+//Core Module Configuration
+const CONFIG = {
+ IMAGE_SVG: {
+ freshTomato:
+ '',
+ rottenTomato:
+ '',
+ },
+ shuffleInterval: 7000,
+ retryInterval: 500,
+ minSwipeDistance: 50,
+ loadingCheckInterval: 100,
+ maxPlotLength: 360,
+ maxMovies: 15,
+ maxTvShows: 15,
+ maxItems: 500,
+ preloadCount: 3,
+ fadeTransitionDuration: 500,
+ maxPaginationDots: 15,
+ slideAnimationEnabled: true,
+ enableVideoBackdrop: true,
+ useSponsorBlock: true,
+ preferLocalTrailers: false,
+ waitForTrailerToEnd: true,
+ startMuted: true,
+ fullWidthVideo: true,
+ enableMobileVideo: false,
+ showTrailerButton: true,
+ preferredVideoQuality: "Auto",
+ enableKeyboardControls: true,
+ alwaysShowArrows: false,
+ enableCustomMediaIds: true,
+ enableSeasonalContent: false,
+ customMediaIds: "",
+ enableLoadingScreen: true,
+ enableClientSideSettings: false,
+ sortBy: "Random",
+ sortOrder: "Ascending",
+};
+
+// State management
+const STATE = {
+ jellyfinData: {
+ userId: null,
+ appName: null,
+ appVersion: null,
+ deviceName: null,
+ deviceId: null,
+ accessToken: null,
+ serverAddress: null,
+ },
+ slideshow: {
+ hasInitialized: false,
+ isTransitioning: false,
+ isPaused: false,
+ currentSlideIndex: 0,
+ focusedSlide: null,
+ containerFocused: false,
+ slideInterval: null,
+ itemIds: [],
+ loadedItems: {},
+ createdSlides: {},
+ totalItems: 0,
+ isLoading: false,
+ videoPlayers: {},
+ sponsorBlockInterval: null,
+ isMuted: CONFIG.startMuted,
+ customTrailerUrls: {},
+ ytPromise: null,
+ autoplayTimeouts: [],
+ },
+};
+
+// Request throttling system
+const requestQueue = [];
+let isProcessingQueue = false;
+
+/**
+ * Process the next request in the queue with throttling
+ */
+const processNextRequest = () => {
+ if (requestQueue.length === 0) {
+ isProcessingQueue = false;
+ return;
+ }
+
+ isProcessingQueue = true;
+ const { url, callback } = requestQueue.shift();
+
+ fetch(url)
+ .then((response) => {
+ if (response.ok) {
+ return response;
+ }
+ throw new Error(`Failed to fetch: ${response.status}`);
+ })
+ .then(callback)
+ .catch((error) => {
+ console.error("Error in throttled request:", error);
+ })
+ .finally(() => {
+ setTimeout(processNextRequest, 100);
+ });
+};
+
+/**
+ * Add a request to the throttled queue
+ * @param {string} url - URL to fetch
+ * @param {Function} callback - Callback to run on successful fetch
+ */
+const addThrottledRequest = (url, callback) => {
+ requestQueue.push({ url, callback });
+ if (!isProcessingQueue) {
+ processNextRequest();
+ }
+};
+
+/**
+ * Checks if the user is currently logged in
+ * @returns {boolean} True if logged in, false otherwise
+ */
+
+const isUserLoggedIn = () => {
+ try {
+ return (
+ window.ApiClient &&
+ window.ApiClient._currentUser &&
+ window.ApiClient._currentUser.Id &&
+ window.ApiClient._serverInfo &&
+ window.ApiClient._serverInfo.AccessToken
+ );
+ } catch (error) {
+ console.error("Error checking login status:", error);
+ return false;
+ }
+};
+
+/**
+ * Initializes Jellyfin data from ApiClient
+ * @param {Function} callback - Function to call once data is initialized
+ */
+const initJellyfinData = (callback) => {
+ if (!window.ApiClient) {
+ console.warn("⏳ window.ApiClient is not available yet. Retrying...");
+ setTimeout(() => initJellyfinData(callback), CONFIG.retryInterval);
+ return;
+ }
+
+ try {
+ const apiClient = window.ApiClient;
+ STATE.jellyfinData = {
+ userId: apiClient.getCurrentUserId() || "Not Found",
+ appName: apiClient._appName || "Not Found",
+ appVersion: apiClient._appVersion || "Not Found",
+ deviceName: apiClient._deviceName || "Not Found",
+ deviceId: apiClient._deviceId || "Not Found",
+ accessToken: apiClient._serverInfo.AccessToken || "Not Found",
+ serverId: apiClient._serverInfo.Id || "Not Found",
+ serverAddress: apiClient._serverAddress || "Not Found",
+ };
+ if (callback && typeof callback === "function") {
+ callback();
+ }
+ } catch (error) {
+ console.error("Error initializing Jellyfin data:", error);
+ setTimeout(() => initJellyfinData(callback), CONFIG.retryInterval);
+ }
+};
+
+/**
+ * Initializes localization by loading translation chunks
+ */
+const initLocalization = async () => {
+ try {
+ const locale = await LocalizationUtils.getCurrentLocale();
+ await LocalizationUtils.loadTranslations(locale);
+ console.log("✅ Localization initialized");
+ } catch (error) {
+ console.error("Error initializing localization:", error);
+ }
+};
+
+/**
+ * Creates and displays loading screen
+ */
+
+const initLoadingScreen = () => {
+ const currentPath = window.location.href.toLowerCase().replace(window.location.origin, "");
+ const isHomePage =
+ currentPath.includes("/web/#/home.html") ||
+ currentPath.includes("/web/#/home") ||
+ currentPath.includes("/web/index.html#/home.html") ||
+ currentPath === "/web/index.html#/home" ||
+ currentPath.endsWith("/web/");
+
+ if (!isHomePage) return;
+
+ // Check LocalStorage for cached preference to avoid flash
+ const cachedSetting = localStorage.getItem('mediaBarEnhanced-enableLoadingScreen');
+ if (cachedSetting === 'false') {
+ return;
+ }
+
+ const loadingDiv = document.createElement("div");
+ loadingDiv.className = "bar-loading";
+ loadingDiv.id = "page-loader";
+ loadingDiv.innerHTML = `
+
+ `;
+ document.body.appendChild(loadingDiv);
+
+ requestAnimationFrame(() => {
+ document.querySelector(".bar-loading h1 div").style.opacity = "1";
+ });
+
+ const progressBar = document.getElementById("progress-bar");
+ const unfilledBar = document.getElementById("unfilled-bar");
+
+ let progress = 0;
+ let lastIncrement = 5;
+
+ const progressInterval = setInterval(() => {
+ if (progress < 95) {
+ lastIncrement = Math.max(0.5, lastIncrement * 0.98);
+ const randomFactor = 0.8 + Math.random() * 0.4;
+ const increment = lastIncrement * randomFactor;
+ progress += increment;
+ progress = Math.min(progress, 95);
+
+ progressBar.style.width = `${progress}%`;
+ unfilledBar.style.width = `${100 - progress}%`;
+ }
+ }, 150);
+
+ const checkInterval = setInterval(() => {
+ const loginFormLoaded = document.querySelector(".manualLoginForm");
+ const activeTab = document.querySelector(".pageTabContent.is-active");
+
+ if (loginFormLoaded) {
+ finishLoading();
+ return;
+ }
+
+ if (activeTab) {
+ const tabIndex = activeTab.getAttribute("data-index");
+
+ if (tabIndex === "0") {
+ const homeSections = document.querySelector(".homeSectionsContainer");
+ const slidesContainer = document.querySelector("#slides-container");
+
+ if (homeSections && slidesContainer) {
+ finishLoading();
+ }
+ } else {
+ if (
+ activeTab.children.length > 0 ||
+ activeTab.innerText.trim().length > 0
+ ) {
+ finishLoading();
+ }
+ }
+ }
+ }, CONFIG.loadingCheckInterval);
+
+ const finishLoading = () => {
+ clearInterval(progressInterval);
+ clearInterval(checkInterval);
+ progressBar.style.transition = "width 300ms ease-in-out";
+ progressBar.style.width = "100%";
+ unfilledBar.style.width = "0%";
+
+ progressBar.addEventListener("transitionend", () => {
+ requestAnimationFrame(() => {
+ const loader = document.querySelector(".bar-loading");
+ if (loader) {
+ loader.style.opacity = "0";
+ setTimeout(() => {
+ loader.remove();
+ }, 300);
+ }
+ });
+ });
+ };
+};
+
+/**
+ * Resets the slideshow state completely
+ */
+const resetSlideshowState = () => {
+ console.log("🔄 Resetting slideshow state...");
+
+ if (STATE.slideshow.slideInterval) {
+ STATE.slideshow.slideInterval.stop();
+ }
+
+ // Destroy all video players
+ if (STATE.slideshow.videoPlayers) {
+ Object.values(STATE.slideshow.videoPlayers).forEach(player => {
+ if (player && typeof player.destroy === 'function') {
+ player.destroy();
+ }
+ });
+ STATE.slideshow.videoPlayers = {};
+ }
+
+ if (STATE.slideshow.sponsorBlockInterval) {
+ clearInterval(STATE.slideshow.sponsorBlockInterval);
+ STATE.slideshow.sponsorBlockInterval = null;
+ }
+
+ const container = document.getElementById("slides-container");
+ if (container) {
+ while (container.firstChild) {
+ container.removeChild(container.firstChild);
+ }
+ }
+
+ STATE.slideshow.hasInitialized = false;
+ STATE.slideshow.isTransitioning = false;
+ STATE.slideshow.isPaused = false;
+ STATE.slideshow.currentSlideIndex = 0;
+ STATE.slideshow.focusedSlide = null;
+ STATE.slideshow.containerFocused = false;
+ STATE.slideshow.slideInterval = null;
+ STATE.slideshow.itemIds = [];
+ STATE.slideshow.loadedItems = {};
+ STATE.slideshow.createdSlides = {};
+ STATE.slideshow.customTrailerUrls = {};
+ STATE.slideshow.totalItems = 0;
+ STATE.slideshow.isLoading = false;
+};
+
+/**
+ * Watches for login status changes
+ */
+const startLoginStatusWatcher = () => {
+ let wasLoggedIn = false;
+
+ setInterval(() => {
+ const isLoggedIn = isUserLoggedIn();
+
+ if (isLoggedIn !== wasLoggedIn) {
+ if (isLoggedIn) {
+ console.log("👤 User logged in. Initializing slideshow...");
+ if (!STATE.slideshow.hasInitialized) {
+ waitForApiClientAndInitialize();
+ } else {
+ console.log("🔄 Slideshow already initialized, skipping");
+ }
+ } else {
+ console.log("👋 User logged out. Stopping slideshow...");
+ resetSlideshowState();
+ }
+ wasLoggedIn = isLoggedIn;
+ }
+ }, 2000);
+};
+
+/**
+ * Wait for ApiClient to initialize before starting the slideshow
+ */
+const waitForApiClientAndInitialize = () => {
+ if (window.slideshowCheckInterval) {
+ clearInterval(window.slideshowCheckInterval);
+ }
+
+ window.slideshowCheckInterval = setInterval(() => {
+ if (!window.ApiClient) {
+ console.log("⏳ ApiClient not available yet. Waiting...");
+ return;
+ }
+
+ if (
+ window.ApiClient._currentUser &&
+ window.ApiClient._currentUser.Id &&
+ window.ApiClient._serverInfo &&
+ window.ApiClient._serverInfo.AccessToken
+ ) {
+ console.log(
+ "🔓 User is fully logged in. Starting slideshow initialization..."
+ );
+ clearInterval(window.slideshowCheckInterval);
+
+ if (!STATE.slideshow.hasInitialized) {
+ initJellyfinData(async () => {
+ console.log("✅ Jellyfin API client initialized successfully");
+ await initLocalization();
+ await fetchPluginConfig();
+ slidesInit();
+ });
+ } else {
+ console.log("🔄 Slideshow already initialized, skipping");
+ }
+ } else {
+ console.log(
+ "🔒 Authentication incomplete. Waiting for complete login..."
+ );
+ }
+ }, CONFIG.retryInterval);
+};
+
+const fetchPluginConfig = async () => {
+ try {
+ const response = await fetch('/MediaBarEnhanced/Config');
+ if (response.ok) {
+ const pluginConfig = await response.json();
+ if (pluginConfig) {
+ for (const key in pluginConfig) {
+ const camelKey = key.charAt(0).toLowerCase() + key.slice(1);
+ if (CONFIG.hasOwnProperty(camelKey)) {
+ CONFIG[camelKey] = pluginConfig[key];
+ }
+ }
+ STATE.slideshow.isMuted = CONFIG.startMuted;
+
+ if (!CONFIG.enableLoadingScreen) {
+ const loader = document.querySelector(".bar-loading");
+ if (loader) {
+ loader.remove();
+ }
+ }
+
+ // Sync to LocalStorage for next load
+ localStorage.setItem('mediaBarEnhanced-enableLoadingScreen', CONFIG.enableLoadingScreen);
+
+ console.log("✅ MediaBarEnhanced config loaded", CONFIG);
+ }
+ }
+ } catch (e) {
+ console.error("Failed to load MediaBarEnhanced config", e);
+ }
+};
+
+waitForApiClientAndInitialize();
+
+/**
+ * Utility functions for slide creation and management
+ */
+const SlideUtils = {
+ /**
+ * Sorts items based on configuration
+ * @param {Array