{
  "manifest_version": 3,
  "name": "Media Loader",
  "version": "1.1",
  "description": "Load and play music and videos from YouTube and Vimeo",
  "permissions": ["storage", "tabs"],
  "host_permissions": [
    "https://www.youtube.com/*",
    "https://player.vimeo.com/*"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "Open Media Loader",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  },
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
  "web_accessible_resources": [
    {
      "resources": ["lib/player.js"],
      "matches": ["<all_urls>"]
    }
  ]
}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Media Loader Dashboard</title>
    <link rel="stylesheet" href="styles.css">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <main class="container">
        <!-- Header with Settings Button and SyncWave Title -->
        <header class="header">
            <button id="settings-button" class="settings-button" title="Settings" aria-label="Open Settings">
                <img src="icons/settings.svg" alt="Settings" class="settings-icon" aria-hidden="true">
            </button>
            <h1 class="main-title">SyncWave</h1>
        </header>
        
        <!-- Load Audio Section -->
        <section class="section" id="load-music-section">
            <!-- Legends Removed -->

            <fieldset>
                <label for="music-url">Audio URL</label>
                <input type="text" id="music-url" name="music-url" placeholder="Enter YouTube or Vimeo URL">

                <label for="music-file">Local Audio File</label>
                <input type="file" id="music-file" name="music-file" accept="audio/*">

                <label for="music-start">Start Time (seconds)</label>
                <input type="number" id="music-start" name="music-start" placeholder="Start Time (seconds)" min="0">

                <button type="button" id="load-music" class="load-button">Load</button>
            </fieldset>
            <div id="music-player-container" class="player-container"></div>
        </section>

        <!-- Load Video Section -->
        <section class="section" id="load-video-section">
            <!-- Legends Removed -->

            <fieldset>
                <label for="video-url">Video URL</label>
                <input type="text" id="video-url" name="video-url" placeholder="Enter YouTube or Vimeo URL">

                <label for="video-file">Local Video File</label>
                <input type="file" id="video-file" name="video-file" accept="video/*">

                <label for="video-start">Start Time (seconds)</label>
                <input type="number" id="video-start" name="video-start" placeholder="Start Time (seconds)" min="0">

                <button type="button" id="load-video" class="load-button">Load</button>
            </fieldset>
            <div id="video-player-container" class="player-container"></div>
        </section>

        <!-- Playback Controls -->
        <section class="controls">
            <button type="button" id="play-button" disabled aria-label="Play">Play</button>
            <button type="button" id="pause-resume-button" disabled aria-label="Pause">Pause</button>
            <button type="button" id="play-start-button" disabled aria-label="Play from Start">Play from Start</button>
        </section>

        <!-- Message Container -->
        <section id="message-container" class="message-container" role="alert" aria-live="assertive"></section>

        <!-- Settings Modal (Remains Unchanged) -->
        <div id="settings-modal" class="modal" role="dialog" aria-labelledby="settings-modal-title" aria-modal="true" hidden>
            <div class="modal-content">
                <button class="close-button" aria-label="Close Settings Modal">&times;</button>
                <h2 id="settings-modal-title">Settings</h2>
                <form>
                    <label for="fullscreen-toggle">
                        <input type="checkbox" id="fullscreen-toggle" name="fullscreen-toggle">
                        Full Screen on Play
                    </label>
                    <!-- Additional settings can go here -->
                </form>
            </div>
        </div>
    </main>

    <!-- Local Vimeo Player API -->
    <script src="lib/player.js"></script>
    
    <!-- Your Dashboard JS -->
    <script src="dashboard.js"></script>
</body>
</html>

"use strict";

document.addEventListener('DOMContentLoaded', () => {
    // === Element References ===
    const elements = {
        music: {
            urlInput: document.getElementById('music-url'),
            fileInput: document.getElementById('music-file'),
            startInput: document.getElementById('music-start'),
            loadButton: document.getElementById('load-music'),
            playerContainer: document.getElementById('music-player-container')
        },
        video: {
            urlInput: document.getElementById('video-url'),
            fileInput: document.getElementById('video-file'),
            startInput: document.getElementById('video-start'),
            loadButton: document.getElementById('load-video'),
            playerContainer: document.getElementById('video-player-container')
        },
        controls: {
            playButton: document.getElementById('play-button'),
            pauseResumeButton: document.getElementById('pause-resume-button'),
            playStartButton: document.getElementById('play-start-button')
        },
        messageContainer: document.getElementById('message-container'),
        settings: {
            button: document.getElementById('settings-button'),
            modal: document.getElementById('settings-modal'),
            closeButton: document.querySelector('.close-button'),
            fullscreenToggle: document.getElementById('fullscreen-toggle')
        }
    };

    // === State Management ===
    const state = {
        music: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLAudioElement | Player, start: Number }
        video: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLVideoElement | Player, start: Number }
        isPaused: false,
        fullscreenOnPlay: false
    };

    // === Utility Functions ===

    /**
     * Formats seconds into 'XmYs' (e.g., 125 seconds -> '2m5s')
     * @param {number} seconds - The time in seconds.
     * @returns {string} Formatted time string.
     */
    function formatTime(seconds) {
        if (isNaN(seconds) || seconds < 0) return '';
        const minutes = Math.floor(seconds / 60);
        const remainingSeconds = seconds % 60;
        return `${minutes}m${remainingSeconds}s`;
    }

    /**
     * Capitalize the first letter of a string.
     * @param {string} text - The string to capitalize.
     * @returns {string} Capitalized string.
     */
    function capitalize(text) {
        if (!text) return '';
        return text.charAt(0).toUpperCase() + text.slice(1);
    }

    /**
     * Displays a message to the user.
     * @param {string} message - The message to display.
     * @param {string} type - The type of message ('success', 'error', 'info').
     */
    function showMessage(message, type) {
        elements.messageContainer.innerHTML = '';
        const msgDiv = document.createElement('div');
        msgDiv.textContent = message;
        msgDiv.classList.add('message', type); // 'success', 'error', 'info'
        elements.messageContainer.appendChild(msgDiv);

        // Automatically hide message after 5 seconds
        setTimeout(() => {
            if (elements.messageContainer.contains(msgDiv)) {
                elements.messageContainer.removeChild(msgDiv);
            }
        }, 5000);
    }

    /**
     * Shows a loading spinner in the specified container.
     * @param {HTMLElement} container - The container to show the loader in.
     */
    function showLoading(container) {
        container.innerHTML = '';
        const loader = document.createElement('div');
        loader.classList.add('loader'); // Define loader styles in CSS
        container.appendChild(loader);
    }

    /**
     * Hides the loading spinner from the specified container.
     * @param {HTMLElement} container - The container to hide the loader from.
     */
    function hideLoading(container) {
        const loader = container.querySelector('.loader');
        if (loader) {
            container.removeChild(loader);
        }
    }

    /**
     * Traps keyboard focus within a specified element.
     * @param {HTMLElement} element - The element to trap focus within.
     */
    function trapFocus(element) {
        const focusableElementsString = 'a[href], area[href], input:not([disabled]), select:not([disabled]),' +
            ' textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"],' +
            ' [contenteditable]';
        const focusableElements = element.querySelectorAll(focusableElementsString);
        const firstTabStop = focusableElements[0];
        const lastTabStop = focusableElements[focusableElements.length - 1];

        // Listen for and trap the keyboard
        element.addEventListener('keydown', trapTabKey);

        function trapTabKey(e) {
            // Check for TAB key press
            if (e.key === 'Tab') {
                // SHIFT + TAB
                if (e.shiftKey) {
                    if (document.activeElement === firstTabStop) {
                        e.preventDefault();
                        lastTabStop.focus();
                    }
                } else { // TAB
                    if (document.activeElement === lastTabStop) {
                        e.preventDefault();
                        firstTabStop.focus();
                    }
                }
            }
        }

        // Remove trap when modal is closed
        function removeTrapKey(e) {
            element.removeEventListener('keydown', trapTabKey);
        }

        // Store the function reference to remove it later
        element.removeTrapKey = removeTrapKey;
    }

    function removeTrapFocus() {
        if (elements.settings.modal.removeTrapKey) {
            elements.settings.modal.removeTrapKey();
        }
    }

    // === Initialization ===
    loadSettings();

    // === Event Listeners ===
    elements.music.loadButton.addEventListener('click', handleLoadMusic);
    elements.video.loadButton.addEventListener('click', handleLoadVideo);
    elements.controls.playButton.addEventListener('click', handlePlay);
    elements.controls.pauseResumeButton.addEventListener('click', handlePauseResume);
    elements.controls.playStartButton.addEventListener('click', handlePlayFromStart);

    // Settings Modal Event Listeners
    elements.settings.button.addEventListener('click', openSettingsModal);
    elements.settings.closeButton.addEventListener('click', closeSettingsModal);
    window.addEventListener('click', (event) => {
        if (event.target === elements.settings.modal) {
            closeSettingsModal();
        }
    });
    document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape' && !elements.settings.modal.hasAttribute('hidden')) {
            closeSettingsModal();
        }
    });
    elements.settings.fullscreenToggle.addEventListener('change', (event) => {
        state.fullscreenOnPlay = event.target.checked;
        saveSettings();
    });

    // === Handler Functions ===

    // Load Music Handler
    function handleLoadMusic() {
        const url = elements.music.urlInput.value.trim();
        const file = elements.music.fileInput.files[0];
        const start = parseInt(elements.music.startInput.value) || 0;

        // Show loading indicator
        showLoading(elements.music.playerContainer);

        // Unload existing music if any
        if (state.music) {
            unloadMedia('music');
        }

        if (file) {
            if (file.size > 10 * 1024 * 1024) { // 10MB limit
                showMessage('Audio file size exceeds 10MB limit.', 'error');
                hideLoading(elements.music.playerContainer);
                return;
            }

            // Handle local audio file
            const fileUrl = URL.createObjectURL(file);
            const audioElement = document.createElement('audio');
            audioElement.controls = true;
            audioElement.src = fileUrl;
            audioElement.id = 'loaded-music';
            audioElement.setAttribute('aria-label', 'Loaded Audio Player');
            audioElement.style.width = '100%';
            audioElement.style.height = 'auto';
            elements.music.playerContainer.innerHTML = '';
            elements.music.playerContainer.appendChild(audioElement);

            // Set start time if applicable
            if (start > 0) {
                audioElement.currentTime = start;
            }

            state.music = {
                type: 'file',
                element: audioElement,
                start: start
            };
            showMessage('Local audio file loaded.', 'success');
            hideLoading(elements.music.playerContainer);
        } else if (url && isValidMediaURL(url)) {
            const mediaInfo = extractMediaInfo(url);
            if (mediaInfo) {
                if (mediaInfo.platform === 'youtube') {
                    embedYouTubeIframe(mediaInfo.id, start, 'music');
                } else if (mediaInfo.platform === 'vimeo') {
                    embedVimeoPlayer(mediaInfo.id, start, 'music');
                }
                showMessage(`Loaded ${capitalize(mediaInfo.platform)} audio.`, 'success');
                hideLoading(elements.music.playerContainer);
            } else {
                showMessage('Invalid URL. Please enter a valid YouTube or Vimeo URL.', 'error');
                hideLoading(elements.music.playerContainer);
            }
        } else {
            showMessage('Please enter a URL or select a local audio file.', 'error');
            hideLoading(elements.music.playerContainer);
        }

        checkReadyToPlay();
        saveSettings();
    }

    // Load Video Handler
    function handleLoadVideo() {
        const url = elements.video.urlInput.value.trim();
        const file = elements.video.fileInput.files[0];
        const start = parseInt(elements.video.startInput.value) || 0;

        // Show loading indicator
        showLoading(elements.video.playerContainer);

        // Unload existing video if any
        if (state.video) {
            unloadMedia('video');
        }

        if (file) {
            if (file.size > 50 * 1024 * 1024) { // 50MB limit
                showMessage('Video file size exceeds 50MB limit.', 'error');
                hideLoading(elements.video.playerContainer);
                return;
            }

            // Handle local video file
            const fileUrl = URL.createObjectURL(file);
            const videoElement = document.createElement('video');
            videoElement.controls = true;
            videoElement.src = fileUrl;
            videoElement.id = 'loaded-video';
            videoElement.setAttribute('aria-label', 'Loaded Video Player');
            videoElement.style.width = '100%';
            videoElement.style.height = 'auto';
            elements.video.playerContainer.innerHTML = '';
            elements.video.playerContainer.appendChild(videoElement);

            // Set start time if applicable
            if (start > 0) {
                videoElement.currentTime = start;
            }

            state.video = {
                type: 'file',
                element: videoElement,
                start: start
            };
            showMessage('Local video file loaded.', 'success');
            hideLoading(elements.video.playerContainer);
        } else if (url && isValidMediaURL(url)) {
            const mediaInfo = extractMediaInfo(url);
            if (mediaInfo) {
                if (mediaInfo.platform === 'youtube') {
                    embedYouTubeIframe(mediaInfo.id, start, 'video');
                } else if (mediaInfo.platform === 'vimeo') {
                    embedVimeoPlayer(mediaInfo.id, start, 'video');
                }
                showMessage(`Loaded ${capitalize(mediaInfo.platform)} video.`, 'success');
                hideLoading(elements.video.playerContainer);
            } else {
                showMessage('Invalid URL. Please enter a valid YouTube or Vimeo URL.', 'error');
                hideLoading(elements.video.playerContainer);
            }
        } else {
            showMessage('Please enter a URL or select a local video file.', 'error');
            hideLoading(elements.video.playerContainer);
        }

        checkReadyToPlay();
        saveSettings();
    }

    // Play Handler
    function handlePlay() {
        // Play Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.music.element);
                }
            } else if (state.music.type === 'vimeo') {
                state.music.element.play().catch(error => {
                    console.error('Error playing Vimeo audio:', error);
                    showMessage('Failed to play Vimeo audio.', 'error');
                });
            }
            // YouTube control can be added similarly if integrated
        }

        // Play Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.video.element);
                }
            } else if (state.video.type === 'vimeo') {
                state.video.element.play().catch(error => {
                    console.error('Error playing Vimeo video:', error);
                    showMessage('Failed to play Vimeo video.', 'error');
                });
            }
            // YouTube control can be added similarly if integrated
        }

        state.isPaused = false;
        elements.controls.pauseResumeButton.textContent = 'Pause';
        showMessage('Playback started!', 'success');
    }

    // Pause/Resume Handler
    function handlePauseResume() {
        if (state.isPaused) {
            resumeMedia();
        } else {
            pauseMedia();
        }
    }

    // Pause Media
    function pauseMedia() {
        // Pause Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.pause();
            } else if (state.music.type === 'vimeo') {
                state.music.element.pause().catch(error => {
                    console.error('Error pausing Vimeo audio:', error);
                    showMessage('Failed to pause Vimeo audio.', 'error');
                });
            }
        }

        // Pause Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.pause();
            } else if (state.video.type === 'vimeo') {
                state.video.element.pause().catch(error => {
                    console.error('Error pausing Vimeo video:', error);
                    showMessage('Failed to pause Vimeo video.', 'error');
                });
            }
        }

        state.isPaused = true;
        elements.controls.pauseResumeButton.textContent = 'Resume';
        showMessage('Playback paused.', 'info');
    }

    // Resume Media
    function resumeMedia() {
        // Resume Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.play();
            } else if (state.music.type === 'vimeo') {
                state.music.element.play().catch(error => {
                    console.error('Error resuming Vimeo audio:', error);
                    showMessage('Failed to resume Vimeo audio.', 'error');
                });
            }
        }

        // Resume Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.play();
            } else if (state.video.type === 'vimeo') {
                state.video.element.play().catch(error => {
                    console.error('Error resuming Vimeo video:', error);
                    showMessage('Failed to resume Vimeo video.', 'error');
                });
            }
        }

        state.isPaused = false;
        elements.controls.pauseResumeButton.textContent = 'Pause';
        showMessage('Playback resumed.', 'success');
    }

    // Play From Start Handler
    function handlePlayFromStart() {
        // Play from Start Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.currentTime = state.music.start;
                state.music.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.music.element);
                }
            } else if (state.music.type === 'vimeo') {
                state.music.element.setCurrentTime(state.music.start).then(() => {
                    return state.music.element.play();
                }).catch(error => {
                    console.error('Error playing from start in Vimeo audio:', error);
                    showMessage('Failed to play from start in Vimeo audio.', 'error');
                });
            }
        }

        // Play from Start Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.currentTime = state.video.start;
                state.video.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.video.element);
                }
            } else if (state.video.type === 'vimeo') {
                state.video.element.setCurrentTime(state.video.start).then(() => {
                    return state.video.element.play();
                }).catch(error => {
                    console.error('Error playing from start in Vimeo video:', error);
                    showMessage('Failed to play from start in Vimeo video.', 'error');
                });
            }
        }

        state.isPaused = false;
        elements.controls.pauseResumeButton.textContent = 'Pause';
        showMessage('Playback restarted!', 'success');
    }

    // === Settings Modal Functions ===
    function openSettingsModal() {
        elements.settings.modal.removeAttribute('hidden');
        elements.settings.modal.setAttribute('aria-hidden', 'false');
        elements.settings.modal.querySelector('.close-button').focus();
        trapFocus(elements.settings.modal);
    }

    function closeSettingsModal() {
        elements.settings.modal.setAttribute('hidden', '');
        elements.settings.modal.setAttribute('aria-hidden', 'true');
        elements.settings.button.focus();
        removeTrapFocus();
    }

    // === Media Embedding Functions ===

    /**
     * Embeds a YouTube video into the specified container using an iframe.
     * Mutes the video and starts at the specified time without autoplay.
     * @param {string} videoId - The YouTube video ID.
     * @param {number} start - The start time in seconds.
     * @param {string} mediaType - 'music' or 'video'.
     */
    function embedYouTubeIframe(videoId, start, mediaType) {
        const container = elements[mediaType].playerContainer;
        container.innerHTML = ''; // Clear previous content

        let src = `https://www.youtube.com/embed/${videoId}?mute=1&start=${start}&controls=1&rel=0`;
        // Note: autoplay=1 removed to prevent auto-play

        const iframe = document.createElement('iframe');
        iframe.src = src;
        iframe.width = '100%';
        iframe.height = '720'; // Increased height
        iframe.frameBorder = '0';
        iframe.allow = 'autoplay; fullscreen; picture-in-picture';

        iframe.setAttribute('title', 'YouTube video player');

        container.appendChild(iframe);

        state[mediaType] = {
            type: 'youtube',
            element: iframe,
            start: start
        };
    }

    /**
     * Embeds a Vimeo video into the specified container using the Player API.
     * Mutes the video and starts at the specified time without autoplay.
     * @param {string} videoId - The Vimeo video ID.
     * @param {number} start - The start time in seconds.
     * @param {string} mediaType - 'music' or 'video'.
     */
    function embedVimeoPlayer(videoId, start, mediaType) {
        const container = elements[mediaType].playerContainer;
        container.innerHTML = ''; // Clear previous content

        const iframe = document.createElement('iframe');
        const src = `https://player.vimeo.com/video/${videoId}?muted=1&autopause=0&background=0`;
        iframe.src = src;
        iframe.width = '100%';
        iframe.height = '720'; // Increased height
        iframe.frameBorder = '0';
        iframe.allow = 'autoplay; fullscreen; picture-in-picture';

        iframe.setAttribute('title', 'Vimeo video player');

        container.appendChild(iframe);

        const player = new Vimeo.Player(iframe, {
            id: videoId,
            width: container.clientWidth,
            muted: true,
            autoplay: false,
            start: start
        });

        state[mediaType] = {
            type: 'vimeo',
            element: player,
            start: start
        };

        // Ensure buffering by loading the video without autoplay
        player.setVolume(0).catch(error => {
            console.error(`Error setting volume for Vimeo ${mediaType}:`, error);
        });
    }

    // === Settings Management ===

    /**
     * Loads settings from Chrome storage.
     */
    function loadSettings() {
        try {
            chrome.storage.local.get(['mediaSettings'], (result) => {
                if (chrome.runtime.lastError) {
                    throw new Error(chrome.runtime.lastError);
                }

                if (result.mediaSettings) {
                    const { music, video, fullscreenOnPlay: fsPlay } = result.mediaSettings;

                    if (music) {
                        if (music.type === 'youtube' 
                            || music.type === 'vimeo') {
                            const url = music.type === 'youtube' 
                                ? `https://www.youtube.com/watch?v=${music.id}` 
                                : `https://vimeo.com/${music.id}`;
                            elements.music.urlInput.value = url;
                            elements.music.startInput.value = music.start || 0;
                            // Optionally, auto-load the media by triggering the load button
                            // handleLoadMusic();
                        }
                        // Handle file-based music loading if necessary
                    }

                    if (video) {
                        if (video.type === 'youtube' 
                            || video.type === 'vimeo') {
                            const url = video.type === 'youtube' 
                                ? `https://www.youtube.com/watch?v=${video.id}` 
                                : `https://vimeo.com/${video.id}`;
                            elements.video.urlInput.value = url;
                            elements.video.startInput.value = video.start || 0;
                            // Optionally, auto-load the media by triggering the load button
                            // handleLoadVideo();
                        }
                        // Handle file-based video loading if necessary
                    }

                    if (typeof fsPlay === 'boolean') {
                        state.fullscreenOnPlay = fsPlay;
                        elements.settings.fullscreenToggle.checked = fsPlay;
                    }
                }
            });
        } catch (error) {
            console.error('Error loading settings:', error);
            showMessage('Failed to load settings.', 'error');
        }
    }

    /**
     * Saves settings to Chrome storage.
     */
    function saveSettings() {
        const settings = {
            music: state.music,
            video: state.video,
            fullscreenOnPlay: state.fullscreenOnPlay
        };
        try {
            chrome.storage.local.set({ mediaSettings: settings }, () => {
                if (chrome.runtime.lastError) {
                    throw new Error(chrome.runtime.lastError);
                }
                console.log('Settings saved.');
            });
        } catch (error) {
            console.error('Error saving settings:', error);
            showMessage('Error saving settings.', 'error');
        }
    }

    /**
     * Unloads media from the specified type.
     * @param {string} mediaType - 'music' or 'video'.
     */
    function unloadMedia(mediaType) {
        if (state[mediaType]) {
            if (state[mediaType].type === 'file') {
                if (state[mediaType].element.src) {
                    URL.revokeObjectURL(state[mediaType].element.src);
                    state[mediaType].element.src = '';
                    state[mediaType].element.remove();
                }
            } else if (state[mediaType].type === 'youtube') {
                const iframe = state[mediaType].element;
                iframe.src = ''; // Reset iframe src to stop the media
            } else if (state[mediaType].type === 'vimeo') {
                const player = state[mediaType].element;
                player.unload().catch(error => {
                    console.error(`Error unloading Vimeo ${mediaType}:`, error);
                });
            }
            state[mediaType] = null;
        }
    }

    // === Playback Controls ===

    /**
     * Enables or disables playback controls based on media loading state.
     */
    function checkReadyToPlay() {
        // Enable Play button only when at least one of audio or video is loaded
        const readyAudio = state.music 
            && (state.music.type === 'file' 
                || state.music.type === 'youtube' 
                || state.music.type === 'vimeo');
        const readyVideo = state.video 
            && (state.video.type === 'file' 
                || state.video.type === 'youtube' 
                || state.video.type === 'vimeo');
        const ready = readyAudio || readyVideo;

        elements.controls.playButton.disabled = !ready;
        elements.controls.pauseResumeButton.disabled = !ready;
        elements.controls.playStartButton.disabled = !ready;
    }

    /**
     * Enters fullscreen mode for the specified element.
     * @param {HTMLElement} element - The element to enter fullscreen.
     */
    function enterFullscreen(element) {
        if (element && element.element && element.element.requestFullscreen) {
            element.element.requestFullscreen().then(() => {
                showMessage('Entered fullscreen mode.', 'success');
            }).catch(err => {
                console.error(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
                showMessage('Failed to enter fullscreen mode.', 'error');
            });
        } else if (element && element.requestFullscreen) {
            element.requestFullscreen().then(() => {
                showMessage('Entered fullscreen mode.', 'success');
            }).catch(err => {
                console.error(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
                showMessage('Failed to enter fullscreen mode.', 'error');
            });
        } else {
            showMessage('Fullscreen not supported on this element.', 'error');
        }
    }

    // === New Utility Functions ===

    /**
     * Validates whether the URL is a valid YouTube or Vimeo URL.
     * @param {string} url - The URL to validate.
     * @returns {boolean} True if valid, else false.
     */
    function isValidMediaURL(url) {
        try {
            const parsedUrl = new URL(url);
            const hostname = parsedUrl.hostname.toLowerCase();
            const pathname = parsedUrl.pathname;

            // YouTube RegEx Patterns
            const youtubeRegex = /^(?:\/watch\/?|\/embed\/|\/v\/)?([a-zA-Z0-9_-]{11})$/;
            // Vimeo RegEx Patterns
            const vimeoRegex = /^\/(?:video\/)?(\d+)$/;

            if (hostname.includes('youtube.com') || hostname === 'youtu.be') {
                // Extract YouTube video ID
                let videoId = '';
                if (hostname === 'youtu.be') {
                    videoId = pathname.slice(1);
                } else {
                    videoId = parsedUrl.searchParams.get('v') || '';
                }
                return youtubeRegex.test(`/${videoId}`);
            } else if (hostname.includes('vimeo.com')) {
                // Extract Vimeo video ID
                const match = pathname.match(vimeoRegex);
                return match && match[1].length > 0;
            }

            return false;
        } catch (e) {
            return false;
        }
    }

    /**
     * Extracts media information from the URL.
     * @param {string} url - The media URL.
     * @returns {Object|null} An object with platform and id, or null if invalid.
     */
    function extractMediaInfo(url) {
        try {
            const parsedUrl = new URL(url);
            const hostname = parsedUrl.hostname.toLowerCase();
            const pathname = parsedUrl.pathname;

            // YouTube Patterns
            if (hostname.includes('youtube.com') 
                || hostname === 'youtu.be') {
                let videoId = '';
                if (hostname === 'youtu.be') {
                    videoId = pathname.slice(1);
                } else {
                    videoId = parsedUrl.searchParams.get('v') || '';
                }

                // Validate videoId length
                if (videoId.length === 11) {
                    return { platform: 'youtube', id: videoId };
                }
            }

            // Vimeo Patterns
            if (hostname.includes('vimeo.com')) {
                const vimeoMatch = pathname.match(/^\/(?:video\/)?(\d+)$/);
                if (vimeoMatch && vimeoMatch[1]) {
                    return { platform: 'vimeo', id: vimeoMatch[1] };
                }
            }

            return null;
        } catch (e) {
            return null;
        }
    }
});

