YouTube独轮车
// ==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";
}
})();