// ==UserScript==
// @name Bilibili Live Tasks Helper
// @name:en Bilibili Live Tasks Helper
// @name:zh Bilibili Live Tasks Helper
// @namespace https://github.com/andywang425
// @version 7.0.4
// @author andywang425
// @description Enhancing the experience of watching Bilibili live streaming.
// @description:en Enhancing the experience of watching Bilibili live streaming.
// @description:zh Enhancing the experience of watching Bilibili live streaming.
// @license MIT
// @copyright 2023, andywang425 (https://github.com/andywang425)
// @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDEuMDY1IiBoZWlnaHQ9IjEyNy43NDciIHZpZXdCb3g9IjAgMCAzNy4zMjQgMzMuOCI+PHBhdGggZmlsbD0iIzIwYjBlMyIgZD0iTTg2Ljk2MiAxMTIuMzMyYTIuNjYxIDIuNjYxIDAgMCAxIDIuMjYyIDAgNS41MzYgNS41MzYgMCAwIDEgMS4zODQgMS4wMTFsNS4zMjMgNC42NThoMy44MDVsNS4zMjMtNC42NThhNS41ODkgNS41ODkgMCAwIDEgMS4zODQtMS4wMTEgMi42NjEgMi42NjEgMCAwIDEgMy41NCAyLjIwOSAyLjY2MSAyLjY2MSAwIDAgMS0uNTg2IDEuNzgzIDE0Ljg3NyAxNC44NzcgMCAwIDEtMS4xNzEgMS4wNjUgNy42OTEgNy42OTEgMCAwIDEtLjc0NS42MTJoMy4zMjZhNS42NDIgNS42NDIgMCAwIDEgMy45MTIgMS43NTYgNS42NjkgNS42NjkgMCAwIDEgMS43ODQgMy45MTJ2MTUuMzAzYTEwLjc3OCAxMC43NzggMCAwIDEtLjEzNCAyLjMxNSA1LjkwOCA1LjkwOCAwIDAgMS0yLjY2IDMuNzI2IDUuNzIyIDUuNzIyIDAgMCAxLTMuMDYxLjg1Mkg4Ni4yMTdhMTEuMjg0IDExLjI4NCAwIDAgMS0yLjM5Ni0uMTMzIDUuODgyIDUuODgyIDAgMCAxLTMuNjcyLTIuNjYyIDUuNjk1IDUuNjk1IDAgMCAxLS45MDUtMy4wNnYtMTUuMTQzYTExLjkyMyAxMS45MjMgMCAwIDEgMC0yLjIwOSA1Ljg1NSA1Ljg1NSAwIDAgMSA1LjMyMy00LjczN2gzLjQ4NmMtLjU1OS0uNC0xLjAzOC0uODc4LTEuNTQ0LTEuMzA0YTIuNjYxIDIuNjYxIDAgMCAxLS44NTEtMi4xODMgMi42NjEgMi42NjEgMCAwIDEgMS4zMDQtMi4xMDJtLS42MTIgMTAuMzI2YTIuNjYxIDIuNjYxIDAgMCAwLTIuMTAzIDEuOTE2IDMuNTkzIDMuNTkzIDAgMCAwIDAgMS4wMTF2MTIuNTg4YTIuNjYxIDIuNjYxIDAgMCAwIDEuODM3IDIuNjYyIDMuNTEzIDMuNTEzIDAgMCAwIDEuMTQ0LjE4NmgyMS42MzdhMi42NjEgMi42NjEgMCAwIDAgMi41MjgtMS41NyAzLjcyNiAzLjcyNiAwIDAgMCAuMjY2LTEuNzU3di0xMS43MWE0LjQ3MSA0LjQ3MSAwIDAgMCAwLTEuMjc3IDIuNjYxIDIuNjYxIDAgMCAwLTEuNzMtMS44MSA0LjI4NSA0LjI4NSAwIDAgMC0xLjY1LS4yMzlIODcuNjAxYTguODg5IDguODg5IDAgMCAwLTEuMjUxIDB6bTAgMCIgc3R5bGU9InN0cm9rZS13aWR0aDouMDMzMDcyOSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTc5LjE5MyAtMTEyLjA4KSIvPjxwYXRoIGQ9Ik04OC45NyAxMjguNjM2Yy4zNjMuMzc3Ljc0NS43NDcgMS4wODggMS4xNDIuNTk3LjY4NyAxLjExOCAxLjE5NyAxLjY2NiAxLjgwOS0uMTI5LTEuMTE3IDEuMzA0LTEuMTk4LjA3NC0xLjc1Ny0uNDA4LjQxNy0uOTQxLjg4NC0xLjM2IDEuMjIzLS4zOTIuMzE2LS44NjMuNjctMS4yMzUuOTUyLTEuOTA3IDEuNDQzLjIyNiA0LjA1MyAyLjEzIDIuNjA3IDAgMCAyLTEuNTM1IDIuODA3LTIuMzAxLjQ0LS40MTcuNjgtLjk1Ni43Mi0xLjU5Mi4wNC0uNjU0LS41MzUtMS4yNC0uNzk0LTEuNDk4LS45Mi0uOTE0LTEuNzQzLTEuOTY4LTIuNTUtMi44MTItMS41NzUtMS44LTQuMTIuNDI4LTIuNTQ2IDIuMjI3ek0xMDYuOTc5IDEyOC42MzZjLS4zNjMuMzc3LS43NDUuNzQ3LTEuMDg4IDEuMTQyLS41OTcuNjg3LTEuMTE4IDEuMTk3LTEuNjY2IDEuODA5LjEyOS0xLjExNy0xLjMwNC0xLjE5OC0uMDc0LTEuNzU3LjQwOC40MTcuOTQxLjg4NCAxLjM2IDEuMjIzLjM5Mi4zMTYuODYzLjY3IDEuMjM1Ljk1MiAxLjkwNyAxLjQ0My0uMjI2IDQuMDUzLTIuMTMgMi42MDcgMCAwLTItMS41MzUtMi44MDctMi4zMDEtLjQ0LS40MTctLjY4LS45NTYtLjcyLTEuNTkyLS4wNC0uNjU0LjUzNS0xLjI0Ljc5NC0xLjQ5OC45Mi0uOTE0IDEuNzQzLTEuOTY4IDIuNTUtMi44MTIgMS41NzUtMS44IDQuMTIuNDI4IDIuNTQ2IDIuMjI3eiIgc3R5bGU9ImZpbGw6IzIwYjBlMztmaWxsLW9wYWNpdHk6MTtzdHJva2Utd2lkdGg6LjUyNDE1OTtzdHJva2UtZGFzaGFycmF5Om5vbmUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC03OS4xOTMgLTExMi4wOCkiLz48L3N2Zz4NCg==
// @homepageURL https://github.com/andywang425/BLTH
// @supportURL https://github.com/andywang425/BLTH/issues
// @include /^https?:\/\/live\.bilibili\.com\/(blanc\/)?\d+\??.*$/
// @require https://unpkg.com/[email protected]/dist/vue.global.prod.js
// @require data:application/javascript,window.Vue%3DVue%2Cwindow.VueDemi%3DVue%3B
// @require https://unpkg.com/[email protected]/dist/index.full.min.js
// @require https://unpkg.com/@element-plus/[email protected]/dist/index.iife.min.js
// @require https://unpkg.com/[email protected]/dist/pinia.iife.prod.js
// @require https://unpkg.com/[email protected]/lodash.min.js
// @require https://unpkg.com/[email protected]/dist/hotkeys.min.js
// @require https://unpkg.com/[email protected]/build/global/luxon.min.js
// @require https://unpkg.com/[email protected]/crypto-js.js
// @resource element-plus/dist/index.css https://unpkg.com/[email protected]/dist/index.css
// @connect api.bilibili.com
// @connect api.live.bilibili.com
// @connect api.vc.bilibili.com
// @connect passport.bilibili.com
// @connect live.bilibili.com
// @connect live-trace.bilibili.com
// @grant GM_getResourceText
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @run-at document-end
// ==/UserScript==
(a=>{const e=document.createElement("style");e.dataset.source="vite-plugin-monkey",e.textContent=a,document.head.append(e)})(" .title[data-v-dda95e10]{padding-left:20px;align-items:center;display:flex}.header-big-text[data-v-dda95e10]{font-size:var(--big-text-size)}.header-small-text[data-v-dda95e10]{font-size:var(--small-text-size);padding-top:calc(var(--big-text-size) - var(--small-text-size));margin-left:10px;--small-text-size: 18px}.collapse-btn[data-v-dda95e10]{display:flex;justify-content:center;align-items:center;height:100%;float:left;cursor:pointer}.avatar-wrap[data-v-eac67691]{width:80px;height:80px}.avatar[data-v-eac67691]{display:flex;justify-content:center;align-items:center;border-radius:50%}.base[data-v-4aed17ff]{z-index:1003;position:absolute;background-color:#fff;border-bottom:1px solid #e3e5e7;border-left:1px solid #e3e5e7;border-right:1px solid #e3e5e7}.header[data-v-4aed17ff]{position:relative;box-sizing:border-box;width:100%;font-size:var(--big-text-size);align-items:center;display:flex;border-bottom:1px solid #e3e5e7;height:60px;--big-text-size: 25px}.aside[data-v-4aed17ff]{width:auto}.aside #aside-el-menu[data-v-4aed17ff]:not(.el-menu--collapse){width:150px}.main[data-v-4aed17ff]{--main-top-botton-padding: calc(var(--el-main-padding) * .625);padding-top:var(--main-top-botton-padding);padding-bottom:var(--main-top-botton-padding)}.fade-enter-active[data-v-4aed17ff],.fade-leave-active[data-v-4aed17ff]{transition:opacity .1s ease}.fade-enter-from[data-v-4aed17ff],.fade-leave-to[data-v-4aed17ff]{opacity:0}.info-icon[data-v-c1d8df5e]{font-size:var(--el-font-size-base);cursor:pointer}.status-icon[data-v-2f9d6050]{font-size:var(--el-font-size-base)}.blth_btn{background-color:#23ade5;font-size:small;margin-inline-start:5px;color:#fff;border-radius:4px;border:none;padding:5px;cursor:pointer;box-shadow:0 0 2px #00000075;line-height:10px;margin-left:15px}.blth_btn:hover{background-color:#1097cc}.blth_btn:hover:active{background-color:#0e86b6;position:relative;top:1px}.el-link-va-baseline{vertical-align:baseline} ");
(function (vue, pinia, _, luxon, CryptoJS, ElementPlusIconsVue, ElementPlus, hotkeys) {
'use strict';
function _interopNamespaceDefault(e) {
const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
if (e) {
for (const k in e) {
if (k !== 'default') {
const d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: () => e[k]
});
}
}
}
n.default = e;
return Object.freeze(n);
}
const ElementPlusIconsVue__namespace = /*#__PURE__*/_interopNamespaceDefault(ElementPlusIconsVue);
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
const defaultValues = {
ui: {
isCollapse: false,
isShowPanel: true,
activeMenuIndex: "MainSiteTasks"
},
modules: {
DailyTasks: {
MainSiteTasks: {
login: {
enabled: false,
_lastCompleteTime: 0
},
watch: {
enabled: false,
_lastCompleteTime: 0
},
coin: {
enabled: false,
num: 1,
_lastCompleteTime: 0
},
share: {
enabled: false,
_lastCompleteTime: 0
}
},
LiveTasks: {
sign: {
enabled: false,
_lastCompleteTime: 0
},
appUser: {
enabled: false,
_lastCompleteTime: 0
},
medalTasks: {
danmu: {
enabled: false,
list: [
"(⌒▽⌒)",
"( ̄▽ ̄)",
"(=・ω・=)",
"(`・ω・´)",
"(〜 ̄△ ̄)〜",
"(・∀・)",
"(°∀°)ノ",
"╮( ̄▽ ̄)╭",
"_(:3」∠)_",
"(^・ω・^ )",
"(● ̄(エ) ̄●)",
"ε=ε=(ノ≧∇≦)ノ",
"⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄",
"←◡←",
`(●'◡'●)ノ♥`
],
_lastCompleteTime: 0
},
like: {
enabled: false,
_lastCompleteTime: 0
},
watch: {
enabled: false,
time: 70,
_watchedSecondsToday: 0,
_lastWatchTime: 0,
_lastCompleteTime: 0
},
isWhiteList: false,
roomidList: []
}
},
OtherTasks: {
groupSign: {
enabled: false,
_lastCompleteTime: 0
},
silverToCoin: {
enabled: false,
_lastCompleteTime: 0
},
coinToSilver: {
enabled: false,
num: 1,
_lastCompleteTime: 0
}
}
},
EnhanceExperience: {
switchLiveStreamQuality: {
enabled: false,
qualityDesc: "原画"
},
banp2p: {
enabled: false
}
}
},
cache: {
lastAliveHeartBeatTime: 0
}
};
class Storage {
/**
* 递归合并配置项。删除当前配置中不存在于默认配置的键,补上相对于默认配置缺少的键值,其它键值不变。
*
* 该方法会修改当前配置。
*
* @param current_config_item 当前配置
* @param default_config_item 默认配置
* @returns 修改后的当前配置
* @example
*
* const current_config = { enabled: true, details: { type: 'efg', status: 'ok' }, msg: 'hi' };
* const default_config = { enabled: false, details: { type: 'abc', num = 1 } };
*
* mergeConfig(current_config, default_config);
* // => { enabled: true, details: { type: 'efg', num = 1 } }
*/
static mergeConfigs(current_config_item, default_config_item) {
const keysOnlyInCurrentConfigItem = _.difference(
_.keys(current_config_item),
_.keys(default_config_item)
);
current_config_item = _.omit(current_config_item, keysOnlyInCurrentConfigItem);
const keysOnlyInDefaultItem = _.difference(
_.keys(default_config_item),
_.keys(current_config_item)
);
_.assign(current_config_item, _.pick(default_config_item, keysOnlyInDefaultItem));
for (const [key, value] of Object.entries(current_config_item).filter(
(keyValue) => !keysOnlyInDefaultItem.includes(keyValue[0])
)) {
if (_.isPlainObject(value)) {
current_config_item[key] = this.mergeConfigs(value, default_config_item[key]);
}
}
return current_config_item;
}
static setUiConfig(uiConfig) {
_GM_setValue("ui", uiConfig);
}
static getUiConfig() {
return this.mergeConfigs(_GM_getValue("ui", {}), defaultValues.ui);
}
static setModuleConfig(moduleConfig) {
_GM_setValue("modules", moduleConfig);
}
static getModuleConfig() {
return this.mergeConfigs(_GM_getValue("modules", {}), defaultValues.modules);
}
static setCache(cache) {
_GM_setValue("cache", cache);
}
static getCache() {
return this.mergeConfigs(_GM_getValue("cache", {}), defaultValues.cache);
}
}
const useUIStore = pinia.defineStore("ui", () => {
const uiConfig = vue.reactive(Storage.getUiConfig());
const activeMenuName = vue.computed(() => {
const index2name = {
MainSiteTasks: "主站任务",
LiveTasks: "直播任务",
OtherTasks: "其它任务"
};
return index2name[uiConfig.activeMenuIndex];
});
const baseStyleValue = vue.reactive({
top: 0,
left: 0,
height: 0,
width: 0
});
const baseStyle = vue.computed(() => ({
top: baseStyleValue.top.toString() + "px",
left: baseStyleValue.left.toString() + "px",
height: baseStyleValue.height.toString() + "px",
width: baseStyleValue.width.toString() + "px"
}));
const isShowPanelButtonText = vue.computed(() => {
if (uiConfig.isShowPanel) {
return "隐藏控制面板";
} else {
return "显示控制面板";
}
});
const scrollBarHeight = vue.computed(() => (baseStyleValue.height - 60).toString() + "px");
function changeCollapse() {
uiConfig.isCollapse = !uiConfig.isCollapse;
}
function changeShowPanel() {
uiConfig.isShowPanel = !uiConfig.isShowPanel;
}
function setActiveMenuIndex(index) {
uiConfig.activeMenuIndex = index;
}
vue.watch(
uiConfig,
_.debounce((newUiConfig) => Storage.setUiConfig(newUiConfig), 350)
);
return {
isShowPanelButtonText,
activeMenuName,
baseStyleValue,
baseStyle,
scrollBarHeight,
uiConfig,
changeCollapse,
changeShowPanel,
setActiveMenuIndex
};
});
const useBiliStore = pinia.defineStore("bili", () => {
const BilibiliLive = vue.ref();
const cookies = vue.ref();
const userInfo = vue.ref();
const giftConfig = vue.ref();
const dailyRewardInfo = vue.ref();
const dynamicVideos = vue.ref();
const fansMedals = vue.ref();
const filteredFansMedals = vue.computed(() => {
if (!fansMedals.value)
return null;
return fansMedals.value.filter((m) => m.room_info.room_id !== 0);
});
return {
BilibiliLive,
userInfo,
giftConfig,
cookies,
dailyRewardInfo,
dynamicVideos,
fansMedals,
filteredFansMedals
};
});
class Request {
constructor(url_prefix, orgin) {
/** 请求 URL 的前缀 */
__publicField(this, "url_prefix");
/**
* 请求 Header 中 Origin 的值,为了方便同时也是 Referer 的值
*/
__publicField(this, "origin");
this.url_prefix = url_prefix ?? "";
this.origin = orgin ?? "https://bilibili.com";
}
/**
* 发起一个 GET 请求
* @param url 请求 URL 除去前缀的部分
* @param params URL 参数
* @param otherDetails GM_xmlhttpRequest 的 details 参数
* @returns Promise
*/
get(url, params, otherDetails) {
return new Promise((resolve, reject) => {
const defaultDetails = {
method: "GET",
url: this.url_prefix + url + (params ? "?" + new URLSearchParams(params).toString() : ""),
responseType: "json",
headers: {
Accept: "application/json, text/plain, */*",
Referer: this.origin,
Origin: this.origin,
"Sec-Fetch-Site": "same-site"
},
onload: function(response) {
resolve(response.response);
},
onerror: function(err) {
reject(err);
}
};
const details = _.defaultsDeep(otherDetails, defaultDetails);
_GM_xmlhttpRequest(details);
});
}
/**
* 发起一个 POST 请求
* @param url 请求 URL 除去前缀的部分
* @param data application/x-www-form-urlencoded 其它类型的数据需要在 otherDetails 中定义
* @param otherDetails GM_xmlhttpRequest 的 details 参数
* @returns Promise
*/
post(url, data, otherDetails) {
return new Promise((resolve, reject) => {
const defaultDetails = {
method: "POST",
url: this.url_prefix.concat(url),
data: new URLSearchParams(data).toString(),
responseType: "json",
headers: {
Accept: "application/json, text/plain, */*",
Referer: this.origin,
Origin: this.origin,
"Sec-Fetch-Site": "same-site",
"Content-Type": "application/x-www-form-urlencoded"
},
onload: function(response) {
resolve(response.response);
},
onerror: function(err) {
reject(err);
}
};
const details = _.defaultsDeep(otherDetails, defaultDetails);
if (details.headers["Content-Type"] === "multipart/form-data") {
delete details.headers["Content-Type"];
}
_GM_xmlhttpRequest(details);
});
}
}
function uuid() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(char) {
const randomInt = 16 * Math.random() | 0;
return ("x" === char ? randomInt : 3 & randomInt | 8).toString(16);
});
}
function sleep(miliseconds) {
return new Promise((resolve) => setTimeout(resolve, miliseconds));
}
function wait(type, timeout = -1) {
return new Promise((resolve) => {
useModuleStore().emitter.on(type, (event) => resolve(event));
if (timeout !== -1)
setTimeout(resolve, timeout);
});
}
function packFormData(json) {
const formData = new FormData();
_.forEach(json, (value, key) => formData.append(key, value.toString()));
return formData;
}
function deepestIterate(obj, fn, path) {
_.forOwn(obj, function(value, key) {
const newPath = path ? path + "." + key : key;
if (_.isPlainObject(value) && !_.isEmpty(value)) {
deepestIterate(value, fn, newPath);
} else {
fn(value, newPath);
}
});
}
luxon.Settings.defaultZone = "Asia/Shanghai";
function isTimestampToday(timestamp, hour = 0, minute = 5) {
const time = luxon.DateTime.fromMillis(timestamp);
const startOfADay = luxon.DateTime.now().set({
hour,
minute,
second: 0,
millisecond: 0
});
const startOfTomorrow = startOfADay.plus({ days: 1 });
const startOfYesterday = startOfADay.minus({ days: 1 });
if (luxon.DateTime.now() >= startOfADay) {
return time >= startOfADay && time < startOfTomorrow;
} else {
return time >= startOfYesterday && time < startOfADay;
}
}
function delayToNextMoment(hour = 0, minute = 5) {
const now = luxon.DateTime.now();
let nextTime = luxon.DateTime.local(now.year, now.month, now.day, hour, minute);
if (now > nextTime) {
nextTime = nextTime.plus({ days: 1 });
}
const diff = nextTime.diff(now);
return {
// 时间戳
ms: diff.toMillis(),
// 便于阅读的字符串,去掉开头的0小时和0分钟
str: diff.toFormat("h小时m分钟s秒").replace(/^0小时/, "").replace(/^0分钟/, "")
};
}
function isNowIn(startHour, startMinute, endHour, endMinute) {
const now = luxon.DateTime.now();
const start = luxon.DateTime.local(now.year, now.month, now.day, startHour, startMinute);
const end = luxon.DateTime.local(now.year, now.month, now.day, endHour, endMinute);
return now >= start && now < end;
}
function ts() {
return Math.round(luxon.DateTime.now().toSeconds());
}
function tsm() {
return luxon.DateTime.now().toMillis();
}
const request = {
live: new Request("https://api.live.bilibili.com", "https://live.bilibili.com"),
liveTrace: new Request("https://live-trace.bilibili.com", "https://live.bilibili.com"),
passport: new Request("https://passport.bilibili.com", "https://passport.bilibili.com/"),
main: new Request("https://api.bilibili.com", "https://www.bilibili.com"),
vc: new Request("https://api.vc.bilibili.com", "https://message.bilibili.com/"),
raw: new Request()
};
const BAPI = {
live: {
roomGiftConfig: (room_id = 0, area_parent_id = 0, area_id = 0, platform = "pc") => {
return request.live.get("/xlive/web-room/v1/giftPanel/roomGiftConfig", {
platform,
room_id,
area_parent_id,
area_id
});
},
doSign: () => {
return request.live.get("/xlive/web-ucenter/v1/sign/DoSign");
},
getSignInfo: () => {
return request.live.get("/xlive/web-ucenter/v1/sign/WebGetSignInfo");
},
fansMedalPanel: (page, page_size = 10) => {
return request.live.get(
"/xlive/app-ucenter/v1/fansMedal/panel",
{
page,
page_size
},
{
Origin: "https://link.bilibili.com",
Referer: "https://link.bilibili.com/p/center/index"
}
);
},
sendMsg: (msg, roomid, room_type = 0, mode = 1, jumpfrom = 0, fontsize = 25, color = 16777215, bubble = 0) => {
const biliStore = useBiliStore();
const bili_jct = biliStore.cookies.bili_jct;
return request.live.post("/msg/send", void 0, {
data: packFormData({
roomid,
room_type,
rnd: ts(),
msg,
mode,
jumpfrom,
fontsize,
csrf: bili_jct,
csrf_token: bili_jct,
color,
bubble
}),
headers: {
"Content-Type": "multipart/form-data"
}
});
},
likeReport: (room_id, anchor_id) => {
const biliStore = useBiliStore();
const bili_jct = biliStore.cookies.bili_jct;
return request.live.post("/xlive/app-ucenter/v1/like_info_v3/like/likeReportV3", {
room_id,
anchor_id,
uid: anchor_id,
ts: ts(),
csrf: bili_jct
});
},
/**
* 该API只在带有多层iframe(背景很好看)的直播间中被使用,但参数填任意直播间均可
*/
getInfoByRoom: (room_id) => {
return request.live.get("/xlive/web-room/v1/index/getInfoByRoom", {
room_id
});
},
getUserTaskProgress: (target_id = 11153765) => {
const biliStore = useBiliStore();
const bili_jct = biliStore.cookies.bili_jct;
return request.live.get("/xlive/app-ucenter/v1/userTask/GetUserTaskProgress", {
target_id,
csrf: bili_jct,
ts: ts()
});
},
userTaskReceiveRewards: (target_id = 11153765) => {
const biliStore = useBiliStore();
const bili_jct = biliStore.cookies.bili_jct;
return request.live.post("/xlive/app-ucenter/v1/userTask/UserTaskReceiveRewards", {
actionKey: "csrf",
target_id,
csrf: bili_jct,
ts: ts()
});
},
silver2coin: (visit_id = "") => {
const bili_jct = useBiliStore().cookies.bili_jct;
return request.live.post("/xlive/revenue/v1/wallet/silver2coin", {
csrf: bili_jct,
csrf_token: bili_jct,
visit_id
});
},
coin2silver: (num, platform = "pc", visit_id = "") => {
const bili_jct = useBiliStore().cookies.bili_jct;
return request.live.post("/xlive/revenue/v1/wallet/coin2silver", {
num,
csrf: bili_jct,
csrf_token: bili_jct,
platform,
visit_id
});
}
},
liveTrace: {
E: (id, device, ruid, is_patch = 0, heart_beat = [], visit_id = "") => {
const bili_jct = useBiliStore().cookies.bili_jct;
return request.liveTrace.post("/xlive/data-interface/v1/x25Kn/E", {
id: JSON.stringify(id),
device: JSON.stringify(device),
ruid,
// 主播 uid
ts: tsm(),
is_patch,
heart_beat: JSON.stringify(heart_beat),
ua: navigator.userAgent,
csrf_token: bili_jct,
csrf: bili_jct,
visit_id
});
},
X: (s, id, device, ruid, ets, benchmark, time, ts2, visit_id = "") => {
const bili_jct = useBiliStore().cookies.bili_jct;
return request.liveTrace.post("/xlive/data-interface/v1/x25Kn/X", {
s,
id: JSON.stringify(id),
device: JSON.stringify(device),
ruid,
// 主播 uid
ets,
benchmark,
time,
ts: ts2,
ua: navigator.userAgent,
csrf_token: bili_jct,
csrf: bili_jct,
visit_id
});
}
},
main: {
nav: () => {
return request.main.get("/x/web-interface/nav");
},
reward: () => {
return request.main.get("/x/member/web/exp/reward");
},
dynamicAll: (type, page = 1, timezone_offset = -480, features = "itemOpusStyle") => {
return request.main.get("/x/polymer/web-dynamic/v1/feed/all", {
timezone_offset,
type,
page,
features
});
},
videoHeartbeat: (aid, cid = "", realtime = 0, played_time = 0, real_played_time = 0, refer_url = "https://t.bilibili.com/?spm_id_from=444.3.0.0", quality = 116, video_duration = 100, type = 3, sub_type = 0, play_type = 0, dt = 2, last_play_progress_time = 0, max_play_progress_time = 0, spmid = "333.488.0.0", from_spmid = "333.31.list.card_archive.click", extra = '{"player_version":"4.1.21-rc.1727.0"}') => {
const biliStore = useBiliStore();
return request.main.post("/x/click-interface/web/heartbeat", {
start_ts: ts(),
mid: useBiliStore().BilibiliLive.UID,
aid,
cid,
type,
sub_type,
dt,
play_type,
realtime,
played_time,
real_played_time,
refer_url,
quality,
video_duration,
last_play_progress_time,
max_play_progress_time,
spmid,
from_spmid,
extra,
csrf: biliStore.cookies.bili_jct
});
},
share: (aid, source = "pc_client_normal", eab_x = 2, ramval = 0, ga = 1) => {
const bili_jct = useBiliStore().cookies.bili_jct;
return request.main.post("/x/web-interface/share/add", {
aid,
eab_x,
ramval,
source,
ga,
csrf: bili_jct
});
},
coinAdd: (aid, num, select_like = 0, cross_domain = true, eab_x = 2, ramval = 6, source = "web_normal", ga = 1) => {
const bili_jct = useBiliStore().cookies.bili_jct;
return request.main.post("/x/web-interface/coin/add ", {
aid,
multiply: num,
select_like,
cross_domain,
eab_x,
ramval,
source,
ga,
csrf: bili_jct
});
},
videoRelation: (aid, bvid = "") => {
return request.main.get("/x/web-interface/archive/relation", {
aid,
bvid
});
}
},
vc: {
myGroups: (build = 0, mobi_app = "web") => {
return request.vc.get("/link_group/v1/member/my_groups", {
build,
mobi_app
});
},
signIn: (group_id, owner_id) => {
return request.vc.get("/link_setting/v1/link_setting/sign_in", {
group_id,
owner_id
});
}
}
};
class Logger {
constructor(title) {
__publicField(this, "NAME", "BLTH");
__publicField(this, "prefix_title_str");
__publicField(this, "_title");
this._title = title;
this.prefix_title_str = title.split("_").join("][");
}
get prefix() {
return [
`%c${this.NAME}%c[${( new Date()).toLocaleString()}]%c[${this.prefix_title_str}]%c:`,
"font-weight: bold; color: white; background-color: #23ade5; padding: 1px 4px; border-radius: 4px;",
"font-weight: bold; color: #0920e6;",
"font-weight: bold;",
""
];
}
log(...data) {
console.log(...this.prefix, ...data);
}
error(...data) {
console.error(...this.prefix, ...data);
}
warn(...data) {
console.warn(...this.prefix, ...data);
}
}
class BaseModule {
constructor(moduleName) {
/**
* 模块名称,在被导出时定义
*
* 输出控制台日志时会用到
*/
__publicField(this, "moduleName");
/**
* 用于在控制台中输出日志信息
*/
__publicField(this, "logger");
/**
* 储存所有模块信息的 Pinia Store
*/
__publicField(this, "moduleStore", useModuleStore());
/**
* 推荐添加一个 config 属性来表示当前模块的配置项
*
* @example this.moduleStore.moduleConfig.DailyTasks.MainSiteTasks.login
*/
__publicField(this, "config");
this.moduleName = moduleName;
this.logger = new Logger(this.moduleName);
}
/**
* 如果需要在控制面板上显示模块状态,推荐添加一个 status setter 用来设置模块状态
*
* @example
* public set status(s: Istatus) {
* this.moduleStore.moduleStatus.DailyTasks.MainSiteTasks.login = s
* }
*/
set status(_s) {
throw new Error("Method not implemented.");
}
run() {
throw new Error("Method not implemented.");
}
}
/**
* 当脚本在多个页面上运行的时候,该模块是否要在每个页面上运行
*
* 默认false,即只在Main BLTH运行的页面上运行
*/
__publicField(BaseModule, "runMultiple", false);
class DefaultBaseModule extends BaseModule {
/**
* 默认模块按顺序逐个运行,所以必须返回一个 Promise
*/
run() {
throw new Error("Method not implemented.");
}
}
/**
* 优先级,数字越小优先级越高
*/
__publicField(DefaultBaseModule, "sequence");
function getCookie(name) {
const nameEqual = name + "=";
for (const cookie of document.cookie.split("; ")) {
if (cookie.startsWith(nameEqual)) {
const value = cookie.substring(nameEqual.length);
return decodeURIComponent(value);
}
}
return null;
}
function getCookies(names) {
const cookies = {};
for (const name of names) {
cookies[name] = null;
}
for (const cookie of document.cookie.split("; ")) {
for (let i = 0; i < names.length; i++) {
const name = names[i];
const nameEqual = name + "=";
if (cookie.startsWith(nameEqual)) {
const value = cookie.substring(nameEqual.length);
cookies[name] = decodeURIComponent(value);
names.splice(i, 1);
break;
}
}
if (names.length === 0)
break;
}
return cookies;
}
class BiliInfo extends DefaultBaseModule {
getBilibiliLive() {
this.logger.log("unsafeWindow.BilibiliLive", _unsafeWindow.BilibiliLive);
return _unsafeWindow.BilibiliLive;
}
/**
* 获取 Cookies
*
* bili_jct: 常作为参数 csrf 在请求中出现
* LIVE_BUVID 不能在此处获取,还没生成
*/
getCookies() {
return getCookies(["bili_jct"]);
}
/**
* 通过 BAPI.main.nav 获取用户基本信息
*/
async getUserInfo() {
try {
const response = await BAPI.main.nav();
this.logger.log("BAPI.main.nav response", response);
if (response.code === 0) {
return Promise.resolve(response.data);
} else {
this.logger.error("获取用户信息失败", response.message);
return Promise.reject(response.message);
}
} catch (error) {
this.logger.error("获取用户信息出错", error);
return Promise.reject(error);
}
}
/**
* 获取礼物配置信息
*
* 如礼物id,名称,亲密度等等
*/
async getGiftConfig() {
try {
throw new Error("送礼功能尚未完成,暂时不需要获取礼物配置信息,请忽略本报错 >︿<");
const response = await BAPI.live.roomGiftConfig();
this.logger.log("BAPI.live.roomGiftConfig response", response);
if (response.code === 0) {
return Promise.resolve(response.data);
} else {
this.logger.error("获取礼物配置信息失败", response.message);
return Promise.reject(response.message);
}
} catch (error) {
this.logger.error("获取礼物配置信息出错", error);
return Promise.reject(error);
}
}
/**
* 获取今日主站每日任务的完成情况
*/
async getDailyRewardInfo() {
const MainSiteTasks = this.moduleStore.moduleConfig.DailyTasks.MainSiteTasks;
if (Object.values(MainSiteTasks).some((t) => t.enabled && !isTimestampToday(t._lastCompleteTime))) {
try {
const response = await BAPI.main.reward();
this.logger.log("BAPI.main.reward response", response);
if (response.code === 0) {
return Promise.resolve(response.data);
} else {
this.logger.error("获取主站每日任务完成情况失败", response.message);
return Promise.reject(response.message);
}
} catch (error) {
this.logger.error("获取主站每日任务完成情况出错", error);
return Promise.reject(error);
}
} else {
return Promise.reject();
}
}
/**
* 从动态中获取一页视频的信息
*
* 每日观看视频,每日分享视频,每日投币都会用到
*/
async getDynamicVideo() {
const MainSiteTasks = this.moduleStore.moduleConfig.DailyTasks.MainSiteTasks;
if (Object.entries(MainSiteTasks).filter(([key]) => ["watch", "share", "coin"].includes(key)).some((keyValue) => keyValue[1].enabled && !isTimestampToday(keyValue[1]._lastCompleteTime))) {
try {
const response = await BAPI.main.dynamicAll("video");
this.logger.log("BAPI.main.dynamicAll response", response);
if (response.code === 0) {
return Promise.resolve(response.data.items);
} else {
this.logger.error("获取主站每日任务完成情况失败", response.message);
return Promise.reject(response.message);
}
} catch (error) {
this.logger.error("获取主站每日任务完成情况出错", error);
return Promise.reject(error);
}
} else {
return Promise.reject();
}
}
/**
* 获取粉丝勋章
*
* @param pages 获取的页数
* @param force 是否无视配置强制获取,默认fasle
*/
async getFansMetals(pages = 10, force = false) {
const medalTasks = this.moduleStore.moduleConfig.DailyTasks.LiveTasks.medalTasks;
if (force || Object.entries(medalTasks).filter(([key]) => ["danmu", "like", "watch"].includes(key)).some(
(keyValue) => keyValue[1].enabled && !isTimestampToday(keyValue[1]._lastCompleteTime)
)) {
const fansMetalList = [];
let total_page = 1;
try {
const firstPageResponse = await BAPI.live.fansMedalPanel(1);
this.logger.log("BAPI.live.fansMedalPanel(1) response", firstPageResponse);
if (firstPageResponse.code === 0) {
total_page = firstPageResponse.data.page_info.total_page;
fansMetalList.push(...firstPageResponse.data.special_list, ...firstPageResponse.data.list);
} else {
this.logger.error("获取粉丝勋章列表第1页失败", firstPageResponse.message);
return Promise.reject(firstPageResponse.message);
}
for (let page = 2; page <= Math.min(total_page, pages); page++) {
const response = await BAPI.live.fansMedalPanel(page);
this.logger.log(`BAPI.live.fansMedalPanel(${page}) response`, response);
if (firstPageResponse.code === 0) {
fansMetalList.push(...response.data.list);
} else {
this.logger.error(`获取粉丝勋章列表第${page}页失败`, firstPageResponse.message);
return fansMetalList;
}
await sleep(250);
}
return Promise.resolve(fansMetalList);
} catch (error) {
return Promise.reject(error);
}
} else {
return Promise.reject();
}
}
async run() {
const biliStore = useBiliStore();
biliStore.BilibiliLive = this.getBilibiliLive();
biliStore.cookies = this.getCookies();
biliStore.userInfo = await this.getUserInfo();
setTimeout(async () => {
biliStore.userInfo = await this.getUserInfo();
}, delayToNextMoment(0, 4).ms);
const allPromiseResult = await Promise.allSettled([
this.getGiftConfig(),
this.getDailyRewardInfo(),
this.getDynamicVideo(),
this.getFansMetals()
]);
this.logger.log("allPromiseResult", allPromiseResult);
biliStore.giftConfig = allPromiseResult[0].status === "fulfilled" ? allPromiseResult[0].value : null;
biliStore.dailyRewardInfo = allPromiseResult[1].status === "fulfilled" ? allPromiseResult[1].value : null;
setTimeout(async () => {
const biliStore2 = useBiliStore();
if (biliStore2.dailyRewardInfo) {
biliStore2.dailyRewardInfo.login = false;
biliStore2.dailyRewardInfo.share = false;
biliStore2.dailyRewardInfo.watch = false;
biliStore2.dailyRewardInfo.coins = 0;
}
biliStore2.dailyRewardInfo = await this.getDailyRewardInfo();
}, delayToNextMoment(0, 4).ms);
biliStore.dynamicVideos = allPromiseResult[2].status === "fulfilled" ? allPromiseResult[2].value : null;
setTimeout(async () => {
biliStore.dynamicVideos = await this.getDynamicVideo();
}, delayToNextMoment(0, 4).ms);
biliStore.fansMedals = allPromiseResult[3].status === "fulfilled" ? allPromiseResult[3].value : null;
setTimeout(async () => {
biliStore.fansMedals = await this.getFansMetals();
}, delayToNextMoment(0, 4).ms);
useModuleStore().emitter.on(this.moduleName, async (event) => {
if (event.target === "getFansMetals") {
biliStore.fansMedals = await this.getFansMetals(10, true);
}
});
}
}
__publicField(BiliInfo, "sequence", 0);
const defaultModules = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
BiliInfo
}, Symbol.toStringTag, { value: "Module" }));
class LoginTask extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.DailyTasks.MainSiteTasks.login);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.MainSiteTasks.login = s;
}
async login() {
this.logger.log("每日登录(不可用)任务已完成");
this.config._lastCompleteTime = tsm();
this.status = "done";
return Promise.resolve();
}
async run() {
this.logger.log("每日登录(不可用)模块开始运行");
if (this.config.enabled) {
const biliStore = useBiliStore();
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
if (biliStore.dailyRewardInfo && !biliStore.dailyRewardInfo.login) {
await this.login();
} else {
this.config._lastCompleteTime = tsm();
this.status = "done";
}
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过每日登录(不可用)任务了");
this.status = "done";
} else {
this.logger.log("昨天的每日登录(不可用)任务已经完成过了,等到今天的00:05再执行");
}
}
}
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("距离每日登录(不可用)模块下次运行时间:", diff.str);
}
}
let WatchTask$1 = class WatchTask extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.DailyTasks.MainSiteTasks.watch);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.MainSiteTasks.watch = s;
}
getAid() {
const biliStore = useBiliStore();
if (!_.isEmpty(biliStore.dynamicVideos)) {
return biliStore.dynamicVideos[0].modules.module_dynamic.major.archive.aid;
} else {
return "2";
}
}
async watch(aid) {
try {
const response = await BAPI.main.videoHeartbeat(aid);
this.logger.log(`BAPI.main.videoHeartbeat(${aid}) response`, response);
if (response.code === 0) {
this.logger.log("每日观看视频任务已完成");
this.config._lastCompleteTime = tsm();
this.status = "done";
} else {
this.logger.error("发送观看视频心跳失败", response.message);
this.status = "error";
}
} catch (err) {
this.logger.error("执行每日观看视频任务出错", err);
this.status = "error";
}
}
async run() {
this.logger.log("每日观看视频模块开始运行");
if (this.config.enabled) {
const biliStore = useBiliStore();
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
if (biliStore.dailyRewardInfo && !biliStore.dailyRewardInfo.watch) {
const aid = this.getAid();
await this.watch(aid);
} else {
this.config._lastCompleteTime = tsm();
this.status = "done";
this.logger.log("每日观看视频任务已完成");
}
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过每日观看视频任务了");
this.status = "done";
} else {
this.logger.log("昨天的每日观看视频任务已经完成过了,等到今天的00:05再执行");
}
}
}
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("距离每日观看视频模块下次运行时间:", diff.str);
}
};
class ShareTask extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.DailyTasks.MainSiteTasks.share);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.MainSiteTasks.share = s;
}
getAid() {
const biliStore = useBiliStore();
if (!_.isEmpty(biliStore.dynamicVideos)) {
return biliStore.dynamicVideos[0].modules.module_dynamic.major.archive.aid;
} else {
return "2";
}
}
async share(aid) {
try {
const response = await BAPI.main.share(aid);
this.logger.log(`BAPI.main.share(${aid}) response`, response);
if (response.code === 0 || response.code === 71e3) {
this.logger.log("每日分享视频任务已完成");
this.config._lastCompleteTime = tsm();
this.status = "done";
} else {
this.logger.error("分享视频失败", response.message);
this.status = "error";
}
} catch (err) {
this.logger.error("执行每日分享视频任务出错", err);
this.status = "error";
}
}
async run() {
this.logger.log("每日分享视频模块开始运行");
if (this.config.enabled) {
const biliStore = useBiliStore();
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
if (biliStore.dailyRewardInfo && !biliStore.dailyRewardInfo.share) {
const aid = this.getAid();
await this.share(aid);
} else {
this.config._lastCompleteTime = tsm();
this.status = "done";
this.logger.log("每日分享视频任务已完成");
}
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过每日分享任务了");
this.status = "done";
} else {
this.logger.log("昨天的每日分享任务已经完成过了,等到今天的00:05再执行");
}
}
}
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("距离每日分享视频模块下次运行时间:", diff.str);
}
}
class CoinTask extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.DailyTasks.MainSiteTasks.coin);
// 暂时先限制每个视频最多投一个币
// 因为转载视频只能投一个币,原创视频能投两个币
// 但是想查询视频是否为转载,我目前只知道一个 /x/web-interface/wbi/view
// 通过其响应的copyright字段(1原创,2转载)来判断
// 不过这个接口带有 wbi 签名,实现起来复杂
// 所以干脆直接限制每个视频最多投一个币,反正视频数量足够
__publicField(this, "MAX_COIN", 1);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.MainSiteTasks.coin = s;
}
getDynamicVideoIds() {
const biliStore = useBiliStore();
if (!_.isEmpty(biliStore.dynamicVideos)) {
return biliStore.dynamicVideos.map((item) => {
const archive = item.modules.module_dynamic.major.archive;
return {
aid: archive.aid,
bvid: archive.bvid
};
});
} else {
this.status = "error";
return null;
}
}
async getVideoCoinInfo(aid, bvid) {
try {
const response = await BAPI.main.videoRelation(aid, bvid);
this.logger.log(`BAPI.main.videoRelation(${aid}, ${bvid}) response`, response);
if (response.code === 0) {
return response.data.coin;
} else {
this.logger.error(`获取视频投币信息失败 aid = ${aid} bvid = ${bvid}`, response.message);
return 0;
}
} catch (error) {
this.logger.error(`获取视频投币信息出错 aid = ${aid} bvid = ${bvid}`, error);
return 0;
}
}
async coinDynamicVideos(left_coin_num) {
const ids = this.getDynamicVideoIds();
if (ids) {
for (const { aid, bvid } of ids) {
const coined_num = await this.getVideoCoinInfo(aid, bvid);
const allowed_coin_num = this.MAX_COIN - coined_num;
if (allowed_coin_num > 0) {
const coin_num = Math.min(allowed_coin_num, left_coin_num);
const result = await this.coin(aid, coin_num);
if (result === 0) {
left_coin_num -= coin_num;
if (left_coin_num === 0) {
this.logger.log("每日投币任务已完成");
this.config._lastCompleteTime = tsm();
this.status = "done";
break;
}
} else if (result === 1) {
this.status = "error";
break;
}
}
}
}
}
async coin(aid, num) {
try {
const response = await BAPI.main.coinAdd(aid, num);
this.logger.log(`BAPI.main.coinAdd(${aid}) response`, response);
if (response.code === 0) {
this.logger.log(`投币成功 视频aid = ${aid} 投币数量num = ${num}`);
return 0;
} else if (response.code === -104) {
this.logger.warn("硬币余额不足,每日投币任务终止");
return 1;
} else {
this.logger.error(`投币失败 视频aid = ${aid} 投币数量num = ${num}`, response.message);
return 2;
}
} catch (err) {
this.logger.error(`投币出错 视频aid = ${aid} 投币数量num = ${num}`, err);
return 3;
}
}
async run() {
this.logger.log("每日投币模块开始运行");
if (this.config.enabled) {
const biliStore = useBiliStore();
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
if (biliStore.dailyRewardInfo) {
const total_coined_num = biliStore.dailyRewardInfo.coins / 10;
if (total_coined_num < this.config.num) {
const left_coin_num = this.config.num - total_coined_num;
const biliStore2 = useBiliStore();
const money = biliStore2.userInfo.money ?? 5;
if (left_coin_num > money) {
this.logger.log("硬币余额不足,不执行每日投币任务");
this.status = "done";
} else {
await this.coinDynamicVideos(left_coin_num);
}
} else {
this.config._lastCompleteTime = tsm();
this.status = "done";
this.logger.log("每日投币任务已完成");
}
}
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过每日投币任务了");
this.status = "done";
} else {
this.logger.log("昨天的每日投币任务已经完成过了,等到今天的00:05再执行");
}
}
}
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("距离每日投币模块下次运行时间:", diff.str);
}
}
const dq = document.querySelector.bind(document);
document.querySelectorAll.bind(document);
const dce = document.createElement.bind(document);
const pollingQuery = (element, selectors, intervel, timeout) => {
return new Promise((resolve, reject) => {
const timerPolling = setInterval(() => {
const ele = element.querySelector(selectors);
if (ele) {
clearTimeout(timerPolling);
resolve(ele);
}
}, intervel);
const timerTimeout = setTimeout(() => {
clearTimeout(timerPolling);
clearTimeout(timerTimeout);
reject();
}, timeout);
});
};
const isTargetFrame = () => {
if (_unsafeWindow.BilibiliLive) {
return true;
} else {
return false;
}
};
const isSelfTopFrame = () => _unsafeWindow.self === _unsafeWindow.top;
const topFrameDocuemnt = () => {
var _a;
return (_a = _unsafeWindow.top) == null ? void 0 : _a.document;
};
class SignTask extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.DailyTasks.LiveTasks.sign);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.LiveTasks.sign = s;
}
async getSignInfo() {
try {
const response = await BAPI.live.getSignInfo();
this.logger.log("BAPI.live.getSignInfo response", response);
if (response.code === 0) {
return response.data;
} else {
this.logger.error("获取直播签到信息失败", response.message);
return null;
}
} catch (error) {
this.logger.error("获取直播签到信息出错", error);
return null;
}
}
async sign() {
try {
const response = await BAPI.live.doSign();
this.logger.log(`BAPI.live.doSign response`, response);
if (response.code === 0) {
this.logger.log("直播签到成功,获得奖励:", response.data.text);
this.config._lastCompleteTime = tsm();
this.status = "done";
this.logger.log("直播签到任务已完成");
const checkinBtn = dq(".checkin-btn");
if (checkinBtn) {
checkinBtn.remove();
}
} else {
this.logger.error("直播签到失败", response.message);
this.status = "error";
}
} catch (err) {
this.logger.error("执行直播签到任务出错", err);
this.status = "error";
}
}
async run() {
this.logger.log("直播签到模块开始运行");
if (this.config.enabled) {
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
const signInfo = await this.getSignInfo();
if (signInfo) {
if (signInfo.status === 0) {
await this.sign();
} else {
this.config._lastCompleteTime = tsm();
this.status = "done";
}
} else {
await this.sign();
}
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过直播签到任务了");
this.status = "done";
} else {
this.logger.log("昨天的直播签到任务已经完成过了,等到今天的00:05再执行");
}
}
}
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("距离直播签到模块下次运行时间:", diff.str);
}
}
class AppUserTask extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.DailyTasks.LiveTasks.appUser);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.LiveTasks.appUser = s;
}
async getUserTaskProgress() {
try {
const response = await BAPI.live.getUserTaskProgress();
this.logger.log("BAPI.live.getUserTaskProgress response", response);
if (response.code === 0) {
return response.data;
} else {
this.logger.error("获取APP用户任务进度失败", response.message);
this.status = "error";
return null;
}
} catch (error) {
this.logger.error("获取APP用户任务进度出错", error);
this.status = "error";
return null;
}
}
async userTaskReceiveRewards() {
try {
const response = await BAPI.live.userTaskReceiveRewards();
this.logger.log("BAPI.live.userTaskReceiveRewards response", response);
if (response.code === 0) {
return response.data;
} else {
this.logger.error("获取APP用户任务进度失败", response.message);
this.status = "error";
return null;
}
} catch (error) {
this.logger.error("获取APP用户任务进度出错", error);
this.status = "error";
return null;
}
}
async sendDanmu(danmu, roomid) {
try {
const response = await BAPI.live.sendMsg(danmu, roomid);
this.logger.log(`BAPI.live.sendMsg(${danmu}, ${roomid})`, response);
if (response.code === 0) {
this.logger.log(`在直播间 ${roomid} 发送弹幕 ${danmu} 成功`);
} else {
this.logger.error(`在直播间 ${roomid} 发送弹幕 ${danmu} 失败`, response.message);
}
} catch (error) {
this.logger.error(`在直播间 ${roomid} 发送弹幕 ${danmu} 出错`, error);
}
}
async run() {
this.logger.log("APP用户任务模块开始运行");
this.logger.warn("APP用户任务暂时没有,该模块不运行");
this.config.enabled = false;
if (this.config.enabled) {
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
const danmuConfig = this.moduleStore.moduleConfig.DailyTasks.LiveTasks.medalTasks.danmu;
if (danmuConfig.enabled && !isTimestampToday(danmuConfig._lastCompleteTime)) {
await wait(this.moduleName, 3e5);
}
const progressResponse = await this.getUserTaskProgress();
if (progressResponse) {
if (progressResponse.is_surplus !== -1) {
if (progressResponse.day_task.status === 3) {
this.config._lastCompleteTime = tsm();
this.status = "done";
} else if (progressResponse.day_task.status === 2) {
const receiveResponse = await this.userTaskReceiveRewards();
if (receiveResponse) {
const num = receiveResponse.num;
if (num) {
this.logger.log(`领取奖励成功:${num}个电池`);
} else {
this.logger.warn(`领取奖励失败:未领取到电池`);
}
this.config._lastCompleteTime = tsm();
this.status = "done";
}
} else {
let remainProgress = progressResponse.day_task.target - progressResponse.day_task.progress;
while (remainProgress > 0) {
await this.sendDanmu(`打卡${remainProgress}`, 22474988);
await sleep(2e3);
remainProgress--;
}
const receiveResponse = await this.userTaskReceiveRewards();
if (receiveResponse) {
const num = receiveResponse.num;
if (num) {
this.logger.log(`领取奖励成功:${num}个电池`);
} else {
this.logger.warn(`领取奖励失败:未领取到电池`);
}
this.config._lastCompleteTime = tsm();
this.status = "done";
}
}
} else {
this.logger.log("今天APP用户任务的奖励已经没有了,明天早点来吧");
this.config._lastCompleteTime = tsm();
this.status = "done";
}
}
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过APP用户任务了");
this.status = "done";
} else {
this.logger.log("昨天的APP用户任务已经完成过了,等到今天的00:05再执行");
}
}
}
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("距离APP用户任务模块下次运行时间:", diff.str);
}
}
class LikeTask extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "medalTasksConfig", this.moduleStore.moduleConfig.DailyTasks.LiveTasks.medalTasks);
__publicField(this, "config", this.medalTasksConfig.like);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.LiveTasks.medalTasks.like = s;
}
/**
* 获取粉丝勋章的房间号和主播uid,过滤等级大于等于20或不符合黑白名单要求的粉丝勋章
* @returns 数组,每个元素都是数组:[房间号,主播uid]
*/
getRoomidUidList() {
const biliStore = useBiliStore();
if (biliStore.filteredFansMedals) {
return biliStore.filteredFansMedals.filter(
(medal) => medal.medal.level < 20 && (this.medalTasksConfig.isWhiteList ? this.medalTasksConfig.roomidList.includes(medal.room_info.room_id) : !this.medalTasksConfig.roomidList.includes(medal.room_info.room_id))
).map((medal) => [medal.room_info.room_id, medal.medal.target_id]).slice(0, 100);
} else {
this.status = "error";
return null;
}
}
async like(roomid, target_id) {
try {
const response = await BAPI.live.likeReport(roomid, target_id);
this.logger.log(`BAPI.live.likeReport(${roomid}, ${target_id})`, response);
if (response.code === 0) {
this.logger.log(`给主播点赞 房间号 = ${roomid} 主播UID = ${target_id} 成功`);
} else {
this.logger.error(
`给主播点赞 房间号 = ${roomid} 主播UID = ${target_id} 失败`,
response.message
);
}
} catch (error) {
this.logger.error(`给主播点赞 房间号 = ${roomid} 主播UID = ${target_id} 出错`, error);
}
}
async run() {
this.logger.log("给主播点赞模块开始运行");
if (this.config.enabled) {
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
const idList = this.getRoomidUidList();
if (idList) {
for (const [roomid, target_id] of idList) {
await this.like(roomid, target_id);
await sleep(2e3);
}
this.config._lastCompleteTime = tsm();
this.status = "done";
this.logger.log("给主播点赞任务已完成");
}
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过给主播点赞任务了");
this.status = "done";
} else {
this.logger.log("昨天的给主播点赞任务已经完成过了,等到今天的00:05再执行");
}
}
}
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("距离给主播点赞模块下次运行时间:", diff.str);
}
}
class RoomHeart {
constructor(roomID, areaID, parentID, ruid, watchedSeconds, isLast = false) {
__publicField(this, "logger", new Logger("RoomHeart"));
__publicField(this, "config");
/** 是不是最后一个心跳任务 */
__publicField(this, "isLast");
/** 已观看时间(秒) */
__publicField(this, "watchedSeconds");
__publicField(this, "timer");
__publicField(this, "stop", false);
__publicField(this, "areaID");
__publicField(this, "parentID");
__publicField(this, "roomID");
/** 主播的 UID */
__publicField(this, "ruid");
__publicField(this, "seq", 0);
/** Cookie LIVE_BUVID */
__publicField(this, "buvid", getCookie("LIVE_BUVID"));
__publicField(this, "uuid", uuid());
/** 计算签名和发送请求时均需要 JSON.stringify */
__publicField(this, "device", [this.buvid, this.uuid]);
/** 浏览器 user agent */
__publicField(this, "ua", navigator.userAgent);
__publicField(this, "heartBeatInterval");
__publicField(this, "secretKey");
__publicField(this, "secretRule");
/** ets */
__publicField(this, "timestamp");
this.roomID = roomID;
this.areaID = areaID;
this.parentID = parentID;
this.ruid = ruid;
this.watchedSeconds = watchedSeconds;
this.isLast = isLast;
this.config = useModuleStore().moduleConfig.DailyTasks.LiveTasks.medalTasks.watch;
}
set status(s) {
useModuleStore().moduleStatus.DailyTasks.LiveTasks.medalTasks.watch = s;
}
/** 计算签名和发送请求时均需要 JSON.stringify */
get id() {
return [this.parentID, this.areaID, this.seq, this.roomID];
}
/**
* 开始心跳
*/
start() {
if (!this.buvid)
return;
this.timer = setTimeout(() => this.stop = true, delayToNextMoment(0, 0).ms);
return this.E();
}
/**
* E心跳,开始时发送一次
*/
async E() {
if (this.stop) {
this.status = "";
return;
}
try {
const response = await BAPI.liveTrace.E(this.id, this.device, this.ruid);
this.logger.log(
`BAPI.liveTrace.E(${this.id}, ${this.device}, ${this.ruid}) response`,
response
);
if (response.code === 0) {
this.seq += 1;
({
heartbeat_interval: this.heartBeatInterval,
secret_key: this.secretKey,
secret_rule: this.secretRule,
timestamp: this.timestamp
} = response.data);
setTimeout(() => this.X(), this.heartBeatInterval * 1e3);
} else {
this.logger.error(
`BAPI.liveTrace.E(${this.id}, ${this.device}, ${this.ruid}) 失败`,
response.message
);
}
} catch (error) {
this.logger.error(`BAPI.liveTrace.E(${this.id}, ${this.device}, ${this.ruid}) 出错`, error);
}
}
/**
* X心跳,E心跳过后都是X心跳
*/
async X() {
if (this.stop) {
this.status = "";
return;
}
try {
const sypderData = {
id: JSON.stringify(this.id),
device: JSON.stringify(this.device),
ets: this.timestamp,
benchmark: this.secretKey,
time: this.heartBeatInterval,
ts: tsm(),
ua: this.ua
};
const s = this.sypder(JSON.stringify(sypderData), this.secretRule);
const response = await BAPI.liveTrace.X(
s,
this.id,
this.device,
this.ruid,
this.timestamp,
this.secretKey,
this.heartBeatInterval,
sypderData.ts
);
this.logger.log(
`BAPI.liveTrace.X(${s}, ${this.id}, ${this.device}, ${this.ruid}, ${this.timestamp}, ${this.secretKey}, ${this.heartBeatInterval}, ${sypderData.ts}) response`,
response
);
if (response.code === 0) {
this.seq += 1;
this.watchedSeconds += this.heartBeatInterval;
if (this.isLast) {
this.config._watchedSecondsToday = this.watchedSeconds;
}
if (this.watchedSeconds >= this.config.time * 60) {
if (this.isLast) {
this.config._lastCompleteTime = tsm();
this.logger.log("观看直播任务已完成");
this.status = "done";
}
clearTimeout(this.timer);
return;
}
;
({
heartbeat_interval: this.heartBeatInterval,
secret_key: this.secretKey,
secret_rule: this.secretRule,
timestamp: this.timestamp
} = response.data);
setTimeout(() => this.X(), this.heartBeatInterval * 1e3);
} else {
this.logger.error(
`BAPI.liveTrace.X(${s}, ${this.id}, ${this.device}, ${this.ruid}, ${this.timestamp}, ${this.secretKey}, ${this.heartBeatInterval}) 失败`,
response.message
);
}
} catch (error) {
this.logger.error(
`BAPI.liveTrace.X(s, ${this.id}, ${this.device}, ${this.ruid}, ${this.timestamp}, ${this.secretKey}, ${this.heartBeatInterval}) 出错`,
error
);
}
}
/**
* wasm 导出的 spyider 函数的 javascript 实现
* @param str 一个经过 JSON.stringify 的 json 字符串
* @param rule secret_rule 数组
* @returns s
*/
sypder(str, rule) {
const data = JSON.parse(str);
const [parent_id, area_id, seq_id, room_id] = JSON.parse(data.id);
const [buvid, uuid2] = JSON.parse(data.device);
const key = data.benchmark;
const newData = {
platform: "web",
parent_id,
area_id,
seq_id,
room_id,
buvid,
uuid: uuid2,
ets: data.ets,
time: data.time,
ts: data.ts
};
let s = JSON.stringify(newData);
for (const r of rule) {
switch (r) {
case 0:
s = CryptoJS.HmacMD5(s, key).toString(CryptoJS.enc.Hex);
break;
case 1:
s = CryptoJS.HmacSHA1(s, key).toString(CryptoJS.enc.Hex);
break;
case 2:
s = CryptoJS.HmacSHA256(s, key).toString(CryptoJS.enc.Hex);
break;
case 3:
s = CryptoJS.HmacSHA224(s, key).toString(CryptoJS.enc.Hex);
break;
case 4:
s = CryptoJS.HmacSHA512(s, key).toString(CryptoJS.enc.Hex);
break;
case 5:
s = CryptoJS.HmacSHA384(s, key).toString(CryptoJS.enc.Hex);
break;
default:
s = CryptoJS.HmacMD5(s, key).toString(CryptoJS.enc.Hex);
}
}
return s;
}
}
class WatchTask2 extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "medalTasksConfig", this.moduleStore.moduleConfig.DailyTasks.LiveTasks.medalTasks);
__publicField(this, "config", this.medalTasksConfig.watch);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.LiveTasks.medalTasks.watch = s;
}
/**
* 获取粉丝勋章的房间号和主播uid,过滤等级大于等于20或不符合黑白名单要求的粉丝勋章
* @returns 数组,每个元素都是数组:[房间号,主播uid]
*/
getRoomidUidList() {
const biliStore = useBiliStore();
if (biliStore.filteredFansMedals) {
return biliStore.filteredFansMedals.filter(
(medal) => medal.medal.level < 20 && (this.medalTasksConfig.isWhiteList ? this.medalTasksConfig.roomidList.includes(medal.room_info.room_id) : !this.medalTasksConfig.roomidList.includes(medal.room_info.room_id))
).map((medal) => [medal.room_info.room_id, medal.medal.target_id]).slice(0, 100);
} else {
return null;
}
}
/**
* 获取指定直播间的 area_id 和 parent_area_id
*
* @param roomid 房间号
* @returns [area_id, parent_area_id]
*/
async getAreaInfo(roomid) {
try {
const response = await BAPI.live.getInfoByRoom(roomid);
this.logger.log(`BAPI.live.getInfoByRoom(${roomid}) response`, response);
if (response.code === 0) {
const room_info = response.data.room_info;
return [room_info.area_id, room_info.parent_area_id];
} else {
return null;
}
} catch (error) {
this.logger.error(
`获取指定直播间的 area_id 和 parent_area_id(roomid = ${roomid}) 出错`,
error
);
return null;
}
}
async run() {
this.logger.log("观看直播模块开始运行");
if (this.config.enabled) {
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
if (!isTimestampToday(this.config._lastWatchTime, 0, 0)) {
this.config._watchedSecondsToday = 0;
} else {
this.config._watchedSecondsToday -= this.config._watchedSecondsToday % 300;
}
this.config._lastWatchTime = tsm();
const idList = this.getRoomidUidList();
if (idList) {
if (idList.length === 0) {
this.status = "done";
this.config._lastCompleteTime = tsm();
} else {
for (let i = 0; i < idList.length; i++) {
const [roomid, uid] = idList[i];
const areaInfo = await this.getAreaInfo(roomid);
if (areaInfo && areaInfo.every((id) => id > 0)) {
new RoomHeart(
roomid,
areaInfo[0],
areaInfo[1],
uid,
this.config._watchedSecondsToday,
i === idList.length - 1 ? true : false
).start();
}
await sleep(3e3);
}
}
}
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过观看直播任务了");
this.status = "done";
} else {
this.logger.log("昨天的观看直播任务已经完成过了,等到今天的00:05再执行");
}
}
}
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("距离观看直播模块下次运行时间:", diff.str);
}
}
class DanmuTask extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "medalTasksConfig", this.moduleStore.moduleConfig.DailyTasks.LiveTasks.medalTasks);
__publicField(this, "config", this.medalTasksConfig.danmu);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.LiveTasks.medalTasks.danmu = s;
}
/**
* 获取粉丝勋章的房间号,过滤等级大于等于20或不符合黑白名单要求的粉丝勋章
*/
getRoomidList() {
const biliStore = useBiliStore();
if (biliStore.filteredFansMedals) {
return biliStore.filteredFansMedals.filter(
(medal) => medal.medal.level < 20 && medal.room_info.room_id != 910884 && (this.medalTasksConfig.isWhiteList ? this.medalTasksConfig.roomidList.includes(medal.room_info.room_id) : !this.medalTasksConfig.roomidList.includes(medal.room_info.room_id))
).map((medal) => medal.room_info.room_id).slice(0, 100);
} else {
this.status = "error";
return null;
}
}
async sendDanmu(danmu, roomid) {
try {
const response = await BAPI.live.sendMsg(danmu, roomid);
this.logger.log(`BAPI.live.sendMsg(${danmu}, ${roomid})`, response);
if (response.code === 0) {
this.logger.log(`在直播间 ${roomid} 发送弹幕 ${danmu} 成功`);
} else {
this.logger.error(`在直播间 ${roomid} 发送弹幕 ${danmu} 失败`, response.message);
}
} catch (error) {
this.logger.error(`在直播间 ${roomid} 发送弹幕 ${danmu} 出错`, error);
}
}
async run() {
this.logger.log("发送弹幕模块开始运行");
if (this.config.enabled) {
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
const roomIdList = this.getRoomidList();
if (roomIdList) {
const danmuList = this.config.list;
for (let i = 0; i < roomIdList.length; i++) {
const danmu = danmuList[i % danmuList.length];
await this.sendDanmu(danmu, roomIdList[i]);
await sleep(2e3);
}
this.config._lastCompleteTime = tsm();
this.status = "done";
this.logger.log("发送弹幕任务已完成");
}
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过发送弹幕任务了");
this.status = "done";
} else {
this.logger.log("昨天的发送弹幕任务已经完成过了,等到今天的00:05再执行");
}
}
}
this.moduleStore.emitter.emit("DailyTask_LiveTask_AppUserTask", {
module: this.moduleName
});
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("距离发送弹幕模块下次运行时间:", diff.str);
}
}
class GroupSignTask extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.DailyTasks.OtherTasks.groupSign);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.OtherTasks.groupSign = s;
}
/**
* 获取应援团 id 和拥有者 uid
* @returns 数组,每个元素都是数组:[应援团 id,拥有者 uid]
*/
async getGroupidOwneruidList() {
try {
const response = await BAPI.vc.myGroups();
this.logger.log(`BAPI.vc.myGroups response`, response);
if (response.code === 0) {
return response.data.list.map((item) => [item.group_id, item.owner_uid]);
} else {
this.logger.error(`获取应援团信息失败`, response.message);
this.status = "error";
}
} catch (error) {
this.logger.error(`获取应援团信息出错`, error);
this.status = "error";
}
}
async sign(group_id, owner_uid) {
try {
const response = await BAPI.vc.signIn(group_id, owner_uid);
this.logger.log(`BAPI.vc.signIn(${group_id}, ${owner_uid}) response`, response);
if (response.code === 0) {
this.logger.log(
`应援团签到 应援团ID = ${group_id} 拥有者UID = ${owner_uid} 成功, 粉丝勋章亲密度+${response.data.add_num}`
);
} else {
this.logger.error(
`应援团签到 应援团ID = ${group_id} 拥有者UID = ${owner_uid} 失败`,
response.message
);
}
} catch (error) {
this.logger.error(`应援团签到 应援团ID = ${group_id} 拥有者UID = ${owner_uid} 出错`, error);
}
}
async run() {
this.logger.log("应援团签到模块开始运行");
if (this.config.enabled) {
if (!isTimestampToday(this.config._lastCompleteTime, 8, 5)) {
this.status = "running";
const idList = await this.getGroupidOwneruidList();
if (idList) {
for (const [group_id, owner_uid] of idList) {
await this.sign(group_id, owner_uid);
await sleep(2e3);
}
this.config._lastCompleteTime = tsm();
this.logger.log("应援团签到任务已完成");
this.status = "done";
}
} else {
if (!isNowIn(0, 0, 8, 5)) {
this.logger.log("今天已经完成过应援团签到任务了");
this.status = "done";
} else {
this.logger.log("昨天的应援团签到任务已经完成过了,等到今天早上八点零五分再次执行");
}
}
}
const diff = delayToNextMoment(8, 5);
setTimeout(() => this.run(), diff.ms);
this.logger.log("距离应援团签到模块下次运行时间:", diff.str);
}
}
class SilverToCoin extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.DailyTasks.OtherTasks.silverToCoin);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.OtherTasks.silverToCoin = s;
}
async exchange() {
try {
const response = await BAPI.live.silver2coin();
this.logger.log(`BAPI.live.silver2coin response`, response);
if (response.code === 0) {
this.logger.log(`银瓜子换硬币已完成,获得硬币:`, response.data.coin);
this.config._lastCompleteTime = tsm();
this.status = "done";
} else if (response.code === 403) {
this.logger.log("每天最多只能用银瓜子兑换1个硬币");
this.config._lastCompleteTime = tsm();
this.status = "done";
} else {
this.logger.error("银瓜子换硬币失败", response.message);
this.status = "error";
}
} catch (err) {
this.logger.error("银瓜子换硬币出错", err);
this.status = "error";
}
}
async run() {
this.logger.log("银瓜子换硬币模块开始运行");
if (this.config.enabled) {
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
await this.exchange();
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过银瓜子换硬币任务了");
this.status = "done";
} else {
this.logger.log("昨天的银瓜子换硬币任务已经完成过了,等到今天的00:05再执行");
}
}
}
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("银瓜子换硬币模块下次运行时间:", diff.str);
}
}
class CoinToSilver extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.DailyTasks.OtherTasks.coinToSilver);
}
set status(s) {
this.moduleStore.moduleStatus.DailyTasks.OtherTasks.coinToSilver = s;
}
async exchange() {
try {
const response = await BAPI.live.coin2silver(this.config.num);
this.logger.log(`BAPI.live.coin2silver{${this.config.num}} response`, response);
if (response.code === 0) {
this.logger.log("硬币换银瓜子已完成,获得银瓜子:", response.data.silver);
this.config._lastCompleteTime = tsm();
this.status = "done";
} else {
this.logger.error("硬币换银瓜子失败", response.message);
this.status = "error";
}
} catch (err) {
this.logger.error("硬币换银瓜子出错", err);
this.status = "error";
}
}
async run() {
this.logger.log("硬币换银瓜子模块开始运行");
if (this.config.enabled) {
if (!isTimestampToday(this.config._lastCompleteTime)) {
this.status = "running";
await this.exchange();
} else {
if (!isNowIn(0, 0, 0, 5)) {
this.logger.log("今天已经完成过硬币换银瓜子任务了");
this.status = "done";
} else {
this.logger.log("昨天的硬币换银瓜子任务已经完成过了,等到今天的00:05再执行");
}
}
}
const diff = delayToNextMoment();
setTimeout(() => this.run(), diff.ms);
this.logger.log("硬币换银瓜子模块下次运行时间:", diff.str);
}
}
class SwitchLiveStreamQuality extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.EnhanceExperience.switchLiveStreamQuality);
}
async waitForPlayer() {
return new Promise((resolve, reject) => {
const topWindow = _unsafeWindow.top ? _unsafeWindow.top : _unsafeWindow;
const findPlayertimer = setInterval(() => {
if (topWindow.livePlayer && Object.prototype.hasOwnProperty.call(topWindow.livePlayer, "switchQuality") && Object.prototype.hasOwnProperty.call(topWindow.livePlayer, "getPlayerInfo")) {
clearInterval(findPlayertimer);
clearTimeout(timeoutTimer);
resolve(topWindow.livePlayer);
}
}, 200);
const timeoutTimer = setTimeout(() => {
clearInterval(findPlayertimer);
clearTimeout(timeoutTimer);
reject();
}, 1e4);
});
}
switchQuality(livePlayer) {
const playerInfo = livePlayer.getPlayerInfo();
if (playerInfo.liveStatus === 0) {
this.logger.log("当前直播间未开播");
} else {
const targetQuality = playerInfo.qualityCandidates.find(
({ desc }) => desc === this.config.qualityDesc
);
if (targetQuality && playerInfo.quality !== targetQuality.qn) {
livePlayer.switchQuality(targetQuality.qn);
this.logger.log(`已将画质切换为${this.config.qualityDesc}`, targetQuality);
}
}
}
async run() {
this.logger.log("自动切换画质模块开始运行");
if (this.config.enabled) {
try {
const livePlayer = await this.waitForPlayer();
this.switchQuality(livePlayer);
} catch (e) {
this.logger.error("等待播放器超时");
}
}
}
}
__publicField(SwitchLiveStreamQuality, "runMultiple", true);
class BanP2P extends BaseModule {
constructor() {
super(...arguments);
__publicField(this, "config", this.moduleStore.moduleConfig.EnhanceExperience.banp2p);
}
async banP2P() {
var _a;
const RTClist = [
"RTCPeerConnection",
"mozRTCPeerConnection",
"webkitRTCPeerConnection",
"test"
];
for (const i of RTClist) {
if (Object.prototype.hasOwnProperty.call(_unsafeWindow, i) && ((_a = Object.getOwnPropertyDescriptor(_unsafeWindow, i)) == null ? void 0 : _a.configurable)) {
Object.defineProperty(_unsafeWindow, i, {
value: function() {
this.addEventListener = function() {
};
this.createDataChannel = function() {
return { close: function() {
} };
};
this.createOffer = function() {
};
this.setLocalDescription = function() {
};
this.close = function() {
};
this.setRemoteDescription = function() {
};
this.createAnswer = function() {
};
},
enumerable: false,
writable: false,
configurable: false
});
}
}
}
async run() {
this.logger.log("禁用P2P模块开始运行");
if (this.config.enabled) {
try {
await this.banP2P();
} catch (e) {
this.logger.error("禁用P2P失败", e);
}
}
}
}
__publicField(BanP2P, "runMultiple", true);
const otherModules = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
DailyTask_LiveTask_AppUserTask: AppUserTask,
DailyTask_LiveTask_DanmuTask: DanmuTask,
DailyTask_LiveTask_LikeTask: LikeTask,
DailyTask_LiveTask_SignTask: SignTask,
DailyTask_LiveTask_WatchTask: WatchTask2,
DailyTask_MainSiteTask_CoinTask: CoinTask,
DailyTask_MainSiteTask_LoginTask: LoginTask,
DailyTask_MainSiteTask_ShareTask: ShareTask,
DailyTask_MainSiteTask_WatchTask: WatchTask$1,
DailyTask_OtherTask_CoinToSilver: CoinToSilver,
DailyTask_OtherTask_GroupSignTask: GroupSignTask,
DailyTask_OtherTask_SilverToCoin: SilverToCoin,
EnhanceExperience_BanP2P: BanP2P,
EnhanceExperience_SwitchLiveStreamQuality: SwitchLiveStreamQuality
}, Symbol.toStringTag, { value: "Module" }));
function mitt(n) {
return { all: n = n || /* @__PURE__ */ new Map(), on: function(t, e) {
var i = n.get(t);
i ? i.push(e) : n.set(t, [e]);
}, off: function(t, e) {
var i = n.get(t);
i && (e ? i.splice(i.indexOf(e) >>> 0, 1) : n.set(t, []));
}, emit: function(t, e) {
var i = n.get(t);
i && i.slice().map(function(n2) {
n2(e);
}), (i = n.get("*")) && i.slice().map(function(n2) {
n2(t, e);
});
} };
}
const useCacheStore = pinia.defineStore("cache", () => {
const cache = vue.reactive(Storage.getCache());
const isMainBLTHRunning = vue.ref(false);
function startAliveHeartBeat() {
cache.lastAliveHeartBeatTime = Date.now();
const timer = setInterval(() => cache.lastAliveHeartBeatTime = Date.now(), 5e3);
window.onunload = () => {
clearInterval(timer);
cache.lastAliveHeartBeatTime = 0;
};
}
function checkIfMainBLTHRunning() {
if (cache.lastAliveHeartBeatTime !== 0 && Date.now() - cache.lastAliveHeartBeatTime < 8e3) {
isMainBLTHRunning.value = true;
} else {
isMainBLTHRunning.value = false;
}
}
vue.watch(cache, (newCache) => Storage.setCache(newCache));
return {
cache,
isMainBLTHRunning,
startAliveHeartBeat,
checkIfMainBLTHRunning
};
});
const defaultModuleStatus = {
DailyTasks: {
MainSiteTasks: {
login: "",
watch: "",
coin: "",
share: ""
},
LiveTasks: {
sign: "",
appUser: "",
medalTasks: {
danmu: "",
like: "",
watch: ""
}
},
OtherTasks: {
groupSign: "",
silverToCoin: "",
coinToSilver: ""
}
}
};
const useModuleStore = pinia.defineStore("module", () => {
const moduleConfig = vue.reactive(Storage.getModuleConfig());
const emitter = mitt();
const moduleStatus = vue.reactive(defaultModuleStatus);
async function loadModules() {
const cacheStore = useCacheStore();
for (const [name, Module] of Object.entries(defaultModules).sort(
(a, b) => a[1].sequence - b[1].sequence
)) {
try {
if (Module.runMultiple || !cacheStore.isMainBLTHRunning) {
await new Module(name).run();
}
} catch (err) {
new Logger("loadModules").error("加载默认模块时发生致命错误,挂机助手停止运行:", err);
return;
}
}
for (const [name, Module] of Object.entries(otherModules)) {
if (Module.runMultiple || !cacheStore.isMainBLTHRunning) {
new Module(name).run();
}
}
}
vue.watch(
moduleConfig,
_.debounce((newModuleConfig) => Storage.setModuleConfig(newModuleConfig), 250, {
leading: true,
trailing: true
})
);
(function clearStatus() {
setTimeout(() => {
deepestIterate(moduleStatus, (_value, path) => {
_.set(moduleStatus, path, "");
});
clearStatus();
}, delayToNextMoment(0, 0).ms);
})();
return {
moduleConfig,
emitter,
moduleStatus,
loadModules
};
});
const _hoisted_1$3 = { class: "title" };
const _sfc_main$a = /* @__PURE__ */ vue.defineComponent({
__name: "PanelHeader",
setup(__props) {
const uiStore = useUIStore();
return (_ctx, _cache) => {
const _component_el_icon = vue.resolveComponent("el-icon");
const _component_el_text = vue.resolveComponent("el-text");
return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
vue.createElementVNode("div", {
class: "collapse-btn",
onClick: _cache[0] || (_cache[0] = ($event) => vue.unref(uiStore).changeCollapse())
}, [
vue.unref(uiStore).uiConfig.isCollapse ? (vue.openBlock(), vue.createBlock(_component_el_icon, { key: 0 }, {
default: vue.withCtx(() => [
vue.createVNode(vue.unref(ElementPlusIconsVue.Expand))
]),
_: 1
})) : (vue.openBlock(), vue.createBlock(_component_el_icon, { key: 1 }, {
default: vue.withCtx(() => [
vue.createVNode(vue.unref(ElementPlusIconsVue.Fold))
]),
_: 1
}))
]),
vue.createElementVNode("div", _hoisted_1$3, [
vue.createVNode(_component_el_text, {
tag: "b",
class: "header-big-text"
}, {
default: vue.withCtx(() => [
vue.createTextVNode("控制面板")
]),
_: 1
}),
vue.createVNode(_component_el_text, { class: "header-small-text" }, {
default: vue.withCtx(() => [
vue.createTextVNode(vue.toDisplayString(vue.unref(uiStore).activeMenuName), 1)
]),
_: 1
})
])
], 64);
};
}
});
const _export_sfc = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) {
target[key] = val;
}
return target;
};
const PanelHeader = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__scopeId", "data-v-dda95e10"]]);
const _sfc_main$9 = /* @__PURE__ */ vue.defineComponent({
__name: "PanelAside",
setup(__props) {
const uiStore = useUIStore();
const items = [
{
icon: "Tasks",
title: "每日任务",
index: "DailyTasks",
// 有子菜单,index 无所谓
subs: [
{
title: "主站任务",
index: "MainSiteTasks"
// index 是组件名
},
{
title: "直播任务",
index: "LiveTasks"
},
{
title: "其它任务",
index: "OtherTasks"
}
]
},
{
icon: "Monitor",
title: "体验优化",
index: "EnhanceExperience"
}
];
return (_ctx, _cache) => {
const _component_el_icon = vue.resolveComponent("el-icon");
const _component_el_menu_item = vue.resolveComponent("el-menu-item");
const _component_el_sub_menu = vue.resolveComponent("el-sub-menu");
const _component_el_menu = vue.resolveComponent("el-menu");
return vue.openBlock(), vue.createBlock(_component_el_menu, {
"default-active": vue.unref(uiStore).uiConfig.activeMenuIndex,
style: vue.normalizeStyle({ "min-height": vue.unref(uiStore).scrollBarHeight }),
collapse: vue.unref(uiStore).uiConfig.isCollapse,
"unique-opened": "",
onSelect: vue.unref(uiStore).setActiveMenuIndex,
id: "aside-el-menu"
}, {
default: vue.withCtx(() => [
(vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(items, (item) => {
return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
item.subs ? (vue.openBlock(), vue.createBlock(_component_el_sub_menu, {
index: item.index,
key: item.index
}, {
title: vue.withCtx(() => [
vue.createVNode(_component_el_icon, null, {
default: vue.withCtx(() => [
(vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(item.icon)))
]),
_: 2
}, 1024),
vue.createElementVNode("span", null, vue.toDisplayString(item.title), 1)
]),
default: vue.withCtx(() => [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(item.subs, (subItem) => {
return vue.openBlock(), vue.createBlock(_component_el_menu_item, {
key: subItem.index,
index: subItem.index
}, {
default: vue.withCtx(() => [
vue.createTextVNode(vue.toDisplayString(subItem.title), 1)
]),
_: 2
}, 1032, ["index"]);
}), 128))
]),
_: 2
}, 1032, ["index"])) : (vue.openBlock(), vue.createBlock(_component_el_menu_item, {
index: item.index,
key: item.index
}, {
title: vue.withCtx(() => [
vue.createTextVNode(vue.toDisplayString(item.title), 1)
]),
default: vue.withCtx(() => [
vue.createVNode(_component_el_icon, null, {
default: vue.withCtx(() => [
(vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(item.icon)))
]),
_: 2
}, 1024)
]),
_: 2
}, 1032, ["index"]))
], 64);
}), 64))
]),
_: 1
}, 8, ["default-active", "style", "collapse", "onSelect"]);
};
}
});
const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
__name: "MainSiteTasks",
setup(__props) {
const moduleStore = useModuleStore();
const config = moduleStore.moduleConfig.DailyTasks.MainSiteTasks;
const status = moduleStore.moduleStatus.DailyTasks.MainSiteTasks;
return (_ctx, _cache) => {
const _component_el_switch = vue.resolveComponent("el-switch");
const _component_Info = vue.resolveComponent("Info");
const _component_TaskStatus = vue.resolveComponent("TaskStatus");
const _component_el_space = vue.resolveComponent("el-space");
const _component_el_row = vue.resolveComponent("el-row");
const _component_el_option = vue.resolveComponent("el-option");
const _component_el_select = vue.resolveComponent("el-select");
const _component_el_text = vue.resolveComponent("el-text");
const _component_el_divider = vue.resolveComponent("el-divider");
const _component_el_link = vue.resolveComponent("el-link");
return vue.openBlock(), vue.createElementBlock("div", null, [
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).login.enabled,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.unref(config).login.enabled = $event),
"active-text": "每日登录(不可用)"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_Info, { id: "DailyTasks.MainSiteTasks.login" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).login
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).watch.enabled,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.unref(config).watch.enabled = $event),
"active-text": "每日观看视频"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_Info, { id: "DailyTasks.MainSiteTasks.watch" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).watch
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).coin.enabled,
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => vue.unref(config).coin.enabled = $event),
"active-text": "每日投币"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_el_select, {
modelValue: vue.unref(config).coin.num,
"onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => vue.unref(config).coin.num = $event),
placeholder: "Select",
style: { "width": "64px" }
}, {
default: vue.withCtx(() => [
(vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(5, (i) => {
return vue.createVNode(_component_el_option, {
key: i,
label: i,
value: i
}, null, 8, ["label", "value"]);
}), 64))
]),
_: 1
}, 8, ["modelValue"]),
vue.createVNode(_component_el_text, null, {
default: vue.withCtx(() => [
vue.createTextVNode("个")
]),
_: 1
}),
vue.createVNode(_component_Info, { id: "DailyTasks.MainSiteTasks.coin" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).coin
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).share.enabled,
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => vue.unref(config).share.enabled = $event),
"active-text": "每日分享视频"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_Info, { id: "DailyTasks.MainSiteTasks.share" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).share
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_divider),
vue.createElementVNode("div", null, [
vue.createVNode(_component_el_text, null, {
default: vue.withCtx(() => [
vue.createTextVNode(" 主站每日任务的完成情况可在")
]),
_: 1
}),
vue.createVNode(_component_el_link, {
class: "el-link-va-baseline",
rel: "noreferrer",
type: "primary",
href: "https://account.bilibili.com/account/home",
target: "_blank"
}, {
default: vue.withCtx(() => [
vue.createTextVNode("个人中心")
]),
_: 1
}),
vue.createVNode(_component_el_text, null, {
default: vue.withCtx(() => [
vue.createTextVNode("查看。数据更新可能有一定的延时。")
]),
_: 1
})
])
]);
};
}
});
const _withScopeId$1 = (n) => (vue.pushScopeId("data-v-eac67691"), n = n(), vue.popScopeId(), n);
const _hoisted_1$2 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1));
const _hoisted_2$1 = { class: "avatar-wrap" };
const _sfc_main$7 = /* @__PURE__ */ vue.defineComponent({
__name: "LiveTasks",
setup(__props) {
const moduleStore = useModuleStore();
const biliStore = useBiliStore();
const config = moduleStore.moduleConfig.DailyTasks.LiveTasks;
const status = moduleStore.moduleStatus.DailyTasks.LiveTasks;
const medalDanmuPanelVisible = vue.ref(false);
const danmuTableData = vue.computed(
() => config.medalTasks.danmu.list.map((danmu) => {
return { content: danmu };
})
);
const handleEditDanmu = (index, row) => {
ElementPlus.ElMessageBox.prompt("请输入新的弹幕内容", "修改弹幕", {
confirmButtonText: "确认",
cancelButtonText: "取消",
inputPattern: /^.{1,30}$/,
inputErrorMessage: "弹幕内容不得为空且长度不能超过30",
inputValue: row.content,
lockScroll: false
}).then(({ value }) => {
config.medalTasks.danmu.list[index] = value;
}).catch(() => {
});
};
const handleDeleteDanmu = (index) => {
if (config.medalTasks.danmu.list.length === 1) {
ElementPlus.ElMessage.warning({
message: "至少要有一条弹幕",
appendTo: ".el-dialog"
});
return;
}
config.medalTasks.danmu.list.splice(index, 1);
};
const handleAddDanmu = () => {
ElementPlus.ElMessageBox.prompt("请输入新增的弹幕内容", "新增弹幕", {
confirmButtonText: "确认",
cancelButtonText: "取消",
inputPattern: /^.{1,30}$/,
inputErrorMessage: "弹幕内容不得为空且长度不能超过30",
lockScroll: false
}).then(({ value }) => {
config.medalTasks.danmu.list.push(value);
}).catch(() => {
});
};
const medalInfoPanelVisible = vue.ref(false);
const medalInfoTableData = vue.computed(
() => {
var _a;
return (_a = biliStore.filteredFansMedals) == null ? void 0 : _a.map((medal) => ({
avatar: medal.anchor_info.avatar,
nick_name: medal.anchor_info.nick_name,
medal_name: medal.medal.medal_name,
medal_level: medal.medal.level,
roomid: medal.room_info.room_id
}));
}
);
const medalInfoLoading = vue.ref(false);
let firstClickEditList = true;
const handleEditList = () => {
medalInfoPanelVisible.value = !medalInfoPanelVisible.value;
if (firstClickEditList) {
if (!biliStore.fansMedals) {
medalInfoLoading.value = true;
const unwatch = vue.watch(medalInfoTableData, (newData) => {
if (newData) {
unwatch();
firstClickEditList = false;
initSelection(medalInfoTableData.value);
medalInfoLoading.value = false;
}
});
moduleStore.emitter.emit("BiliInfo", {
target: "getFansMetals"
});
} else {
initSelection(medalInfoTableData.value);
}
}
};
const medalInfoTableRef = vue.ref();
let lockConfig = false;
const initSelection = (rows) => {
lockConfig = true;
if (rows) {
const unwatch = vue.watch(
() => medalInfoTableRef.value,
(newValue) => {
setTimeout(() => unwatch(), 0);
if (newValue) {
config.medalTasks.roomidList.forEach(
(roomid) => newValue.toggleRowSelection(
rows.find((row) => row.roomid === roomid),
true
)
);
}
},
{ immediate: true }
);
}
lockConfig = false;
};
function handleSelectionChange(selectedRows) {
if (!lockConfig) {
config.medalTasks.roomidList = selectedRows.map((row) => row.roomid);
}
}
return (_ctx, _cache) => {
const _component_el_switch = vue.resolveComponent("el-switch");
const _component_Info = vue.resolveComponent("Info");
const _component_TaskStatus = vue.resolveComponent("TaskStatus");
const _component_el_space = vue.resolveComponent("el-space");
const _component_el_row = vue.resolveComponent("el-row");
const _component_el_divider = vue.resolveComponent("el-divider");
const _component_el_button = vue.resolveComponent("el-button");
const _component_el_option = vue.resolveComponent("el-option");
const _component_el_select = vue.resolveComponent("el-select");
const _component_el_text = vue.resolveComponent("el-text");
const _component_el_link = vue.resolveComponent("el-link");
const _component_el_table_column = vue.resolveComponent("el-table-column");
const _component_el_dialog = vue.resolveComponent("el-dialog");
const _component_el_image = vue.resolveComponent("el-image");
const _directive_loading = vue.resolveDirective("loading");
return vue.openBlock(), vue.createElementBlock("div", null, [
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).sign.enabled,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.unref(config).sign.enabled = $event),
"active-text": "直播签到"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_Info, { id: "DailyTasks.LiveTasks.sign" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).sign
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).appUser.enabled,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.unref(config).appUser.enabled = $event),
disabled: "",
"active-text": "APP用户任务"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_Info, { id: "DailyTasks.LiveTasks.appUser" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).appUser
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_divider),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).medalTasks.like.enabled,
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => vue.unref(config).medalTasks.like.enabled = $event),
"active-text": "给主播点赞"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_Info, { id: "DailyTasks.LiveTasks.medalTasks.like" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).medalTasks.like
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).medalTasks.danmu.enabled,
"onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => vue.unref(config).medalTasks.danmu.enabled = $event),
"active-text": "发送弹幕"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_el_button, {
type: "primary",
size: "small",
icon: vue.unref(ElementPlusIconsVue.Edit),
onClick: _cache[4] || (_cache[4] = ($event) => medalDanmuPanelVisible.value = !medalDanmuPanelVisible.value)
}, {
default: vue.withCtx(() => [
vue.createTextVNode("编辑弹幕")
]),
_: 1
}, 8, ["icon"]),
vue.createVNode(_component_Info, { id: "DailyTasks.LiveTasks.medalTasks.danmu" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).medalTasks.danmu
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).medalTasks.watch.enabled,
"onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => vue.unref(config).medalTasks.watch.enabled = $event),
"active-text": "观看直播"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_el_select, {
modelValue: vue.unref(config).medalTasks.watch.time,
"onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => vue.unref(config).medalTasks.watch.time = $event),
placeholder: "Select",
style: { "width": "64px" }
}, {
default: vue.withCtx(() => [
(vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(24, (i) => {
return vue.createVNode(_component_el_option, {
key: i,
label: i * 5,
value: i * 5
}, null, 8, ["label", "value"]);
}), 64))
]),
_: 1
}, 8, ["modelValue"]),
vue.createVNode(_component_el_text, null, {
default: vue.withCtx(() => [
vue.createTextVNode("分钟")
]),
_: 1
}),
vue.createVNode(_component_Info, { id: "DailyTasks.LiveTasks.medalTasks.watch" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).medalTasks.watch
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).medalTasks.isWhiteList,
"onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => vue.unref(config).medalTasks.isWhiteList = $event),
"active-text": "白名单",
"inactive-text": "黑名单"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_el_button, {
type: "primary",
size: "small",
icon: vue.unref(ElementPlusIconsVue.Edit),
onClick: handleEditList
}, {
default: vue.withCtx(() => [
vue.createTextVNode("编辑名单")
]),
_: 1
}, 8, ["icon"]),
vue.createVNode(_component_Info, { id: "DailyTasks.LiveTasks.medalTasks.list" })
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_divider),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_text, null, {
default: vue.withCtx(() => [
vue.createTextVNode("直播任务相关信息可在")
]),
_: 1
}),
vue.createVNode(_component_el_link, {
class: "el-link-va-baseline",
rel: "noreferrer",
type: "primary",
href: "https://link.bilibili.com/p/help/index#/audience-fans-medal",
target: "_blank"
}, {
default: vue.withCtx(() => [
vue.createTextVNode("帮助中心")
]),
_: 1
}),
vue.createVNode(_component_el_text, null, {
default: vue.withCtx(() => [
vue.createTextVNode("查看。")
]),
_: 1
})
]),
_: 1
}),
_hoisted_1$2,
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_text, { tag: "b" }, {
default: vue.withCtx(() => [
vue.createTextVNode("注意:")
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_text, null, {
default: vue.withCtx(() => [
vue.createTextVNode(" 由于每天能通过完成任务获得亲密度的粉丝勋章数量有限,目前脚本仅为最多100个等级小于20的粉丝勋章完成给主播点赞,发送弹幕,观看直播任务。")
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_dialog, {
modelValue: medalDanmuPanelVisible.value,
"onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => medalDanmuPanelVisible.value = $event),
title: "编辑弹幕内容",
"lock-scroll": false,
width: "40%"
}, {
footer: vue.withCtx(() => [
vue.createVNode(_component_el_button, {
type: "primary",
onClick: handleAddDanmu
}, {
default: vue.withCtx(() => [
vue.createTextVNode("新增弹幕")
]),
_: 1
})
]),
default: vue.withCtx(() => [
vue.createVNode(vue.unref(ElementPlus.ElTable), {
data: danmuTableData.value,
"max-height": "500"
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_table_column, {
type: "index",
width: "50"
}),
vue.createVNode(_component_el_table_column, {
prop: "content",
label: "弹幕内容"
}),
vue.createVNode(_component_el_table_column, {
label: "操作",
width: "220",
align: "center"
}, {
default: vue.withCtx((scope) => [
vue.createVNode(_component_el_button, {
text: "",
icon: vue.unref(ElementPlusIconsVue.Edit),
onClick: ($event) => handleEditDanmu(scope.$index, scope.row)
}, {
default: vue.withCtx(() => [
vue.createTextVNode(" 修改 ")
]),
_: 2
}, 1032, ["icon", "onClick"]),
vue.createVNode(_component_el_button, {
text: "",
icon: vue.unref(ElementPlusIconsVue.Delete),
type: "danger",
onClick: ($event) => handleDeleteDanmu(scope.$index)
}, {
default: vue.withCtx(() => [
vue.createTextVNode(" 删除 ")
]),
_: 2
}, 1032, ["icon", "onClick"])
]),
_: 1
})
]),
_: 1
}, 8, ["data"])
]),
_: 1
}, 8, ["modelValue"]),
vue.createVNode(_component_el_dialog, {
modelValue: medalInfoPanelVisible.value,
"onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => medalInfoPanelVisible.value = $event),
title: "编辑粉丝勋章名单",
"lock-scroll": false,
width: "40%"
}, {
default: vue.withCtx(() => [
vue.withDirectives((vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElTable), {
ref_key: "medalInfoTableRef",
ref: medalInfoTableRef,
data: medalInfoTableData.value,
"max-height": "500",
"empty-text": "没有粉丝勋章",
onSelectionChange: handleSelectionChange
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_table_column, {
type: "selection",
align: "center",
width: "55"
}),
vue.createVNode(_component_el_table_column, {
prop: "avatar",
label: "头像"
}, {
default: vue.withCtx((scope) => [
vue.createElementVNode("div", _hoisted_2$1, [
vue.createVNode(_component_el_image, {
src: scope.row.avatar,
loading: "lazy",
referrerpolicy: "origin",
class: "avatar"
}, {
error: vue.withCtx(() => [
vue.createVNode(_component_el_image, {
src: "//i0.hdslb.com/bfs/face/member/noface.jpg",
referrerpolicy: "origin",
class: "avatar"
})
]),
_: 2
}, 1032, ["src"])
])
]),
_: 1
}),
vue.createVNode(_component_el_table_column, {
prop: "nick_name",
label: "昵称"
}),
vue.createVNode(_component_el_table_column, {
prop: "medal_name",
label: "粉丝勋章"
}),
vue.createVNode(_component_el_table_column, {
prop: "medal_level",
label: "等级",
sortable: ""
}),
vue.createVNode(_component_el_table_column, {
prop: "roomid",
label: "房间号"
}, {
default: vue.withCtx((scope) => [
vue.createVNode(_component_el_link, {
href: "https://live.bilibili.com/" + scope.row.roomid + "?visit_id=",
rel: "noreferrer",
type: "primary",
target: "_blank"
}, {
default: vue.withCtx(() => [
vue.createTextVNode(vue.toDisplayString(scope.row.roomid), 1)
]),
_: 2
}, 1032, ["href"])
]),
_: 1
})
]),
_: 1
}, 8, ["data"])), [
[_directive_loading, medalInfoLoading.value]
])
]),
_: 1
}, 8, ["modelValue"])
]);
};
}
});
const LiveTasks = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-eac67691"]]);
const _sfc_main$6 = /* @__PURE__ */ vue.defineComponent({
__name: "OtherTasks",
setup(__props) {
const moduleStore = useModuleStore();
const config = moduleStore.moduleConfig.DailyTasks.OtherTasks;
const status = moduleStore.moduleStatus.DailyTasks.OtherTasks;
return (_ctx, _cache) => {
const _component_el_switch = vue.resolveComponent("el-switch");
const _component_Info = vue.resolveComponent("Info");
const _component_TaskStatus = vue.resolveComponent("TaskStatus");
const _component_el_space = vue.resolveComponent("el-space");
const _component_el_row = vue.resolveComponent("el-row");
const _component_el_text = vue.resolveComponent("el-text");
const _component_el_option = vue.resolveComponent("el-option");
const _component_el_select = vue.resolveComponent("el-select");
const _component_el_divider = vue.resolveComponent("el-divider");
return vue.openBlock(), vue.createElementBlock("div", null, [
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).groupSign.enabled,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.unref(config).groupSign.enabled = $event),
"active-text": "应援团签到"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_Info, { id: "DailyTasks.OtherTasks.groupSign" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).groupSign
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).silverToCoin.enabled,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.unref(config).silverToCoin.enabled = $event),
"active-text": "银瓜子换硬币"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_Info, { id: "DailyTasks.OtherTasks.silverToCoin" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).silverToCoin
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).coinToSilver.enabled,
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => vue.unref(config).coinToSilver.enabled = $event),
"active-text": "硬币换银瓜子"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_el_text, null, {
default: vue.withCtx(() => [
vue.createTextVNode("花费硬币")
]),
_: 1
}),
vue.createVNode(_component_el_select, {
modelValue: vue.unref(config).coinToSilver.num,
"onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => vue.unref(config).coinToSilver.num = $event),
placeholder: "Select",
style: { "width": "64px" }
}, {
default: vue.withCtx(() => [
(vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(50, (i) => {
return vue.createVNode(_component_el_option, {
key: i,
label: i,
value: i
}, null, 8, ["label", "value"]);
}), 64))
]),
_: 1
}, 8, ["modelValue"]),
vue.createVNode(_component_el_text, null, {
default: vue.withCtx(() => [
vue.createTextVNode("个")
]),
_: 1
}),
vue.createVNode(_component_Info, { id: "DailyTasks.OtherTasks.coinToSilver" }),
vue.createVNode(_component_TaskStatus, {
status: vue.unref(status).coinToSilver
}, null, 8, ["status"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_divider)
]);
};
}
});
const _sfc_main$5 = /* @__PURE__ */ vue.defineComponent({
__name: "EnhanceExperience",
setup(__props) {
const moduleStore = useModuleStore();
const config = moduleStore.moduleConfig.EnhanceExperience;
const qualityDescList = ["原画", "蓝光PRO", "蓝光", "超清PRO", "超清", "高清"];
return (_ctx, _cache) => {
const _component_el_switch = vue.resolveComponent("el-switch");
const _component_el_option = vue.resolveComponent("el-option");
const _component_el_select = vue.resolveComponent("el-select");
const _component_Info = vue.resolveComponent("Info");
const _component_el_space = vue.resolveComponent("el-space");
const _component_el_row = vue.resolveComponent("el-row");
const _component_el_divider = vue.resolveComponent("el-divider");
return vue.openBlock(), vue.createElementBlock("div", null, [
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).switchLiveStreamQuality.enabled,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.unref(config).switchLiveStreamQuality.enabled = $event),
"active-text": "自动切换画质"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_el_select, {
modelValue: vue.unref(config).switchLiveStreamQuality.qualityDesc,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.unref(config).switchLiveStreamQuality.qualityDesc = $event),
placeholder: "Select",
style: { "width": "110px" }
}, {
default: vue.withCtx(() => [
(vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(qualityDescList, (i) => {
return vue.createVNode(_component_el_option, {
key: i,
label: i,
value: i
}, null, 8, ["label", "value"]);
}), 64))
]),
_: 1
}, 8, ["modelValue"]),
vue.createVNode(_component_Info, { id: "EnhanceExperience.switchLiveStreamQuality" })
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_row, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_space, { wrap: "" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: vue.unref(config).banp2p.enabled,
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => vue.unref(config).banp2p.enabled = $event),
"active-text": "禁用P2P"
}, null, 8, ["modelValue"]),
vue.createVNode(_component_Info, { id: "EnhanceExperience.banp2p" })
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_divider)
]);
};
}
});
const __default__ = {
components: {
MainSiteTasks: _sfc_main$8,
LiveTasks,
OtherTasks: _sfc_main$6,
EnhanceExperience: _sfc_main$5
}
};
const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
...__default__,
__name: "PanelMain",
setup(__props) {
const uiStore = useUIStore();
return (_ctx, _cache) => {
return vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(vue.unref(uiStore).uiConfig.activeMenuIndex));
};
}
});
const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
__name: "App",
setup(__props) {
const uiStore = useUIStore();
const moduleStore = useModuleStore();
const logger = new Logger("App.vue");
let isShowPanel = uiStore.uiConfig.isShowPanel;
uiStore.uiConfig.isShowPanel = false;
let livePlayer;
let button;
function setPanelSize() {
const rect = livePlayer.getBoundingClientRect();
uiStore.baseStyleValue.top = rect.top + window.scrollY;
uiStore.baseStyleValue.left = rect.left + window.scrollX;
uiStore.baseStyleValue.height = rect.height;
uiStore.baseStyleValue.width = rect.width * 0.4;
}
function buttonOnClick() {
uiStore.changeShowPanel();
button.innerText = uiStore.isShowPanelButtonText;
}
const throttleButtoOnClick = _.throttle(buttonOnClick, 300);
moduleStore.loadModules();
window.onload = () => {
livePlayer = dq("#live-player-ctnr");
if (livePlayer) {
setPanelSize();
pollingQuery(document, ".left-ctnr.left-header-area", 300, 3e3).then((playerHeaderLeft) => {
button = dce("button");
button.setAttribute("class", "blth_btn");
button.onclick = throttleButtoOnClick;
button.innerText = uiStore.isShowPanelButtonText;
playerHeaderLeft.append(button);
if (!isSelfTopFrame()) {
hotkeys(
"alt+b",
{
element: topFrameDocuemnt()
},
throttleButtoOnClick
);
}
hotkeys("alt+b", throttleButtoOnClick);
}).catch(() => logger.error("Can't find playerHeaderLeft in time"));
window.onresize = setPanelSize;
const observer = new MutationObserver(() => setPanelSize());
observer.observe(document.documentElement, { attributes: true });
observer.observe(document.body, { attributes: true });
if (isShowPanel) {
uiStore.uiConfig.isShowPanel = true;
}
} else {
logger.error("livePlayer not found");
}
};
return (_ctx, _cache) => {
const _component_el_header = vue.resolveComponent("el-header");
const _component_el_aside = vue.resolveComponent("el-aside");
const _component_el_main = vue.resolveComponent("el-main");
const _component_el_container = vue.resolveComponent("el-container");
const _component_el_scrollbar = vue.resolveComponent("el-scrollbar");
const _component_el_collapse_transition = vue.resolveComponent("el-collapse-transition");
return vue.openBlock(), vue.createBlock(_component_el_collapse_transition, null, {
default: vue.withCtx(() => [
vue.withDirectives(vue.createElementVNode("div", {
style: vue.normalizeStyle(vue.unref(uiStore).baseStyle),
class: "base"
}, [
vue.createVNode(_component_el_container, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_header, { class: "header" }, {
default: vue.withCtx(() => [
vue.createVNode(PanelHeader)
]),
_: 1
}),
vue.createVNode(_component_el_scrollbar, {
height: vue.unref(uiStore).scrollBarHeight
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_container, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_aside, { class: "aside" }, {
default: vue.withCtx(() => [
vue.createVNode(_sfc_main$9)
]),
_: 1
}),
vue.createVNode(_component_el_main, { class: "main" }, {
default: vue.withCtx(() => [
(vue.openBlock(), vue.createBlock(vue.KeepAlive, null, [
vue.createVNode(vue.Transition, {
name: "fade",
mode: "out-in"
}, {
default: vue.withCtx(() => [
vue.createVNode(_sfc_main$4)
]),
_: 1
})
], 1024))
]),
_: 1
})
]),
_: 1
})
]),
_: 1
}, 8, ["height"])
]),
_: 1
})
], 4), [
[vue.vShow, vue.unref(uiStore).uiConfig.isShowPanel]
])
]),
_: 1
});
};
}
});
const App = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-4aed17ff"]]);
const cssLoader = (e) => {
const t = GM_getResourceText(e), o = document.createElement("style");
return o.innerText = t, document.head.append(o), t;
};
cssLoader("element-plus/dist/index.css");
const _sfc_main$2 = {};
const _hoisted_1$1 = {
xmlns: "http://www.w3.org/2000/svg",
width: "128",
height: "128",
class: "icon",
viewBox: "0 0 1024 1024"
};
const _hoisted_2 = /* @__PURE__ */ vue.createElementVNode("path", { d: "M831.825 63.94H191.94c-70.692 0-128 57.308-128 128v639.885c0 70.692 57.308 128 128 128h639.885c70.692 0 128-57.308 128-128V191.94c0-70.692-57.308-128-128-128zM895.885 832a63.835 63.835 0 0 1-63.973 63.886H192.088c-17.112 0-33.27-6.575-45.372-18.676S127.88 849.112 127.88 832V192a64.236 64.236 0 0 1 64.208-64.12h639.824A64.038 64.038 0 0 1 895.885 192v640z" }, null, -1);
const _hoisted_3 = /* @__PURE__ */ vue.createElementVNode("path", { d: "M791.998 351.852H536a31.97 31.97 0 0 0 0 63.94h256a31.97 31.97 0 0 0 0-63.94zm0 256.121H536a31.97 31.97 0 0 0 0 63.94h256a31.97 31.97 0 0 0 0-63.94zm-447.996-79.975c-61.856 0-111.986 50.144-111.986 111.985S282.16 751.97 344.002 751.97s111.985-50.144 111.985-111.986-50.13-111.985-111.985-111.985zm33.982 145.982a48.045 48.045 0 1 1 14.088-33.982 47.746 47.746 0 0 1-14.088 33.986zm39.412-376.586L311.999 402.787l-41.391-41.395a31.97 31.97 0 1 0-45.213 45.213l63.997 64.002a31.97 31.97 0 0 0 45.214 0l128-128a31.97 31.97 0 0 0-45.21-45.213z" }, null, -1);
const _hoisted_4 = [
_hoisted_2,
_hoisted_3
];
function _sfc_render(_ctx, _cache) {
return vue.openBlock(), vue.createElementBlock("svg", _hoisted_1$1, _hoisted_4);
}
const TasksIcon = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render]]);
const help_info = {
DailyTasks: {
MainSiteTasks: {
login: {
title: "每日登录(不可用)",
message: "完成主站的每日登录(不可用)任务。"
},
watch: {
title: "每日观看视频",
message: vue.h("p", [
vue.h("div", "完成主站的每日观看视频任务。"),
vue.h("div", "从动态中选取视频观看,会产生观看历史记录。")
])
},
coin: {
title: "每日投币",
message: vue.h("p", [
vue.h("div", "完成主站的每日投币任务。"),
vue.h("div", "从动态中选取视频投币,会根据你今天已经投过的币的数量计算还要投几个币。")
])
},
share: {
title: "每日分享视频",
message: vue.h("p", [
vue.h("div", "完成主站的每日分享视频任务。"),
vue.h("div", "不会真的分享到某处。")
])
}
},
LiveTasks: {
sign: {
title: "直播签到",
message: vue.h("p", [
vue.h("div", "完成直播签到任务。"),
vue.h("div", "完成后会移除当前直播间右上角签到窗口中的签到按钮。")
])
},
appUser: {
title: "APP用户任务",
message: vue.h("p", [
vue.h("div", "完成APP用户任务并领取奖励。"),
vue.h("div", [
vue.h(
"strong",
"由于曾经的APP用户任务下架已久,目前的新任务(观看新主播直播并发弹幕)又没有对全部用户开放,故改功能暂时被禁用。"
),
vue.h("div", [
vue.h(
"span",
"在APP中观看直播时右下角可能会有个电池图标,点击即可查看APP用户任务内容。并非所有账号都可以参加该任务。 如果开启了发送弹幕功能,该功能会在发送弹幕功能运行完毕后再运行。如果之前发送的弹幕数量不够,会先在直播间"
),
vue.h(
"a",
{
class: "el-link el-link--primary is-underline el-link-va-baseline",
href: "https://live.bilibili.com/22474988",
rel: "noreferrer",
target: "_blank"
},
"22474988"
),
vue.h("span", "发送弹幕再领取奖励。")
])
])
])
},
medalTasks: {
list: {
title: "黑白名单",
message: vue.h("p", [
vue.h("div", "为更精细地控制为哪些粉丝勋章执行任务,你可以使用黑名单或白名单模式。"),
vue.h("div", [
vue.h("li", [
vue.h("span", "黑名单:仅为"),
vue.h("strong", "不在"),
vue.h("span", "名单中的粉丝勋章执行任务。")
]),
vue.h("li", [
vue.h("span", "白名单:仅为"),
vue.h("strong", "在"),
vue.h("span", "名单中的粉丝勋章执行任务。")
])
]),
vue.h("div", "点击编辑名单按钮,然后使用第一列的多选框即可编辑名单中的粉丝勋章。")
])
},
like: {
title: "给主播点赞",
message: vue.h("p", [
vue.h("div", "在你的每个粉丝勋章对应的直播间给主播点赞。"),
vue.h("div", "部分直播间无法完成该任务,原因未知。")
])
},
danmu: {
title: "发送弹幕",
message: vue.h("p", [
vue.h("div", "在你的每个粉丝勋章对应的直播间发送一条弹幕。"),
vue.h("div", [
vue.h("span", "点击编辑弹幕按钮编辑发送的弹幕,脚本会从中按顺序循环抽取弹幕发送。"),
vue.h("span", "部分直播间无法完成该任务,可能的原因有:,"),
vue.h("li", "你被禁言了"),
vue.h("li", "发言有粉丝勋章等级要求"),
vue.h("li", [
vue.h("span", "特殊直播间(比如"),
vue.h(
"a",
{ href: "https://live.bilibili.com/54", rel: "noreferrer", target: "_blank" },
"54"
),
vue.h("span", ")")
])
])
])
},
watch: {
title: "观看直播",
message: vue.h("p", [
vue.h("div", "完成观看持有粉丝勋章对应主播直播的任务。"),
vue.h(
"div",
"部分直播间因为没有设置直播分区导致任务无法完成。主播当前是否开播不会影响该任务的完成。"
)
])
}
}
},
OtherTasks: {
groupSign: {
title: "应援团签到",
message: "完成应援团签到任务。"
},
silverToCoin: {
title: "银瓜子换硬币",
message: vue.h("p", [
vue.h("div", "把银瓜子兑换为硬币。"),
vue.h("div", "具体兑换规则请点击直播间页面的“立即充值→银瓜子商店”查看。")
])
},
coinToSilver: {
title: "硬币换银瓜子",
message: vue.h("p", [
vue.h("div", "把硬币兑换为银瓜子。"),
vue.h("div", "具体兑换规则请点击直播间页面的“立即充值→银瓜子商店”查看。")
])
}
}
},
EnhanceExperience: {
switchLiveStreamQuality: {
title: "自动切换画质",
message: vue.h("p", [
vue.h("div", "打开直播间后自动把播放器切换到指定画质。"),
vue.h("div", "如果指定画质不存在,则还是使用B站的默认画质。")
])
},
banp2p: {
title: "禁用P2P",
message: vue.h("p", [
vue.h("div", "禁用直播流的P2P上传/下载"),
vue.h(
"div",
"B站使用WebRTC技术把许多浏览器点对点(P2P)地连接起来,实现视频流和音频流的传输。这样做是为了减轻B站服务器的压力,但是会占用你一定的上行带宽(大约几百kb每秒)。如果你不想被占用上行带宽,可以开启该功能。若开启后发现观看直播时有明显卡顿,请关闭。"
)
])
}
}
};
const _withScopeId = (n) => (vue.pushScopeId("data-v-c1d8df5e"), n = n(), vue.popScopeId(), n);
const _hoisted_1 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("svg", {
xmlns: "http://www.w3.org/2000/svg",
width: "128",
height: "128",
class: "icon",
viewBox: "0 0 1024 1024"
}, [
/* @__PURE__ */ vue.createElementVNode("path", {
fill: "#276BC0",
d: "M512.67 959.47c-246.343 0-446.76-200.632-446.76-447.24S266.326 64.98 512.67 64.98s446.76 200.642 446.76 447.25-200.416 447.24-446.76 447.24zm0-829.04c-210.291 0-381.38 171.283-381.38 381.8s171.089 381.79 381.38 381.79 381.381-171.273 381.381-381.79-171.09-381.8-381.38-381.8z"
}),
/* @__PURE__ */ vue.createElementVNode("path", {
fill: "#276BC0",
d: "M447.29 317.172a63.891 63.959 0 1 0 130.76 0 63.891 63.959 0 1 0-130.76 0Zm64.907 503.047c-30.093 0-54.235-24.416-54.235-54.541V482.062c0-30.126 24.142-54.541 54.235-54.541 30.094 0 54.236 24.416 54.236 54.541v283.616c0 30.125-24.142 54.54-54.236 54.54z"
})
], -1));
const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
__name: "InfoIcon",
props: {
id: {}
},
setup(__props) {
const props = __props;
const open = () => {
const { title, message } = _.get(help_info, props.id, {
title: "无",
message: "无"
});
ElementPlus.ElMessageBox({
title,
message,
lockScroll: false,
autofocus: true,
confirmButtonText: "OK"
});
};
return (_ctx, _cache) => {
const _component_el_icon = vue.resolveComponent("el-icon");
return vue.openBlock(), vue.createBlock(_component_el_icon, {
class: "info-icon",
onClick: open
}, {
default: vue.withCtx(() => [
_hoisted_1
]),
_: 1
});
};
}
});
const InfoIcon = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-c1d8df5e"]]);
const _sfc_main = /* @__PURE__ */ vue.defineComponent({
__name: "TaskStatusIcon",
props: {
status: {}
},
setup(__props) {
return (_ctx, _cache) => {
const _component_Loading = vue.resolveComponent("Loading");
const _component_el_icon = vue.resolveComponent("el-icon");
const _component_Select = vue.resolveComponent("Select");
const _component_CloseBold = vue.resolveComponent("CloseBold");
return _ctx.status === "running" ? (vue.openBlock(), vue.createBlock(_component_el_icon, {
key: 0,
class: "status-icon is-loading"
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_Loading)
]),
_: 1
})) : _ctx.status === "done" ? (vue.openBlock(), vue.createBlock(_component_el_icon, {
key: 1,
class: "status-icon",
style: { "color": "#1ab059" }
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_Select)
]),
_: 1
})) : _ctx.status === "error" ? (vue.openBlock(), vue.createBlock(_component_el_icon, {
key: 2,
class: "status-icon",
style: { "color": "#ff6464" }
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_CloseBold)
]),
_: 1
})) : vue.createCommentVNode("", true);
};
}
});
const TaskStatusIcon = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-2f9d6050"]]);
const MyIconsVue = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
Info: InfoIcon,
TaskStatus: TaskStatusIcon,
Tasks: TasksIcon
}, Symbol.toStringTag, { value: "Module" }));
(function() {
if (isTargetFrame()) {
const app = vue.createApp(App);
const pinia$1 = pinia.createPinia();
app.use(ElementPlus);
app.use(pinia$1);
const logger = new Logger("main.ts");
const cacheStore = useCacheStore();
cacheStore.checkIfMainBLTHRunning();
if (!cacheStore.isMainBLTHRunning) {
logger.log("当前脚本是Main BLTH,开始存活心跳");
cacheStore.startAliveHeartBeat();
} else {
logger.log("其它页面上存在正在运行的Main BLTH");
}
for (const [key, component] of Object.entries(ElementPlusIconsVue__namespace)) {
app.component(key, component);
}
for (const [key, component] of Object.entries(MyIconsVue)) {
app.component(key, component);
}
app.mount(
(() => {
try {
const app2 = dce("div");
app2.id = "BLTH";
document.body.append(app2);
return app2;
} catch (e) {
logger.error("挂载Vue app时发送错误", e);
return "Error";
}
})()
);
}
})();
})(Vue, Pinia, _, luxon, CryptoJS, ElementPlusIconsVue, ElementPlus, hotkeys);