Wyze Thumbnail Slideshow

Adds a slideshow feature to Wyze Events page with keyboard navigation, playback speed control, interactive timeline, and more

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Wyze Thumbnail Slideshow
// @namespace    http://ptelectronics.net
// @version      1.9.14
// @description  Adds a slideshow feature to Wyze Events page with keyboard navigation, playback speed control, interactive timeline, and more
// @author       Math Shamenson
// @match        https://my.wyze.com/events*
// @grant        GM_xmlhttpRequest
// @connect      wyze-event-streaming-prod.a.momentohq.com
// @license      MIT
// @run-at       document-idle
// @supportURL   https://greasyfork.org/scripts/SCRIPT_ID/feedback
// @homepageURL  https://greasyfork.org/scripts/SCRIPT_ID
// ==/UserScript==


(function() {
    'use strict';

    // 1. State variables
    // 2. Logger
    // 3. Core slideshow logic
    // 4. UI initialization and styles
    // 5. Controls and features
    // 6. Memory management
    // 7. Initialization system
    // End of IIFE

    // ------------------------------
    //       SHARED SLIDESHOW STATE
    // ------------------------------
    let thumbnails = []; // Array of objects: { src, videoSrc }
    let currentIndex = 0;
    let interval = null;
    let isPlaying = false;
    let speed = 1000; // Default: 1s
    const MIN_SPEED = 200; // Min speed (0.2s)
    const MAX_SPEED = 5000; // Max speed (5s)
    let slideshowInitialized = false;

    // For lazy-loading IntersectionObserver
    let thumbnailObserver = null;

    // --------------------------------
    //             LOGGER
    // --------------------------------
    const Logger = {
        levels: {
            ERROR: 'ERROR',
            WARN:  'WARN',
            INFO:  'INFO',
            DEBUG: 'DEBUG'
        },

        log(level, message, error = null) {
            const timestamp = new Date().toISOString();
            const logMessage = `[${timestamp}] [${level}] ${message}`;

            if (localStorage.getItem('wyzeSlideshow_debug') === 'false') {
                console.log(logMessage);
                if (error) console.error(error);
            }

            if (!window.wyzeSlideshowLogs) window.wyzeSlideshowLogs = [];
            window.wyzeSlideshowLogs.push({ timestamp, level, message, error });

            if (window.wyzeSlideshowLogs.length > 1000) {
                window.wyzeSlideshowLogs.shift();
            }
        }
    };
    // DOM Observer Functions
function observeDOMChanges() {
    let debounceTimeout;
    const observer = new MutationObserver((mutationsList) => {
        Logger.log(Logger.levels.DEBUG, `MutationObserver saw ${mutationsList.length} mutations.`);
        clearTimeout(debounceTimeout);
        debounceTimeout = setTimeout(() => {
            collectThumbnailsAndUpdateUI();
        }, 300);
    });

    observer.observe(document.body, { childList: true, subtree: true });
    Logger.log(Logger.levels.INFO, 'MutationObserver initialized.');
}

// Lazy Loading Functions
function improvedThumbnailCollection() {
    const observerOptions = {
        root: null,
        rootMargin: '50px',
        threshold: 0.1
    };

    thumbnailObserver = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const img = entry.target;
                if (img.dataset.src) {
                    img.src = img.dataset.src;
                    img.removeAttribute('data-src');
                    Logger.log(Logger.levels.DEBUG, `Lazy-loaded thumbnail: ${img.alt}`);
                }
                thumbnailObserver.unobserve(img);
            }
        });
    }, observerOptions);

    Logger.log(Logger.levels.INFO, 'IntersectionObserver for lazy-loading initialized.');
}
    // Set playback speed (referenced in keyboard controls)
function setPlaybackSpeed(multiplier) {
    if (multiplier === 1) {
        speed = 1000;
    } else {
        speed = Math.floor(1000 / multiplier);
    }
    speed = Math.max(MIN_SPEED, Math.min(speed, MAX_SPEED));

    if (isPlaying) {
        pauseSlideshow();
        startSlideshowInterval();
    }
    updateSpeedDisplay();
    Logger.log(Logger.levels.INFO, `Playback speed set via multiplier (${multiplier}). New speed: ${speed}ms.`);
}

// Jump to percentage (used in timeline navigation)
function jumpToPercentage(percent) {
    if (thumbnails.length === 0) return;

    const targetIndex = Math.floor((percent / 100) * thumbnails.length);
    currentIndex = Math.min(targetIndex, thumbnails.length - 1);
    updateSlideshow();
    Logger.log(Logger.levels.INFO, `Jumped to ${percent}% (index: ${currentIndex})`);
}

// Show/hide thumbnail preview functions
function showThumbnailPreview(index, x, y) {
    if (!thumbnails[index]) return;

    let preview = document.getElementById('timeline-preview');
    if (!preview) {
        preview = document.createElement('div');
        preview.id = 'timeline-preview';
        preview.style.cssText = `
            position: fixed;
            background: white;
            padding: 5px;
            border-radius: 5px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.3);
            z-index: 10004;
            pointer-events: none;
        `;
        document.body.appendChild(preview);
    }

    const img = new Image();
    img.src = thumbnails[index].src;
    img.style.maxWidth = '200px';
    img.style.maxHeight = '150px';

    preview.innerHTML = '';
    preview.appendChild(img);

    preview.style.left = `${x - preview.offsetWidth/2}px`;
    preview.style.top = `${y - preview.offsetHeight - 10}px`;
    preview.style.display = 'block';
}

function hideThumbnailPreview() {
    const preview = document.getElementById('timeline-preview');
    if (preview) {
        preview.style.display = 'none';
    }
}

// Button Management
function addStartButton() {
    let btn = document.getElementById('start-slideshow-btn');
    if (!btn) {
        btn = document.createElement('button');
        btn.id = 'start-slideshow-btn';
        btn.textContent = 'Start Slideshow';
        btn.className = 'slideshow-button';
        btn.onclick = startSlideshow;
        document.body.appendChild(btn);
        Logger.log(Logger.levels.INFO, 'Start Slideshow button added.');
    } else {
        btn.style.display = 'block';
        Logger.log(Logger.levels.DEBUG, 'Start Slideshow button already exists, now ensured visible.');
    }
}

