// ==UserScript==
// @name 雨天的自动回复机器人
// @namespace http://tampermonkey.net/
// @version 0.0.1
// @description 获取bilibili的直播弹幕内容并自动发送回复弹幕
// @author 雨天lul
// @include /https?:\/\/live\.bilibili\.com\/?\??.*/
// @include /https?:\/\/live\.bilibili\.com\/\d+\??.*/
// @include /https?:\/\/live\.bilibili\.com\/(blanc\/)?\d+\??.*/
// @run-at document-start
// @require https://cdn.jsdelivr.net/gh/google/brotli@5692e422da6af1e991f9182345d58df87866bc5e/js/decode.js
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/pako_inflate.min.js
// @grant none
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js
// @license MIT
// ==/UserScript==
//填入自己的id,检测弹幕的时候过滤掉自己发送的弹幕
var selfId = '4955333';
var autoReply = false;
//cgd
(function () {
console.log('autoreply st')
const HEADER_SIZE = 16
const WS_BODY_PROTOCOL_VERSION_NORMAL = 0
const WS_BODY_PROTOCOL_VERSION_HEARTBEAT = 1
const WS_BODY_PROTOCOL_VERSION_DEFLATE = 2
const WS_BODY_PROTOCOL_VERSION_BROTLI = 3
const OP_HEARTBEAT_REPLY = 3
const OP_SEND_MSG_REPLY = 5
let textEncoder = new TextEncoder()
let textDecoder = new TextDecoder()
function main() {
if (window.bliveproxy) {
// 防止多次加载
return
}
initApi()
hook()
}
function initApi() {
window.bliveproxy = api
}
let api = {
addCommandHandler(cmd, handler) {
let handlers = this._commandHandlers[cmd]
if (!handlers) {
handlers = this._commandHandlers[cmd] = []
}
handlers.push(handler)
},
removeCommandHandler(cmd, handler) {
let handlers = this._commandHandlers[cmd]
if (!handlers) {
return
}
this._commandHandlers[cmd] = handlers.filter(item => item !== handler)
},
// 私有API
_commandHandlers: {},
_getCommandHandlers(cmd) {
// if (this._commandHandlers[cmd] != null) {
// console.log('HAND EXT ' + cmd);
// } else {
// console.log('HAND NE! ' + cmd);
// }
return this._commandHandlers[cmd] || null
}
}
function hook() {
window.WebSocket = new Proxy(window.WebSocket, {
construct(target, args) {
let obj = new target(...args)
return new Proxy(obj, proxyHandler)
}
})
}
let proxyHandler = {
get(target, property) {
let value = target[property]
if ((typeof value) === 'function') {
value = value.bind(target)
}
return value
},
set(target, property, value) {
if (property === 'onmessage') {
let realOnMessage = value
value = function (event) {
myOnMessage(event, realOnMessage)
}
}
target[property] = value
return value
}
}
function myOnMessage(event, realOnMessage) {
if (!(event.data instanceof ArrayBuffer)) {
realOnMessage(event)
return
}
let data = new Uint8Array(event.data)
function callRealOnMessageByPacket(packet) {
realOnMessage({ ...event, data: packet })
}
try {
handleMessage(data, callRealOnMessageByPacket)
} catch (e) {
console.log('handlemessage Error: ' + e.message)
// console.log(data)
}
}
function makePacketFromCommand(command) {
let body = textEncoder.encode(JSON.stringify(command))
return makePacketFromUint8Array(body, OP_SEND_MSG_REPLY)
}
function makePacketFromUint8Array(body, operation) {
let packLen = HEADER_SIZE + body.byteLength
let packet = new ArrayBuffer(packLen)
// 不需要压缩
let ver = operation === OP_HEARTBEAT_REPLY ? WS_BODY_PROTOCOL_VERSION_HEARTBEAT : WS_BODY_PROTOCOL_VERSION_NORMAL
let packetView = new DataView(packet)
packetView.setUint32(0, packLen) // pack_len
packetView.setUint16(4, HEADER_SIZE) // raw_header_size
packetView.setUint16(6, ver) // ver
packetView.setUint32(8, operation) // operation
packetView.setUint32(12, 1) // seq_id
let packetBody = new Uint8Array(packet, HEADER_SIZE, body.byteLength)
for (let i = 0; i < body.byteLength; i++) {
packetBody[i] = body[i]
}
return packet
}
function handleMessage(data, callRealOnMessageByPacket) {
let offset = 0
while (offset < data.byteLength) {
let dataView = new DataView(data.buffer, offset)
let packLen = dataView.getUint32(0)
// let rawHeaderSize = dataView.getUint16(4)
let ver = dataView.getUint16(6)
let operation = dataView.getUint32(8)
// let seqId = dataView.getUint32(12)
let body = new Uint8Array(data.buffer, offset + HEADER_SIZE, packLen - HEADER_SIZE)
if (operation === OP_SEND_MSG_REPLY) {
switch (ver) {
case WS_BODY_PROTOCOL_VERSION_NORMAL:
body = textDecoder.decode(body)
body = JSON.parse(body)
handleCommand(body, callRealOnMessageByPacket)
break
case WS_BODY_PROTOCOL_VERSION_DEFLATE:
body = pako.inflate(body)
handleMessage(body, callRealOnMessageByPacket)
break
case WS_BODY_PROTOCOL_VERSION_BROTLI:
body = BrotliDecode(body)
handleMessage(body, callRealOnMessageByPacket)
break
default: {
let packet = makePacketFromUint8Array(body, operation)
callRealOnMessageByPacket(packet)
break
}
}
} else {
let packet = makePacketFromUint8Array(body, operation)
callRealOnMessageByPacket(packet)
}
offset += packLen
}
}
function handleCommand(command, callRealOnMessageByPacket) {
if (command instanceof Array) {
for (let oneCommand of command) {
this.handleCommand(oneCommand)
}
return
}
let cmd = command.cmd || ''
let pos = cmd.indexOf(':')
if (pos != -1) {
cmd = cmd.substr(0, pos)
}
// console.log('!! ' + cmd);
let handlers = api._getCommandHandlers(cmd)
if (handlers) {
for (let handler of handlers) {
handler(command)
}
}
// console.log(command)
let packet = makePacketFromCommand(command)
callRealOnMessageByPacket(packet)
}
main()
setTimeout(() => {
//添加面板
var div = document.getElementById('control-panel-ctnr-box');
var btn = document.createElement('button');
btn.innerHTML = '自动回复:' + (autoReply ? '开' : '关');
btn.style.background = '#23ade5';
btn.style.color = 'white';
btn.style.cursor = 'pointer';;
btn.style.padding = '6px 12px';
btn.style.border = '0';
btn.style.borderRadius = '4px';
btn.id = 'autoReplyBtn';
div.appendChild(btn);
btn.addEventListener('click', () => {
autoReply = !autoReply;
btn.innerHTML = '自动回复:' + (autoReply ? '开' : '关');
});
}, 1000);
})();
async function sendDM(sendMsg) {
let shortUid = window.location.href.split('live.bilibili.com/')[1];
let room = await fetch(`http://api.live.bilibili.com/room/v1/Room/room_init?id=${shortUid}`, {
method: 'GET',
credentials: 'include'
})
let roomid = await room.json();
roomid = roomid['data']['room_id'];
let scrf = document.cookie.split(';').map(c => c.trim()).filter(c => c.startsWith('bili_jct='))[0].split('bili_jct=')[1];
let send = await fetch('https://api.live.bilibili.com/msg/send', {
method: 'POST',
credentials: 'include',
headers: {
'accept': 'application/json, text/javascript, */*; q=0.01',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: `color=16777215&fontsize=25&mode=1&msg=${sendMsg}&rnd=16082868&roomid=${roomid}&csrf_token=${scrf}&csrf=${scrf}`
});
let sendApiRes = await send.json();
if (sendApiRes['message'] !== "") {
console.log(`发送弹幕:【${sendMsg}】失败,原因:${sendApiRes['message']}。\n`);
} else {
console.log(`发送弹幕:【${sendMsg}】成功\n`);
};
}
(async function () {
bliveproxy.addCommandHandler('DANMU_MSG', command => {
console.log('get ' + command.info[1]);
if (autoReply) {
let info = command.info
console.log('info--DANMU_MSG')
console.log('user: ' + command.info[2][1] + ' : ' + command.info[2][0]);
console.log('cont: ' + command.info[1]);
var _dm = command.info[1];
var _userid = command.info[2][0];
var _username = command.info[2][1];
if (_userid == selfId.toString()) {
console.log('idok');
if (_dm.match(/确实/)) {
sendDM(_username + ', 确实');
}
// } else if (_username.match(/^[a-zA-Z\_]*$/)) {//纯英文id
// console.log('纯英文id: ' + _userid);
else if (_dm.match(/晚安/)) {
sendDM(_username + '晚安');
}
}
}
}
// if (command.info[1].toString().substr(0, 5) != 'reply')
// sendDM('reply-- ' + command.info[2][1])
);
bliveproxy.addCommandHandler('ROOM_REAL_TIME_MESSAGE_UPDATE', command => {
if (autoReply) {
let info = command
console.log('info--ROOM_REAL_TIME_MESSAGE_UPDATE ' + Object.keys(info.data))
console.log(Object.values(info.data));
console.log('');
}
});
// bliveproxy.addCommandHandler('NOTICE_MSG', command => {
// let info = command
// console.log('info--NOTICE_MSG ' + Object.keys(info.data))
// console.log(Object.values(info.data));
// console.log('');
// });
// bliveproxy.addCommandHandler('INTERACT_WORD', command => {
// let info = command
// console.log('info--INTERACT_WORD ' + Object.keys(info.data))
// console.log(Object.values(info.data));
// console.log('');
// });
// bliveproxy.addCommandHandler('STOP_LIVE_ROOM_LIST', command => {
// let info = command
// console.log('info--STOP_LIVE_ROOM_LIST ' + Object.keys(info.data))
// console.log(Object.values(info.data));
// console.log('');
// });
// bliveproxy.addCommandHandler('NOTICE_MSG', command => {
// let info = command
// console.log('info--NOTICE_MSG ' + Object.keys(info.data))
// console.log(Object.values(info.data));
// console.log('');
// });
})();