// ==UserScript==
// @name BiliOnlineHook
// @description B站直播间同接数显示,弹幕HOOK框架
// @namespace http://tampermonkey.net/
// @version 0.1.2
// @author jeffz615
// @match *://live.bilibili.com/*
// @match *://live.bilibili.com/blanc/*
// @icon https://live.bilibili.com/favicon.ico
// @run-at document-start
// @sandbox raw
// @license MIT
// ==/UserScript==
(function () {
'use strict';
function hook_wrapper() {
let g_rank_count = 0;
let g_online_count = 0;
function on_online_rank_count(obj) {
const rank_count = obj.data.count;
const online_count = obj.data.online_count;
let flag = false;
if (rank_count && rank_count !== g_rank_count) {
g_rank_count = rank_count;
flag = true;
}
if (online_count && online_count !== g_online_count) {
g_online_count = online_count;
flag = true;
}
if (flag) {
const showers = document.querySelectorAll("#rank-list-ctnr-box > div.tabs > ul > li.item");
if (showers.length > 0) {
const origin_text = showers[0].innerText.split('(')[0];
showers[0].innerText = origin_text + '(' + g_rank_count + '/' + g_online_count + ')';
showers[0].setAttribute('title', '除号左边是贡献值非0人数,右边是所有人数。' + (g_online_count === 0 ? '' : ('计算结果:' + (g_rank_count / g_online_count * 100).toFixed(2) + '%')));
}
}
}
function on_send_gift(obj) {
function calc_total_price(obj) {
return obj.data.coin_type === 'gold' ? (obj.data.total_coin / 1000).toFixed(2) : '0.00';
}
console.debug('[BiliOnlineHook] SEND_GIFT', obj.data.uid, obj.data.uname, obj.data.action, obj.data.giftName, 'x', obj.data.num,
calc_total_price(obj));
}
function on_danmu_msg(obj) {
if (obj.info.length === 0 || obj.info[0].length <= 16 || obj.info[0][16].activity_identity !== '') {
return;
}
/* uid, uname, msg */
console.debug('[BiliOnlineHook] DANMU_MSG', obj.info[2][0], obj.info[2][1], obj.info[1]);
}
function on_guard_buy(obj) {
/* uid, username, num, price, gift_name */
console.debug('[BiliOnlineHook] GUARD_BUY', obj.data.uid, obj.data.username, obj.data.num, obj.data.price, obj.data.gift_name);
}
function on_super_chat_message(obj) {
/* uid, uname, message, price, rmb */
console.debug('[BiliOnlineHook] SUPER_CHAT_MESSAGE', obj.data.uid, obj.data.uname, obj.data.message, obj.data.price, obj.data.rmb);
}
function on_interact_word(obj) {
/* uid, uname */
console.debug('[BiliOnlineHook] INTERACT_WORD', obj.data.uid, obj.data.uname);
}
function on_entry_effect(obj) {
/* uid, uinfo */
console.debug('[BiliOnlineHook] ENTRY_EFFECT', obj.data.uid, obj.data.uinfo.base.name);
}
function on_raw(obj) {
console.debug('[BiliOnlineHook]', obj);
}
const cb_map = {
"ONLINE_RANK_COUNT": on_online_rank_count,
"SEND_GIFT": on_send_gift,
"DANMU_MSG": on_danmu_msg,
"GUARD_BUY": on_guard_buy,
"SUPER_CHAT_MESSAGE": on_super_chat_message,
"ENTRY_EFFECT": on_entry_effect,
"INTERACT_WORD": on_interact_word,
};
function check_stack() {
const callstack = new Error().stack.split("\n");
if (callstack.length < 4) {
return false;
}
for (let call_func of callstack.slice(3)) {
if (call_func.includes(".convertToObject ")) {
continue;
} else if (call_func.includes(".onMessage ")) {
return true;
}
break;
}
return false;
}
const origin_parse = JSON.parse;
JSON.parse = function (...args) {
let result = origin_parse.apply(this, args);
if (result.cmd && check_stack()) {
const cb_func = cb_map[result.cmd];
try {
if (cb_func) cb_func(result);
} catch (err) {
}
}
return result;
}
}
hook_wrapper();
})();