{
  "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'"
  }
}

// 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">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <main class="container">
        <!-- Settings Header -->
        <header class="settings-container">
            <button id="settings-button" class="settings-button" title="Settings" aria-label="Open Settings">
                <img src="icons/settings.svg" alt="" class="settings-icon" aria-hidden="true">
            </button>
        </header>

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

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

                <label for="music-file">Upload Music 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 Music</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>
    </main>

    <script src="dashboard.js"></script>
</body>
</html>

// dashboard.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 | iframe Element, start: Number }
        video: null, // { type: 'file' | 'youtube' | 'vimeo', element: HTMLVideoElement | iframe Element, start: Number }
        isPaused: false,
        fullscreenOnPlay: false
    };

    // === 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('Music 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';
            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') {
                    embedYouTubeVideo('music-player-container', mediaInfo.id, start, 'music');
                } else if (mediaInfo.platform === 'vimeo') {
                    embedVimeoVideo('music-player-container', mediaInfo.id, start, 'music');
                }
                showMessage(`Loaded ${capitalize(mediaInfo.platform)} music.`, '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 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';
            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') {
                    embedYouTubeVideo('video-player-container', mediaInfo.id, start, 'video');
                } else if (mediaInfo.platform === 'vimeo') {
                    embedVimeoVideo('video-player-container', 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 file.', 'error');
            hideLoading(elements.video.playerContainer);
        }

        checkReadyToPlay();
        saveSettings();
    }

    // Play Handler
    function handlePlay() {
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.play();
            } else if (state.music.type === 'youtube' || state.music.type === 'vimeo') {
                // For iframe embeds, play by setting autoplay parameter
                const iframe = state.music.element;
                const src = new URL(iframe.src);
                src.searchParams.set('autoplay', '1');
                iframe.src = src.toString();
            }
        }

        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.play();
            } else if (state.video.type === 'youtube' || state.video.type === 'vimeo') {
                const iframe = state.video.element;
                const src = new URL(iframe.src);
                src.searchParams.set('autoplay', '1');
                iframe.src = src.toString();
            }
        }

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

        if (state.fullscreenOnPlay) {
            enterFullscreen();
        }
    }

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

    // Pause Media
    function pauseMedia() {
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.pause();
            } else if (state.music.type === 'youtube' || state.music.type === 'vimeo') {
                // Pausing iframe embed without API by removing autoplay
                const iframe = state.music.element;
                const src = new URL(iframe.src);
                src.searchParams.set('autoplay', '0');
                iframe.src = src.toString();
            }
        }

        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.pause();
            } else if (state.video.type === 'youtube' || state.video.type === 'vimeo') {
                const iframe = state.video.element;
                const src = new URL(iframe.src);
                src.searchParams.set('autoplay', '0');
                iframe.src = src.toString();
            }
        }

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

    // Resume Media
    function resumeMedia() {
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.play();
            } else if (state.music.type === 'youtube' || state.music.type === 'vimeo') {
                const iframe = state.music.element;
                const src = new URL(iframe.src);
                src.searchParams.set('autoplay', '1');
                iframe.src = src.toString();
            }
        }

        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.play();
            } else if (state.video.type === 'youtube' || state.video.type === 'vimeo') {
                const iframe = state.video.element;
                const src = new URL(iframe.src);
                src.searchParams.set('autoplay', '1');
                iframe.src = src.toString();
            }
        }

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

    // Play From Start Handler
    function handlePlayFromStart() {
        if (state.music) {
            if (state.music.type === 'file') {
                state.music.element.currentTime = state.music.start;
                state.music.element.play();
            } else if (state.music.type === 'youtube' || state.music.type === 'vimeo') {
                const iframe = state.music.element;
                const src = new URL(iframe.src);
                src.searchParams.set('start', formatTime(state.music.start));
                src.searchParams.set('autoplay', '1');
                iframe.src = src.toString();
            }
        }

        if (state.video) {
            if (state.video.type === 'file') {
                state.video.element.currentTime = state.video.start;
                state.video.element.play();
            } else if (state.video.type === 'youtube' || state.video.type === 'vimeo') {
                const iframe = state.video.element;
                const src = new URL(iframe.src);
                src.searchParams.set('start', formatTime(state.video.start));
                src.searchParams.set('autoplay', '1');
                iframe.src = src.toString();
            }
        }

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

        if (state.fullscreenOnPlay) {
            enterFullscreen();
        }
    }

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

    // Focus Trap Implementation
    function trapFocus(element) {
        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 trapTabKey(e) {
        // Placeholder to prevent errors if called outside trapFocus
    }

    function removeTrapFocus() {
        elements.settings.modal.removeEventListener('keydown', trapTabKey);
    }

    // === Utility Functions ===

    // Checks if the URL is a valid YouTube or Vimeo URL
    function isValidMediaURL(url) {
        const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+$/;
        const vimeoRegex = /^(https?:\/\/)?(www\.)?vimeo\.com\/.+$/;
        return youtubeRegex.test(url) || vimeoRegex.test(url);
    }

    // Formats seconds into 'XmYs'
    function formatTime(seconds) {
        if (isNaN(seconds) || seconds < 0) return '';
        const minutes = Math.floor(seconds / 60);
        const remainingSeconds = seconds % 60;
        return `${minutes}m${remainingSeconds}s`;
    }

    // Extract Media Information from URL
    function extractMediaInfo(url) {
        try {
            const youtubeRegex = /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^\&\?\/]+)/;
            const youtubeShortRegex = /(?:https?:\/\/)?youtu\.be\/([^\&\?\/]+)/;
            const vimeoRegex = /(?:https?:\/\/)?(?:www\.)?vimeo\.com\/(\d+)/;

            let match = url.match(youtubeRegex);
            if (match && match[1]) {
                return { platform: 'youtube', id: match[1] };
            }

            match = url.match(youtubeShortRegex);
            if (match && match[1]) {
                return { platform: 'youtube', id: match[1] };
            }

            match = url.match(vimeoRegex);
            if (match && match[1]) {
                return { platform: 'vimeo', id: match[1] };
            }

            return null;
        } catch (error) {
            console.error('Error extracting media info:', error);
            return null;
        }
    }

    // Capitalize First Letter
    function capitalize(text) {
        if (!text) return '';
        return text.charAt(0).toUpperCase() + text.slice(1);
    }

    // Show Messages to User
    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);
    }

    // Show Loading Indicator
    function showLoading(container) {
        container.innerHTML = '';
        const loader = document.createElement('div');
        loader.classList.add('loader'); // Define loader styles in CSS
        container.appendChild(loader);
    }

    function hideLoading(container) {
        const loader = container.querySelector('.loader');
        if (loader) {
            container.removeChild(loader);
        }
    }

    // Check if Playback Buttons Should be Enabled
    function checkReadyToPlay() {
        const ready = state.music || state.video;
        elements.controls.playButton.disabled = !ready;
        elements.controls.pauseResumeButton.disabled = !ready;
        elements.controls.playStartButton.disabled = !ready;
    }

    // Enter Fullscreen Mode
    function enterFullscreen() {
        let targetElement = null;
        if (state.video && state.video.element) {
            // If it's an iframe (YouTube/Vimeo), request fullscreen on the container
            targetElement = (state.video.type === 'file') ? state.video.element : document.getElementById('video-player-container');
        } else if (state.music && state.music.element) {
            targetElement = (state.music.type === 'file') ? state.music.element : document.getElementById('music-player-container');
        }

        if (targetElement && targetElement.requestFullscreen) {
            targetElement.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');
        }
    }

    // === Media Embedding Functions ===

    // Embed YouTube Video without API
    function embedYouTubeVideo(containerId, videoId, start, mediaType) {
        const iframe = document.createElement('iframe');
        iframe.width = '100%';
        iframe.height = '360';
        iframe.src = `https://www.youtube.com/embed/${videoId}?start=${start}&autoplay=0&controls=1&rel=0`;
        iframe.frameBorder = '0';
        iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture';
        iframe.allowFullscreen = true;
        iframe.id = `iframe-${mediaType}-${videoId}`;

        elements[mediaType].playerContainer.innerHTML = '';
        elements[mediaType].playerContainer.appendChild(iframe);

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

    // Embed Vimeo Video without API
    function embedVimeoVideo(containerId, videoId, start, mediaType) {
        const formattedTime = formatTime(start);
        const iframe = document.createElement('iframe');
        iframe.src = `https://player.vimeo.com/video/${videoId}?autoplay=0#t=${formattedTime}`;
        iframe.width = '100%';
        iframe.height = '360';
        iframe.frameBorder = '0';
        iframe.allow = 'autoplay; fullscreen; picture-in-picture';
        iframe.allowFullscreen = true;
        iframe.id = `iframe-${mediaType}-${videoId}`;

        elements[mediaType].playerContainer.innerHTML = '';
        elements[mediaType].playerContainer.appendChild(iframe);

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

        console.log(`Embedded Vimeo Video: ${iframe.src}`);
    }

    // === Settings Management ===

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

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

    // === Unload Media Function ===
    function unloadMedia(mediaType) {
        if (state[mediaType]) {
            if (state[mediaType].type === 'file') {
                URL.revokeObjectURL(state[mediaType].element.src);
                state[mediaType].element.src = '';
            } else {
                // Reset iframe src to stop the media
                const iframe = state[mediaType].element;
                iframe.src = '';
            }
            state[mediaType] = null;
        }
    }
});

/* styles.css */

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

.container {
    position: relative; /* To position settings button absolutely within the 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);
}

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

/* Settings Button positioned at Top Left */
.settings-container {
    position: absolute;
    top: 20px;
    left: 20px;
}

.settings-button {
    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;
}

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

/* 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 {
        top: 10px;
        left: 10px;
    }

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

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

when i hit load video or load music there is an error. Errors
Allow attribute will take precedence over 'allowfullscreen'.
Context
dashboard.html