i only need the complete updated files.

{
  "manifest_version": 3,
  "name": "Media Loader",
  "version": "1.4",
  "description": "Load and play music and videos from YouTube and Vimeo",
  "permissions": ["storage", "tabs"],
  "host_permissions": [
    "https://www.youtube.com/*",
    "https://youtu.be/*",
    "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'; frame-src https://www.youtube.com https://youtu.be https://player.vimeo.com"
  },
  "web_accessible_resources": [
    {
      "resources": ["lib/player.js"],
      "matches": ["<all_urls>"]
    },
    {
      "resources": ["youtube-sandbox.html"],
      "matches": ["<all_urls>"]
    }
  ]
}

// background.js

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);
                }
            });
        }
    });
});

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Media Loader Dashboard</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <main class="container">
        <!-- Header with Settings Button and Title -->
        <header class="header">
            <button id="settings-button" class="settings-button" aria-label="Open Settings">
                <img src="icons/settings.svg" alt="Settings" class="settings-icon">
            </button>
            <h1 class="main-title">SyncWave</h1>
        </header>

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

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

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

                <button type="button" id="load-music" class="load-button">Load Audio</button>
            </fieldset>
            <div id="music-player-container" class="player-container" aria-live="polite"></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" aria-label="Enter YouTube or Vimeo Video URL">

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

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

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

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

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

        <!-- Settings Modal -->
        <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>

    <!-- YouTube Sandbox IFrame -->
    <iframe id="youtube-sandbox-iframe" src="youtube-sandbox.html" sandbox="allow-scripts" style="display:none;"></iframe>

    <!-- Local Vimeo Player API -->
    <script src="lib/player.js"></script>

    <!-- Your Dashboard JS -->
    <script src="dashboard.js"></script>
</body>
</html>

// dashboard.js

"use strict";

let youtubePlayers = {
    music: null,
    video: null
};

