// ==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); } })();