chrome.action.onClicked.addListener(() => {
    const dashboardURL = chrome.runtime.getURL("dashboard.html");
    
    // Query for any existing tabs with the dashboard URL
    chrome.tabs.query({ url: dashboardURL }, (tabs) => {
        if (chrome.runtime.lastError) {
            console.error("Tab Query Error:", chrome.runtime.lastError);
            return;
        }

        if (tabs.length > 0) {
            // Activate the first existing dashboard tab
            chrome.tabs.update(tabs[0].id, { active: true }, (updatedTab) => {
                if (chrome.runtime.lastError) {
                    console.error("Tab Update Error:", chrome.runtime.lastError);
                }
            });
        } else {
            // Create a new dashboard tab
            chrome.tabs.create({ url: dashboardURL, active: true }, (newTab) => {
                if (chrome.runtime.lastError) {
                    console.error("Tab Creation Error:", chrome.runtime.lastError);
                }
            });
        }
    });
});

/* General Styles */
body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    margin: 0;
    padding: 0;
}

.container {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 20px;
    max-width: 1000px; /* Increased max-width for larger displays */
    margin: 0 auto;
}

.section {
    width: 100%;
    margin-bottom: 20px;
    background-color: #fff;
    padding: 15px;
    border-radius: 8px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

/* Header with Settings Button and Main Title */
.header {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center; /* Center the content */
    margin-bottom: 20px;
    position: relative;
}

.settings-button {
    position: absolute;
    left: 0;
    background: #fff;
    border: 1px solid #ccc;
    border-radius: 5px;
    padding: 5px;
    cursor: pointer;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.3s ease, border-color 0.3s ease;
}

.settings-button:hover {
    background-color: #f0f0f0;
    border-color: #999;
}

.settings-icon {
    width: 20px;
    height: 20px;
}

.main-title {
    font-size: 2.5em; /* Increased font size for better visibility */
    font-weight: bold;
    margin: 0;
    opacity: 0;
    animation: fadeInShake 5s forwards;
}

@keyframes fadeInShake {
    0% {
        opacity: 0;
        transform: translateX(0);
        color: #FF0000; /* Red */
    }
    10% {
        opacity: 0.2;
        transform: translateX(-10px);
        color: #FF7F00; /* Orange */
    }
    20% {
        opacity: 0.4;
        transform: translateX(10px);
        color: #FFFF00; /* Yellow */
    }
    30% {
        opacity: 0.6;
        transform: translateX(-10px);
        color: #00FF00; /* Green */
    }
    40% {
        opacity: 0.7;
        transform: translateX(10px);
        color: #0000FF; /* Blue */
    }
    50% {
        opacity: 0.8;
        transform: translateX(-10px);
        color: #4B0082; /* Indigo */
    }
    60% {
        opacity: 0.85;
        transform: translateX(10px);
        color: #8B00FF; /* Violet */
    }
    70% {
        opacity: 0.9;
        transform: translateX(-10px);
        color: #FF00FF; /* Magenta */
    }
    80% {
        opacity: 0.95;
        transform: translateX(10px);
        color: #000000; /* Black */
    }
    100% {
        opacity: 1;
        transform: translateX(0);
        color: #000000; /* Black */
    }
}

/* Controls */
.controls {
    display: flex;
    gap: 10px;
    margin-bottom: 20px;
}

.controls button {
    padding: 12px 24px; /* Increased padding for better accessibility */
    cursor: pointer;
    border: none;
    border-radius: 5px;
    background-color: #4285f4;
    color: #fff;
    transition: background-color 0.3s ease;
    font-size: 1em;
}

.controls button:disabled {
    background-color: #a0c3ff;
    cursor: not-allowed;
}

.controls button:hover:not(:disabled) {
    background-color: #357ae8;
}

/* Modal Styles */
.modal[hidden] {
    display: none;
}

.modal {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.5);
    display: flex; /* Visible when not hidden */
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

.modal-content {
    background-color: #fff;
    padding: 20px 30px;
    border-radius: 8px;
    width: 90%;
    max-width: 500px; /* Increased max-width for better layout */
    position: relative;
}

.close-button {
    position: absolute;
    top: 10px;
    right: 15px;
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
}

.modal-content h2 {
    margin-top: 0;
}

/* Form Elements */
fieldset {
    border: none;
    padding: 0;
}

fieldset label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold;
}

fieldset input[type="text"],
fieldset input[type="number"],
fieldset input[type="file"] {
    width: 100%;
    padding: 10px; /* Increased padding for better usability */
    margin-bottom: 15px;
    box-sizing: border-box;
    border: 1px solid #ccc;
    border-radius: 4px;
}

fieldset .load-button {
    width: 100%;
    padding: 12px;
    background-color: #34a853;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s ease;
    font-size: 1em;
}

fieldset .load-button:hover {
    background-color: #2c8e46;
}

/* Player Containers */
.player-container {
    margin-top: 10px;
    width: 100%;
    max-width: 100%;
    min-height: 100px; /* Increased minimum height */
    box-sizing: border-box;
    overflow: hidden; /* Prevent overflow */
}

/* Responsive Video and Audio Elements */
.player-container video,
.player-container iframe {
    width: 100%;
    height: 720px; /* Fixed height for consistency */
    border-radius: 8px;
    /* Ensure the iframe fills the container */
    display: block;
}

/* Messages */
.message-container {
    margin-top: 20px;
    width: 100%;
}

.message {
    padding: 12px;
    border-radius: 5px;
    margin-bottom: 10px;
    color: #fff;
    font-size: 1em;
}

.message.success {
    background-color: #4caf50;
}

.message.error {
    background-color: #f44336;
}

.message.info {
    background-color: #2196f3;
}

/* Loader */
.loader {
    border: 8px solid #f3f3f3; /* Light grey */
    border-top: 8px solid #4285f4; /* Blue */
    border-radius: 50%;
    width: 60px; /* Increased size for better visibility */
    height: 60px; /* Increased size for better visibility */
    animation: spin 1s linear infinite;
    margin: 0 auto;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

/* Responsive Design */
@media (max-width: 800px) {
    .container {
        padding: 15px;
    }

    .modal-content {
        padding: 15px 20px;
    }

    .controls {
        flex-direction: column;
        width: 100%;
    }

    .controls button {
        width: 100%;
    }

    .settings-button {
        width: 35px;
        height: 35px;
    }

    .settings-icon {
        width: 18px;
        height: 18px;
    }

    .main-title {
        font-size: 2em;
    }

    .player-container video,
    .player-container iframe {
        height: 480px; /* Adjusted height for smaller screens */
    }

    .loader {
        width: 50px; /* Adjusted size for smaller screens */
        height: 50px; /* Adjusted size for smaller screens */
    }
}

@media (max-width: 500px) {
    .container {
        padding: 10px;
    }

    .controls button {
        padding: 10px;
        font-size: 0.9em;
    }

    .modal-content {
        padding: 10px 15px;
    }

    .main-title {
        font-size: 1.8em;
    }

    .player-container video,
    .player-container iframe {
        height: 360px; /* Further adjusted height for very small screens */
    }

    .loader {
        width: 40px; /* Further adjusted size for very small screens */
        height: 40px; /* Further adjusted size for very small screens */
    }
}



{
"manifest_version": 3,
"name": "Media Loader",
"version": "1.0",
"description": "Load and play music and videos from YouTube and Vimeo",
"permissions": ["storage", "tabs"],
"host_permissions": [
"https://www.youtube.com/",
"https://player.vimeo.com/"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Open Media Loader",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
}
}

Settings
SyncWave


<!-- Load Audio Section -->
<section class="section" id="load-music-section">
    <div class="section-header">
        <legend>Load Audio</legend>
    </div>
    
    <fieldset>
        <label for="music-url">Audio URL</label>
        <input type="text" id="music-url" name="music-url" placeholder="Enter YouTube or Vimeo URL">

        <label for="music-file">Upload Audio File</label>
        <input type="file" id="music-file" name="music-file" accept="audio/*">

        <label for="music-start">Start Time (seconds)</label>
        <input type="number" id="music-start" name="music-start" placeholder="Start Time (seconds)" min="0">

        <button type="button" id="load-music" class="load-button">Load Audio</button>
    </fieldset>
    <div id="music-player-container" class="player-container"></div>
</section>

<!-- Load Video Section -->
<section class="section" id="load-video-section">
    <fieldset>
        <legend>Load Video</legend>
        
        <label for="video-url">Video URL</label>
        <input type="text" id="video-url" name="video-url" placeholder="Enter YouTube or Vimeo URL">

        <label for="video-file">Upload Video File</label>
        <input type="file" id="video-file" name="video-file" accept="video/*">

        <label for="video-start">Start Time (seconds)</label>
        <input type="number" id="video-start" name="video-start" placeholder="Start Time (seconds)" min="0">

        <button type="button" id="load-video" class="load-button">Load Video</button>
    </fieldset>
    <div id="video-player-container" class="player-container"></div>
</section>

<!-- Playback Controls -->
<section class="controls">
    <button type="button" id="play-button" disabled aria-label="Play">Play</button>
    <button type="button" id="pause-resume-button" disabled aria-label="Pause">Pause</button>
    <button type="button" id="play-start-button" disabled aria-label="Play from Start">Play from Start</button>
</section>

<!-- Message Container -->
<section id="message-container" class="message-container" role="alert" aria-live="assertive"></section>

<!-- Settings Modal (Remains Unchanged) -->
<div id="settings-modal" class="modal" role="dialog" aria-labelledby="settings-modal-title" aria-modal="true" hidden>
    <div class="modal-content">
        <button class="close-button" aria-label="Close Settings Modal">&times;</button>
        <h2 id="settings-modal-title">Settings</h2>
        <form>
            <label for="fullscreen-toggle">
                <input type="checkbox" id="fullscreen-toggle" name="fullscreen-toggle">
                Full Screen on Play
            </label>
            <!-- Additional settings can go here -->
        </form>
    </div>
</div>
"use strict";

document.addEventListener('DOMContentLoaded', () => {
// === Element References ===
const elements = {
music: {
urlInput: document.getElementById('music-url'),
fileInput: document.getElementById('music-file'),
startInput: document.getElementById('music-start'),
loadButton: document.getElementById('load-music'),
playerContainer: document.getElementById('music-player-container')
},
video: {
urlInput: document.getElementById('video-url'),
fileInput: document.getElementById('video-file'),
startInput: document.getElementById('video-start'),
loadButton: document.getElementById('load-video'),
playerContainer: document.getElementById('video-player-container')
},
controls: {
playButton: document.getElementById('play-button'),
pauseResumeButton: document.getElementById('pause-resume-button'),
playStartButton: document.getElementById('play-start-button')
},
messageContainer: document.getElementById('message-container'),
settings: {
button: document.getElementById('settings-button'),
modal: document.getElementById('settings-modal'),
closeButton: document.querySelector('.close-button'),
fullscreenToggle: document.getElementById('fullscreen-toggle')
}
};

// === State Management ===
const state = {
music: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLAudioElement | HTMLIFrameElement, start: Number }
video: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLVideoElement | HTMLIFrameElement, start: Number }
isPaused: false,
fullscreenOnPlay: false
};

// === Utility Functions ===

/**

Formats seconds into 'XmYs' (e.g., 125 seconds -> '2m5s')
@param {number} seconds - The time in seconds.
@returns {string} Formatted time string.
*/
function formatTime(seconds) {
if (isNaN(seconds) || seconds < 0) return '';
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return ${minutes}m${remainingSeconds}s;
}
/**

Capitalize the first letter of a string.
@param {string} text - The string to capitalize.
@returns {string} Capitalized string.
*/
function capitalize(text) {
if (!text) return '';
return text.charAt(0).toUpperCase() + text.slice(1);
}
/**

Displays a message to the user.
@param {string} message - The message to display.
@param {string} type - The type of message ('success', 'error', 'info').
*/
function showMessage(message, type) {
elements.messageContainer.innerHTML = '';
const msgDiv = document.createElement('div');
msgDiv.textContent = message;
msgDiv.classList.add('message', type); // 'success', 'error', 'info'
elements.messageContainer.appendChild(msgDiv); // Automatically hide message after 5 seconds
setTimeout(() => {
if (elements.messageContainer.contains(msgDiv)) {
elements.messageContainer.removeChild(msgDiv);
}
}, 5000);
}

/**

Shows a loading spinner in the specified container.
@param {HTMLElement} container - The container to show the loader in.
*/
function showLoading(container) {
container.innerHTML = '';
const loader = document.createElement('div');
loader.classList.add('loader'); // Define loader styles in CSS
container.appendChild(loader);
}
/**

Hides the loading spinner from the specified container.
@param {HTMLElement} container - The container to hide the loader from.
*/
function hideLoading(container) {
const loader = container.querySelector('.loader');
if (loader) {
container.removeChild(loader);
}
}
/**

Traps keyboard focus within a specified element.
@param {HTMLElement} element - The element to trap focus within.
*/
function trapFocus(element) {
const focusableElementsString = 'a[href], area[href], input:not([disabled]), select:not([disabled]),' +
' textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"],' +
' [contenteditable]';
const focusableElements = element.querySelectorAll(focusableElementsString);
const firstTabStop = focusableElements[0];
const lastTabStop = focusableElements[focusableElements.length - 1]; // Listen for and trap the keyboard
element.addEventListener('keydown', trapTabKey); function trapTabKey(e) {
// Check for TAB key press
if (e.key === 'Tab') {
// SHIFT + TAB
if (e.shiftKey) {
if (document.activeElement === firstTabStop) {
e.preventDefault();
lastTabStop.focus();
}
} else { // TAB
if (document.activeElement === lastTabStop) {
e.preventDefault();
firstTabStop.focus();
}
}
}
} // Remove trap when modal is closed
function removeTrapKey(e) {
element.removeEventListener('keydown', trapTabKey);
} // Store the function reference to remove it later
element.removeTrapKey = removeTrapKey;
}

function removeTrapFocus() {
if (elements.settings.modal.removeTrapKey) {
elements.settings.modal.removeTrapKey();
}
}

// === Initialization ===
loadSettings();

// === Event Listeners ===
elements.music.loadButton.addEventListener('click', handleLoadMusic);
elements.video.loadButton.addEventListener('click', handleLoadVideo);
elements.controls.playButton.addEventListener('click', handlePlay);
elements.controls.pauseResumeButton.addEventListener('click', handlePauseResume);
elements.controls.playStartButton.addEventListener('click', handlePlayFromStart);

// Settings Modal Event Listeners
elements.settings.button.addEventListener('click', openSettingsModal);
elements.settings.closeButton.addEventListener('click', closeSettingsModal);
window.addEventListener('click', (event) => {
if (event.target === elements.settings.modal) {
closeSettingsModal();
}
});
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && !elements.settings.modal.hasAttribute('hidden')) {
closeSettingsModal();
}
});
elements.settings.fullscreenToggle.addEventListener('change', (event) => {
state.fullscreenOnPlay = event.target.checked;
saveSettings();
});

// === Handler Functions ===

// Load Music Handler
function handleLoadMusic() {
const url = elements.music.urlInput.value.trim();
const file = elements.music.fileInput.files[0];
const start = parseInt(elements.music.startInput.value) || 0;


// Show loading indicator
showLoading(elements.music.playerContainer);

// Unload existing music if any
if (state.music) {
    unloadMedia('music');
}

if (file) {
    if (file.size > 10 * 1024 * 1024) { // 10MB limit
        showMessage('Audio file size exceeds 10MB limit.', 'error');
        hideLoading(elements.music.playerContainer);
        return;
    }

    // Handle local audio file
    const fileUrl = URL.createObjectURL(file);
    const audioElement = document.createElement('audio');
    audioElement.controls = true;
    audioElement.src = fileUrl;
    audioElement.id = 'loaded-music';
    audioElement.setAttribute('aria-label', 'Loaded Audio Player');
    audioElement.style.width = '100%';
    audioElement.style.height = 'auto';
    elements.music.playerContainer.innerHTML = '';
    elements.music.playerContainer.appendChild(audioElement);

    // Set start time if applicable
    if (start > 0) {
        audioElement.currentTime = start;
    }

    state.music = {
        type: 'file',
        element: audioElement,
        start: start
    };
    showMessage('Local audio file loaded.', 'success');
    hideLoading(elements.music.playerContainer);
} else if (url && isValidMediaURL(url)) {
    const mediaInfo = extractMediaInfo(url);
    if (mediaInfo) {
        if (mediaInfo.platform === 'youtube') {
            embedYouTubeIframe(mediaInfo.id, start, 'music');
        } else if (mediaInfo.platform === 'vimeo') {
            embedVimeoIframe(mediaInfo.id, start, 'music');
        }
        showMessage(`Loaded ${capitalize(mediaInfo.platform)} audio.`, 'success');
        hideLoading(elements.music.playerContainer);
    } else {
        showMessage('Invalid URL. Please enter a valid YouTube or Vimeo URL.', 'error');
        hideLoading(elements.music.playerContainer);
    }
} else {
    showMessage('Please enter a URL or select an audio file.', 'error');
    hideLoading(elements.music.playerContainer);
}

checkReadyToPlay();
saveSettings();
}

