Space-efficient Youtube

AKA: "Wide Youtube", AKA: "Wide video container" - Uses the page space on youtube more efficiently (especially good for high resolutions)

目前為 2020-09-24 提交的版本,檢視 最新版本

// ==UserScript==
// @name        Space-efficient Youtube
// @namespace   1N07
// @author      1N07
// @icon        https://i.imgur.com/VgEiyi3.png
// @description AKA: "Wide Youtube", AKA: "Wide video container" - Uses the page space on youtube more efficiently (especially good for high resolutions)
// @include     https://www.youtube.com/*
// @version     2.1
// @grant       GM_registerMenuCommand
// @grant       GM_unregisterMenuCommand
// @grant       GM_getValue
// @grant       GM_setValue
// ==/UserScript==

(function() {

    //===== SETTINGS =====//
    var FPPHandle;
    var FPPCompOn = GM_getValue("FPPCompOn", false);
    SetFPPHandle();

	var ForceCSSHandle;
    var ForceCSSOn = GM_getValue("ForceCSSOn", false);
    SetForceCSSHandle();

    var HomeVideoContainerWidthHandle;
    var HomeVideoContainerWidth = GM_getValue("HomeVideoContainerWidth", "360px");
    SetHomeVideoContainerWidthHandle();

    var ShowChannelIconNextToVideosOnHomePageHandle;
    var ShowChannelIconNextToVideosOnHomePage = GM_getValue("ShowChannelIconNextToVideosOnHomePage", true);
    SetShowChannelIconNextToVideosOnHomePageHandle();

    var SubVideoContainerWidthHandle;
    var SubVideoContainerWidth = GM_getValue("SubVideoContainerWidth", "210px");
    SetSubVideoContainerWidthHandle();

    var HQTNHandle;
    var HQTN = GM_getValue("HQTN", false);
    SetHQTNHandle();

    var TrendingVideoContainerWidthHandle;
    var TrendingVideoContainerWidth = GM_getValue("TrendingVideoContainerWidth", "600px");
    SetTrendingVideoContainerWidthHandle();

    var SearchVideoContainerWidthHandle;
    var SearchVideoContainerWidth = GM_getValue("SearchVideoContainerWidth", "600px");
    SetSearchVideoContainerWidthHandle();

    var VideoContainerHorMarginHandle;
    var VideoContainerHorMargin = GM_getValue("VideoContainerHorMargin", "4px");
    SetVideoContainerHorMarginHandle();

    var VideoContainerVerMarginHandle;
    var VideoContainerVerMargin = GM_getValue("VideoContainerVerMargin", "24px");
    SetVideoContainerVerMarginHandle();

	var AutoExpandChannelVidContainersHandle;
    var AutoExpandChannelVidContainers = GM_getValue("AutoExpandChannelVidContainers", true);
    SetAutoExpandChannelVidContainersHandle();

    //var SpaceEfficientSearchResultsHandle;
    var SpaceEfficientSearchResults = true;//GM_getValue("SpaceEfficientSearchResults", true);
    //SetSpaceEfficientSearchResultsHandle();

    var LessenVideoTitleTopMarginOnHomePage = true;

    //===== SETTINGS END =====//


    var screenWidth = screen.width;
    if(!!document.getElementById("early-body")) { //if old youtube
        document.getElementById("content").setAttribute("style", "width: 99%;");
    } else { //new youtube
        addGlobalStyle(`
			ytd-app #page-manager > ytd-browse:not([page-subtype="playlist"]):not([page-subtype="home"]) ytd-two-column-browse-results-renderer.ytd-browse
			{
				box-sizing: border-box`+(ForceCSSOn ? `!important`:``)+`;
				width: calc(100% - 25px) !important;
				margin: 10px`+(ForceCSSOn ? `!important`:``)+`;
				max-width: none;
			}

			#items.ytd-grid-renderer > ytd-grid-video-renderer.ytd-grid-renderer,
			#items.ytd-grid-renderer > ytd-grid-radio-renderer.ytd-grid-renderer,
			#items.ytd-grid-renderer > ytd-grid-channel-renderer.ytd-grid-renderer,
			#items.ytd-grid-renderer > ytd-grid-playlist-renderer.ytd-grid-renderer,
			#items.ytd-grid-renderer > ytd-grid-movie-playlist-renderer.ytd-grid-renderer,
			#items.ytd-grid-renderer > ytd-grid-movie-renderer.ytd-grid-renderer,
			#items.ytd-grid-renderer > ytd-grid-show-renderer.ytd-grid-renderer,
			#items.ytd-grid-renderer > ytd-game-card-renderer.ytd-grid-renderer,
			ytd-grid-video-renderer
			{
				width: `+SubVideoContainerWidth+`;
				margin-left: 0;
				margin-top: 0;
				margin-right: `+VideoContainerHorMargin+`;
				margin-bottom: `+VideoContainerVerMargin+`;
			}
			ytd-thumbnail.ytd-grid-video-renderer
			{
				width: `+SubVideoContainerWidth+`;
				height: calc(`+SubVideoContainerWidth+` * 0.5625);
			}
			ytd-thumbnail #thumbnail.ytd-thumbnail yt-img-shadow.ytd-thumbnail
			{
				width: 100%;
				height: 100%;
			}
			img.yt-img-shadow
			{
				max-width: 100%;
				max-height: 100%;
				margin-left: 0;
				margin-right: 0;
				width: 100%;
				height: 100%;
			}

			/*channels page rules*/
			ytd-app #page-manager > ytd-browse[page-subtype="channels"] ytd-two-column-browse-results-renderer.ytd-browse ytd-item-section-renderer.ytd-section-list-renderer
			{
				width: calc(100% - 20px);
				max-width: none;
			}
			/*for some reason the arrows sometimes dont show up, so now forcing them to*/
			ytd-app #page-manager > ytd-browse[page-subtype="channels"] ytd-two-column-browse-results-renderer.ytd-browse ytd-item-section-renderer.ytd-section-list-renderer ytd-button-renderer.yt-horizontal-list-renderer.arrow
			{
				opacity: 1;
				display: flex;
			}

			/*trending page rules*/
			ytd-app #page-manager > ytd-browse:not([page-subtype]) #grid-container.ytd-expanded-shelf-contents-renderer > .ytd-expanded-shelf-contents-renderer,
			ytd-app #page-manager > ytd-browse:not([page-subtype]) #grid-container.ytd-expanded-shelf-contents-renderer > .ytd-expanded-shelf-contents-renderer > .ytd-video-renderer
			{
				max-width: `+TrendingVideoContainerWidth+`;
			}
			ytd-app #page-manager > ytd-browse:not([page-subtype]) ytd-video-renderer.ytd-expanded-shelf-contents-renderer,
			ytd-app #page-manager > ytd-browse:not([page-subtype]) ytd-video-renderer.ytd-expanded-shelf-contents-renderer:not(:last-child)
			{
				padding-right: 3px;
				margin-left: 0;
				margin-top: 0;
				margin-right: `+VideoContainerHorMargin+`;
				margin-bottom: `+VideoContainerVerMargin+`;
			}
			ytd-app #page-manager > ytd-browse:not([page-subtype]) ytd-thumbnail.ytd-video-renderer
			{
				margin-right: 10px;
			}

			/*Playlist page rules*/
			ytd-browse[page-subtype="playlist"] ytd-two-column-browse-results-renderer.ytd-browse
			{
				max-width: none;
			}

			/*home page rules*/
			ytd-rich-item-renderer {
			    width: `+HomeVideoContainerWidth+`;
				margin-left: 0;
				margin-top: 0;
				margin-right: `+VideoContainerHorMargin+`;
				margin-bottom: `+VideoContainerVerMargin+`;
			}
		`);
        console.log("Youtube Wide video container style added to DOM");

        if(!ShowChannelIconNextToVideosOnHomePage)
        {
            addGlobalStyle(`
				#avatar-link.ytd-rich-grid-video-renderer,
                #avatar-link.ytd-rich-grid-media
				{
					display: none;
				}
			`);
        }

        if(HQTN)
        {
            addGlobalStyle(`
				img.yt-img-shadow:not([src*='?'])
				{
					object-fit: cover;
				}
			`);
        }

        if(LessenVideoTitleTopMarginOnHomePage)
        {
            addGlobalStyle(`
				h3.ytd-rich-grid-video-renderer
				{
					margin-top: 6px;
				}
			`);
        }

        if(FPPCompOn) {
			addGlobalStyle(`
				/*========== Fade++ Compatibility ==========*/
				ytd-app #page-manager > ytd-browse:not([page-subtype="playlist"]) {
					display: block;
				}
				ytd-app[guide-persistent-and-visible] #page-manager > ytd-browse:not([page-subtype="playlist"]) ytd-two-column-browse-results-renderer.ytd-browse
				{
					margin-left: 250px !important;
				}
			`);
            console.log("Youtube Wide video container Fade++ compatibilty style added to DOM");
        }

        if(SpaceEfficientSearchResults)
        {
            addGlobalStyle(`
				ytd-two-column-search-results-renderer.ytd-search,
				ytd-two-column-search-results-renderer.ytd-search > #primary
				{
					width: 100%;
					max-width: 100%;
				}

				ytd-two-column-search-results-renderer.ytd-search > #primary ytd-video-renderer.ytd-item-section-renderer,
				ytd-two-column-search-results-renderer.ytd-search > #primary ytd-video-renderer.ytd-vertical-list-renderer,
				ytd-two-column-search-results-renderer.ytd-search > #primary ytd-channel-renderer.ytd-item-section-renderer
				{
					display: inline-block;
					width: `+SearchVideoContainerWidth+`;
					margin-left: 0;
					margin-bottom: 0;
					padding-right: 3px;
					margin-right: `+VideoContainerHorMargin+`;
					margin-top: `+VideoContainerVerMargin+`;
				}

			`);
        }
    }

    if(AutoExpandChannelVidContainers || HQTN)
    {
        var lastCheckedURL = window.location.href;
        URLChanged(); //for initial page load

        //poll for url changes
        setInterval(function(){
            if(lastCheckedURL != window.location.href)
            {
                lastCheckedURL = window.location.href;
                URLChanged();
            }
        }, 200);
        var waitForArrows, waitForSubsThumbnails;
    }
    /*============================================================*/

    function AutoExpandContainers()
    {
        clearInterval(waitForArrows);

        //=== clear potential old containers ===//
        let expandedEls = document.getElementsByClassName("expanded-wwc");
        //console.log("expanded els found: " + expandedEls.length);
        let numRemoved = 0;

        //seems to always remove exactly half of them only, for some reason. So I guess do this until all have been removed
        while(expandedEls.length > 0)
        {
            for(let x = 0; x < expandedEls.length; x++)
            {
                if(!!expandedEls[x])
                {
                    expandedEls[x].classList.remove("expanded-wwc");
                    //console.log(++numRemoved + " cleared");
                }
            }
            expandedEls = document.getElementsByClassName("expanded-wwc");
        }
        //=== old containers cleared ===//

        //=== unmark container arrows marked as clicked ===//
        numRemoved = 0;
        let clickedArrows = document.getElementsByClassName("clicked");
        //console.log("clicked found: " + clickedArrows.length);
        while(clickedArrows.length > 0)
        {
            for(let x = 0; x < clickedArrows.length; x++)
            {
                if(!!clickedArrows[x])
                {
                    clickedArrows[x].classList.remove("clicked");
                    //console.log(++numRemoved + " cleared");
                }
            }
            clickedArrows = document.getElementsByClassName("clicked");
        }
        //=== all arrows unmarked ===//
        //console.log("-expandedclear-");

        //check that we are on a page that can have containers
        if(lastCheckedURL.includes("/user/") || lastCheckedURL.includes("/channel/"))
        {
            //poll for untouched containers
            waitForArrows = setInterval(function(){
                //console.log("-searching...-");
                let arrowsRight = document.querySelectorAll("yt-horizontal-list-renderer:not(.expanded-wwc) > #right-arrow > ytd-button-renderer.arrow");
                let arrowsLeft = document.querySelectorAll("yt-horizontal-list-renderer:not(.expanded-wwc) > #left-arrow > ytd-button-renderer.arrow");
                if(!!arrowsRight && arrowsRight.length > 0 && !!arrowsLeft && arrowsLeft.length > 0)
                {
                    //console.log("-found-");
                    //do the thing for found untouched containers and mark them
                    for(let i = 0; i < arrowsRight.length; i++)
                    {
                        if(!!arrowsRight[i] && arrowsRight[i].offsetParent !== null && !!arrowsLeft[i] && arrowsLeft[i].offsetParent !== null)
                        {
                            arrowsRight[i].parentElement.parentElement.classList.add("expanded-wwc");
                            arrowsRight[i].click();
                            //console.log("simulated click on right arrow");
                            arrowsRight[i].classList.add("clicked");
                            arrowsLeft[i].click();
                            //console.log("simulated click on left arrow");
                            arrowsLeft[i].classList.add("clicked");
                        }
                    }
                }
            }, 250);
        }
    }

    function SwapSubsVidThumbnailsHQ()
    {
        clearInterval(waitForSubsThumbnails);
        if(lastCheckedURL.includes("/subscriptions"))
        {
            waitForSubsThumbnails = setInterval(function(){
                let nails = document.querySelectorAll("img.yt-img-shadow[src*='hqdefault.jpg?']");
                //console.log("found " + nails.length + " LQ nails");
                for(let i = 0; i < nails.length; i++)
                    nails[i].src = nails[i].src.split("?")[0];
            }, 200);
        }
    }

    function URLChanged()
    {
        console.log("-urlchanged-");

        if(AutoExpandChannelVidContainers)
            AutoExpandContainers();

        if(HQTN)
            SwapSubsVidThumbnailsHQ();
    }
    function CleanCSSValue(val)
    {
        val = val.trim();

        //if only numbers...
        if(/^\d+$/.test(val))
            val += "px"; //...add px

        return val;
    }
    function addGlobalStyle(css)
    {
        var head, style;
        head = document.getElementsByTagName('head')[0];
        if (!head) { return; }
        style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = css;
        head.appendChild(style);
    }

    //=== SETTINGS HANDLE FUCTIONS ===//
    function SetFPPHandle() {
        GM_unregisterMenuCommand(FPPHandle);

        FPPHandle = GM_registerMenuCommand("Fade++ Compatibility mode (" + (FPPCompOn ? "On" : "Off") + ") -click to change-", function(){
            FPPCompOn = !FPPCompOn;
            GM_setValue("FPPCompOn", FPPCompOn);
            SetFPPHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
	function SetForceCSSHandle() {
        GM_unregisterMenuCommand(ForceCSSHandle);

        ForceCSSHandle = GM_registerMenuCommand("CSS important rule mode (" + (ForceCSSOn ? "On" : "Off") + ") -click to change-", function(){
            ForceCSSOn = !ForceCSSOn;
            GM_setValue("ForceCSSOn", ForceCSSOn);
            SetForceCSSHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
    function SetHomeVideoContainerWidthHandle() {
        GM_unregisterMenuCommand(HomeVideoContainerWidthHandle);

        HomeVideoContainerWidthHandle = GM_registerMenuCommand("[home-page] Video-renderer width (" + HomeVideoContainerWidth + ") -click to change-", function(){
            HomeVideoContainerWidth = CleanCSSValue(prompt("Set the width of a single video renderer on the page (use CSS units)\nThe current value is: '" + HomeVideoContainerWidth + "'"));
            GM_setValue("HomeVideoContainerWidth", HomeVideoContainerWidth);
            SetHomeVideoContainerWidthHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
    function SetHQTNHandle() {
        GM_unregisterMenuCommand(HQTNHandle);

        HQTNHandle = GM_registerMenuCommand("[subs-page] Load HQ thumbnails (" + (HQTN ? "On" : "Off") + ") -click to change-", function(){
            HQTN = !HQTN;
            GM_setValue("HQTN", HQTN);
            SetHQTNHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
    function SetSubVideoContainerWidthHandle() {
        GM_unregisterMenuCommand(SubVideoContainerWidthHandle);

        SubVideoContainerWidthHandle = GM_registerMenuCommand("[subs-page] Video-renderer width (" + SubVideoContainerWidth + ") -click to change-", function(){
            SubVideoContainerWidth = CleanCSSValue(prompt("Set the width of a single video renderer on the page (use CSS units)\nNote: Currently values larger than the default (210px) make the thumbnails blurry, as youtube only loads 210px resolution images. I might make a workaround for this later.\nThe current value is: '" + SubVideoContainerWidth + "'"));
            GM_setValue("SubVideoContainerWidth", SubVideoContainerWidth);
            SetSubVideoContainerWidthHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
    function SetTrendingVideoContainerWidthHandle() {
        GM_unregisterMenuCommand(TrendingVideoContainerWidthHandle);

        TrendingVideoContainerWidthHandle = GM_registerMenuCommand("[trending-page] Video-renderer width (" + TrendingVideoContainerWidth + ") -click to change-", function(){
            TrendingVideoContainerWidth = CleanCSSValue(prompt("Set the width of a single video renderer on the page (use CSS units)\nThe current value is: '" + TrendingVideoContainerWidth + "'"));
            GM_setValue("TrendingVideoContainerWidth", TrendingVideoContainerWidth);
            SetTrendingVideoContainerWidthHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
    function SetSearchVideoContainerWidthHandle() {
        GM_unregisterMenuCommand(SearchVideoContainerWidthHandle);

        SearchVideoContainerWidthHandle = GM_registerMenuCommand("[search-results-page] Video-renderer width (" + SearchVideoContainerWidth + ") -click to change-", function(){
            SearchVideoContainerWidth = CleanCSSValue(prompt("Set the width of a single video renderer on the page (use CSS units)\nThe current value is: '" + SearchVideoContainerWidth + "'"));
            GM_setValue("SearchVideoContainerWidth", SearchVideoContainerWidth);
            SetSearchVideoContainerWidthHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
    function SetVideoContainerHorMarginHandle() {
        GM_unregisterMenuCommand(VideoContainerHorMarginHandle);

        VideoContainerHorMarginHandle = GM_registerMenuCommand("[all pages] Video-renderer horizontal margin (" + VideoContainerHorMargin + ") -click to change-", function(){
            VideoContainerHorMargin = CleanCSSValue(prompt("Set the horizontal margin of a single video renderer on the page. i.e. the space between videos (use CSS units)\nThe current value is: '" + VideoContainerHorMargin + "'"));
            GM_setValue("VideoContainerHorMargin", VideoContainerHorMargin);
            SetVideoContainerHorMarginHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
    function SetVideoContainerVerMarginHandle() {
        GM_unregisterMenuCommand(VideoContainerVerMarginHandle);

        VideoContainerVerMarginHandle = GM_registerMenuCommand("[all pages] Video-renderer vertical margin (" + VideoContainerVerMargin + ") -click to change-", function(){
            VideoContainerVerMargin = CleanCSSValue(prompt("Set the vertical margin of a single video renderer on the page. i.e. the space between videos (use CSS units)\nThe current value is: '" + VideoContainerVerMargin + "'"));
            GM_setValue("VideoContainerVerMargin", VideoContainerVerMargin);
            SetVideoContainerVerMarginHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
    function SetShowChannelIconNextToVideosOnHomePageHandle() {
        GM_unregisterMenuCommand(ShowChannelIconNextToVideosOnHomePageHandle);

        ShowChannelIconNextToVideosOnHomePageHandle = GM_registerMenuCommand("[homepage] Show channel icons next to videos (" + (ShowChannelIconNextToVideosOnHomePage ? "Yes" : "No") + ") -click to change-", function(){
            ShowChannelIconNextToVideosOnHomePage = !ShowChannelIconNextToVideosOnHomePage;
            GM_setValue("ShowChannelIconNextToVideosOnHomePage", ShowChannelIconNextToVideosOnHomePage);
            SetShowChannelIconNextToVideosOnHomePageHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
	function SetAutoExpandChannelVidContainersHandle() {
        GM_unregisterMenuCommand(AutoExpandChannelVidContainersHandle);

        AutoExpandChannelVidContainersHandle = GM_registerMenuCommand("[channel-page] Auto-expand horizontal video lists (" + (AutoExpandChannelVidContainers ? "Yes" : "No") + ") -click to change-", function(){
            AutoExpandChannelVidContainers = !AutoExpandChannelVidContainers;
            GM_setValue("AutoExpandChannelVidContainers", AutoExpandChannelVidContainers);
            SetAutoExpandChannelVidContainersHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }
    /*function SetSpaceEfficientSearchResultsHandle() {
        GM_unregisterMenuCommand(SpaceEfficientSearchResultsHandle);

        SpaceEfficientSearchResultsHandle = GM_registerMenuCommand("[search-results] Space efficient search results (" + (SpaceEfficientSearchResults ? "Yes" : "No") + ") -click to change-", function(){
            SpaceEfficientSearchResults = !SpaceEfficientSearchResults;
            GM_setValue("SpaceEfficientSearchResults", SpaceEfficientSearchResults);
            SetSpaceEfficientSearchResultsHandle();

            if(confirm('Press "OK" to refresh the page to apply new settings'))
                location.reload();
        });
    }*/
})();

QingJ © 2025

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