// ==UserScript== // @name Bilibili直播间挂机助手 // @namespace SeaLoong // @version 1.4.4 // @description Bilibili直播间自动签到,领瓜子,参加抽奖,完成任务,送礼等 // @author SeaLoong // @include /https?:\/\/live\.bilibili\.com\/\d+/ // @require https://greasyfork.org/scripts/38140-bilibili-api/code/Bilibili-API.js // @grant none // @run-at document-end // @license MIT License // @downloadURL none // ==/UserScript== (function() { 'use strict'; // <-!!!请注意,修改此处设置将不会再生效,请点击页面右下角的"挂机助手设置"打开设置界面进行设置!!!-> var CONFIG = { USE_SIGN: true, // 自动签到 USE_AWARD: true, // 自动领取瓜子 USE_LOTTERY: true, // 自动参加抽奖 LOTTERY_CONFIG: { ALLOW_NOT_SHORT_ROOMID: false // 允许在非短房间号直播间进行抽奖(挂在2号直播间) }, USE_TASK: true, // 自动完成任务 USE_GIFT: false, // 自动送礼物 GIFT_CONFIG: { // 若启用自动送礼物,则需要设置以下项 SHORT_ROOMID: 0, // 送礼物的直播间ID(即地址中live.bilibili.com/后面的数字), 设置为0则表示自动检查当前主播勋章 CHANGE_MEDAL: false, // 设置是否允许 当有当前主播勋章,且当前佩戴的勋章不是当前主播勋章时自动切换为当前主播勋章 SEND_GIFT: ['1'], // 设置默认送的礼物类型编号(见下方列表/点击问号),多个请用英文逗号(,)隔开,为空则表示默认不送出礼物 ALLOW_GIFT: ['1', '4', '6'], // 设置允许送的礼物类型编号(见下方列表/点击问号)(!!任何未在此列表的礼物一定不会被送出!!),多个请用英文逗号(,)隔开,为空则表示允许送出所有类型的礼物 SEND_TODAY: false // 送出包裹中今天到期的礼物(!会送出SEND_GIFT之外的礼物!若今日亲密度已满则不送) }, SHOW_TOAST: true, // 显示浮动提示 EXCHANGE_SILVER2COIN: false // 消耗700银瓜子兑换1个硬币 }; // <-!!!请注意,修改此处设置将不会再生效,请点击页面右下角的"挂机助手设置"打开设置界面进行设置!!!-> /* 礼物编号及对应礼物、亲密度对照表 (有些数据暂时不清楚,如有知道的可以告诉我,目前采用的亲密度计算方法是:礼物亲密度=向上取整(礼物价值瓜子数/100)) 1:辣条:亲密度+1 3:B坷垃:亲密度+99 4:喵娘:亲密度+52 6:亿元:亲密度+10 7:666:亲密度+? 8:233:亲密度+? 25:小电视:亲密度+12450? 39:节奏风暴:亲密度+1000? 105:火力票:亲密度+20 106:哔哩星:亲密度+20 109:红灯笼:亲密度+20 110:小爆竹:亲密度+20 */ /* 此行以下内容请勿修改,当然你要改那我也没办法 */ var DEBUGMODE = false; var DEBUG = function(sign, data) { if (!DEBUGMODE) return; var d = new Date(); d = '[' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() + '.' + d.getMilliseconds() + ']'; window.console.debug(d, sign + ':', data); }; var CONFIG_DEFAULT = { USE_SIGN: true, USE_AWARD: true, USE_LOTTERY: true, LOTTERY_CONFIG: { ALLOW_NOT_SHORT_ROOMID: false }, USE_TASK: true, USE_GIFT: false, GIFT_CONFIG: { SHORT_ROOMID: 0, CHANGE_MEDAL: false, SEND_GIFT: ['1'], ALLOW_GIFT: ['1', '4', '6'], SEND_TODAY: false }, SHOW_TOAST: true, EXCHANGE_SILVER2COIN: false }; var CONFIG_NAME_LIST = { USE_SIGN: '自动签到', USE_AWARD: '自动领取瓜子', USE_LOTTERY: '自动参加抽奖', LOTTERY_CONFIG: '抽奖设置', ALLOW_NOT_SHORT_ROOMID: '允许在任意直播间抽奖(实验)', USE_TASK: '自动完成任务', USE_GIFT: '自动送礼物', GIFT_CONFIG: '送礼设置', SHORT_ROOMID: '房间号', SEND_GIFT: '默认礼物类型', ALLOW_GIFT: '允许礼物类型', CHANGE_MEDAL: '允许切换勋章', SEND_TODAY: '送出包裹中今天到期的礼物', SHOW_TOAST: '显示浮动提示', EXCHANGE_SILVER2COIN: '银瓜子换硬币' }; var CONFIG_PLACEHOLDER_LIST = { SHORT_ROOMID: '为0则自动检测勋章', SEND_GIFT: "为空则默认不送", ALLOW_GIFT: '为空则允许所有' }; var CONFIG_HELP_LIST = { USE_LOTTERY: '设置是否自动参加抽奖功能,包括小电视抽奖、活动(即B站当前进行的活动)抽奖', ALLOW_NOT_SHORT_ROOMID: '(实验性)允许在任意直播间进行抽奖(实际上是挂在一个短号直播间参加抽奖)
注意:会消耗更多的系统资源', SHORT_ROOMID: '送礼物的直播间ID(即地址中live.bilibili.com/后面的数字), 设置为0则表示自动检查当前主播勋章', CHANGE_MEDAL: '设置是否允许“当有当前主播勋章,且当前佩戴的勋章不是当前主播勋章时自动切换为当前主播勋章”', SEND_GIFT: function() { var s = '设置默认送的礼物类型编号,多个请用英文逗号(,)隔开,为空则表示默认不送出礼物'; return s + '