// Load Video Handler
function handleLoadVideo() {
const url = elements.video.urlInput.value.trim();
const file = elements.video.fileInput.files[0];
const start = parseInt(elements.video.startInput.value) || 0;


// Show loading indicator
showLoading(elements.video.playerContainer);

// Unload existing video if any
if (state.video) {
    unloadMedia('video');
}

if (file) {
    if (file.size > 50 * 1024 * 1024) { // 50MB limit
        showMessage('Video file size exceeds 50MB limit.', 'error');
        hideLoading(elements.video.playerContainer);
        return;
    }

    // Handle local video file
    const fileUrl = URL.createObjectURL(file);
    const videoElement = document.createElement('video');
    videoElement.controls = true;
    videoElement.src = fileUrl;
    videoElement.id = 'loaded-video';
    videoElement.setAttribute('aria-label', 'Loaded Video Player');
    videoElement.style.width = '100%';
    videoElement.style.height = 'auto';
    elements.video.playerContainer.innerHTML = '';
    elements.video.playerContainer.appendChild(videoElement);

    // Set start time if applicable
    if (start > 0) {
        videoElement.currentTime = start;
    }

    state.video = {
        type: 'file',
        element: videoElement,
        start: start
    };
    showMessage('Local video file loaded.', 'success');
    hideLoading(elements.video.playerContainer);
} else if (url && isValidMediaURL(url)) {
    const mediaInfo = extractMediaInfo(url);
    if (mediaInfo) {
        if (mediaInfo.platform === 'youtube') {
            embedYouTubeIframe(mediaInfo.id, start, 'video');
        } else if (mediaInfo.platform === 'vimeo') {
            embedVimeoIframe(mediaInfo.id, start, 'video');
        }
        showMessage(`Loaded ${capitalize(mediaInfo.platform)} video.`, 'success');
        hideLoading(elements.video.playerContainer);
    } else {
        showMessage('Invalid URL. Please enter a valid YouTube or Vimeo URL.', 'error');
        hideLoading(elements.video.playerContainer);
    }
} else {
    showMessage('Please enter a URL or select a video file.', 'error');
    hideLoading(elements.video.playerContainer);
}

checkReadyToPlay();
saveSettings();
}

// Play Handler
function handlePlay() {
// Play Music
if (state.music) {
if (state.music.type === 'file') {
state.music.element.play();
if (state.fullscreenOnPlay) {
enterFullscreen(state.music.element);
}
} else {
// Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
showMessage('Cannot control external media playback programmatically.', 'info');
}
}


// Play Video
if (state.video) {
    if (state.video.type === 'file') {
        state.video.element.play();
        if (state.fullscreenOnPlay) {
            enterFullscreen(state.video.element);
        }
    } else {
        // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
        showMessage('Cannot control external media playback programmatically.', 'info');
    }
}

state.isPaused = false;
elements.controls.pauseResumeButton.textContent = 'Pause';
showMessage('Playback started!', 'success');
}

// Pause/Resume Handler
function handlePauseResume() {
if (state.isPaused) {
resumeMedia();
} else {
pauseMedia();
}
}

// Pause Media
function pauseMedia() {
// Pause Music
if (state.music) {
if (state.music.type === 'file') {
state.music.element.pause();
} else {
// Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
showMessage('Cannot pause external media playback programmatically.', 'info');
}
}


// Pause Video
if (state.video) {
    if (state.video.type === 'file') {
        state.video.element.pause();
    } else {
        // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
        showMessage('Cannot pause external media playback programmatically.', 'info');
    }
}

state.isPaused = true;
elements.controls.pauseResumeButton.textContent = 'Resume';
showMessage('Playback paused.', 'info');
}

// Resume Media
function resumeMedia() {
// Resume Music
if (state.music) {
if (state.music.type === 'file') {
state.music.element.play();
} else {
// Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
showMessage('Cannot resume external media playback programmatically.', 'info');
}
}


// Resume Video
if (state.video) {
    if (state.video.type === 'file') {
        state.video.element.play();
    } else {
        // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
        showMessage('Cannot resume external media playback programmatically.', 'info');
    }
}

state.isPaused = false;
elements.controls.pauseResumeButton.textContent = 'Pause';
showMessage('Playback resumed.', 'success');
}

// Play From Start Handler
function handlePlayFromStart() {
// Play from Start Music
if (state.music) {
if (state.music.type === 'file') {
state.music.element.currentTime = state.music.start;
state.music.element.play();
if (state.fullscreenOnPlay) {
enterFullscreen(state.music.element);
}
} else {
// Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
showMessage('Cannot control external media playback programmatically.', 'info');
}
}


// Play from Start Video
if (state.video) {
    if (state.video.type === 'file') {
        state.video.element.currentTime = state.video.start;
        state.video.element.play();
        if (state.fullscreenOnPlay) {
            enterFullscreen(state.video.element);
        }
    } else {
        // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
        showMessage('Cannot control external media playback programmatically.', 'info');
    }
}

state.isPaused = false;
elements.controls.pauseResumeButton.textContent = 'Pause';
showMessage('Playback restarted!', 'success');
}

// === Settings Modal Functions ===
function openSettingsModal() {
elements.settings.modal.removeAttribute('hidden');
elements.settings.modal.setAttribute('aria-hidden', 'false');
elements.settings.modal.querySelector('.close-button').focus();
trapFocus(elements.settings.modal);
}

function closeSettingsModal() {
elements.settings.modal.setAttribute('hidden', '');
elements.settings.modal.setAttribute('aria-hidden', 'true');
elements.settings.button.focus();
removeTrapFocus();
}

// === Media Embedding Functions ===

/**

Embeds a YouTube video into the specified container using an iframe.
Adds 'autoplay=1' and 'mute=1' to initiate buffering upon load.
Removes the redundant 'allowfullscreen' attribute.
@param {string} videoId - The YouTube video ID.
@param {number} start - The start time in seconds.
@param {string} mediaType - 'music' or 'video'.
*/
function embedYouTubeIframe(videoId, start, mediaType) {
const container = elements[mediaType].playerContainer;
container.innerHTML = ''; // Clear previous content const iframe = document.createElement('iframe');
iframe.src = https://www.youtube.com/embed/${videoId}?autoplay=1&mute=1&start=${start}&controls=1&rel=0;
iframe.width = '100%';
iframe.height = '360';
iframe.frameBorder = '0';
iframe.allow = 'autoplay; fullscreen; picture-in-picture';
// Remove the 'allowfullscreen' attribute if it's being set separately
// Using 'allow' instead to include fullscreen
// iframe.allowFullscreen = true; // Removed to prevent CSP conflict iframe.setAttribute('title', 'YouTube video player'); container.appendChild(iframe); state[mediaType] = {
type: 'youtube',
element: iframe,
start: start
};
}

/**

Embeds a Vimeo video into the specified container using an iframe.
Adds 'autoplay=1' and 'muted=1' to initiate buffering upon load.
Removes the redundant 'allowfullscreen' attribute.
@param {string} videoId - The Vimeo video ID.
@param {number} start - The start time in seconds.
@param {string} mediaType - 'music' or 'video'.
*/
function embedVimeoIframe(videoId, start, mediaType) {
const container = elements[mediaType].playerContainer;
container.innerHTML = ''; // Clear previous content const iframe = document.createElement('iframe');
iframe.src = https://player.vimeo.com/video/${videoId}?autoplay=1&muted=1#t=${start}s;
iframe.width = '100%';
iframe.height = '360';
iframe.frameBorder = '0';
iframe.allow = 'autoplay; fullscreen; picture-in-picture';
// Remove the 'allowfullscreen' attribute if it's being set separately
// Using 'allow' instead to include fullscreen
// iframe.allowFullscreen = true; // Removed to prevent CSP conflict iframe.setAttribute('title', 'Vimeo video player'); container.appendChild(iframe); state[mediaType] = {
type: 'vimeo',
element: iframe,
start: start
};
}

// === Settings Management ===

/**

Loads settings from Chrome storage.
*/
function loadSettings() {
try {
chrome.storage.local.get(['mediaSettings'], (result) => {
if (chrome.runtime.lastError) {
throw new Error(chrome.runtime.lastError);
}

if (result.mediaSettings) {
const { music, video, fullscreenOnPlay: fsPlay } = result.mediaSettings;

if (music) {
if (music.type === 'youtube' || music.type === 'vimeo') {
const url = music.type === 'youtube'
? https://www.youtube.com/watch?v=${music.id}
: https://vimeo.com/${music.id};
elements.music.urlInput.value = url;
elements.music.startInput.value = music.start || 0;
// Optionally, auto-load the media by triggering the load button
// handleLoadMusic();
}
// Handle file-based music loading if necessary
}

if (video) {
if (video.type === 'youtube' || video.type === 'vimeo') {
const url = video.type === 'youtube'
? https://www.youtube.com/watch?v=${video.id}
: https://vimeo.com/${video.id};
elements.video.urlInput.value = url;
elements.video.startInput.value = video.start || 0;
// Optionally, auto-load the media by triggering the load button
// handleLoadVideo();
}
// Handle file-based video loading if necessary
}

if (typeof fsPlay === 'boolean') {
state.fullscreenOnPlay = fsPlay;
elements.settings.fullscreenToggle.checked = fsPlay;
}
}
});
} catch (error) {
console.error('Error loading settings:', error);
showMessage('Failed to load settings.', 'error');
}
}

/**

Saves settings to Chrome storage.
*/
function saveSettings() {
const settings = {
music: state.music,
video: state.video,
fullscreenOnPlay: state.fullscreenOnPlay
};
try {
chrome.storage.local.set({ mediaSettings: settings }, () => {
if (chrome.runtime.lastError) {
throw new Error(chrome.runtime.lastError);
}
console.log('Settings saved.');
});
} catch (error) {
console.error('Error saving settings:', error);
showMessage('Error saving settings.', 'error');
}
}
/**

Unloads media from the specified type.
@param {string} mediaType - 'music' or 'video'.
*/
function unloadMedia(mediaType) {
if (state[mediaType]) {
if (state[mediaType].type === 'file') {
if (state[mediaType].element.src) {
URL.revokeObjectURL(state[mediaType].element.src);
state[mediaType].element.src = '';
state[mediaType].element.remove();
}
} else if (state[mediaType].type === 'youtube' || state[mediaType].type === 'vimeo') {
const iframe = state[mediaType].element;
iframe.src = ''; // Reset iframe src to stop the media
}
state[mediaType] = null;
}
}
// === Playback Controls ===

/**

Enables or disables playback controls based on media loading state.
*/
function checkReadyToPlay() {
// Enable Play button only when at least one of audio or video is loaded
const readyAudio = state.music && (state.music.type === 'file' || state.music.type === 'youtube' || state.music.type === 'vimeo');
const readyVideo = state.video && (state.video.type === 'file' || state.video.type === 'youtube' || state.video.type === 'vimeo');
const ready = readyAudio || readyVideo; elements.controls.playButton.disabled = !ready;
elements.controls.pauseResumeButton.disabled = !ready;
elements.controls.playStartButton.disabled = !ready;
}

/**

Enters fullscreen mode for the specified element.
@param {HTMLElement} element - The element to enter fullscreen.
*/
function enterFullscreen(element) {
if (element && element.requestFullscreen) {
element.requestFullscreen().then(() => {
showMessage('Entered fullscreen mode.', 'success');
}).catch(err => {
console.error(Error attempting to enable full-screen mode: ${err.message} (${err.name}));
showMessage('Failed to enter fullscreen mode.', 'error');
});
} else {
showMessage('Fullscreen not supported on this element.', 'error');
}
}
// === New Utility Functions ===

/**

Validates whether the URL is a valid YouTube or Vimeo URL.
@param {string} url - The URL to validate.
@returns {boolean} True if valid, else false.
*/
function isValidMediaURL(url) {
try {
const parsedUrl = new URL(url);
const hostname = parsedUrl.hostname.toLowerCase();
const pathname = parsedUrl.pathname;

// YouTube RegEx Patterns
const youtubeRegex = /^(?:/watch/?|/embed/|/v/)?([a-zA-Z0-9_-]{11})$/;
// Vimeo RegEx Patterns
const vimeoRegex = /^/(?:video/)?(\d+)$/;

if (hostname.includes('youtube.com') || hostname === 'youtu.be') {
// Extract YouTube video ID
let videoId = '';
if (hostname === 'youtu.be') {
videoId = pathname.slice(1);
} else {
videoId = parsedUrl.searchParams.get('v') || '';
}
return youtubeRegex.test(/${videoId});
} else if (hostname.includes('vimeo.com')) {
// Extract Vimeo video ID
const match = pathname.match(vimeoRegex);
return match && match[1].length > 0;
}

return false;
} catch (e) {
return false;
}
}

/**

Extracts media information from the URL.
@param {string} url - The media URL.
@returns {Object|null} An object with platform and id, or null if invalid.
*/
function extractMediaInfo(url) {
try {
const parsedUrl = new URL(url);
const hostname = parsedUrl.hostname.toLowerCase();
const pathname = parsedUrl.pathname;

// YouTube Patterns
if (hostname.includes('youtube.com') || hostname === 'youtu.be') {
let videoId = '';
if (hostname === 'youtu.be') {
videoId = pathname.slice(1);
} else {
videoId = parsedUrl.searchParams.get('v') || '';
}

// Validate videoId length
if (videoId.length === 11) {
return { platform: 'youtube', id: videoId };
}
}

// Vimeo Patterns
if (hostname.includes('vimeo.com')) {
const vimeoMatch = pathname.match(/^/(?:video/)?(\d+)$/);
if (vimeoMatch && vimeoMatch[1]) {
return { platform: 'vimeo', id: vimeoMatch[1] };
}
}

return null;
} catch (e) {
return null;
}
}
});

chrome.action.onClicked.addListener(() => {
const dashboardURL = chrome.runtime.getURL("dashboard.html");

// Query for any existing tabs with the dashboard URL
chrome.tabs.query({ url: dashboardURL }, (tabs) => {
if (chrome.runtime.lastError) {
console.error("Tab Query Error:", chrome.runtime.lastError);
return;
}


if (tabs.length > 0) {
    // Activate the first existing dashboard tab
    chrome.tabs.update(tabs[0].id, { active: true }, (updatedTab) => {
        if (chrome.runtime.lastError) {
            console.error("Tab Update Error:", chrome.runtime.lastError);
        }
    });
} else {
    // Create a new dashboard tab
    chrome.tabs.create({ url: dashboardURL, active: true }, (newTab) => {
        if (chrome.runtime.lastError) {
            console.error("Tab Creation Error:", chrome.runtime.lastError);
        }
    });
}
});
});

/* General Styles */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}

.container {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
max-width: 800px;
margin: 0 auto;
}

.section {
width: 100%;
margin-bottom: 20px;
background-color: #fff;
padding: 15px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

/* Header with Settings Button and Main Title /
.header {
width: 100%;
display: flex;
align-items: center;
justify-content: center; / Center the content */
margin-bottom: 20px;
position: relative;
}

.settings-button {
position: absolute;
left: 0;
background: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
cursor: pointer;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.3s ease, border-color 0.3s ease;
}

.settings-button:hover {
background-color: #f0f0f0;
border-color: #999;
}

.settings-icon {
width: 20px;
height: 20px;
}

.main-title {
font-size: 2em;
font-weight: bold;
margin: 0;
opacity: 0;
animation: fadeInShake 5s forwards;
}

@keyframes fadeInShake {
0% {
opacity: 0;
transform: translateX(0);
color: #FF0000; /* Red /
}
10% {
opacity: 0.2;
transform: translateX(-10px);
color: #FF7F00; / Orange /
}
20% {
opacity: 0.4;
transform: translateX(10px);
color: #FFFF00; / Yellow /
}
30% {
opacity: 0.6;
transform: translateX(-10px);
color: #00FF00; / Green /
}
40% {
opacity: 0.7;
transform: translateX(10px);
color: #0000FF; / Blue /
}
50% {
opacity: 0.8;
transform: translateX(-10px);
color: #4B0082; / Indigo /
}
60% {
opacity: 0.85;
transform: translateX(10px);
color: #8B00FF; / Violet /
}
70% {
opacity: 0.9;
transform: translateX(-10px);
color: #FF00FF; / Magenta /
}
80% {
opacity: 0.95;
transform: translateX(10px);
color: #000000; / Black /
}
100% {
opacity: 1;
transform: translateX(0);
color: #000000; / Black */
}
}

/* Section Header */
.section-header {
display: flex;
align-items: center;
margin-bottom: 10px;
}

.section-header legend {
font-size: 1.2em;
font-weight: bold;
margin: 0;
}

/* Controls */
.controls {
display: flex;
gap: 10px;
margin-bottom: 20px;
}

.controls button {
padding: 10px 20px;
cursor: pointer;
border: none;
border-radius: 5px;
background-color: #4285f4;
color: #fff;
transition: background-color 0.3s ease;
}

.controls button:disabled {
background-color: #a0c3ff;
cursor: not-allowed;
}

.controls button:hover:not(:disabled) {
background-color: #357ae8;
}

/* Modal Styles */
.modal[hidden] {
display: none;
}

.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex; /* Visible when not hidden */
align-items: center;
justify-content: center;
z-index: 1000;
}

.modal-content {
background-color: #fff;
padding: 20px 30px;
border-radius: 8px;
width: 90%;
max-width: 400px;
position: relative;
}

.close-button {
position: absolute;
top: 10px;
right: 15px;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
}

.modal-content h2 {
margin-top: 0;
}

/* Form Elements */
fieldset {
border: none;
padding: 0;
}

fieldset label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}

fieldset input[type="text"],
fieldset input[type="number"],
fieldset input[type="file"] {
width: 100%;
padding: 8px;
margin-bottom: 15px;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 4px;
}

fieldset .load-button {
width: 100%;
padding: 10px;
background-color: #34a853;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}

fieldset .load-button:hover {
background-color: #2c8e46;
}

/* Player Containers /
.player-container {
margin-top: 10px;
width: 100%;
max-width: 100%;
min-height: 50px;
box-sizing: border-box;
overflow: hidden; / Prevent overflow */
}

/* Responsive Video Elements /
.player-container video,
.player-container iframe {
width: 100%;
height: auto;
max-height: 360px; / Adjust as needed /
border-radius: 8px;
/ Ensure the iframe fills the container */
display: block;
}

/* Messages */
.message-container {
margin-top: 20px;
width: 100%;
}

.message {
padding: 10px;
border-radius: 5px;
margin-bottom: 10px;
color: #fff;
}

.message.success {
background-color: #4caf50;
}

.message.error {
background-color: #f44336;
}

.message.info {
background-color: #2196f3;
}

/* Loader /
.loader {
border: 8px solid #f3f3f3; / Light grey /
border-top: 8px solid #4285f4; / Blue */
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto;
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

/* Responsive Design */
@media (max-width: 600px) {
.container {
padding: 10px;
}

.modal-content {
padding: 15px 20px;
}

.controls {
flex-direction: column;
width: 100%;
}

.controls button {
width: 100%;
}

.settings-container {
/* Removed absolute positioning */
}

.settings-button {
width: 35px;
height: 35px;
}

.settings-icon {
width: 18px;
height: 18px;
}

.main-title {
font-size: 1.5em;
}
}

i only need the full updated files. the videos are still small when loaded and i dont want them to auto play just buffer. i only tested vimeo urls if that matters. get rid of the load video and load audio texts that are not on the buttons. replace the words upload with local.

Certainly! Below are the fully updated files for your Chrome extension based on your requirements:

Increase Video Size
Prevent Auto-Play (Only Buffer)
Replace "Upload" with "Local" in Labels
Remove "Load Audio" and "Load Video" Texts Outside Buttons

manifest.json
No changes were required for this file based on your specifications. However, it's included here for completeness.
{
"manifest_version": 3,
"name": "Media Loader",
"version": "1.0",
"description": "Load and play music and videos from YouTube and Vimeo",
"permissions": ["storage", "tabs"],
"host_permissions": [
"https://www.youtube.com/",
"https://player.vimeo.com/"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Open Media Loader",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
}
}
2. background.js
Handles the action when the extension icon is clicked, ensuring only one dashboard tab is open.

chrome.action.onClicked.addListener(() => {
const dashboardURL = chrome.runtime.getURL("dashboard.html");


// Query for any existing tabs with the dashboard URL
chrome.tabs.query({ url: dashboardURL }, (tabs) => {
    if (chrome.runtime.lastError) {
        console.error("Tab Query Error:", chrome.runtime.lastError);
        return;
    }

    if (tabs.length > 0) {
        // Activate the first existing dashboard tab
        chrome.tabs.update(tabs[0].id, { active: true }, (updatedTab) => {
            if (chrome.runtime.lastError) {
                console.error("Tab Update Error:", chrome.runtime.lastError);
            }
        });
    } else {
        // Create a new dashboard tab
        chrome.tabs.create({ url: dashboardURL, active: true }, (newTab) => {
            if (chrome.runtime.lastError) {
                console.error("Tab Creation Error:", chrome.runtime.lastError);
            }
        });
    }
});
});
3. dashboard.html
Updated to remove the "Load Audio" and "Load Video" legends and replace "Upload" with "Local" in labels.

