YouTube Sizer

Make YouTube Player 480p Size

目前為 2023-04-15 提交的版本,檢視 最新版本

/*
    Resize the YouTube player to 480p size.
    Copyright (C) 2023 Runio

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>
*/
// ==UserScript==
// @name          YouTube Sizer
// @author        Runio
// @namespace     namespace_runio
// @version       1.69
// @description   Make YouTube Player 480p Size
// @match         https://www.youtube.com/*
// @match         https://www.youtu.be/*
// @exclude       https://www.youtube.com/tv*
// @exclude       https://www.youtube.com/embed/*
// @exclude       https://www.youtube.com/live_chat*
// @exclude       https://www.youtube.com/shorts/*
// @run-at        document-end
// @grant         GM_setValue
// @grant         GM_getValue
// @icon          https://i.imgur.com/KJeLd60.png
// @license       GPL-3.0+
// @noframes
// ==/UserScript==
"use strict";
//==================================================================
//Local Storage Functions
if (window.frameElement) throw new Error("Stopped JavaScript.");

function setPref(preference, new_value) {
    GM_setValue(preference, new_value);
}

function getPref(preference) {
    return GM_getValue(preference);
}

function initPref(preference, new_value) {
    let value = getPref(preference);
    if (value === null) {
        setPref(preference, new_value);
        value = new_value;
    }
    return value;
}
//==================================================================
// Global Variables
//var transitionendEventFired = false;
var ytLoadendEventFired = false;
var checkPage = false;
var checkStart = false;
var maxWidth = 480; // Max Width of Video
var aspectRatio = 16 / 9; // Aspect Ratio
var shortcutKey = "r"; // Shortcut Key
var smallerCss = `#primary.ytd-watch-flexy:not([theater]):not([fullscreen]) { max-width:calc(${maxWidth}px*${aspectRatio})!important; }`;
var ytresizeCss = `.ytp-big-mode .ytp-chrome-controls .ytp-resize-button { display:none!important; }`;
//==================================================================
initPref("yt-resize", false);
//==================================================================
function checkURL() {
    function checkCss() {
        if (!document.getElementById("yt-css")) {
            location.reload();
        }
    }
    if (!window.location.pathname.includes("watch")) {
        if (!checkPage) {
            checkPage = true;
            location.reload();
        }
    }
    setInterval(() => {
        const playerContainer = document.getElementById("player-container-outer");
        if (playerContainer) {
            if (window.location.pathname.includes("watch")) {
                if (!checkStart) {
                    startMethods();
                    checkStart = true;
                }
                checkCss();
            }
            clearInterval(this);
        }
    }, 500);
}
// loadend event listener
window.addEventListener("loadend", () => {
    if (!ytLoadendEventFired) {
        ytLoadendEventFired = true;
        checkURL();
    }
}, {
    once: true
});
// Check URL when page loaded directly
if (!ytLoadendEventFired) {
    checkURL();
}
//==================================================================
function startMethods() {
    const outer = document.getElementById("player-container-outer");
    if (outer !== "null") {
        sizeObserver(); // Size Observer
        if (getPref("yt-resize")) {
            addCss(smallerCss, "small-player");
        }
        addCss(ytresizeCss, "yt-css");
        controlResize(); // Create Resize Button
        viewInterval(); // Video Container Interval
    } else {
        alert("player-container-outer not found");
    }
}
//==================================================================
function isCentered(element1, element2) {
    const box1 = element1.getBoundingClientRect();
    const box2 = element2.getBoundingClientRect();
    const center1 = {
        x: box1.left + box1.width / 2,
        y: box1.top + box1.height / 2
    };
    const center2 = {
        x: box2.left + box2.width / 2,
        y: box2.top + box2.height / 2
    };
    const horizontalDistance = Math.abs(center1.x - center2.x);
    const verticalDistance = Math.abs(center1.y - center2.y);

    return horizontalDistance <= 1 && verticalDistance <= 1;
}