' + gift_list_str; }, ALLOW_GIFT: function() { var s = '设置允许送的礼物类型编号(任何未在此列表的礼物一定不会被送出!),多个请用英文逗号(,)隔开,为空则表示允许送出所有类型的礼物'; return s + '

' + gift_list_str; }, SEND_TODAY: '送出包裹中今天到期的礼物(会送出"默认礼物类型"之外的礼物,若今日亲密度已满则不送)', EXCHANGE_SILVER2COIN: '消耗700银瓜子兑换1个硬币(每天只能兑换一次)' }; var CONFIG_CONTROL_LIST = { USE_GIFT: 'GIFT_CONFIG', USE_LOTTERY: 'LOTTERY_CONFIG' }; var NAME = 'Bilibili-LiveRoom-HangHelper'; var API = BilibiliAPI; var TaskAward_Running = false; var Toast = { element: null, list: [], count: 0 }; var DOM = { treasure: { div: null, image: null, canvas: null, div_tip: null, div_timer: null }, storm: { div: null, image: null, canvas: null }, config: { is_showed: false, div_button: null, div_button_span: null, div_side_bar: null, div_position: null, div_style: null, div_title: null, div_title_span: null, div_title_button: null, div_button_reset: null, div_context_position: null, div_context: null }, alertdialog: { div_background: null, div_position: null, div_style: null, div_title: null, div_title_span: null, div_content: null, div_button: null, button_ok: null }, lottery: { iframe: null } }; var interval_treasure_timer; var room_id_list = []; var lottery_list_last = [], lottery_check_time = 20; var gift_list; var gift_list_str = '礼物编号及对应礼物、亲密度对照表
'; var timediff = 0; 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 }; function ts_s() { return Math.floor(ts_ms() / 1000); } function ts_ms() { return Date.now() + timediff; } 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, 10) !== 0) { var date = new Date(); date.setTime(date.getTime() + (seconds * 1000)); expires = '; expires=' + date.toUTCString(); } document.cookie = name + '=' + escape(value) + expires + '; path=/'; } /* 验证码识别算法来自互联网,作者未知 该算法已被简单修改 */ 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 solveCaptcha() { 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)); } function giftIDtoFeed(gift_id) { for (var i = gift_list.length - 1; i >= 0; i--) { if (gift_list[i].id == gift_id) { return Math.ceil(gift_list[i].price / 100); } } return null; } window.toast = function(e, n, r) { var t = Toast.element; 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 = '' + e + '', 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'; a.style.left = s + p + 'px'; var d = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop; // a.style.top = u + f + d + Toast.count * 40 + 'px'; a.style.top = u + d + Toast.count * 40 + 'px'; setTimeout((function() { a.className += ' out'; setTimeout((function() { Toast.count--; Toast.list.unshift(); Toast.list.forEach(function(v) { v.style.top = (parseInt(v.style.top, 10) - 40) + 'px'; }); a.parentNode.removeChild(a); }), 200); }), 4e3); 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'; Toast.count++; Toast.list.push(a); }; window.Lottery_join = function(lottery_list, room_id_list) { 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); Raffle(room_id); } else { API.room.room_init(short_id).done(function(response) { DEBUG('TaskLottery: room_init', response); if (response.code === 0) { room_id = response.data.room_id; if (response.data.short_id > 0 && response.data.short_id != short_id) room_id_list[response.data.short_id] = room_id; room_id_list[short_id] = room_id; SmallTV(room_id); Raffle(room_id); } }); } } }); return room_id_list; }; function alertDialog(title, content) { DOM.alertdialog.div_title_span.html(title); DOM.alertdialog.div_content.html(content); DOM.alertdialog.button_ok.click(function() { $('#' + NAME + '_alertdialog').remove(); }); $('body > .link-popup-ctnr').append(DOM.alertdialog.div_background); } function execUntilSucceed(callback, delay, period) { setTimeout(function() { if (!callback()) { var p = period < 1 ? 200 : period; execUntilSucceed(callback, p, p); } }, delay < 1 ? 1 : delay); } function tommorrowRun(callback) { var t = new Date(); do { t.setHours(t.getHours() + 1); } while (t.getHours() !== 0); setTimeout(callback, t.valueOf() - Date.now()); } function removeBlankChar(str) { return str.replace(/(\s|\u00A0)+/, ''); } function addCSS(context) { var style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = context; document.getElementsByTagName('head')[0].appendChild(style); } function recurLoadConfig(cfg) { for (var item in cfg) { var e = $('#' + NAME + '_config_' + item); if (e[0]) { switch (typeof cfg[item]) { case 'string': case 'number': e.val(cfg[item]); break; case 'boolean': e.prop('checked', cfg[item]); if (e.is(':checked')) { $('#' + NAME + '_config_' + CONFIG_CONTROL_LIST[DOMtoItem(e)]).show(); } else { $('#' + NAME + '_config_' + CONFIG_CONTROL_LIST[DOMtoItem(e)]).hide(); } break; case 'object': if (Array.isArray(cfg[item])) e.val(cfg[item].join(',')); else recurLoadConfig(cfg[item]); break; } } } } function recurSaveConfig(config) { var cfg = JSON.parse(JSON.stringify(config || CONFIG_DEFAULT)); if (typeof cfg !== 'object') return cfg; for (var item in cfg) { var e = $('#' + NAME + '_config_' + item); if (e[0]) { switch (typeof cfg[item]) { case 'string': cfg[item] = e.val() || ''; break; case 'number': cfg[item] = parseInt(e.val(), 10) || 0; break; case 'boolean': cfg[item] = e.is(':checked'); break; case 'object': if (Array.isArray(cfg[item])) { if (removeBlankChar(e.val()) === '') { cfg[item] = []; } else { cfg[item] = removeBlankChar(e.val()).split(','); } } else { cfg[item] = recurSaveConfig(cfg[item]); } break; } } } return cfg; } function loadConfig() { try { CONFIG = JSON.parse(localStorage.getItem(NAME + '_CONFIG')) || JSON.parse(JSON.stringify(CONFIG_DEFAULT)); if (typeof CONFIG !== 'object') { CONFIG = JSON.parse(JSON.stringify(CONFIG_DEFAULT)); localStorage.setItem(NAME + '_CONFIG', JSON.stringify(CONFIG)); } } catch (e) { console.info('Bilibili直播间挂机助手读取配置失败'); // localStorage.removeItem(NAME + '_CONFIG'); // localStorage.removeItem('Bilibili-LiveRoom-HangHelper_CONFIG'); CONFIG = JSON.parse(JSON.stringify(CONFIG_DEFAULT)); localStorage.setItem(NAME + '_CONFIG', JSON.stringify(CONFIG)); } DEBUG('loadConfig: CONFIG', CONFIG); if (DOM.config.div_context) { recurLoadConfig(CONFIG); } } function saveConfig() { if (DOM.config.div_context) { CONFIG = recurSaveConfig(CONFIG_DEFAULT); } localStorage.setItem(NAME + '_CONFIG', JSON.stringify(CONFIG)); // DEBUG('saveConfig: CONFIG', CONFIG); } function DOMtoItem(element) { return element.attr('id').replace(NAME + '_config_', ''); } function DOMhelptoItem(element) { return element.attr('id').replace(NAME + '_config_help_', ''); } /* 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.$b */ function Init() { if (!API) { toast('BilibiliAPI初始化失败,脚本已停用!', 'error'); console.error('BilibiliAPI初始化失败,脚本已停用!'); return; } if (window.frameElement) { console.info('已启用任意直播间抽奖!'); DEBUG('Init: window.frameElement', window.frameElement); execUntilSucceed(function() { if (window.BilibiliLive && parseInt(window.BilibiliLive.ROOMID, 10) !== 0) { if (parseInt(window.BilibiliLive.UID, 10) !== 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; window.toast = window.top.toast; window.parent.Lottery_join = window.Lottery_join; DEBUG('Iframe: Init: Info', Info); execUntilSucceed(function() { if ($('.live-room-app.p-relative')[0]) { document.getElementsByTagName('head')[0].innerHTML = ''; $('.live-room-app.p-relative').remove(); } }, 9e3, 3e3); } return true; } }, 1, 500); return; } console.info('Bilibili直播间挂机助手: 已加载'); InitAlertDialogGui(); InitConfigGui(); loadConfig(); saveConfig(); execUntilSucceed(function() { DEBUG('Init: BilibiliLive', window.BilibiliLive); if (timediff === 0 && parseInt(window.BilibiliLive.INIT_TIME, 10) !== 0) { timediff = window.BilibiliLive.INIT_TIME - Date.now(); DEBUG('Init: timediff', timediff); } if (window.BilibiliLive && parseInt(window.BilibiliLive.ROOMID, 10) !== 0) { if (parseInt(window.BilibiliLive.UID, 10) !== 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) { execUntilSucceed(function() { var _treasure_box = $('#gift-control-vm div.treasure-box.p-relative'); if (_treasure_box[0]) { _treasure_box.attr('id', 'old_treasure_box'); _treasure_box.hide(); DOM.treasure.div = $('
'); DOM.treasure.div_tip = $('
自动
领取中
'); DOM.treasure.div_timer = $('
0
'); DOM.treasure.image = $(''); DOM.treasure.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[0].style = css_text; DOM.treasure.div_timer[0].style = css_text; DOM.treasure.div.append(DOM.treasure.div_tip); DOM.treasure.div.append(DOM.treasure.image); DOM.treasure.div.append(DOM.treasure.canvas); DOM.treasure.div_tip.after(DOM.treasure.div_timer); _treasure_box.after(DOM.treasure.div); interval_treasure_timer = setInterval(function() { var t = parseInt(DOM.treasure.div_timer.text(), 10); if (t > 0) DOM.treasure.div_timer.text((t - 1) + 's'); else DOM.treasure.div_timer.hide(); }, 1e3); return true; } }); } if (CONFIG.USE_LOTTERY) { DOM.storm.div = $(''); DOM.storm.image = $(''); DOM.storm.canvas = $(''); DOM.storm.div.append(DOM.storm.image); DOM.storm.div.append(DOM.storm.canvas); document.body.appendChild(DOM.storm.div[0]); if (CONFIG.LOTTERY_CONFIG.ALLOW_NOT_SHORT_ROOMID && Info.roomid === Info.short_id) { // 非短号直播间 DOM.lottery.iframe = $(''); DOM.lottery.iframe[0].src = '//live.bilibili.com/2'; document.body.appendChild(DOM.lottery.iframe[0]); DEBUG('Init: lottery_iframe_window', window.frames[NAME + '_iframe']); } } 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', response); if (response.code === 0) { Info.medal_target_id = response.data.target_id; Info.today_feed = parseInt(response.data.today_feed, 10); 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', response); if (response.code === 0) { gift_list = response.data; gift_list.forEach(function(v) { gift_list_str += v.id + ':' + v.name + ',亲密度+' + Math.ceil(v.price / 100) + '
'; }); } DEBUG('gift_list_str', gift_list_str); }); } }); API.live_user.get_info_in_room(Info.roomid).done(function(response) { DEBUG('Init: get_info_in_room', 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', Info); Toast.element = $('
'); Toast.element.appendTo($('#rank-list-vm')); Toast.element = Toast.element[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 (CONFIG.EXCHANGE_SILVER2COIN) str.push('银瓜子换硬币'); if (str.length) str = str.join(','); else str = '无'; toast('助手已启用功能:' + str, 'info'); console.info('Bilibili直播间挂机助手: 助手已启用功能:' + str); TaskStart(); }, 3e3); } else { // 未登录 toast('你还没有登录,助手无法使用!', 'caution'); console.info('Bilibili直播间挂机助手: 你还没有登录,助手无法使用!'); } return true; } }, 1, 500); } function InitAlertDialogGui() { DOM.alertdialog.div_background = $('
'); DOM.alertdialog.div_background[0].style = 'display: table;position: fixed;height: 100%;width: 100%;top: 0;left: 0;font-size: 12px;z-index: 10000;background-color: rgba(0,0,0,.5);'; DOM.alertdialog.div_position = $('
'); DOM.alertdialog.div_position[0].style = 'display: table-cell;vertical-align: middle;'; DOM.alertdialog.div_style = $('
'); DOM.alertdialog.div_style[0].style = 'position: relative;top: 50%;width: 40%;padding: 16px;border-radius: 5px;background-color: #fff;margin: 0 auto;'; DOM.alertdialog.div_position.append(DOM.alertdialog.div_style); DOM.alertdialog.div_background.append(DOM.alertdialog.div_position); DOM.alertdialog.div_title = $('
'); DOM.alertdialog.div_title[0].style = 'position: relative;padding-bottom: 12px;'; DOM.alertdialog.div_title_span = $('提示'); DOM.alertdialog.div_title_span[0].style = 'margin: 0;color: #23ade5;font-size: 16px;'; DOM.alertdialog.div_title.append(DOM.alertdialog.div_title_span); DOM.alertdialog.div_style.append(DOM.alertdialog.div_title); DOM.alertdialog.div_content = $('
'); DOM.alertdialog.div_content[0].style = 'display: inline-block;vertical-align: top;font-size: 14px;'; DOM.alertdialog.div_style.append(DOM.alertdialog.div_content); DOM.alertdialog.div_button = $('
'); DOM.alertdialog.div_button[0].style = 'position: relative;height: 32px;margin-top: 12px;'; DOM.alertdialog.div_style.append(DOM.alertdialog.div_button); DOM.alertdialog.button_ok = $(''); DOM.alertdialog.button_ok[0].style = 'position: absolute;height: 100%;min-width: 68px;right: 0;background-color: #23ade5;color: #fff;border-radius: 4px;font-size: 14px;border: 0;cursor: pointer;'; DOM.alertdialog.div_button.append(DOM.alertdialog.button_ok); } function InitConfigGui() { function recur(cfg, element) { for (var item in cfg) { var e, h, id = NAME + '_config_' + item; if (CONFIG_HELP_LIST[item]) { h = $('
?
'); } switch (typeof cfg[item]) { case 'string': case 'number': e = $('
'); e.html(''); if (CONFIG_HELP_LIST[item] && h) e.append(h); element.append(e); break; case 'boolean': e = $('
'); e.html(''); if (CONFIG_HELP_LIST[item] && h) e.append(h); element.append(e); if (CONFIG_CONTROL_LIST[item]) { $('#' + id).addClass('BLRHH_control'); } break; case 'object': if (Array.isArray(cfg[item])) { e = $('
'); e.html(''); if (CONFIG_HELP_LIST[item] && h) e.append(h); element.append(e); } else { e = $('
'); element.append(e); recur(cfg[item], e); } break; } } } execUntilSucceed(function() { if ($('#sidebar-vm div.side-bar-cntr')[0]) { // 加载css addCSS('.BLRHH_clickable {font-size: 12px;color: #0080c6;cursor: pointer;text-decoration: underline;}' + '.BLRHH_setting_item {margin: 6px 0px;}' + '.BLRHH_input_checkbox {vertical-align: bottom;}' + '.BLRHH_input_text {margin: -2px 0 -2px 4px;padding: 0;}'); // 绘制右下角按钮 DOM.config.div_button_span = $('挂机助手设置'); DOM.config.div_button_span[0].style = 'font-size: 12px;line-height: 16px;color: #0080c6;'; DOM.config.div_button = $('
'); DOM.config.div_button[0].style = 'cursor: pointer;text-align: center;padding: 0px;'; DOM.config.div_side_bar = $('
'); DOM.config.div_side_bar[0].style = 'width: 56px;height: 32px;overflow: hidden;position: fixed;right: 0px;bottom: 10%;padding: 4px 4px;background-color: rgb(255, 255, 255);z-index: 10001;border-radius: 8px 0px 0px 8px;box-shadow: rgba(0, 85, 255, 0.0980392) 0px 0px 20px 0px;border: 1px solid rgb(233, 234, 236);'; DOM.config.div_button.append(DOM.config.div_button_span); DOM.config.div_side_bar.append(DOM.config.div_button); $('#sidebar-vm div.side-bar-cntr').after(DOM.config.div_side_bar); // 绘制设置界面 DOM.config.div_position = $('
'); DOM.config.div_position[0].style = 'display: none;position: fixed;height: 300px;width: 300px;bottom: 5%;z-index: 9999;'; DOM.config.div_style = $('
'); DOM.config.div_style[0].style = 'display: block;overflow: hidden;height: 300px;width: 300px;border-radius: 8px;box-shadow: rgba(106, 115, 133, 0.219608) 0px 6px 12px 0px;border: 1px solid rgb(233, 234, 236);background-color: rgb(255, 255, 255);'; DOM.config.div_position.append(DOM.config.div_style); document.body.appendChild(DOM.config.div_position[0]); // 绘制标题栏及按钮 DOM.config.div_title = $('
'); DOM.config.div_title[0].style = 'display: block;border-bottom: 1px solid #E6E6E6;height: 35px;line-height: 35px;margin: 0;padding: 0;overflow: hidden;'; DOM.config.div_title_span = $('Bilibili直播间挂机助手'); DOM.config.div_title_button = $('
'); DOM.config.div_title_button[0].style = 'float: right;display: inline;padding-right: 8px;'; DOM.config.div_button_reset = $('
重置
'); DOM.config.div_title_button.append(DOM.config.div_button_reset); DOM.config.div_title.append(DOM.config.div_title_span); DOM.config.div_title.append(DOM.config.div_title_button); DOM.config.div_style.append(DOM.config.div_title); // 绘制设置项内容 DOM.config.div_context_position = $('
'); DOM.config.div_context_position[0].style = 'display: block;position: absolute;top: 36px;width: 100%;height: calc(100% - 36px);'; DOM.config.div_context = $('
'); DOM.config.div_context[0].style = 'height: 100%;overflow: auto;padding: 0 12px;margin: 0px;'; DOM.config.div_context_position.append(DOM.config.div_context); DOM.config.div_style.append(DOM.config.div_context_position); recur(CONFIG_DEFAULT, DOM.config.div_context); // 设置事件 DOM.config.div_button.click(function() { if (!DOM.config.is_showed) { loadConfig(); DOM.config.div_position.css('right', DOM.config.div_side_bar[0].clientWidth + 'px'); DOM.config.div_position.show(); DOM.config.div_button_span.text('点击保存设置'); DOM.config.div_button_span.css('color', '#ff8e29'); } else { saveConfig(); DOM.config.div_position.hide(); DOM.config.div_button_span.text('挂机助手设置'); DOM.config.div_button_span.css('color', '#0080c6'); } DOM.config.is_showed = !DOM.config.is_showed; }); DOM.config.div_button_reset.click(function() { recurLoadConfig(CONFIG_DEFAULT); }); $('.BLRHH_help').click(function() { alertDialog('说明', typeof CONFIG_HELP_LIST[DOMhelptoItem($(this))] === 'function' ? CONFIG_HELP_LIST[DOMhelptoItem($(this))]() : CONFIG_HELP_LIST[DOMhelptoItem($(this))]); }); $('.BLRHH_control').click(function() { if ($(this).is(':checked')) { $('#' + NAME + '_config_' + CONFIG_CONTROL_LIST[DOMtoItem($(this))]).show(); } else { $('#' + NAME + '_config_' + CONFIG_CONTROL_LIST[DOMtoItem($(this))]).hide(); } }); return true; } }); } function SmallTV(room_id) { API.gift.smalltv.check(room_id).done(function(response) { // 检查是否有小电视抽奖 DEBUG('TaskLottery: smalltv.check', response); if (response.code === 0) { response.data.forEach(function(v) { var time = v.time; if (v.status === 1) { // 可以参加 API.gift.smalltv.join(room_id, v.raffleId).done(function(response) { DEBUG('TaskLottery: smalltv.join', response); if (response.code === 0) { setTimeout(function() { SmallTVNotice(room_id, response.data.raffleId); }, time * 1e3 + 12e3); toast('已参加直播间【' + room_id + '】的小电视抽奖', 'success'); } }); } else if (v.status === 2 && v.time > 0) { // 已参加且未开奖 setTimeout(function() { SmallTVNotice(room_id, response.data.raffleId); }, time * 1e3 + 12e3); toast('已参加直播间【' + room_id + '】的小电视抽奖', 'success'); } }); } else if (response.code === -400) { // 没有需要提示的小电视 } }); } function Raffle(room_id) { API.activity.check(room_id).done(function(response) { // 检查是否有活动抽奖 DEBUG('TaskLottery: activity.check', response); if (response.code === 0) { response.data.forEach(function(v) { var time = v.time; if (v.status === 1) { // 可以参加 API.activity.join(room_id, v.raffleId).done(function(response) { DEBUG('TaskLottery: activity.join', response); if (response.code === 0) { // 加入成功 setTimeout(function() { RaffleNotice(room_id, response.data.raffleId); }, time * 1e3 + 24e3); toast('已参加直播间【' + room_id + '】的活动抽奖', 'success'); } else if (response.code === 65531) { // 65531: 非当前直播间或短ID直播间试图参加抽奖 toast('参加活动抽奖失败', 'error'); } }); } else if (v.status === 2 && v.time > 0) { // 已参加且未开奖 setTimeout(function() { RaffleNotice(room_id, response.data.raffleId); }, time * 1e3 + 24e3); toast('已参加直播间【' + room_id + '】的活动抽奖', 'success'); } }); } }); } function SmallTVNotice(room_id, raffleId, cnt) { if (cnt > 5) return; API.gift.smalltv.notice(room_id, raffleId).done(function(response) { DEBUG('TaskLottery: smalltv.notice', response); if (response.code === 0) { if (response.data.status === 1) { // 非常抱歉,您错过了此次抽奖,下次记得早点来哦 } else if (response.data.status === 2) { if (response.data.gift_id === '-1' && !response.data.gift_name) { toast('直播间【' + room_id + '】小电视抽奖结果:' + response.msg, 'info'); } else { toast('直播间【' + room_id + '】小电视抽奖结果:' + response.data.gift_name + '*' + response.data.gift_num, 'info'); } } else if (response.data.status === 3) { // 还未开奖 setTimeout(function() { SmallTVNotice(room_id, raffleId, cnt); }, 6e3); } else { toast('直播间【' + room_id + '】小电视抽奖结果:' + response.msg, 'error'); } } else { // 其他情况 setTimeout(function() { SmallTVNotice(room_id, raffleId, cnt + 1); }, 6e3); } }); } function RaffleNotice(room_id, raffleId, cnt) { if (cnt > 5) return; API.activity.notice(room_id, raffleId).done(function(response) { DEBUG('TaskLottery: activity.notice', response); if (response.code === 0) { if (response.data.gift_id === '-1') { toast('直播间【' + room_id + '】活动抽奖结果:' + response.msg, 'info'); } else { toast('直播间【' + room_id + '】活动抽奖结果:' + response.data.gift_name + '*' + response.data.gift_num, 'info'); } } else if (response.msg === '参数错误!') { // 参数错误! } else if (response.msg === '尚未开奖,请耐心等待!') { // 尚未开奖,请耐心等待! setTimeout(function() { RaffleNotice(room_id, raffleId, cnt); }, 6e3); } else { // 其他情况 setTimeout(function() { RaffleNotice(room_id, raffleId, cnt + 1); }, 6e3); } }); } function Storm(cnt) { if (cnt > 5) return; API.create(112, 32).done(function(response) { if (response.code === 0) { DOM.storm.image[0].onload = function() { var phrase = solveCaptcha(); API.lottery.join(Info.roomid, response.data.token, phrase, Info.csrf_token).done(function(response) { if (response.code === 0) { toast('节奏风暴抽奖结果:' + response.data.gift_name + '*' + response.data.gift_num, 'info'); } else { setTimeout(function() { Storm(cnt + 1); }, 1e3); } }); }; DOM.storm.image[0].src = response.data.image; } }); } function Award(callback, cnt) { if (!CONFIG.USE_AWARD) return; if (cnt > 5) { callback(); return; } API.lottery.getCaptcha(ts_ms()).done(function(response) { 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', response); if (response.code === 0) { // 领取瓜子成功 toast('自动领取瓜子:领取了 ' + response.data.awardSilver + ' 银瓜子', 'success'); callback(); } else if (response.code === -903) { // -903: 已经领取过这个宝箱 toast('自动领取瓜子:已经领取过这个宝箱', 'caution'); callback(); } else if (response.code === -902 || response.code === -901) { // -902: 验证码错误, -901: 验证码过期 setTimeout(function() { Award(callback, cnt + 1); }, 1e3); } else { // 其他错误 setTimeout(function() { Award(callback, cnt + 1); }, 3e3); } }); } else { // 验证码识别失败 setTimeout(function() { Award(callback, cnt); }, 500); } }; DOM.treasure.image[0].src = response.data.img; }); } function TaskAward_newTask() { if (!CONFIG.USE_AWARD) return; API.FreeSilver.getCurrentTask().done(function(response) { DEBUG('TaskAward: getCurrentTask', response); if (response.code === 0) { // 获取任务成功 if (parseInt(response.data.minute, 10) !== 0) { setTimeout(TaskAward, response.data.minute * 60e3 + 1e3); TaskAward_Running = true; execUntilSucceed(function() { if (DOM.treasure.div_timer) { DOM.treasure.div_timer.text((response.data.minute * 60 + 1) + 's'); DOM.treasure.div_timer.show(); return true; } }); execUntilSucceed(function() { if (DOM.treasure.div_tip) { DOM.treasure.div_tip.html('次数
' + response.data.times + '/' + response.data.max_times + '
银瓜子
' + response.data.silver); return true; } }); } } else if (response.code === -10017) { // 今天所有的宝箱已经领完! toast('自动领取瓜子:' + response.msg, 'info'); clearInterval(interval_treasure_timer); execUntilSucceed(function() { if (DOM.treasure.div_timer) { DOM.treasure.div_timer.hide(); return true; } }); execUntilSucceed(function() { if (DOM.treasure.div_tip) { DOM.treasure.div_tip.html('今日
已领完'); return true; } }); tommorrowRun(function() { TaskAward_Running = false; TaskAward(); }); } else { toast('自动领取瓜子:' + response.msg, 'info'); } }); } function TaskAward() { if (!CONFIG.USE_AWARD) return; if (TaskAward_Running) Award(TaskAward_newTask, 0); else TaskAward_newTask(); } function Lottery() { if (!CONFIG.USE_LOTTERY) return; 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]) lottery_list_temp.push(parseInt(matched[1], 10)); }); $.each(lottery_list_temp, function(i, v) { if (i === 0) { var index = $.inArray(v, lottery_list_last); 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); } }); DEBUG('TaskLottery: Lottery: last', lottery_list_last.toString()); lottery_list_last = lottery_list_temp; lottery_list_temp = lottery_list; lottery_list = []; lottery_list_temp.forEach(function(v) { if ($.inArray(v, lottery_list) === -1) lottery_list.push(v); }); DEBUG('TaskLottery: Lottery: list', lottery_list.toString()); // 根据可抽奖的房间数自动调整检测周期 if (lottery_list.length > 10) { lottery_check_time = 3; } else if (lottery_list.length > 8) { lottery_check_time = 6; } else if (lottery_list.length > 5) { lottery_check_time = 10; } else if (lottery_list.length > 1) { lottery_check_time = 15; } else { lottery_check_time = 20; } room_id_list = window.Lottery_join(lottery_list, room_id_list); setTimeout(Lottery, lottery_check_time * 1e3); } function TaskSign() { if (!CONFIG.USE_SIGN) return; API.sign.GetSignInfo().done(function(response) { DEBUG('TaskSign: GetSignInfo', response); if (response.code === 0) { if (response.data.status === 0) { // 未签到 API.sign.doSign().done(function(response) { DEBUG('TaskSign: doSign', response); if (response.code === 0) { // 签到成功 toast(response.data.text, 'success'); tommorrowRun(TaskSign); } else { toast(response.data.text, 'error'); } }); } else if (response.data.status === 1) { // 已签到 toast('今日已签到:' + response.data.text, 'success'); tommorrowRun(TaskSign); } } }); } function TaskLottery() { if (!CONFIG.USE_LOTTERY) return; setTimeout(Lottery, 10e3); } function TaskReceiveAward(task_id) { if (!CONFIG.USE_TASK) return; API.activity.receive_award(task_id, Info.csrf_token).done(function(response) { DEBUG('TaskTask: receive_award', response); if (response.code === 0) { // 完成任务 toast('完成任务:' + task_id, 'success'); } }); } function Task() { if (!CONFIG.USE_TASK) return; toast('检查任务完成情况', 'info'); API.i.taskInfo().done(function(response) { DEBUG('TaskTask: taskInfo', 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', 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', 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() { if (!CONFIG.USE_TASK) return; setTimeout(Task, 6e3); } function Gift() { if (!CONFIG.USE_GIFT) return; API.live_user.get_weared_medal(Info.uid, Info.roomid, Info.csrf_token).done(function(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, 10); Info.day_limit = response.data.day_limit; var remain_feed = Info.day_limit - Info.today_feed; if (remain_feed > 0) { toast('今日亲密度未满,送礼开始', 'info'); API.gift.bag_list().done(function(response) { DEBUG('TaskGift: bag_list', response); if (response.code === 0) { Info.bag_list = response.data.list; $.each(Info.bag_list, function(i, v) { v.gift_id += ''; DEBUG('TaskGift: v.gift_id', v.gift_id); // DEBUG('TaskGift: check: ALLOW_GIFT', ($.inArray(v.gift_id, CONFIG.GIFT_CONFIG.ALLOW_GIFT) > -1 || !CONFIG.GIFT_CONFIG.ALLOW_GIFT.length)); // DEBUG('TaskGift: check: SEND_GIFT', (CONFIG.GIFT_CONFIG.SEND_GIFT.length && $.inArray(v.gift_id, CONFIG.GIFT_CONFIG.SEND_GIFT) > -1)); // DEBUG('TaskGift: check: SEND_TODAY', (CONFIG.GIFT_CONFIG.SEND_TODAY && v.expire_at > ts_s() && v.expire_at - ts_s() < 86400)); if (remain_feed > 0) { // 检查今日亲密度 if (($.inArray(v.gift_id, CONFIG.GIFT_CONFIG.ALLOW_GIFT) > -1 || !CONFIG.GIFT_CONFIG.ALLOW_GIFT.length) && // 检查ALLOW_GIFT ((CONFIG.GIFT_CONFIG.SEND_GIFT.length && $.inArray(v.gift_id, CONFIG.GIFT_CONFIG.SEND_GIFT) > -1 && remain_feed > 0) || // 检查SEND_GIFT (CONFIG.GIFT_CONFIG.SEND_TODAY && v.expire_at > ts_s() && v.expire_at - ts_s() < 86400))) { // 检查SEND_TODAY和礼物到期时间 var feed_single = giftIDtoFeed(v.gift_id); DEBUG('TaskGift: v.gift_id', v.gift_id); DEBUG('TaskGift: feed_single', feed_single); if (feed_single > 0) { var feed_num = Math.floor(remain_feed / feed_single); if (feed_num > v.gift_num) feed_num = v.gift_num; 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', response); if (response.code === 0) { // 送礼成功 Info.rnd = response.data.rnd; toast('包裹送礼成功,送出' + feed_num + '个' + v.gift_name, 'success'); } else { toast('包裹送礼异常,' + response.msg, 'error'); } }); remain_feed -= feed_num * feed_single; } } } } else { return false; } }); if (remain_feed > 0) { toast('送礼结束,1小时后再次送礼', 'success'); setTimeout(Gift, 3600e3); } else { toast('送礼结束,今日亲密度已满', 'success'); tommorrowRun(TaskGift); } } else { toast('获取包裹礼物异常,' + response.msg, 'error'); } }); } } else { toast('获取亲密度异常,' + response.msg, 'error'); } }); } function TaskGift() { if (!CONFIG.USE_GIFT) return; 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('已佩戴的勋章不是当前主播勋章,送礼功能停止', 'caution'); return; } API.i.medal(1, 25).done(function(response) { DEBUG('TaskGift: medal', 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', response); toast('已自动切换为当前主播勋章', 'success'); toast('请注意送礼设置,30秒后开始送礼', 'caution'); setTimeout(Gift, 30e3); }); return false; } }); } }); } else { toast('请注意送礼设置,30秒后开始送礼', 'caution'); setTimeout(Gift, 30e3); } } function TaskExchange() { DEBUG('TaskExchange', 'start'); API.pay.silver2coin(Info.csrf_token).done(function(response) { DEBUG('TaskExchange', response); if (response.code === 0) { // 兑换成功 toast('银瓜子兑换硬币:兑换成功', 'success'); } else if (response.code === 403) { // 每天最多能兑换 1 个 toast('银瓜子兑换硬币:每天最多能兑换 1 个', 'info'); } else { toast('银瓜子兑换硬币:' + response.msg, 'info'); } }).complete(function(response) { DEBUG('TaskExchange', response); }); } 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(); if (CONFIG.EXCHANGE_SILVER2COIN) TaskExchange(); } $(document).ready(function() { Init(); }); })();