// Close functions
function closeSlideshow() {
    pauseSlideshow();
    const container = document.getElementById('slideshow-container');
    if (container) {
        container.style.display = 'none';
        Logger.log(Logger.levels.INFO, 'Slideshow closed.');
    }
}

// Timeline management functions
function handleKeyboard(e) {
    const container = document.getElementById('slideshow-container');
    if (!container || container.style.display === 'none') return;

    switch (e.key) {
        case 'ArrowLeft':
            prevImage();
            break;
        case 'ArrowRight':
            nextImage();
            break;
        case ' ':
            e.preventDefault();
            togglePlayPause();
            break;
        case 'Escape':
            closeSlideshow();
            break;
        case '+':
        case '=':
            increaseSpeed();
            break;
        case '-':
            decreaseSpeed();
            break;
        default:
            break;
    }
}

function togglePlayPause() {
    if (isPlaying) {
        pauseSlideshow();
        Logger.log(Logger.levels.INFO, 'Slideshow paused.');
    } else {
        startSlideshowInterval();
        Logger.log(Logger.levels.INFO, 'Slideshow playing.');
    }
}

// Memory management
function cleanupUnusedThumbnails() {
    const MAX_CACHED_THUMBNAILS = 50;
    if (thumbnails.length > MAX_CACHED_THUMBNAILS) {
        const excess = thumbnails.length - MAX_CACHED_THUMBNAILS;
        const removed = thumbnails.splice(MAX_CACHED_THUMBNAILS, excess);
        Logger.log(Logger.levels.INFO, `Cleaned up ${removed.length} excess thumbnails from memory.`);

        // Clean up DOM thumbnails
        const unusedThumbs = document.querySelectorAll('.slideshow-thumbnail:not(.active)');
        unusedThumbs.forEach((thumb) => {
            thumb.src = '';
            thumb.remove();
            Logger.log(Logger.levels.DEBUG, 'Removed unused thumbnail from DOM.');
        });
    }
}

    // --------------------------------
    //        CORE SLIDESHOW LOGIC
    // --------------------------------

    function startSlideshow() {
        Logger.log(Logger.levels.INFO, 'Starting slideshow...');
        collectThumbnailsAndUpdateUI();

        const container = document.getElementById('slideshow-container');
        if (!container) {
            Logger.log(Logger.levels.ERROR, 'Slideshow container not found.');
            return;
        }

        if (thumbnails.length > 0) {
            currentIndex = 0;
            updateSlideshow();
            container.style.display = 'flex';
            togglePlayPause(); // Start playing by default
            Logger.log(Logger.levels.INFO, 'Slideshow started.');
        } else {
            notifyNoThumbnails();
            Logger.log(Logger.levels.WARN, 'No thumbnails to display.');
        }
    }

function updateSlideshow() {
    const container = document.getElementById('slideshow-container');
    const link = document.getElementById('slideshow-link');
    const img = document.getElementById('slideshow-image');

    if (!container || !img || thumbnails.length === 0) {
        Logger.log(Logger.levels.WARN, 'No container/image or thumbnails available for slideshow.');
        return;
    }

    currentIndex = (currentIndex + thumbnails.length) % thumbnails.length;
    const currentThumbnail = thumbnails[currentIndex];

    if (currentThumbnail) {
        if (currentThumbnail.needsRotation) {
            img.classList.add('doorbell-orientation');
            link.classList.add('doorbell-container');
            container.classList.add('has-rotated-image');
        } else {
            img.classList.remove('doorbell-orientation');
            link.classList.remove('doorbell-container');
            container.classList.remove('has-rotated-image');
        }

        img.src = currentThumbnail.src;

        if (link) {
            link.onclick = (e) => {
                e.preventDefault();
                playVideo(currentThumbnail.videoSrc);
            };
            link.href = '#';
        }

        Logger.log(Logger.levels.INFO, `Displaying thumbnail ${currentIndex + 1}/${thumbnails.length} (rotation: ${currentThumbnail.needsRotation})`);
        updateProgressBar();
    }
}
    // [Previous functions through createHelpOverlay() remain unchanged]

    // --------------------------------
    //      COLLECT THUMBNAILS
    // --------------------------------
/*
    function collectThumbnails() {
        thumbnails = [];
        const eventDivs = document.querySelectorAll('div[id^="event_"]');

        Logger.log(Logger.levels.INFO, `Found ${eventDivs.length} event containers`);

        eventDivs.forEach(eventDiv => {
            const imgWrapper = eventDiv.querySelector('.VideoWrap img');

            if (imgWrapper) {
                const src = imgWrapper.dataset.src || imgWrapper.src;

                // Extract event ID using updated pattern for Wyze's current system
                const match = src.match(/wyze-thumbnail-service-prod\/(.+?)_\d+\.jpg/);
                if (match) {
                    const eventId = match[1];
                    // Construct video URL using Wyze's streaming service endpoint
                    const videoSrc = `https://wyze-event-streaming-prod.a.momentohq.com/cache/wyze-streaming-service-prod/${eventId}.mp4`;

                    thumbnails.push({ src, videoSrc });
                    Logger.log(Logger.levels.DEBUG, `Added thumbnail for event ${eventId}`);
                } else {
                    Logger.log(Logger.levels.DEBUG, `Could not parse event ID from thumbnail URL: ${src}`);
                }
            }
        });

        Logger.log(Logger.levels.INFO, `Collected ${thumbnails.length} thumbnails`);
        updateStartButtonVisibility();
    }
*/