function addCss(cssString, id) {
    const css = document.createElement("style");
    css.type = "text/css";
    css.id = id;
    css.innerHTML = cssString;
    document.head.appendChild(css);
}
//==================================================================
/*Resize Video Container*/
function createResize() {
    const element = document.querySelector("ytd-app");
    element.dispatchEvent(
        new CustomEvent("yt-action", {
            bubbles: !0,
            cancelable: !0,
            composed: !0,
            detail: {
                actionName: "yt-window-resized",
                disableBroadcast: false,
                optionalAction: true,
                returnValue: []
            }
        })
    );
    return;
}
/* Check Video Container */
function viewInterval() {
    let movie_player = document.querySelector(".html5-video-player");
    let video = document.querySelector("video");
    let isCenteredMoviePlayer = isCentered(video, movie_player);
    setInterval(() => {
        if (!isCenteredMoviePlayer) {
            let height = video.clientHeight; // Height Of The Video Element
            if (height !== maxWidth) {
                createResize();
                console.log(`Player Size: ${video.clientHeight} x ${video.clientWidth}`);
            }
        }
    }, 500);
}
//==================================================================
/*Saves Size Setting*/
function sizeObserver() {
    const targetNode = document.head;
    const config = {
        attributes: true,
        childList: true,
        subtree: true
    };
    const callback = function(mutationsList, observer) {
        for (let mutation of mutationsList) {
            if (mutation.removedNodes.length >= 1 && mutation.removedNodes[0].id == "small-player") {
                setPref("yt-resize", false); // Set Resize To False
                controlResize(); // Change Button Icon
                createResize(); // Resize Video Container
            } else if (mutation.addedNodes.length >= 1 && mutation.addedNodes[0].id == "small-player") {
                setPref("yt-resize", true); // Set Resize To True
                controlResize(); // Change Button Icon
                createResize(); // Resize Video Container
            }
        }
    };
    const observer = new MutationObserver(callback);
    observer.observe(targetNode, config);
}
//==================================================================
function showResizeButtonTooltip(btn, show = true) {
    let tooltipTopOffset = 62; // Height Above The Button For The Tooltip
    const buttonRect = btn.getBoundingClientRect(); // Get Button Position
    const tooltipHorizontalCenter = buttonRect.left + buttonRect.width / 2; // Tooltip Horizontal Center
    const tooltipTop = buttonRect.top + buttonRect.height / 2 - tooltipTopOffset; // Tooltip Top
    const tooltip = document.getElementById("ytd-resize-tt") || createTooltip();
    const tooltipText = tooltip.querySelector('#ytd-resize-tt-text');
    if (show) { // Show
        tooltip.style.top = `${tooltipTop}px`;
        tooltipText.textContent = btn.getAttribute("aria-label");
        tooltip.style.removeProperty("display");
        const tooltipWidth = tooltip.getBoundingClientRect().width;
        tooltip.style.left = `${tooltipHorizontalCenter - tooltipWidth / 2}px`;
        btn.removeAttribute("title");
    } else { // Hide
        tooltip.style.setProperty("display", "none");
        tooltipText.textContent = "";
        btn.setAttribute("title", btn.getAttribute("aria-label"));
    }

    function createTooltip() {
        const htmlPlayer = document.querySelector(".html5-video-player");
        const tooltip = document.createElement("div");
        const tooltipTextWrapper = document.createElement("div");
        const tooltipText = document.createElement("span");
        tooltip.setAttribute("class", "ytp-tooltip ytp-bottom");
        tooltip.setAttribute("id", "ytd-resize-tt");
        tooltip.style.setProperty("position", "fixed");
        tooltipTextWrapper.setAttribute("class", "ytp-tooltip-text-wrapper");
        tooltipText.setAttribute("class", "ytp-tooltip-text");
        tooltipText.setAttribute("id", "ytd-resize-tt-text");
        tooltip.appendChild(tooltipTextWrapper);
        tooltipTextWrapper.appendChild(tooltipText);
        htmlPlayer.appendChild(tooltip);
        return tooltip;
    }
}
//==================================================================
/*Resize Button Script*/
function buttonScript() {
    let splayer = document.getElementById("small-player");
    if (document.head.contains(splayer)) {
        document.head.removeChild(splayer);
    } else {
        addCss(smallerCss, "small-player");
    }
    return;
}