// Function to send messages to the YouTube sandbox iframe
function sendMessageToYouTubeSandbox(message) {
    const iframe = document.getElementById('youtube-sandbox-iframe');
    iframe.contentWindow.postMessage(message, '*');
}

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'),
            pauseButton: document.getElementById('pause-button'),
            resumeButton: document.getElementById('resume-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')
        },
        youtubeSandbox: document.getElementById('youtube-sandbox-iframe')
    };

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

    // === Utility Functions ===

    /**
     * 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.pauseButton.addEventListener('click', handlePause);
    elements.controls.resumeButton.addEventListener('click', handleResume);

    // 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();
    });

    // Listen for messages from YouTube Sandbox
    window.addEventListener('message', (event) => {
        // For security, you can check event.origin here if necessary
        const data = event.data;
        if (data.type === 'playerReady') {
            // YouTube Player is ready
            showMessage(`YouTube ${capitalize(data.mediaType)} loaded and ready.`, 'success');
            hideLoading(elements[data.mediaType].playerContainer);
        } else if (data.type === 'playerError') {
            showMessage(`Error loading YouTube ${capitalize(data.mediaType)}.`, 'error');
            hideLoading(elements[data.mediaType].playerContainer);
        }
    });

    // === 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) {
            // 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';

            // Listen for metadata to set start time
            audioElement.addEventListener('loadedmetadata', () => {
                if (start > 0 && audioElement.duration > start) {
                    audioElement.currentTime = start;
                }
            });

            elements.music.playerContainer.innerHTML = '';
            elements.music.playerContainer.appendChild(audioElement);

            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') {
                    embedYouTubePlayer(mediaInfo.id, start, 'music');
                } else if (mediaInfo.platform === 'vimeo') {
                    embedVimeoPlayer(mediaInfo.id, start, 'music');
                }
                // Loading will be handled inside embed functions
            } 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) {
            // 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';

            // Listen for metadata to set start time
            videoElement.addEventListener('loadedmetadata', () => {
                if (start > 0 && videoElement.duration > start) {
                    videoElement.currentTime = start;
                }
            });

            elements.video.playerContainer.innerHTML = '';
            elements.video.playerContainer.appendChild(videoElement);

            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') {
                    embedYouTubePlayer(mediaInfo.id, start, 'video');
                } else if (mediaInfo.platform === 'vimeo') {
                    embedVimeoPlayer(mediaInfo.id, start, 'video');
                }
                // Loading will be handled inside embed functions
            } 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');
                });
            } else if (state.music.type === 'youtube') {
                sendMessageToYouTubeSandbox({ type: 'play' });
            }
        }

        // 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');
                });
            } else if (state.video.type === 'youtube') {
                sendMessageToYouTubeSandbox({ type: 'play' });
            }
        }

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

    // Pause Handler
    function handlePause() {
        if (state.isPaused) return;

        // 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');
                });
            } else if (state.music.type === 'youtube') {
                sendMessageToYouTubeSandbox({ type: 'pause' });
            }
        }

        // 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');
                });
            } else if (state.video.type === 'youtube') {
                sendMessageToYouTubeSandbox({ type: 'pause' });
            }
        }

        state.isPaused = true;
        elements.controls.resumeButton.disabled = false;
        elements.controls.pauseButton.disabled = true;
        elements.controls.pauseButton.textContent = 'Paused';
        showMessage('Playback paused.', 'info');
    }

    // Resume Handler
    function handleResume() {
        if (!state.isPaused) return;

        // Resume 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 resuming Vimeo audio:', error);
                    showMessage('Failed to resume Vimeo audio.', 'error');
                });
            } else if (state.music.type === 'youtube') {
                sendMessageToYouTubeSandbox({ type: 'play' });
            }
        }

        // Resume 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 resuming Vimeo video:', error);
                    showMessage('Failed to resume Vimeo video.', 'error');
                });
            } else if (state.video.type === 'youtube') {
                sendMessageToYouTubeSandbox({ type: 'play' });
            }
        }

        state.isPaused = false;
        elements.controls.resumeButton.disabled = true;
        elements.controls.pauseButton.disabled = false;
        elements.controls.pauseButton.textContent = 'Pause';
        showMessage('Playback resumed.', '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 by sending an initialization message to the sandboxed iframe.
     * @param {string} videoId - The YouTube video ID.
     * @param {number} start - The start time in seconds.
     * @param {string} mediaType - 'music' or 'video'.
     */
    function embedYouTubePlayer(videoId, start, mediaType) {
        const container = elements[mediaType].playerContainer;
        container.innerHTML = ''; // Clear previous content

        showLoading(container);

        // Send initialization message to sandbox
        sendMessageToYouTubeSandbox({
            type: 'init',
            videoId: videoId,
            startTime: start,
            mediaType: mediaType
        });

        state[mediaType] = {
            type: 'youtube',
            element: null, // Will be set when sandbox responds
            start: start
        };
    }

    /**
     * Embeds a Vimeo video using the Player API.
     * @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&autoplay=0&start=${start}`;
        iframe.src = src;
        iframe.width = '640';
        iframe.height = '360';
        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: 640,
            muted: true,
            autoplay: false,
            start: start
        });

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

        // Buffering: play briefly, then pause and set start time
        bufferAndPause('vimeo', mediaType, start);

        hideLoading(container);
    }

    /**
     * Implements the buffering process: plays briefly, then pauses and sets to start time.
     * @param {string} platform - 'youtube' or 'vimeo'.
     * @param {string} mediaType - 'music' or 'video'.
     * @param {number} startTime - The start time in seconds.
     */
    function bufferAndPause(platform, mediaType, startTime) {
        if (platform === 'vimeo') {
            const player = state[mediaType].element;
            player.play().then(() => {
                // Wait for at least 125ms
                setTimeout(() => {
                    player.pause().then(() => {
                        player.setCurrentTime(startTime).then(() => {
                            showMessage(`Vimeo ${capitalize(mediaType)} buffered and set to ${startTime} seconds.`, 'success');
                        }).catch(error => {
                            console.error(`Error setting start time for Vimeo ${mediaType}:`, error);
                            showMessage(`Failed to set start time for Vimeo ${mediaType}.`, 'error');
                        });
                    }).catch(error => {
                        console.error(`Error pausing Vimeo ${mediaType}:`, error);
                        showMessage(`Failed to pause Vimeo ${mediaType}.`, 'error');
                    });
                }, 125);
            }).catch(error => {
                console.error(`Error playing Vimeo ${mediaType}:`, error);
                showMessage(`Failed to play Vimeo ${mediaType}.`, 'error');
            });
        }
    }

    // === Settings Persistence ===

    /**
     * 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') {
                // No direct access to destroy YouTube player from main
                // Send a message to sandbox to destroy player if needed
                // For simplicity, reload the sandbox iframe
                const iframe = document.getElementById('youtube-sandbox-iframe');
                iframe.src = iframe.src;
            } 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 buttons 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.pauseButton.disabled = !ready;
        elements.controls.resumeButton.disabled = true; // Start with Resume disabled
    }

    /**
     * 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(?:\?v=|v\/)|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;
        }
    }

    /**
     * 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);
    }

    /**
     * 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 if (element && element.parentElement && element.parentElement.requestFullscreen) {
            // Fallback to parent element
            element.parentElement.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');
        }
    }

    /**
     * Sends a message to the YouTube sandbox iframe.
     * @param {Object} message - The message object to send.
     */
    function sendMessageToYouTubeSandbox(message) {
        sendMessageToYouTubeSandboxFrame(message);
    }

    /**
     * Directly sends a message to the YouTube sandbox iframe.
     * @param {Object} message - The message object to send.
     */
    function sendMessageToYouTubeSandboxFrame(message) {
        const iframe = document.getElementById('youtube-sandbox-iframe');
        iframe.contentWindow.postMessage(message, '*');
    }

    // === YouTube Sandbox Communication Handlers ===

    // No additional code here as messaging is handled via event listeners above

    // === Initialize ready state ===
    checkReadyToPlay();

    // Ensure buttons are correctly enabled/disabled on load
    if (state.music || state.video) {
        elements.controls.playButton.disabled = false;
    }
});