function collectThumbnails() {
    thumbnails = [];
    const eventDivs = document.querySelectorAll('div[id^="event_"]');

    Logger.log(Logger.levels.INFO, `Found ${eventDivs.length} event containers`);

    eventDivs.forEach(eventDiv => {
        const imgWrapper = eventDiv.querySelector('.VideoWrap img');

        if (imgWrapper) {
            const src = imgWrapper.dataset.src || imgWrapper.src;

            if (!src) {
                Logger.log(Logger.levels.DEBUG, 'No src found for image wrapper');
                return;
            }

            // Check if this is a doorbell camera image that needs rotation
            const needsRotation = src.includes('wyze-device-alarm-file-face.s3.us-west-2.amazonaws.com');

            let eventId = null;
            let videoSrc = null;

            // Multiple pattern matching
            let match = src.match(/wyze-thumbnail-service-prod\/(.+?)_\d+\.jpg/) ||
                       src.match(/cp-t-usw2\.s3[^\/]*\/([^_]+)_\d+\.jpg/) ||
                       src.match(/momentohq\.com\/([^_]+)_\d+\.jpg/) ||
                       src.match(/([a-f0-9-]{36})/i) ||
                       src.match(/(\w+)\/\d{4}-\d{2}-\d{2}\/(\w+)/); // New pattern for alarm files

            if (match) {
                eventId = match[1];
                videoSrc = `https://wyze-event-streaming-prod.a.momentohq.com/cache/wyze-streaming-service-prod/${eventId}.mp4`;

                thumbnails.push({
                    src,
                    videoSrc,
                    eventId,
                    needsRotation: needsRotation,
                    timestamp: eventDiv.getAttribute('data-timestamp') || null
                });

                Logger.log(Logger.levels.DEBUG, `Added thumbnail for event ${eventId} (rotation: ${needsRotation}), src: ${src}`);
            }
        }
    });

    // Sort thumbnails by timestamp if available
    if (thumbnails.length > 0 && thumbnails[0].timestamp) {
        thumbnails.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
    }

    Logger.log(Logger.levels.INFO, `Collected ${thumbnails.length} thumbnails`);
    updateStartButtonVisibility();
}


    // --------------------------------
    //       VIDEO PLAYER CONTROL
    // --------------------------------

    function playVideo(videoSrc) {
        const videoPlayer = document.querySelector('video.vjs-tech');
        const spinner = document.getElementById('loading-spinner');

        if (!videoPlayer) {
            Logger.log(Logger.levels.ERROR, 'Video player element not found.');
            notifyVideoPlayerNotFound();
            return;
        }

        if (spinner) spinner.style.display = 'block';

        // Using GM_xmlhttpRequest for cross-origin video requests
        GM_xmlhttpRequest({
            method: 'GET',
            url: videoSrc,
            responseType: 'blob',
            onload: function(response) {
                const blobUrl = URL.createObjectURL(response.response);

                videoPlayer.pause();
                videoPlayer.src = blobUrl;
                videoPlayer.load();

                videoPlayer.play()
                    .then(() => {
                        Logger.log(Logger.levels.INFO, `Playing video: ${videoSrc}`);
                        if (spinner) spinner.style.display = 'none';
                    })
                    .catch(error => {
                        Logger.log(Logger.levels.ERROR, `Error playing video: ${videoSrc}`, error);
                        notifyVideoError();
                        if (spinner) spinner.style.display = 'none';
                    });

                videoPlayer.addEventListener('ended', () => {
                    URL.revokeObjectURL(blobUrl);
                }, { once: true });
            },
            onerror: function(error) {
                Logger.log(Logger.levels.ERROR, `Failed to fetch video: ${videoSrc}`, error);
                notifyVideoError();
                if (spinner) spinner.style.display = 'none';
            }
        });
    }

// After the Logger object but before UI initialization:

function collectThumbnailsAndUpdateUI() {
    collectThumbnails();
    updateSlideshowUI();
}

function updateSlideshowUI() {
    const container = document.getElementById('slideshow-container');
    if (!container) return;
    updateProgressBar();
}

function preloadImage(src) {
    return new Promise((resolve, reject) => {
        const img = new Image();
        img.onload = () => resolve(img);
        img.onerror = () => reject(new Error(`Failed to load image: ${src}`));
        img.src = src;
        Logger.log(Logger.levels.DEBUG, `Preloading image: ${src}`);
    });
}

// Navigation Functions
function prevImage() {
    pauseSlideshow();
    currentIndex = (currentIndex - 1 + thumbnails.length) % thumbnails.length;
    Logger.log(Logger.levels.DEBUG, 'Navigating to previous image.');
    updateSlideshow();
}

function nextImage() {
    pauseSlideshow();
    currentIndex = (currentIndex + 1) % thumbnails.length;
    Logger.log(Logger.levels.DEBUG, 'Navigating to next image.');
    updateSlideshow();
}



    function startSlideshowInterval() {
    isPlaying = true;

    // Start auto-play with dynamic thumbnail updates
    interval = setInterval(() => {
        // Refresh thumbnails dynamically
        collectThumbnails();

        // Ensure the index stays within bounds
        if (currentIndex >= thumbnails.length) {
            currentIndex = 0; // Loop back to the start if out of bounds
        }

        updateSlideshow();

        // Increment to the next slide
        currentIndex = (currentIndex + 1) % thumbnails.length;

    }, speed);

    Logger.log(Logger.levels.INFO, `Slideshow interval started (speed: ${speed}ms).`);
}


function pauseSlideshow() {
    isPlaying = false;
    if (interval) {
        clearInterval(interval);
        interval = null;
        Logger.log(Logger.levels.DEBUG, 'Slideshow interval cleared.');
    }
}

// Speed Control Functions
function increaseSpeed() {
    speed = Math.max(MIN_SPEED, speed - 200);
    if (isPlaying) {
        pauseSlideshow();
        startSlideshowInterval();
    }
    updateSpeedDisplay();
    Logger.log(Logger.levels.INFO, `Playback speed increased to ${speed}ms`);
}

function decreaseSpeed() {
    speed = Math.min(MAX_SPEED, speed + 200);
    if (isPlaying) {
        pauseSlideshow();
        startSlideshowInterval();
    }
    updateSpeedDisplay();
    Logger.log(Logger.levels.INFO, `Playback speed decreased to ${speed}ms`);
}

function resetSpeed() {
    speed = 1000;
    if (isPlaying) {
        pauseSlideshow();
        startSlideshowInterval();
    }
    updateSpeedDisplay();
    Logger.log(Logger.levels.INFO, 'Playback speed reset to default');
}

function updateSpeedDisplay() {
    const speedDisplay = document.getElementById('speed-display');
    if (speedDisplay) {
        speedDisplay.textContent = `Speed: ${speed} ms`;
    }
}