Settings
SyncWave

    <!-- Load Audio Section -->
    <section class="section" id="load-music-section">
        <!-- Removed the legend "Load Audio" -->
        
        <fieldset>
            <label for="music-url">Audio URL</label>
            <input type="text" id="music-url" name="music-url" placeholder="Enter YouTube or Vimeo URL">

            <label for="music-file">Local Audio File</label>
            <input type="file" id="music-file" name="music-file" accept="audio/*">

            <label for="music-start">Start Time (seconds)</label>
            <input type="number" id="music-start" name="music-start" placeholder="Start Time (seconds)" min="0">

            <button type="button" id="load-music" class="load-button">Load Audio</button>
        </fieldset>
        <div id="music-player-container" class="player-container"></div>
    </section>

    <!-- Load Video Section -->
    <section class="section" id="load-video-section">
        <!-- Removed the legend "Load Video" -->
        
        <fieldset>
            <label for="video-url">Video URL</label>
            <input type="text" id="video-url" name="video-url" placeholder="Enter YouTube or Vimeo URL">

            <label for="video-file">Local Video File</label>
            <input type="file" id="video-file" name="video-file" accept="video/*">

            <label for="video-start">Start Time (seconds)</label>
            <input type="number" id="video-start" name="video-start" placeholder="Start Time (seconds)" min="0">

            <button type="button" id="load-video" class="load-button">Load Video</button>
        </fieldset>
        <div id="video-player-container" class="player-container"></div>
    </section>

    <!-- Playback Controls -->
    <section class="controls">
        <button type="button" id="play-button" disabled aria-label="Play">Play</button>
        <button type="button" id="pause-resume-button" disabled aria-label="Pause">Pause</button>
        <button type="button" id="play-start-button" disabled aria-label="Play from Start">Play from Start</button>
    </section>

    <!-- Message Container -->
    <section id="message-container" class="message-container" role="alert" aria-live="assertive"></section>

    <!-- Settings Modal (Remains Unchanged) -->
    <div id="settings-modal" class="modal" role="dialog" aria-labelledby="settings-modal-title" aria-modal="true" hidden>
        <div class="modal-content">
            <button class="close-button" aria-label="Close Settings Modal">&times;</button>
            <h2 id="settings-modal-title">Settings</h2>
            <form>
                <label for="fullscreen-toggle">
                    <input type="checkbox" id="fullscreen-toggle" name="fullscreen-toggle">
                    Full Screen on Play
                </label>
                <!-- Additional settings can go here -->
            </form>
        </div>
    </div>
</main>

<!-- Your Dashboard JS -->
<script src="dashboard.js"></script>
4. dashboard.js Removed autoplay=1 from YouTube and Vimeo embed URLs to prevent auto-playing and ensure buffering only. Also increased iframe heights for larger video display.
"use strict";

document.addEventListener('DOMContentLoaded', () => {
// === Element References ===
const elements = {
music: {
urlInput: document.getElementById('music-url'),
fileInput: document.getElementById('music-file'),
startInput: document.getElementById('music-start'),
loadButton: document.getElementById('load-music'),
playerContainer: document.getElementById('music-player-container')
},
video: {
urlInput: document.getElementById('video-url'),
fileInput: document.getElementById('video-file'),
startInput: document.getElementById('video-start'),
loadButton: document.getElementById('load-video'),
playerContainer: document.getElementById('video-player-container')
},
controls: {
playButton: document.getElementById('play-button'),
pauseResumeButton: document.getElementById('pause-resume-button'),
playStartButton: document.getElementById('play-start-button')
},
messageContainer: document.getElementById('message-container'),
settings: {
button: document.getElementById('settings-button'),
modal: document.getElementById('settings-modal'),
closeButton: document.querySelector('.close-button'),
fullscreenToggle: document.getElementById('fullscreen-toggle')
}
};


// === State Management ===
const state = {
    music: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLAudioElement | HTMLIFrameElement, start: Number }
    video: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLVideoElement | HTMLIFrameElement, start: Number }
    isPaused: false,
    fullscreenOnPlay: false
};

// === Utility Functions ===

/**
 * Formats seconds into 'XmYs' (e.g., 125 seconds -> '2m5s')
 * @param {number} seconds - The time in seconds.
 * @returns {string} Formatted time string.
 */
function formatTime(seconds) {
    if (isNaN(seconds) || seconds < 0) return '';
    const minutes = Math.floor(seconds / 60);
    const remainingSeconds = seconds % 60;
    return `${minutes}m${remainingSeconds}s`;
}

/**
 * Capitalize the first letter of a string.
 * @param {string} text - The string to capitalize.
 * @returns {string} Capitalized string.
 */
function capitalize(text) {
    if (!text) return '';
    return text.charAt(0).toUpperCase() + text.slice(1);
}

/**
 * Displays a message to the user.
 * @param {string} message - The message to display.
 * @param {string} type - The type of message ('success', 'error', 'info').
 */
function showMessage(message, type) {
    elements.messageContainer.innerHTML = '';
    const msgDiv = document.createElement('div');
    msgDiv.textContent = message;
    msgDiv.classList.add('message', type); // 'success', 'error', 'info'
    elements.messageContainer.appendChild(msgDiv);

    // Automatically hide message after 5 seconds
    setTimeout(() => {
        if (elements.messageContainer.contains(msgDiv)) {
            elements.messageContainer.removeChild(msgDiv);
        }
    }, 5000);
}

/**
 * Shows a loading spinner in the specified container.
 * @param {HTMLElement} container - The container to show the loader in.
 */
function showLoading(container) {
    container.innerHTML = '';
    const loader = document.createElement('div');
    loader.classList.add('loader'); // Define loader styles in CSS
    container.appendChild(loader);
}

/**
 * Hides the loading spinner from the specified container.
 * @param {HTMLElement} container - The container to hide the loader from.
 */
function hideLoading(container) {
    const loader = container.querySelector('.loader');
    if (loader) {
        container.removeChild(loader);
    }
}

/**
 * Traps keyboard focus within a specified element.
 * @param {HTMLElement} element - The element to trap focus within.
 */
function trapFocus(element) {
    const focusableElementsString = 'a[href], area[href], input:not([disabled]), select:not([disabled]),' +
        ' textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"],' +
        ' [contenteditable]';
    const focusableElements = element.querySelectorAll(focusableElementsString);
    const firstTabStop = focusableElements[0];
    const lastTabStop = focusableElements[focusableElements.length - 1];

    // Listen for and trap the keyboard
    element.addEventListener('keydown', trapTabKey);

    function trapTabKey(e) {
        // Check for TAB key press
        if (e.key === 'Tab') {
            // SHIFT + TAB
            if (e.shiftKey) {
                if (document.activeElement === firstTabStop) {
                    e.preventDefault();
                    lastTabStop.focus();
                }
            } else { // TAB
                if (document.activeElement === lastTabStop) {
                    e.preventDefault();
                    firstTabStop.focus();
                }
            }
        }
    }

    // Remove trap when modal is closed
    function removeTrapKey(e) {
        element.removeEventListener('keydown', trapTabKey);
    }

    // Store the function reference to remove it later
    element.removeTrapKey = removeTrapKey;
}

function removeTrapFocus() {
    if (elements.settings.modal.removeTrapKey) {
        elements.settings.modal.removeTrapKey();
    }
}

// === Initialization ===
loadSettings();

// === Event Listeners ===
elements.music.loadButton.addEventListener('click', handleLoadMusic);
elements.video.loadButton.addEventListener('click', handleLoadVideo);
elements.controls.playButton.addEventListener('click', handlePlay);
elements.controls.pauseResumeButton.addEventListener('click', handlePauseResume);
elements.controls.playStartButton.addEventListener('click', handlePlayFromStart);

// Settings Modal Event Listeners
elements.settings.button.addEventListener('click', openSettingsModal);
elements.settings.closeButton.addEventListener('click', closeSettingsModal);
window.addEventListener('click', (event) => {
    if (event.target === elements.settings.modal) {
        closeSettingsModal();
    }
});
document.addEventListener('keydown', (event) => {
    if (event.key === 'Escape' && !elements.settings.modal.hasAttribute('hidden')) {
        closeSettingsModal();
    }
});
elements.settings.fullscreenToggle.addEventListener('change', (event) => {
    state.fullscreenOnPlay = event.target.checked;
    saveSettings();
});

// === Handler Functions ===

// Load Music Handler
function handleLoadMusic() {
    const url = elements.music.urlInput.value.trim();
    const file = elements.music.fileInput.files[0];
    const start = parseInt(elements.music.startInput.value) || 0;

    // Show loading indicator
    showLoading(elements.music.playerContainer);

    // Unload existing music if any
    if (state.music) {
        unloadMedia('music');
    }

    if (file) {
        if (file.size > 10 * 1024 * 1024) { // 10MB limit
            showMessage('Audio file size exceeds 10MB limit.', 'error');
            hideLoading(elements.music.playerContainer);
            return;
        }

        // Handle local audio file
        const fileUrl = URL.createObjectURL(file);
        const audioElement = document.createElement('audio');
        audioElement.controls = true;
        audioElement.src = fileUrl;
        audioElement.id = 'loaded-music';
        audioElement.setAttribute('aria-label', 'Loaded Audio Player');
        audioElement.style.width = '100%';
        audioElement.style.height = 'auto';
        elements.music.playerContainer.innerHTML = '';
        elements.music.playerContainer.appendChild(audioElement);

        // Set start time if applicable
        if (start > 0) {
            audioElement.currentTime = start;
        }

        state.music = {
            type: 'file',
            element: audioElement,
            start: start
        };
        showMessage('Local audio file loaded.', 'success');
        hideLoading(elements.music.playerContainer);
    } else if (url && isValidMediaURL(url)) {
        const mediaInfo = extractMediaInfo(url);
        if (mediaInfo) {
            if (mediaInfo.platform === 'youtube') {
                embedYouTubeIframe(mediaInfo.id, start, 'music');
            } else if (mediaInfo.platform === 'vimeo') {
                embedVimeoIframe(mediaInfo.id, start, 'music');
            }
            showMessage(`Loaded ${capitalize(mediaInfo.platform)} audio.`, 'success');
            hideLoading(elements.music.playerContainer);
        } else {
            showMessage('Invalid URL. Please enter a valid YouTube or Vimeo URL.', 'error');
            hideLoading(elements.music.playerContainer);
        }
    } else {
        showMessage('Please enter a URL or select an audio file.', 'error');
        hideLoading(elements.music.playerContainer);
    }

    checkReadyToPlay();
    saveSettings();
}

// Load Video Handler
function handleLoadVideo() {
    const url = elements.video.urlInput.value.trim();
    const file = elements.video.fileInput.files[0];
    const start = parseInt(elements.video.startInput.value) || 0;

    // Show loading indicator
    showLoading(elements.video.playerContainer);

    // Unload existing video if any
    if (state.video) {
        unloadMedia('video');
    }

    if (file) {
        if (file.size > 50 * 1024 * 1024) { // 50MB limit
            showMessage('Video file size exceeds 50MB limit.', 'error');
            hideLoading(elements.video.playerContainer);
            return;
        }

        // Handle local video file
        const fileUrl = URL.createObjectURL(file);
        const videoElement = document.createElement('video');
        videoElement.controls = true;
        videoElement.src = fileUrl;
        videoElement.id = 'loaded-video';
        videoElement.setAttribute('aria-label', 'Loaded Video Player');
        videoElement.style.width = '100%';
        videoElement.style.height = 'auto';
        elements.video.playerContainer.innerHTML = '';
        elements.video.playerContainer.appendChild(videoElement);

        // Set start time if applicable
        if (start > 0) {
            videoElement.currentTime = start;
        }

        state.video = {
            type: 'file',
            element: videoElement,
            start: start
        };
        showMessage('Local video file loaded.', 'success');
        hideLoading(elements.video.playerContainer);
    } else if (url && isValidMediaURL(url)) {
        const mediaInfo = extractMediaInfo(url);
        if (mediaInfo) {
            if (mediaInfo.platform === 'youtube') {
                embedYouTubeIframe(mediaInfo.id, start, 'video');
            } else if (mediaInfo.platform === 'vimeo') {
                embedVimeoIframe(mediaInfo.id, start, 'video');
            }
            showMessage(`Loaded ${capitalize(mediaInfo.platform)} video.`, 'success');
            hideLoading(elements.video.playerContainer);
        } else {
            showMessage('Invalid URL. Please enter a valid YouTube or Vimeo URL.', 'error');
            hideLoading(elements.video.playerContainer);
        }
    } else {
        showMessage('Please enter a URL or select a video file.', 'error');
        hideLoading(elements.video.playerContainer);
    }

    checkReadyToPlay();
    saveSettings();
}

// Play Handler
function handlePlay() {
    // Play Music
    if (state.music) {
        if (state.music.type === 'file') {
            state.music.element.play();
            if (state.fullscreenOnPlay) {
                enterFullscreen(state.music.element);
            }
        } else {
            // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
            showMessage('Cannot control external media playback programmatically.', 'info');
        }
    }

    // Play Video
    if (state.video) {
        if (state.video.type === 'file') {
            state.video.element.play();
            if (state.fullscreenOnPlay) {
                enterFullscreen(state.video.element);
            }
        } else {
            // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
            showMessage('Cannot control external media playback programmatically.', 'info');
        }
    }

    state.isPaused = false;
    elements.controls.pauseResumeButton.textContent = 'Pause';
    showMessage('Playback started!', 'success');
}

// Pause/Resume Handler
function handlePauseResume() {
    if (state.isPaused) {
        resumeMedia();
    } else {
        pauseMedia();
    }
}

// Pause Media
function pauseMedia() {
    // Pause Music
    if (state.music) {
        if (state.music.type === 'file') {
            state.music.element.pause();
        } else {
            // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
            showMessage('Cannot pause external media playback programmatically.', 'info');
        }
    }

    // Pause Video
    if (state.video) {
        if (state.video.type === 'file') {
            state.video.element.pause();
        } else {
            // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
            showMessage('Cannot pause external media playback programmatically.', 'info');
        }
    }

    state.isPaused = true;
    elements.controls.pauseResumeButton.textContent = 'Resume';
    showMessage('Playback paused.', 'info');
}

// Resume Media
function resumeMedia() {
    // Resume Music
    if (state.music) {
        if (state.music.type === 'file') {
            state.music.element.play();
        } else {
            // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
            showMessage('Cannot resume external media playback programmatically.', 'info');
        }
    }

    // Resume Video
    if (state.video) {
        if (state.video.type === 'file') {
            state.video.element.play();
        } else {
            // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
            showMessage('Cannot resume external media playback programmatically.', 'info');
        }
    }

    state.isPaused = false;
    elements.controls.pauseResumeButton.textContent = 'Pause';
    showMessage('Playback resumed.', 'success');
}

// Play From Start Handler
function handlePlayFromStart() {
    // Play from Start Music
    if (state.music) {
        if (state.music.type === 'file') {
            state.music.element.currentTime = state.music.start;
            state.music.element.play();
            if (state.fullscreenOnPlay) {
                enterFullscreen(state.music.element);
            }
        } else {
            // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
            showMessage('Cannot control external media playback programmatically.', 'info');
        }
    }

    // Play from Start Video
    if (state.video) {
        if (state.video.type === 'file') {
            state.video.element.currentTime = state.video.start;
            state.video.element.play();
            if (state.fullscreenOnPlay) {
                enterFullscreen(state.video.element);
            }
        } else {
            // Embedded iframes (YouTube/Vimeo) cannot be programmatically controlled without APIs
            showMessage('Cannot control external media playback programmatically.', 'info');
        }
    }

    state.isPaused = false;
    elements.controls.pauseResumeButton.textContent = 'Pause';
    showMessage('Playback restarted!', 'success');
}

// === Settings Modal Functions ===
function openSettingsModal() {
    elements.settings.modal.removeAttribute('hidden');
    elements.settings.modal.setAttribute('aria-hidden', 'false');
    elements.settings.modal.querySelector('.close-button').focus();
    trapFocus(elements.settings.modal);
}

function closeSettingsModal() {
    elements.settings.modal.setAttribute('hidden', '');
    elements.settings.modal.setAttribute('aria-hidden', 'true');
    elements.settings.button.focus();
    removeTrapFocus();
}

// === Media Embedding Functions ===

/**
 * Embeds a YouTube video into the specified container using an iframe.
 * Mutes the video and starts at the specified time without autoplay.
 * @param {string} videoId - The YouTube video ID.
 * @param {number} start - The start time in seconds.
 * @param {string} mediaType - 'music' or 'video'.
 */
function embedYouTubeIframe(videoId, start, mediaType) {
    const container = elements[mediaType].playerContainer;
    container.innerHTML = ''; // Clear previous content

    let src = `https://www.youtube.com/embed/${videoId}?mute=1&start=${start}&controls=1&rel=0`;
    // Note: autoplay=1 removed to prevent auto-play

    const iframe = document.createElement('iframe');
    iframe.src = src;
    iframe.width = '100%';
    iframe.height = '720'; // Increased height
    iframe.frameBorder = '0';
    iframe.allow = 'autoplay; fullscreen; picture-in-picture';

    iframe.setAttribute('title', 'YouTube video player');

    container.appendChild(iframe);

    state[mediaType] = {
        type: 'youtube',
        element: iframe,
        start: start
    };
}

/**
 * Embeds a Vimeo video into the specified container using an iframe.
 * Mutes the video and starts at the specified time without autoplay.
 * @param {string} videoId - The Vimeo video ID.
 * @param {number} start - The start time in seconds.
 * @param {string} mediaType - 'music' or 'video'.
 */
function embedVimeoIframe(videoId, start, mediaType) {
    const container = elements[mediaType].playerContainer;
    container.innerHTML = ''; // Clear previous content

    let src = `https://player.vimeo.com/video/${videoId}?muted=1#t=${start}s`;
    // Note: autoplay=1 removed to prevent auto-play

    const iframe = document.createElement('iframe');
    iframe.src = src;
    iframe.width = '100%';
    iframe.height = '720'; // Increased height
    iframe.frameBorder = '0';
    iframe.allow = 'autoplay; fullscreen; picture-in-picture';

    iframe.setAttribute('title', 'Vimeo video player');

    container.appendChild(iframe);

    state[mediaType] = {
        type: 'vimeo',
        element: iframe,
        start: start
    };
}

// === Settings Management ===

/**
 * Loads settings from Chrome storage.
 */
function loadSettings() {
    try {
        chrome.storage.local.get(['mediaSettings'], (result) => {
            if (chrome.runtime.lastError) {
                throw new Error(chrome.runtime.lastError);
            }

            if (result.mediaSettings) {
                const { music, video, fullscreenOnPlay: fsPlay } = result.mediaSettings;

                if (music) {
                    if (music.type === 'youtube' 
                        || music.type === 'vimeo') {
                        const url = music.type === 'youtube' 
                            ? `https://www.youtube.com/watch?v=${music.id}` 
                            : `https://vimeo.com/${music.id}`;
                        elements.music.urlInput.value = url;
                        elements.music.startInput.value = music.start || 0;
                        // Optionally, auto-load the media by triggering the load button
                        // handleLoadMusic();
                    }
                    // Handle file-based music loading if necessary
                }

                if (video) {
                    if (video.type === 'youtube' 
                        || video.type === 'vimeo') {
                        const url = video.type === 'youtube' 
                            ? `https://www.youtube.com/watch?v=${video.id}` 
                            : `https://vimeo.com/${video.id}`;
                        elements.video.urlInput.value = url;
                        elements.video.startInput.value = video.start || 0;
                        // Optionally, auto-load the media by triggering the load button
                        // handleLoadVideo();
                    }
                    // Handle file-based video loading if necessary
                }

                if (typeof fsPlay === 'boolean') {
                    state.fullscreenOnPlay = fsPlay;
                    elements.settings.fullscreenToggle.checked = fsPlay;
                }
            }
        });
    } catch (error) {
        console.error('Error loading settings:', error);
        showMessage('Failed to load settings.', 'error');
    }
}

/**
 * Saves settings to Chrome storage.
 */
function saveSettings() {
    const settings = {
        music: state.music,
        video: state.video,
        fullscreenOnPlay: state.fullscreenOnPlay
    };
    try {
        chrome.storage.local.set({ mediaSettings: settings }, () => {
            if (chrome.runtime.lastError) {
                throw new Error(chrome.runtime.lastError);
            }
            console.log('Settings saved.');
        });
    } catch (error) {
        console.error('Error saving settings:', error);
        showMessage('Error saving settings.', 'error');
    }
}

/**
 * Unloads media from the specified type.
 * @param {string} mediaType - 'music' or 'video'.
 */
function unloadMedia(mediaType) {
    if (state[mediaType]) {
        if (state[mediaType].type === 'file') {
            if (state[mediaType].element.src) {
                URL.revokeObjectURL(state[mediaType].element.src);
                state[mediaType].element.src = '';
                state[mediaType].element.remove();
            }
        } else if (state[mediaType].type === 'youtube' 
            || state[mediaType].type === 'vimeo') {
            const iframe = state[mediaType].element;
            iframe.src = ''; // Reset iframe src to stop the media
        }
        state[mediaType] = null;
    }
}

// === Playback Controls ===

/**
 * Enables or disables playback controls based on media loading state.
 */
function checkReadyToPlay() {
    // Enable Play button only when at least one of audio or video is loaded
    const readyAudio = state.music 
        && (state.music.type === 'file' 
            || state.music.type === 'youtube' 
            || state.music.type === 'vimeo');
    const readyVideo = state.video 
        && (state.video.type === 'file' 
            || state.video.type === 'youtube' 
            || state.video.type === 'vimeo');
    const ready = readyAudio || readyVideo;

    elements.controls.playButton.disabled = !ready;
    elements.controls.pauseResumeButton.disabled = !ready;
    elements.controls.playStartButton.disabled = !ready;
}

/**
 * Enters fullscreen mode for the specified element.
 * @param {HTMLElement} element - The element to enter fullscreen.
 */
