// ==UserScript==
// @name B站直播心心助手
// @namespace http://tampermonkey.net/
// @version 7.4
// @description 我的我的 都是我的
// @author 逆回十六夜
// @license MIT License
// @include /https?:\/\/live\.bilibili\.com\/\d+\??.*/
// @require https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js
// @require https://cdn.bootcss.com/layer/2.4/layer.js
// @grant unsafeWindow
// @run-at document-start
// ==/UserScript==
let logSwitch = false; //控制开关
let NAME = 'IZAYOI';
let BAPI, MY_API, SmallHeart;
if (!logSwitch) {
console.log = () => {
};//关闭控制台输出
}
if (typeof unsafeWindow !== 'undefined') {
const safeWindow = window;
window = unsafeWindow; // eslint-disable-line no-global-assign
window.safeWindow = safeWindow;
}
let Info = {
roomId: undefined,
uid: undefined,
silver: undefined,
gold: undefined,
mobile_verify: undefined,
identification: undefined,
awardBlocked: undefined,
token: undefined,
};
$(function () {//DOM完毕,等待弹幕加载完成
let loadInfo = (delay) => {
setTimeout(function () {
if (BilibiliLive === undefined || parseInt(BilibiliLive.UID) === 0 || isNaN(parseInt(BilibiliLive.UID))) {
loadInfo(1000);
console.log('无配置信息');
} else {
Info.roomId = BilibiliLive.ROOMID;
Info.uid = BilibiliLive.UID;
console.log(Info);
init();
}
}, delay);
};
loadInfo(1000);
addStyle();//加载style
$('head').append('<link rel="stylesheet" type="text/css" href="https://cdn.bootcss.com/layer/2.4/skin/layer.css">');//加载layer样式
});
Array.prototype.remove = function (val) {
let index = this.indexOf(val);
if (index > -1) {
this.splice(index, 1);
}
};
function addStyle() {
$('head').append(`
<style>
.izayoi_input{
outline: none;
border: 1px solid #e9eaec;
background-color: #fff;
border-radius: 4px;
padding: 1px 0 0;
overflow: hidden;
font-size: 12px;
line-height: 19px;
width: 30px;
}
.izayoi_btn{
background-color: #23ade5;
color: #fff;
border-radius: 4px;
border: none;
padding: 5px;
cursor: pointer;
box-shadow: 0 0 2px #00000075;
}
.izayoi_fs{
border: 2px solid #d4d4d4;
}
</style>
`)
}
function init() {//API初始化
try {
BAPI = BilibiliAPI;
} catch (err) {
alert(`[${NAME}]BilibiliAPI初始化失败,请手动更改源`);
return;
}
let tk = getCookie('bili_jct');
BAPI.setCommonArgs(tk, '');// 设置token
Info.token = tk;
MY_API = {
CONFIG_DEFAULT: {
RANDOM_DELAY: true,
TIME_AREA_DISABLE: false,
TIME_AREA_START: 2,
TIME_AREA_END: 8,
RANDOM_SKIP: 0,
MAX_GIFT: 99999,
AUTO_EXCHANGE: true,
AUTO_SIGNIN: true,
AUTO_HEART: true,
SHARE: true,
AUTO_GROUP_SIGN: true,
},
CONFIG: {},
GIFT_COUNT: {
COUNT: 0,
LOVE_COUNT: 0,
CLEAR_TS: 0,
EXCHANGE_TS: 0,
SIGN_TS: 0,
SHARE_TS: 0,
AUTO_GROUP_SIGH_TS: 0,
},
init: function () {
let p = $.Deferred();
try {
MY_API.loadConfig().then(function () {
MY_API.chatLog('脚本载入配置成功', 'success');
p.resolve()
});
} catch (e) {
console.log('API初始化出错', e);
MY_API.chatLog('脚本初始化出错', 'warning');
p.reject()
}
return p
},
loadConfig: function () {
let p = $.Deferred();
try {
let config = JSON.parse(localStorage.getItem(`${NAME}_CONFIG`));
$.extend(true, MY_API.CONFIG, MY_API.CONFIG_DEFAULT);
for (let item in MY_API.CONFIG) {
if (!MY_API.CONFIG.hasOwnProperty(item)) continue;
if (config[item] !== undefined && config[item] !== null) MY_API.CONFIG[item] = config[item];
}
MY_API.loadGiftCount();//载入礼物统计
p.resolve()
} catch (e) {
console.log('API载入配置失败,加载默认配置', e);
MY_API.setDefaults();
p.reject()
}
return p
},
saveConfig: function () {
try {
localStorage.setItem(`${NAME}_CONFIG`, JSON.stringify(MY_API.CONFIG));
MY_API.chatLog('配置已保存');
console.log(MY_API.CONFIG);
return true
} catch (e) {
console.log('API保存出错', e);
return false
}
},
setDefaults: function () {
MY_API.CONFIG = MY_API.CONFIG_DEFAULT;
MY_API.saveConfig();
MY_API.chatLog('配置已重置为默认3秒后刷新页面');
setTimeout(() => {
window.location.reload()
}, 3000);
},
loadGiftCount: function () {
try {
let config = JSON.parse(localStorage.getItem(`${NAME}_GIFT_COUNT`));
for (let item in MY_API.GIFT_COUNT) {
if (!MY_API.GIFT_COUNT.hasOwnProperty(item)) continue;
if (config[item] !== undefined && config[item] !== null) MY_API.GIFT_COUNT[item] = config[item];
}
console.log(MY_API.GIFT_COUNT);
} catch (e) {
console.log('读取统计失败', e);
}
},
saveGiftCount: function () {
try {
localStorage.setItem(`${NAME}_GIFT_COUNT`, JSON.stringify(MY_API.GIFT_COUNT));
console.log('统计保存成功', MY_API.GIFT_COUNT);
return true
} catch (e) {
console.log('统计保存出错', e);
return false
}
},
addGift: function (count) {
MY_API.GIFT_COUNT.COUNT += count;
$('#giftCount span:eq(0)').text(MY_API.GIFT_COUNT.COUNT);
MY_API.saveGiftCount();
},
addLove: function (count) {
MY_API.GIFT_COUNT.LOVE_COUNT = parseInt(MY_API.GIFT_COUNT.LOVE_COUNT) + parseInt(count);
$('#giftCount span:eq(1)').text(MY_API.GIFT_COUNT.LOVE_COUNT);
MY_API.saveGiftCount();
},
creatSetBox: function () {//创建设置框
//添加按钮
let btn = $('<button class="izayoi_btn" style="opacity: .5;position: absolute;' +
'top: 128px; left: 0;z-index: 10;">隐藏信息</button>');
btn.click(function () {
$('.izayoiMsg').hide();
});
let div = $('<div>');
div.css({
'width': '400px',
'height': 'auto',
'position': 'absolute',
'top': '110px',
'right': '10px',
'background': 'rgb(248, 248, 248)',
'padding': '10px',
'z-index': '10',
'border-radius': '4px',
'overflow': 'hidden',
'box-shadow': '1px 1px 2px #00000075',
'display': 'none',
});
//添加按钮
let btn2 = $('<button id="izayoi_setting" class="izayoi_btn" style="opacity: .5;' +
'position: absolute;top: 128px; right: 0;z-index: 10;">设置界面</button>');
btn2.click(function () {
if (btn2.text() === '设置界面'){
div.fadeIn();
btn2.text('隐藏界面')
} else {
div.fadeOut();
btn2.text('设置界面')
}
});
$('.chat-history-panel').append(btn, btn2);
div.append(`
<fieldset class="izayoi_fs">
<legend>瓜子及签到</legend>
<div data-toggle="AUTO_SIGNIN">
<label style="cursor: pointer; margin: 5px auto;">
<input style="vertical-align: text-top;" type="checkbox">自动签到
</label>
</div>
<div data-toggle="AUTO_EXCHANGE">
<label style="cursor: pointer; margin: 5px auto;">
<input style="vertical-align: text-top;" type="checkbox">自动银瓜子换硬币(一天一个)
</label>
</div>
<div data-toggle="AUTO_HEART">
<label style="cursor: pointer; margin: 5px auto;">
<input style="vertical-align: text-top;" type="checkbox">自动后台挂心心
</label>
</div>
<div data-toggle="SHARE">
<label style="cursor: pointer; margin: 5px auto;">
<input style="vertical-align: text-top;" type="checkbox">自动分享视频(5点经验,不会出现在动态)
</label>
</div>
<div data-toggle="AUTO_GROUP_SIGN">
<label style="cursor: pointer; margin: 5px auto;">
<input style="vertical-align: text-top;" type="checkbox">自动应援团签到(相应勋章加10点亲密度)
</label>
</div>
</fieldset>
<fieldset class="izayoi_fs">
<legend>功能</legend>
<div data-toggle="BUY_BADGE">
<label style="cursor: pointer; margin: 5px auto; color: blue">
20硬币购买指定直播间勋章 直播间号:<input class="ID izayoi_input" style="width: 70px;" placeholder="房间ID" type="text">
</label>
<button data-action="buy" class="izayoi_btn">购买</button>
<br>↑和视频投币不一样 购买后的勋章无需领取 官方接口放心使用↑
</div>
</fieldset>
<fieldset class="izayoi_fs">
<legend>其他设置</legend>
<div><button data-action="reset" style="color: red;" class="izayoi_btn">重置所有为默认</button></div>
</fieldset>
<fieldset class="izayoi_fs">
<legend>说明</legend>
<span style="color: #cf00ff;">有问题私信</span><br>
</fieldset>
<fieldset class="izayoi_fs">
<legend>更新</legend>
<ul>
<li><span style="color: rgb(79,178,255);">8-28:优化挂心心模式,删除自动领瓜子,删除统计,整合库不用换源了</span></li>
<li><span style="color: rgb(79,178,255);">8-11:改回旧版挂心心模式</span></li>
<li><span style="color: rgb(79,178,255);">8-9:优化签到逻辑,改进直播流拦截,设置界面隐藏</span></li>
</ul>
</fieldset>
`);
$('.player-ctnr').append(div);
let checkList = [
'AUTO_SIGNIN',
'AUTO_EXCHANGE',
'AUTO_HEART',
'SHARE',
'AUTO_GROUP_SIGN',
];
for (let i of checkList) {//所有checkbox事件绑定
let input = div.find(`div[data-toggle="${i}"] input:checkbox`);
if (MY_API.CONFIG[i]) input.attr('checked', '');
input.change(function () {
MY_API.CONFIG[i] = $(this).prop('checked');
MY_API.saveConfig()
});
}
//事件绑定
div.find('button[data-action="reset"]').click(function () {//重置按钮
MY_API.setDefaults();
});
div.find('#giftCount [data-action="countReset"]').click(function () {//
MY_API.GIFT_COUNT = {
COUNT: 0,
LOVE_COUNT: 0,
CLEAR_TS: 0,
};
MY_API.saveGiftCount();
MY_API.chatLog('已清空3秒后刷新页面');
setTimeout(() => {
window.location.reload()
}, 3000);
});
div.find('div[data-toggle="BUY_BADGE"] [data-action="buy"]').click(function () {
let id = parseInt(div.find('div[data-toggle="BUY_BADGE"] .ID').val());
MY_API.buyBadge(id);
});
},
chatLog: function (text, type = 'info') {//自定义提示
let div = $("<div class='izayoiMsg'>");
let msg = $("<div>");
let ct = $('#chat-history-list');
let myDate = new Date();
msg.html(text);
div.text(myDate.toLocaleString());
div.append(msg);
div.css({
'text-align': 'center',
'border-radius': '4px',
'min-height': '30px',
'width': '256px',
'color': '#9585FF',
'line-height': '30px',
'padding': '0 10px',
'margin': '10px auto',
});
msg.css({
'word-wrap': 'break-word',
'width': '100%',
'line-height': '1em',
'margin-bottom': '10px',
});
switch (type) {
case 'warning':
div.css({
'border': '1px solid rgb(236, 221, 192)',
'color': 'rgb(218, 142, 36)',
'background': 'rgb(245, 235, 221) none repeat scroll 0% 0%',
});
break;
case 'success':
div.css({
'border': '1px solid rgba(22, 140, 0, 0.28)',
'color': 'rgb(69, 171, 69)',
'background': 'none 0% 0% repeat scroll rgba(16, 255, 0, 0.18)',
});
break;
case 'error':
div.css({
'border': '1px solid rgba(255, 0, 39, 0.28)',
'color': 'rgb(116,0,15)',
'background': 'none 0% 0% repeat scroll rgba(255, 0, 39, 0.18)',
});
break;
default:
div.css({
'border': '1px solid rgb(203, 195, 255)',
'background': 'rgb(233, 230, 255) none repeat scroll 0% 0%',
});
}
ct.find('#chat-items').append(div);//向聊天框加入信息
ct.scrollTop(ct.prop("scrollHeight"));//滚动到底部
},
blocked: false,
max_blocked: false,
listen: (roomId, uid, area = '本直播间') => {
BAPI.room.getConf(roomId).then((response) => {
console.log('服务器地址', response);
let wst = new BAPI.DanmuWebSocket(uid, roomId, response.data.host_server_list, response.data.token);
wst.bind((newWst) => {
wst = newWst;
MY_API.chatLog(`${area}弹幕服务器连接断开,尝试重连`, 'warning');
}, () => {
MY_API.chatLog(`连接弹幕服务器成功<br>房间号: ${roomId} 分区: ${area}`
, 'success');
}, () => {
if (MY_API.blocked) {
wst.close();
MY_API.chatLog(`进了小黑屋主动与弹幕服务器断开连接-${area}`, 'warning')
}
if (MY_API.max_blocked) {
wst.close();
MY_API.chatLog(`辣条最大值主动与弹幕服务器断开连接-${area}`, 'warning')
}
}, (obj) => {
if (inTimeArea(MY_API.CONFIG.TIME_AREA_START, MY_API.CONFIG.TIME_AREA_END) && MY_API.CONFIG.TIME_AREA_DISABLE) return;//当前是否在两点到八点 如果在则返回
console.log('弹幕公告' + area, obj);
switch (obj.cmd) {
case 'GUARD_MSG':
if (obj.roomid === obj.real_roomid) {
MY_API.checkRoom(obj.roomid, area);
} else {
MY_API.checkRoom(obj.roomid, area);
MY_API.checkRoom(obj.real_roomid, area);
}
break;
case 'PK_BATTLE_SETTLE_USER':
if (!!obj.data.winner) {
MY_API.checkRoom(obj.data.winner.room_id, area);
} else {
MY_API.checkRoom(obj.data.my_info.room_id, area);
}
break;
case 'NOTICE_MSG':
if (obj.roomid === obj.real_roomid) {
MY_API.checkRoom(obj.roomid, area);
} else {
MY_API.checkRoom(obj.roomid, area);
MY_API.checkRoom(obj.real_roomid, area);
}
break;
default:
return;
}
});
}, () => {
MY_API.chatLog('获取弹幕服务器地址错误', 'warning')
});
},
RoomId_list: [],
err_roomId: [],
checkRoom: function (roomId, area = '本直播间') {
if (roomId === undefined) return;
if (MY_API.blocked || MY_API.max_blocked) {
return
}
if (MY_API.RoomId_list.indexOf(roomId) >= 0) {//防止重复检查直播间
return
} else {
MY_API.RoomId_list.push(roomId);
}
BAPI.room.room_entry_action(roomId);//直播间进入记录
$.get('https://api.live.bilibili.com/xlive/lottery-interface/v1/lottery/Check?roomid=' + roomId,
function (re) {
setTimeout(() => {
MY_API.RoomId_list.remove(roomId);//移除房间号
// console.log('防重复检查房间号列表', MY_API.RoomId_list);
}, 5e3);
console.log('检查房间返回信息', re);
let data = re.data;
if (re.code === 0) {
let list;
if (data.gift) {
list = data.gift;
for (let i in list) {
if (!list.hasOwnProperty(i)) continue;
MY_API.creat_join(roomId, list[i], 'gift', area)
}
}
if (data.guard) {
list = data.guard;
for (let i in list) {
if (!list.hasOwnProperty(i)) continue;
MY_API.creat_join(roomId, list[i], 'guard', area)
}
}
if (data.pk) {
list = data.pk;
for (let i in list) {
if (!list.hasOwnProperty(i)) continue;
MY_API.creat_join(roomId, list[i], 'pk', area)
}
}
} else {
if (MY_API.err_roomId.indexOf(roomId) > -1) {
console.log(`[检查此房间出错多次]${roomId}${re.message}`);
} else {
MY_API.err_roomId.push(roomId);
MY_API.checkRoom(roomId, area);
console.log(`[检查房间出错_重试一次]${roomId}${re.message}`);
}
}
});
},
Id_list_history: {
add: function (id, type) {
let id_list = [];
try {
let config = JSON.parse(localStorage.getItem(`${NAME}_${type}Id_list`));
id_list = [].concat(config.list);
id_list.push(id);
if (id_list.length > 1000) {
id_list.splice(0, 200);//删除前200条数据
}
localStorage.setItem(`${NAME}_${type}Id_list`, JSON.stringify({list: id_list}));
console.log(`${NAME}_${type}Id_list_add`, id_list);
} catch (e) {
id_list.push(id);
localStorage.setItem(`${NAME}_${type}Id_list`, JSON.stringify({list: id_list}));
}
},
isIn: function (id, type) {
let id_list = [];
try {
let config = JSON.parse(localStorage.getItem(`${NAME}_${type}Id_list`));
if (config === null) {
id_list = [];
} else {
id_list = [].concat(config.list);
}
console.log(`${NAME}_${type}Id_list_read`, config);
return id_list.indexOf(id) > -1
} catch (e) {
localStorage.setItem(`${NAME}_${type}Id_list`, JSON.stringify({list: id_list}));
console.log('读取' + `${NAME}_${type}Id_list` + '缓存错误已重置');
return id_list.indexOf(id) > -1
}
}
},
raffleId_list: [],
guardId_list: [],
pkId_list: [],
creat_join: function (roomId, data, type, area = '本直播间') {
console.log('礼物信息', data);
if (MY_API.GIFT_COUNT.COUNT >= MY_API.CONFIG.MAX_GIFT) {//判断是否超过辣条限制
console.log('超过今日辣条限制,不参与抽奖');
MY_API.max_blocked = true;
return
}
switch (type) {//防止重复抽奖上船PK
case 'gift':
if (MY_API.Id_list_history.isIn(data.raffleId, 'raffle')) {
console.log('礼物重复');
return
} else {
MY_API.raffleId_list.push(data.raffleId);
MY_API.Id_list_history.add(data.raffleId, 'raffle');
}
break;
case 'guard':
if (MY_API.Id_list_history.isIn(data.id, 'guard')) {
console.log('舰长重复');
return
} else {
MY_API.guardId_list.push(data.id);
MY_API.Id_list_history.add(data.id, 'guard');
}
break;
case 'pk':
if (MY_API.Id_list_history.isIn(data.id, 'pk')) {
console.log('pk重复');
return
} else {
MY_API.pkId_list.push(data.id);
MY_API.Id_list_history.add(data.id, 'pk');
}
break;
}
let delay = data.time_wait || 0;
if (MY_API.CONFIG.RANDOM_DELAY) delay += 2 + Math.ceil(Math.random() * 8);//随机延迟
let div = $("<div class='izayoiMsg'>");
let msg = $("<div>");
let aa = $("<div>");
let ct = $('#chat-history-list');
let myDate = new Date();
msg.text(`[${area}]` + data.thank_text.split('<%')[1].split('%>')[0] + data.thank_text.split('%>')[1]);
div.text(myDate.toLocaleString());
div.append(msg);
aa.css('color', 'red');
msg.append(aa);
div.css({
'text-align': 'center',
'border-radius': '4px',
'min-height': '30px',
'width': '256px',
'color': '#9585FF',
'line-height': '30px',
'padding': '0 10px',
'margin': '10px auto',
});
msg.css({
'word-wrap': 'break-word',
'width': '100%',
'line-height': '1em',
'margin-bottom': '10px',
});
div.css({
'border': '1px solid rgb(203, 195, 255)',
'background': 'rgb(233, 230, 255) none repeat scroll 0% 0%',
});
ct.find('#chat-items').append(div);//向聊天框加入信息
ct.scrollTop(ct.prop("scrollHeight"));//滚动到底部
let run = () => {
aa.text(`等待抽奖倒计时${delay}秒`);
if (delay <= 0) {
if (probability(MY_API.CONFIG.RANDOM_SKIP)) {
aa.text(`跳过此礼物抽奖`);
} else {
switch (type) {
case 'gift':
MY_API.lineUpCall(aa, MY_API.gift_join, roomId, data.raffleId, data.type).then(function (msg, num) {
aa.css('color', 'green');
aa.text('获得' + msg);
if (num) {
if (msg.indexOf('辣条') > -1) {
MY_API.addGift(num);
} else if (msg.indexOf('亲密度') > -1) {
MY_API.addLove(num);
}
}
MY_API.raffleId_list.remove(data.raffleId);//移除礼物id列表
});
break;
case 'guard':
MY_API.lineUpCall(aa, MY_API.guard_join, roomId, data.id).then(function (msg, num) {
aa.css('color', 'green');
aa.text('获得' + msg);
if (num) {
if (msg.indexOf('辣条') > -1) {
MY_API.addGift(num);
} else if (msg.indexOf('亲密度') > -1) {
MY_API.addLove(num);
}
}
MY_API.guardId_list.remove(data.id);//移除礼物id列表
});
break;
case 'pk':
MY_API.lineUpCall(aa, MY_API.pk_join, roomId, data.id).then(function (msg, num) {
aa.css('color', 'green');
aa.text('获得' + msg);
if (num) {
if (msg.indexOf('辣条') > -1) {
MY_API.addGift(num);
} else if (msg.indexOf('亲密度') > -1) {
MY_API.addLove(num);
}
}
MY_API.pkId_list.remove(data.id);//移除礼物id列表
});
break;
}
}
clearInterval(timer)
}
delay--;
};
let timer = setInterval(run, 1000);
run();
},
gift_join: function (roomid, raffleId, type) {
let p = $.Deferred();
BAPI.Lottery.Gift.join(roomid, raffleId, type).then((response) => {
console.log('抽奖返回信息', response);
switch (response.code) {
case 0:
if (response.data.award_text) {
p.resolve(response.data.award_text, response.data.award_num);
} else {
p.resolve(response.data.award_name + 'X' + response.data.award_num.toString()
, response.data.award_num);
}
break;
default:
if (response.msg.indexOf('拒绝') > -1) {
MY_API.blocked = true;//停止抽奖
p.resolve('访问被拒绝,您的帐号可能已经被关小黑屋,已停止');
} else {
p.resolve(`[礼物抽奖](roomid=${roomid},id=${raffleId},type=${type})${response.msg}`);
}
}
});
return p
},
guard_join: function (roomid, Id) {
let p = $.Deferred();
BAPI.Lottery.Guard.join(roomid, Id).then((response) => {
console.log('上船抽奖返回信息', response);
switch (response.code) {
case 0:
if (response.data.award_text) {
p.resolve(response.data.award_text, response.data.award_num);
} else {
p.resolve(response.data.award_name + 'X' + response.data.award_num.toString()
, response.data.award_num);
}
break;
default:
if (response.msg.indexOf('拒绝') > -1) {
MY_API.blocked = true;//停止抽奖
p.resolve('访问被拒绝,您的帐号可能已经被关小黑屋,已停止');
} else {
p.resolve(`[上船](roomid=${roomid},id=${Id})${response.msg}`);
}
break;
}
});
return p
},
pk_join: function (roomid, Id) {
let p = $.Deferred();
BAPI.Lottery.Pk.join(roomid, Id).then((response) => {
console.log('PK抽奖返回信息', response);
switch (response.code) {
case 0:
if (response.data.award_text) {
p.resolve(response.data.award_text, response.data.award_num);
} else {
p.resolve(response.data.award_name + 'X' + response.data.award_num.toString()
, response.data.award_num);
}
break;
default:
if (response.msg.indexOf('拒绝') > -1) {
MY_API.blocked = true;//停止抽奖
p.resolve('访问被拒绝,您的帐号可能已经被关小黑屋,已停止');
} else {
p.resolve(`[PK](roomid=${roomid},id=${Id})${response.msg}`);
}
break;
}
});
return p
},
Exchange: {
run: () => {
try {
return MY_API.Exchange.silver2coin().then(() => {
}, () => delayCall(() => MY_API.Exchange.run()));
} catch (err) {
MY_API.chatLog('[银瓜子换硬币]运行时出现异常,已停止', 'error');
console.error(`[${NAME}]`, err);
return $.Deferred().reject();
}
},
silver2coin: () => {
return BAPI.Exchange.silver2coin().then((response) => {
console.log('Exchange.silver2coin: API.SilverCoinExchange.silver2coin', response);
if (response.code === 0) {
// 兑换成功
MY_API.chatLog(`[银瓜子换硬币]${response.msg}`, 'success');
} else if (response.code === 403) {
// 每天最多能兑换 1 个
// 银瓜子余额不足
MY_API.chatLog(`[银瓜子换硬币]${response.msg}`, 'info');
} else {
MY_API.chatLog(`[银瓜子换硬币]${response.msg}`, 'caution');
}
}, () => {
MY_API.chatLog('[银瓜子换硬币]兑换失败,请检查网络', 'error');
return delayCall(() => MY_API.Exchange.silver2coin());
});
}
},
lineList: [],
lineDelay: 0,
reSetDelay: function () {
this.lineDelay = this.CONFIG.LINE_DELAY;
let timer = setInterval(() => {
if (this.lineDelay > 0.15) {
this.lineDelay -= 0.1;
} else {
this.lineDelay = 0;
clearInterval(timer);
}
}, 100)
},
lineUpCall: function (div, fun, arg1, arg2, arg3, arg4, arg5, arg6) {
let p = $.Deferred();
let delayRunTimer;
let delayRun = () => {
if (this.lineDelay === 0) {
run();
} else {
delayRunTimer = setInterval(() => {
if (this.lineDelay === 0) {
run();
clearInterval(delayRunTimer);
} else {
div.css('color', '#b700ff');
div.text(`抽奖等待中...${this.lineDelay.toFixed(1)}S`);
}
}, 100)
}
};
let run = () => {
this.lineList.shift();//删除第一个
this.reSetDelay();//重置冷却
div.text(`进行抽奖...`);
let funRt = fun(arg1, arg2, arg3, arg4, arg5, arg6);
if (funRt && funRt.then) funRt.then((arg1, arg2, arg3, arg4, arg5, arg6) => p.resolve(arg1, arg2, arg3, arg4, arg5, arg6));
else p.resolve();
if (this.lineList.length !== 0) this.lineList[0]();
};
if (this.CONFIG.LINE_DELAY === 0) {//如果为延迟0则直接运行
run();
} else if (this.lineList.length === 0) {
this.lineList.push(delayRun);
delayRun();
} else {
this.lineList.push(delayRun);
div.css('color', '#00b5e5');
div.text(`排队中...`);
}
return p
},
sendBagGift: function () {
BAPI.gift.bag_list().then(function (bagResult) {
if (bagResult.data.list[0].corner_mark === '1天' && bagResult.data.list[0].gift_name === '辣条') {
BAPI.live_user.get_anchor_in_room(MY_API.CONFIG.GIFT_ROOM).then(function (roomResult) {
bagSend(roomResult.data.info.uid,
bagResult.data.list[0].gift_id,
bagResult.data.list[0].bag_id,
bagResult.data.list[0].gift_num)
});
}
});
let bagSend = (rUid, gift_id, bag_id, num) => {
let ts = Math.round(new Date() / 1000);//时间戳
BAPI.gift.bag_send(Info.uid, gift_id, rUid, num, bag_id, MY_API.CONFIG.GIFT_ROOM, ts).then(function (result) {
if (result.code === 0 && result.msg === 'success') {
MY_API.chatLog('[只剩1天辣条]' + result.data.send_tips, 'success');
} else {
MY_API.chatLog('[礼物]赠送失败', 'warning');
}
});
}
},
buyBadge: function (roomId) {
BAPI.live_user.get_anchor_in_room(roomId).then(function (roomResult) {
if (roomResult.code === 0) {
if (confirm(`提示:该房间主播是${roomResult.data.info.uname} 确定购买勋章吗?`)) {
MY_API.buyRequest(roomResult.data.info.uid).then(function (data) {
MY_API.chatLog(`购买勋章${data.code === 0 ? '成功' : `失败 code ${data.code} ${data.message}`}`)
}, function () {
MY_API.chatLog(`购买勋章出错`)
});
}
} else {
MY_API.chatLog('检测房间出错,你确定是正确房间ID?');
}
});
},
buyRequest: function (uid) {
let p = $.Deferred();
$.ajax({
url: '//api.vc.bilibili.com/link_group/v1/member/buy_medal',
method: 'POST',
data: {
coin_type: 'metal',
master_uid: uid,
platform: 'android',
csrf_token: Info.token,
csrf: Info.token
},
success: function (result) {
p.resolve(result);
},
error: function () {
p.reject();
},
crossDomain: true,
dataType: 'json',
xhrFields: {
withCredentials: true,
},
});
return p
},
share: async () => {
if (!MY_API.CONFIG.SHARE) return $.Deferred().resolve();
if (!checkNewDay(MY_API.GIFT_COUNT.SHARE_TS)) {
console.log(`[${NAME}]无需分享`);
return
}
let response = await BAPI.dynamic_svr.dynamic_new(Info.uid, 8).catch(() => {
console.log('获取"动态-投稿视频"失败,请检查网络', 'error');
});
let aid = 0;
if (response.code === 0) {
if (!!response.data.cards) {
let obj = JSON.parse(response.data.cards[0].card);
aid = obj.aid;
BAPI.DailyReward.share(aid).then((response) => {
if (response.code === 0) {
MY_API.chatLog(`[每日分享]分享成功(av=${aid})`, 'success');
MY_API.GIFT_COUNT.SHARE_TS = ts_ms();
MY_API.saveGiftCount();
} else if (response.code === 71000) {
// 重复分享
MY_API.chatLog('[每日分享]今日分享已完成', 'info');
MY_API.GIFT_COUNT.SHARE_TS = ts_ms();
MY_API.saveGiftCount();
} else {
MY_API.chatLog(`[每日分享]'${response.msg}`, 'warning');
}
}, () => {
MY_API.chatLog('[每日分享]分享失败,请检查网络', 'error');
return delayCall(() => MY_API.share(aid));
});
} else {
console.log('"动态-投稿视频"中暂无动态', 'info');
}
} else {
console.log(`获取"动态-投稿视频"'${response.msg}`, 'caution');
}
},
GroupSign: {//修改自SeaLoong大神的代码
getGroups: () => {//获取应援团列表
return BAPI.Group.my_groups().then((response) => {
if (response.code === 0) return $.Deferred().resolve(response.data.list);
MY_API.chatLog(`[自动应援团签到]'${response.msg}`, 'warning');
return $.Deferred().reject();
}, () => {
MY_API.chatLog('[自动应援团签到]获取应援团列表失败,请检查网络', 'error');
return delayCall(() => MY_API.GroupSign.getGroups());
});
},
signInList: (list, i = 0) => {//应援团签到
if (i >= list.length) return $.Deferred().resolve();
const obj = list[i];
//自己不能给自己的应援团应援
if (obj.owner_uid === Info.uid) return MY_API.GroupSign.signInList(list, i + 1);
return BAPI.Group.sign_in(obj.group_id, obj.owner_uid).then((response) => {
let p = $.Deferred();
if (response.code === 0) {
if (response.data.add_num > 0) {// || response.data.status === 1
MY_API.chatLog(`[自动应援团签到]应援团${obj.group_name}签到成功,当前勋章亲密度+${response.data.add_num}`, 'success');
p.resolve();
} else if (response.data.add_num === 0) {
MY_API.chatLog(`[自动应援团签到]应援团${obj.group_name}已签到`, 'success');
p.resolve();
} else {
MY_API.chatLog(`[自动应援团签到]应援团${obj.group_name}错误亲密度${response.data.add_num}`, 'error');
p.reject();
}
} else {
MY_API.chatLog(`[自动应援团签到]'${response.msg}`, 'warning');
return p.reject();
}
return $.when(MY_API.GroupSign.signInList(list, i + 1), p);
}, () => {
MY_API.chatLog(`[自动应援团签到]应援团${obj.group_name}签到失败,请检查网络`, 'error');
return delayCall(() => MY_API.GroupSign.signInList(list, i));
});
},
run: () => {//执行应援团任务
try {
if (!MY_API.CONFIG.AUTO_GROUP_SIGN) return $.Deferred().resolve();
if (!checkNewDay(MY_API.GIFT_COUNT.AUTO_GROUP_SIGH_TS)) {
console.log(`[${NAME}]应援团无需签到`);
return $.Deferred().resolve();
} else if (new Date().getHours() < 8 && MY_API.GIFT_COUNT.AUTO_GROUP_SIGH_TS !== 0) {
MY_API.chatLog('应援团8点前不签到');
return $.Deferred().resolve();
}
return MY_API.GroupSign.getGroups().then((list) => {
console.log(`[${NAME}]应援团列表获取成功${list}`);
return MY_API.GroupSign.signInList(list).then(() => {
MY_API.GIFT_COUNT.AUTO_GROUP_SIGH_TS = ts_ms();
MY_API.saveGiftCount();//保存签到时间
console.log(`[${NAME}]应援团签到完成`);
return $.Deferred().resolve();
}, () => delayCall(() => MY_API.GroupSign.run()));
}, () => delayCall(() => MY_API.GroupSign.run()));
} catch (err) {
MY_API.chatLog('[自动应援团签到]运行时出现异常,已停止', 'error');
console.error(`[${NAME}]`, err);
return $.Deferred().reject();
}
}
},
};
SmallHeart = {
openRoom: [],//记录以及打开的直播间
timer: undefined,
run() {
if (SmallHeart.timer) {
clearInterval(SmallHeart.timer);
}
SmallHeart.timer = setInterval(() => {//每隔60s检查开播勋章直播间
if (MY_API.GIFT_COUNT.COUNT >= 24) {
console.log(`[${NAME}]今日小心心已满`);
SmallHeart.stop();
return
}
SmallHeart.checkMedalRoom();
SmallHeart.checkSmallHeartCount();
}, 60e3);
SmallHeart.checkMedalRoom();
},
stop() {
layer.closeAll();
clearInterval(SmallHeart.timer);
},
checkSmallHeartCount: async () => {
let bagResult = await BAPI.gift.bag_list();
if (bagResult.code === 0) {
let count = 0;
for (let i of bagResult.data.list) {
if (i.corner_mark === '7天' && i.gift_name === '小心心') {
count += parseInt(i.gift_num);
}
}
console.log(`[${NAME}]今日小心心数量:${count}`);
MY_API.GIFT_COUNT.COUNT = count;
MY_API.saveGiftCount();
$('#giftCount span:eq(0)').text(count);
if (count === 24) {
MY_API.chatLog(`今日小心心已满,停止挂小心心`);
SmallHeart.stop();
}
} else {
console.log(`[${NAME}]检查心心数量,获取背包礼物失败`)
}
},
checkMedalRoom: async () => {
if (MY_API.GIFT_COUNT.COUNT >= 24) return;
let result = await SmallHeart.getMedalList();
if (result.code === 0) {
for (let i of result.data) {
if (i.live_stream_status === 1) {
let roomId = i.room_id;
if (!SmallHeart.openRoom.includes(roomId)) {
SmallHeart.openWin(roomId);
} else {
console.log(`[${NAME}]直播间${roomId}已打开`)
}
}
}
} else {
console.log(`[${NAME}]获取勋章列表失败`)
}
},
openWin(roomId) {
if (MY_API.GIFT_COUNT.COUNT >= 24) return;
let rid = roomId;
let index;
if (SmallHeart.openRoom.length > 3) {
console.log(`[${NAME}]最大打开4个直播间`);
return
}
if (roomId === Info.roomId) {//如果当前直播间就是需要打开的直播间
console.log(`[${NAME}]当前直播间就是无需重复打开`);
return
}
if (roomId === 6498960) return;
SmallHeart.openRoom.push(roomId);
MY_API.chatLog(`开始在直播间${roomId}挂小心心`);
let checkTimer = setInterval(async () => {
let result = await SmallHeart.getRoomInfo(roomId);
if (result.code === 0) {
if (result.data.room_info.live_status === 0) {
layer.close(index);
console.log(`[${NAME}]直播间${rid}没有开播 关闭窗口`);
MY_API.chatLog(`直播间${roomId}未开播,停止挂小心心`);
} else {
console.log(`[${NAME}]直播间${rid}为开播状态`)
}
} else {
console.log(`[${NAME}]直播间${rid}状态获取出错`)
}
}, 60e3);
window.localStorage["LIVE_PLAYER_STATUS"] = window.localStorage["LIVE_PLAYER_STATUS"].replace("flash", 'html5');
window.localStorage["videoVolume"] = 0;//修改音量
index = layer.open({
title: `${rid}`,
type: 2,
shade: 0,
content: `https://live.bilibili.com/${rid}?cut`,
end: () => {
clearInterval(checkTimer);
SmallHeart.openRoom.remove(roomId);
}
});
setTimeout(() => {
layer.close(index)
}, 11 * 60e3);
layer.style(index, { // 隐藏弹窗
display: 'none',
});
},
getMedalList() {
return SmallHeart.xhrRequest(
'https://api.live.bilibili.com/fans_medal/v1/FansMedal/get_list_in_room',
'GET');
},
getRoomInfo(roomId) {
return SmallHeart.xhrRequest(
`https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=${roomId}`,
'GET'
)
},
xhrRequest(url, method, data) {
let p = $.Deferred();
$.ajax({
url: url,
method: method,
data: data,
success: function (result) {
p.resolve(result);
},
error: function (result) {
p.reject(result);
},
crossDomain: true,
dataType: 'json',
xhrFields: {
withCredentials: true,
},
});
return p
},
};
const ts_ms = () => Date.now();
const delayCall = (callback, delay = 10e3) => {
const p = $.Deferred();
setTimeout(() => {
const t = callback();
if (t && t.then) t.then((arg1, arg2, arg3, arg4, arg5, arg6) => p.resolve(arg1, arg2, arg3, arg4, arg5, arg6));
else p.resolve();
}, delay);
return p;
};
MY_API.init().then(function () {
if (Info.uid === 0 || isNaN(Info.uid)) {
MY_API.chatLog('未登录,请先登录再使用脚本', 'warning');
return
}
console.log(MY_API.CONFIG);
StartPlunder(MY_API);
});
}
let cut = window.location.href.indexOf('cut') > -1;
const controllers = [];
let isRemove = false;
if (cut) {
/**
* 截流源码来自SeaLoong大神
* https://github.com/SeaLoong/TampermonkeyScripts/blob/master/%E7%A7%BB%E9%99%A4Bilibili%E7%9B%B4%E6%92%AD%E6%92%AD%E6%94%BE%E5%99%A8.user.js
*/
const urlSet = new Set();
const wfetch = window.fetch;
window.fetch = (input, init) => new Promise((resolve, reject) => {
let url = input;
if (typeof Request !== 'undefined' && input instanceof Request) url = input.url;
if (!url.includes('//data.bilibili.com') && url.includes('bilivideo.com')) {
if (isRemove) return;
urlSet.add(url);
if (!init) init = {};
const controller = new AbortController();
controllers.push(controller);
if (init.signal) {
const _onabort = init.signal.onabort;
init.signal.onabort = function (...args) {
controller.abort.apply(this, args);
if (_onabort instanceof Function) return _onabort.apply(this, args);
};
}
init.signal = controller.signal;
}
wfetch(input, init).then(resolve, function (reason) {
if (urlSet.has(url)) return;
return reject.call(this, reason);
});
});
}
function StartPlunder() {
'use strict';
if (!cut) {
let YB = () => {//判断是否换硬币
if (MY_API.CONFIG.AUTO_EXCHANGE && checkNewDay(MY_API.GIFT_COUNT.EXCHANGE_TS)) {
MY_API.GIFT_COUNT.EXCHANGE_TS = dateNow();
MY_API.saveGiftCount();
MY_API.Exchange.run();
console.log('银瓜子换硬币')
} else {
console.log('无需银瓜子换硬币')
}
};
YB();
let SS = () => {//判断是否签到
if (MY_API.CONFIG.AUTO_SIGNIN && checkNewDay(MY_API.GIFT_COUNT.SIGN_TS)) {
BAPI.sign.doSign().then((result) => {
if (result.code === 0) {
MY_API.chatLog('[签到]签到成功', 'success');
MY_API.GIFT_COUNT.SIGN_TS = dateNow();
MY_API.saveGiftCount();
} else if (result.code === 1011040) {
MY_API.chatLog('[签到]今日签到已完成', 'info');
MY_API.GIFT_COUNT.SIGN_TS = dateNow();
MY_API.saveGiftCount();
} else {
MY_API.chatLog(`[签到]${result.message}`, 'warning')
}
}, () => {
MY_API.chatLog('[签到]签到失败,请检查网络', 'error');
});
} else {
console.log('无需签到')
}
};
SS();
MY_API.creatSetBox();//创建设置框
setTimeout(function () {
layer.tips('Here!', '#izayoi_setting', {
tips: 1
});
}, 1000);
let G_Timer = () => {//判断是否清空礼物数量
if (checkNewDay(MY_API.GIFT_COUNT.CLEAR_TS)) {
MY_API.GIFT_COUNT.COUNT = 0;
MY_API.GIFT_COUNT.LOVE_COUNT = 0;
MY_API.GIFT_COUNT.CLEAR_TS = dateNow();
MY_API.saveGiftCount();
$('#giftCount span').text(0);
console.log('清空礼物数量')
} else {
console.log('无需清空礼物数量')
}
};
setInterval(G_Timer, 60e3);
G_Timer();
if (MY_API.CONFIG.AUTO_HEART) {
if (MY_API.GIFT_COUNT.COUNT < 24) {
setTimeout(SmallHeart.run, 10e3);
} else {
MY_API.chatLog('今日小心心已满');
}
}
MY_API.share();
MY_API.GroupSign.run();
} else {
isRemove = true;
document.getElementById('live-player').remove();
controllers.forEach(v => v.abort());
}
}
/**
* (2,10) 当前是否在两点到十点之间(10,2) 当前是否在十点到次日两点之间
* @param a 整数 起始时间
* @param b 整数 终止时间
* @returns {boolean}
*/
function inTimeArea(a, b) {
a %= 24;
b %= 24;
if (a < 0 || b < 0 || a === b) {
console.log('错误时间段');
return false
}
let myDate = new Date();
let h = myDate.getHours();
if (a < b) {
return h >= a && h < b
} else {
return h >= a || h < b
}
}
/**
* 概率
* @param val
* @returns {boolean}
*/
function probability(val) {
if (val <= 0) return false;
let rad = Math.ceil(Math.random() * 100);
return val >= rad
}
const dateNow = () => Date.now();
/**
* 检查是否为新一天
* @param ts
* @returns {boolean}
*/
const checkNewDay = (ts) => {
if (ts === 0) return true;
let t = new Date(ts);
let d = new Date();
let td = t.getDate();
let dd = d.getDate();
return (dd !== td);
};
/**
* 获取cookie
* @param name
* @returns {string|boolean}
*/
function getCookie(name) {
let arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
if (arr != null) return unescape(arr[2]);
return false;
}
let csrf_token, visit_id;
/**
* SeaLoong BilibiliAPI_1.4.6 BilibiliAPI,PC端抓包研究所得 https://github.com/SeaLoong/BLRHH
* @type {{msg: (function(*=): (*|jQuery|{})), gift: {heart_gift_receive: (function(*=, *=): (*|jQuery|{})), receive_daily_bag: (function(): (*|jQuery|{})), room_gift_list: (function(*=, *=): (*|jQuery|{})), bag_list: (function(): (*|jQuery|{})), heart_gift_status: (function(*=, *=): (*|jQuery|{})), bag_send: (function(*=, *=, *=, *=, *=, *=, *=, *=, *=, *=, *=): (*|jQuery|{})), send: (function(*=, *=, *=, *=, *=, *=, *=, *=, *=, *=, *=): (*|jQuery|{})), gift_config: (function(): (*|jQuery|{})), smalltv: {check: (function(*=): (*|jQuery|{})), join: (function(*=, *=, *=): (*|jQuery|{})), notice: (function(*=, *=): (*|jQuery|{}))}}, Group: {my_groups: (function(): (*|jQuery|{})), sign_in: (function(*=, *=): (*|jQuery|{}))}, Storm: {check: (function(*=): (*|jQuery|{})), join: (function(*=, *=, *=, *=, *=): (*|jQuery|{}))}, activity: {welcomeInfo: (function(*=, *=): (*|jQuery|{})), mobileRoomInfo: (function(*=): (*|jQuery|{})), receive_award: (function(*=): (*|jQuery|{})), check: (function(*): (*|jQuery|{})), join: (function(*=, *=): (*|jQuery|{})), mobileActivity: (function(): (*|jQuery|{})), roomInfo: (function(*=, *=, *=, *=): (*|jQuery|{})), notice: (function(*=, *=): (*|jQuery|{}))}, ajaxGetCaptchaKey: (function(): (*|jQuery|{})), YearWelfare: {checkFirstCharge: (function(): (*|jQuery|{})), inviteUserList: (function(): (*|jQuery|{}))}, sign: {doSign: (function(): (*|jQuery|{})), getLastMonthSignDays: (function(): (*|jQuery|{})), GetSignInfo: (function(): (*|jQuery|{}))}, runUntilSucceed: BilibiliAPI.runUntilSucceed, ajax: (function(*=): (*|jQuery|{})), relation: {IsUserFollow: (function(*): (*|jQuery|{})), getList: (function(*=, *=): (*|jQuery|{})), heartBeat: (function(): (*|jQuery|{})), GetUserFc: (function(*): (*|jQuery|{}))}, fans_medal: {get_fans_medal_info: (function(*=, *=, *=): (*|jQuery|{}))}, topList: (function(*=, *=, *=): (*|jQuery|{})), create: (function(*=, *=): (*|jQuery|{})), giftBag: {getSendGift: (function(): (*|jQuery|{})), sendDaily: (function(): (*|jQuery|{}))}, feed_svr: {my: (function(*=, *=, *=, *=): (*|jQuery|{})), notice: (function(): (*|jQuery|{}))}, live_user: {get_weared_medal: (function(*=, *=, *=): (*|jQuery|{})), get_anchor_in_room: (function(*): (*|jQuery|{})), get_info_in_room: (function(*): (*|jQuery|{})), governorShow: (function(*): (*|jQuery|{}))}, setCommonArgs: BilibiliAPI.setCommonArgs, exp: (function(): (*|jQuery|{})), ajaxCapsule: (function(): (*|jQuery|{})), live: {getRoomKanBanModel: (function(*): (*|jQuery|{})), rankTab: (function(*): (*|jQuery|{})), roomAdList: (function(): (*|jQuery|{}))}, player: (function(*=, *=, *=, *=): (*|jQuery|{})), HeartBeat: {web: (function(): (*|jQuery|{})), mobile: (function(): (*|jQuery|{}))}, getSuser: (function(): (*|jQuery|{})), DailyReward: {task: (function(): (*|jQuery|{})), watch: (function(*=, *=, *=, *=, *=, *=, *=, *=, *=): (*|jQuery|{})), share: (function(*=): (*|jQuery|{})), exp: (function(): (*|jQuery|{})), login: (function(): (*|jQuery|{})), coin: (function(*=, *=): (*|jQuery|{}))}, get_ip_addr: (function(): (*|jQuery|{})), TreasureBox: {getCurrentTask: (function(): (*|jQuery|{})), getCaptcha: (function(*=): (*|jQuery|{})), getAward: (function(*=, *=, *=): (*|jQuery|{}))}, getuserinfo: (function(): (*|jQuery|{})), mobile: {userOnlineHeart: (function(): (*|jQuery|{}))}, refresh: (function(*=): (*|jQuery|{})), i: {liveinfo: (function(): (*|jQuery|{})), ajaxGetMyMedalList: (function(): (*|jQuery|{})), following: (function(*=, *=): (*|jQuery|{})), guard: (function(*=, *=): (*|jQuery|{})), ajaxGetAchieve: (function(*=, *=, *=, *=, *=, *=): (*|jQuery|{})), medal: (function(*=, *=): (*|jQuery|{})), ajaxCancelWear: (function(): (*|jQuery|{})), taskInfo: (function(): (*|jQuery|{})), ajaxWearFansMedal: (function(*): (*|jQuery|{})), operation: (function(*=): (*|jQuery|{}))}, pay: {silver2coin: (function(*=): (*|jQuery|{})), coin2silver: (function(*=, *=): (*|jQuery|{})), getRule: (function(*=): (*|jQuery|{})), getStatus: (function(*=): (*|jQuery|{}))}, xlive: {guard: {join: (function(*=, *=, *=): (*|jQuery|{}))}, lottery: {check: (function(*=): (*|jQuery|{}))}, pk: {check: (function(*=): (*|jQuery|{})), join: (function(*=, *=): (*|jQuery|{}))}, smalltv: {check: (function(*=): (*|jQuery|{})), join: (function(*=, *=, *=): (*|jQuery|{})), notice: (function(*=, *=): (*|jQuery|{}))}}, lottery: {Storm: {check: (function(*): (*|jQuery|{})), join: (function(*=, *=, *=, *=, *=): (*|jQuery|{}))}, SilverBox: {getCurrentTask: (function(): (*|jQuery|{})), getCaptcha: (function(*): (*|jQuery|{})), getAward: (function(*=, *=, *=): (*|jQuery|{}))}, box: {getRoomActivityByRoomid: (function(*): (*|jQuery|{})), getWinnerGroupInfo: (function(*=, *=): (*|jQuery|{})), draw: (function(*=, *=): (*|jQuery|{})), getStatus: (function(*=, *=): (*|jQuery|{}))}, lottery: {check_guard: (function(*): (*|jQuery|{})), join: (function(*=, *=, *=): (*|jQuery|{}))}}, ajaxWithCommonArgs: (function(*=): (*|jQuery|{})), room: {getConf: (function(*=, *=, *=): (*|jQuery|{})), getList: (function(): (*|jQuery|{})), get_recommend_by_room: (function(*=, *=, *=): (*|jQuery|{})), room_entry_action: (function(*=, *=): (*|jQuery|{})), get_info: (function(*=, *=): (*|jQuery|{})), getRoomList: (function(*=, *=, *=, *=, *=, *=, *=): (*|jQuery|{})), playUrl: (function(*=, *=, *=): (*|jQuery|{})), room_init: (function(*): (*|jQuery|{}))}, home: {reward: (function(): (*|jQuery|{}))}, Exchange: {silver2coin: (function(*=): (*|jQuery|{})), coin2silver: (function(*=, *=): (*|jQuery|{})), old: {silver2coin: (function(): (*|jQuery|{})), coin2silver: (function(*=): (*|jQuery|{}))}}, DanmuWebSocket: BilibiliAPI.DanmuWebSocket, Lottery: {Gift: {check: (function(*=): (*|jQuery|{})), join: (function(*=, *=, *=): (*|jQuery|{})), notice: (function(*=, *=): (*|jQuery|{}))}, MaterialObject: {getRoomActivityByRoomid: (function(*=): (*|jQuery|{})), getWinnerGroupInfo: (function(*=, *=): (*|jQuery|{})), draw: (function(*=, *=): (*|jQuery|{})), getStatus: (function(*=, *=): (*|jQuery|{}))}, Guard: {check: (function(*=): (*|jQuery|{})), join: (function(*=, *=, *=): (*|jQuery|{}))}, Pk: {check: (function(*=): (*|jQuery|{})), join: (function(*=, *=): (*|jQuery|{}))}, Raffle: {check: (function(*=): (*|jQuery|{})), join: (function(*=, *=): (*|jQuery|{})), notice: (function(*=, *=): (*|jQuery|{}))}}, av: {getTimestamp: (function(*=): (*|jQuery|{}))}, dynamic_svr: {dynamic_new: (function(*=, *=): (*|jQuery|{}))}, rankdb: {roomInfo: (function(*=, *=, *=): (*|jQuery|{}))}, x: {heartbeat: (function(*=, *=, *=, *=, *=, *=, *=, *=, *=): (*|jQuery|{})), now: (function(): (*|jQuery|{})), share_add: (function(*=): (*|jQuery|{})), coin_add: (function(*=, *=): (*|jQuery|{}))}, processing: number, exchange: {silver2coin: (function(): (*|jQuery|{})), coin2silver: (function(*=): (*|jQuery|{}))}, link_group: {my_groups: (function(): (*|jQuery|{})), sign_in: (function(*=, *=): (*|jQuery|{}))}, user: {getWear: (function(*): (*|jQuery|{})), userOnlineHeart: (function(): (*|jQuery|{})), isBiliVip: (function(*): (*|jQuery|{})), getUserInfo: (function(*): (*|jQuery|{}))}}}
*/
let BilibiliAPI = {
setCommonArgs: (csrfToken = '', visitId = '') => {
csrf_token = csrfToken;
visit_id = visitId;
},
// 整合常用API
TreasureBox: {
getAward: (time_start, end_time, captcha) => BilibiliAPI.lottery.SilverBox.getAward(time_start, end_time, captcha),
getCaptcha: (ts) => BilibiliAPI.lottery.SilverBox.getCaptcha(ts),
getCurrentTask: () => BilibiliAPI.lottery.SilverBox.getCurrentTask()
},
Exchange: {
coin2silver: (num, platform) => BilibiliAPI.pay.coin2silver(num, platform),
silver2coin: (platform) => BilibiliAPI.pay.silver2coin(platform),
old: {
coin2silver: (coin) => BilibiliAPI.exchange.coin2silver(coin),
silver2coin: () => BilibiliAPI.exchange.silver2coin()
}
},
Lottery: {
Gift: {
check: (roomid) => BilibiliAPI.xlive.smalltv.check(roomid),
join: (roomid, raffleId, type) => BilibiliAPI.xlive.smalltv.join(roomid, raffleId, type),
notice: (raffleId, type) => BilibiliAPI.xlive.smalltv.notice(raffleId, type)
},
Raffle: {
check: (roomid) => BilibiliAPI.activity.check(roomid),
join: (roomid, raffleId) => BilibiliAPI.activity.join(roomid, raffleId),
notice: (roomid, raffleId) => BilibiliAPI.activity.notice(roomid, raffleId)
},
MaterialObject: {
getRoomActivityByRoomid: (roomid) => BilibiliAPI.lottery.box.getRoomActivityByRoomid(roomid),
getStatus: (aid, times) => BilibiliAPI.lottery.box.getStatus(aid, times),
draw: (aid, number) => BilibiliAPI.lottery.box.draw(aid, number),
getWinnerGroupInfo: (aid, number) => BilibiliAPI.lottery.box.getWinnerGroupInfo(aid, number)
},
Guard: {
check: (roomid) => BilibiliAPI.lottery.lottery.check_guard(roomid),
join: (roomid, id, type) => BilibiliAPI.xlive.guard.join(roomid, id, type)
},
Pk: {
check: (roomid) => BilibiliAPI.xlive.pk.check(roomid),
join: (roomid, id) => BilibiliAPI.xlive.pk.join(roomid, id)
}
},
Group: {
my_groups: () => BilibiliAPI.link_group.my_groups(),
sign_in: (group_id, owner_id) => BilibiliAPI.link_group.sign_in(group_id, owner_id)
},
Storm: {
check: (roomid) => BilibiliAPI.lottery.Storm.check(roomid),
join: (id, captcha_token, captcha_phrase, roomid, color) => BilibiliAPI.lottery.Storm.join(id, captcha_token, captcha_phrase, roomid, color)
},
HeartBeat: {
web: () => BilibiliAPI.user.userOnlineHeart(),
mobile: () => BilibiliAPI.mobile.userOnlineHeart()
},
DailyReward: {
task: () => BilibiliAPI.home.reward(), // CORS
exp: () => BilibiliAPI.exp(),
login: () => BilibiliAPI.x.now(),
watch: (aid, cid, mid, start_ts, played_time, realtime, type, play_type, dt) => BilibiliAPI.x.heartbeat(aid, cid, mid, start_ts, played_time, realtime, type, play_type, dt),
coin: (aid, multiply) => BilibiliAPI.x.coin_add(aid, multiply),
share: (aid) => BilibiliAPI.x.share_add(aid)
},
// ajax调用B站API
runUntilSucceed: (callback, delay = 0, period = 50) => {
setTimeout(() => {
if (!callback()) BilibiliAPI.runUntilSucceed(callback, period, period);
}, delay);
},
processing: 0,
ajax: (settings) => {
if (settings.xhrFields === undefined) settings.xhrFields = {};
settings.xhrFields.withCredentials = true;
jQuery.extend(settings, {
url: (settings.url.substr(0, 2) === '//' ? '' : '//api.live.bilibili.com/') + settings.url,
method: settings.method || 'GET',
crossDomain: true,
dataType: settings.dataType || 'json'
});
const p = jQuery.Deferred();
BilibiliAPI.runUntilSucceed(() => {
if (BilibiliAPI.processing > 8) return false;
++BilibiliAPI.processing;
return jQuery.ajax(settings).then((arg1, arg2, arg3) => {
--BilibiliAPI.processing;
p.resolve(arg1, arg2, arg3);
return true;
}, (arg1, arg2, arg3) => {
--BilibiliAPI.processing;
p.reject(arg1, arg2, arg3);
return true;
});
});
return p;
},
ajaxWithCommonArgs: (settings) => {
if (!settings.data) settings.data = {};
settings.data.csrf = csrf_token;
settings.data.csrf_token = csrf_token;
settings.data.visit_id = visit_id;
return BilibiliAPI.ajax(settings);
},
// 以下按照URL分类
ajaxGetCaptchaKey: () => {
return BilibiliAPI.ajax({
url: '//www.bilibili.com/plus/widget/ajaxGetCaptchaKey.php?js'
});
},
exp: () => {
// 获取今日已获得的投币经验?
return BilibiliAPI.ajax({
url: '//www.bilibili.com/plus/account/exp.php'
});
},
msg: (roomid) => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'ajax/msg',
data: {
roomid: roomid
}
});
},
ajaxCapsule: () => {
return BilibiliAPI.ajax({
url: 'api/ajaxCapsule'
});
},
player: (id, ts, platform = 'pc', player_type = 'web') => {
return BilibiliAPI.ajax({
url: 'api/player',
data: {
id: typeof id === 'string' && id.substr(0, 4) === 'cid:' ? id : 'cid:' + id, // cid:{room_id}
ts: typeof ts === 'string' ? ts : ts.toString(16), // HEX
platform: platform,
player_type: player_type
},
dataType: 'text'
});
},
create: (width, height) => {
// 生成一个验证码(用于节奏风暴)
return BilibiliAPI.ajax({
url: 'captcha/v1/Captcha/create',
data: {
width: width || '112',
height: height || '32'
},
cache: false
});
},
topList: (roomid, page, ruid) => {
return BilibiliAPI.ajax({
url: 'guard/topList',
data: {
roomid: roomid,
page: page,
ruid: ruid
}
});
},
getSuser: () => {
return BilibiliAPI.ajax({
url: 'msg/getSuser'
});
},
refresh: (area = 'all') => {
return BilibiliAPI.ajax({
url: 'index/refresh?area=' + area
});
},
get_ip_addr: () => {
return BilibiliAPI.ajax({
url: 'ip_service/v1/ip_service/get_ip_addr'
});
},
getuserinfo: () => {
return BilibiliAPI.ajax({
url: 'user/getuserinfo'
});
},
activity: {
mobileActivity: () => {
return BilibiliAPI.ajax({
url: 'activity/v1/Common/mobileActivity'
});
},
mobileRoomInfo: (roomid) => {
return BilibiliAPI.ajax({
url: 'activity/v1/Common/mobileRoomInfo',
data: {
roomid: roomid
}
});
},
roomInfo: (roomid, ruid, area_v2_id, area_v2_parent_id) => {
return BilibiliAPI.ajax({
url: 'activity/v1/Common/roomInfo',
data: {
roomid: roomid,
ruid: ruid,
area_v2_id: area_v2_id,
area_v2_parent_id: area_v2_parent_id
}
});
},
welcomeInfo: (roomid, ruid) => {
return BilibiliAPI.ajax({
url: 'activity/v1/Common/welcomeInfo',
data: {
roomid: roomid,
ruid: ruid
}
});
},
check: (roomid) => {
// 检查是否有活动抽奖
return BilibiliAPI.ajax({
url: 'activity/v1/Raffle/check?roomid=' + roomid
});
},
join: (roomid, raffleId) => {
// 参加活动抽奖
return BilibiliAPI.ajax({
url: 'activity/v1/Raffle/join',
data: {
roomid: roomid,
raffleId: raffleId
}
});
},
notice: (roomid, raffleId) => {
// 领取活动抽奖奖励
return BilibiliAPI.ajax({
url: 'activity/v1/Raffle/notice',
data: {
roomid: roomid,
raffleId: raffleId
}
});
},
receive_award: (task_id) => {
// 领取任务奖励
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'activity/v1/task/receive_award',
data: {
task_id: task_id
}
});
}
},
av: {
getTimestamp: (platform = 'pc') => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'av/v1/Time/getTimestamp',
data: {
platform: platform
}
});
}
},
dynamic_svr: {
dynamic_new: (uid, type = 8) => {
// 获取动态
return BilibiliAPI.ajax({
url: 'dynamic_svr/v1/dynamic_svr/dynamic_new',
data: {
uid: uid,
type: type // 8: 投稿视频; 268435455: 全部
}
});
}
},
exchange: {
coin2silver: (coin) => {
// 硬币兑换银瓜子(旧API),1硬币=900银瓜子
return BilibiliAPI.ajax({
method: 'POST',
url: 'exchange/coin2silver',
data: {
coin: coin
}
});
},
silver2coin: () => {
// 银瓜子兑换硬币(旧API),1400银瓜子=1硬币
return BilibiliAPI.ajax({
type: 'GET',
url: 'exchange/silver2coin'
});
}
},
fans_medal: {
get_fans_medal_info: (uid, target_id, source = 1) => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'fans_medal/v1/fans_medal/get_fans_medal_info',
data: {
source: source,
uid: uid,
target_id: target_id
}
});
}
},
feed_svr: {
notice: () => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'feed_svr/v1/feed_svr/notice',
data: {}
});
},
my: (page_size, live_status = 0, type = 0, offset = 0) => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'feed_svr/v1/feed_svr/my',
data: {
live_status: live_status,
type: type,
page_size: page_size,
offset: offset
}
});
}
},
gift: {
bag_list: () => {
// 获取包裹礼物列表
return BilibiliAPI.ajax({
url: 'gift/v2/gift/bag_list'
});
},
send: (uid, gift_id, ruid, gift_num, biz_id, rnd, coin_type = 'silver', platform = 'pc', biz_code = 'live', storm_beat_id = 0, price = 0) => {
// 消耗瓜子送礼
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'gift/v2/gift/send',
data: {
uid: uid,
gift_id: gift_id,
ruid: ruid,
gift_num: gift_num,
coin_type: coin_type,
bag_id: 0,
platform: platform,
biz_code: biz_code,
biz_id: biz_id, // roomid
rnd: rnd,
storm_beat_id: storm_beat_id,
metadata: '',
price: price
}
});
},
bag_send: (uid, gift_id, ruid, gift_num, bag_id, biz_id, rnd, platform = 'pc', biz_code = 'live', storm_beat_id = 0, price = 0) => {
// 送出包裹中的礼物
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'gift/v2/live/bag_send',
data: {
uid: uid,
gift_id: gift_id,
ruid: ruid,
gift_num: gift_num,
bag_id: bag_id,
platform: platform,
biz_code: biz_code,
biz_id: biz_id, // roomid
rnd: rnd,
storm_beat_id: storm_beat_id,
metadata: '',
price: price
}
});
},
gift_config: () => {
return BilibiliAPI.ajax({
url: 'gift/v3/live/gift_config'
});
},
heart_gift_receive: (roomid, area_v2_id) => {
return BilibiliAPI.ajax({
url: 'gift/v2/live/heart_gift_receive',
data: {
roomid: roomid,
area_v2_id: area_v2_id
}
});
},
heart_gift_status: (roomid, area_v2_id) => {
return BilibiliAPI.ajax({
url: 'gift/v2/live/heart_gift_status',
data: {
roomid: roomid,
area_v2_id: area_v2_id
}
});
},
receive_daily_bag: () => {
// 领取每日礼物
return BilibiliAPI.ajax({
url: 'gift/v2/live/receive_daily_bag'
});
},
room_gift_list: (roomid, area_v2_id) => {
return BilibiliAPI.ajax({
url: 'gift/v2/live/room_gift_list',
data: {
roomid: roomid,
area_v2_id: area_v2_id
}
});
},
smalltv: {
// 礼物抽奖
check: (roomid) => {
return BilibiliAPI.ajax({
url: 'gift/v3/smalltv/check',
data: {
roomid: roomid
}
});
},
join: (roomid, raffleId, type = 'Gift') => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'gift/v3/smalltv/join',
data: {
roomid: roomid,
raffleId: raffleId,
type: type
}
});
},
notice: (raffleId, type = 'small_tv') => {
return BilibiliAPI.ajax({
url: 'gift/v3/smalltv/notice',
data: {
type: type,
raffleId: raffleId
}
});
}
}
},
giftBag: {
getSendGift: () => {
return BilibiliAPI.ajax({
url: 'giftBag/getSendGift'
});
},
sendDaily: () => {
return BilibiliAPI.ajax({
url: 'giftBag/sendDaily'
});
}
},
home: {
reward: () => {
// 获取每日奖励情况
return BilibiliAPI.ajax({
url: '//account.bilibili.com/home/reward'
});
}
},
i: {
ajaxCancelWear: () => {
// 取消佩戴勋章
return BilibiliAPI.ajax({
url: 'i/ajaxCancelWear'
});
},
ajaxGetAchieve: (keywords, page, pageSize = 6, type = 'normal', status = 0, category = 'all') => {
return BilibiliAPI.ajax({
url: 'i/api/ajaxGetAchieve',
data: {
type: type, // 'legend'
status: status,
category: category,
keywords: keywords,
page: page,
pageSize: pageSize
}
});
},
ajaxGetMyMedalList: () => {
// 勋章列表
return BilibiliAPI.ajax({
url: 'i/ajaxGetMyMedalList'
});
},
ajaxWearFansMedal: (medal_id) => {
// 佩戴勋章/更换当前佩戴的勋章
return BilibiliAPI.ajax({
url: 'i/ajaxWearFansMedal?medal_id=' + medal_id
});
},
following: (page = 1, pageSize = 9) => {
return BilibiliAPI.ajax({
url: 'i/api/following',
data: {
page: page,
pageSize: pageSize
}
});
},
guard: (page, pageSize = 10) => {
return BilibiliAPI.ajax({
url: 'i/api/guard',
data: {
page: page,
pageSize: pageSize
}
});
},
liveinfo: () => {
return BilibiliAPI.ajax({
url: 'i/api/liveinfo'
});
},
medal: (page = 1, pageSize = 10) => {
// 获取勋章列表信息
return BilibiliAPI.ajax({
url: 'i/api/medal',
data: {
page: page,
pageSize: pageSize
}
});
},
operation: (page = 1) => {
return BilibiliAPI.ajax({
url: 'i/api/operation?page=' + page
});
},
taskInfo: () => {
return BilibiliAPI.ajax({
url: 'i/api/taskInfo'
});
}
},
link_group: {
my_groups: () => {
// 应援团列表
return BilibiliAPI.ajax({
url: 'link_group/v1/member/my_groups'
});
},
sign_in: (group_id, owner_id) => {
// 应援团签到
return BilibiliAPI.ajax({
url: 'link_setting/v1/link_setting/sign_in',
data: {
group_id: group_id,
owner_id: owner_id
}
});
}
},
live: {
getRoomKanBanModel: (roomid) => {
return BilibiliAPI.ajax({
url: 'live/getRoomKanBanModel?roomid' + roomid
});
},
rankTab: (roomid) => {
return BilibiliAPI.ajax({
url: 'live/rankTab?roomid=' + roomid
});
},
roomAdList: () => {
return BilibiliAPI.ajax({
url: 'live/roomAdList'
});
}
},
live_user: {
get_anchor_in_room: (roomid) => {
return BilibiliAPI.ajax({
url: 'live_user/v1/UserInfo/get_anchor_in_room?roomid=' + roomid
});
},
get_info_in_room: (roomid) => {
return BilibiliAPI.ajax({
url: 'live_user/v1/UserInfo/get_info_in_room?roomid=' + roomid
});
},
get_weared_medal: (uid, target_id, source = 1) => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'live_user/v1/UserInfo/get_weared_medal',
data: {
source: source,
uid: uid,
target_id: target_id // ruid
}
});
},
governorShow: (target_id) => {
return BilibiliAPI.ajax({
url: 'live_user/v1/Master/governorShow?target_id=' + target_id
});
}
},
lottery: {
box: {
getRoomActivityByRoomid: (roomid) => {
// 获取房间特有的活动 (实物抽奖)
return BilibiliAPI.ajax({
url: 'lottery/v1/box/getRoomActivityByRoomid?roomid=' + roomid
});
},
getStatus: (aid, times = '') => {
// 获取活动信息/状态
return BilibiliAPI.ajax({
url: 'lottery/v1/box/getStatus',
data: {
aid: aid,
times: times
}
});
},
draw: (aid, number = 1) => {
// 参加实物抽奖
return BilibiliAPI.ajax({
url: 'lottery/v1/box/draw',
data: {
aid: aid,
number: number
}
});
},
getWinnerGroupInfo: (aid, number = 1) => {
// 获取中奖名单
return BilibiliAPI.ajax({
url: 'lottery/v1/box/getWinnerGroupInfo',
data: {
aid: aid,
number: number
}
});
}
},
SilverBox: {
getAward: (time_start, end_time, captcha) => {
// 领取银瓜子
return BilibiliAPI.ajax({
url: 'lottery/v1/SilverBox/getAward',
data: {
time_start: time_start,
end_time: end_time,
captcha: captcha
}
});
},
getCaptcha: (ts) => {
// 获取银瓜子验证码图片
return BilibiliAPI.ajax({
url: 'lottery/v1/SilverBox/getCaptcha?ts=' + ts
});
},
getCurrentTask: () => {
// 获取领取银瓜子的任务
return BilibiliAPI.ajax({
url: 'lottery/v1/SilverBox/getCurrentTask'
});
}
},
Storm: {
check: (roomid) => {
// 检查是否有节奏风暴
return BilibiliAPI.ajax({
url: 'lottery/v1/Storm/check?roomid=' + roomid
});
},
join: (id, captcha_token, captcha_phrase, roomid, color = 16777215) => {
// 参加节奏风暴
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'lottery/v1/Storm/join',
data: {
id: id,
color: color,
captcha_token: captcha_token,
captcha_phrase: captcha_phrase,
roomid: roomid
}
});
}
},
lottery: {
check_guard: (roomid) => {
// 检查是否有舰队领奖
return BilibiliAPI.ajax({
url: 'lottery/v1/Lottery/check_guard?roomid=' + roomid
});
},
join: (roomid, id, type = 'guard') => {
// 参加总督领奖
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'lottery/v2/Lottery/join',
data: {
roomid: roomid,
id: id,
type: type
}
});
}
}
},
mobile: {
userOnlineHeart: () => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'mobile/userOnlineHeart',
data: {}
});
}
},
pay: {
coin2silver: (num, platform = 'pc') => {
// 硬币兑换银瓜子(新API),1硬币=450银瓜子
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'pay/v1/Exchange/coin2silver',
data: {
num: num,
platform: platform
}
});
},
getRule: (platform = 'pc') => {
return BilibiliAPI.ajax({
url: 'pay/v1/Exchange/getRule?platform=' + platform
});
},
getStatus: (platform = 'pc') => {
return BilibiliAPI.ajax({
url: 'pay/v1/Exchange/getStatus?platform=' + platform
});
},
silver2coin: (platform = 'pc') => {
// 银瓜子兑换硬币,700银瓜子=1硬币
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'pay/v1/Exchange/silver2coin',
data: {
platform: platform
}
});
}
},
rankdb: {
roomInfo: (ruid, roomid, areaId) => {
return BilibiliAPI.ajax({
url: 'rankdb/v1/Common/roomInfo',
data: {
ruid: ruid,
roomid: roomid,
areaId: areaId
}
});
}
},
relation: {
getList: (page, page_size) => {
return BilibiliAPI.ajax({
url: 'relation/v1/feed/getList',
data: {
page: page,
page_size: page_size
},
cache: false
});
},
heartBeat: () => {
return BilibiliAPI.ajax({
url: 'relation/v1/feed/heartBeat',
cache: false
});
},
GetUserFc: (follow) => { // follow: 主播uid===ruid
return BilibiliAPI.ajax({
url: 'relation/v1/Feed/GetUserFc?follow=' + follow
});
},
IsUserFollow: (follow) => { // follow: 主播uid===ruid
return BilibiliAPI.ajax({
url: 'relation/v1/Feed/IsUserFollow?follow=' + follow
});
}
},
room: {
get_info: (room_id, from = 'room') => {
return BilibiliAPI.ajax({
url: 'room/v1/Room/get_info',
data: {
room_id: room_id,
from: from
}
});
},
get_recommend_by_room: (room_id, count, rnd) => {
return BilibiliAPI.ajax({
url: 'room/v1/room/get_recommend_by_room',
data: {
room_id: room_id,
count: count,
rnd: rnd || Math.floor(Date.now() / 1000)
}
});
},
playUrl: (cid, quality = '0', platform = 'web') => {
return BilibiliAPI.ajax({
url: 'room/v1/Room/playUrl',
data: {
cid: cid, // roomid
quality: quality,
platform: platform
}
});
},
room_entry_action: (room_id, platform = 'pc') => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'room/v1/Room/room_entry_action',
data: {
room_id: room_id,
platform: platform
}
});
},
room_init: (id) => {
return BilibiliAPI.ajax({
url: 'room/v1/Room/room_init?id=' + id
});
},
getConf: (room_id, platform = 'pc', player = 'web') => {
return BilibiliAPI.ajax({
url: 'room/v1/Danmu/getConf',
data: {
room_id: room_id,
platform: platform,
player: player
}
});
},
getList: () => {
return BilibiliAPI.ajax({
url: 'room/v1/Area/getList'
});
},
getRoomList: (parent_area_id = 1, cate_id = 0, area_id = 0, page = 1, page_size = 30, sort_type = 'online', platform = 'web') => {
return BilibiliAPI.ajax({
url: 'room/v1/area/getRoomList',
data: {
platform: platform,
parent_area_id: parent_area_id,
cate_id: cate_id,
area_id: area_id,
sort_type: sort_type,
page: page,
page_size: page_size
}
});
}
},
sign: {
doSign: () => {
// 签到
return BilibiliAPI.ajax({
url: 'sign/doSign'
});
},
GetSignInfo: () => {
// 获取签到信息
return BilibiliAPI.ajax({
url: 'sign/GetSignInfo'
});
},
getLastMonthSignDays: () => {
return BilibiliAPI.ajax({
url: 'sign/getLastMonthSignDays'
});
}
},
user: {
getWear: (uid) => {
return BilibiliAPI.ajax({
url: 'user/v1/user_title/getWear?uid=' + uid
});
},
isBiliVip: (uid) => {
return BilibiliAPI.ajax({
url: 'user/v1/user/isBiliVip?uid=' + uid
});
},
userOnlineHeart: () => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'User/userOnlineHeart',
data: {}
});
},
getUserInfo: (ts) => { // ms
return BilibiliAPI.ajax({
url: 'User/getUserInfo?ts=' + ts
});
}
},
x: {
coin_add: (aid, multiply = 1) => {
// 投币
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: '//api.bilibili.com/x/web-interface/coin/add',
data: {
aid: aid,
multiply: multiply,
cross_domain: true
}
});
},
share_add: (aid) => {
// 分享
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: '//api.bilibili.com/x/web-interface/share/add',
data: {
aid: aid,
jsonp: 'jsonp'
}
});
},
heartbeat: (aid, cid, mid, start_ts, played_time = 0, realtime = 0, type = 3, play_type = 1, dt = 2) => {
// B站视频心跳
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: '//api.bilibili.com/x/report/web/heartbeat',
data: {
aid: aid,
cid: cid,
mid: mid, // uid
start_ts: start_ts || (Date.now() / 1000),
played_time: played_time,
realtime: realtime,
type: type,
play_type: play_type, // 1:播放开始,2:播放中
dt: dt
}
});
},
now: () => {
// 点击播放视频时出现的事件,可能与登录/观看视频判定有关
return BilibiliAPI.ajax({
url: '//api.bilibili.com/x/report/click/now',
data: {
jsonp: 'jsonp'
}
});
}
},
xlive: {
guard: {
join: (roomid, id, type = 'guard') => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'xlive/lottery-interface/v3/guard/join',
data: {
roomid: roomid,
id: id,
type: type
}
});
}
},
lottery: {
check: (roomid) => {
return BilibiliAPI.ajax({
url: 'xlive/lottery-interface/v1/lottery/Check',
data: {
roomid: roomid
}
});
}
},
smalltv: {
check: (roomid) => {
return BilibiliAPI.ajax({
url: 'xlive/lottery-interface/v3/smalltv/Check',
data: {
roomid: roomid
}
});
},
join: (roomid, id, type = 'small_tv') => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'xlive/lottery-interface/v5/smalltv/join',
data: {
roomid: roomid,
id: id,
type: type
}
});
},
notice: (raffleId, type = 'small_tv') => {
return BilibiliAPI.ajax({
url: 'xlive/lottery-interface/v3/smalltv/Notice',
data: {
type: type,
raffleId: raffleId
}
});
}
},
pk: {
check: (roomid) => {
return BilibiliAPI.ajax({
url: 'xlive/lottery-interface/v1/pk/check',
data: {
roomid: roomid
}
});
},
join: (roomid, id) => {
return BilibiliAPI.ajaxWithCommonArgs({
method: 'POST',
url: 'xlive/lottery-interface/v1/pk/join',
data: {
roomid: roomid,
id: id
}
});
}
}
},
YearWelfare: {
checkFirstCharge: () => {
return BilibiliAPI.ajax({
url: 'YearWelfare/checkFirstCharge'
});
},
inviteUserList: () => {
return BilibiliAPI.ajax({
url: 'YearWelfare/inviteUserList/1'
});
}
},
DanmuWebSocket: class extends WebSocket {
static stringToUint(string) {
const charList = string.split('');
const uintArray = [];
for (var i = 0; i < charList.length; ++i) {
uintArray.push(charList[i].charCodeAt(0));
}
return new Uint8Array(uintArray);
}
static uintToString(uintArray) {
return decodeURIComponent(escape(String.fromCharCode.apply(null, uintArray)));
}
constructor(uid, roomid, host_server_list, token) {
// 总字节长度 int(4bytes) + 头字节长度(16=4+2+2+4+4) short(2bytes) + protover(1,2) short(2bytes) + operation int(4bytes) + sequence(1,0) int(4bytes) + Data
let address = 'wss://broadcastlv.chat.bilibili.com/sub';
if (Array.isArray(host_server_list) && host_server_list.length > 0) {
let flag = false;
do {
const chosen = host_server_list.shift();
if (chosen.wss_port) address = `wss://${chosen.host}:${chosen.wss_port}/sub`;
else flag = true;
} while (flag && host_server_list.length > 0);
} else if (typeof host_server_list === 'string' && host_server_list.length > 0) {
address = host_server_list;
}
super(address);
this.binaryType = 'arraybuffer';
this.handlers = {
reconnect: [],
login: [],
heartbeat: [],
cmd: [],
receive: []
};
this.host_server_list = host_server_list;
this.token = token;
this.closed = false;
this.addEventListener('open', () => {
this.sendLoginPacket(uid, roomid).sendHeartBeatPacket();
this.heartBeatHandler = setInterval(() => {
this.sendHeartBeatPacket();
}, 30e3);
});
this.addEventListener('close', () => {
if (this.heartBeatHandler) clearInterval(this.heartBeatHandler);
if (this.closed) return;
// 自动重连
setTimeout(() => {
const ws = new BilibiliAPI.DanmuWebSocket(uid, roomid, this.host_server_list, this.token);
ws.handlers = this.handlers;
ws.unzip = this.unzip;
for (const key in this.handlers) {
if (this.handlers.hasOwnProperty(key)) {
this.handlers[key].forEach(handler => {
switch (key) {
case 'reconnect':
ws.addEventListener('reconnect', (event) => {
handler.call(ws, event.detail.ws);
});
break;
case 'login':
ws.addEventListener('login', () => {
handler.call(ws);
});
break;
case 'heartbeat':
ws.addEventListener('heartbeat', (event) => {
handler.call(ws, event.detail.num);
});
break;
case 'cmd':
ws.addEventListener('cmd', (event) => {
handler.call(ws, event.detail.obj, event.detail.str);
});
break;
case 'receive':
ws.addEventListener('receive', (event) => {
handler.call(ws, event.detail.len, event.detail.headerLen, event.detail.protover, event.detail.operation, event.detail.sequence, event.detail.data);
});
break;
}
});
}
}
this.dispatchEvent(new CustomEvent('reconnect', {
detail: {
ws: ws
}
}));
}, 10e3);
});
this.addEventListener('message', (event) => {
const dv = new DataView(event.data);
let len = 0;
for (let position = 0; position < event.data.byteLength; position += len) {
/*
登录 总字节长度 int(4bytes) + 头字节长度 short(2bytes) + 00 01 + 00 00 00 08 + 00 00 00 01
心跳 总字节长度 int(4bytes) + 头字节长度 short(2bytes) + 00 01 + 00 00 00 03 + 00 00 00 01 + 直播间人气 int(4bytes)
弹幕消息/系统消息/送礼 总字节长度 int(4bytes) + 头字节长度 short(2bytes) + 00 00 + 00 00 00 05 + 00 00 00 00 + Data
*/
len = dv.getUint32(position);
const headerLen = dv.getUint16(position + 4);
const protover = dv.getUint16(position + 6);
const operation = dv.getUint32(position + 8);
const sequence = dv.getUint32(position + 12);
let data = event.data.slice(position + headerLen, position + len);
if (protover === 2 && this.unzip) data = this.unzip(data);
this.dispatchEvent(new CustomEvent('receive', {
detail: {
len: len,
headerLen: headerLen,
protover: protover,
operation: operation,
sequence: sequence,
data: data
}
}));
if (protover === 2 && !this.unzip) continue;
const dataV = new DataView(data);
switch (operation) {
case 3:
{
const num = dataV.getUint32(0); // 在线人数
this.dispatchEvent(new CustomEvent('heartbeat', {
detail: {
num: num
}
}));
break;
}
case 5:
{
const str = BilibiliAPI.DanmuWebSocket.uintToString(new Uint8Array(data));
const obj = JSON.parse(str);
this.dispatchEvent(new CustomEvent('cmd', {
detail: {
obj: obj,
str: str
}
}));
break;
}
case 8:
this.dispatchEvent(new CustomEvent('login'));
break;
}
}
});
}
close(code, reason) {
this.closed = true;
super.close(code, reason);
}
setUnzip(fn) {
this.unzip = fn;
}
bind(onreconnect = undefined, onlogin = undefined, onheartbeat = undefined, oncmd = undefined, onreceive = undefined) {
/*
参数说明
onreconnect(DanmuWebSocket) // 必要,DanmuWebSocket为新的
onlogin()
onheartbeat(number)
oncmd(object, string)
onreceive(number, number, number, number, number, arraybuffer)
*/
if (typeof onreconnect === 'function') {
this.addEventListener('reconnect', (event) => {
onreconnect.call(this, event.detail.ws);
});
this.handlers.reconnect.push(onreconnect);
}
if (typeof onlogin === 'function') {
this.addEventListener('login', () => {
onlogin.call(this);
});
this.handlers.login.push(onlogin);
}
if (typeof onheartbeat === 'function') {
this.addEventListener('heartbeat', (event) => {
onheartbeat.call(this, event.detail.num);
});
this.handlers.heartbeat.push(onheartbeat);
}
if (typeof oncmd === 'function') {
this.addEventListener('cmd', (event) => {
oncmd.call(this, event.detail.obj, event.detail.str);
});
this.handlers.cmd.push(oncmd);
}
if (typeof onreceive === 'function') {
this.addEventListener('receive', (event) => {
onreceive.call(this, event.detail.len, event.detail.headerLen, event.detail.protover, event.detail.operation, event.detail.sequence, event.detail.data);
});
this.handlers.receive.push(onreceive);
}
}
sendData(data, protover, operation, sequence) {
if (this.readyState !== WebSocket.OPEN) throw new Error('DanmuWebSocket未连接');
switch (Object.prototype.toString.call(data)) {
case '[object Object]':
return this.sendData(JSON.stringify(data), protover, operation, sequence);
case '[object String]':
{
let dataUint8Array = BilibiliAPI.DanmuWebSocket.stringToUint(data);
let buffer = new ArrayBuffer(BilibiliAPI.DanmuWebSocket.headerLength + dataUint8Array.byteLength);
let dv = new DataView(buffer);
dv.setUint32(0, BilibiliAPI.DanmuWebSocket.headerLength + dataUint8Array.byteLength);
dv.setUint16(4, BilibiliAPI.DanmuWebSocket.headerLength);
dv.setUint16(6, parseInt(protover, 10));
dv.setUint32(8, parseInt(operation, 10));
dv.setUint32(12, parseInt(sequence, 10));
for (let i = 0; i < dataUint8Array.byteLength; ++i) {
dv.setUint8(BilibiliAPI.DanmuWebSocket.headerLength + i, dataUint8Array[i]);
}
this.send(buffer);
}
return this;
default:
this.send(data);
}
return this;
}
sendLoginPacket(uid, roomid) {
// 总字节长度 int(4bytes) + 头字节长度 short(2bytes) + 00 01 + 00 00 00 07 + 00 00 00 01 + Data 登录数据包
const data = {
'uid': parseInt(uid, 10),
'roomid': parseInt(roomid, 10),
'protover': 2,
'platform': 'web',
'clientver': '1.8.5',
'type': 2,
'key': this.token
};
return this.sendData(data, 1, 7, 1);
}
sendHeartBeatPacket() {
// 总字节长度 int(4bytes) + 头字节长度 short(2bytes) + 00 01 + 00 00 00 02 + 00 00 00 01 + Data 心跳数据包
return this.sendData('[object Object]', 1, 2, 1);
}
}
};
BilibiliAPI.DanmuWebSocket.headerLength = 16;