// Notification Functions
function notifyNoThumbnails() {
    const el = document.getElementById('no-thumbnails-notification');
    if (el) {
        el.style.display = 'block';
        setTimeout(() => { el.style.display = 'none'; }, 3000);
        Logger.log(Logger.levels.INFO, 'Displayed "No thumbnails" notification');
    }
}

function notifyVideoError() {
    const el = document.getElementById('video-error-notification');
    if (el) {
        el.style.display = 'block';
        setTimeout(() => { el.style.display = 'none'; }, 3000);
        Logger.log(Logger.levels.INFO, 'Displayed "Video error" notification');
    }
}

function notifyVideoPlayerNotFound() {
    const el = document.getElementById('video-player-not-found-notification');
    if (el) {
        el.style.display = 'block';
        setTimeout(() => { el.style.display = 'none'; }, 3000);
        Logger.log(Logger.levels.INFO, 'Displayed "Video player not found" notification');
    }
}

// Display Control Functions
function toggleFullscreen() {
    const container = document.getElementById('slideshow-container');
    if (!container) return;

    try {
        if (!document.fullscreenElement) {
            container.requestFullscreen();
            Logger.log(Logger.levels.INFO, 'Entered fullscreen mode');
        } else {
            document.exitFullscreen();
            Logger.log(Logger.levels.INFO, 'Exited fullscreen mode');
        }
    } catch (error) {
        Logger.log(Logger.levels.ERROR, 'Fullscreen toggle failed', error);
    }
}

function toggleMute() {
    const videoPlayer = document.querySelector('video.vjs-tech');
    if (videoPlayer) {
        videoPlayer.muted = !videoPlayer.muted;
        Logger.log(Logger.levels.INFO, `Video ${videoPlayer.muted ? 'muted' : 'unmuted'}`);
    }
}

function toggleHelpOverlay() {
    const helpOverlay = document.getElementById('slideshow-help-overlay');
    if (helpOverlay) {
        const isHidden = helpOverlay.style.display === 'none' || !helpOverlay.style.display;
        helpOverlay.style.display = isHidden ? 'block' : 'none';
        Logger.log(Logger.levels.INFO, `Help overlay ${isHidden ? 'shown' : 'hidden'}`);
    }
}

function updateStartButtonVisibility() {
    const startBtn = document.getElementById('start-slideshow-btn');
    if (startBtn) {
        startBtn.style.display = thumbnails.length > 0 ? 'block' : 'none';
        Logger.log(Logger.levels.DEBUG, `Start button visibility updated: ${thumbnails.length > 0 ? 'visible' : 'hidden'}`);
    }
}
    function updateProgressBar() {
    const progress = document.getElementById('progress');
    if (!progress) {
        Logger.log(Logger.levels.DEBUG, 'No progress bar found.');
        return;
    }

    if (thumbnails.length <= 1) {
        progress.style.width = '100%';
        return;
    }

    const percent = ((currentIndex + 1) / thumbnails.length) * 100;
    progress.style.width = percent + '%';
    Logger.log(Logger.levels.DEBUG, `Progress bar updated to ${percent}%`);
}

function handleButtonClick(label) {
    Logger.log(Logger.levels.DEBUG, `Button clicked: ${label}`);
    switch (label) {
        case 'Prev':
            prevImage();
            break;
        case 'Play/Pause':
            togglePlayPause();
            break;
        case 'Next':
            nextImage();
            break;
        case 'Faster':
            increaseSpeed();
            break;
        case 'Slower':
            decreaseSpeed();
            break;
        case 'Reset Speed':
            resetSpeed();
            break;
        case 'Close':
            closeSlideshow();
            break;
        default:
            Logger.log(Logger.levels.WARN, `Unknown button label: ${label}`);
            break;
    }
}
// --------------------------------
    //         UI INITIALIZATION
    // --------------------------------

