shumin-youtube

自用整合修改,部分代码和样式来自 https://greasyfork.org/zh-CN/scripts/420140 和 https://userstyles.org/styles/115362 ,版权属于原作者。

当前为 2024-03-09 提交的版本,查看 最新版本

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

You will need to install an extension such as Tampermonkey to install this script.

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name               shumin-youtube
// @namespace          http://tampermonkey.net/
// @version            1.2.0
// @description        自用整合修改,部分代码和样式来自 https://greasyfork.org/zh-CN/scripts/420140 和 https://userstyles.org/styles/115362 ,版权属于原作者。
// @author             qianjunlang
// @match              *://*.youtube.com/*
// @icon               https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @require            https://cdn.staticfile.org/jquery/3.3.1/jquery.min.js
// @grant              GM_setValue
// @grant              GM_getValue
// @run-at             document-start
// @noframes
// @license            MIT License
// ==/UserScript==
'use strict';

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


var css = [
	".ytp-play-progress {",
	"	background: linear-gradient(left,#FF0000,#FF7F00,#FFFF00,#00FF00,#0000FF,#4B0082,#8F00FF);",
	"	background: -moz-linear-gradient(left,#FF0000,#FF7F00,#FFFF00,#00FF00,#0000FF,#4B0082,#8F00FF);",
	"	background: -o-linear-gradient(left,#FF0000,#FF7F00,#FFFF00,#00FF00,#0000FF,#4B0082,#8F00FF);",
	"	background: -webkit-linear-gradient(left,#FF0000,#FF7F00,#FFFF00,#00FF00,#0000FF,#4B0082,#8F00FF);",
	"}",
	".ytp-hover-progress-light {",
	" 	background: linear-gradient(left,#FF8080,#FFBF80,#FFFF80,#80FF80,#8080FF,#A580C0,#C780FF);",
	"	background: -moz-linear-gradient(left,#FF8080,#FFBF80,#FFFF80,#80FF80,#8080FF,#A580C0,#C780FF);",
	"	background: -o-linear-gradient(left,#FF8080,#FFBF80,#FFFF80,#80FF80,#8080FF,#A580C0,#C780FF);",
	"	background: -webkit-linear-gradient(left,#FF8080,#FFBF80,#FFFF80,#80FF80,#8080FF,#A580C0,#C780FF);",
	"}",
	".ytp-unloaded-progress {",
	"	background: linear-gradient(left ,#191919, #4d4d4d, #4C0000, #4c3200, #4c4c00, #002600, #00004c, #260026, #36264c, #4d4d4d, #191919);",
	"  	background: -moz-linear-gradient(left ,#191919, #4d4d4d, #4C0000, #4c3200, #4c4c00, #002600, #00004c, #260026, #36264c, #4d4d4d, #191919);",
	"  	background: -o-linear-gradient(left ,#191919, #4d4d4d, #4C0000, #4c3200, #4c4c00, #002600, #00004c, #260026, #36264c, #4d4d4d, #191919);",
	"  	background: -webkit-linear-gradient(left ,#191919, #4d4d4d, #4C0000, #4c3200, #4c4c00, #002600, #00004c, #260026, #36264c, #4d4d4d, #191919);",
	"}",
	".ytp-load-progress {",
	"  background: rgba(90, 90, 90, .5);",
	"}"
].join("\n");
if (typeof GM_addStyle != "undefined") {
	GM_addStyle(css);
} else if (typeof PRO_addStyle != "undefined") {
	PRO_addStyle(css);
} else if (typeof addStyle != "undefined") {
	addStyle(css);
} else {
	var node = document.createElement("style");
	node.type = "text/css";
	node.appendChild(document.createTextNode(css));
	var heads = document.getElementsByTagName("head");
	if (heads.length > 0) {
		heads[0].appendChild(node);
	} else {
		// no head yet, stick it whereever
		document.documentElement.appendChild(node);
	}
}


//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


