YoutubeDLC

YouTube独轮车

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

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

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Advertisement:

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

Advertisement:

// ==UserScript==
// @name         YoutubeDLC
// @description  YouTube独轮车
// @namespace    http://tampermonkey.net/
// @version      2026-07-17-3:08
// @author       奶糖花的绿冻兄弟
// @match https://www.youtube.com/watch*
// @match https://www.youtube.com/live_chat*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        GM_setValue
// @grant        GM_addValueChangeListener
// @license      MIT
// ==/UserScript==


(function() {
    'use strict';


    if (location.pathname === "/watch") {


        const observer = new MutationObserver(() => {

            if (document.querySelector("ytd-live-chat-frame")) {

                observer.disconnect();

                const panel = createPanel();

                createToggle(panel);

            }

        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });

    }

    if (location.pathname === "/live_chat") {
        GM_addValueChangeListener("SM2RR", (name, oldValue, newValue) => {
            sendMessageToRealChatRoom(newValue.msg);
        });
    }

    function createToggle(panel){

        const toggleBtn = document.createElement("button");

        toggleBtn.textContent = "独轮车";
        toggleBtn.style.display = "flex";
        toggleBtn.style.justifyContent = "center"; // 水平居中
        toggleBtn.style.alignItems = "center";// 垂直居中
        toggleBtn.style.position = "fixed";
        toggleBtn.style.right = "0px";
        toggleBtn.style.bottom = "5px";
        toggleBtn.style.width = "60px";
        toggleBtn.style.height = "25px";
        toggleBtn.style.cursor = "pointer";
        toggleBtn.style.backgroundColor = "red";
        toggleBtn.style.zIndex = 999999;
        toggleBtn.style.display = "flex";

        toggleBtn.onclick = () => {

            if (panel.style.display === "none") {
                panel.style.display = "flex"
            }else{
                panel.style.removeProperty("left");
                panel.style.removeProperty("top");

                panel.style.right = "20px";
                panel.style.bottom = "35px";
            }

        };


        document.body.appendChild(toggleBtn);

    }

    function createPanel(){
        const Panel = document.createElement("div");
        Panel.style.position = "fixed";
        Panel.style.right = "20px";
        Panel.style.bottom = "35px";
        Panel.style.width = "280px";
        Panel.style.background = "#222";
        Panel.style.color = "white";
        Panel.style.padding = "0px";
        Panel.style.borderRadius = "0px";
        Panel.style.display = "none";
        Panel.style.flexDirection = "column";
        Panel.style.zIndex = 999999;

        const TopRow = document.createElement("div");
        TopRow.style.display = "flex";
        TopRow.style.width = "100%";

        const title = document.createElement("div");
        title.textContent = "YouTube DLC";
        title.style.cursor = "move";
        title.style.padding = "8px";
        title.style.background = "red";
        title.style.flex = "0.9";

        const btnHide = document.createElement("button");
        btnHide.textContent = "-";
        btnHide.style.flex = "0.1";

        btnHide.onclick = () => {

            Panel.style.display = "none";

        };

        TopRow.append(title, btnHide);

        Panel.prepend(TopRow);

        //panel move

        let dragging = false;
        let offsetX = 0;
        let offsetY = 0;

        const mask = document.createElement("div");
        mask.style.position = "fixed";
        mask.style.left = "0";
        mask.style.top = "0";
        mask.style.width = "100vw";
        mask.style.height = "100vh";
        mask.style.zIndex = "999998";
        mask.style.background = "transparent";

        title.addEventListener("pointerdown", (e) => {

            document.body.appendChild(mask);
            dragging = true;

            const rect = Panel.getBoundingClientRect();

            // 转换为 left/top 定位
            Panel.style.left = rect.left + "px";
            Panel.style.top = rect.top + "px";

            Panel.style.right = "auto";
            Panel.style.bottom = "auto";

            offsetX = e.clientX - rect.left;
            offsetY = e.clientY - rect.top;

            e.preventDefault();
        });


        document.addEventListener("pointermove", (e) => {

            if (!dragging) return;

            Panel.style.left = (e.clientX - offsetX) + "px";
            Panel.style.top = (e.clientY - offsetY) + "px";

        });


        document.addEventListener("pointerup", () => {

            dragging = false;

            mask.remove();
        });

        //






        const pageDlc= createDlcUI();

        const pageRandomDlc = createRandomDlcUI();

        const menu = createMenuUI(pageDlc,pageRandomDlc);

        Panel.appendChild(menu);

        Panel.appendChild(pageDlc);
        Panel.appendChild(pageRandomDlc);



        document.body.appendChild(Panel);

        return Panel;
    }

    function createMenuUI(page1,page2){
        const menu = document.createElement("div");
        menu.style.padding = "10px 10px 5px 10px";
        menu.style.display = "flex";
        menu.style.borderBottom = "1px solid #555";

        const btnDLC = document.createElement("button");
        btnDLC.textContent = "独轮车";

        const btnAuto = document.createElement("button");
        btnAuto.textContent = "敬請期待";

        const btnSetting = document.createElement("button");
        btnSetting.textContent = "敬請期待";

        [btnDLC, btnAuto, btnSetting].forEach(btn => {

            btn.style.flex = "1";// 平分宽度
            btn.style.padding = "8px";
            btn.style.cursor = "pointer";

        });

        btnDLC.onclick = () => {
            changeShowHide(page1,page2);
        };

        btnAuto.onclick = () => {
            changeShowHide(page2,page1);
        };

        btnSetting.onclick = () => {
        };


        menu.append(btnDLC, btnAuto, btnSetting);

        return menu;
    }

    function createDlcUI() {
        //panel
        const pageDLC = document.createElement("div");
        pageDLC.style.padding = "5px 10px 10px 10px";
        pageDLC.style.display = "flex";
        pageDLC.style.flexWrap = "wrap";

        const input = document.createElement("input");

        input.type = "text";
        input.placeholder = "输入弹幕";

        input.style.width = "100%";
        input.style.padding = "10px";
        input.style.boxSizing = "border-box";

        pageDLC.appendChild(input);

        const button = document.createElement("button");
        button.textContent = "发送";
        button.style.padding = "10px";
        button.style.cursor = "pointer";
        button.style.width = "100%";
        pageDLC.appendChild(button);
        //
        const inputStyle = document.createElement("style");

        inputStyle.textContent = `input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button {display: none;}`;
        document.head.appendChild(inputStyle);

        const CDinput = document.createElement("input");
        CDinput.type = "number";
        CDinput.style.padding = "10px";
        CDinput.placeholder = "冷却秒数";
        CDinput.min = 0.01;
        CDinput.max = 100000;
        CDinput.style.minWidth = "0";

        const DLCbutton = document.createElement("button");
        DLCbutton.textContent = "独轮车启动";
        DLCbutton.style.padding = "10px";
        DLCbutton.style.cursor = "pointer";

        const row = document.createElement("div");
        row.style.display = "flex";
        row.style.width = "100%";

        CDinput.style.width = "30%";
        DLCbutton.style.width = "70%";


        row.append(CDinput, DLCbutton);

        pageDLC.appendChild(row);
        //
        button.onclick = () => {
            GM_setValue("SM2RR", { msg: input.value, time: Date.now() });
        };

        let timer = null;

        DLCbutton.onclick = () => {

            const value = CDinput.valueAsNumber;

            if (Number.isNaN(value)) {
                return;
            }

            if (timer) {
                // 已经在运行,不重复启动
                clearInterval(timer);
                timer = null;
                DLCbutton.textContent = "独轮车启动";
                DLCbutton.style.backgroundColor = "white";
                return;
            }


            DLCbutton.textContent = "独轮车启动中";
            DLCbutton.style.backgroundColor = "red";

            GM_setValue("SM2RR", { msg: input.value, time: Date.now() });

            timer = setInterval(() => {

                console.log("T发送");
                GM_setValue("SM2RR", { msg: input.value, time: Date.now() });

            }, CDinput.value*1000); // 每 1 秒发送一次

        };

        return pageDLC;
    }

    function createRandomDlcUI() {

        const page = document.createElement("div");
        page.style.display = "none";
        page.style.flexDirection = "column";
        page.style.gap = "10px";
        page.style.padding = "10px";

        function createRow() {

            const row = document.createElement("div");
            row.style.display = "flex";
            row.style.gap = "8px";
            row.style.alignItems = "center";

            const select = document.createElement("select");
            select.style.flex = "1";

            const addBtn = document.createElement("button");
            addBtn.textContent = "新增";

            const delBtn = document.createElement("button");
            delBtn.textContent = "删除当前";

            row.append(select, addBtn, delBtn);

            return {
                row,
                select,
                addBtn,
                delBtn
            };
        }

        // 第一行
        const row1 = createRow();
        row1.select.append(new Option("组1"));
        row1.select.append(new Option("组2"));
        row1.select.append(new Option("组3"));


        // 第二行
        const row2 = createRow();
        row2.select.append(new Option("随机弹幕1"));
        row2.select.append(new Option("随机弹幕2"))
        row2.select.append(new Option("随机弹幕3"))

        // 第三行
        const textarea = document.createElement("textarea");
        textarea.placeholder = "请输入内容...";
        textarea.style.width = "100%";
        textarea.style.height = "180px";
        textarea.style.resize = "vertical";
        textarea.style.boxSizing = "border-box";

        page.append(row1.row,row2.row,textarea);

        return page;
    }

    function sendMessageToRealChatRoom(msg) {

        const chatInput = document.querySelector(
            'yt-live-chat-text-input-field-renderer div[contenteditable]'
        );

        const sendButton = document.querySelector("#send-button button");

        if (!chatInput || !sendButton) {
            console.log("没找到聊天框");
            return;
        }

        chatInput.focus();

        chatInput.textContent = msg;

        chatInput.dispatchEvent(new InputEvent("input", {
            bubbles: true
        }));

        sendButton.click();
    }

    function showPage(pageShow,pageHide1,pageHide2) {

    pageShow.style.display = "block";
    pageHide1.style.display = "none";
    pageHide2.style.display = "none";


}

    function changeShowHide(pageShow,pageHide){
        pageShow.style.display = "flex";
        pageHide.style.display = "none";
    }


})();