function injectOrientationStyles() {
    const style = document.createElement('style');
    style.textContent = `
        .doorbell-orientation {
            transform: rotate(90deg);
            transform-origin: center center;
            width: auto;
            height: auto;
            max-width: 80vh;  /* Use viewport height for better scaling */
            max-height: 80vw; /* Use viewport width for better scaling */
            object-fit: contain;
            margin: auto;
        }

        .doorbell-container {
            display: flex;
            justify-content: center;
            align-items: center;
            width: 100%;
            height: 100%;
            padding: 2rem;
            box-sizing: border-box;
        }

        /* Ensure the slideshow container can accommodate rotated images */
        #slideshow-container.has-rotated-image {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            overflow: hidden;
        }
    `;
    document.head.appendChild(style);
}
    function injectStyles() {
        const style = document.createElement('style');
        style.textContent = `
            #slideshow-container {
                position: fixed;
                top: 5%;
                left: 5%;
                width: 90%;
                height: 90%;
                background: rgba(0, 0, 0, 0.95);
                color: white;
                display: flex;
                flex-direction: column;
                justify-content: center;
                align-items: center;
                z-index: 10000;
                border-radius: 10px;
                border: 2px solid #fff;
                overflow: hidden;
            }
            #slideshow-link {
                display: block;
                max-width: 95%;
                max-height: 75%;
                cursor: pointer;
                text-align: center;
            }
            #slideshow-image {
                max-width: 100%;
                max-height: 100%;
                border-radius: 5px;
            }
            #progress-bar {
                width: 90%;
                height: 30px;
                background: gray;
                margin-top: 10px;
                border-radius: 10px;
                cursor: pointer;
                position: relative;
            }
            #progress {
                height: 100%;
                background: limegreen;
                width: 0%;
                border-radius: 10px;
                transition: width 0.5s ease;
            }
            .slideshow-button, .speed-button {
                margin: 5px;
                padding: 10px 15px;
                border: none;
                border-radius: 5px;
                background-color: #007BFF;
                color: white;
                font-size: 16px;
                cursor: pointer;
            }
            .slideshow-button:hover, .speed-button:hover {
                background-color: #0056b3;
            }
            #speed-display {
                margin-top: 10px;
                font-size: 16px;
            }
            #start-slideshow-btn {
                position: fixed;
                bottom: 10px;
                right: 150px;
                z-index: 10001;
                padding: 10px 15px;
                border: none;
                border-radius: 5px;
                background-color: #28a745;
                color: white;
                font-size: 16px;
                cursor: pointer;
            }
            /* Enhanced visibility for the start button */
            #start-slideshow-btn:hover {
                background-color: #218838;
                transform: scale(1.05);
                transition: all 0.2s ease;
            }
            .slideshow-thumbnail.active {
                border: 3px solid #007BFF;
                border-radius: 5px;
            }
            /* Improved loading spinner visibility */
            #loading-spinner {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                display: none;
                z-index: 10002;
                background: rgba(0, 0, 0, 0.7);
                padding: 20px;
                border-radius: 10px;
            }
            /* Enhanced notification styling */
            #no-thumbnails-notification,
            #video-error-notification,
            #video-player-not-found-notification {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: rgba(255, 0, 0, 0.8);
                padding: 20px;
                border-radius: 5px;
                z-index: 10003;
                color: white;
                font-size: 18px;
                text-align: center;
                box-shadow: 0 2px 10px rgba(0,0,0,0.3);
            }
            /* Accessibility improvements */
            .slideshow-button:focus,
            .slideshow-thumbnail:focus {
                outline: 3px solid #007BFF;
                outline-offset: 2px;
                box-shadow: 0 0 5px rgba(0,123,255,0.5);
            }
            /* Help overlay styling */
            #slideshow-help-overlay {
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.9);
                z-index: 10001;
                display: none;
            }
            .help-content {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: white;
                padding: 20px;
                border-radius: 10px;
                color: black;
                max-width: 80%;
                max-height: 80%;
                overflow-y: auto;
            }
            .help-content h3 {
                margin-top: 0;
                color: #007BFF;
            }
            .help-content ul {
                list-style-type: none;
                padding: 0;
            }
            .help-content li {
                margin: 10px 0;
                padding: 5px 0;
                border-bottom: 1px solid #eee;
            }
        `;
        document.head.appendChild(style);
        Logger.log(Logger.levels.INFO, 'Enhanced styles injected.');
    }

    // Enhanced UI creation with better error handling
    function createSlideshowUI() {
        const container = document.createElement('div');
        container.id = 'slideshow-container';
        container.style.display = 'none';

        // Link & main image with improved error handling
        const link = document.createElement('a');
        link.id = 'slideshow-link';
        link.href = '#';
        const img = document.createElement('img');
        img.id = 'slideshow-image';
        img.onerror = () => {
            Logger.log(Logger.levels.ERROR, 'Failed to load image');
            img.src = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><rect width="100" height="100" fill="%23ccc"/><text x="50%" y="50%" text-anchor="middle" dy=".3em" fill="%23666">Error</text></svg>';
        };
        link.appendChild(img);
        container.appendChild(link);

        // Improved spinner with better visibility
        const spinner = document.createElement('div');
        spinner.id = 'loading-spinner';
        spinner.innerHTML = `
            <div style="text-align: center;">
                <img src="https://i.imgur.com/llF5iyg.gif" alt="Loading..." width="50" height="50">
                <div style="margin-top: 10px; color: white;">Loading video...</div>
            </div>
        `;
        container.appendChild(spinner);

        // Enhanced progress bar with better visual feedback
        const progressBar = document.createElement('div');
        progressBar.id = 'progress-bar';
        const progress = document.createElement('div');
        progress.id = 'progress';
        progressBar.appendChild(progress);
        container.appendChild(progressBar);

        // Improved control buttons with better accessibility
        const controlContainer = document.createElement('div');
        controlContainer.style.marginTop = '10px';
        controlContainer.style.display = 'flex';
        controlContainer.style.flexWrap = 'wrap';
        controlContainer.style.justifyContent = 'center';

        const controls = [
            { label: 'Prev', icon: '⏮' },
            { label: 'Play/Pause', icon: '⏯' },
            { label: 'Next', icon: '⏭' },
            { label: 'Faster', icon: '⚡' },
            { label: 'Slower', icon: '🐢' },
            { label: 'Reset Speed', icon: '⟲' },
            { label: 'Close', icon: '✖' }
        ];

        controls.forEach(({ label, icon }) => {
            const btn = document.createElement('button');
            btn.textContent = `${icon} ${label}`;
            btn.className = 'slideshow-button';
            btn.setAttribute('aria-label', label);
            btn.onclick = () => handleButtonClick(label);
            controlContainer.appendChild(btn);
        });
        container.appendChild(controlContainer);

        // Enhanced thumbnail preview container
        const thumbnailPreviewContainer = document.createElement('div');
        thumbnailPreviewContainer.id = 'thumbnail-preview-container';
        thumbnailPreviewContainer.style.display = 'flex';
        thumbnailPreviewContainer.style.flexWrap = 'wrap';
        thumbnailPreviewContainer.style.marginTop = '10px';
        container.appendChild(thumbnailPreviewContainer);

        // Improved speed display with better visibility
        const speedDisplay = document.createElement('div');
        speedDisplay.id = 'speed-display';
        speedDisplay.textContent = `Speed: ${speed} ms`;
        container.appendChild(speedDisplay);

        // Enhanced notifications
        const notifications = [
            { id: 'no-thumbnails-notification', text: 'No thumbnails found to start the slideshow.' },
            { id: 'video-error-notification', text: 'Failed to play the selected video.' },
            { id: 'video-player-not-found-notification', text: 'Video player not found on the page.' }
        ];

        notifications.forEach(({ id, text }) => {
            const notification = document.createElement('div');
            notification.id = id;
            notification.style.display = 'none';
            notification.textContent = text;
            container.appendChild(notification);
        });

        document.body.appendChild(container);

        // Enhanced progress bar interaction
        progressBar.addEventListener('click', (e) => {
            const rect = progressBar.getBoundingClientRect();
            const percent = (e.clientX - rect.left) / rect.width;
            currentIndex = Math.floor(percent * thumbnails.length);
            updateSlideshow();
            pauseSlideshow();
            Logger.log(Logger.levels.INFO, `Scrubbed to index ${currentIndex + 1}/${thumbnails.length}`);
        });

        // Enhanced keyboard controls
        window.addEventListener('keydown', handleKeyboard);

        Logger.log(Logger.levels.INFO, 'Enhanced slideshow UI created.');
    }
// --------------------------------
    //  ENHANCED KEYBOARD AND TOUCH CONTROLS
    // --------------------------------