if (
    window.location.href.indexOf( "watch?v=" ) >= 0 ||
    window.location.href.indexOf( "/v/" ) >= 0 ||
    false
){

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    let cycle_id = setInterval(() => {
        if(
            $(".ytp-endscreen-previous").is(":visible") ||
            $(".ytp-endscreen-next").is(":visible") ||
            $(".ytp-endscreen-content").is(":visible") ||
            false
        ) {
            document.webkitCancelFullScreen();
            document.exitFullscreen();
            document.cancelFullScreen();
        }
    }, 1000);

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    document.addEventListener('keydown',(e)=>{
        if( 81==e.keyCode ){
            $(".YtSegmentedLikeDislikeButtonViewModelSegmentedButtonsWrapper button").first().click()
        }
    });

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    console.log("youtube Cover is loading");
    (async () => // onStart
    {
        let tryTimes = 0;
        while(true)
        {
            console.log("try load");
            if(document.querySelector("#start")!=null)
            {
                load();
                return;
            }
            if(++tryTimes>10) return;
            await delay(300);
        }
    })();


    function delay(ms = 0){return new Promise((r)=>{setTimeout(r, ms)})}

    function getXY(element)
    {
        let x = 0, y = 0;
        while (element)
        {
            x += element.offsetLeft - element.scrollLeft + element.clientLeft;
            y += element.offsetTop - element.scrollLeft + element.clientTop;
            element = element.offsetParent;
        }
        return {X: x, Y: y}
    }

    function checkImg(imgUrl)
    {
      return new Promise(function(resolve)
      {
          let img = new Image();
          img.src = imgUrl;
          img.onload = () => {resolve(img);}
      })
    }


    function load()
    {
        var div = document.createElement("div");
        div.style.marginLeft = "3em";
        div.innerHTML =`

        <!-- css -->
        <style>
            #ytCover {
                text-decoration: none;
                font-size: 1.1em;
                font-weight: bold;
                font-family: Roboto, Arial, sans-serif;
                color: var(--yt-spec-text-primary);
            }

            div.list {
                background-color: var(--yt-spec-brand-background-primary);
                border: 1px solid var(--yt-spec-10-percent-layer);
                padding: 0.5em 0;
                position: fixed;
                z-index: 114514;
                max-height: 40em;
                font-size: 10px
            }

            .linkBtn {
                text-decoration: none;
            }

            .list-item {
                text-align: center;
                font-size: 1.5em;
                color: var(--yt-spec-text-primary);
                background-color: var(--yt-spec-brand-background-primary);
                height: 2.5em;
                line-height: 2.5em;
            }
            .list-item:hover {
                background: #AAA;
                box-shadow: 0 4px 5px rgba(0, 0, 0, 0.2);
            }

            .slide {
                cursor: default
            }

            img#preview {
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                z-index: 2000;
                max-width: 100vw;
                max-height: 65vh;
                min-width: 40vw;
                border: 3px solid #FFF;
            }

            .list > button {
                border: none;
                padding: unset;
                width: inherit;
                cursor: pointer;
            }

        </style>

        <!-- html -->
        <div>
            <div class="slide" id="ytCover"></div>

            <div class="list" id="ytListHead" style="border-top: none; top: 4.8em; left: 19em;" hidden>

                <div class="list-item slide">1280x720+
                    <div class="list" style="border-left: none; width: 11.5em" hidden>
                        <a class="linkBtn" imgTag="maxresdefault"><div class="list-item">maxresdefault</div></a>
                        <a class="linkBtn" imgTag="maxres1"><div class="list-item">maxres1</div></a>
                        <a class="linkBtn" imgTag="maxres2"><div class="list-item">maxres2</div></a>
                        <a class="linkBtn" imgTag="maxres3"><div class="list-item">maxres3</div></a>
                    </div>
                </div>

                <div class="list-item slide">640x480
                    <div class="list" style="border-left: none; width: 8.5em" hidden>
                        <a class="linkBtn" imgTag="sddefault"><div class="list-item">sddefault</div></a>
                        <a class="linkBtn" imgTag="sd1"><div class="list-item">sd1</div></a>
                        <a class="linkBtn" imgTag="sd2"><div class="list-item">sd2</div></a>
                        <a class="linkBtn" imgTag="sd3"><div class="list-item">sd3</div></a>
                    </div>
                </div>

                <div class="list-item slide">480x360
                    <div class="list" style="border-left: none; width: 8.5em" hidden>
                        <a class="linkBtn" imgTag="hqdefault"><div class="list-item">hqdefault</div></a>
                        <a class="linkBtn" imgTag="hq1"><div class="list-item">hq1</div></a>
                        <a class="linkBtn" imgTag="hq2"><div class="list-item">hq2</div></a>
                        <a class="linkBtn" imgTag="hq3"><div class="list-item">hq3</div></a>
                    </div>
                </div>

                <div class="list-item slide">320x180
                    <div class="list" style="border-left: none; width: 8.5em" hidden>
                        <a class="linkBtn" imgTag="mqdefault"><div class="list-item">mqdefault</div></a>
                        <a class="linkBtn" imgTag="mq1"><div class="list-item">mq1</div></a>
                        <a class="linkBtn" imgTag="mq2"><div class="list-item">mq2</div></a>
                        <a class="linkBtn" imgTag="mq3"><div class="list-item">mq3</div></a>
                    </div>
                </div>

                <div class="list-item slide">120x90
                    <div class="list" style="border-left: none; width: 6.5em" hidden>
                        <a class="linkBtn" imgTag="default"><div class="list-item">default</div></a>
                        <a class="linkBtn" imgTag="1"><div class="list-item">1</div></a>
                        <a class="linkBtn" imgTag="2"><div class="list-item">2</div></a>
                        <a class="linkBtn" imgTag="3"><div class="list-item">3</div></a>
                    </div>
                </div>

                <button class="list-item">: <span id="previewSpan" style="font-weight: bold;">On</span></button>
            </div>
        </div>`

        document.querySelector("#start").append(div);
        var preview = document.createElement("img");
        preview.id = "preview";
        preview.hidden = true;
        document.body.append(preview);

        var ytC = document.querySelector("#ytCover");
        var ytLH = document.querySelector("#ytListHead");
        var Btns = document.querySelectorAll(".linkBtn");
        var previewBtn = document.querySelector(".list > button");
        var Lang = { cover: {en:"Cover", tc:"封面", sc:"封面"},
                   preview: {en:"Preview", tc:"圖片預覽", sc:"图片预览"},
                        on: {en:"On", tc:"開", sc:"开"},
                       off: {en:"Off", tc:"關", sc:"关"}};
        var usedLang;

        if (document.querySelector("html").lang.indexOf("zh")!=-1)
            {usedLang = document.querySelector("html").lang.indexOf("CN")!=-1?"sc":"tc";}
        else
            {usedLang = "en";}

        ytC.innerText = Lang.cover[usedLang];
        previewBtn.innerHTML = Lang.preview[usedLang] + previewBtn.innerHTML;
        ytLH.style.width = usedLang=="en"?"10em":"10.4em";

        window.onresize = () =>
        {
            ytLH.style.left = (getXY(ytC).X/10-1)+"em";
            if(window.innerWidth<1350)
            {
                if(window.innerWidth>850)div.style.marginLeft = 3*((window.innerWidth-500)/850) + "em";
                else div.style.marginLeft = "1em";
            }
            else
            {div.style.marginLeft = "3em";}
        }

        document.querySelectorAll(".list > .slide").forEach((e)=>
        {
            let list = e.querySelector(".list");
            e.onmouseenter = () =>
            {
                list.style.top = (getXY(e).Y/10-0.5)+"em";
                list.style.left = parseFloat(ytLH.style.left) + parseFloat(ytLH.style.width) + "em";
                list.hidden = false;
            };
            e.onmouseleave = () => {list.hidden = true;}
        });
        Btns.forEach((e)=>
        {
            e.onmouseenter = () =>
            {
                if(!GM_getValue("previewOn")) return;
                preview.hidden = false;
                preview.src = e.href;
            };
            e.onmouseleave = () => {preview.hidden = true;}
            e.target="_blank";
        });
        var previewSpan = document.querySelector("#previewSpan");

        var previewBtnChange = () =>
        {
            if (GM_getValue("previewOn"))
            {
                previewSpan.style.color = "green";
                previewSpan.innerText = Lang.on[usedLang];
            }
            else
            {
                previewSpan.style.color = "red";
                previewSpan.innerText = Lang.off[usedLang];
            }
        };
        previewBtnChange();
        previewBtn.onclick = () =>
        {
            GM_setValue("previewOn", !GM_getValue("previewOn"));
            previewBtnChange();
        };


        var hide;
        ytC.onmouseenter = () =>
        {
            hide = false;
            ytLH.hidden = false;
        };
        ytC.onmouseleave = async () =>
        {
            hide = true;
            await delay(500);
            ytLH.hidden = hide;
        };
        ytLH.onmouseenter = () =>
        {
            hide = false;
        };
        ytLH.onmouseleave = async () =>
        {
            hide = true;
            await delay(200);
            ytLH.hidden = hide;
        };


        var oldHref = null;
        new MutationObserver(() => // onUrlChange
        {
            if (oldHref != document.location.href)
            {
                oldHref = document.location.href

                let video_id = null;
                window.location.search.replace("?","").split('&').forEach((s)=>{if(s.startsWith("v=")){video_id=s.replace("v=","")};});
                ytC.hidden = (video_id == null);
                if (video_id == null) return;

                document.querySelectorAll(".list-item > .list").forEach((e)=>
                {
                    if (e.style.width=="6.5em") return;
                    let tempBtns = e.querySelectorAll(".linkBtn");
                    e.parentNode.hidden = true;
                    tempBtns.forEach((forEachBtn)=>
                    {
                        checkImg("https://i.ytimg.com/vi/" + video_id + "/" + forEachBtn.getAttribute("imgTag") + ".jpg").then((img)=>
                        {
                            let notHide = (img.width>120 && img.height>90);
                            forEachBtn.hidden = !notHide;
                            if(notHide) e.parentNode.hidden = false;
                        });
                    });
                });

                checkImg("https://i.ytimg.com/vi/" + video_id + "/mq1.jpg").then((img)=>
                {
                    document.querySelector("#ytListHead > div:nth-child(5)").querySelectorAll(".linkBtn").forEach((e)=>
                    {if(e.getAttribute("imgTag").indexOf("default")==-1) e.hidden=(img.width<=120 && img.height<=90);});
                });

                Btns.forEach((e)=>{e.href = "https://i.ytimg.com/vi/" + video_id + "/" + e.getAttribute("imgTag") + ".jpg";});
            }
        }).observe(document.body, {childList: true, subtree: true});

        console.log("done");
    }


//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

}