YouTube直播独轮车,随机独轮车,自动融入
// ==UserScript==
// @name Youtube直播独轮车-随机独轮车-自动融入
// @description YouTube直播独轮车,随机独轮车,自动融入
// @namespace http://tampermonkey.net/
// @version 2026-07-18-536
// @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
// @grant GM_setValue
// @grant GM_getValue
// @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") {
AutoIntegrate();
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 = "350px";
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 pageAutoInteragte = creatAutoIntegrateUI();
const menu = createMenuUI(pageDlc,pageRandomDlc,pageAutoInteragte);
Panel.appendChild(menu);
Panel.appendChild(pageDlc);
Panel.appendChild(pageRandomDlc);
Panel.appendChild(pageAutoInteragte);
document.body.appendChild(Panel);
return Panel;
}
function createMenuUI(page1,page2,page3){
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 btnAutoIntegrate = document.createElement("button");
btnAutoIntegrate.textContent = "自动融入";
[btnDLC, btnAuto, btnAutoIntegrate].forEach(btn => {
btn.style.flex = "1";// 平分宽度
btn.style.padding = "8px";
btn.style.cursor = "pointer";
});
btnDLC.onclick = () => {
showPage(page1,page2,page3);
};
btnAuto.onclick = () => {
showPage(page2,page1,page3);
};
btnAutoIntegrate.onclick = () => {
showPage(page3,page2,page1);
};
menu.append(btnDLC, btnAuto, btnAutoIntegrate);
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); // 每 * 秒发送一次
};
return pageDLC;
}
function createRandomDlcUI() {
const groups = [ ["组一随机一", "组一随机二","组一随机三"], ["组二随机一", "组二随机二", "组二随机三"], ["组三随机一", "组三随机二", "组三随机三"] ];
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";
select.style.flex = "1";
select.style.minWidth = "0";// 允许缩小,不会被内容撑开
select.style.width = "0";// 配合 flex 使用
select.style.textAlign = "left";// 文字靠左
const addBtn = document.createElement("button");
addBtn.textContent = "新增";
const delBtn = document.createElement("button");
delBtn.textContent = "删除当前";
row.append(select, addBtn, delBtn);
return {
row,
select,
addBtn,
delBtn
};
}
function refreshGroupItems(selectC, group) {
selectC.options.length = 0;
group.forEach((item, index) => {
let text;
if (item === "") {
text = "(空)";
} else if (item.length > 10) {
text = item.slice(0, 10) + "...";
} else {
text = item;
}
selectC.add(new Option(text, index));
});
}
function refreshGrops(selectG, selectC, groups) {
selectG.options.length = 0;
selectC.options.length = 0;
// 填充组
groups.forEach((group, index) => {
selectG.add(new Option(`组 ${index + 1}`, index));
});
}
function InitGrops(selectG, selectC, groups) {
selectG.options.length = 0;
selectC.options.length = 0;
// 填充组
groups.forEach((group, index) => {
selectG.add(new Option(`组 ${index + 1}`, index));
});
// 默认显示第一组
refreshGroupItems(selectC, groups[0]);
}
// 第一行
const row1 = createRow();
// 第二行
const row2 = createRow();
row1.select.onchange = () => {
refreshGroupItems(row2.select, groups[row1.select.selectedIndex]);
};
InitGrops(row1.select, row2.select, groups);
// 第三行
const textarea = document.createElement("textarea");
textarea.placeholder = "请输入内容...";
textarea.style.width = "100%";
textarea.style.height = "50px";
textarea.style.resize = "vertical";
textarea.style.boxSizing = "border-box";
page.append(row1.row,row2.row,textarea);
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 DLCrow = document.createElement("div");
DLCrow.style.display = "flex";
DLCrow.style.width = "100%";
CDinput.style.width = "30%";
DLCbutton.style.width = "70%";
DLCrow.append(CDinput, DLCbutton);
page.appendChild(DLCrow);
row1.addBtn.onclick = () => {
groups.push([""]);
refreshGrops(row1.select, row2.select, groups);
row1.select.selectedIndex = groups.length - 1;
refreshGroupItems(row2.select, groups[row1.select.selectedIndex]);
// 自动选中新建的组
};
row2.addBtn.onclick = () => {
const groupIndex = row1.select.selectedIndex;
if (groupIndex < 0) return;
// 新增一个空字符串
groups[groupIndex].push("");
// 刷新第二个下拉框
refreshGroupItems(row2.select, groups[groupIndex]);
// 自动选中新建项
row2.select.selectedIndex = groups[groupIndex].length - 1;
// 清空编辑框
textarea.value = "";
// 聚焦到输入框
textarea.focus();
};
row2.select.onchange = () => {
const groupIndex = Number(row1.select.value);
const msgIndex = Number(row2.select.value);
textarea.value = groups[groupIndex][msgIndex];
};
textarea.oninput = () => {
const groupIndex = Number(row1.select.value);
const msgIndex = Number(row2.select.value);
if (groups[groupIndex] && groups[groupIndex][msgIndex] !== undefined) {
groups[groupIndex][msgIndex] = textarea.value;
}
row2.select.options[msgIndex].text = textarea.value.slice(0, 10);
};
row1.delBtn.onclick = () => {
const groupIndex = row1.select.selectedIndex;
if (groupIndex < 0) return;
groups.splice(groupIndex, 1);
refreshGrops(row1.select, row2.select, groups);
if (groups.length > 0) {
row1.select.selectedIndex = Math.min(groupIndex, groups.length - 1);
refreshGroupItems(row2.select, groups[row1.select.selectedIndex]);
} else {
row2.select.innerHTML = "";
textarea.value = "";
}
};
row2.delBtn.onclick = () => {
const groupIndex = row1.select.selectedIndex;
const itemIndex = row2.select.selectedIndex;
if (groupIndex < 0 || itemIndex < 0) return;
// 从数组删除
groups[groupIndex].splice(itemIndex, 1);
// 刷新第二个下拉框
refreshGroupItems(row2.select, groups[groupIndex]);
// 清空 textarea(如果已经没有内容)
if (groups[groupIndex].length === 0) {
textarea.value = "";
} else {
// 重新选中一项
row2.select.selectedIndex = Math.min(itemIndex, groups[groupIndex].length - 1);
textarea.value = groups[groupIndex][row2.select.selectedIndex];
}
};
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: groups[row1.select.selectedIndex][Math.floor(Math.random() * groups[row1.select.selectedIndex].length)], time: Date.now() });
timer = setInterval(() => {
console.log("DLC发送"+groups[row1.select.selectedIndex][Math.floor(Math.random() * groups[row1.select.selectedIndex].length)]);
GM_setValue("SM2RR", { msg: groups[row1.select.selectedIndex][Math.floor(Math.random() * groups[row1.select.selectedIndex].length)], time: Date.now() });
}, CDinput.value*1000); // 每 * 秒发送一次
};
return page;
}
function creatAutoIntegrateUI(){
/* const page = document.createElement("div");
page.style.display = "none";
page.style.flexDirection = "column";
page.style.gap = "10px";
page.style.padding = "10px";
const headCountinput = document.createElement("input");
headCountinput.type = "number";
headCountinput.style.padding = "10px";
headCountinput.placeholder = "人数";
headCountinput.min = 0.01;
headCountinput.max = 100000;
headCountinput.style.minWidth = "0";
const chatCountinput = document.createElement("input");
chatCountinput.type = "number";
chatCountinput.style.padding = "10px";
chatCountinput.placeholder = "重复";
chatCountinput.min = 0.01;
chatCountinput.max = 100000;
chatCountinput.style.minWidth = "0";
const timeLimitInput = document.createElement("input");
timeLimitInput.type = "number";
timeLimitInput.style.padding = "10px";
timeLimitInput.placeholder = "时限";
timeLimitInput.min = 0.01;
timeLimitInput.max = 100000;
timeLimitInput.style.minWidth = "0";
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 AuItbutton = document.createElement("button");
AuItbutton.textContent = "自动融入启动";
AuItbutton.style.padding = "10px";
AuItbutton.style.cursor = "pointer";
const AuItrow = document.createElement("div");
AuItrow.style.display = "flex";
AuItrow.style.width = "100%";
headCountinput.style.width = "15%";
chatCountinput.style.width = "15%";
timeLimitInput.style.width = "15%";
CDinput.style.width = "15%";
AuItbutton.style.width = "40%";
AuItrow.append(headCountinput,chatCountinput,timeLimitInput,CDinput, AuItbutton);
page.appendChild(AuItrow);*/
const page = document.createElement("div");
page.style.display = "none";
page.style.flexDirection = "column";
page.style.gap = "10px";
page.style.padding = "10px";
const row1 = document.createElement("div");
row1.style.display = "flex";
row1.style.alignItems = "center";
row1.style.width = "100%";
row1.style.gap = "5px";
const row2 = document.createElement("div");
row2.style.display = "flex";
row2.style.alignItems = "center";
row2.style.width = "100%";
row2.style.gap = "5px";
function createInput(placeholder) {
const input = document.createElement("input");
input.type = "number";
input.style.padding = "5px";
input.placeholder = placeholder;
input.min = 0.01;
input.max = 100000;
input.style.width = "70px";
return input;
}
function text(content) {
const span = document.createElement("span");
span.textContent = content;
return span;
}
const headCountinput = createInput("");
headCountinput.style.width = "25px";
const timeLimitInput = createInput("");
timeLimitInput.style.width = "25px";
const chatCountinput = createInput("");
chatCountinput.style.width = "25px";
const CDinput = createInput("");
CDinput.style.width = "25px";
row1.append(
text("触发:"),
headCountinput,
text("人在"),
timeLimitInput,
text("秒内重复"),
chatCountinput,
text("次")
);
row2.append(
text("自动融入冷却"),
CDinput,
text("秒")
);
const AuItbutton = document.createElement("button");
AuItbutton.textContent = "自动融入启动";
AuItbutton.style.padding = "10px";
AuItbutton.style.cursor = "pointer";
page.append(row1, row2,AuItbutton);
let AuItstatus = false;
AuItbutton.onclick = () => {
if(!AuItstatus)
{
AuItbutton.style.background = "red";
AuItstatus = true;
GM_setValue("AutoIntegrateSwich", {
msg: "start",
HC: Number(headCountinput.value),
CC: Number(chatCountinput.value),
TL: Number(timeLimitInput.value),
CD: Number(CDinput.value),
time: Date.now()
});
}else{
AuItbutton.style.background = "white";
AuItstatus = false;
GM_setValue("AutoIntegrateSwich", { msg: "stop", time: Date.now() });
}
}
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 = "flex";
pageHide1.style.display = "none";
pageHide2.style.display = "none";
}
function changeShowHide(pageShow,pageHide){
pageShow.style.display = "flex";
pageHide.style.display = "none";
}
function UpdateChatComments(){
const chat = document.querySelector("#items");
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.tagName !== "YT-LIVE-CHAT-TEXT-MESSAGE-RENDERER") return;
const author = node.querySelector("#author-name")?.textContent.trim();
const text = node.querySelector("#message")?.textContent.trim();
console.log(author, ":", text);
});
});
});
observer.observe(chat, {
childList: true
});
}
function AutoIntegrate(){
let chat = document.querySelector("#items");
GM_addValueChangeListener("AutoIntegrateSwich", (name, oldValue, newValue) => {
if(newValue.msg==="start"){
chat = document.querySelector("#items");
startAutoCopy(newValue.HC,newValue.CC,newValue.TL,newValue.CD)
}
if(newValue.msg==="stop"){
stopAutoCopy();
}
});
const messageMap = new Map();
let observer = null;
let clearTimer = null;
function startAutoCopy(hc,cc,tl,cd) {
if (
hc == null || hc === "" || hc == 0 ||
cc == null || cc === "" || cc == 0 ||
tl == null || tl === "" || tl == 0 ||
cd == null || cd === "" || cd == 0
) {
console.log("不能有0和空");
return;
}
if (observer) return;
observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.tagName !== "YT-LIVE-CHAT-TEXT-MESSAGE-RENDERER") return;
const author = node.querySelector("#author-name")?.textContent.trim();
const text = node.querySelector("#message")?.textContent.trim();
console.log(author, ":", text);
let isSent = autoCopy(hc, cc, author, text);
if (isSent) {
console.log("暂停监听 10 秒");
observer.disconnect();
setTimeout(() => {
messageMap.clear();
observeChat();
console.log("恢复监听");
clearInterval(clearTimer); // 先取消旧的
clearTimer = setInterval(() => {
messageMap.clear();
console.log("messageMap 已清空");
}, tl*1000);
}, cd*1000);
}
});
});
});
observeChat();
// 每30秒清空一次
clearTimer = setInterval(() => {
messageMap.clear();
console.log("messageMap 已清空");
}, tl*1000);
console.log("AutoCopy Started");
}
function restartClearTimer() {
clearInterval(clearTimer); // 先取消旧的
clearTimer = setInterval(() => {
messageMap.clear();
console.log("messageMap 已清空");
}, 1000);
}
function observeChat() {
const chat = document.querySelector("#items");
if (!chat) return;
observer.observe(chat, {
childList: true
});
}
function stopAutoCopy() {
if (!observer) return;
observer.disconnect();
observer = null;
clearInterval(clearTimer);
clearTimer = null;
messageMap.clear();
console.log("AutoCopy Stopped");
}
function autoCopy(headcount, chatcount, author, message) {
if (!message || message.trim() === "") {
return;
}
if (!messageMap.has(message)) {
messageMap.set(message, {
users: new Set(),
count: 0
});
}
const data = messageMap.get(message);
data.count++;
data.users.add(author);
if (
data.users.size >= headcount &&
data.count >= chatcount
) {
console.log("自动发送:", message);
sendMessageToRealChatRoom(message);
messageMap.delete(message);
return true;
}
}
}
})();