function enterFullscreen(element) {
    if (element && element.requestFullscreen) {
        element.requestFullscreen().then(() => {
            showMessage('Entered fullscreen mode.', 'success');
        }).catch(err => {
            console.error(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
            showMessage('Failed to enter fullscreen mode.', 'error');
        });
    } else {
        showMessage('Fullscreen not supported on this element.', 'error');
    }
}

// === New Utility Functions ===

/**
 * Validates whether the URL is a valid YouTube or Vimeo URL.
 * @param {string} url - The URL to validate.
 * @returns {boolean} True if valid, else false.
 */
function isValidMediaURL(url) {
    try {
        const parsedUrl = new URL(url);
        const hostname = parsedUrl.hostname.toLowerCase();
        const pathname = parsedUrl.pathname;

        // YouTube RegEx Patterns
        const youtubeRegex = /^(?:\/watch\/?|\/embed\/|\/v\/)?([a-zA-Z0-9_-]{11})$/;
        // Vimeo RegEx Patterns
        const vimeoRegex = /^\/(?:video\/)?(\d+)$/;

        if (hostname.includes('youtube.com') || hostname === 'youtu.be') {
            // Extract YouTube video ID
            let videoId = '';
            if (hostname === 'youtu.be') {
                videoId = pathname.slice(1);
            } else {
                videoId = parsedUrl.searchParams.get('v') || '';
            }
            return youtubeRegex.test(`/${videoId}`);
        } else if (hostname.includes('vimeo.com')) {
            // Extract Vimeo video ID
            const match = pathname.match(vimeoRegex);
            return match && match[1].length > 0;
        }

        return false;
    } catch (e) {
        return false;
    }
}

/**
 * Extracts media information from the URL.
 * @param {string} url - The media URL.
 * @returns {Object|null} An object with platform and id, or null if invalid.
 */
function extractMediaInfo(url) {
    try {
        const parsedUrl = new URL(url);
        const hostname = parsedUrl.hostname.toLowerCase();
        const pathname = parsedUrl.pathname;

        // YouTube Patterns
        if (hostname.includes('youtube.com') 
            || hostname === 'youtu.be') {
            let videoId = '';
            if (hostname === 'youtu.be') {
                videoId = pathname.slice(1);
            } else {
                videoId = parsedUrl.searchParams.get('v') || '';
            }

            // Validate videoId length
            if (videoId.length === 11) {
                return { platform: 'youtube', id: videoId };
            }
        }

        // Vimeo Patterns
        if (hostname.includes('vimeo.com')) {
            const vimeoMatch = pathname.match(/^\/(?:video\/)?(\d+)$/);
            if (vimeoMatch && vimeoMatch[1]) {
                return { platform: 'vimeo', id: vimeoMatch[1] };
            }
        }

        return null;
    } catch (e) {
        return null;
    }
}
});
Key Changes:

Prevent Auto-Play: Removed autoplay=1 from both YouTube and Vimeo iframe URLs to ensure media doesn't auto-play but only buffers.
YouTube Embed URL Changed From:

https://www.youtube.com/embed/${videoId}?autoplay=1&mute=1&start=${start}&controls=1&rel=0
To:

https://www.youtube.com/embed/${videoId}?mute=1&start=${start}&controls=1&rel=0
Vimeo Embed URL Changed From:

https://player.vimeo.com/video/${videoId}?autoplay=1&muted=1#t=${start}s
To:

https://player.vimeo.com/video/${videoId}?muted=1#t=${start}s
Increased Player Size: Changed the iframe heights from 360 to 720 pixels for larger video displays.
5. styles.css
Updated the maximum height for video and audio players to display larger content.

/* General Styles */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}

.container {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
max-width: 800px;
margin: 0 auto;
}

.section {
width: 100%;
margin-bottom: 20px;
background-color: #fff;
padding: 15px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

/* Header with Settings Button and Main Title /
.header {
width: 100%;
display: flex;
align-items: center;
justify-content: center; / Center the content */
margin-bottom: 20px;
position: relative;
}

.settings-button {
position: absolute;
left: 0;
background: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
cursor: pointer;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.3s ease, border-color 0.3s ease;
}

.settings-button:hover {
background-color: #f0f0f0;
border-color: #999;
}

.settings-icon {
width: 20px;
height: 20px;
}

.main-title {
font-size: 2em;
font-weight: bold;
margin: 0;
opacity: 0;
animation: fadeInShake 5s forwards;
}

@keyframes fadeInShake {
0% {
opacity: 0;
transform: translateX(0);
color: #FF0000; /* Red /
}
10% {
opacity: 0.2;
transform: translateX(-10px);
color: #FF7F00; / Orange /
}
20% {
opacity: 0.4;
transform: translateX(10px);
color: #FFFF00; / Yellow /
}
30% {
opacity: 0.6;
transform: translateX(-10px);
color: #00FF00; / Green /
}
40% {
opacity: 0.7;
transform: translateX(10px);
color: #0000FF; / Blue /
}
50% {
opacity: 0.8;
transform: translateX(-10px);
color: #4B0082; / Indigo /
}
60% {
opacity: 0.85;
transform: translateX(10px);
color: #8B00FF; / Violet /
}
70% {
opacity: 0.9;
transform: translateX(-10px);
color: #FF00FF; / Magenta /
}
80% {
opacity: 0.95;
transform: translateX(10px);
color: #000000; / Black /
}
100% {
opacity: 1;
transform: translateX(0);
color: #000000; / Black */
}
}

/* Section Header */
.section-header {
display: flex;
align-items: center;
margin-bottom: 10px;
}

.section-header legend {
font-size: 1.2em;
font-weight: bold;
margin: 0;
}

/* Controls */
.controls {
display: flex;
gap: 10px;
margin-bottom: 20px;
}

.controls button {
padding: 10px 20px;
cursor: pointer;
border: none;
border-radius: 5px;
background-color: #4285f4;
color: #fff;
transition: background-color 0.3s ease;
}

.controls button:disabled {
background-color: #a0c3ff;
cursor: not-allowed;
}

.controls button:hover:not(:disabled) {
background-color: #357ae8;
}

/* Modal Styles */
.modal[hidden] {
display: none;
}

.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex; /* Visible when not hidden */
align-items: center;
justify-content: center;
z-index: 1000;
}

.modal-content {
background-color: #fff;
padding: 20px 30px;
border-radius: 8px;
width: 90%;
max-width: 400px;
position: relative;
}

.close-button {
position: absolute;
top: 10px;
right: 15px;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
}

.modal-content h2 {
margin-top: 0;
}

/* Form Elements */
fieldset {
border: none;
padding: 0;
}

fieldset label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}

fieldset input[type="text"],
fieldset input[type="number"],
fieldset input[type="file"] {
width: 100%;
padding: 8px;
margin-bottom: 15px;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 4px;
}

fieldset .load-button {
width: 100%;
padding: 10px;
background-color: #34a853;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}

fieldset .load-button:hover {
background-color: #2c8e46;
}

/* Player Containers /
.player-container {
margin-top: 10px;
width: 100%;
max-width: 100%;
min-height: 50px;
box-sizing: border-box;
overflow: hidden; / Prevent overflow */
}

/* Responsive Video and Audio Elements /
.player-container video,
.player-container iframe {
width: 100%;
height: auto;
max-height: 720px; / Increased from 360px to 720px /
border-radius: 8px;
/ Ensure the iframe fills the container */
display: block;
}

/* Messages */
.message-container {
margin-top: 20px;
width: 100%;
}

.message {
padding: 10px;
border-radius: 5px;
margin-bottom: 10px;
color: #fff;
}

.message.success {
background-color: #4caf50;
}

.message.error {
background-color: #f44336;
}

.message.info {
background-color: #2196f3;
}

/* Loader /
.loader {
border: 8px solid #f3f3f3; / Light grey /
border-top: 8px solid #4285f4; / Blue */
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto;
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

/* Responsive Design */
@media (max-width: 600px) {
.container {
padding: 10px;
}


.modal-content {
    padding: 15px 20px;
}

.controls {
    flex-direction: column;
    width: 100%;
}

.controls button {
    width: 100%;
}

.settings-container {
    /* Removed absolute positioning */
}

.settings-button {
    width: 35px;
    height: 35px;
}

.settings-icon {
    width: 18px;
    height: 18px;
}

.main-title {
    font-size: 1.5em;
}
}
Key Changes:

Increased Player Size: Changed the max-height for both


Certainly! Below are the fully updated files for your Chrome extension, addressing the issues you've encountered:

Increased Video Size
Prevented Auto-Play (Only Buffer)
Replaced "Upload" with "Local" in Labels
Removed "Load Audio" and "Load Video" Legends Outside Buttons
Fixed Content Security Policy (CSP) Issues
1. manifest.json
Key Changes:

