// ==UserScript==
// @name 【移动端】bilibili优化
// @namespace https://github.com/WhiteSevs/TamperMonkeyScript
// @version 2025.8.21
// @author WhiteSevs
// @description 阻止跳转App、App端推荐视频流、解锁视频画质(番剧解锁需配合其它插件)、美化显示、去广告等
// @license GPL-3.0-only
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAACjBJREFUeF7tnX+MHGUZx7/PbFsr3O3eNWBTaQu1RhNQEv7CBKNtQsBQTRDSJiYabNBaerP2bmcL8pcHiZH2du6u7Fx/SCmESGLQSP+QQk0aMAElMTGmsURQCQSLqcG7222ttb2dR8a700u7e/u+8850d2ae/Xee55nn+T6ffWd29p33Jcgn0wpQpquX4iEAZBwCAUAAyLgCGS9fRgABIOMKZLx8GQEEgIwrkPHyZQQQADKuQMbLlxFAAMi4Ahkvv+MjwJQ9MpyDtQ6gtT7xn5n9U/3eruE09qUba+0oALXi6DEw39Gk2Uct4l291fIbaQDhTLFyo880AuCuS+sh4GTecz7TqTo7BkDddv/AwE2tCg+EIeItSYcgaD4zPbdYrSD6ZaFaurMTEHQEgGAotGB9v13BSYdAqflzIvjwH+nEpa8jAEwX3SeI8a12AATHkwqBTvPn6nwm7zn3qWgSpU1HAKjboy8zeINqIUmDQLf5swDQK3mvtFFVk6jsOgKAzggwX2hSIAjT/MyNAKr3AM3umLv5xjBs84M6M3UPEBRcs90Xmv0saje0detIYNJ8AEcLnrOpXe1xHO/IJSAoxESwboMgybV0DIC0QJDk5s/de8QxsKjHTLKASc59wc21erPiskyikEnMuVn/OnoJWJhQkgRNUq7tvrRdA0BS7gnS1PyuuAe4lNBuFribc2v3TW91vKtGgPkku1HobswpbNMX+nUlAN12OUhr87vyEtBtN4Zpbv4VAWDadjdbwGYG1oOxAoQVAPJRDF8pjFEHYxKESYDfAvBMwSu/GGedsVwCzu4cv7nhN7YRcA8zVsVZQNpjM/AeAUdyudyhnr2DJ6KuN1IApgYq1xORbQE2A8ujTjbL8Qg47wMeM3v9E+V3o9IiMgBqtvt1ABUAK6NKTuI0VeA0QI8WvNK+KPSJBIBaccQGW9UoEpIYagoQ4XC+6tyvZt3ayhiAsP/rmyYu/v+dR3a8UHVuN9HCCICa7R4D0Gxev0lO4qungFfwnKKey/+tQwNQH3APMOE7YU8sftEpYDKdLBQAZ+zR7T54f3QlSCRTBSzQA71e6YBuHG0A/r5juGe51fv6om+66GYh9sYKBNPkzvtnPvexfcNndYJpAzBtV75HoB/qnGShbfBgwwL9Jax/mv2YeS0InwhbI4Mf7vPKj+n4awEwue2xgrVs6UkCrtM5CYDXCNiTW2L99urxob9p+mbKfGpwrC/n+zfCpx/ovDwTiMTAKTQufLZv/8NTqqJpAVArjmwCW79QDT6bFD/U55X36PiI7awCZ4rumM8Y1NGDgS19nvNTVR8tAOq2u5uBB1WD+8Tl/mrZVbUXu8sVCP5MI+A5VW0I9KO8V1L+daYFQG2g8kcQfVolGSYc6qs631axFZvFFajZbvCU1VbU6e2C56xXtFVfLJqHn1pe/2DyX6qBeam1vm9s6G1Ve7FrrcC5He6aCxbeIKBHRaf8NSs+SsNbz6vYKo8A/xwcWzUz47+vErSTrzop5pc4s7rt/oqBL6gkvmSJ9XHVm21lAOaWOTmpkgATtvdVnYMqtmKjpoDODaFFfJPqyirKANTtsdsY/qsq6frwN/Z7u15RsRUbNQWm7MrdFuh5FWuC9fm8N/Samq2KFYApe2SDBetlFXMBQEUlPZu49FceAeJKQE+G7FrHpb8AkBCmBICENCquNAWAuJRNSFwBICGNiitNASAuZRMSN9MAnCs+vnrG//caEE31XtU4RXseOtONfftH8fH8MlxY7fvce7GR++s1B0qnosozkwAEj58bDT7IzF9ZKKTJHLioGnJpnLrtlhkIFoRe8KHfUM7amt87+KbpeTMHwFTRvcVi/K6VcAw82ec5SsvNmorfzn/adg8R0HKOvj9jres/MPROuziLHc8UAO9vG77q6mU9JwBq87cmf6nglYOp6R371OzKnQC9tGgCjF/nr12zkYa3XAibaKYAmNrhftOy8FQ7sYjxdH7C2drOLs7jdXv0IIO3tTsHgx/o88ras3bn42YKAOW1hBnvFCacde3Ej/N4zXb/BOCTCuf4ccFzvqFg19QkUwDorCZe8Bzlx9lhxV/Mr2a7rBLXdDVwAaCFygLA5cLo/Bur/O2Ji8BmfZUR4HJV4tJfAFAZvxexkUtAE3F0hiAZAdQIlBFA7gFimZEllwC1L2BLK7kEyCVAfgZeyoDcA1z+rZDnABpDrfwMlJ+ByvsKyoOgFD4Imrbd3aT0FjL9vuCVbtEYXCI3rdmjrwN8a/vAvK/glQfa2zW3yNTPwGnbvZeAn7UTyyKM91adoXZ2cR6vD4xWmNhpew72v1aY2PWTtnYtDDIFQKBB3XafZ+DuxQS7OEOro5x2FaY5Su9MMp4tTDjBSqqhP5kDYO5t5GBOQKtt1Yc/vP4/ElrRCB3b7IR6LJfL3dezd/C0ySkzB8C8WHV79H6Av8zABoDeJMarZPmHVd9+NRFdx/eD7aPXfWQpl32mDQCvBXCMQMfzXulJnTitbDMLQBTipSGGAJCGLhrUIAAYiJcGVwEgDV00qEEAMBAvDa4CQBq6aFCDAGAgXhpcBYA0dNGgBgHAQLw0uAoAaeiiQQ0CgIF4aXAVANLQRYMaBAAD8dLg2nEAdJaKBWNTYcI5mgbhu6UGHQBiWSpWaeLD/9TiUsErj3WLeGnIo1Z0vwvGXpVaYlksWme5+A/3FHoi7zltF01QKUZsZhXQmSkdy3LxOhtGENGJRo6+2D8+NC0NNFegPuB+ignKC03FsmFEUIbOljEE+nneK91rXr5EmLYr+wm0XVGJeLaMmR2GNDeNAn+13ysfUUxczJooUCuO2mBW3pk93k2jQmwb5/vY2r/PeVq6q6/AtF15kEC7dTxj3TYu7MaRwWpePuHoxXMzL117uDtX+dQROU7bszvHV/qNxq1z2/PdpnOu2DeODJIx3To2eElSp6gs2TLzDSDcELbm2LeODRKTzaPDtidevyu2eXRQhmwfH28zw0S/YtvHzydXH3APMEF5i9IwRYmPmgImi2crLxHTLJWa7Qbr9N6hlqZYxaSAV/CcYtjYRgAEJ63Z7gsA7gqbgPgZKEA4Xqg6txtEUN87eLGT1IojNthSflhhkrD4zipAhMP5qtNyiXpVnYxHgPkT1Ww3eP25AmCl6snFLpQCpwF6tOCV9oXyvsQpMgCCuFMDleuJyLYAm4HlUSQoMea+8cB5H/CY2eufKL8blS6RAjCf1Nmd4zc3/MY2Au5hxqqoks1iHAbeI+BILpc71LN38ETUGsQCwMIkp213swVsZmA9GCtAWAEgH3UhKYlXB2MShEmA3wLwTMErvxhnbbEDEGfyEttcAQHAXMNERxAAEt0+8+QFAHMNEx1BAEh0+8yTFwDMNUx0BAEg0e0zT14AMNcw0REEgES3zzx5AcBcw0RHEAAS3T7z5AUAcw0THUEASHT7zJMXAMw1THQEASDR7TNPXgAw1zDREf4DSPKG2yZqlokAAAAASUVORK5CYII=
// @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues
// @match *://m.bilibili.com/*
// @match *://live.bilibili.com/*
// @match *://www.bilibili.com/read/*
// @match *://www.bilibili.com/h5/comment/*
// @require https://fastly.jsdelivr.net/gh/WhiteSevs/TamperMonkeyScript@86be74b83fca4fa47521cded28377b35e1d7d2ac/lib/CoverUMD/index.js
// @require https://fastly.jsdelivr.net/gh/WhiteSevs/TamperMonkeyScript@86be74b83fca4fa47521cded28377b35e1d7d2ac/lib/QRCode/index.umd.js
// @require https://fastly.jsdelivr.net/npm/@whitesev/utils@2.7.4/dist/index.umd.js
// @require https://fastly.jsdelivr.net/npm/@whitesev/domutils@1.6.3/dist/index.umd.js
// @require https://fastly.jsdelivr.net/npm/@whitesev/pops@2.3.5/dist/index.umd.js
// @require https://fastly.jsdelivr.net/npm/qmsg@1.4.0/dist/index.umd.js
// @require https://fastly.jsdelivr.net/npm/viewerjs@1.11.7/dist/viewer.min.js
// @require https://fastly.jsdelivr.net/npm/md5@2.3.0/dist/md5.min.js
// @require https://fastly.jsdelivr.net/npm/flv.js@1.6.2/dist/flv.js
// @require https://fastly.jsdelivr.net/npm/artplayer@5.2.5/dist/artplayer.js
// @require https://fastly.jsdelivr.net/npm/artplayer-plugin-danmuku@5.1.8/dist/artplayer-plugin-danmuku.js
// @resource ViewerCSS https://fastly.jsdelivr.net/npm/viewerjs@1.11.7/dist/viewer.min.css
// @connect *
// @connect m.bilibili.com
// @connect www.bilibili.com
// @connect api.bilibili.com
// @connect app.bilibili.com
// @connect passport.bilibili.com
// @connect hdslb.com
// @connect aisubtitle.hdslb.com
// @grant GM_addStyle
// @grant GM_deleteValue
// @grant GM_getResourceText
// @grant GM_getValue
// @grant GM_info
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_unregisterMenuCommand
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @run-at document-start
// @downloadURL none
// ==/UserScript==
(function (Qmsg, DOMUtils, Utils, pops, md5, Artplayer, artplayerPluginDanmuku, Viewer, flvjs) {
'use strict';
const o=new Set;const p = async t=>{o.has(t)||o.add(t);};
p(' @charset "UTF-8";.m-video2-awaken-btn,.openapp-dialog{display:none!important}.m-head .launch-app-btn.m-nav-openapp,.m-head .launch-app-btn.home-float-openapp,.m-head m-open-app{display:none!important}.m-home .launch-app-btn.home-float-openapp{display:none!important}.m-space .launch-app-btn.m-space-float-openapp,.m-space .launch-app-btn.m-nav-openapp,.m-space m-open-app:has(>.m-fixed-openapp){display:none!important}#app .video .launch-app-btn.m-video-main-launchapp:has([class^=m-video2-awaken]),#app .video .launch-app-btn.m-nav-openapp,#app .video .mplayer-widescreen-callapp,#app .video .launch-app-btn.m-float-openapp,#app .video .m-video-season-panel .launch-app-btn .open-app{display:none!important}#app.LIVE .open-app-btn.bili-btn-warp{display:none!important}#app .m-dynamic .launch-app-btn.m-nav-openapp,#app .m-dynamic .dynamic-float-openapp.dynamic-float-btn,#app .m-dynamic m-open-app:has(>.m-fixed-openapp){display:none!important}#app .m-opus .float-openapp.opus-float-btn,#app .m-opus .v-switcher .launch-app-btn.list-more,#app .m-opus .opus-nav .launch-app-btn.m-nav-openapp,#app .m-opus .m-navbar .m-nav-openapp,#app .m-opus m-open-app.m-open-app.fixed-openapp{display:none!important}#app .topic-detail .launch-app-btn.m-nav-openapp,#app .topic-detail .launch-app-btn.m-topic-float-openapp{display:none!important}#app.main-container bili-open-app.btn-download{display:none!important}#__next m-open-app[class^=TopBar_download],#__next m-open-app:has([class^=GoApp]){display:none!important}#__next m-open-app[class^=MainButton_btnWrap]{visibility:hidden!important}#app .read-app-main bili-open-app{display:none!important}#app .playlist>.open-app-wp{display:none!important}#app .playlist>.open-app-wp+div{padding-top:56.25%}html{--bili-color: #fb7299;--bili-color-rgb: 251, 114, 153} ');
const BilibiliBeautifyCSS = '@charset "UTF-8";\r\n/* 主页 */\r\n#app .m-head {\r\n --bg-color: #f0f1f3;\r\n --bg-rever-color: #ffffff;\r\n --pd-width: 1.3333vmin;\r\n --bd-circle: 1.3333vmin;\r\n --card-height: 30vmin;\r\n --icon-font-size: 3.2vmin;\r\n --icon-text-font-size: 2.6vmin;\r\n --icon-font-margin-right: 3vmin;\r\n --title-font-size: 2.8vmin;\r\n background-color: var(--bg-color);\r\n}\r\n#app .m-head .m-home {\r\n background-color: var(--bg-color);\r\n}\r\n/* 美化视频卡片 */\r\n#app .m-head .video-list .card-box .v-card {\r\n background-color: var(--bg-rever-color);\r\n padding: 0px;\r\n margin: 0px;\r\n width: calc(50% - var(--pd-width) / 2);\r\n border-radius: var(--bd-circle);\r\n margin-top: var(--pd-width);\r\n display: grid;\r\n /* 视频封面区域 */\r\n}\r\n#app .m-head .video-list .card-box .v-card .card {\r\n background: var(--bg-rever-color);\r\n border-radius: unset;\r\n border-top-left-radius: var(--bd-circle);\r\n border-top-right-radius: var(--bd-circle);\r\n height: var(--card-height);\r\n}\r\n#app .m-head .video-list .card-box .v-card .card .count {\r\n display: flex;\r\n justify-content: safe flex-start;\r\n padding-right: 0;\r\n}\r\n#app .m-head .video-list .card-box .v-card .card .count .iconfont {\r\n font-size: var(--icon-text-font-size);\r\n}\r\n#app .m-head .video-list .card-box .v-card .card .count > span {\r\n font-size: var(--icon-text-font-size);\r\n margin-right: var(--icon-font-margin-right);\r\n}\r\n/* 视频标题区域 */\r\n#app .m-head .video-list .card-box .v-card .title {\r\n padding: 0;\r\n margin: var(--pd-width);\r\n font-size: var(--title-font-size);\r\n}\r\n/* 两列 => 左边的 */\r\n#app .m-head .video-list .card-box .v-card:nth-child(2n-1) {\r\n /*background-color: red;*/\r\n margin-right: calc(var(--pd-width) / 2);\r\n}\r\n/* 两列 => 右边的 */\r\n#app .m-head .video-list .card-box .v-card:nth-child(2n) {\r\n /*background-color: rebeccapurple;*/\r\n margin-left: calc(var(--pd-width) / 2);\r\n}\r\n';
const BilibiliRouter = {
/**
* 视频页面
* + /video/
*/
isVideo() {
return window.location.pathname.startsWith("/video/");
},
/**
* 番剧
* + /bangumi/
*/
isBangumi() {
return window.location.pathname.startsWith("/bangumi/");
},
/**
* 搜索
* + /search
*/
isSearch() {
return window.location.pathname.startsWith("/search");
},
/**
* 搜索结果页面
*
* + /search?keyword=xxx
*/
isSearchResult() {
let urlSearchParams = new URLSearchParams(window.location.search);
return this.isSearch() && urlSearchParams.has("keyword");
},
/**
* 直播
* + live.bilibili.com
*/
isLive() {
return window.location.hostname === "live.bilibili.com";
},
/**
* 专栏稿件
* + /opus
*/
isOpus() {
return window.location.pathname.startsWith("/opus");
},
/**
* 话题
* + /topic-detail
*/
isTopicDetail() {
return window.location.pathname.startsWith("/topic-detail");
},
/**
* 动态
* + /dynamic
*/
isDynamic() {
return window.location.pathname.startsWith("/dynamic");
},
/**
* 首页
* + /
* + /channel
*/
isHead() {
return window.location.pathname === "/" || window.location.pathname.startsWith("/channel");
},
/**
* 个人空间
* + /space
*/
isSpace() {
return window.location.pathname.startsWith("/space");
},
/**
* 播放列表
* + /playlist
*/
isPlayList() {
return window.location.pathname.startsWith("/playlist");
}
};
const BilibiliPCRouter = {
/**
* 桌面端
*/
isPC() {
return window.location.hostname === "www.bilibili.com";
},
/**
* 应该是动态?
* + /read/mobile-readlist/
* + /read/mobile?id=
*/
isReadMobile() {
return this.isPC() && window.location.pathname.startsWith("/read/mobile");
}
};
var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)();
var _GM_getResourceText = /* @__PURE__ */ (() => typeof GM_getResourceText != "undefined" ? GM_getResourceText : void 0)();
var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)();
var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
var _GM_unregisterMenuCommand = /* @__PURE__ */ (() => typeof GM_unregisterMenuCommand != "undefined" ? GM_unregisterMenuCommand : void 0)();
var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
var _monkeyWindow = /* @__PURE__ */ (() => window)();
const KEY = "GM_Panel";
const ATTRIBUTE_INIT = "data-init";
const ATTRIBUTE_KEY = "data-key";
const ATTRIBUTE_DEFAULT_VALUE = "data-default-value";
const ATTRIBUTE_INIT_MORE_VALUE = "data-init-more-value";
const PROPS_STORAGE_API = "data-storage-api";
const PanelUISize = {
/**
* 一般设置界面的尺寸
*/
setting: {
get width() {
if (window.innerWidth < 550) {
return "88vw";
} else if (window.innerWidth < 700) {
return "550px";
} else {
return "700px";
}
},
get height() {
if (window.innerHeight < 450) {
return "70vh";
} else if (window.innerHeight < 550) {
return "450px";
} else {
return "550px";
}
}
},
/**
* 中等的设置界面
*/
settingMiddle: {
get width() {
return window.innerWidth < 350 ? "88vw" : "350px";
}
},
/**
* 信息界面,一般用于提示信息之类
*/
info: {
get width() {
return window.innerWidth < 350 ? "88vw" : "350px";
},
get height() {
return window.innerHeight < 250 ? "88vh" : "250px";
}
}
};
class StorageUtils {
/** 存储的键名 */
storageKey;
listenerData;
/**
* 存储的键名,可以是多层的,如:a.b.c
*
* 那就是
* {
* "a": {
* "b": {
* "c": {
* ...你的数据
* }
* }
* }
* }
* @param key
*/
constructor(key) {
if (typeof key === "string") {
let trimKey = key.trim();
if (trimKey == "") {
throw new Error("key参数不能为空字符串");
}
this.storageKey = trimKey;
} else {
throw new Error("key参数类型错误,必须是字符串");
}
this.listenerData = new Utils.Dictionary();
}
/**
* 获取本地值
*/
getLocalValue() {
let localValue = _GM_getValue(this.storageKey);
if (localValue == null) {
localValue = {};
this.setLocalValue(localValue);
}
return localValue;
}
/**
* 设置本地值
* @param value
*/
setLocalValue(value) {
_GM_setValue(this.storageKey, value);
}
/**
* 设置值
* @param key 键
* @param value 值
*/
set(key, value) {
let oldValue = this.get(key);
let localValue = this.getLocalValue();
Reflect.set(localValue, key, value);
this.setLocalValue(localValue);
this.triggerValueChangeListener(key, oldValue, value);
}
/**
* 获取值
* @param key 键
* @param defaultValue 默认值
*/
get(key, defaultValue) {
let localValue = this.getLocalValue();
return Reflect.get(localValue, key) ?? defaultValue;
}
/**
* 获取所有值
*/
getAll() {
let localValue = this.getLocalValue();
return localValue;
}
/**
* 删除值
* @param key 键
*/
delete(key) {
let oldValue = this.get(key);
let localValue = this.getLocalValue();
Reflect.deleteProperty(localValue, key);
this.setLocalValue(localValue);
this.triggerValueChangeListener(key, oldValue, void 0);
}
/**
* 判断是否存在该值
*/
has(key) {
let localValue = this.getLocalValue();
return Reflect.has(localValue, key);
}
/**
* 获取所有键
*/
keys() {
let localValue = this.getLocalValue();
return Reflect.ownKeys(localValue);
}
/**
* 获取所有值
*/
values() {
let localValue = this.getLocalValue();
return Reflect.ownKeys(localValue).map(
(key) => Reflect.get(localValue, key)
);
}
/**
* 清空所有值
*/
clear() {
_GM_deleteValue(this.storageKey);
}
/**
* 监听值改变
* + .set
* + .delete
* @param key 监听的键
* @param callback 值改变的回调函数
*/
addValueChangeListener(key, callback) {
let listenerId = Math.random();
let listenerData = this.listenerData.get(key) || [];
listenerData.push({
id: listenerId,
key,
callback
});
this.listenerData.set(key, listenerData);
return listenerId;
}
/**
* 移除监听
* @param listenerId 监听的id或键名
*/
removeValueChangeListener(listenerId) {
let flag = false;
for (const [key, listenerData] of this.listenerData.entries()) {
for (let index = 0; index < listenerData.length; index++) {
const value = listenerData[index];
if (typeof listenerId === "string" && value.key === listenerId || typeof listenerId === "number" && value.id === listenerId) {
listenerData.splice(index, 1);
index--;
flag = true;
}
}
this.listenerData.set(key, listenerData);
}
return flag;
}
/**
* 主动触发监听器
* @param key 键
* @param oldValue (可选)旧值
* @param newValue (可选)新值
*/
triggerValueChangeListener(key, oldValue, newValue) {
if (!this.listenerData.has(key)) {
return;
}
let listenerData = this.listenerData.get(key);
for (let index = 0; index < listenerData.length; index++) {
const data2 = listenerData[index];
if (typeof data2.callback === "function") {
let value = this.get(key);
let __newValue;
let __oldValue;
if (typeof oldValue !== "undefined" && arguments.length >= 2) {
__oldValue = oldValue;
} else {
__oldValue = value;
}
if (typeof newValue !== "undefined" && arguments.length > 2) {
__newValue = newValue;
} else {
__newValue = value;
}
data2.callback(key, __oldValue, __newValue);
}
}
}
}
const PopsPanelStorageApi = new StorageUtils(KEY);
const PanelContent = {
$data: {
/**
* @private
*/
__contentConfig: null,
get contentConfig() {
if (this.__contentConfig == null) {
this.__contentConfig = new utils.Dictionary();
}
return this.__contentConfig;
}
},
/**
* 设置所有配置项,用于初始化默认的值
*
* 如果是第一组添加的话,那么它默认就是设置菜单打开的配置
* @param configList 配置项
*/
addContentConfig(configList) {
if (!Array.isArray(configList)) {
configList = [configList];
}
let index = this.$data.contentConfig.keys().length;
this.$data.contentConfig.set(index, configList);
},
/**
* 获取所有的配置内容,用于初始化默认的值
*/
getAllContentConfig() {
return this.$data.contentConfig.values().flat();
},
/**
* 获取配置内容
* @param index 配置索引
*/
getConfig(index = 0) {
return this.$data.contentConfig.get(index) ?? [];
},
/**
* 获取默认左侧底部的配置项
*/
getDefaultBottomContentConfig() {
return [
{
id: "script-version",
title: `版本:${_GM_info?.script?.version || "未知"}`,
isBottom: true,
forms: [],
clickFirstCallback(event, rightHeaderElement, rightContainerElement) {
let supportURL = _GM_info?.script?.supportURL || _GM_info?.script?.namespace;
if (typeof supportURL === "string" && utils.isNotNull(supportURL)) {
window.open(supportURL, "_blank");
}
return false;
}
}
];
}
};
const PanelMenu = {
$data: {
__menuOption: [
{
key: "show_pops_panel_setting",
text: "⚙ 设置",
autoReload: false,
isStoreValue: false,
showText(text) {
return text;
},
callback: () => {
Panel.showPanel(PanelContent.getConfig(0));
}
}
],
get menuOption() {
return this.__menuOption;
}
},
init() {
this.initExtensionsMenu();
},
/**
* 初始化菜单项
*/
initExtensionsMenu() {
if (!Panel.isTopWindow()) {
return;
}
GM_Menu.add(this.$data.menuOption);
},
/**
* 添加菜单项
* @param option 菜单配置
*/
addMenuOption(option) {
if (!Array.isArray(option)) {
option = [option];
}
this.$data.menuOption.push(...option);
},
/**
* 更新菜单项
* @param option 菜单配置
*/
updateMenuOption(option) {
if (!Array.isArray(option)) {
option = [option];
}
option.forEach((optionItem) => {
let findIndex = this.$data.menuOption.findIndex((it) => {
return it.key === optionItem.key;
});
if (findIndex !== -1) {
this.$data.menuOption[findIndex] = optionItem;
}
});
},
/**
* 获取菜单项
* @param [index=0] 索引
*/
getMenuOption(index = 0) {
return this.$data.menuOption[index];
},
/**
* 删除菜单项
* @param [index=0] 索引
*/
deleteMenuOption(index = 0) {
this.$data.menuOption.splice(index, 1);
}
};
const CommonUtil = {
/**
* 移除元素(未出现也可以等待出现)
* @param selector 元素选择器
*/
waitRemove(...args) {
args.forEach((selector) => {
if (typeof selector !== "string") {
return;
}
utils.waitNodeList(selector).then((nodeList) => {
nodeList.forEach(($el) => $el.remove());
});
});
},
/**
* 添加屏蔽CSS
* @param args
* @example
* addBlockCSS("")
* addBlockCSS("","")
* addBlockCSS(["",""])
*/
addBlockCSS(...args) {
let selectorList = [];
if (args.length === 0) {
return;
}
if (args.length === 1 && typeof args[0] === "string" && args[0].trim() === "") {
return;
}
args.forEach((selector) => {
if (Array.isArray(selector)) {
selectorList = selectorList.concat(selector);
} else {
selectorList.push(selector);
}
});
return addStyle(`${selectorList.join(",\n")}{display: none !important;}`);
},
/**
* 设置GM_getResourceText的style内容
* @param resourceMapData 资源数据
* @example
* setGMResourceCSS({
* keyName: "ViewerCSS",
* url: "https://example.com/example.css",
* })
*/
setGMResourceCSS(resourceMapData) {
let cssText = typeof _GM_getResourceText === "function" ? _GM_getResourceText(resourceMapData.keyName) : null;
if (typeof cssText === "string" && cssText) {
addStyle(cssText);
} else {
CommonUtil.loadStyleLink(resourceMapData.url);
}
},
/**
* 添加标签
* @param url
* @example
* loadStyleLink("https://example.com/example.css")
*/
async loadStyleLink(url) {
let $link = document.createElement("link");
$link.rel = "stylesheet";
$link.type = "text/css";
$link.href = url;
DOMUtils.ready(() => {
document.head.appendChild($link);
});
},
/**
* 添加