YouTube Live Chat in Fullscreen

Display live chat while watching YouTube videos in fullscreen mode

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         YouTube Live Chat in Fullscreen
// @namespace    https://greasyfork.org/en/users/781396
// @version      1.8
// @description  Display live chat while watching YouTube videos in fullscreen mode
// @author       YAD
// @license      MIT
// @icon         https://www.iconpacks.net/icons/1/free-icon-video-837.png
// @match        *://*.youtube.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Load settings from localStorage or set defaults
    let chatboxWidth = localStorage.getItem('chatboxWidth') || 350;
    let chatboxHeight = localStorage.getItem('chatboxHeight') || 600;
    let chatboxOpacity = localStorage.getItem('chatboxOpacity') || 0.65;
    let chatboxPosX = localStorage.getItem('chatboxPosX') || 420;
    let chatboxPosY = localStorage.getItem('chatboxPosY') || -320;
    let backgroundColor = localStorage.getItem('backgroundColor') || '#000000';
    let backgroundOpacity = localStorage.getItem('backgroundOpacity') || 0.5;

    // CSS styles for transparency
    function getStyles() {
        return `
            yt-live-chat-header-renderer,
            yt-live-chat-message-input-renderer,
            #container.yt-live-chat-restricted-participation-renderer,
            yt-live-chat-renderer {
                background: rgba(${hexToRgb(backgroundColor)}, ${backgroundOpacity}) !important; // Adjust background color
                overflow: hidden;
            }
            .draggable {
                cursor: move;
            }
        `;
    }

    // Convert hex color to RGB
    function hexToRgb(hex) {
        const bigint = parseInt(hex.slice(1), 16);
        const r = (bigint >> 16) & 255;
        const g = (bigint >> 8) & 255;
        const b = bigint & 255;
        return `${r}, ${g}, ${b}`;
    }

    // Function to apply styles to the iframe document
    function applyStylesToIframe(iframeDoc) {
        const styleTag = iframeDoc.createElement('style');
        styleTag.textContent = getStyles();
        iframeDoc.head.appendChild(styleTag);
    }

    // Function to apply styles to the chatbox on load and fullscreen change
    function applyStyles() {
        const iframe = document.querySelector('iframe#chatframe');
        if (iframe) {
            setTimeout(() => {
                applyStylesToIframe(iframe.contentDocument || iframe.contentWindow.document);
            }, 2000); // Adding a 2secs delay to ensure the iframe loads
        }
    }

    // Create settings modal
    const settingsModal = document.createElement('div');
    settingsModal.style.position = 'fixed';
    settingsModal.style.top = '50%';
    settingsModal.style.left = '50%';
    settingsModal.style.transform = 'translate(-50%, -50%)';
    settingsModal.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
    settingsModal.style.color = 'white';
    settingsModal.style.padding = '20px';
    settingsModal.style.borderRadius = '10px';
    settingsModal.style.zIndex = '10001';
    settingsModal.style.display = 'none';

    // Create the title
    const title = document.createElement('h3');
    title.innerText = 'Chatbox Settings';
    settingsModal.appendChild(title);

    // Create width input
    const widthLabel = document.createElement('label');
    widthLabel.innerText = 'Width: ';
    const widthInput = document.createElement('input');
    widthInput.type = 'number';
    widthInput.id = 'chatWidth';
    widthInput.value = chatboxWidth;
    widthInput.style.width = '80px';
    widthLabel.appendChild(widthInput);
    widthLabel.appendChild(document.createTextNode(' px'));
    settingsModal.appendChild(widthLabel);
    settingsModal.appendChild(document.createElement('br'));

    // Create height input
    const heightLabel = document.createElement('label');
    heightLabel.innerText = 'Height: ';
    const heightInput = document.createElement('input');
    heightInput.type = 'number';
    heightInput.id = 'chatHeight';
    heightInput.value = chatboxHeight;
    heightInput.style.width = '80px';
    heightLabel.appendChild(heightInput);
    heightLabel.appendChild(document.createTextNode(' px'));
    settingsModal.appendChild(heightLabel);
    settingsModal.appendChild(document.createElement('br'));

    // Create opacity slider
    const opacityLabel = document.createElement('label');
    opacityLabel.innerText = 'Chat Opacity: ';
    const opacitySlider = document.createElement('input');
    opacitySlider.type = 'range';
    opacitySlider.id = 'chatOpacity';
    opacitySlider.min = '0';
    opacitySlider.max = '1';
    opacitySlider.step = '0.1';
    opacitySlider.value = chatboxOpacity;
    opacityLabel.appendChild(opacitySlider);
    settingsModal.appendChild(opacityLabel);
    settingsModal.appendChild(document.createElement('br'));

    // Create background color input
    const bgColorLabel = document.createElement('label');
    bgColorLabel.innerText = 'Background Color: ';
    const bgColorInput = document.createElement('input');
    bgColorInput.type = 'color';
    bgColorInput.value = backgroundColor;
    bgColorLabel.appendChild(bgColorInput);
    settingsModal.appendChild(bgColorLabel);
    settingsModal.appendChild(document.createElement('br'));

    // Create background opacity slider
    const bgOpacityLabel = document.createElement('label');
    bgOpacityLabel.innerText = 'Background Transparency: ';
    const bgOpacitySlider = document.createElement('input');
    bgOpacitySlider.type = 'range';
    bgOpacitySlider.id = 'bgOpacity';
    bgOpacitySlider.min = '0';
    bgOpacitySlider.max = '1';
    bgOpacitySlider.step = '0.1';
    bgOpacitySlider.value = backgroundOpacity;
    bgOpacityLabel.appendChild(bgOpacitySlider);
    settingsModal.appendChild(bgOpacityLabel);
    settingsModal.appendChild(document.createElement('br'));

    // Create X position slider
    const posXLabel = document.createElement('label');
    posXLabel.innerText = 'X Position: ';
    const posXSlider = document.createElement('input');
    posXSlider.type = 'range';
    posXSlider.id = 'chatPosX';
    posXSlider.min = `-${window.innerWidth}`;
    posXSlider.max = `${window.innerWidth}`;
    posXSlider.value = chatboxPosX;
    posXLabel.appendChild(posXSlider);
    settingsModal.appendChild(posXLabel);
    settingsModal.appendChild(document.createElement('br'));

    // Create Y position slider
    const posYLabel = document.createElement('label');
    posYLabel.innerText = 'Y Position: ';
    const posYSlider = document.createElement('input');
    posYSlider.type = 'range';
    posYSlider.id = 'chatPosY';
    posYSlider.min = `-${window.innerHeight}`;
    posYSlider.max = `${window.innerHeight}`;
    posYSlider.value = chatboxPosY;
    posYLabel.appendChild(posYSlider);
    settingsModal.appendChild(posYLabel);
    settingsModal.appendChild(document.createElement('br'));

    // Create apply button
    const applyButton = document.createElement('button');
    applyButton.innerText = 'Apply';
    applyButton.id = 'applySettings';
    settingsModal.appendChild(applyButton);

    // Create reset button
    const resetButton = document.createElement('button');
    resetButton.innerText = 'Reset';
    resetButton.id = 'resetSettings';
    settingsModal.appendChild(resetButton);

    document.body.appendChild(settingsModal);

    // Handle settings button click (open modal)
    const settingsButton = document.createElement('button');
    settingsButton.innerText = '⚙';
    settingsButton.style.position = 'fixed';
    settingsButton.style.top = '2%';
    settingsButton.style.right = '2%';
    settingsButton.style.zIndex = '10000';
    settingsButton.style.display = 'none';
    settingsButton.addEventListener('click', () => {
        settingsModal.style.display = 'block';
    });

    document.body.appendChild(settingsButton);

    // Update iframe settings in real-time
    function updateChatbox() {
        const iframe = document.querySelector('iframe#chatframe');
        if (iframe) {
            iframe.style.width = `${chatboxWidth}px`;
            iframe.style.height = `${chatboxHeight}px`;
            iframe.style.position = 'fixed';
            iframe.style.left = `${(window.innerWidth / 2) + parseInt(chatboxPosX)}px`;
            iframe.style.top = `${(window.innerHeight / 2) + parseInt(chatboxPosY)}px`;
            iframe.style.opacity = chatboxOpacity;
            iframe.style.borderRadius = '12px';
            applyStyles();
        }
    }

    // Handle apply button click
    applyButton.addEventListener('click', () => {
        // Update settings
        chatboxWidth = widthInput.value;
        chatboxHeight = heightInput.value;
        chatboxOpacity = opacitySlider.value;
        backgroundColor = bgColorInput.value;
        backgroundOpacity = bgOpacitySlider.value;
        chatboxPosX = posXSlider.value;
        chatboxPosY = posYSlider.value;

        // Save settings to localStorage
        localStorage.setItem('chatboxWidth', chatboxWidth);
        localStorage.setItem('chatboxHeight', chatboxHeight);
        localStorage.setItem('chatboxOpacity', chatboxOpacity);
        localStorage.setItem('backgroundColor', backgroundColor);
        localStorage.setItem('backgroundOpacity', backgroundOpacity);
        localStorage.setItem('chatboxPosX', chatboxPosX);
        localStorage.setItem('chatboxPosY', chatboxPosY);

        settingsModal.style.display = 'none';
        updateChatbox();
    });

    // Handle reset settings
    resetButton.addEventListener('click', () => {
        localStorage.removeItem('chatboxWidth');
        localStorage.removeItem('chatboxHeight');
        localStorage.removeItem('chatboxOpacity');
        localStorage.removeItem('backgroundColor');
        localStorage.removeItem('backgroundOpacity');
        localStorage.removeItem('chatboxPosX');
        localStorage.removeItem('chatboxPosY');

        // Reset to defaults
        chatboxWidth = 350;
        chatboxHeight = 600;
        chatboxOpacity = 0.65;
        backgroundColor = '#000000';
        backgroundOpacity = 0.5;
        chatboxPosX = 420;
        chatboxPosY = -320;

        // Update UI elements
        widthInput.value = chatboxWidth;
        heightInput.value = chatboxHeight;
        opacitySlider.value = chatboxOpacity;
        bgColorInput.value = backgroundColor;
        bgOpacitySlider.value = backgroundOpacity;
        posXSlider.value = chatboxPosX;
        posYSlider.value = chatboxPosY;

        updateChatbox(); // Apply reset settings
    });

    // Handle slider inputs for real-time updates
    opacitySlider.addEventListener('input', () => {
        chatboxOpacity = opacitySlider.value;
        updateChatbox();
    });

    bgOpacitySlider.addEventListener('input', () => {
        backgroundOpacity = bgOpacitySlider.value;
        updateChatbox();
    });

    bgColorInput.addEventListener('input', () => {
        backgroundColor = bgColorInput.value;
        updateChatbox();
    });

    widthInput.addEventListener('input', () => {
        chatboxWidth = widthInput.value;
        updateChatbox();
    });

    heightInput.addEventListener('input', () => {
        chatboxHeight = heightInput.value;
        updateChatbox();
    });

    posXSlider.addEventListener('input', () => {
        chatboxPosX = posXSlider.value;
        updateChatbox();
    });

    posYSlider.addEventListener('input', () => {
        chatboxPosY = posYSlider.value;
        updateChatbox();
    });

    // Function to adjust slider value with scroll wheel
    function adjustSliderValue(slider, delta) {
        const step = parseFloat(slider.step) || 10;
        const min = parseFloat(slider.min) || 0;
        const max = parseFloat(slider.max) || 100;
        let value = parseFloat(slider.value) || 0;

        value += delta * step;
        if (value < min) value = min;
        if (value > max) value = max;

        slider.value = value;
        slider.dispatchEvent(new Event('input'));
    }

    // Handle mouse scroll on sliders
    document.querySelectorAll('input[type="range"]').forEach(slider => {
        slider.addEventListener('wheel', event => {
            event.preventDefault();
            const delta = Math.sign(event.deltaY) * -1;
            adjustSliderValue(slider, delta);
        });

        // Handle arrow key controls on sliders
        slider.addEventListener('keydown', event => {
            if (event.key === 'ArrowUp' && slider.id === 'chatPosY') {
                adjustSliderValue(slider, -1);
            } else if (event.key === 'ArrowDown' && slider.id === 'chatPosY') {
                adjustSliderValue(slider, 1);
            } else if (event.key === 'ArrowLeft' && slider.id === 'chatPosX') {
                adjustSliderValue(slider, -1);
            } else if (event.key === 'ArrowRight' && slider.id === 'chatPosX') {
                adjustSliderValue(slider, 1);
            } else if ((event.key === 'ArrowUp' || event.key === 'ArrowRight') && slider.id !== 'chatPosX' && slider.id !== 'chatPosY') {
                adjustSliderValue(slider, 1);
            } else if ((event.key === 'ArrowDown' || event.key === 'ArrowLeft') && slider.id !== 'chatPosX' && slider.id !== 'chatPosY') {
                adjustSliderValue(slider, -1);
            }
        });
    });

    // Handle fullscreen changes
    function handleFullscreenChange() {
        const iframe = document.querySelector('iframe#chatframe');
        if (!iframe) return;

        const isFullscreen = document.fullscreenElement;

        if (isFullscreen) {
            updateChatbox();
            applyStyles();
            settingsButton.style.display = 'block';
        } else {
            settingsButton.style.display = 'none';
            settingsModal.style.display = 'none';
            // Reset to default values (do not remove saved settings)
            iframe.style.width = '';
            iframe.style.height = '';
            iframe.style.position = '';
            iframe.style.left = '';
            iframe.style.top = '';
            iframe.style.opacity = '';
        }
    }

    // Listen for fullscreen changes
    document.addEventListener('fullscreenchange', handleFullscreenChange);

    // Initial chatbox update
    updateChatbox();
    applyStylesOnLoad();
})();