Removed External Script Sources: Ensured that no external scripts (like https://player.vimeo.com) are referenced in the content_security_policy.
Included Local Scripts: Added lib/player.js as a local resource.

{
  "manifest_version": 3,
  "name": "Media Loader",
  "version": "1.1",
  "description": "Load and play music and videos from YouTube and Vimeo",
  "permissions": ["storage", "tabs"],
  "host_permissions": [
    "https://www.youtube.com/*",
    "https://player.vimeo.com/*"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "Open Media Loader",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  },
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
  "web_accessible_resources": [
    {
      "resources": ["lib/player.js"],
      "matches": ["<all_urls>"]
    }
  ]
}
2. background.js
No changes were required for this file based on your specifications. It handles the extension icon click event and ensures that only one dashboard tab is open.


chrome.action.onClicked.addListener(() => {
    const dashboardURL = chrome.runtime.getURL("dashboard.html");
    
    // Query for any existing tabs with the dashboard URL
    chrome.tabs.query({ url: dashboardURL }, (tabs) => {
        if (chrome.runtime.lastError) {
            console.error("Tab Query Error:", chrome.runtime.lastError);
            return;
        }

        if (tabs.length > 0) {
            // Activate the first existing dashboard tab
            chrome.tabs.update(tabs[0].id, { active: true }, (updatedTab) => {
                if (chrome.runtime.lastError) {
                    console.error("Tab Update Error:", chrome.runtime.lastError);
                }
            });
        } else {
            // Create a new dashboard tab
            chrome.tabs.create({ url: dashboardURL, active: true }, (newTab) => {
                if (chrome.runtime.lastError) {
                    console.error("Tab Creation Error:", chrome.runtime.lastError);
                }
            });
        }
    });
});
3. dashboard.html
Key Changes:

Removed Legends: Eliminated the <legend> tags to remove "Load Audio" and "Load Video" texts outside buttons.
Replaced "Upload" with "Local": Updated labels to reflect "Local Audio File" and "Local Video File".
Included Local Vimeo Player API: Added a script tag to include the locally stored player.js.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Media Loader Dashboard</title>
    <link rel="stylesheet" href="styles.css">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <main class="container">
        <!-- Header with Settings Button and SyncWave Title -->
        <header class="header">
            <button id="settings-button" class="settings-button" title="Settings" aria-label="Open Settings">
                <img src="icons/settings.svg" alt="Settings" class="settings-icon" aria-hidden="true">
            </button>
            <h1 class="main-title">SyncWave</h1>
        </header>
        
        <!-- Load Audio Section -->
        <section class="section" id="load-music-section">
            <fieldset>
                <label for="music-url">Audio URL</label>
                <input type="text" id="music-url" name="music-url" placeholder="Enter YouTube or Vimeo URL">

                <label for="music-file">Local Audio File</label>
                <input type="file" id="music-file" name="music-file" accept="audio/*">

                <label for="music-start">Start Time (seconds)</label>
                <input type="number" id="music-start" name="music-start" placeholder="Start Time (seconds)" min="0">

                <button type="button" id="load-music" class="load-button">Load</button>
            </fieldset>
            <div id="music-player-container" class="player-container"></div>
        </section>

        <!-- Load Video Section -->
        <section class="section" id="load-video-section">
            <fieldset>
                <label for="video-url">Video URL</label>
                <input type="text" id="video-url" name="video-url" placeholder="Enter YouTube or Vimeo URL">

                <label for="video-file">Local Video File</label>
                <input type="file" id="video-file" name="video-file" accept="video/*">

                <label for="video-start">Start Time (seconds)</label>
                <input type="number" id="video-start" name="video-start" placeholder="Start Time (seconds)" min="0">

                <button type="button" id="load-video" class="load-button">Load</button>
            </fieldset>
            <div id="video-player-container" class="player-container"></div>
        </section>

        <!-- Playback Controls -->
        <section class="controls">
            <button type="button" id="play-button" disabled aria-label="Play">Play</button>
            <button type="button" id="pause-resume-button" disabled aria-label="Pause">Pause</button>
            <button type="button" id="play-start-button" disabled aria-label="Play from Start">Play from Start</button>
        </section>

        <!-- Message Container -->
        <section id="message-container" class="message-container" role="alert" aria-live="assertive"></section>

        <!-- Settings Modal (Remains Unchanged) -->
        <div id="settings-modal" class="modal" role="dialog" aria-labelledby="settings-modal-title" aria-modal="true" hidden>
            <div class="modal-content">
                <button class="close-button" aria-label="Close Settings Modal">&times;</button>
                <h2 id="settings-modal-title">Settings</h2>
                <form>
                    <label for="fullscreen-toggle">
                        <input type="checkbox" id="fullscreen-toggle" name="fullscreen-toggle">
                        Full Screen on Play
                    </label>
                    <!-- Additional settings can go here -->
                </form>
            </div>
        </div>
    </main>

    <!-- Local Vimeo Player API -->
    <script src="lib/player.js"></script>
    
    <!-- Your Dashboard JS -->
    <script src="dashboard.js"></script>
</body>
</html>
4. dashboard.js
Key Changes:

Integrated Vimeo Player API: Utilized the locally stored player.js to control Vimeo players programmatically.
Increased Video Size: Set iframe heights to 720px for larger displays.
Prevented Auto-Play: Removed autoplay parameters to ensure videos only buffer upon loading.
Enhanced Playback Controls: Implemented play, pause, and play from start functionalities using the Vimeo Player API.

"use strict";

document.addEventListener('DOMContentLoaded', () => {
    // === Element References ===
    const elements = {
        music: {
            urlInput: document.getElementById('music-url'),
            fileInput: document.getElementById('music-file'),
            startInput: document.getElementById('music-start'),
            loadButton: document.getElementById('load-music'),
            playerContainer: document.getElementById('music-player-container')
        },
        video: {
            urlInput: document.getElementById('video-url'),
            fileInput: document.getElementById('video-file'),
            startInput: document.getElementById('video-start'),
            loadButton: document.getElementById('load-video'),
            playerContainer: document.getElementById('video-player-container')
        },
        controls: {
            playButton: document.getElementById('play-button'),
            pauseResumeButton: document.getElementById('pause-resume-button'),
            playStartButton: document.getElementById('play-start-button')
        },
        messageContainer: document.getElementById('message-container'),
        settings: {
            button: document.getElementById('settings-button'),
            modal: document.getElementById('settings-modal'),
            closeButton: document.querySelector('.close-button'),
            fullscreenToggle: document.getElementById('fullscreen-toggle')
        }
    };

    // === State Management ===
    const state = {
        music: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLAudioElement | Player, start: Number }
        video: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLVideoElement | Player, start: Number }
        isPaused: false,
        fullscreenOnPlay: false
    };

    // === Utility Functions ===

    /**
     * Formats seconds into 'XmYs' (e.g., 125 seconds -> '2m5s')
     * @param {number} seconds - The time in seconds.
     * @returns {string} Formatted time string.
     */
    function formatTime(seconds) {
        if (isNaN(seconds) || seconds < 0) return '';
        const minutes = Math.floor(seconds / 60);
        const remainingSeconds = seconds % 60;
        return `${minutes}m${remainingSeconds}s`;
    }

    /**
     * Capitalize the first letter of a string.
     * @param {string} text - The string to capitalize.
     * @returns {string} Capitalized string.
     */
    function capitalize(text) {
        if (!text) return '';
        return text.charAt(0).toUpperCase() + text.slice(1);
    }

    /**
     * Displays a message to the user.
     * @param {string} message - The message to display.
     * @param {string} type - The type of message ('success', 'error', 'info').
     */
    function showMessage(message, type) {
        elements.messageContainer.innerHTML = '';
        const msgDiv = document.createElement('div');
        msgDiv.textContent = message;
        msgDiv.classList.add('message', type); // 'success', 'error', 'info'
        elements.messageContainer.appendChild(msgDiv);

        // Automatically hide message after 5 seconds
        setTimeout(() => {
            if (elements.messageContainer.contains(msgDiv)) {
                elements.messageContainer.removeChild(msgDiv);
            }
        }, 5000);
    }

    /**
     * Shows a loading spinner in the specified container.
     * @param {HTMLElement} container - The container to show the loader in.
     */
    function showLoading(container) {
        container.innerHTML = '';
        const loader = document.createElement('div');
        loader.classList.add('loader'); // Define loader styles in CSS
        container.appendChild(loader);
    }

    /**
     * Hides the loading spinner from the specified container.
     * @param {HTMLElement} container - The container to hide the loader from.
     */
    function hideLoading(container) {
        const loader = container.querySelector('.loader');
        if (loader) {
            container.removeChild(loader);
        }
    }

    /**
     * Traps keyboard focus within a specified element.
     * @param {HTMLElement} element - The element to trap focus within.
     */
    function trapFocus(element) {
        const focusableElementsString = 'a[href], area[href], input:not([disabled]), select:not([disabled]),' +
            ' textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"],' +
            ' [contenteditable]';
        const focusableElements = element.querySelectorAll(focusableElementsString);
        const firstTabStop = focusableElements[0];
        const lastTabStop = focusableElements[focusableElements.length - 1];

        // Listen for and trap the keyboard
        element.addEventListener('keydown', trapTabKey);

        function trapTabKey(e) {
            // Check for TAB key press
            if (e.key === 'Tab') {
                // SHIFT + TAB
                if (e.shiftKey) {
                    if (document.activeElement === firstTabStop) {
                        e.preventDefault();
                        lastTabStop.focus();
                    }
                } else { // TAB
                    if (document.activeElement === lastTabStop) {
                        e.preventDefault();
                        firstTabStop.focus();
                    }
                }
            }
        }

        // Remove trap when modal is closed
        function removeTrapKey(e) {
            element.removeEventListener('keydown', trapTabKey);
        }

        // Store the function reference to remove it later
        element.removeTrapKey = removeTrapKey;
    }

    function removeTrapFocus() {
        if (elements.settings.modal.removeTrapKey) {
            elements.settings.modal.removeTrapKey();
        }
    }

    // === Initialization ===
    loadSettings();

    // === Event Listeners ===
    elements.music.loadButton.addEventListener('click', handleLoadMusic);
    elements.video.loadButton.addEventListener('click', handleLoadVideo);
    elements.controls.playButton.addEventListener('click', handlePlay);
    elements.controls.pauseResumeButton.addEventListener('click', handlePauseResume);
    elements.controls.playStartButton.addEventListener('click', handlePlayFromStart);

    // Settings Modal Event Listeners
    elements.settings.button.addEventListener('click', openSettingsModal);
    elements.settings.closeButton.addEventListener('click', closeSettingsModal);
    window.addEventListener('click', (event) => {
        if (event.target === elements.settings.modal) {
            closeSettingsModal();
        }
    });
    document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape' && !elements.settings.modal.hasAttribute('hidden')) {
            closeSettingsModal();
        }
    });
    elements.settings.fullscreenToggle.addEventListener('change', (event) => {
        state.fullscreenOnPlay = event.target.checked;
        saveSettings();
    });

    // === Handler Functions ===

    // Load Music Handler
    function handleLoadMusic() {
        const url = elements.music.urlInput.value.trim();
        const file = elements.music.fileInput.files[0];
        const start = parseInt(elements.music.startInput.value) || 0;

        // Show loading indicator
        showLoading(elements.music.playerContainer);

        // Unload existing music if any
        if (state.music) {
            unloadMedia('music');
        }

        if (file) {
            if (file.size > 10 * 1024 * 1024) { // 10MB limit
                showMessage('Audio file size exceeds 10MB limit.', 'error');
                hideLoading(elements.music.playerContainer);
                return;
            }

            // Handle local audio file
            const fileUrl = URL.createObjectURL(file);
            const audioElement = document.createElement('audio');
            audioElement.controls = true;
            audioElement.src = fileUrl;
            audioElement.id = 'loaded-music';
            audioElement.setAttribute('aria-label', 'Loaded Audio Player');
            audioElement.style.width = '100%';
            audioElement.style.height = 'auto';
            elements.music.playerContainer.innerHTML = '';
            elements.music.playerContainer.appendChild(audioElement);

            // Set start time if applicable
            if (start > 0) {
                audioElement.currentTime = start;
            }

            state.music = {
                type: 'file',
                element: audioElement,
                start: start
            };
            showMessage('Local audio file loaded.', 'success');
            hideLoading(elements.music.playerContainer);
        } else if (url && isValidMediaURL(url)) {
            const mediaInfo = extractMediaInfo(url);
            if (mediaInfo) {
                if (mediaInfo.platform === 'youtube') {
                    embedYouTubeIframe(mediaInfo.id, start, 'music');
                } else if (mediaInfo.platform === 'vimeo') {
                    embedVimeoPlayer(mediaInfo.id, start, 'music');
                }
                showMessage(`Loaded ${capitalize(mediaInfo.platform)} audio.`, 'success');
                hideLoading(elements.music.playerContainer);
            } else {
                showMessage('Invalid URL. Please enter a valid YouTube or Vimeo URL.', 'error');
                hideLoading(elements.music.playerContainer);
            }
        } else {
            showMessage('Please enter a URL or select an audio file.', 'error');
            hideLoading(elements.music.playerContainer);
        }

        checkReadyToPlay();
        saveSettings();
    }

    // Load Video Handler
    function handleLoadVideo() {
        const url = elements.video.urlInput.value.trim();
        const file = elements.video.fileInput.files[0];
        const start = parseInt(elements.video.startInput.value) || 0;

        // Show loading indicator
        showLoading(elements.video.playerContainer);

        // Unload existing video if any
        if (state.video) {
            unloadMedia('video');
        }

        if (file) {
            if (file.size > 50 * 1024 * 1024) { // 50MB limit
                showMessage('Video file size exceeds 50MB limit.', 'error');
                hideLoading(elements.video.playerContainer);
                return;
            }

            // Handle local video file
            const fileUrl = URL.createObjectURL(file);
            const videoElement = document.createElement('video');
            videoElement.controls = true;
            videoElement.src = fileUrl;
            videoElement.id = 'loaded-video';
            videoElement.setAttribute('aria-label', 'Loaded Video Player');
            videoElement.style.width = '100%';
            videoElement.style.height = 'auto';
            elements.video.playerContainer.innerHTML = '';
            elements.video.playerContainer.appendChild(videoElement);

            // Set start time if applicable
            if (start > 0) {
                videoElement.currentTime = start;
            }

            state.video = {
                type: 'file',
                element: videoElement,
                start: start
            };
            showMessage('Local video file loaded.', 'success');
            hideLoading(elements.video.playerContainer);
        } else if (url && isValidMediaURL(url)) {
            const mediaInfo = extractMediaInfo(url);
            if (mediaInfo) {
                if (mediaInfo.platform === 'youtube') {
                    embedYouTubeIframe(mediaInfo.id, start, 'video');
                } else if (mediaInfo.platform === 'vimeo') {
                    embedVimeoPlayer(mediaInfo.id, start, 'video');
                }
                showMessage(`Loaded ${capitalize(mediaInfo.platform)} video.`, 'success');
                hideLoading(elements.video.playerContainer);
            } else {
                showMessage('Invalid URL. Please enter a valid YouTube or Vimeo URL.', 'error');
                hideLoading(elements.video.playerContainer);
            }
        } else {
            showMessage('Please enter a URL or select a video file.', 'error');
            hideLoading(elements.video.playerContainer);
        }

        checkReadyToPlay();
        saveSettings();
    }

    // Play Handler
    function handlePlay() {
        // Play Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.music.element);
                }
            } else if (state.music.type === 'vimeo') {
                state.music.element.play().catch(error => {
                    console.error('Error playing Vimeo audio:', error);
                    showMessage('Failed to play Vimeo audio.', 'error');
                });
            }
            // YouTube control can be added similarly if integrated
        }

        // Play Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.video.element);
                }
            } else if (state.video.type === 'vimeo') {
                state.video.element.play().catch(error => {
                    console.error('Error playing Vimeo video:', error);
                    showMessage('Failed to play Vimeo video.', 'error');
                });
            }
            // YouTube control can be added similarly if integrated
        }

        state.isPaused = false;
        elements.controls.pauseResumeButton.textContent = 'Pause';
        showMessage('Playback started!', 'success');
    }

    // Pause/Resume Handler
    function handlePauseResume() {
        if (state.isPaused) {
            resumeMedia();
        } else {
            pauseMedia();
        }
    }

    // Pause Media
    function pauseMedia() {
        // Pause Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.pause();
            } else if (state.music.type === 'vimeo') {
                state.music.element.pause().catch(error => {
                    console.error('Error pausing Vimeo audio:', error);
                    showMessage('Failed to pause Vimeo audio.', 'error');
                });
            }
        }

        // Pause Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.pause();
            } else if (state.video.type === 'vimeo') {
                state.video.element.pause().catch(error => {
                    console.error('Error pausing Vimeo video:', error);
                    showMessage('Failed to pause Vimeo video.', 'error');
                });
            }
        }

        state.isPaused = true;
        elements.controls.pauseResumeButton.textContent = 'Resume';
        showMessage('Playback paused.', 'info');
    }

    // Resume Media
    function resumeMedia() {
        // Resume Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.play();
            } else if (state.music.type === 'vimeo') {
                state.music.element.play().catch(error => {
                    console.error('Error resuming Vimeo audio:', error);
                    showMessage('Failed to resume Vimeo audio.', 'error');
                });
            }
        }

        // Resume Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.play();
            } else if (state.video.type === 'vimeo') {
                state.video.element.play().catch(error => {
                    console.error('Error resuming Vimeo video:', error);
                    showMessage('Failed to resume Vimeo video.', 'error');
                });
            }
        }

        state.isPaused = false;
        elements.controls.pauseResumeButton.textContent = 'Pause';
        showMessage('Playback resumed.', 'success');
    }

    // Play From Start Handler
    function handlePlayFromStart() {
        // Play from Start Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.currentTime = state.music.start;
                state.music.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.music.element);
                }
            } else if (state.music.type === 'vimeo') {
                state.music.element.setCurrentTime(state.music.start).then(() => {
                    return state.music.element.play();
                }).catch(error => {
                    console.error('Error playing from start in Vimeo audio:', error);
                    showMessage('Failed to play from start in Vimeo audio.', 'error');
                });
            }
        }

        // Play from Start Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.currentTime = state.video.start;
                state.video.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.video.element);
                }
            } else if (state.video.type === 'vimeo') {
                state.video.element.setCurrentTime(state.video.start).then(() => {
                    return state.video.element.play();
                }).catch(error => {
                    console.error('Error playing from start in Vimeo video:', error);
                    showMessage('Failed to play from start in Vimeo video.', 'error');
                });
            }
        }

        state.isPaused = false;
        elements.controls.pauseResumeButton.textContent = 'Pause';
        showMessage('Playback restarted!', 'success');
    }

    // === Settings Modal Functions ===
    function openSettingsModal() {
        elements.settings.modal.removeAttribute('hidden');
        elements.settings.modal.setAttribute('aria-hidden', 'false');
        elements.settings.modal.querySelector('.close-button').focus();
        trapFocus(elements.settings.modal);
    }

    function closeSettingsModal() {
        elements.settings.modal.setAttribute('hidden', '');
        elements.settings.modal.setAttribute('aria-hidden', 'true');
        elements.settings.button.focus();
        removeTrapFocus();
    }

    // === Media Embedding Functions ===

    /**
     * Embeds a YouTube video into the specified container using an iframe.
     * Mutes the video and starts at the specified time without autoplay.
     * @param {string} videoId - The YouTube video ID.
     * @param {number} start - The start time in seconds.
     * @param {string} mediaType - 'music' or 'video'.
     */
    function embedYouTubeIframe(videoId, start, mediaType) {
        const container = elements[mediaType].playerContainer;
        container.innerHTML = ''; // Clear previous content

        let src = `https://www.youtube.com/embed/${videoId}?mute=1&start=${start}&controls=1&rel=0&enablejsapi=1`;
        // Note: autoplay=1 removed to prevent auto-play

        const iframe = document.createElement('iframe');
        iframe.src = src;
        iframe.width = '100%';
        iframe.height = '720'; // Increased height
        iframe.frameBorder = '0';
        iframe.allow = 'autoplay; fullscreen; picture-in-picture';

        iframe.setAttribute('title', 'YouTube video player');
        iframe.setAttribute('id', `youtube-${mediaType}-player`);

        container.appendChild(iframe);

        state[mediaType] = {
            type: 'youtube',
            element: iframe,
            start: start
        };
    }

    /**
     * Embeds a Vimeo video into the specified container using the Player API.
     * Mutes the video and starts at the specified time without autoplay.
     * @param {string} videoId - The Vimeo video ID.
     * @param {number} start - The start time in seconds.
     * @param {string} mediaType - 'music' or 'video'.
     */
    function embedVimeoPlayer(videoId, start, mediaType) {
        const container = elements[mediaType].playerContainer;
        container.innerHTML = ''; // Clear previous content

        const iframe = document.createElement('iframe');
        const src = `https://player.vimeo.com/video/${videoId}?muted=1&autopause=0&background=0`;
        iframe.src = src;
        iframe.width = '100%';
        iframe.height = '720'; // Increased height
        iframe.frameBorder = '0';
        iframe.allow = 'autoplay; fullscreen; picture-in-picture';

        iframe.setAttribute('title', 'Vimeo video player');
        iframe.setAttribute('id', `vimeo-${mediaType}-player`);

        container.appendChild(iframe);

        const player = new Vimeo.Player(iframe, {
            id: videoId,
            width: container.clientWidth,
            muted: true,
            autoplay: false,
            start: start
        });

        state[mediaType] = {
            type: 'vimeo',
            element: player,
            start: start
        };

        // Ensure buffering by loading the video without autoplay
        player.setVolume(0).catch(error => {
            console.error(`Error setting volume for Vimeo ${mediaType}:`, error);
        });
    }

    // === Settings Management ===

    /**
     * Loads settings from Chrome storage.
     */
    function loadSettings() {
        try {
            chrome.storage.local.get(['mediaSettings'], (result) => {
                if (chrome.runtime.lastError) {
                    throw new Error(chrome.runtime.lastError);
                }

                if (result.mediaSettings) {
                    const { music, video, fullscreenOnPlay: fsPlay } = result.mediaSettings;

                    if (music) {
                        if (music.type === 'youtube' 
                            || music.type === 'vimeo') {
                            const url = music.type === 'youtube' 
                                ? `https://www.youtube.com/watch?v=${music.id}` 
                                : `https://vimeo.com/${music.id}`;
                            elements.music.urlInput.value = url;
                            elements.music.startInput.value = music.start || 0;
                            // Optionally, auto-load the media by triggering the load button
                            // handleLoadMusic();
                        }
                        // Handle file-based music loading if necessary
                    }

                    if (video) {
                        if (video.type === 'youtube' 
                            || video.type === 'vimeo') {
                            const url = video.type === 'youtube' 
                                ? `https://www.youtube.com/watch?v=${video.id}` 
                                : `https://vimeo.com/${video.id}`;
                            elements.video.urlInput.value = url;
                            elements.video.startInput.value = video.start || 0;
                            // Optionally, auto-load the media by triggering the load button
                            // handleLoadVideo();
                        }
                        // Handle file-based video loading if necessary
                    }

                    if (typeof fsPlay === 'boolean') {
                        state.fullscreenOnPlay = fsPlay;
                        elements.settings.fullscreenToggle.checked = fsPlay;
                    }
                }
            });
        } catch (error) {
            console.error('Error loading settings:', error);
            showMessage('Failed to load settings.', 'error');
        }
    }

    /**
     * Saves settings to Chrome storage.
     */
    function saveSettings() {
        const settings = {
            music: state.music,
            video: state.video,
            fullscreenOnPlay: state.fullscreenOnPlay
        };
        try {
            chrome.storage.local.set({ mediaSettings: settings }, () => {
                if (chrome.runtime.lastError) {
                    throw new Error(chrome.runtime.lastError);
                }
                console.log('Settings saved.');
            });
        } catch (error) {
            console.error('Error saving settings:', error);
            showMessage('Error saving settings.', 'error');
        }
    }

    /**
     * Unloads media from the specified type.
     * @param {string} mediaType - 'music' or 'video'.
     */
    function unloadMedia(mediaType) {
        if (state[mediaType]) {
            if (state[mediaType].type === 'file') {
                if (state[mediaType].element.src) {
                    URL.revokeObjectURL(state[mediaType].element.src);
                    state[mediaType].element.src = '';
                    state[mediaType].element.remove();
                }
            } else if (state[mediaType].type === 'youtube') {
                const iframe = state[mediaType].element;
                iframe.src = ''; // Reset iframe src to stop the media
            } else if (state[mediaType].type === 'vimeo') {
                const player = state[mediaType].element;
                player.unload().catch(error => {
                    console.error(`Error unloading Vimeo ${mediaType}:`, error);
                });
            }
            state[mediaType] = null;
        }
    }

    // === Playback Controls ===

    /**
     * Enables or disables playback controls based on media loading state.
     */
    function checkReadyToPlay() {
        // Enable Play button only when at least one of audio or video is loaded
        const readyAudio = state.music 
            && (state.music.type === 'file' 
                || state.music.type === 'youtube' 
                || state.music.type === 'vimeo');
        const readyVideo = state.video 
            && (state.video.type === 'file' 
                || state.video.type === 'youtube' 
                || state.video.type === 'vimeo');
        const ready = readyAudio || readyVideo;

        elements.controls.playButton.disabled = !ready;
        elements.controls.pauseResumeButton.disabled = !ready;
        elements.controls.playStartButton.disabled = !ready;
    }

    /**
     * Enters fullscreen mode for the specified element.
     * @param {HTMLElement} element - The element to enter fullscreen.
     */
    function enterFullscreen(element) {
        if (element && element.element && element.element.requestFullscreen) {
            element.element.requestFullscreen().then(() => {
                showMessage('Entered fullscreen mode.', 'success');
            }).catch(err => {
                console.error(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
                showMessage('Failed to enter fullscreen mode.', 'error');
            });
        } else if (element && element.requestFullscreen) {
            element.requestFullscreen().then(() => {
                showMessage('Entered fullscreen mode.', 'success');
            }).catch(err => {
                console.error(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
                showMessage('Failed to enter fullscreen mode.', 'error');
            });
        } else {
            showMessage('Fullscreen not supported on this element.', 'error');
        }
    }

    // === New Utility Functions ===

    /**
     * Validates whether the URL is a valid YouTube or Vimeo URL.
     * @param {string} url - The URL to validate.
     * @returns {boolean} True if valid, else false.
     */
    function isValidMediaURL(url) {
        try {
            const parsedUrl = new URL(url);
            const hostname = parsedUrl.hostname.toLowerCase();
            const pathname = parsedUrl.pathname;

            // YouTube RegEx Patterns
            const youtubeRegex = /^(?:\/watch\/?|\/embed\/|\/v\/)?([a-zA-Z0-9_-]{11})$/;
            // Vimeo RegEx Patterns
            const vimeoRegex = /^\/(?:video\/)?(\d+)$/;

            if (hostname.includes('youtube.com') || hostname === 'youtu.be') {
                // Extract YouTube video ID
                let videoId = '';
                if (hostname === 'youtu.be') {
                    videoId = pathname.slice(1);
                } else {
                    videoId = parsedUrl.searchParams.get('v') || '';
                }
                return youtubeRegex.test(`/${videoId}`);
            } else if (hostname.includes('vimeo.com')) {
                // Extract Vimeo video ID
                const match = pathname.match(vimeoRegex);
                return match && match[1].length > 0;
            }

            return false;
        } catch (e) {
            return false;
        }
    }

    /**
     * Extracts media information from the URL.
     * @param {string} url - The media URL.
     * @returns {Object|null} An object with platform and id, or null if invalid.
     */
    function extractMediaInfo(url) {
        try {
            const parsedUrl = new URL(url);
            const hostname = parsedUrl.hostname.toLowerCase();
            const pathname = parsedUrl.pathname;

            // YouTube Patterns
            if (hostname.includes('youtube.com') 
                || hostname === 'youtu.be') {
                let videoId = '';
                if (hostname === 'youtu.be') {
                    videoId = pathname.slice(1);
                } else {
                    videoId = parsedUrl.searchParams.get('v') || '';
                }

                // Validate videoId length
                if (videoId.length === 11) {
                    return { platform: 'youtube', id: videoId };
                }
            }

            // Vimeo Patterns
            if (hostname.includes('vimeo.com')) {
                const vimeoMatch = pathname.match(/^\/(?:video\/)?(\d+)$/);
                if (vimeoMatch && vimeoMatch[1]) {
                    return { platform: 'vimeo', id: vimeoMatch[1] };
                }
            }

            return null;
        } catch (e) {
            return null;
        }
    }
});
5. styles.css
Key Changes:

Increased Player Sizes: Set height: 720px for iframes to display larger videos.
Enhanced Responsiveness: Adjusted styles to ensure the extension looks good on various screen sizes.
Loader Visibility: Increased loader size for better visibility.

/* General Styles */
body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    margin: 0;
    padding: 0;
}

.container {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 20px;
    max-width: 1000px; /* Increased max-width for larger displays */
    margin: 0 auto;
}

.section {
    width: 100%;
    margin-bottom: 20px;
    background-color: #fff;
    padding: 15px;
    border-radius: 8px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

/* Header with Settings Button and Main Title */
.header {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center; /* Center the content */
    margin-bottom: 20px;
    position: relative;
}

.settings-button {
    position: absolute;
    left: 0;
    background: #fff;
    border: 1px solid #ccc;
    border-radius: 5px;
    padding: 5px;
    cursor: pointer;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.3s ease, border-color 0.3s ease;
}

.settings-button:hover {
    background-color: #f0f0f0;
    border-color: #999;
}

.settings-icon {
    width: 20px;
    height: 20px;
}

.main-title {
    font-size: 2.5em; /* Increased font size for better visibility */
    font-weight: bold;
    margin: 0;
    opacity: 0;
    animation: fadeInShake 5s forwards;
}

@keyframes fadeInShake {
    0% {
        opacity: 0;
        transform: translateX(0);
        color: #FF0000; /* Red */
    }
    10% {
        opacity: 0.2;
        transform: translateX(-10px);
        color: #FF7F00; /* Orange */
    }
    20% {
        opacity: 0.4;
        transform: translateX(10px);
        color: #FFFF00; /* Yellow */
    }
    30% {
        opacity: 0.6;
        transform: translateX(-10px);
        color: #00FF00; /* Green */
    }
    40% {
        opacity: 0.7;
        transform: translateX(10px);
        color: #0000FF; /* Blue */
    }
    50% {
        opacity: 0.8;
        transform: translateX(-10px);
        color: #4B0082; /* Indigo */
    }
    60% {
        opacity: 0.85;
        transform: translateX(10px);
        color: #8B00FF; /* Violet */
    }
    70% {
        opacity: 0.9;
        transform: translateX(-10px);
        color: #FF00FF; /* Magenta */
    }
    80% {
        opacity: 0.95;
        transform: translateX(10px);
        color: #000000; /* Black */
    }
    100% {
        opacity: 1;
        transform: translateX(0);
        color: #000000; /* Black */
    }
}

/* Controls */
.controls {
    display: flex;
    gap: 10px;
    margin-bottom: 20px;
}

.controls button {
    padding: 12px 24px; /* Increased padding for better accessibility */
    cursor: pointer;
    border: none;
    border-radius: 5px;
    background-color: #4285f4;
    color: #fff;
    transition: background-color 0.3s ease;
    font-size: 1em;
}

.controls button:disabled {
    background-color: #a0c3ff;
    cursor: not-allowed;
}

.controls button:hover:not(:disabled) {
    background-color: #357ae8;
}

/* Modal Styles */
.modal[hidden] {
    display: none;
}

.modal {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.5);
    display: flex; /* Visible when not hidden */
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

.modal-content {
    background-color: #fff;
    padding: 20px 30px;
    border-radius: 8px;
    width: 90%;
    max-width: 500px; /* Increased max-width for better layout */
    position: relative;
}

.close-button {
    position: absolute;
    top: 10px;
    right: 15px;
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
}

.modal-content h2 {
    margin-top: 0;
}

/* Form Elements */
fieldset {
    border: none;
    padding: 0;
}

fieldset label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold;
}

fieldset input[type="text"],
fieldset input[type="number"],
fieldset input[type="file"] {
    width: 100%;
    padding: 10px; /* Increased padding for better usability */
    margin-bottom: 15px;
    box-sizing: border-box;
    border: 1px solid #ccc;
    border-radius: 4px;
}

fieldset .load-button {
    width: 100%;
    padding: 12px;
    background-color: #34a853;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s ease;
    font-size: 1em;
}

fieldset .load-button:hover {
    background-color: #2c8e46;
}

/* Player Containers */
.player-container {
    margin-top: 10px;
    width: 100%;
    max-width: 100%;
    min-height: 100px; /* Increased minimum height */
    box-sizing: border-box;
    overflow: hidden; /* Prevent overflow */
}

/* Responsive Video and Audio Elements */
.player-container video,
.player-container iframe {
    width: 100%;
    height: 720px; /* Fixed height for consistency */
    border-radius: 8px;
    /* Ensure the iframe fills the container */
    display: block;
}

/* Messages */
.message-container {
    margin-top: 20px;
    width: 100%;
}

.message {
    padding: 12px;
    border-radius: 5px;
    margin-bottom: 10px;
    color: #fff;
    font-size: 1em;
}

.message.success {
    background-color: #4caf50;
}

.message.error {
    background-color: #f44336;
}

.message.info {
    background-color: #2196f3;
}