/*
    const touchControls = {
        initialize() {
            const container = document.getElementById('slideshow-container');
            if (!container) return;

            // Track touch positions for gesture detection
            let touchStartX = 0;
            let touchEndX = 0;
            let touchStartY = 0;
            let touchEndY = 0;
            let touchStartTime = 0;

            container.addEventListener('touchstart', (e) => {
                // Store initial touch coordinates and time
                touchStartX = e.changedTouches[0].screenX;
                touchStartY = e.changedTouches[0].screenY;
                touchStartTime = Date.now();
            });

            container.addEventListener('touchend', (e) => {
                // Calculate touch movement and duration
                touchEndX = e.changedTouches[0].screenX;
                touchEndY = e.changedTouches[0].screenY;
                const touchDuration = Date.now() - touchStartTime;
                handleGesture();
            });

            function handleGesture() {
                const SWIPE_THRESHOLD = 50; // Minimum distance for swipe
                const SWIPE_TIME_LIMIT = 300; // Maximum time for swipe (ms)
                const touchDuration = Date.now() - touchStartTime;
                const swipeDistanceX = touchEndX - touchStartX;
                const swipeDistanceY = touchEndY - touchStartY;

                // Only process quick, intentional swipes
                if (touchDuration <= SWIPE_TIME_LIMIT) {
                    if (Math.abs(swipeDistanceX) > SWIPE_THRESHOLD &&
                        Math.abs(swipeDistanceX) > Math.abs(swipeDistanceY)) {
                        if (swipeDistanceX > 0) {
                            prevImage();
                            Logger.log(Logger.levels.INFO, 'Swiped right => Previous image');
                        } else {
                            nextImage();
                            Logger.log(Logger.levels.INFO, 'Swiped left => Next image');
                        }
                    }
                }
            }
        }
    };
*/
    // --------------------------------
    //   ENHANCED TIMELINE NAVIGATION
    // --------------------------------

    const timelineNavigation = {
        initialize() {
            const progressBar = document.getElementById('progress-bar');
            if (!progressBar) return;

            let isDragging = false;
            let wasPlaying = false;

            // Enhanced drag handling with play state management
            progressBar.addEventListener('mousedown', (e) => {
                isDragging = true;
                wasPlaying = isPlaying;
                pauseSlideshow();
                updateTimelinePosition(e);
                Logger.log(Logger.levels.DEBUG, 'Started dragging progress bar');
            });

            document.addEventListener('mousemove', (e) => {
                if (!isDragging) return;
                updateTimelinePosition(e);
            });

            document.addEventListener('mouseup', () => {
                if (isDragging) {
                    isDragging = false;
                    // Restore previous play state if was playing
                    if (wasPlaying) {
                        startSlideshowInterval();
                    }
                    Logger.log(Logger.levels.DEBUG, 'Stopped dragging progress bar');
                }
            });

         function updateTimelinePosition(e) {
             const progressBar = document.getElementById('progress-bar');
             if (!progressBar) return;

             const rect = progressBar.getBoundingClientRect();
             const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
             const targetIndex = Math.floor(percent * thumbnails.length);

             // Preload the thumbnail for the target index if not already loaded
             if (thumbnails[targetIndex] && !thumbnails[targetIndex].loaded) {
                 preloadImage(thumbnails[targetIndex].src).then(() => {
                     thumbnails[targetIndex].loaded = true;
                     Logger.log(Logger.levels.DEBUG, `Preloaded thumbnail for scrubbing: ${thumbnails[targetIndex].src}`);
                 }).catch((error) => {
                     Logger.log(Logger.levels.ERROR, `Failed to preload thumbnail for scrubbing: ${error.message}`);
                 });
             }

             // Update current index and slideshow
             currentIndex = targetIndex;
             updateSlideshow();
         }


            // Add hover preview functionality
            let previewTimeout;
            progressBar.addEventListener('mousemove', (e) => {
                clearTimeout(previewTimeout);
                previewTimeout = setTimeout(() => {
                    if (!isDragging) {
                        const rect = progressBar.getBoundingClientRect();
                        const percent = (e.clientX - rect.left) / rect.width;
                        const previewIndex = Math.floor(percent * thumbnails.length);
                        showThumbnailPreview(previewIndex, e.clientX, e.clientY);
                    }
                }, 100);
            });

            progressBar.addEventListener('mouseleave', () => {
                clearTimeout(previewTimeout);
                hideThumbnailPreview();
            });
        }
    };




    // --------------------------------
    //    ENHANCED KEYBOARD SHORTCUTS
    // --------------------------------

    const enhancedKeyboardControls = {
        initialize() {
            // Map of keyboard shortcuts to their actions
            const shortcuts = {
                'f': () => toggleFullscreen(),
                'm': () => toggleMute(),
                '1': () => setPlaybackSpeed(1),
                '2': () => setPlaybackSpeed(2),
                '3': () => setPlaybackSpeed(0.5),
                'h': () => toggleHelpOverlay(),
                // Number keys 1-9 for quick navigation
                ...[...Array(9)].reduce((acc, _, i) => ({
                    ...acc,
                    [`${i + 1}`]: () => jumpToPercentage((i + 1) * 10)
                }), {})
            };

            document.addEventListener('keydown', (e) => {
                // Only process shortcuts if slideshow is visible
                const container = document.getElementById('slideshow-container');
                if (!container || container.style.display === 'none') return;

                if (shortcuts[e.key]) {
                    e.preventDefault();
                    shortcuts[e.key]();
                    Logger.log(Logger.levels.INFO, `Keyboard shortcut: ${e.key}`);
                }
            });
        }
    };


