// ==UserScript==
// @name Bilibili直播间挂机助手
// @namespace SeaLoong
// @version 1.2.6
// @description Bilibili直播间自动签到,领瓜子,加入抽奖,完成任务,送礼等
// @author SeaLoong
// @include /https?:\/\/live\.bilibili\.com\/\d+/
// @grant none
// @run-at document-end
// @license MIT License
// ==/UserScript==
(function() {
'use strict';
/* 可修改以下内容用以自定义功能 */
var CONFIG = { // 请注意JSON格式
USE_SIGN: true, // 自动签到: true:启用, false:不启用
USE_AWARD: true, // 自动领取瓜子: true:启用, false:不启用
USE_LOTTERY: true, // 自动加入抽奖: true:启用, false:不启用
USE_TASK: true, // 自动完成任务: true:启用, false:不启用
USE_GIFT: true, // 自动送礼物: true:启用, false:不启用
GIFT_CONFIG: { // 若启用自动送礼物,则需要设置以下项
SHORT_ROOMID: 0, // 送礼物的直播间ID(即地址中live.bilibili.com/后面的数字), 设置为0则表示自动检查当前主播勋章
CHANGE_MEDAL: false, // 当有当前主播勋章,且当前佩戴的勋章不是当前主播勋章时自动切换为当前主播勋章: true:自动切换,false:不切换
USE_SILVER: false, // 消耗银瓜子购买辣条来送礼物: true:允许, false:不允许
ONLY_AFTER_23: true, // 只允许在23:00后消耗银瓜子购买辣条送礼物: true:只允许23:00后,false:任意时间都可用银瓜子
ALLOW_GIFT: [1] // 设置允许送的礼物类型编号(见下方列表),多个请用英文逗号(,)隔开,为空则表示允许送出所有类型的礼物
},
SHOW_TOAST: true // 显示浮动提示: true:显示,false:不显示
};
/* 可修改以上内容用以自定义功能 */
/* 礼物编号及对应礼物、亲密度对照表
(有些数据暂时不清楚,如有知道的可以告诉我,目前采用的亲密度计算方法是:礼物亲密度=向下取整(礼物价值瓜子数/100))
1:辣条:亲密度+1
3:B坷垃:亲密度+99
4:喵娘:亲密度+52
6:亿元:亲密度+10
7:666:亲密度+?
8:233:亲密度+?
25:小电视:亲密度+12450?
39:节奏风暴:亲密度+1000?
105:火力票:亲密度+20
106:哔哩星:亲密度+20
*/
var NAME = 'Bilibili-LiveRoom-HangHelper';
var TaskAward_Running = false;
var ToastElement, ToastCount = 0;
var DOM = {
treasure: {
div: null,
image: null,
canvas: null,
div_tip: null,
div_timer: null
},
storm: {
div: null,
image: null,
canvas: null
}
};
var interval_treasure_timer;
var room_id_list = [];
var lottery_list_last = [],
lottery_check_time = 20;
var gift_list;
var Info = {
short_id: null,
uid: null,
ruid: null,
roomid: null,
rnd: null,
area_id: null, // area_v2_id
area_parent_id: null,
old_area_id: null, // areaId
csrf_token: function() {
return getCookie('bili_jct');
},
today_feed: null,
day_limit: null,
silver: null,
gold: null,
mobile_verified: null,
medal_list: null,
medal_target_id: null,
task_list: null,
bag_list: null
};
var DEBUG = function(arg) {
console.debug(arg);
};
var API = {
last_ajax: 0,
cnt_fast_ajax: 0,
ajax: function(settings) {
if (Date.now() - API.last_ajax < 20) {
API.cnt_fast_ajax += 1;
API.last_ajax = Date.now();
}
if (API.cnt_fast_ajax > 5) throw Error('调用Bilibili API太快,可能出现了bug');
// DEBUG('API.ajax: settings:' + JSON.stringify(settings));
if (settings.xhrFields) {
$.extend(settings.xhrFields, {
withCredentials: true
});
} else {
settings.xhrFields = {
withCredentials: true
};
}
$.extend(settings, {
url: (settings.url.substr(0, 2) == '//' ? '' : '//api.live.bilibili.com/') + settings.url,
type: settings.type || 'GET',
crossDomain: true,
dataType: settings.dataType || 'json'
});
return $.ajax(settings);
},
ajaxGetCaptchaKey: function() {
return API.ajax({
url: '//www.bilibili.com/plus/widget/ajaxGetCaptchaKey.php?js'
});
},
msg: function(roomid, csrf_token) {
return API.ajax({
type: 'POST',
url: 'ajax/msg',
data: {
roomid: roomid,
csrf_token: typeof csrf_token == 'function' ? csrf_token() : csrf_token
}
});
},
ajaxCapsule: function(id, ts, platform, player_type) {
return API.ajax({
url: 'api/ajaxCapsule'
});
},
player: function(id, ts, platform, player_type) { //获取直播流相关信息
return API.ajax({
url: 'api/player',
data: {
id: id,
ts: ts, // HEX
platform: platform || 'pc',
player_type: player_type || 'web'
},
dataType: 'text'
});
},
create: function(width, height) { // 生成一个验证码
return API.ajax({
url: 'captcha/v1/Captcha/create',
data: {
width: width,
height: height,
_: Date.now()
}
});
},
topList: function(roomid, page, ruid) {
return API.ajax({
url: 'guard/topList',
data: {
roomid: roomid,
page: page,
ruid: ruid
}
});
},
getSuser: function() {
return API.ajax({
url: 'msg/getSuser'
});
},
refresh: function() {
return API.ajax({
url: 'index/refresh?area=all'
});
},
get_ip_addr: function() {
return API.ajax({
url: 'ip_service/v1/ip_service/get_ip_addr'
});
},
ajaxGetMyMedalList: function() {
return API.ajax({
url: '//live.bilibili.com/i/ajaxGetMyMedalList'
});
},
getuserinfo: function() {
return API.ajax({
url: '//live.bilibili.com/user/getuserinfo'
});
},
MyInfo: function() {
return API.ajax({
url: '//space.bilibili.com/ajax/member/MyInfo'
});
},
activity: {
mobileActivity: function() {
return API.ajax({
url: 'activity/v1/Common/mobileActivity'
});
},
roomInfo: function(roomid, ruid) {
return API.ajax({
url: 'activity/v1/Common/roomInfo',
data: {
roomid: roomid,
ruid: ruid
}
});
},
welcomeInfo: function(roomid) {
return API.ajax({
url: 'activity/v1/Common/welcomeInfo?roomid=' + roomid
});
},
master_invite_task: function() {
return API.ajax({
url: 'activity/v1/invite/master_invite_task'
});
},
check: function(roomid) {
return API.ajax({
url: 'activity/v1/Raffle/check?roomid=' + roomid
});
},
join: function(roomid, raffleId) {
return API.ajax({
url: 'activity/v1/Raffle/join',
data: {
roomid: roomid,
raffleId: raffleId
}
});
},
notice: function(roomid, raffleId) {
return API.ajax({
url: 'activity/v1/Raffle/notice',
data: {
roomid: roomid,
raffleId: raffleId
}
});
},
master_limit_tasks: function() {
return API.ajax({
url: 'activity/v1/task/master_limit_tasks'
});
},
receive_award: function(task_id, csrf_token) {
return API.ajax({
type: 'POST',
url: 'activity/v1/task/receive_award',
data: {
task_id: task_id,
csrf_token: typeof csrf_token == 'function' ? csrf_token() : csrf_token
}
});
},
user_limit_tasks: function() {
return API.ajax({
url: 'activity/v1/task/user_limit_tasks'
});
}
},
feed: {
getList: function(page, page_size) {
return API.ajax({
url: 'feed/v1/feed/getList',
data: {
page: page,
page_size: page_size,
_: Date.now()
}
});
},
heartBeat: function(_cb) {
return API.ajax({
url: 'feed/v1/feed/heartBeat',
data: {
_cb: _cb
}
});
},
GetUserFc: function(follow) { // follow: 主播uid==ruid
return API.ajax({
url: 'feed/v1/Feed/GetUserFc?follow=' + follow
});
},
IsUserFollow: function(follow) { // follow: 主播uid==ruid
return API.ajax({
url: 'feed/v1/Feed/IsUserFollow?follow=' + follow
});
},
},
feed_svr: {
notice: function(csrf_token) {
return API.ajax({
type: 'POST',
url: 'feed_svr/v1/feed_svr/notice',
data: {
csrf_token: typeof csrf_token == 'function' ? csrf_token() : csrf_token
}
});
},
my: function(page_size, csrf_token, live_status, type, offset) {
return API.ajax({
type: 'POST',
url: 'feed_svr/v1/feed_svr/my',
data: {
live_status: live_status || 0,
type: type || 0,
page_size: page_size,
offset: offset || 0,
csrf_token: typeof csrf_token == 'function' ? csrf_token() : csrf_token
}
});
}
},
FreeSilver: {
getSurplus: function() {
return API.ajax({
url: 'FreeSilver/getSurplus'
});
},
getAward: function(time_start, end_time, captcha) {
return API.ajax({
url: 'FreeSilver/getAward',
data: {
time_start: time_start,
end_time: end_time,
captcha: captcha
}
});
},
getCurrentTask: function() {
return API.ajax({
url: 'FreeSilver/getCurrentTask'
});
},
getCaptcha: function(ts, callback) {
getBlobDataURL("//api.live.bilibili.com/freeSilver/getCaptcha?ts=" + ts, callback);
}
},
gift: {
bag_list: function() {
return API.ajax({
url: 'gift/v2/gift/bag_list'
});
},
send: function(uid, gift_id, ruid, gift_num, coin_type, biz_id, rnd, csrf_token, platform, biz_code, storm_beat_id) {
return API.ajax({
type: 'POST',
url: 'gift/v2/gift/send',
data: {
uid: uid,
gift_id: gift_id,
ruid: ruid,
gift_num: gift_num,
coin_type: coin_type || 'silver',
bag_id: 0,
platform: platform || 'pc',
biz_code: biz_code || 'live',
biz_id: biz_id, //roomid
rnd: rnd,
storm_beat_id: storm_beat_id || 0,
// metadata: metadata,
csrf_token: typeof csrf_token == 'function' ? csrf_token() : csrf_token
}
});
},
bag_send: function(uid, gift_id, ruid, gift_num, bag_id, biz_id, rnd, csrf_token, platform, biz_code, storm_beat_id) {
return API.ajax({
type: '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 || 'pc',
biz_code: biz_code || 'live',
biz_id: biz_id, //roomid
rnd: rnd,
storm_beat_id: storm_beat_id || 0,
// metadata: metadata,
csrf_token: typeof csrf_token == 'function' ? csrf_token() : csrf_token
}
});
},
heart_gift_receive: function(roomid, area_v2_id) {
return API.ajax({
url: 'gift/v2/live/heart_gift_receive',
data: {
roomid: roomid,
area_v2_id: area_v2_id
}
});
},
heart_gift_status: function(roomid, area_v2_id) {
return API.ajax({
url: 'gift/v2/live/heart_gift_status',
data: {
roomid: roomid,
area_v2_id: area_v2_id
}
});
},
receive_daily_bag: function() {
return API.ajax({
url: 'gift/v2/live/receive_daily_bag'
});
},
room_gift_list: function(roomid, area_v2_id) {
return API.ajax({
url: 'gift/v2/live/room_gift_list',
data: {
roomid: roomid,
area_v2_id: area_v2_id
}
});
},
smalltv: {
check: function(roomid) {
return API.ajax({
url: 'gift/v2/smalltv/check',
data: {
roomid: roomid
}
});
},
join: function(roomid, raffleId) {
return API.ajax({
url: 'gift/v2/smalltv/join',
data: {
roomid: roomid,
raffleId: raffleId
}
});
},
notice: function(roomid, raffleId) {
return API.ajax({
url: 'gift/v2/smalltv/notice',
data: {
roomid: roomid,
raffleId: raffleId
}
});
}
}
},
giftBag: {
getSendGift: function() {
return API.ajax({
url: 'giftBag/getSendGift'
});
},
sendDaily: function() {
return API.ajax({
url: 'giftBag/sendDaily'
});
}
},
i: {
ajaxGetAchieve: function(page, pageSize, type, status, category, keywords) {
return API.ajax({
url: 'i/api/ajaxGetAchieve',
data: {
type: type || 'normal', // or'legend'
status: status || 0,
category: category || 'all',
keywords: keywords,
page: page,
pageSize: pageSize || 6
}
});
},
ajaxCancelWear: function() {
return API.ajax({
url: 'i/ajaxCancelWear'
});
},
ajaxWearFansMedal: function(medal_id) {
return API.ajax({
url: 'i/ajaxWearFansMedal?medal_id=' + medal_id
});
},
following: function(page, pageSize) {
return API.ajax({
url: 'i/api/following',
data: {
page: page,
pageSize: pageSize
}
});
},
guard: function(page, pageSize) {
return API.ajax({
url: 'i/api/guard',
data: {
page: page,
pageSize: pageSize
}
});
},
liveinfo: function() {
return API.ajax({
url: 'i/api/liveinfo'
});
},
medal: function(page, pageSize) {
return API.ajax({
url: 'i/api/medal',
data: {
page: page,
pageSize: pageSize
}
});
},
operation: function(page) {
return API.ajax({
url: 'i/api/operation?page=' + page
});
},
taskInfo: function() {
return API.ajax({
url: 'i/api/taskInfo'
});
}
},
live: {
getRoomKanBanModel: function(roomid) {
return API.ajax({
url: 'live/getRoomKanBanModel?roomid' + roomid
});
},
rankTab: function(roomid) {
return API.ajax({
url: 'live/rankTab?roomid=' + roomid
});
},
roomAdList: function() {
return API.ajax({
url: 'live/roomAdList'
});
}
},
live_user: {
get_anchor_in_room: function(roomid) {
return API.ajax({
url: 'live_user/v1/UserInfo/get_anchor_in_room?roomid=' + roomid
});
},
get_info_in_room: function(roomid) {
return API.ajax({
url: 'live_user/v1/UserInfo/get_info_in_room?roomid=' + roomid
});
},
get_weared_medal: function(uid, target_id, csrf_token, source) {
return API.ajax({
type: 'POST',
url: 'live_user/v1/UserInfo/get_weared_medal',
data: {
source: source || 1,
uid: uid,
target_id: target_id, // roomid
csrf_token: typeof csrf_token == 'function' ? csrf_token() : csrf_token
}
});
}
},
lottery: {
getRoomActivityByRoomid: function(roomid) {
return API.ajax({
url: 'lottery/v1/box/getRoomActivityByRoomid?roomid=' + roomid
});
},
check: function(roomid) {
return API.ajax({
url: 'lottery/v1/Storm/check?roomid=' + roomid
});
},
join: function(id, color, captcha_token, captcha_phrase, csrf_token) { // 加入节奏风暴
return API.ajax({
type: 'POST',
url: 'lottery/v1/Storm/join',
data: {
id: id,
color: color, // HEX
captcha_token: captcha_token,
captcha_phrase: captcha_phrase,
csrf_token: typeof csrf_token == 'function' ? csrf_token() : csrf_token
}
});
}
},
rankdb: {
roomInfo: function(ruid, roomid, areaId) {
return API.ajax({
url: 'rankdb/v1/Common/roomInfo',
data: {
ruid: ruid,
roomid: roomid,
areaId: areaId
}
});
}
},
room: {
get_info: function(room_id, from) {
return API.ajax({
url: 'room/v1/Room/get_info',
data: {
room_id: room_id,
from: from || 'room'
}
});
},
playUrl: function(cid, quality, platform) {
return API.ajax({
url: 'room/v1/Room/playUrl',
data: {
cid: cid, // roomid
quality: quality || '0',
platform: platform || 'web'
}
});
},
room_entry_action: function(room_id, csrf_token, platform) {
return API.ajax({
type: 'POST',
url: 'room/v1/Room/room_entry_action',
data: {
room_id: room_id,
platform: platform || 'pc',
csrf_token: typeof csrf_token == 'function' ? csrf_token() : csrf_token
}
});
},
room_init: function(id) {
return API.ajax({
url: 'room/v1/Room/room_init?id=' + id
});
}
},
sign: {
doSign: function() {
return API.ajax({
url: 'sign/doSign'
});
},
GetSignInfo: function() {
return API.ajax({
url: 'sign/GetSignInfo'
});
},
getLastMonthSignDays: function() {
return API.ajax({
url: 'sign/getLastMonthSignDays'
});
}
},
user: {
getWear: function(uid) {
return API.ajax({
url: 'user/v1/user_title/getWear?uid=' + uid
});
},
userOnlineHeart: function() {
return API.ajax({
type: 'POST',
url: 'User/userOnlineHeart'
});
},
getUserInfo: function(ts) { // ms
return API.ajax({
url: 'User/getUserInfo?ts=' + ts
});
}
},
YearWelfare: {
checkFirstCharge: function() {
return API.ajax({
url: 'YearWelfare/checkFirstCharge'
});
},
inviteUserList: function() {
return API.ajax({
url: 'YearWelfare/inviteUserList/1'
});
}
}
};
function ts_s() {
return Math.floor(Date.now() / 1000);
}
function ts_ms() {
return Date.now();
}
function getCookie(name) {
var arr, reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)');
if ((arr = document.cookie.match(reg))) {
return unescape(arr[2]);
} else {
return null;
}
}
function setCookie(name, value, seconds) {
seconds = seconds || 0;
var expires = '';
if (parseInt(seconds) !== 0) {
var date = new Date();
date.setTime(date.getTime() + (seconds * 1000));
expires = '; expires=' + date.toGMTString();
}
document.cookie = name + '=' + escape(value) + expires + '; path=/';
}
function getBlobDataURL(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.withCredentials = true;
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
xhr.send();
}
/*
验证码识别算法来自互联网,作者未知
该算法已被简单修改
*/
function getChar(t) {
if (t.sum <= 50) return '-';
if (t.sum > 120 && t.sum < 135) return '+';
if (t.sum > 155 && t.sum < 162) return 1;
if (t.sum > 189 && t.sum < 195) return 7;
if (t.sum > 228 && t.sum < 237) return 4;
if (t.sum > 250 && t.sum < 260) return 2;
if (t.sum > 286 && t.sum < 296) return 3;
if (t.sum > 303 && t.sum < 313) return 5;
if (t.sum > 335 && t.sum < 342) return 8;
if (t.sum > 343 && t.sum < 350) {
if (t.first > 24 && t.last > 24) return 0;
if (t.first < 24 && t.last > 24) return 9;
if (t.first > 24 && t.last < 24) return 6;
}
}
function calcImg() {
/*
* 1.验证码图片->二维点阵
* 2.二维点阵->横向一维压缩
* 3.分析并计算
*/
var ctx = DOM.treasure.canvas[0].getContext("2d");
ctx.drawImage(DOM.treasure.image[0], 0, 0, 120, 40);
var pixels = ctx.getImageData(0, 0, 120, 40).data;
var pix = [];
var i = 0;
var j = 0;
var n = 0;
for (i = 1; i <= 40; i++) {
pix[i] = [];
for (j = 1; j <= 120; j++) {
var c = 1;
if (pixels[n] - (-pixels[n + 1]) - (-pixels[n + 2]) > 200) {
c = 0;
}
n += 4;
pix[i][j] = c;
}
}
//二维点阵pix[40][120]
var line = [];
line[0] = 0;
for (i = 1; i <= 120; i++) {
line[i] = 0;
for (j = 1; j <= 40; j++) {
line[i] += pix[j][i];
}
}
//一维line[120]
var temp = [];
n = 0;
for (i = 1; i <= 120; i++) {
if (line[i] > 0 && line[i - 1] === 0) {
n++;
temp[n] = {};
temp[n].first = line[i];
temp[n].sum = 0;
}
if (line[i] > 0) {
temp[n].sum += line[i];
}
if (line[i - 1] > 0 && line[i] === 0) {
temp[n].last = line[i - 1];
}
}
if (n == 4) {
var result = 0;
var a = getChar(temp[1]) * 10 - (-getChar(temp[2]));
var b = getChar(temp[4]);
if (getChar(temp[3]) == '+') {
result = a - (-b);
} else {
result = a - b;
}
DEBUG('TaskAward: calcImg: 识别验证码: ' + getChar(temp[1]) + getChar(temp[2]) + ' ' + getChar(temp[3]) + ' ' + getChar(temp[4]) + ' = ' + result);
return result;
} else {
DEBUG('TaskAward: calcImg: 识别验证码失败');
return null;
}
}
function recognizeCaptcha() {
var ctx = DOM.storm.canvas[0].getContext('2d');
ctx.drawImage(DOM.storm.image[0], 0, 0, 112, 32);
return OCRAD(ctx.getImageData(0, 0, 112, 32));
}
var liveQuickLogin = function() {
if (!getCookie('DedeUserID') && !getCookie('LIVE_LOGIN_DATA')) {
try {
if (!window.biliQuickLogin) {
$.getScript('https://static-s.bilibili.com/account/bili_quick_login.js', function(response, status) {
if (status === 'success') login();
});
} else {
login();
}
} catch (tryErr) {
throw new Error(tryErr);
}
}
function login() {
if (window.biliQuickLogin) {
window.biliQuickLogin(function() {
window.location.reload();
});
throw 'Bilibili Live: 您还未登陆.';
} else {
throw 'Bilibili Live: 快速登录脚本加载失败.';
}
}
};
function giftIDtoFeed(gift_id) {
for (var i = gift_list.length - 1; i >= 0; i--) {
if (gift_list[i].id === gift_id) {
return Math.floor(gift_list[i].price / 100);
}
}
return 0;
}
function toast(t, e, n, r) {
if (!CONFIG.SHOW_TOAST || !t) return;
if ('boolean' == typeof n) n = 'info';
var o = document.createDocumentFragment(),
a = document.createElement('div');
if ('success' !== (n = n || 'info') && 'caution' !== n && 'error' !== n && 'info' !== n)
throw new Error(i + ' 在使用 Link Toast 时必须指定正确的类型: success || caution || error || info');
if (a.innerHTML = '<span class="toast-text">' + e + '</span>',
a.className = 'link-toast ' + n + ' ' + (r ? 'fixed' : ''), !t.className && !t.attributes)
throw new Error(i + ' 传入 element 不是有效节点.');
var c = t.getBoundingClientRect(),
s = c.left,
u = c.top,
l = c.width,
f = c.height,
p = document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft;
a.style.left = s + l + p + 'px';
var d = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop;
a.style.top = u + f + d + ToastCount * 40 + 'px';
setTimeout((function() {
a.className += ' out';
setTimeout((function() { // TODO
ToastCount = 0;
a.parentNode.removeChild(a);
}), 350);
}), 3e3);
o.appendChild(a);
document.body.appendChild(o);
var h = document.body.offsetWidth,
v = a.getBoundingClientRect().left,
m = a.offsetWidth;
if (h - m - v < 0) a.style.left = h - m - 10 + p + 'px';
ToastCount += 1;
}
function execUntilSuccess(callback) {
var interval = setInterval(function() {
if (callback()) clearInterval(interval);
}, 200);
}
/*
window.BilibiliLive.ANCHOR_UID
window.BilibiliLive.COLORFUL_LOGGER
window.BilibiliLive.INIT_TIME
window.BilibiliLive.RND === window.DANMU_RND
window.BilibiliLive.ROOMID
window.BilibiliLive.SHORT_ROOMID
window.BilibiliLive.UID
window.captcha_key
window.Yb
*/
function Init() {
// liveQuickLogin();
execUntilSuccess(function() {
if (window.BilibiliLive) {
DEBUG('Init: BilibiliLive: ' + JSON.stringify(window.BilibiliLive));
if (parseInt(window.BilibiliLive.UID) !== 0) {
Info.short_id = window.BilibiliLive.SHORT_ROOMID;
Info.uid = window.BilibiliLive.UID;
Info.roomid = window.BilibiliLive.ROOMID;
Info.ruid = window.BilibiliLive.ANCHOR_UID;
Info.rnd = window.BilibiliLive.RND;
room_id_list[Info.short_id] = Info.roomid;
if (CONFIG.USE_AWARD) {
execUntilSuccess(function() {
var _treasure_box = $('div.treasure-box.p-relative');
if (_treasure_box[0]) {
_treasure_box.attr('id', 'old_treasure_box');
_treasure_box.hide();
DOM.treasure.div = $('<div id="' + NAME + '_treasure_div" class="treasure-box p-relative"></div>');
DOM.treasure.div_tip = $('<div id="' + NAME + '_treasure_div_tip" class="t-center b-box none-select">自动<br>领取中</div>');
DOM.treasure.div_timer = $('<div id="' + NAME + '_treasure_div_timer" class="t-center b-box none-select">0</div>');
DOM.treasure.image = $('<img id="' + NAME + '_treasure_image" style="display:none">');
DOM.treasure.canvas = $('<canvas id="' + NAME + '_treasure_canvas" style="display:none" height="40" width="120"></canvas>');
var css_text = {
'max-width': '40px',
'padding': '2px 3px',
'margin-top': '3px',
'font-size': '12px',
'color': '#fff',
'background-color': 'rgba(0,0,0,.5)',
'border-radius': '10px'
};
DOM.treasure.div_tip.css(css_text);
DOM.treasure.div_timer.css(css_text);
DOM.treasure.div_tip.after(DOM.treasure.div_timer);
DOM.treasure.div.append(DOM.treasure.div_tip);
DOM.treasure.div.append(DOM.treasure.image);
DOM.treasure.div.append(DOM.treasure.canvas);
// $('div.vertical-middle.dp-table.section.left-part div.dp-table-cell.v-middle').append(DOM.treasure.div);
_treasure_box.after(DOM.treasure.div);
interval_treasure_timer = setInterval(function() {
var t = parseInt(DOM.treasure.div_timer.text());
if (t > 0) DOM.treasure.div_timer.text(t - 1);
}, 1e3);
return true;
}
});
}
if (CONFIG.USE_LOTTERY) {
DOM.storm.div = $('<div id="' + NAME + '_storm_div" style="display:none"></div>');
DOM.storm.image = $('<img id="' + NAME + '_storm_image" style="display:none">');
DOM.storm.canvas = $('<canvas id="' + NAME + '_storm_canvas" style="display:none"></canvas>');
DOM.storm.div.append(DOM.storm.image);
DOM.storm.div.append(DOM.storm.canvas);
document.body.appendChild(DOM.storm.div[0]);
}
if (CONFIG.USE_GIFT && (CONFIG.GIFT_CONFIG.SHORT_ROOMID === 0 || CONFIG.GIFT_CONFIG.SHORT_ROOMID == Info.short_id)) {
API.live_user.get_weared_medal(Info.uid, Info.roomid, Info.csrf_token).done(function(response) {
DEBUG('Init: get_weared_medal: ' + JSON.stringify(response));
if (response.code === 0) {
Info.medal_target_id = response.data.target_id;
Info.today_feed = parseInt(response.data.today_feed);
Info.day_limit = response.data.day_limit;
Info.old_area_id = response.data.area;
Info.area_id = response.data.area_v2_id;
Info.area_parent_id = response.data.area_v2_parent_id;
API.gift.room_gift_list(Info.roomid, Info.area_id).done(function(response) {
// DEBUG('Init: room_gift_list: ' + JSON.stringify(response));
if (response.code === 0) {
gift_list = response.data;
}
});
}
});
API.live_user.get_info_in_room(Info.roomid).done(function(response) {
DEBUG('Init: get_info_in_room: ' + JSON.stringify(response));
if (response.code === 0) {
Info.silver = response.data.wallet.silver;
Info.gold = response.data.wallet.gold;
Info.mobile_verified = response.data.info.mobile_verified;
}
});
}
setTimeout(function() {
DEBUG('Init: Info: ' + JSON.stringify(Info));
ToastElement = $('<div id="' + NAME + '_div_toast"></div>');
ToastElement.appendTo($('#rank-list-vm'));
ToastElement = ToastElement[0];
var str = [];
if (CONFIG.USE_SIGN) str.push('自动签到');
if (CONFIG.USE_AWARD) str.push('自动领取瓜子');
if (CONFIG.USE_LOTTERY) str.push('自动加入抽奖');
if (CONFIG.USE_TASK) str.push('自动完成任务');
if (CONFIG.USE_GIFT) str.push('自动送礼');
if (str.length) str = str.join(',');
else str = '无';
toast(ToastElement, '助手已启用功能:' + str, 'info');
TaskStart();
}, 3e3);
} else {
// 未登录
toast(ToastElement, '你还没有登录,助手无法使用!', 'error');
}
return true;
}
});
}
/*
function TaskLogWatcher(callback) {
var logs_last_length = 0;
setInterval(function() {
if (logs_last_length !== window.Yb.length) {
var logs_new = window.Yb.slice(logs_last_length, window.Yb.length);
if (logs_new && logs_new.length) {
logs_last_length = window.Yb.length;
callback(logs_new);
}
}
}, 1000);
}
*/
function SmallTV(room_id, callback) {
API.gift.smalltv.check(room_id).done(function(response) { // 检查是否有小电视抽奖
DEBUG('TaskLottery: smalltv.check: ' + JSON.stringify(response));
if (response.code === 0) {
response.data.forEach(function(v) {
if (v.status === 1) { // 可以加入
API.gift.smalltv.join(room_id, v.raffleId).done(function(response) {
DEBUG('TaskLottery: smalltv.join: ' + JSON.stringify(response));
if (response.code === 0) {
setTimeout(function() {
SmallTVNotice(room_id, response.data.raffleId, function(msg) {
toast(ToastElement, msg, 'info');
}, 0);
}, response.data.time * 1e3 + 8e3);
callback();
}
});
}
});
}
});
}
function Raffle(room_id, callback) {
API.activity.check(room_id).done(function(response) { // 检查是否有活动抽奖
DEBUG('TaskLottery: activity.check: ' + JSON.stringify(response));
if (response.code === 0) {
response.data.forEach(function(v) {
if (v.status === 1) {
API.activity.join(room_id, v.raffleId).done(function(response) {
// DEBUG('TaskLottery: activity.join: ' + JSON.stringify(response));
if (response.code === 0) {
setTimeout(function() {
RaffleNotice(room_id, response.data.raffleId, function(msg) {
toast(ToastElement, msg, 'info');
}, 0);
}, response.data.time * 1e3 + 8e3);
callback();
}
});
}
});
}
});
}
function SmallTVNotice(room_id, raffleId, callback, cnt) {
if (cnt > 3) return;
API.gift.smalltv.notice(room_id, raffleId).done(function(response) {
DEBUG('TaskLottery: smalltv.notice: ' + JSON.stringify(response));
if (response.code === 0 && response.data.status !== 3) {
if (parseInt(response.data.gift_id) === -1 && !response.data.gift_name) {
callback(response.msg);
} else {
callback('直播间【' + room_id + '】小电视抽奖结果:' + response.data.gift_name + '*' + response.data.gift_num);
}
} else {
// 还未开奖或其他情况
setTimeout(function() {
SmallTVNotice(room_id, raffleId, callback, cnt + 1);
}, 5e3);
}
});
}
function RaffleNotice(room_id, raffleId, callback, cnt) {
if (cnt > 3) return;
API.activity.notice(room_id, raffleId).done(function(response) {
DEBUG('TaskLottery: activity.notice: ' + JSON.stringify(response));
if (response.code === 0) {
if (parseInt(response.data.gift_id) === -1) {
callback(response.msg);
} else {
callback('直播间【' + room_id + '】活动抽奖结果:' + response.data.gift_name + '*' + response.data.gift_num);
}
} else {
// 还未开奖或其他情况
setTimeout(function() {
RaffleNotice(room_id, raffleId, callback, cnt + 1);
}, 5e3);
}
});
}
function Storm(cnt) {
if (cnt > 3) return;
API.create(112, 32).done(function(response) {
if (response.code === 0) {
DOM.storm.image.load(function() {
// TODO
var phrase = recognizeCaptcha();
// 暂时不清楚验证码与phrase的关系,猜测是对验证码计算sha1
API.lottery.join(id, color, response.data.token, phrase, Info.csrf_token).done(function(response) {
if (response.code === 0) {
toast(ToastElement, '节奏风暴抽奖结果:' + response.data.gift_name + '*' + response.data.gift_num, 'info');
} else {
setTimeout(function() {
Storm(cnt + 1);
}, 1e3);
}
});
});
DOM.storm.image.attr('src', response.data.image);
}
});
}
function Award(callback, cnt) {
if (cnt > 3) {
callback();
return;
}
API.FreeSilver.getCaptcha(ts_ms(), function(dataURL) {
DOM.treasure.image[0].onload = function() {
var captcha = calcImg();
if (captcha) {
// 验证码识别成功
API.FreeSilver.getAward(ts_s(), ts_s(), captcha).done(function(response) {
DEBUG('TaskAward: getAward: ' + JSON.stringify(response));
if (response.code === 0) {
// 领取瓜子成功
toast(ToastElement, '领取了 ' + response.data.awardSilver + ' 银瓜子', 'success');
callback();
} else if (response.code === -903) {
// 已经领取过这个宝箱
callback();
} else if (response.code === -902) {
// 验证码错误
setTimeout(function() {
Award(callback, cnt + 1);
}, 2e3);
} else if (response.code === -901) {
// 验证码过期
setTimeout(function() {
Award(callback, cnt + 1);
}, 2e3);
}
});
} else {
// 验证码识别失败
setTimeout(function() {
Award(callback, cnt);
}, 500);
}
};
DOM.treasure.image[0].src = dataURL;
});
}
function Lottery() {
var lottery_list = [],
lottery_list_temp = [],
overlap_index = Infinity;
$('div.chat-item.system-msg div.msg-content a.link').each(function(index, el) {
var matched = el.pathname.match(/^\/(\d+)/);
if (matched && matched[1]) {
var short_id = parseInt(matched[1]);
lottery_list_temp.push(short_id);
}
});
$.each(lottery_list_temp, function(i, v) {
if (i === 0) {
var index = lottery_list_last.indexOf(v);
if (index > -1) {
overlap_index = lottery_list_last.length - index;
} else {
overlap_index = 0;
lottery_list.push(v);
}
} else if (i >= overlap_index) {
lottery_list.push(v);
}
});
lottery_list_last = lottery_list_temp;
lottery_list_temp = lottery_list;
lottery_list = [];
lottery_list_temp.forEach(function(v) {
if (lottery_list.indexOf(v) === -1) lottery_list.push(v);
});
DEBUG('TaskLottery: Lottery: last: ' + lottery_list_last.toString());
DEBUG('TaskLottery: Lottery: list: ' + lottery_list.toString());
// 根据可抽奖的房间数自动调整检测周期
if (lottery_list.length > 11) {
lottery_check_time = 3;
} else if (lottery_list.length > 9) {
lottery_check_time = 6;
} else if (lottery_list.length > 6) {
lottery_check_time = 10;
} else if (lottery_list.length > 1) {
lottery_check_time = 15;
} else {
lottery_check_time = 20;
}
lottery_list.forEach(function(short_id) {
if (short_id > 0) {
var room_id = room_id_list[short_id];
if (room_id > 0) {
SmallTV(room_id, function() {
toast(ToastElement, '已加入直播间【' + room_id + '】的小电视抽奖', 'success');
});
Raffle(room_id, function() {
toast(ToastElement, '已加入直播间【' + room_id + '】的活动抽奖', 'success');
});
} else {
API.room.room_init(short_id).done(function(response) {
DEBUG('TaskLottery: room_init: ' + JSON.stringify(response));
if (response.code === 0) {
room_id = response.data.room_id;
room_id_list[short_id] = room_id;
SmallTV(room_id, function() {
toast(ToastElement, '已加入直播间【' + room_id + '】的小电视抽奖', 'success');
});
Raffle(room_id, function() {
toast(ToastElement, '已加入直播间【' + room_id + '】的活动抽奖', 'success');
});
}
});
}
}
});
setTimeout(Lottery, lottery_check_time * 1e3);
}
function TaskSign() {
API.sign.GetSignInfo().done(function(response) {
DEBUG('TaskSign: GetSignInfo: ' + JSON.stringify(response));
if (response.code === 0) {
if (response.data.status === 0) {
// 未签到
API.sign.doSign().done(function(response) {
DEBUG('TaskSign: doSign: ' + JSON.stringify(response));
if (response.code === 0) {
// 签到成功
toast(ToastElement, response.data.text, 'success');
} else {
toast(ToastElement, response.data.text, 'error');
}
});
} else if (response.data.status === 1) {
// 已签到
}
}
});
}
function TaskAward_newTask() {
API.FreeSilver.getCurrentTask().done(function(response) {
DEBUG('TaskAward: getCurrentTask: ' + JSON.stringify(response));
if (response.code === 0) {
// 获取任务成功
if (parseInt(response.data.minute) !== 0) {
setTimeout(TaskAward, response.data.minute * 60e3 + 5e3);
TaskAward_Running = true;
execUntilSuccess(function() {
if (DOM.treasure.div_timer) {
DOM.treasure.div_timer.text(response.data.minute * 60e3 + 4e3);
return true;
}
});
execUntilSuccess(function() {
if (DOM.treasure.div_tip) {
DOM.treasure.div_tip.html('次数: ' + response.data.times + '/' + response.data.max_times + '<br>银瓜子: ' + response.data.silver);
return true;
}
});
}
} else if (response.code === -10017) {
// 今天所有的宝箱已经领完!
toast(ToastElement, response.msg, 'info');
clearInterval(interval_treasure_timer);
execUntilSuccess(function() {
if (DOM.treasure.div_tip) {
DOM.treasure.div_tip.html('今日<br>已领完');
return true;
}
});
} else {
toast(ToastElement, response.msg, 'info');
}
});
}
function TaskAward() {
if (TaskAward_Running) Award(TaskAward_newTask, 0);
else TaskAward_newTask();
}
function TaskLottery() {
setTimeout(Lottery, 4e3);
}
function TaskReceiveAward(task_id) {
API.activity.receive_award(task_id, Info.csrf_token).done(function(response) {
// DEBUG('TaskTask: receive_award: ' + JSON.stringify(response));
if (response.code === 0) {
// 完成任务
toast(ToastElement, '完成任务:' + task_id, 'info');
}
});
}
function Task() {
toast(ToastElement, '检查任务情况', 'info');
API.i.taskInfo().done(function(response) {
DEBUG('TaskTask: taskInfo: ' + JSON.stringify(response));
if (response.code === 0) {
for (var key in response.data) {
if (response.data[key].task_id && response.data[key].status) {
// 当前对象是任务且任务可完成
TaskReceiveAward(response.data[key].task_id);
}
}
}
});
API.activity.user_limit_tasks().done(function(response) {
DEBUG('TaskTask: user_limit_tasks: ' + JSON.stringify(response));
if (response.code === 0) {
for (var key in response.data) {
if (response.data[key].task_id && response.data[key].status) {
// 当前对象是任务且任务可完成
TaskReceiveAward(response.data[key].task_id);
}
}
}
});
API.activity.master_limit_tasks().done(function(response) {
DEBUG('TaskTask: master_limit_tasks: ' + JSON.stringify(response));
if (response.code === 0) {
for (var key in response.data) {
if (response.data[key].task_id && response.data[key].status) {
// 当前对象是任务且任务可完成
TaskReceiveAward(response.data[key].task_id);
}
}
}
});
setTimeout(Task, 3600e3);
}
function TaskTask() {
setTimeout(Task, 6e3);
}
function Gift() {
/*
任务周期1小时,脚本运行后立即执行一次任务
判断是否佩戴当前主播的头衔
否:判断是否拥有当前主播的头衔,有则自动切换,没有则停止任务
是:刷新当前亲密度上限和已喂养亲密度
可以继续喂养则刷新背包,不可以则停止任务
按照过期时间(天)从短到长排序,同一天按照礼物提供的亲密度从大到小排序
按已排序的背包顺序送礼,直到亲密度已满或无法送礼,如:亲密度还可增加9但没有辣条,此时不送礼物
可选:消耗银瓜子购买辣条送礼,直到亲密度已满或银瓜子不足
可选:当前时间超过23:00时才消耗银瓜子
*/
API.live_user.get_weared_medal(Info.uid, Info.roomid, Info.csrf_token).done(function(response) {
DEBUG('TaskGift: get_weared_medal: ' + JSON.stringify(response));
if (response.code === 0) {
Info.medal_target_id = response.data.target_id;
if (Info.medal_target_id !== Info.ruid) {
setTimeout(TaskGift, 1e3);
return;
}
Info.today_feed = parseInt(response.data.today_feed);
Info.day_limit = response.data.day_limit;
var remain_feed = Info.day_limit - Info.today_feed;
if (remain_feed > 0) {
toast(ToastElement, '今日亲密度未满,送礼开始', 'info');
API.gift.bag_list().done(function(response) {
DEBUG('TaskGift: bag_list: ' + JSON.stringify(response));
if (response.code === 0) {
Info.bag_list = response.data.list;
// DEBUG('TaskGift: remain_feed: ' + remain_feed + ',day_limit:' + Info.day_limit + ',today_feed:' + Info.today_feed);
$.each(Info.bag_list, function(i, v) {
if (remain_feed <= 0) return false;
else if (CONFIG.GIFT_CONFIG.ALLOW_GIFT.indexOf(v.gift_id) > -1 || !CONFIG.GIFT_CONFIG.ALLOW_GIFT[0]) {
var feed_single = giftIDtoFeed(v.gift_id);
// DEBUG('TaskGift: Before bag_send: remain_feed:' + remain_feed + ',giftIDtoFeed(v.gift_id):' + giftIDtoFeed(v.gift_id) + ',' + JSON.stringify(v));
if (feed_single > 0) {
var feed_num = Math.floor(remain_feed / feed_single);
if (feed_num > v.gift_num) {
feed_num = v.gift_num;
}
// DEBUG('TaskGift: Before bag_send: remain_feed:' + remain_feed + ',feed_num:' + feed_num + ',feed_single:' + feed_single);
if (feed_num > 0) {
API.gift.bag_send(Info.uid, v.gift_id, Info.ruid, feed_num, v.bag_id, Info.roomid, Info.rnd, Info.csrf_token).done(function(response) {
DEBUG('TaskGift: bag_send: ' + JSON.stringify(response));
if (response.code === 0) {
// 送礼成功
Info.rnd = response.data.rnd;
toast(ToastElement, '包裹送礼成功,送出' + feed_num + '个' + v.gift_name, 'success');
} else {
toast(ToastElement, '包裹送礼异常,' + response.msg, 'error');
}
});
remain_feed -= feed_num * feed_single;
}
}
}
});
if (CONFIG.GIFT_CONFIG.USE_SILVER && remain_feed > 0 && (CONFIG.GIFT_CONFIG.ALLOW_GIFT.indexOf(1) > -1 || !CONFIG.GIFT_CONFIG.ALLOW_GIFT[0])) {
if (CONFIG.GIFT_CONFIG.ONLY_AFTER_23) {
DEBUG('TaskGift: 检查当前时间: ' + (new Date()).getHours());
if ((new Date()).getHours() < 23) {
toast(ToastElement, '时间未到23:00', 'info');
setTimeout(Gift, 3600e3);
return;
}
}
var feed_num = remain_feed;
if (feed_num * 100 > Info.silver) {
feed_num = Math.floor(Info.silver / 100);
}
if (feed_num > 0) {
API.gift.send(Info.uid, 1, Info.ruid, feed_num, 'silver', Info.roomid, Info.rnd, Info.csrf_token).done(function(response) {
DEBUG('TaskGift: send: ' + JSON.stringify(response));
if (response.code === 0) {
// 送礼成功
Info.rnd = response.data.rnd;
Info.silver = response.data.extra.wallet.silver;
Info.gold = response.data.extra.wallet.gold;
toast(ToastElement, '银瓜子送礼成功,送出' + feed_num + '个辣条,剩余银瓜子:' + Info.silver, 'success');
} else {
toast(ToastElement, '银瓜子送礼异常,' + response.msg, 'error');
}
});
remain_feed -= feed_num;
}
}
if (remain_feed > 0) {
toast(ToastElement, '送礼结束,1小时后再次送礼', 'info');
setTimeout(Gift, 3600e3);
} else {
toast(ToastElement, '送礼结束,今日亲密度已满', 'info');
}
} else {
toast(ToastElement, '获取包裹礼物异常,' + response.msg, 'error');
}
});
}
} else {
toast(ToastElement, '获取亲密度异常,' + response.msg, 'error');
}
});
}
function TaskGift() {
if (!(CONFIG.GIFT_CONFIG.SHORT_ROOMID === 0 || CONFIG.GIFT_CONFIG.SHORT_ROOMID == Info.short_id)) return;
if (Info.medal_target_id !== Info.ruid) {
if (!CONFIG.GIFT_CONFIG.CHANGE_MEDAL) {
toast(ToastElement, '已佩戴的勋章不是当前主播勋章,送礼功能停止', 'info');
return;
}
API.i.medal(1, 10).done(function(response) {
DEBUG('TaskGift: medal: ' + JSON.stringify(response));
if (response.code === 0) {
Info.medal_list = response.data.fansMedalList;
$.each(Info.medal_list, function(index, v) {
if (v.target_id === Info.ruid) {
API.i.ajaxWearFansMedal(v.medal_id).done(function(response) {
DEBUG('TaskGift: ajaxWearFansMedal: ' + JSON.stringify(response));
toast(ToastElement, '已自动切换为当前主播勋章', 'info');
setTimeout(Gift, 10e3);
});
return false;
}
});
}
});
} else {
setTimeout(Gift, 10e3);
}
}
function TaskStart() {
if (CONFIG.USE_SIGN) TaskSign();
if (CONFIG.USE_AWARD) TaskAward();
if (CONFIG.USE_LOTTERY) TaskLottery();
if (CONFIG.USE_TASK) TaskTask();
if (CONFIG.USE_GIFT) TaskGift();
}
$(document).ready(function() {
DEBUG(NAME + ': 脚本已运行');
Init();
});
})();