/* Loader */
.loader {
    border: 8px solid #f3f3f3; /* Light grey */
    border-top: 8px solid #4285f4; /* Blue */
    border-radius: 50%;
    width: 60px; /* Increased size for better visibility */
    height: 60px; /* Increased size for better visibility */
    animation: spin 1s linear infinite;
    margin: 0 auto;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

/* Responsive Design */
@media (max-width: 800px) {
    .container {
        padding: 15px;
    }

    .modal-content {
        padding: 15px 20px;
    }

    .controls {
        flex-direction: column;
        width: 100%;
    }

    .controls button {
        width: 100%;
    }

    .settings-button {
        width: 35px;
        height: 35px;
    }

    .settings-icon {
        width: 18px;
        height: 18px;
    }

    .main-title {
        font-size: 2em;
    }

    .player-container video,
    .player-container iframe {
        height: 480px; /* Adjusted height for smaller screens */
    }

    .loader {
        width: 50px; /* Adjusted size for smaller screens */
        height: 50px; /* Adjusted size for smaller screens */
    }
}

@media (max-width: 500px) {
    .container {
        padding: 10px;
    }

    .controls button {
        padding: 10px;
        font-size: 0.9em;
    }

    .modal-content {
        padding: 10px 15px;
    }

    .main-title {
        font-size: 1.8em;
    }

    .player-container video,
    .player-container iframe {
        height: 360px; /* Further adjusted height for very small screens */
    }

    .loader {
        width: 40px; /* Further adjusted size for very small screens */
        height: 40px; /* Further adjusted size for very small screens */
    }
}
6. lib/player.js
Important: Since Chrome extensions cannot load external scripts due to CSP restrictions, you need to download the Vimeo Player API script and place it in the lib directory within your extension folder.

Steps:

Download Vimeo Player API:
Visit the Vimeo Player.js GitHub Repository or directly download the latest version of player.js.
Add to Extension:
Create a lib folder inside your extension directory (myext/lib/).
Place the downloaded player.js file inside this folder.
Ensure Correct Pathing:
The dashboard.html file references this script as <script src="lib/player.js"></script>, so ensure the file exists at this path.
Summary of Key Changes:
Increased Video Size:
Set iframe heights to 720px to display larger videos.
Adjusted player containers to accommodate larger iframes.
Prevented Auto-Play:
Removed autoplay=1 from Vimeo and YouTube embed URLs.
Ensured videos only buffer upon loading, waiting for user interaction to play.
Replaced "Upload" with "Local":
Updated labels in dashboard.html from "Upload Audio File" and "Upload Video File" to "Local Audio File" and "Local Video File" respectively.
Removed "Load Audio" and "Load Video" Legends:
Eliminated the <legend> tags to streamline the UI.
Fixed CSP Issues:
Removed external script sources from manifest.json.
Included the Vimeo Player API as a local script (lib/player.js) to comply with CSP.
Enhanced Playback Controls:
Utilized the Vimeo Player API to programmatically control playback (play, pause, play from start).
Ensured that the Play button triggers playback, and Pause/Resume toggles playback state accordingly.
Improved Responsiveness:
Adjusted CSS to ensure the extension looks good on various screen sizes.
Ensured that player containers and iframes are fully responsive.
Accessibility Enhancements:
Maintained appropriate ARIA labels and focus management, especially for the settings modal.
Final Steps:
Ensure Directory Structure: Your extension directory (myext/) should have the following structure:

myext/
├── background.js
├── dashboard.html
├── dashboard.js
├── styles.css
├── lib/
│   └── player.js
├── icons/
│   ├── icon16.png
│   ├── icon48.png
│   ├── icon128.png
│   └── settings.svg
└── manifest.json
Reload the Extension:
Open Chrome and navigate to chrome://extensions/.
Enable "Developer mode" if it's not already enabled (toggle in the top-right corner).
Click on "Load unpacked" and select your myext directory.
Ensure there are no errors. If errors persist, review the Developer Console for more details.
Test Functionality:
Loading Videos:
Enter a valid Vimeo URL in the Video URL field or select a local video file.
Click the "Load" button.
The video should appear in the player container with increased size and start buffering.
Playback Controls:
Click "Play" to start playback.
Use "Pause" to pause and "Resume" to continue.
Click "Play from Start" to rewind to the specified start time and play.
Settings:
Click the Settings button (gear icon) to toggle "Full Screen on Play".
When enabled, clicking "Play" should trigger fullscreen mode for the media.
Troubleshooting:
CSP Errors:
Ensure that the manifest.json does not include any external script sources.
Verify that lib/player.js is correctly placed and referenced.
Playback Controls Not Working:
Confirm that the Vimeo Player API is correctly loaded via lib/player.js.
Check for any errors in the Chrome Developer Console.
Video Not Buffering:
Ensure that the Vimeo URLs are correct and that the player is initialized without autoplay.
Developer Console:
Open Chrome's Developer Console (Ctrl+Shift+I or Cmd+Option+I on Mac) to check for any runtime errors and debug accordingly.
Important Notes:
Security Considerations:
Always validate and sanitize any user inputs to prevent security vulnerabilities.
Be cautious when handling media files to avoid introducing malicious content.
Vimeo Player API Usage:
The Vimeo Player API allows for extensive control over embedded videos. Refer to the Vimeo Player.js Documentation for more advanced integrations and functionalities.
Extensibility:
Consider adding more settings or features based on user feedback or requirements.
Ensure that new features comply with Chrome's extension policies and best practices.
User Experience:
Ensure that the UI is intuitive and responsive.
Provide feedback to users through messages and loading indicators to enhance usability.
By following the above updates and guidelines, your Chrome extension should now load Vimeo videos at larger sizes, buffer upon loading without auto-playing, and have fully functional playback controls while complying with Chrome's Content Security Policy (CSP). If you encounter any further issues or need additional assistance, feel free to ask!


when extension is run i got this error: Errors
Uncaught SyntaxError: Cannot use import statement outside a module
Context
dashboard.html


Apologies for the inconvenience you're experiencing. The error you're encountering:


Uncaught SyntaxError: Cannot use import statement outside a module
is typically caused by using ES6 import statements in scripts that are not designated as modules. In your case, the issue arises because the <script> tags in your dashboard.html are set to type="module", but the player.js file (Vimeo's Player API) is not an ES module and doesn't support import statements.

To resolve this, follow these steps:

Remove type="module" from <script> Tags: Ensure that neither player.js nor dashboard.js uses import statements unless they are designated as modules.
Ensure player.js is the Correct Version: The Vimeo Player API should be included as a standard script (UMD format) and not as an ES module.
Update Your Files Accordingly: Below are the fully updated files with the necessary corrections.
1. manifest.json
No changes are needed here based on your current requirements. Ensure it matches the following:


{
  "manifest_version": 3,
  "name": "Media Loader",
  "version": "1.1",
  "description": "Load and play music and videos from YouTube and Vimeo",
  "permissions": ["storage", "tabs"],
  "host_permissions": [
    "https://www.youtube.com/*",
    "https://player.vimeo.com/*"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "Open Media Loader",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  },
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
  "web_accessible_resources": [
    {
      "resources": ["lib/player.js"],
      "matches": ["<all_urls>"]
    }
  ]
}
2. background.js
No changes are needed here. Ensure it matches the following:


chrome.action.onClicked.addListener(() => {
    const dashboardURL = chrome.runtime.getURL("dashboard.html");
    
    // Query for any existing tabs with the dashboard URL
    chrome.tabs.query({ url: dashboardURL }, (tabs) => {
        if (chrome.runtime.lastError) {
            console.error("Tab Query Error:", chrome.runtime.lastError);
            return;
        }

        if (tabs.length > 0) {
            // Activate the first existing dashboard tab
            chrome.tabs.update(tabs[0].id, { active: true }, (updatedTab) => {
                if (chrome.runtime.lastError) {
                    console.error("Tab Update Error:", chrome.runtime.lastError);
                }
            });
        } else {
            // Create a new dashboard tab
            chrome.tabs.create({ url: dashboardURL, active: true }, (newTab) => {
                if (chrome.runtime.lastError) {
                    console.error("Tab Creation Error:", chrome.runtime.lastError);
                }
            });
        }
    });
});
3. dashboard.html
Key Changes:

Removed type="module" from <script> Tags: This prevents the browser from treating the scripts as ES modules, which don't support the current player.js setup.
Ensured Correct Inclusion of player.js: The Vimeo Player API should be included as a standard script.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Media Loader Dashboard</title>
    <link rel="stylesheet" href="styles.css">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <main class="container">
        <!-- Header with Settings Button and SyncWave Title -->
        <header class="header">
            <button id="settings-button" class="settings-button" title="Settings" aria-label="Open Settings">
                <img src="icons/settings.svg" alt="Settings" class="settings-icon" aria-hidden="true">
            </button>
            <h1 class="main-title">SyncWave</h1>
        </header>
        
        <!-- Load Audio Section -->
        <section class="section" id="load-music-section">
            <!-- Legends Removed -->

            <fieldset>
                <label for="music-url">Audio URL</label>
                <input type="text" id="music-url" name="music-url" placeholder="Enter YouTube or Vimeo URL">

                <label for="music-file">Local Audio File</label>
                <input type="file" id="music-file" name="music-file" accept="audio/*">

                <label for="music-start">Start Time (seconds)</label>
                <input type="number" id="music-start" name="music-start" placeholder="Start Time (seconds)" min="0">

                <button type="button" id="load-music" class="load-button">Load</button>
            </fieldset>
            <div id="music-player-container" class="player-container"></div>
        </section>

        <!-- Load Video Section -->
        <section class="section" id="load-video-section">
            <!-- Legends Removed -->

            <fieldset>
                <label for="video-url">Video URL</label>
                <input type="text" id="video-url" name="video-url" placeholder="Enter YouTube or Vimeo URL">

                <label for="video-file">Local Video File</label>
                <input type="file" id="video-file" name="video-file" accept="video/*">

                <label for="video-start">Start Time (seconds)</label>
                <input type="number" id="video-start" name="video-start" placeholder="Start Time (seconds)" min="0">

                <button type="button" id="load-video" class="load-button">Load</button>
            </fieldset>
            <div id="video-player-container" class="player-container"></div>
        </section>

        <!-- Playback Controls -->
        <section class="controls">
            <button type="button" id="play-button" disabled aria-label="Play">Play</button>
            <button type="button" id="pause-resume-button" disabled aria-label="Pause">Pause</button>
            <button type="button" id="play-start-button" disabled aria-label="Play from Start">Play from Start</button>
        </section>

        <!-- Message Container -->
        <section id="message-container" class="message-container" role="alert" aria-live="assertive"></section>

        <!-- Settings Modal (Remains Unchanged) -->
        <div id="settings-modal" class="modal" role="dialog" aria-labelledby="settings-modal-title" aria-modal="true" hidden>
            <div class="modal-content">
                <button class="close-button" aria-label="Close Settings Modal">&times;</button>
                <h2 id="settings-modal-title">Settings</h2>
                <form>
                    <label for="fullscreen-toggle">
                        <input type="checkbox" id="fullscreen-toggle" name="fullscreen-toggle">
                        Full Screen on Play
                    </label>
                    <!-- Additional settings can go here -->
                </form>
            </div>
        </div>
    </main>

    <!-- Local Vimeo Player API -->
    <script src="lib/player.js"></script>
    
    <!-- Your Dashboard JS -->
    <script src="dashboard.js"></script>
</body>
</html>
4. dashboard.js
Key Changes:

Removed type="module" Compatibility: Since scripts are no longer loaded as modules, ensure that no import or export statements are present.
Integrated Vimeo Player API Properly: Utilize the globally available Vimeo.Player object provided by player.js.

"use strict";

document.addEventListener('DOMContentLoaded', () => {
    // === Element References ===
    const elements = {
        music: {
            urlInput: document.getElementById('music-url'),
            fileInput: document.getElementById('music-file'),
            startInput: document.getElementById('music-start'),
            loadButton: document.getElementById('load-music'),
            playerContainer: document.getElementById('music-player-container')
        },
        video: {
            urlInput: document.getElementById('video-url'),
            fileInput: document.getElementById('video-file'),
            startInput: document.getElementById('video-start'),
            loadButton: document.getElementById('load-video'),
            playerContainer: document.getElementById('video-player-container')
        },
        controls: {
            playButton: document.getElementById('play-button'),
            pauseResumeButton: document.getElementById('pause-resume-button'),
            playStartButton: document.getElementById('play-start-button')
        },
        messageContainer: document.getElementById('message-container'),
        settings: {
            button: document.getElementById('settings-button'),
            modal: document.getElementById('settings-modal'),
            closeButton: document.querySelector('.close-button'),
            fullscreenToggle: document.getElementById('fullscreen-toggle')
        }
    };

    // === State Management ===
    const state = {
        music: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLAudioElement | Player, start: Number }
        video: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLVideoElement | Player, start: Number }
        isPaused: false,
        fullscreenOnPlay: false
    };

    // === Utility Functions ===

    /**
     * Formats seconds into 'XmYs' (e.g., 125 seconds -> '2m5s')
     * @param {number} seconds - The time in seconds.
     * @returns {string} Formatted time string.
     */
    function formatTime(seconds) {
        if (isNaN(seconds) || seconds < 0) return '';
        const minutes = Math.floor(seconds / 60);
        const remainingSeconds = seconds % 60;
        return `${minutes}m${remainingSeconds}s`;
    }

    /**
     * Capitalize the first letter of a string.
     * @param {string} text - The string to capitalize.
     * @returns {string} Capitalized string.
     */
    function capitalize(text) {
        if (!text) return '';
        return text.charAt(0).toUpperCase() + text.slice(1);
    }

    /**
     * Displays a message to the user.
     * @param {string} message - The message to display.
     * @param {string} type - The type of message ('success', 'error', 'info').
     */
    function showMessage(message, type) {
        elements.messageContainer.innerHTML = '';
        const msgDiv = document.createElement('div');
        msgDiv.textContent = message;
        msgDiv.classList.add('message', type); // 'success', 'error', 'info'
        elements.messageContainer.appendChild(msgDiv);

        // Automatically hide message after 5 seconds
        setTimeout(() => {
            if (elements.messageContainer.contains(msgDiv)) {
                elements.messageContainer.removeChild(msgDiv);
            }
        }, 5000);
    }

    /**
     * Shows a loading spinner in the specified container.
     * @param {HTMLElement} container - The container to show the loader in.
     */
    function showLoading(container) {
        container.innerHTML = '';
        const loader = document.createElement('div');
        loader.classList.add('loader'); // Define loader styles in CSS
        container.appendChild(loader);
    }

    /**
     * Hides the loading spinner from the specified container.
     * @param {HTMLElement} container - The container to hide the loader from.
     */
    function hideLoading(container) {
        const loader = container.querySelector('.loader');
        if (loader) {
            container.removeChild(loader);
        }
    }

    /**
     * Traps keyboard focus within a specified element.
     * @param {HTMLElement} element - The element to trap focus within.
     */
    function trapFocus(element) {
        const focusableElementsString = 'a[href], area[href], input:not([disabled]), select:not([disabled]),' +
            ' textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"],' +
            ' [contenteditable]';
        const focusableElements = element.querySelectorAll(focusableElementsString);
        const firstTabStop = focusableElements[0];
        const lastTabStop = focusableElements[focusableElements.length - 1];

        // Listen for and trap the keyboard
        element.addEventListener('keydown', trapTabKey);

        function trapTabKey(e) {
            // Check for TAB key press
            if (e.key === 'Tab') {
                // SHIFT + TAB
                if (e.shiftKey) {
                    if (document.activeElement === firstTabStop) {
                        e.preventDefault();
                        lastTabStop.focus();
                    }
                } else { // TAB
                    if (document.activeElement === lastTabStop) {
                        e.preventDefault();
                        firstTabStop.focus();
                    }
                }
            }
        }

        // Remove trap when modal is closed
        function removeTrapKey(e) {
            element.removeEventListener('keydown', trapTabKey);
        }

        // Store the function reference to remove it later
        element.removeTrapKey = removeTrapKey;
    }

    function removeTrapFocus() {
        if (elements.settings.modal.removeTrapKey) {
            elements.settings.modal.removeTrapKey();
        }
    }

    // === Initialization ===
    loadSettings();

    // === Event Listeners ===
    elements.music.loadButton.addEventListener('click', handleLoadMusic);
    elements.video.loadButton.addEventListener('click', handleLoadVideo);
    elements.controls.playButton.addEventListener('click', handlePlay);
    elements.controls.pauseResumeButton.addEventListener('click', handlePauseResume);
    elements.controls.playStartButton.addEventListener('click', handlePlayFromStart);

    // Settings Modal Event Listeners
    elements.settings.button.addEventListener('click', openSettingsModal);
    elements.settings.closeButton.addEventListener('click', closeSettingsModal);
    window.addEventListener('click', (event) => {
        if (event.target === elements.settings.modal) {
            closeSettingsModal();
        }
    });
    document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape' && !elements.settings.modal.hasAttribute('hidden')) {
            closeSettingsModal();
        }
    });
    elements.settings.fullscreenToggle.addEventListener('change', (event) => {
        state.fullscreenOnPlay = event.target.checked;
        saveSettings();
    });

    // === Handler Functions ===

    // Load Music Handler
    function handleLoadMusic() {
        const url = elements.music.urlInput.value.trim();
        const file = elements.music.fileInput.files[0];
        const start = parseInt(elements.music.startInput.value) || 0;

        // Show loading indicator
        showLoading(elements.music.playerContainer);

        // Unload existing music if any
        if (state.music) {
            unloadMedia('music');
        }

        if (file) {
            if (file.size > 10 * 1024 * 1024) { // 10MB limit
                showMessage('Audio file size exceeds 10MB limit.', 'error');
                hideLoading(elements.music.playerContainer);
                return;
            }

            // Handle local audio file
            const fileUrl = URL.createObjectURL(file);
            const audioElement = document.createElement('audio');
            audioElement.controls = true;
            audioElement.src = fileUrl;
            audioElement.id = 'loaded-music';
            audioElement.setAttribute('aria-label', 'Loaded Audio Player');
            audioElement.style.width = '100%';
            audioElement.style.height = 'auto';
            elements.music.playerContainer.innerHTML = '';
            elements.music.playerContainer.appendChild(audioElement);

            // Set start time if applicable
            if (start > 0) {
                audioElement.currentTime = start;
            }

            state.music = {
                type: 'file',
                element: audioElement,
                start: start
            };
            showMessage('Local audio file loaded.', 'success');
            hideLoading(elements.music.playerContainer);
        } else if (url && isValidMediaURL(url)) {
            const mediaInfo = extractMediaInfo(url);
            if (mediaInfo) {
                if (mediaInfo.platform === 'youtube') {
                    embedYouTubeIframe(mediaInfo.id, start, 'music');
                } else if (mediaInfo.platform === 'vimeo') {
                    embedVimeoPlayer(mediaInfo.id, start, 'music');
                }
                showMessage(`Loaded ${capitalize(mediaInfo.platform)} audio.`, 'success');
                hideLoading(elements.music.playerContainer);
            } else {
                showMessage('Invalid URL. Please enter a valid YouTube or Vimeo URL.', 'error');
                hideLoading(elements.music.playerContainer);
            }
        } else {
            showMessage('Please enter a URL or select a local audio file.', 'error');
            hideLoading(elements.music.playerContainer);
        }

        checkReadyToPlay();
        saveSettings();
    }

    // Load Video Handler
    function handleLoadVideo() {
        const url = elements.video.urlInput.value.trim();
        const file = elements.video.fileInput.files[0];
        const start = parseInt(elements.video.startInput.value) || 0;

        // Show loading indicator
        showLoading(elements.video.playerContainer);

        // Unload existing video if any
        if (state.video) {
            unloadMedia('video');
        }

        if (file) {
            if (file.size > 50 * 1024 * 1024) { // 50MB limit
                showMessage('Video file size exceeds 50MB limit.', 'error');
                hideLoading(elements.video.playerContainer);
                return;
            }

            // Handle local video file
            const fileUrl = URL.createObjectURL(file);
            const videoElement = document.createElement('video');
            videoElement.controls = true;
            videoElement.src = fileUrl;
            videoElement.id = 'loaded-video';
            videoElement.setAttribute('aria-label', 'Loaded Video Player');
            videoElement.style.width = '100%';
            videoElement.style.height = 'auto';
            elements.video.playerContainer.innerHTML = '';
            elements.video.playerContainer.appendChild(videoElement);

            // Set start time if applicable
            if (start > 0) {
                videoElement.currentTime = start;
            }

            state.video = {
                type: 'file',
                element: videoElement,
                start: start
            };
            showMessage('Local video file loaded.', 'success');
            hideLoading(elements.video.playerContainer);
        } else if (url && isValidMediaURL(url)) {
            const mediaInfo = extractMediaInfo(url);
            if (mediaInfo) {
                if (mediaInfo.platform === 'youtube') {
                    embedYouTubeIframe(mediaInfo.id, start, 'video');
                } else if (mediaInfo.platform === 'vimeo') {
                    embedVimeoPlayer(mediaInfo.id, start, 'video');
                }
                showMessage(`Loaded ${capitalize(mediaInfo.platform)} video.`, 'success');
                hideLoading(elements.video.playerContainer);
            } else {
                showMessage('Invalid URL. Please enter a valid YouTube or Vimeo URL.', 'error');
                hideLoading(elements.video.playerContainer);
            }
        } else {
            showMessage('Please enter a URL or select a local video file.', 'error');
            hideLoading(elements.video.playerContainer);
        }

        checkReadyToPlay();
        saveSettings();
    }

    // Play Handler
    function handlePlay() {
        // Play Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.music.element);
                }
            } else if (state.music.type === 'vimeo') {
                state.music.element.play().catch(error => {
                    console.error('Error playing Vimeo audio:', error);
                    showMessage('Failed to play Vimeo audio.', 'error');
                });
            }
            // YouTube control can be added similarly if integrated
        }

        // Play Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.video.element);
                }
            } else if (state.video.type === 'vimeo') {
                state.video.element.play().catch(error => {
                    console.error('Error playing Vimeo video:', error);
                    showMessage('Failed to play Vimeo video.', 'error');
                });
            }
            // YouTube control can be added similarly if integrated
        }

        state.isPaused = false;
        elements.controls.pauseResumeButton.textContent = 'Pause';
        showMessage('Playback started!', 'success');
    }

    // Pause/Resume Handler
    function handlePauseResume() {
        if (state.isPaused) {
            resumeMedia();
        } else {
            pauseMedia();
        }
    }

    // Pause Media
    function pauseMedia() {
        // Pause Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.pause();
            } else if (state.music.type === 'vimeo') {
                state.music.element.pause().catch(error => {
                    console.error('Error pausing Vimeo audio:', error);
                    showMessage('Failed to pause Vimeo audio.', 'error');
                });
            }
        }

        // Pause Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.pause();
            } else if (state.video.type === 'vimeo') {
                state.video.element.pause().catch(error => {
                    console.error('Error pausing Vimeo video:', error);
                    showMessage('Failed to pause Vimeo video.', 'error');
                });
            }
        }

        state.isPaused = true;
        elements.controls.pauseResumeButton.textContent = 'Resume';
        showMessage('Playback paused.', 'info');
    }

    // Resume Media
    function resumeMedia() {
        // Resume Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.play();
            } else if (state.music.type === 'vimeo') {
                state.music.element.play().catch(error => {
                    console.error('Error resuming Vimeo audio:', error);
                    showMessage('Failed to resume Vimeo audio.', 'error');
                });
            }
        }

        // Resume Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.play();
            } else if (state.video.type === 'vimeo') {
                state.video.element.play().catch(error => {
                    console.error('Error resuming Vimeo video:', error);
                    showMessage('Failed to resume Vimeo video.', 'error');
                });
            }
        }

        state.isPaused = false;
        elements.controls.pauseResumeButton.textContent = 'Pause';
        showMessage('Playback resumed.', 'success');
    }

    // Play From Start Handler
    function handlePlayFromStart() {
        // Play from Start Music
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.currentTime = state.music.start;
                state.music.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.music.element);
                }
            } else if (state.music.type === 'vimeo') {
                state.music.element.setCurrentTime(state.music.start).then(() => {
                    return state.music.element.play();
                }).catch(error => {
                    console.error('Error playing from start in Vimeo audio:', error);
                    showMessage('Failed to play from start in Vimeo audio.', 'error');
                });
            }
        }

        // Play from Start Video
        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.currentTime = state.video.start;
                state.video.element.play();
                if (state.fullscreenOnPlay) {
                    enterFullscreen(state.video.element);
                }
            } else if (state.video.type === 'vimeo') {
                state.video.element.setCurrentTime(state.video.start).then(() => {
                    return state.video.element.play();
                }).catch(error => {
                    console.error('Error playing from start in Vimeo video:', error);
                    showMessage('Failed to play from start in Vimeo video.', 'error');
                });
            }
        }

        state.isPaused = false;
        elements.controls.pauseResumeButton.textContent = 'Pause';
        showMessage('Playback restarted!', 'success');
    }

    // === Settings Modal Functions ===
    function openSettingsModal() {
        elements.settings.modal.removeAttribute('hidden');
        elements.settings.modal.setAttribute('aria-hidden', 'false');
        elements.settings.modal.querySelector('.close-button').focus();
        trapFocus(elements.settings.modal);
    }

    function closeSettingsModal() {
        elements.settings.modal.setAttribute('hidden', '');
        elements.settings.modal.setAttribute('aria-hidden', 'true');
        elements.settings.button.focus();
        removeTrapFocus();
    }

    // === Media Embedding Functions ===

    /**
     * Embeds a YouTube video into the specified container using an iframe.
     * Mutes the video and starts at the specified time without autoplay.
     * @param {string} videoId - The YouTube video ID.
     * @param {number} start - The start time in seconds.
     * @param {string} mediaType - 'music' or 'video'.
     */
    function embedYouTubeIframe(videoId, start, mediaType) {
        const container = elements[mediaType].playerContainer;
        container.innerHTML = ''; // Clear previous content

        let src = `https://www.youtube.com/embed/${videoId}?mute=1&start=${start}&controls=1&rel=0`;
        // Note: autoplay=1 removed to prevent auto-play

        const iframe = document.createElement('iframe');
        iframe.src = src;
        iframe.width = '100%';
        iframe.height = '720'; // Increased height
        iframe.frameBorder = '0';
        iframe.allow = 'autoplay; fullscreen; picture-in-picture';

        iframe.setAttribute('title', 'YouTube video player');

        container.appendChild(iframe);

        state[mediaType] = {
            type: 'youtube',
            element: iframe,
            start: start
        };
    }

    /**
     * Embeds a Vimeo video into the specified container using the Player API.
     * Mutes the video and starts at the specified time without autoplay.
     * @param {string} videoId - The Vimeo video ID.
     * @param {number} start - The start time in seconds.
     * @param {string} mediaType - 'music' or 'video'.
     */
    function embedVimeoPlayer(videoId, start, mediaType) {
        const container = elements[mediaType].playerContainer;
        container.innerHTML = ''; // Clear previous content

        const iframe = document.createElement('iframe');
        const src = `https://player.vimeo.com/video/${videoId}?muted=1&autopause=0&background=0`;
        iframe.src = src;
        iframe.width = '100%';
        iframe.height = '720'; // Increased height
        iframe.frameBorder = '0';
        iframe.allow = 'autoplay; fullscreen; picture-in-picture';

        iframe.setAttribute('title', 'Vimeo video player');

        container.appendChild(iframe);

        const player = new Vimeo.Player(iframe, {
            id: videoId,
            width: container.clientWidth,
            muted: true,
            autoplay: false,
            start: start
        });

        state[mediaType] = {
            type: 'vimeo',
            element: player,
            start: start
        };

        // Ensure buffering by loading the video without autoplay
        player.setVolume(0).catch(error => {
            console.error(`Error setting volume for Vimeo ${mediaType}:`, error);
        });
    }

    // === Settings Management ===

    /**
     * Loads settings from Chrome storage.
     */
    function loadSettings() {
        try {
            chrome.storage.local.get(['mediaSettings'], (result) => {
                if (chrome.runtime.lastError) {
                    throw new Error(chrome.runtime.lastError);
                }

                if (result.mediaSettings) {
                    const { music, video, fullscreenOnPlay: fsPlay } = result.mediaSettings;

                    if (music) {
                        if (music.type === 'youtube' 
                            || music.type === 'vimeo') {
                            const url = music.type === 'youtube' 
                                ? `https://www.youtube.com/watch?v=${music.id}` 
                                : `https://vimeo.com/${music.id}`;
                            elements.music.urlInput.value = url;
                            elements.music.startInput.value = music.start || 0;
                            // Optionally, auto-load the media by triggering the load button
                            // handleLoadMusic();
                        }
                        // Handle file-based music loading if necessary
                    }

                    if (video) {
                        if (video.type === 'youtube' 
                            || video.type === 'vimeo') {
                            const url = video.type === 'youtube' 
                                ? `https://www.youtube.com/watch?v=${video.id}` 
                                : `https://vimeo.com/${video.id}`;
                            elements.video.urlInput.value = url;
                            elements.video.startInput.value = video.start || 0;
                            // Optionally, auto-load the media by triggering the load button
                            // handleLoadVideo();
                        }
                        // Handle file-based video loading if necessary
                    }

                    if (typeof fsPlay === 'boolean') {
                        state.fullscreenOnPlay = fsPlay;
                        elements.settings.fullscreenToggle.checked = fsPlay;
                    }
                }
            });
        } catch (error) {
            console.error('Error loading settings:', error);
            showMessage('Failed to load settings.', 'error');
        }
    }

    /**
     * Saves settings to Chrome storage.
     */
    function saveSettings() {
        const settings = {
            music: state.music,
            video: state.video,
            fullscreenOnPlay: state.fullscreenOnPlay
        };
        try {
            chrome.storage.local.set({ mediaSettings: settings }, () => {
                if (chrome.runtime.lastError) {
                    throw new Error(chrome.runtime.lastError);
                }
                console.log('Settings saved.');
            });
        } catch (error) {
            console.error('Error saving settings:', error);
            showMessage('Error saving settings.', 'error');
        }
    }

    /**
     * Unloads media from the specified type.
     * @param {string} mediaType - 'music' or 'video'.
     */
    function unloadMedia(mediaType) {
        if (state[mediaType]) {
            if (state[mediaType].type === 'file') {
                if (state[mediaType].element.src) {
                    URL.revokeObjectURL(state[mediaType].element.src);
                    state[mediaType].element.src = '';
                    state[mediaType].element.remove();
                }
            } else if (state[mediaType].type === 'youtube') {
                const iframe = state[mediaType].element;
                iframe.src = ''; // Reset iframe src to stop the media
            } else if (state[mediaType].type === 'vimeo') {
                const player = state[mediaType].element;
                player.unload().catch(error => {
                    console.error(`Error unloading Vimeo ${mediaType}:`, error);
                });
            }
            state[mediaType] = null;
        }
    }

    // === Playback Controls ===

    /**
     * Enables or disables playback controls based on media loading state.
     */
    function checkReadyToPlay() {
        // Enable Play button only when at least one of audio or video is loaded
        const readyAudio = state.music 
            && (state.music.type === 'file' 
                || state.music.type === 'youtube' 
                || state.music.type === 'vimeo');
        const readyVideo = state.video 
            && (state.video.type === 'file' 
                || state.video.type === 'youtube' 
                || state.video.type === 'vimeo');
        const ready = readyAudio || readyVideo;

        elements.controls.playButton.disabled = !ready;
        elements.controls.pauseResumeButton.disabled = !ready;
        elements.controls.playStartButton.disabled = !ready;
    }

    /**
     * Enters fullscreen mode for the specified element.
     * @param {HTMLElement} element - The element to enter fullscreen.
     */
    function enterFullscreen(element) {
        if (element && element.element && element.element.requestFullscreen) {
            element.element.requestFullscreen().then(() => {
                showMessage('Entered fullscreen mode.', 'success');
            }).catch(err => {
                console.error(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
                showMessage('Failed to enter fullscreen mode.', 'error');
            });
        } else if (element && element.requestFullscreen) {
            element.requestFullscreen().then(() => {
                showMessage('Entered fullscreen mode.', 'success');
            }).catch(err => {
                console.error(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
                showMessage('Failed to enter fullscreen mode.', 'error');
            });
        } else {
            showMessage('Fullscreen not supported on this element.', 'error');
        }
    }

    // === New Utility Functions ===

    /**
     * Validates whether the URL is a valid YouTube or Vimeo URL.
     * @param {string} url - The URL to validate.
     * @returns {boolean} True if valid, else false.
     */
    function isValidMediaURL(url) {
        try {
            const parsedUrl = new URL(url);
            const hostname = parsedUrl.hostname.toLowerCase();
            const pathname = parsedUrl.pathname;

            // YouTube RegEx Patterns
            const youtubeRegex = /^(?:\/watch\/?|\/embed\/|\/v\/)?([a-zA-Z0-9_-]{11})$/;
            // Vimeo RegEx Patterns
            const vimeoRegex = /^\/(?:video\/)?(\d+)$/;

            if (hostname.includes('youtube.com') || hostname === 'youtu.be') {
                // Extract YouTube video ID
                let videoId = '';
                if (hostname === 'youtu.be') {
                    videoId = pathname.slice(1);
                } else {
                    videoId = parsedUrl.searchParams.get('v') || '';
                }
                return youtubeRegex.test(`/${videoId}`);
            } else if (hostname.includes('vimeo.com')) {
                // Extract Vimeo video ID
                const match = pathname.match(vimeoRegex);
                return match && match[1].length > 0;
            }

            return false;
        } catch (e) {
            return false;
        }
    }

    /**
     * Extracts media information from the URL.
     * @param {string} url - The media URL.
     * @returns {Object|null} An object with platform and id, or null if invalid.
     */
    function extractMediaInfo(url) {
        try {
            const parsedUrl = new URL(url);
            const hostname = parsedUrl.hostname.toLowerCase();
            const pathname = parsedUrl.pathname;

            // YouTube Patterns
            if (hostname.includes('youtube.com') 
                || hostname === 'youtu.be') {
                let videoId = '';
                if (hostname === 'youtu.be') {
                    videoId = pathname.slice(1);
                } else {
                    videoId = parsedUrl.searchParams.get('v') || '';
                }

                // Validate videoId length
                if (videoId.length === 11) {
                    return { platform: 'youtube', id: videoId };
                }
            }

            // Vimeo Patterns
            if (hostname.includes('vimeo.com')) {
                const vimeoMatch = pathname.match(/^\/(?:video\/)?(\d+)$/);
                if (vimeoMatch && vimeoMatch[1]) {
                    return { platform: 'vimeo', id: vimeoMatch[1] };
                }
            }

            return null;
        } catch (e) {
            return null;
        }
    }
});
5. styles.css
No changes are needed here. Ensure it matches the following or includes the previous updates:


