Dreaming Spanish - Widescreen Layout

Makes the video player fill the available space for both YouTube and Shaka players, requests 1080p quality for YouTube, with toggles to hide/show sidebars, and automatically clicks the 'Not now' button on popups, ensuring playback resumes.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Dreaming Spanish - Widescreen Layout
// @namespace    http://tampermonkey.net/
// @version      1.9
// @description  Makes the video player fill the available space for both YouTube and Shaka players, requests 1080p quality for YouTube, with toggles to hide/show sidebars, and automatically clicks the 'Not now' button on popups, ensuring playback resumes.
// @author       OthorWight
// @match        https://www.dreamingspanish.com/*
// @match        https://app.dreaming.com/*
// @grant        GM_addStyle
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const MASTER_TOGGLE_ID = 'ds-widescreen-master-toggle';
    const MASTER_ENABLED_KEY = 'dsWidescreenEnabled';
    const MASTER_ENABLED_CLASS = 'ds-widescreen-active';

    const STYLE_ID = 'ds-widescreen-features-styles-987';
    const LEFT_SIDEBAR_HIDDEN_CLASS = 'ds-widescreen-left-hidden';
    const RIGHT_SIDEBAR_HIDDEN_CLASS = 'ds-widescreen-right-hidden';

    let lastUrl = location.href;

    function isMasterEnabled() {
        return localStorage.getItem(MASTER_ENABLED_KEY) !== 'false';
    }

    function waitForElement(selector, conditionFn = (el) => true) {
        return new Promise(resolve => {
            const element = document.querySelector(selector);
            if (element && conditionFn(element)) {
                return resolve(element);
            }
            const observer = new MutationObserver(() => {
                const targetElement = document.querySelector(selector);
                if (targetElement && conditionFn(targetElement)) {
                    observer.disconnect();
                    resolve(targetElement);
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });
        });
    }

    function setHighQuality(iframe) {
        // This function specifically targets YouTube iframes
        if (!iframe || !iframe.src || !iframe.src.includes('youtube.com')) return;

        let src = iframe.src;
        if (!src.includes('vq=hd1080')) {
            iframe.src = src + (src.includes('?') ? '&' : '?') + 'vq=hd1080';
            console.log("DS Widescreen Script: Requested 1080p quality for YouTube player.");
        }
    }

    function addFeatures() {
        if (document.getElementById(STYLE_ID)) return;
        console.log("DS Widescreen Script: Applying features to watch page.");

        GM_addStyle(`
            /* Main layout adjustments */
            body.${MASTER_ENABLED_CLASS} .ds-page.ds-watch-page { max-width: 100% !important; margin: 0 auto; padding: 0px !important; }
            body.${MASTER_ENABLED_CLASS} .ds-watch-page__sections { gap: 0rem !important; }
            body.${MASTER_ENABLED_CLASS} .ds-video-section { flex: 1 1 auto; min-width: 500px; gap: 0rem !important; }
            body.${MASTER_ENABLED_CLASS} .ds-playlist-section, body.ds-widescreen-active .ds-sidebar-area, body.ds-widescreen-active .ds-content-area { transition: all 0.3s ease-in-out; }
            body.${MASTER_ENABLED_CLASS} .ds-playlist-section { flex: 0 0 340px; overflow: hidden; }

            /* New Shaka Player Support */
            body.${MASTER_ENABLED_CLASS} .ds-video-section__embed,
            body.${MASTER_ENABLED_CLASS} .embed-responsive,
            body.${MASTER_ENABLED_CLASS} .ds-shaka-player {
                height: 100% !important;
                width: 100% !important;
            }

            /* Sidebar toggle buttons */
            #ds-toggle-left-sidebar, #ds-toggle-right-playlist { position: fixed; top: 50%; transform: translateY(-50%); width: 30px; height: 30px; background-color: #ff9301; color: #000000; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: bold; font-family: monospace; cursor: pointer; z-index: 9999; transition: all 0.3s ease-in-out; user-select: none; border: 2px solid #000000; border-radius: 50%; }
            #ds-toggle-left-sidebar:hover, #ds-toggle-right-playlist:hover { background-color: #ef8301; box-shadow: 0px 0px 8px rgba(0,0,0,0.3); }
            #ds-toggle-left-sidebar::after, #ds-toggle-right-playlist::after { content: 'Hide'; position: absolute; bottom: 120%; left: 50%; transform: translateX(-50%); background-color: #222; color: #fff; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-family: sans-serif; white-space: nowrap; opacity: 0; visibility: hidden; transition: opacity 0.2s, visibility 0.2s; pointer-events: none; }
            #ds-toggle-left-sidebar:hover::after, #ds-toggle-right-playlist:hover::after { opacity: 1; visibility: visible; }
            #ds-toggle-left-sidebar { left: calc(var(--sidebar-width, 256px) - 40px); }
            #ds-toggle-left-sidebar::before { content: '<<'; }
            #ds-toggle-right-playlist { right: calc(340px - 40px); }
            #ds-toggle-right-playlist::before { content: '>>'; }

            /* Hidden states for sidebars */
            body.${LEFT_SIDEBAR_HIDDEN_CLASS} .ds-sidebar-area { transform: translateX(-100%); }
            body.${LEFT_SIDEBAR_HIDDEN_CLASS} .ds-content-area { padding-left: 0 !important; }
            body.${LEFT_SIDEBAR_HIDDEN_CLASS} #ds-toggle-left-sidebar { left: 5px; }
            body.${LEFT_SIDEBAR_HIDDEN_CLASS} #ds-toggle-left-sidebar::before { content: '>>'; }
            body.${LEFT_SIDEBAR_HIDDEN_CLASS} #ds-toggle-left-sidebar::after { content: 'Show'; }
            body.${RIGHT_SIDEBAR_HIDDEN_CLASS} .ds-playlist-section { flex-basis: 0 !important; min-width: 0 !important; }
            body.${RIGHT_SIDEBAR_HIDDEN_CLASS} #ds-toggle-right-playlist { right: 5px; }
            body.${RIGHT_SIDEBAR_HIDDEN_CLASS} #ds-toggle-right-playlist::before { content: '<<'; }
            body.${RIGHT_SIDEBAR_HIDDEN_CLASS} #ds-toggle-right-playlist::after { content: 'Show'; }
        `).id = STYLE_ID;

        const leftToggleButton = document.createElement('div');
        leftToggleButton.id = 'ds-toggle-left-sidebar';
        leftToggleButton.addEventListener('click', () => {
            const isHidden = document.body.classList.toggle(LEFT_SIDEBAR_HIDDEN_CLASS);
            localStorage.setItem('dsLeftSidebarHidden', isHidden);
        });

        const rightToggleButton = document.createElement('div');
        rightToggleButton.id = 'ds-toggle-right-playlist';
        rightToggleButton.addEventListener('click', () => {
            const isHidden = document.body.classList.toggle(RIGHT_SIDEBAR_HIDDEN_CLASS);
            localStorage.setItem('dsRightSidebarHidden', isHidden);
        });

        if (localStorage.getItem('dsLeftSidebarHidden') === 'true') document.body.classList.add(LEFT_SIDEBAR_HIDDEN_CLASS);
        if (localStorage.getItem('dsRightSidebarHidden') === 'true') document.body.classList.add(RIGHT_SIDEBAR_HIDDEN_CLASS);

        document.body.append(leftToggleButton, rightToggleButton);
    }

    function removeFeatures() {
        const styleTag = document.getElementById(STYLE_ID);
        if (styleTag) styleTag.remove();

        const leftBtn = document.getElementById('ds-toggle-left-sidebar');
        if (leftBtn) leftBtn.remove();
        const rightBtn = document.getElementById('ds-toggle-right-playlist');
        if (rightBtn) rightBtn.remove();

        document.body.classList.remove(LEFT_SIDEBAR_HIDDEN_CLASS, RIGHT_SIDEBAR_HIDDEN_CLASS);
        console.log("DS Widescreen Script: Features removed.");
    }

    function handlePageChange() {
        const masterToggle = document.getElementById(MASTER_TOGGLE_ID);
        if (!masterToggle) return;

        const isWatchPage = location.href.includes('/watch?');
        masterToggle.style.display = isWatchPage ? 'flex' : 'none';

        if (isWatchPage) {
            if (isMasterEnabled()) {
                // Look for either the old YouTube player or the new Shaka player embed container
                waitForElement('.ds-youtube-player, .ds-video-section__embed').then(addFeatures);

                // This part only affects the old YouTube player, it will be ignored by the new one
                const iframeSelector = '.ds-video-section iframe';
                const iframeCondition = (el) => el.src && el.src.includes('youtube.com');
                waitForElement(iframeSelector, iframeCondition).then(setHighQuality).catch(() => {
                    console.log("DS Widescreen Script: YouTube player not found, skipping HD quality request.");
                });

            } else {
                removeFeatures();
            }
        } else {
            removeFeatures();
        }
    }

    function addMasterToggleStyles() {
        GM_addStyle(`
            #${MASTER_TOGGLE_ID} {
                display: none; position: fixed; top: 10px; left: 10px;
                width: 40px; height: 25px; background-color: #d9534f;
                color: white; align-items: center; justify-content: center;
                font-size: 11px; font-weight: bold; font-family: sans-serif;
                cursor: pointer; z-index: 10001; border-radius: 5px;
                border: 1px solid #333; user-select: none; transition: background-color 0.3s ease;
            }
            body.${MASTER_ENABLED_CLASS} #${MASTER_TOGGLE_ID} {
                background-color: #5cb85c;
            }
        `);
    }

    function createMasterToggle() {
        const toggleButton = document.createElement('div');
        toggleButton.id = MASTER_TOGGLE_ID;

        const updateButtonState = (enabled) => {
            document.body.classList.toggle(MASTER_ENABLED_CLASS, enabled);
            toggleButton.textContent = enabled ? 'ON' : 'OFF';
            toggleButton.title = enabled ? 'Click to disable Widescreen features' : 'Click to enable Widescreen features';
        };

        toggleButton.addEventListener('click', () => {
            const currentlyEnabled = isMasterEnabled();
            localStorage.setItem(MASTER_ENABLED_KEY, !currentlyEnabled);
            updateButtonState(!currentlyEnabled);
            handlePageChange();
        });

        document.body.appendChild(toggleButton);
        updateButtonState(isMasterEnabled());
    }

    // --- Auto-click "Not now" button & Resume Playback ---
    function autoClickNotNow() {
        const checkInterval = 2000; // Check every 2 seconds

        setInterval(() => {
            if (!isMasterEnabled()) return;
            const buttons = document.querySelectorAll('button');
            for (const button of buttons) {
                if (button.innerText && button.innerText.trim().toLowerCase() === 'not now') {
                    console.log("DS Widescreen Script: 'Not now' button found. Clicking it automatically.");
                    button.click();

                    setTimeout(() => {
                        const videoElement = document.querySelector('video.ds-shaka-player__video');
                        if (videoElement && videoElement.paused) {
                            console.log("DS Widescreen Script: Video is paused after popup, resuming playback.");
                            videoElement.play();
                        }
                    }, 100);
                }
            }
        }, checkInterval);
    }

    // --- Script Initialization ---
    addMasterToggleStyles();
    createMasterToggle();

    const bodyObserver = new MutationObserver(() => {
        if (location.href !== lastUrl) {
            lastUrl = location.href;
            handlePageChange();
        }
    });
    bodyObserver.observe(document.body, { childList: true, subtree: true });

    handlePageChange();

    autoClickNotNow();

})();