// --------------------------------
    //    ENHANCED HELP OVERLAY SYSTEM
    // --------------------------------

    function createHelpOverlay() {
        const helpOverlay = document.createElement('div');
        helpOverlay.id = 'slideshow-help-overlay';

        // Creating a more comprehensive and organized help content
        helpOverlay.innerHTML = `
            <div class="help-content">
                <h3>Wyze Slideshow Controls</h3>
                <div style="margin-bottom: 20px;">
                    <h4>Navigation</h4>
                    <ul>
                        <li>←/→ : Navigate between images</li>
                        <li>Space : Play/Pause slideshow</li>
                        <li>1-9 : Jump to percentage through slideshow (1=10%, 9=90%)</li>
                        <li>Esc : Close slideshow</li>
                    </ul>
                </div>
                <div style="margin-bottom: 20px;">
                    <h4>Playback Control</h4>
                    <ul>
                        <li>+ / = : Increase speed</li>
                        <li>- : Decrease speed</li>
                        <li>R : Reset speed to default</li>
                        <li>M : Toggle video mute</li>
                    </ul>
                </div>
                <div style="margin-bottom: 20px;">
                    <h4>Display Options</h4>
                    <ul>
                        <li>F : Toggle fullscreen</li>
                        <li>H : Toggle this help overlay</li>
                    </ul>
                </div>
                <div style="margin-bottom: 20px;">
                    <h4>Touch Controls</h4>
                    <ul>
                        <li>Swipe Left : Next image</li>
                        <li>Swipe Right : Previous image</li>
                        <li>Double Tap : Play/Pause</li>
                    </ul>
                </div>
                <div>
                    <h4>Timeline Navigation</h4>
                    <ul>
                        <li>Click or drag the progress bar to navigate</li>
                        <li>Hover over progress bar to preview thumbnails</li>
                    </ul>
                </div>
            </div>
        `;

        // Add click handler to close help overlay when clicking outside content
        helpOverlay.addEventListener('click', (e) => {
            if (e.target === helpOverlay) {
                toggleHelpOverlay();
            }
        });

        document.body.appendChild(helpOverlay);
        Logger.log(Logger.levels.INFO, 'Enhanced help overlay created');
    }

    // --------------------------------
    //    ACCESSIBILITY ENHANCEMENTS
    // --------------------------------

    const accessibilityEnhancements = {
        initialize() {
            const container = document.getElementById('slideshow-container');
            if (!container) return;

            // Add ARIA attributes for better screen reader support
            container.setAttribute('role', 'region');
            container.setAttribute('aria-label', 'Thumbnail Slideshow');

            // Enhance keyboard navigation
            this.setupKeyboardNav();
            // Add announcements for screen readers
            this.setupLiveRegion();
            // Enhance button labels
            this.enhanceButtonLabels();

            Logger.log(Logger.levels.INFO, 'Accessibility enhancements initialized');
        },

        setupKeyboardNav() {
            // Add tabindex to make elements focusable
            const focusableElements = document.querySelectorAll('.slideshow-button, .slideshow-thumbnail');
            focusableElements.forEach(el => {
                el.setAttribute('tabindex', '0');
            });

            // Add key handlers for focused elements
            document.addEventListener('keydown', (e) => {
                if (e.key === 'Enter' || e.key === ' ') {
                    if (document.activeElement.classList.contains('slideshow-thumbnail')) {
                        e.preventDefault();
                        const index = parseInt(document.activeElement.dataset.index);
                        if (!isNaN(index)) {
                            currentIndex = index;
                            updateSlideshow();
                        }
                    }
                }
            });
        },

        setupLiveRegion() {
            // Create an ARIA live region for dynamic announcements
            const liveRegion = document.createElement('div');
            liveRegion.id = 'slideshow-announcer';
            liveRegion.setAttribute('aria-live', 'polite');
            liveRegion.setAttribute('aria-atomic', 'true');
            liveRegion.style.position = 'absolute';
            liveRegion.style.width = '1px';
            liveRegion.style.height = '1px';
            liveRegion.style.overflow = 'hidden';
            document.body.appendChild(liveRegion);
        },

        enhanceButtonLabels() {
            // Add descriptive ARIA labels to buttons
            const buttons = document.querySelectorAll('.slideshow-button');
            buttons.forEach(button => {
                const action = button.textContent.trim();
                let description = '';

                switch (action) {
                    case 'Prev':
                        description = 'View previous image';
                        break;
                    case 'Next':
                        description = 'View next image';
                        break;
                    case 'Play/Pause':
                        description = 'Toggle slideshow playback';
                        break;
                    // Add cases for other buttons
                }

                if (description) {
                    button.setAttribute('aria-label', description);
                }
            });
        },

        announce(message) {
            // Make announcement in live region
            const announcer = document.getElementById('slideshow-announcer');
            if (announcer) {
                announcer.textContent = message;
            }
        }
    };

    // --------------------------------
    //    DEBUG TOOLS AND MONITORING
    // --------------------------------

    const debugTools = {
        initialize() {
            // Create debug interface accessible via console
            window.WyzeSlideshow = {
                version: '1.9.14',
                getThumbnails: () => thumbnails,
                getCurrentState: () => ({
                    currentIndex,
                    isPlaying,
                    speed,
                    thumbnailCount: thumbnails.length
                }),
                forceRefresh: () => {
                    collectThumbnailsAndUpdateUI();
                    Logger.log(Logger.levels.INFO, 'Forced refresh of thumbnails');
                },
                clearCache: () => {
                    thumbnails = [];
                    currentIndex = 0;
                    updateSlideshow();
                    Logger.log(Logger.levels.INFO, 'Cleared thumbnails cache');
                },
                // Add performance monitoring
                getPerformanceMetrics: () => this.getPerformanceMetrics(),
                // Add error tracking
                getErrorLog: () => this.getErrorLog()
            };

            // Initialize performance monitoring
            this.initializePerformanceMonitoring();

            Logger.log(Logger.levels.INFO, 'Debug tools initialized');
        },

        initializePerformanceMonitoring() {
            this.performanceMetrics = {
                loadTimes: [],
                errorCount: 0,
                lastRefresh: Date.now()
            };

            // Monitor thumbnail loading performance
            const originalPreloadImage = window.preloadImage;
            window.preloadImage = (src) => {
                const startTime = performance.now();
                originalPreloadImage(src).then(() => {
                    const loadTime = performance.now() - startTime;
                    this.performanceMetrics.loadTimes.push(loadTime);
                });
            };
        },

        getPerformanceMetrics() {
            const loadTimes = this.performanceMetrics.loadTimes;
            return {
                averageLoadTime: loadTimes.reduce((a, b) => a + b, 0) / loadTimes.length,
                maxLoadTime: Math.max(...loadTimes),
                minLoadTime: Math.min(...loadTimes),
                errorCount: this.performanceMetrics.errorCount,
                uptime: Date.now() - this.performanceMetrics.lastRefresh
            };
        },

        getErrorLog() {
            return window.wyzeSlideshowLogs.filter(log =>
                log.level === Logger.levels.ERROR || log.level === Logger.levels.WARN
            );
        }
    };