function setButton(btn, path) {
    var pathData = {};
    var ariaLabel = "";
    var title = "";

    if (!getPref("yt-resize")) {
        pathData.d = `M 19 23 L 11 15 L 11 23 Z M 29 25
                          L 29 10.98 C 29 9.88 28.1 9 27 9
                          L 9 9 C 7.9 9 7 9.88 7 10.98
                          L 7 25 C 7 26.1 7.9 27 9 27
                          L 27 27 C 28.1 27 29 26.1 29 25
                          L 29 25 Z M 27 25.02 L 9 25.02 L 9 10.97
                          L 27 10.97 L 27 25.02 L 27 25.02 Z`;
        ariaLabel = `Resize mode (${shortcutKey})`;
        title = `Resize mode (${shortcutKey})`;
    } else {
        pathData.d = `M 25 21 L 25 13 L 17 13 Z M 29 25
                          L 29 10.98 C 29 9.88 28.1 9 27 9
                          L 9 9 C 7.9 9 7 9.88 7 10.98
                          L 7 25 C 7 26.1 7.9 27 9 27
                          L 27 27 C 28.1 27 29 26.1 29 25
                          L 29 25 Z M 27 25.02
                          L 9 25.02 L 9 10.97 L 27 10.97
                          L 27 25.02 L 27 25.02 Z`;
        ariaLabel = `Default view (${shortcutKey})`;
        title = `Default view (${shortcutKey})`;
    }

    path.setAttribute("d", pathData.d);
    btn.setAttribute("aria-label", ariaLabel);
    btn.setAttribute("title", title);
}

function createButton() {
    var abtn = document.querySelector(".ytp-right-controls");
    var btn = document.createElement("button");
    var path = document.createElement("path");
    var clickEvent = new Event("click", {
        bubbles: false
    });

    /*Start Create SVG*/
    var svg = document.createElement("svg");
    svg.setAttribute("height", "100%");
    svg.setAttribute("version", "1.1");
    svg.setAttribute("viewBox", "0 0 36 36");
    svg.setAttribute("width", "100%");
    var use = document.createElement("use");
    use.setAttribute("class", "ytp-svg-shadow");

    setButton(btn, path); // Decide Which Button

    path.setAttribute("fill", "#fff");
    path.setAttribute("fill-rule", "evenodd");
    svg.appendChild(use);
    svg.appendChild(path);

    const btnContent = svg.outerHTML;
    /*Finished Create SVG*/

    btn.innerHTML = btnContent;
    btn.classList.add("ytp-resize-button", "ytp-button");
    btn.setAttribute("id", "ytp-resize-button");
    btn.setAttribute("data-tooltip-target-id", "ytp-resize-button");
    abtn.insertBefore(btn, abtn.lastChild.previousSibling);

    /*Tooltip Event Handlers*/
    const showTooltip = (event) => {
        const isMouseOver = ["mouseover", "focus"].includes(event.type);
        showResizeButtonTooltip(btn, isMouseOver);
    };

    btn.addEventListener("click", function(e) {
        e.stopPropagation();
        e.preventDefault();
        buttonScript();
    }, clickEvent);

    btn.addEventListener("mouseover", showTooltip);
    btn.addEventListener("mouseout", showTooltip);
    btn.addEventListener("focus", showTooltip);
    btn.addEventListener("blur", showTooltip);
}
/*Create Resize Button*/
function controlResize() {
    var buttonExists = document.getElementById("ytp-resize-button");
    if (!buttonExists) {
        window.addEventListener("keydown", function(e) {
            if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
            if (/^(?:input|textarea|select|button)$/i.test(e.target.tagName)) return;
            if (/(?:contenteditable-root)/i.test(e.target.id)) return;
            if (e.key == shortcutKey.toLowerCase() || e.key == shortcutKey.toUpperCase()) {
                e.stopPropagation();
                e.preventDefault();
                buttonScript();
            }
            return;
        });
        createButton();
    } else {
        setButton(buttonExists, buttonExists.querySelector("path"));
    }
}
//==================================================================

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址