/* styles.css */

/* 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: 1200px; /* Increased max-width for larger displays */
    margin: 0 auto;
}

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

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

.settings-button {
    position: absolute;
    left: 0;
    background: #fff;
    border: 1px solid #ccc;
    border-radius: 5px;
    padding: 8px;
    cursor: pointer;
    width: 50px; /* Increased size for better touch targets */
    height: 50px; /* Increased size for better touch targets */
    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: 24px;
    height: 24px;
}

/* Main Title with Animation */
.main-title {
    font-size: 3em; /* Increased font size for better visibility */
    font-weight: bold;
    margin: 0;
    animation: titleAnimation 3s infinite;
}

/* Title Animation Keyframes */
@keyframes titleAnimation {
    0% { color: #4285f4; transform: scale(1); }
    50% { color: #ea4335; transform: scale(1.05); }
    100% { color: #4285f4; transform: scale(1); }
}

/* Section Headers */
.section > fieldset > legend {
    font-size: 1.5em;
    font-weight: bold;
    margin-bottom: 15px;
}

/* Controls */
.controls {
    display: flex;
    gap: 15px; /* Increased gap for better spacing */
    margin-bottom: 30px; /* Increased margin for better spacing */
}

.controls button {
    padding: 15px 30px; /* Increased padding for better accessibility */
    cursor: pointer;
    border: none;
    border-radius: 8px;
    background-color: #4285f4;
    color: #fff;
    transition: background-color 0.3s ease;
    font-size: 1.2em; /* Increased font size for better readability */
}

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

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

/* Play Button Specific Styles */
.play-button {
    background-color: #34a853; /* Green */
}

.play-button:hover:not(:disabled) {
    background-color: #2c8e46;
}

/* Pause Button Specific Styles */
.pause-button {
    background-color: #fbbc05; /* Yellow */
}

.pause-button:hover:not(:disabled) {
    background-color: #e0a800;
}

/* Resume Button Specific Styles */
.resume-button {
    background-color: #ea4335; /* Red */
}

.resume-button:hover:not(:disabled) {
    background-color: #c33c2c;
}

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

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

.modal-content {
    background-color: #fff;
    padding: 25px 35px; /* Increased padding for better spacing */
    border-radius: 10px; /* More pronounced rounding */
    width: 90%;
    max-width: 600px; /* Increased max-width for better layout */
    position: relative;
    box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}

.close-button {
    position: absolute;
    top: 15px;
    right: 20px;
    background: none;
    border: none;
    font-size: 28px;
    cursor: pointer;
    color: #333;
}

.modal-content h2 {
    margin-top: 0;
    font-size: 2em; /* Increased font size for better visibility */
}

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

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

fieldset input[type="text"],
fieldset input[type="number"],
fieldset input[type="file"] {
    width: 100%;
    padding: 12px; /* Increased padding for better usability */
    margin-bottom: 20px; /* Increased margin for better spacing */
    box-sizing: border-box;
    border: 1px solid #ccc;
    border-radius: 6px;
    font-size: 1em; /* Increased font size for better readability */
}

fieldset .load-button {
    width: 100%;
    padding: 15px;
    background-color: #4285f4; /* Blue */
    color: #fff;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: background-color 0.3s ease;
    font-size: 1.2em; /* Increased font size for better readability */
}

fieldset .load-button:hover {
    background-color: #357ae8;
}

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

/* Responsive Video and Audio Elements */
.player-container video,
.player-container iframe {
    width: 100%;
    height: 360px; /* Fixed height for larger displays */
    border-radius: 8px;
    display: block;
}

.player-container audio {
    width: 100%;
    height: auto;
    border-radius: 5px;
    margin-top: 10px; /* Increased margin for better spacing */
}

/* Messages */
.message-container {
    position: fixed;
    top: 20px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1001; /* Above other content */
    width: 90%;
    max-width: 700px;
}

.message {
    padding: 15px 25px;
    border-radius: 8px;
    margin-bottom: 15px;
    color: #fff;
    font-size: 1.1em;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    opacity: 0.95;
    animation: fadeInOut 6s forwards;
}

.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: 80px; /* Increased size for better visibility */
    height: 80px; /* Increased size for better visibility */
    animation: spin 1s linear infinite;
    margin: 0 auto;
}

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

/* Fade In and Out for Messages */
@keyframes fadeInOut {
    0% { opacity: 0; transform: translateY(-20px); }
    10% { opacity: 0.95; transform: translateY(0); }
    90% { opacity: 0.95; transform: translateY(0); }
    100% { opacity: 0; transform: translateY(-20px); }
}

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

    .controls {
        flex-direction: column;
        gap: 10px;
    }

    .controls button {
        width: 100%;
    }

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

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

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

@media (max-width: 700px) {
    .section {
        padding: 15px;
    }

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

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

    .player-container video,
    .player-container iframe {
        height: 220px; /* Further adjusted height for even smaller screens */
    }

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

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

    .controls button {
        padding: 12px;
        font-size: 1em;
    }

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

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

    .player-container video,
    .player-container iframe {
        height: 180px; /* 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 */
    }
}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>YouTube Sandbox</title>
</head>
<body>
    <!-- YouTube Player Container -->
    <div id="youtube-player"></div>

    <!-- YouTube IFrame API -->
    <script src="https://www.youtube.com/iframe_api"></script>
    <script>
        let player;
        let mediaType = ''; // 'music' or 'video'

        // Function called by YouTube API once it's ready
        function onYouTubeIframeAPIReady() {
            // Player will be created upon receiving initialization message
        }

        // Listen for messages from the parent
        window.addEventListener('message', (event) => {
            // For security, you can check event.origin here if necessary
            const data = event.data;
            if (data.type === 'init') {
                mediaType = data.mediaType; // 'music' or 'video'
                player = new YT.Player('youtube-player', {
                    height: '360',
                    width: '640',
                    videoId: data.videoId,
                    playerVars: {
                        'autoplay': 0,
                        'controls': 1,
                        'start': data.startTime,
                        'mute': 1,
                        'rel': 0,
                        'disablekb': 1,
                        'modestbranding': 1,
                        'iv_load_policy': 3,
                        'fs': 1
                    },
                    events: {
                        'onReady': () => {
                            // Notify the parent that the player is ready
                            window.parent.postMessage({
                                type: 'playerReady',
                                mediaType: mediaType
                            }, '*');
                        },
                        'onError': (error) => {
                            window.parent.postMessage({
                                type: 'playerError',
                                mediaType: mediaType,
                                error: error
                            }, '*');
                        }
                    }
                });
            } else if (data.type === 'play') {
                if (player && typeof player.playVideo === 'function') {
                    player.playVideo();
                }
            } else if (data.type === 'pause') {
                if (player && typeof player.pauseVideo === 'function') {
                    player.pauseVideo();
                }
            } else if (data.type === 'seek') {
                if (player && typeof player.seekTo === 'function') {
                    player.seekTo(data.time, true);
                }
            }
        });
    </script>
</body>
</html>

Errors
Refused to load the script 'https://www.youtube.com/iframe_api' because it violates the following Content Security Policy directive: "script-src 'self'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.
Context
dashboard.html
Stack Trace
youtube-sandbox.html:0 (anonymous function)