// --------------------------------
    //    MEMORY MANAGEMENT SYSTEM
    // --------------------------------
/*
    const memoryManager = {
        initialize() {
            // Configure memory management settings
            this.settings = {
                maxCachedThumbnails: 50,
                // Maximum number of thumbnails to keep in memory
                cleanupInterval: 30000,
                // Run cleanup every 30 seconds
                preloadLimit: 5,
                // Number of images to preload ahead/behind
                maxLogEntries: 1000,
                // Maximum number of log entries to retain
                gcThreshold: 100
                // Run garbage collection suggestion after this many operations
            };

            // Initialize counters for garbage collection monitoring
            this.operationCount = 0;

            // Start periodic cleanup
            this.startPeriodicCleanup();

            Logger.log(Logger.levels.INFO, 'Memory management system initialized');
        },

        startPeriodicCleanup() {
            // Set up periodic cleanup of unused resources
            setInterval(() => {
                this.cleanupUnusedThumbnails();
                this.cleanupUnusedBlobs();
                this.pruneLogEntries();
                this.checkMemoryUsage();
            }, this.settings.cleanupInterval);
        },

        cleanupUnusedThumbnails() {
            // Remove excess thumbnails while keeping currently visible and adjacent ones
            if (thumbnails.length > this.settings.maxCachedThumbnails) {
                // Determine range of thumbnails to keep
                const keepStart = Math.max(0, currentIndex - this.settings.preloadLimit);
                const keepEnd = Math.min(thumbnails.length, currentIndex + this.settings.preloadLimit);

                // Remove thumbnails outside the keep range
                const removedThumbnails = thumbnails.splice(this.settings.maxCachedThumbnails);

                Logger.log(Logger.levels.INFO,
                    `Cleaned up ${removedThumbnails.length} excess thumbnails from memory`);

                // Clean up associated DOM elements
                this.cleanupThumbnailDOM();
            }
        },

        cleanupThumbnailDOM() {
            // Remove thumbnail elements that are no longer needed
            const unusedThumbs = document.querySelectorAll('.slideshow-thumbnail:not(.active)');
            unusedThumbs.forEach(thumb => {
                thumb.src = '';
                // Clear the source to help with memory
                thumb.remove();
                Logger.log(Logger.levels.DEBUG, 'Removed unused thumbnail from DOM');
            });
        },

        cleanupUnusedBlobs() {
            // Revoke any outstanding blob URLs that are no longer needed
            const blobUrls = Array.from(document.querySelectorAll('video'))
                .map(video => video.src)
                .filter(src => src.startsWith('blob:'));

            blobUrls.forEach(url => {
                if (!document.querySelector(`video[src="${url}"]`)) {
                    URL.revokeObjectURL(url);
                    Logger.log(Logger.levels.DEBUG, `Revoked unused blob URL: ${url}`);
                }
            });
        },

        pruneLogEntries() {
            // Keep log size manageable by removing oldest entries
            if (window.wyzeSlideshowLogs?.length > this.settings.maxLogEntries) {
                const exceeding = window.wyzeSlideshowLogs.length - this.settings.maxLogEntries;
                window.wyzeSlideshowLogs.splice(0, exceeding);
                Logger.log(Logger.levels.DEBUG, `Pruned ${exceeding} old log entries`);
            }
        },

        checkMemoryUsage() {
            // Monitor operation count and suggest garbage collection if needed
            this.operationCount++;

            if (this.operationCount >= this.settings.gcThreshold) {
                this.operationCount = 0;

                // Log memory usage statistics if available
                if (window.performance?.memory) {
                    const memory = window.performance.memory;
                    Logger.log(Logger.levels.INFO,
                        `Memory usage: ${Math.round(memory.usedJSHeapSize / 1048576)}MB ` +
                        `of ${Math.round(memory.jsHeapSizeLimit / 1048576)}MB`);
                }
            }
        }
    };
*/
    // --------------------------------
    //    FINAL INITIALIZATION SYSTEM
    // --------------------------------

    function initializeSlideshowSystem() {
        // Check if we're already initialized to prevent duplicate setup
        if (slideshowInitialized) {
            Logger.log(Logger.levels.WARN, 'Slideshow system already initialized');
            return;
        }

        try {
            // Initialize core components in specific order
            injectStyles();
            injectOrientationStyles();
            createSlideshowUI();
            createHelpOverlay();
            addStartButton();

            // Initialize feature systems
            improvedThumbnailCollection();
            //memoryManager.initialize();
            // touchControls.initialize();
            timelineNavigation.initialize();
            enhancedKeyboardControls.initialize();
            accessibilityEnhancements.initialize();
            debugTools.initialize();

            // Set up DOM observation for dynamic content
            observeDOMChanges();

            // Perform initial thumbnail collection
            collectThumbnailsAndUpdateUI();

            slideshowInitialized = true;
            Logger.log(Logger.levels.INFO, 'Slideshow system fully initialized');
        } catch (error) {
            Logger.log(Logger.levels.ERROR, 'Error during slideshow initialization', error);
            // Attempt to cleanup if initialization fails
            performEmergencyCleanup();
        }
    }

function performEmergencyCleanup() {
    try {
        // Define the elements array with IDs of elements to remove
        const elements = [
            'slideshow-container',
            'start-slideshow-btn',
            'slideshow-help-overlay',
            'timeline-preview',
            'loading-spinner',
            'slideshow-announcer'
        ];

        // Remove DOM elements
        elements.forEach(id => {
            const element = document.getElementById(id);
            if (element) {
                element.remove();
            }
        });

        // Rest of the function remains the same...
    } catch (error) {
        Logger.log(Logger.levels.ERROR, 'Error during emergency cleanup', error);
    }
}

// Initialize when page is ready
if (document.readyState === 'loading') {
    window.addEventListener('load', initializeSlideshowSystem);
} else {
    initializeSlideshowSystem();
}

})();
// End of IIFE