B站直播间弹幕广播
// ==UserScript==
// @name B站直播间弹幕广播
// @namespace http://tampermonkey.net/
// @version 0.1
// @description B站直播间弹幕转发,需要用户已登录。若有滥用等问题概不负责,诶嘿。顺便关注一下小东人鱼和noworld吧~
// @author 太陽闇の力
// @match https://live.bilibili.com/*
// @grant none
// @require https://greasyfork.org/scripts/417560-bliveproxy/code/bliveproxy.js
// @require https://cdn.jsdelivr.net/npm/axios@0.21.0/dist/axios.min.js
// 命令分析参考自 https://segmentfault.com/a/1190000017328813
//界面参考自小东人鱼午安社五更耗纸 https://github.com/gokoururi-git/gachihelper/
// 弹幕api使用参考自 https://greasyfork.org/zh-CN/scripts/434726
// @license MIT
// ==/UserScript==
// 当前直播间号
const proomid = /(?!https:\/\/live.bilibili.com\/)\d+/.exec(window.location.href)[0];
(function() {
//-----------配置区----------
//0默认收起,1默认展开
let isunfold = 0;
// 转发对象的UID,也即转发谁的弹幕
let uid = 353039514;
// 要转发的直播间号,也即发到哪儿
let rooms = `
9806022
2077803
431458
145657
`.replace(/ /g, '').trim().split('\n');
// 设置弹幕的发送间隔(秒),默认1秒,指转发到直播间A,然后再转发到直播间B,中间的时间间隔
//如果设置太小,会因发送频率过快而被B站吞掉弹幕,将自动重发并且自动设置发送间隔为1秒(如果本来是1秒,将设置成1.5秒)
let inter = 1;
//-----------UI区----------
let unfold = ["展开","收起"];
// 总容器
const container = window.document.createElement('div');
container.style.cssText = 'width:218px;position:fixed;bottom:5px;right:60px;z-index:999;box-sizing:border-box;';
// 工具名称
const topTool = window.document.createElement('div');
topTool.innerText = '弹幕转发';
topTool.style.cssText = 'text-align:center;line-height:20px;width:100%;color:rgb(210,143,166);font-size:14px;';
// 最小化按钮
const collapseButton = window.document.createElement('button');
collapseButton.innerText = unfold[isunfold];
collapseButton.style.cssText = 'float:right;width:40px;height:20px;border:none;cursor:pointer;background-color:#1890ff;border-radius:1px;color:#ffffff;';
// 主窗口
const mainWindow = window.document.createElement('div');
mainWindow.style.cssText = 'width:100%;background-color:rgba(220, 192, 221, .5);padding:10px;box-sizing:border-box;';
if(isunfold==0){
mainWindow.style.display = "none";
}
// 直播间号输入框
const textArea = window.document.createElement('textarea');
textArea.placeholder = '转发的直播间号,换行分隔'
textArea.style.cssText = 'width:100%;height:60px;resize:none;outline:none;background-color:rgba(255,255,255,.5);';
// 按钮区容器
const buttonArea = window.document.createElement('div');
buttonArea.style.cssText = 'width:100%;height:30px;box-sizing:border-box;display:flex;';
// 开始按钮
const goButton = window.document.createElement('button');
goButton.innerText = '开始';
goButton.style.cssText = 'width:max-content;height:28px;padding:0 5px;margin-left:5px;';
//用户UID
const uidBox = window.document.createElement('input');
uidBox.placeholder = "输入用户uid";
uidBox.style.cssText = 'width:70px;height:28px;padding:0 5px;margin-left:5px;';
//发送间隔
const interBox = window.document.createElement('input');
interBox.value = 1;
interBox.placeholder = "间隔(秒";
interBox.style.cssText = 'width:40px;height:28px;padding:0 5px;margin-left:5px;';
// 组装
topTool.appendChild(collapseButton);
container.appendChild(topTool);
mainWindow.appendChild(textArea);
buttonArea.appendChild(uidBox);
buttonArea.appendChild(interBox);
buttonArea.appendChild(goButton);
mainWindow.appendChild(buttonArea);
container.appendChild(mainWindow);
window.document.body.appendChild(container);
// 显示逻辑控制
collapseButton.addEventListener('click', () => {
if (collapseButton.innerText === '收起') {
mainWindow.style.display = 'none';
collapseButton.innerText = '展开';
return;
}
if (collapseButton.innerText === '展开') {
mainWindow.style.display = 'block';
collapseButton.innerText = '收起';
return;
}
}, false);
function fadeOut(ele,time) {
let count = 20;
ele.style.opacity=1;
return setInterval(function() {
ele.style.opacity = ele.style.opacity - 1/count;
}, time/count);
}
function showmessage(intext) {
const div = window.document.createElement('div');
div.innerText = intext;
div.style.cssText = 'box-sizing:border-box;width:200px;height:40px;position:fixed;bottom:40px;left:50px;z-index:999;background-color:rgba(255, 255, 0,.2);border-radius:5px;color:#FF0000;font-size:medium;line-height:40px;text-align:center;';
window.document.body.appendChild(div);
let st = fadeOut(div, 2000);
if (inter == 1) {
inter = 1.5;
} else {
inter = 1;
}
setTimeout((ele) => {
clearInterval(st);
ele.remove();
}, 2000, div);
}
//-----------逻辑区区----------
// 主要逻辑为检测弹幕,转发弹幕
function hdl(command) {
let info = command.info
if (info[2][0] != uid) {
return;
}
let apiClient = axios.create({
baseURL: 'https://api.live.bilibili.com',
withCredentials: true
})
async function PostRequest(msg, roomid) {
let cookie = document.cookie;
let rnd = parseInt(+new Date() / 1000);
let ObjectCookie = objectCookies(cookie)
let data = new FormData()
data.append('bubble', 0)
data.append('color', 16777215)
data.append('fontsize', 25)
data.append('mode', 1)
data.append('rnd', rnd)
data.append('msg', msg)
data.append('roomid', roomid)
data.append('csrf', ObjectCookie.bili_jct)
data.append('csrf_token', ObjectCookie.bili_jct)
let ajaxObj = (await apiClient.post('/msg/send', data, {
cookie: cookie
})).data
return ajaxObj;
}
function objectCookies(cookie) {
var cookies = cookie.split(';');
var result = {};
for (var i = 0; i < cookies.length; i++) {
var keyvaluepair = cookies[i].split('=');
result[keyvaluepair[0].trim()] = keyvaluepair[1];
}
return result;
}
let depth = 0;
function send(msg, roomid) {
let resp = PostRequest(msg, roomid);
resp.then(res => {
if (res.msg == "您发送弹幕的频率过快") {
depth += 1;
showmessage(res.msg + ",正在重发");
setTimeout(send, 1000 * inter * rooms.length + depth, msg, roomid);
if (depth == 20) {
alert("弹幕转发:请刷新网页以确认网络是否处于正常状态");
}
}
})
};
for (let i = 0; i < rooms.length; i++) {
setTimeout(send, 1000 * inter * (i + 1), info[1], rooms[i]);
}
}
try{
goButton.addEventListener('click', () => {
if (goButton.innerText == '暂停') {
bliveproxy.removeCommandHandler('DANMU_MSG', hdl)
goButton.innerText = '开始';
return;
}
uid = uidBox.value;
if(uid==''){
showmessage("您未输入uid");
return;
}
rooms=textArea.value;
if(rooms==''){
showmessage("您未输入直播间号");
return;
}
rooms = textArea.value.replace(/ /g, '').trim().split('\n');
if (rooms.indexOf(proomid) > -1) {
showmessage("不能转发到所在直播间");
return;
}
bliveproxy.addCommandHandler('DANMU_MSG', hdl)
goButton.innerText = '暂停';
}, false);
}catch (e) {
alert('弹幕转发:发生未知错误\n' + e);
}
})();