/* General Styles */
body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    margin: 0;
    padding: 0;
}

.container {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 20px;
    max-width: 1000px; /* Increased max-width for larger displays */
    margin: 0 auto;
}

.section {
    width: 100%;
    margin-bottom: 20px;
    background-color: #fff;
    padding: 15px;
    border-radius: 8px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

/* Header with Settings Button and Main Title */
.header {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center; /* Center the content */
    margin-bottom: 20px;
    position: relative;
}

.settings-button {
    position: absolute;
    left: 0;
    background: #fff;
    border: 1px solid #ccc;
    border-radius: 5px;
    padding: 5px;
    cursor: pointer;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.3s ease, border-color 0.3s ease;
}

.settings-button:hover {
    background-color: #f0f0f0;
    border-color: #999;
}

.settings-icon {
    width: 20px;
    height: 20px;
}

.main-title {
    font-size: 2.5em; /* Increased font size for better visibility */
    font-weight: bold;
    margin: 0;
    opacity: 0;
    animation: fadeInShake 5s forwards;
}

@keyframes fadeInShake {
    0% {
        opacity: 0;
        transform: translateX(0);
        color: #FF0000; /* Red */
    }
    10% {
        opacity: 0.2;
        transform: translateX(-10px);
        color: #FF7F00; /* Orange */
    }
    20% {
        opacity: 0.4;
        transform: translateX(10px);
        color: #FFFF00; /* Yellow */
    }
    30% {
        opacity: 0.6;
        transform: translateX(-10px);
        color: #00FF00; /* Green */
    }
    40% {
        opacity: 0.7;
        transform: translateX(10px);
        color: #0000FF; /* Blue */
    }
    50% {
        opacity: 0.8;
        transform: translateX(-10px);
        color: #4B0082; /* Indigo */
    }
    60% {
        opacity: 0.85;
        transform: translateX(10px);
        color: #8B00FF; /* Violet */
    }
    70% {
        opacity: 0.9;
        transform: translateX(-10px);
        color: #FF00FF; /* Magenta */
    }
    80% {
        opacity: 0.95;
        transform: translateX(10px);
        color: #000000; /* Black */
    }
    100% {
        opacity: 1;
        transform: translateX(0);
        color: #000000; /* Black */
    }
}

/* Controls */
.controls {
    display: flex;
    gap: 10px;
    margin-bottom: 20px;
}

.controls button {
    padding: 12px 24px; /* Increased padding for better accessibility */
    cursor: pointer;
    border: none;
    border-radius: 5px;
    background-color: #4285f4;
    color: #fff;
    transition: background-color 0.3s ease;
    font-size: 1em;
}

.controls button:disabled {
    background-color: #a0c3ff;
    cursor: not-allowed;
}

.controls button:hover:not(:disabled) {
    background-color: #357ae8;
}

/* Modal Styles */
.modal[hidden] {
    display: none;
}

.modal {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.5);
    display: flex; /* Visible when not hidden */
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

.modal-content {
    background-color: #fff;
    padding: 20px 30px;
    border-radius: 8px;
    width: 90%;
    max-width: 500px; /* Increased max-width for better layout */
    position: relative;
}

.close-button {
    position: absolute;
    top: 10px;
    right: 15px;
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
}

.modal-content h2 {
    margin-top: 0;
}

/* Form Elements */
fieldset {
    border: none;
    padding: 0;
}

fieldset label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold;
}

fieldset input[type="text"],
fieldset input[type="number"],
fieldset input[type="file"] {
    width: 100%;
    padding: 10px; /* Increased padding for better usability */
    margin-bottom: 15px;
    box-sizing: border-box;
    border: 1px solid #ccc;
    border-radius: 4px;
}

fieldset .load-button {
    width: 100%;
    padding: 12px;
    background-color: #34a853;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s ease;
    font-size: 1em;
}

fieldset .load-button:hover {
    background-color: #2c8e46;
}

/* Player Containers */
.player-container {
    margin-top: 10px;
    width: 100%;
    max-width: 100%;
    min-height: 100px; /* Increased minimum height */
    box-sizing: border-box;
    overflow: hidden; /* Prevent overflow */
}

/* Responsive Video and Audio Elements */
.player-container video,
.player-container iframe {
    width: 100%;
    height: 720px; /* Fixed height for consistency */
    border-radius: 8px;
    /* Ensure the iframe fills the container */
    display: block;
}

/* Messages */
.message-container {
    margin-top: 20px;
    width: 100%;
}

.message {
    padding: 12px;
    border-radius: 5px;
    margin-bottom: 10px;
    color: #fff;
    font-size: 1em;
}

.message.success {
    background-color: #4caf50;
}

.message.error {
    background-color: #f44336;
}

.message.info {
    background-color: #2196f3;
}

/* Loader */
.loader {
    border: 8px solid #f3f3f3; /* Light grey */
    border-top: 8px solid #4285f4; /* Blue */
    border-radius: 50%;
    width: 60px; /* Increased size for better visibility */
    height: 60px; /* Increased size for better visibility */
    animation: spin 1s linear infinite;
    margin: 0 auto;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

/* Responsive Design */
@media (max-width: 800px) {
    .container {
        padding: 15px;
    }

    .modal-content {
        padding: 15px 20px;
    }

    .controls {
        flex-direction: column;
        width: 100%;
    }

    .controls button {
        width: 100%;
    }

    .settings-button {
        width: 35px;
        height: 35px;
    }

    .settings-icon {
        width: 18px;
        height: 18px;
    }

    .main-title {
        font-size: 2em;
    }

    .player-container video,
    .player-container iframe {
        height: 480px; /* Adjusted height for smaller screens */
    }

    .loader {
        width: 50px; /* Adjusted size for smaller screens */
        height: 50px; /* Adjusted size for smaller screens */
    }
}

@media (max-width: 500px) {
    .container {
        padding: 10px;
    }

    .controls button {
        padding: 10px;
        font-size: 0.9em;
    }

    .modal-content {
        padding: 10px 15px;
    }

    .main-title {
        font-size: 1.8em;
    }

    .player-container video,
    .player-container iframe {
        height: 360px; /* Further adjusted height for very small screens */
    }

    .loader {
        width: 40px; /* Further adjusted size for very small screens */
        height: 40px; /* Further adjusted size for very small screens */
    }
}
6. lib/player.js
Ensure that you're using the correct version of the Vimeo Player API. It should be the UMD (Universal Module Definition) version, not an ES module.

Steps to Include Vimeo's Player API Locally:

Download the Vimeo Player API:
Visit the Vimeo Player.js GitHub Repository or directly download the latest version of player.js from Vimeo's Official Source.
Add to Extension:
Create a lib directory inside your extension folder: myext/lib/.
Place the downloaded player.js inside this folder: myext/lib/player.js.
Ensure Correct Pathing in dashboard.html:
The script reference should point to the local player.js:

<script src="lib/player.js"></script>
Important:

Do Not Modify player.js: Ensure that player.js remains as provided by Vimeo without any additional modifications or import statements.
No type="module" Needed: Since player.js is a UMD script, it should be included without the type="module" attribute.
Final Directory Structure
Ensure your extension's directory (myext/) has the following structure:


myext/
├── background.js
├── dashboard.html
├── dashboard.js
├── styles.css
├── lib/
│   └── player.js
├── icons/
│   ├── icon16.png
│   ├── icon48.png
│   ├── icon128.png
│   └── settings.svg
└── manifest.json
Reload and Test the Extension
Reload the Extension:
Open Chrome and navigate to chrome://extensions/.
Enable "Developer mode" if it’s not already enabled (toggle in the top-right corner).
Click on the "Reload" button for your "Media Loader" extension to apply the changes.
Test Functionality:
Loading Videos:
Enter a valid Vimeo URL in the "Video URL" field or select a local video file.
Click the "Load" button.
The video should appear in the player container with increased size and start buffering.
Playback Controls:
Click "Play" to start playback.
Use "Pause" to pause and "Resume" to continue.
Click "Play from Start" to rewind to the specified start time and play.
Settings:
Click the Settings button (gear icon) to toggle "Full Screen on Play".
When enabled, clicking "Play" should trigger fullscreen mode for the media.
Verify in Developer Console:
Open Chrome's Developer Console (Ctrl+Shift+I or Cmd+Option+I on Mac) to check for any runtime errors during operation.
Troubleshooting
CSP Errors:
Ensure that manifest.json does not include any external script sources outside of 'self'.
Verify that lib/player.js is correctly placed and referenced in dashboard.html.
Playback Controls Not Working:
Ensure that lib/player.js is the correct UMD version of the Vimeo Player API.
Confirm that Vimeo URLs are valid and properly formatted.
Check for any errors in the Developer Console.
Video Not Buffering:
Ensure that the Vimeo URLs are correct and that the player is initialized without autoplay parameters.
Verify network connectivity and that Vimeo isn't blocking the request.
Other Errors:
Review the Developer Console for specific error messages and address them accordingly.
Ensure that all file paths are correct and that all required resources (like icons) are present in their respective directories.
Additional Recommendations
Maintain Accessibility:
Ensure all interactive elements are keyboard-navigable.
Use ARIA attributes effectively to aid screen readers.
Enhance User Experience:
Provide clear error messages and feedback.
Optimize loading times by minimizing large file sizes or implementing lazy loading where appropriate.
Security Best Practices:
Validate and sanitize all user inputs.
Avoid exposing any sensitive information through messages or error logs.
Future Enhancements:
Consider integrating YouTube's Player API similarly if you plan to support YouTube videos with enhanced controls.
Implement additional settings or features based on user feedback.
By following the above steps and ensuring that your scripts are correctly loaded without misusing import statements, your Chrome extension should function as expected. The error regarding the import statement should no longer appear, and Vimeo videos should load at the desired size, buffer upon loading, and play correctly when the Play button is pressed.

If you continue to experience issues or have further questions, feel free to ask!    can a vimro video start buffering without playing when load video button is pressed and a vimeo url is used?