// ==UserScript== // @name Bilibili直播间挂机助手 // @namespace SeaLoong // @version 1.3.1 // @description Bilibili直播间自动签到,领瓜子,参加抽奖,完成任务,送礼等 // @author SeaLoong // @include /https?:\/\/live\.bilibili\.com\/\d+/ // @grant none // @run-at document-end // @license MIT License // @downloadURL none // ==/UserScript== (function() { 'use strict'; // <-!!!请注意,修改此处设置将不会再生效,请点击页面右下角的"挂机助手设置"打开设置界面进行设置!!!-> var CONFIG = { // <-!!!请注意,修改此处设置将不会再生效,请点击页面右下角的"挂机助手设置"打开设置界面进行设置!!!-> 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: true, // 当有当前主播勋章,且当前佩戴的勋章不是当前主播勋章时自动切换为当前主播勋章: true:自动切换,false:不切换 SEND_GIFT: [1], // 设置默认送的礼物类型编号(见下方列表),多个请用英文逗号(,)隔开,为空则表示允许送出ALLOW_GIFT允许的礼物 ALLOW_GIFT: [1, 4, 6, 109, 110], // 设置允许送的礼物类型编号(见下方列表)(!!任何未在此列表的礼物一定不会被送出!!),多个请用英文逗号(,)隔开,为空则表示允许送出所有类型的礼物 SEND_TODAY: true // 送出包裹中今天到期的礼物(!会送出SEND_GIFT之外的礼物!若今日亲密度已满则不送): true:启用,false:不启用 }, 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 109:红灯笼:亲密度+20 110:小爆竹:亲密度+20 */ /* 此行以下内容请勿修改,当然你要改那我也没办法 */ var CONFIG_DEFAULT = { USE_SIGN: true, USE_AWARD: true, USE_LOTTERY: true, USE_TASK: true, USE_GIFT: true, GIFT_CONFIG: { SHORT_ROOMID: 0, CHANGE_MEDAL: true, SEND_GIFT: [1], ALLOW_GIFT: [1, 4, 6, 109, 110], SEND_TODAY: true }, SHOW_TOAST: true }; var NAME = 'Bilibili-LiveRoom-HangHelper'; 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: { div_button: null, div_button_p: null, div: null, div_showed: false } }; var interval_treasure_timer; var room_id_list = []; var lottery_list_last = [], lottery_check_time = 20; var gift_list; 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 }; var DEBUG = function(sign, data) { // var d = new Date(); // d = '[' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() + '.' + d.getMilliseconds() + ']'; // console.debug(d, sign + ':', data); }; var API = { last_ajax: 0, cnt_frequently_ajax: 0, ajax: function(settings) { if (Date.now() - API.last_ajax < 20) { API.cnt_frequently_ajax++; } else { API.cnt_frequently_ajax = 0; } API.last_ajax = Date.now(); if (API.cnt_frequently_ajax > 5) throw new Error('调用Bilibili API太快,可能出现了bug'); // DEBUG('API.ajax: settings', 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, _: ts_ms() } }); }, 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, _: ts_ms() } }); }, 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(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 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; } } /* TODO 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 null; } function toast(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); } function execUntilSucceed(callback) { setTimeout(function() { if (!callback()) { execUntilSucceed(callback); } }, 200); } function toInt(v) { return parseInt(v, 10); } function removeBlankChar(str) { return str.replace(/(\s|\u00A0)+/, ''); } 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.attr('checked', cfg[item]); break; case 'object': if (Array.isArray(cfg[item])) e.val(cfg[item].join(',')); else recurLoadConfig(cfg[item]); break; } } } } function recurSaveConfig(config) { var cfg = config; 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])) { cfg[item] = removeBlankChar(e.val()).split(',').map(toInt) || []; } else { cfg[item] = recurSaveConfig(cfg[item]); } break; } } } return cfg; } function loadConfig() { // CONFIG = JSON.parse(GM_getValue('CONFIG', JSON.stringify(CONFIG))); try { CONFIG = JSON.parse(localStorage.getItem(NAME + '_CONFIG')) || CONFIG_DEFAULT; if (typeof CONFIG != 'object') { CONFIG = CONFIG_DEFAULT; localStorage.setItem(NAME + '_CONFIG', JSON.stringify(CONFIG_DEFAULT)); } } catch (e) { console.log('Bilibili直播间挂机助手读取配置失败'); // localStorage.removeItem(NAME + '_CONFIG'); // localStorage.removeItem('Bilibili-LiveRoom-HangHelper_CONFIG'); CONFIG = CONFIG_DEFAULT; localStorage.setItem(NAME + '_CONFIG', JSON.stringify(CONFIG_DEFAULT)); } DEBUG('loadConfig: CONFIG', CONFIG); if (DOM.config.div) { recurLoadConfig(CONFIG); } } function saveConfig() { if (DOM.config.div) { CONFIG = recurSaveConfig(CONFIG_DEFAULT); } // GM_setValue('CONFIG', CONFIG); localStorage.setItem(NAME + '_CONFIG', JSON.stringify(CONFIG)); DEBUG('saveConfig: CONFIG', CONFIG); } /* 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() { // liveQuickLogin(); InitConfigGui(); loadConfig(); DEBUG('CONFIG', CONFIG); execUntilSucceed(function() { if (window.BilibiliLive) { timediff = window.BilibiliLive.INIT_TIME - Date.now(); DEBUG('Init: BilibiliLive', window.BilibiliLive); 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 = $('