// ==UserScript==
// @name 仓库用度盘投稿助手
// @namespace moe.jixun.dupan.galacg
// @version 1.2.3
// @description 简易功能增强, 方便仓库投稿用
// @author Jixun
// @include http://pan.baidu.com/disk/home*
// @include http://yun.baidu.com/disk/home*
// @include https://pan.baidu.com/disk/home*
// @include https://yun.baidu.com/disk/home*
// @compatible firefox GreaseMonkey (有限)
// @compatible firefox Violentmonkey
// @compatible chrome Violentmonkey
// @grant none
// @run-at document-start
// @downloadURL none
// ==/UserScript==
function entryPoint () {
'use strict';
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css_248z = ".jx_btn {\n background: #fefefe;\n background: linear-gradient(to bottom, #fefefe 0%,#f2f2f2 88%);\n\n display: inline-block;\n line-height: 25px;\n vertical-align: middle;\n margin: 0 0 0 10px;\n text-decoration: none;\n border: 1px solid #AAA;\n padding: 0px 20px;\n height: 26px;\n border-radius: 2px;\n\n min-width: 3em;\n text-align: center;\n}\n.jx_btn, .jx_btn:hover, .jx_btn:focus {\n color: #666;\n}\n.jx_btn:active {\n color: #06C;\n background: #e3e3e3;\n background: -moz-linear-gradient(top, #e3e3e3 0%, #f7f7f7 12%);\n background: -webkit-linear-gradient(top, #e3e3e3 0%,#f7f7f7 12%);\n background: linear-gradient(to bottom, #e3e3e3 0%,#f7f7f7 12%);\n}\n.jx-input {\n margin: 9px 0;\n _margin: 7px 0;\n padding: 0 0 0 5px;\n width: 200px;\n height: 24px;\n vertical-align: middle;\n border: 1px solid #3b8cff;\n border: 1px solid rgba(58,140,255,.3);\n background: #fff;\n border-radius: 2px;\n}\n\n.jx_hide { display: none }\n.jx_c_warn { color: red }\n\n.jx_list {\n text-align: left;\n max-height: 5.5em;\n overflow-y: scroll;\n overflow-x: hidden;\n line-height: 1;\n padding: .2em;\n margin-bottom: .5em;\n}\n\n/*\n.jx_list:not(:empty) {\n border: 1px solid #ddd;\n}\n*/\n\n.jx_list > li {\n display: flex;\n white-space: nowrap;\n line-height: 1.3;\n}\n\n.jx_list .name {\n color: black;\n\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.jx_list .size {\n color: #777;\n\n flex-grow: 1;\n}\n\n.save-complete-details {\n max-height: 30em;\n}\n\n.jx-status {\n padding-left: 0.25em;\n}\n\n.jx-status-success {\n color: green;\n}\n\n.jx-status-skip {\n color: gray;\n}\n\n.jx-status-fail {\n color: red;\n}\n\ntextarea.jx{\n width: 100%;\n min-height: 5em;\n line-height: 1;\n}\n\n.jx-form-options {\n display: flex;\n justify-content: left;\n}\n\n.jx-form-options > label {\n display: inline-flex;\n align-items: center;\n}\n\n.jx-form-options > label + label {\n margin-left: 0.5em;\n}\n\n.jx-form-options > label > input {\n margin-right: 0.25em;\n}\n";
styleInject(css_248z);
const TAG = '[仓库助手]';
const pluginBlacklist = ['右上角广告位', '网盘APP下载', '满减活动', '会员提醒'];
let oRequire;
const hooks = new Map();
function fakeRequire(module) {
// console.info('%s Load module: %s', INFO, module);
const moduleHook = hooks.get(module);
if (moduleHook) {
moduleHook();
hooks.delete(module);
}
return oRequire.apply(this, arguments);
}
function load(module) {
return oRequire.call(window, module);
}
function hook(module, fn) {
hooks.set(module, fn);
}
if (window.require) {
console.warn('%s 覆盖方式安装,若无效请强制刷新。', TAG);
oRequire = window.require;
window.require = fakeRequire;
Object.assign(fakeRequire, oRequire);
} else {
console.info('%s 钩子方式安装,若失效请报告。', TAG);
Object.defineProperty(window, 'require', {
set(require) {
oRequire = require;
},
get() {
return fakeRequire;
},
});
}
function getFileList() {
return load('disk-system:widget/pageModule/list/listInit.js');
}
function getCheckedItems() {
return getFileList().getCheckedItems();
}
function anythingChecked() {
return getCheckedItems().length > 0;
}
function getCurrentDirectory() {
return getFileList().currentKey;
}
var css_248z$1 = ".jx-dialog-body {\n text-align:center;\n padding:22px;\n}\n";
styleInject(css_248z$1);
let id = 0;
function nextId() {
// eslint-disable-next-line no-plusplus
return id++;
}
function firstFunction(...fns) {
return fns.find((fn) => typeof fn === 'function');
}
function getDialog() {
return load('system-core:system/uiService/dialog/dialog.js');
}
const bigButton = {
type: 'big',
padding: ['50px', '50px'],
};
function confirmDialog(data) {
let dialog;
const hideDialog = () => dialog.hide();
const dialogData = {
id: `confirm-${nextId()}`,
show: true,
title: data.title,
body: $('
').append(data.body),
buttons: [{
...bigButton,
name: 'confirm',
title: data.sureText || '确定',
color: 'blue',
click: firstFunction(data.onSure, hideDialog),
}],
};
if (data.cancel !== false) {
dialogData.buttons.push({
...bigButton,
name: 'cancel',
title: data.cancelText || '取消',
click: firstFunction(data.onCancel, hideDialog),
});
}
const Dialog = getDialog();
dialog = new Dialog(dialogData);
return dialog;
}
function infoDialog(data) {
return confirmDialog({
...data,
cancel: false,
});
}
function getTip() {
return load('system-core:system/uiService/tip/tip.js');
}
function showTip() {
return getTip().show.apply(this, arguments);
}
function hideTip() {
return getTip().hide.apply(this, arguments);
}
function getContext() {
return load('system-core:context/context.js').instanceForSystem;
}
function getErrorMessage(code) {
const msg = String(getContext().errorMsg(code));
return msg.replace(/\s+rapidupload 错误码$/, '');
}
function injectErrorMessage(obj) {
if ($.isPlainObject(obj)) {
obj.error = obj.show_msg || getErrorMessage(obj.errno || 0);
}
return obj;
}
async function ajax(data) {
return new Promise((resolve) => {
$.ajax(data)
.fail((err) => {
resolve({ errno: -1, error: '网络错误。' });
console.error('%s 网络请求错误: %o', TAG, err);
})
.success((result) => {
resolve(injectErrorMessage(result));
});
});
}
const div = document.createElement('a');
const escapeDict = {
'"': 'quot',
"'": 'apos',
};
function escapeHtml(text) {
div.textContent = text;
const result = div.innerHTML.replace(/["']/g, (x) => `&${escapeDict[x]};`);
div.textContent = '';
return result;
}
var template = "
\n
\n
无效的提取码, 脚本将随机生成一个分享代码 …
\n
\n\n
\n
\n
\n\n
\n
\n \n
\n
\n";
class LocalStore {
constructor(id) {
this.id = id;
}
get value() {
return localStorage.getItem(this.id);
}
set value(value) {
return localStorage.setItem(this.id, value);
}
}
const PREFIX = '__jx_';
class OpDialog {
get id() {
return this.constructor.name;
}
getNamespacedKey(key) {
return `${PREFIX}_${this.id}_${key}`;
}
createStore(key) {
return new LocalStore(this.getNamespacedKey(key));
}
constructor(template, title) {
this.title = title;
this.root = $(template);
this.bindContext();
this.createDialog();
this.bootstrap();
}
bindContext() {
this.show = this.show.bind(this);
this.hide = this.hide.bind(this);
this.onConfirm = this.onConfirm.bind(this);
this.onCancel = this.onCancel.bind(this);
}
createDialog() {
this.dialog = confirmDialog({
title: this.title,
body: this.root,
onSure: this.onConfirm,
onCancel: this.onCancel,
});
}
/**
* 选择对话框内的内容。
* @param selector
* @returns {JQuery
}
*/
$(selector) {
return $(selector, this.root);
}
/**
* Bind events.
*/
bootstrap() {
return this;
}
show() {
this.dialog.show();
}
hide() {
this.dialog.hide();
}
async onConfirm() {
this.hide();
}
onCancel() {
this.hide();
}
}
/* 依赖函数表 */
function isCodeValid(code) {
return encodeURIComponent(code).replace(/%[A-F\d]{2}/gi, '-').length === 4;
}
function fixCode(code) {
return code.replace(/"/g, '"').replace(/]/g, ']');
}
function fixWidthDigits(d) {
return (`0${d.toString()}`).slice(-2);
}
function makeDate(d) {
return `${d.getFullYear()}.${fixWidthDigits(d.getMonth() + 1)}.${fixWidthDigits(d.getDate())}`;
}
function genKey(size = 4) {
// length => 26 + 10, 36
const keySet = 'abcdefghijklmnopqrstuvwxyz0123456789';
let r = '';
for (let i = size; i--;) {
// eslint-disable-next-line no-bitwise
r += keySet[0 | (Math.random() * 36)];
}
return r;
}
function getFileId(item) {
return item.fs_id;
}
class CustomShareDialog extends OpDialog {
static create() {
return new CustomShareDialog();
}
constructor() {
super(template, '自定义分享');
}
bindContext() {
super.bindContext();
this.validateCode = this.validateCode.bind(this);
this.hideError = this.hideError.bind(this);
}
bootstrap() {
this.$error = this.$('.jx_errmsg');
this.$footer = this.dialog.find(getDialog().QUERY.dialogFooter);
this.$key = this.$('#jx_shareKey').val(genKey());
this.$key.on('input change', this.validateCode);
this.$key.on('focus', this.hideError);
}
async onConfirm() {
this.hide();
let key = this.$key.val();
if (!isCodeValid(key)) {
key = genKey(4);
this.$key.val(key);
}
showTip({
mode: 'loading',
msg: '正在分享,请稍后 ...',
autoClose: false,
});
const sharedItems = getCheckedItems();
const resp = await ajax({
url: '/share/set',
type: 'POST',
data: {
fid_list: JSON.stringify(sharedItems.map(getFileId)),
schannel: 4,
channel_list: '[]',
pwd: key,
// 0: 永久
// 1、7: 天数
period: 0,
},
dataType: 'json',
});
hideTip();
if (resp.errno || !resp.shorturl) {
showTip({
mode: 'failure',
msg: `分享失败:${resp.error}`,
});
return;
}
showTip({
mode: 'success',
msg: '分享成功!',
});
this.$footer.children('.g-button-blue-large').hide();
this.$footer.children('.g-button-large').find('.text').text('关闭');
const url = `${resp.shorturl}#${key}`;
this.$('#jx_shortUrl').val(url);
this.$('#jx_shareCode').val(key);
this.root.toggleClass('jx_hide');
const title = fixCode(sharedItems[0].server_filename) + (sharedItems.length === 1 ? '' : ' 等文件');
const code = `[dlbox title="${escapeHtml(title)}" from="浩瀚的宇宙" time="${makeDate(new Date())}" info="提取:${escapeHtml(key)}" link1="度娘|${url}"][/dlbox]]`;
this.$('#jx_dlboxCode').val(code);
this.show();
}
/**
* @returns string
*/
get value() {
return this.$key.val();
}
get isValueValid() {
return encodeURIComponent(this.value).replace(/%[A-F\d]{2}/gi, '-').length === 4;
}
hideError() {
this.$error.addClass('jx_hide');
}
validateCode() {
this.$error.toggleClass('jx_hide', this.isValueValid);
}
}
var template$1 = "\n :\n \n
\n\n\n :n
表示不带扩展名的文件名; :e
表示扩展名; :E
表示 .扩展名;\n
:d
表示一位随机数字; :c
表示一位随机字符; :t
表示当前时间戳\n
\n";
function getMessage() {
return load('system-core:system/baseService/message/message.js');
}
function trigger(event) {
getMessage().trigger(event);
}
/**
* 刷新当前文件列表
*/
function refreshFileListView() {
trigger('system-refresh');
}
const fixRules = {
n(name) {
const match = name.match(/^(.+)\./);
return match ? match[1] : match;
},
c() {
return String.fromCharCode(97 + Math.random() * 26);
},
d() {
return Math.random().toString().slice(3, 4);
},
t() {
return Date.now();
},
e(name) {
const ext = name.match(/\.([^.]+)$/);
return ext ? ext[1] : '';
},
E(name) {
return name.match(/\.[^.]+$/) || '';
},
};
/* 依赖函数表 */
function fixName(name, code) {
const fn = fixRules[code];
if (fn) {
return fn(name);
}
return null;
}
class BatchRenameDialog extends OpDialog {
static create() {
return new BatchRenameDialog();
}
constructor() {
super(template$1, '批量重命名');
}
bindContext() {
super.bindContext();
this.namePatternStore = this.createStore('pattern');
}
bootstrap() {
this.$namePattern = this.$('#jx_nameRule');
this.$namePattern.val(this.namePatternStore.value || '[GalACG] :d:d:d:d:d:d:d:d:d:d:E');
}
async onConfirm() {
this.hide();
const namePattern = this.$namePattern.val();
this.namePatternStore.value = namePattern;
const fileList = getCheckedItems().map((item) => ({
path: item.path,
newname: namePattern.replace(/:([cdeEnt])/g, (_, code) => fixName(item.server_filename, code)),
}));
showTip({
mode: 'loading',
msg: '正在批量重命名,请稍后 ...',
autoClose: false,
});
const resp = await ajax({
url: '/api/filemanager?opera=rename',
type: 'POST',
data: {
filelist: JSON.stringify(fileList),
},
});
hideTip();
refreshFileListView();
if (resp.errno) {
showTip({
mode: 'failure',
msg: `批量重命名失败, 请稍后重试! (${resp.error})`,
});
} else {
showTip({
mode: 'success',
msg: '重命名成功!',
});
}
}
}
function menuInsertAfter(list, name, item, noPush) {
for (let i = 0; i < list.length; i++) {
if (list[i] instanceof Array) {
if (menuInsertAfter(list[i], name, item, true)) {
return false;
}
} else if (list[i].title === name) {
i++;
list.splice(i, 0, item);
return true;
}
}
if (!noPush) list.push(item);
return false;
}
function injectMenu() {
const faceData = load('system-core:data/faceData.js');
const fileCtxMenu = faceData.getData().contextMenu.file;
menuInsertAfter(fileCtxMenu, '分享', {
index: 8,
keyboard: 'u',
title: '自定义分享',
display: anythingChecked,
action: CustomShareDialog.create,
});
fileCtxMenu.forEach((m) => {
if (m.index >= 2) {
m.index += 1;
}
});
fileCtxMenu.push({
index: 2, // '删除' 的 index。
keyboard: 'r',
position: 'bottom',
title: '批量重命名',
display: anythingChecked,
action: BatchRenameDialog.create,
});
}
var template$2 = "\n";
function debounce(fn) {
let timer;
return () => {
cancelAnimationFrame(timer);
timer = requestAnimationFrame(fn);
};
}
/**
* 将数值转换为 2 位数的十六进制文本。
* @param {Number} value
* @returns {string}
*/
function toStdHex(value) {
const hex = Math.floor(value).toString(16);
return (`0${hex}`).slice(-2);
}
const slice = Function.prototype.call.bind(Array.prototype.slice);
/**
* 一个简单的类似于 NodeJS Buffer 的实现.
* 用于解析游侠度娘提取码。
*/
class SimpleBuffer {
/**
* @param {String} str
*/
constructor(str) {
this.fromString(str);
}
fromString(str) {
const len = str.length;
this.buf = new Uint8Array(len);
for (let i = 0; i < len; i++) {
this.buf[i] = str.charCodeAt(i);
}
}
readUnicode(index, size) {
const bufText = slice(this.buf, index, index + size).map(toStdHex);
const buf = [''];
for (let i = 0; i < size; i += 2) {
buf.push(bufText[i + 1] + bufText[i]);
}
return JSON.parse(`"${buf.join('\\u')}"`);
}
readNumber(index, size) {
let ret = 0;
for (let i = index + size; i > index;) ret = this.buf[--i] + (ret * 256);
return ret;
}
readUInt(index) {
return this.readNumber(index, 4);
}
readULong(index) {
return this.readNumber(index, 8);
}
readHex(index, size) {
return Array.prototype.slice.call(this.buf, index, index + size).map(toStdHex).join('');
}
}
/**
* UTF-8 字符转换成 base64 后在 JS 里解析会出毛病。
* @param str
* @returns {string}
*/
function decodeBase64(str) {
return decodeURIComponent(atob(str).replace(/[^\x00-\x7F]/g, (z) => `%${toStdHex(z.charCodeAt(0))}`));
}
const trim = (str) => String.prototype.trim.call(str);
class DuParser {
constructor() {
this.reset();
}
reset() {
this.results = [];
this.versions = new Set();
}
parse(url) {
if (url.indexOf('BDLINK') === 0) {
this.parseAli(url);
return;
}
const links = url.split('\n').map(trim);
for (const link of links) {
if (link.startsWith('bdpan://')) {
this.parsePanDownload(link);
} else {
this.parseStandard(link);
}
}
}
hasResults() {
return this.results.length;
}
parseAli(url) {
const raw = atob(url.slice(6).replace(/\s/g, ''));
if (raw.slice(0, 5) !== 'BDFS\x00') return null;
const buf = new SimpleBuffer(raw);
let ptr = 9;
const fileCount = buf.readUInt(5);
if (fileCount === 0) {
return null;
}
this.versions.add('游侠 v1');
for (let i = 0; i < fileCount; i++) {
// 大小 (8 bytes)
// MD5 + MD5S (0x20)
// nameSize (4 bytes)
// Name (unicode)
const fileInfo = Object.create(null);
fileInfo.size = buf.readULong(ptr);
fileInfo.md5 = buf.readHex(ptr + 8, 0x10);
fileInfo.md5s = buf.readHex(ptr + 0x18, 0x10);
const sizeofName = buf.readUInt(ptr + 0x28) * 2;
ptr += 0x2C;
fileInfo.name = buf.readUnicode(ptr, sizeofName);
this.results.push(fileInfo);
ptr += sizeofName;
}
return true;
}
parseStandard(szUrl) {
const match = szUrl.trim().match(/^([\dA-F]{32})#([\dA-F]{32})#([\d]{1,20})#([\s\S]+)$/i);
if (match) {
const [, md5, md5s, size, name] = match;
this.versions.add('梦姬标准');
this.results.push({
md5, md5s, size, name,
});
}
return null;
}
parsePanDownload(szUrl) {
const match = decodeBase64(szUrl.slice(8)).match(/^([\s\S]+)\|([\d]{1,20})\|([\dA-F]{32})\|([\dA-F]{32})$/i);
if (match) {
const [, name, size, md5, md5s] = match;
this.versions.add('PanDownload');
this.results.push({
md5, md5s, size, name,
});
}
return null;
}
}
/**
* 将文本形式的文件大小转换为
* @param {string} size
* @returns {string}
*/
function parseSize(size) {
let unit = 'MiB';
let sizeInUnit = parseInt(size, 10) / 1024 / 1024;
// 超过 GB
if (sizeInUnit > 1024) {
unit = 'GiB';
sizeInUnit /= 1024;
}
return `${sizeInUnit.toFixed(2)} ${unit}`;
}
function itemInfo(item) {
const name = escapeHtml(item.name);
return `
${name}
(${escapeHtml(parseSize(item.size))})
`;
}
function wrapTag(tag) {
return (html) => `<${tag}>${html}${tag}>`;
}
const toLowerCase = Function.prototype.call.bind(String.prototype.toLowerCase);
async function rapidUpload(dir, file, ondup) {
if (dir.slice(-1) !== '/') {
dir += '/';
}
return ajax({
url: '/api/rapidupload?rtype=1',
type: 'POST',
// https://github.com/iikira/BaiduPCS-Go/blob/9837f8e24328e5f881d6a07cf1249508c485a063/baidupcs/prepare.go#L272-L279
data: {
// overwrite: 表示覆盖同名文件; newcopy: 表示生成文件副本并进行重命名,命名规则为“文件名_日期.后缀”
ondup,
path: dir + file.name,
'content-md5': toLowerCase(file.md5),
'slice-md5': toLowerCase(file.md5s),
'content-length': file.size,
local_mtime: '',
},
});
}
function statusHtml(result) {
const className = result.success ? 'success' : 'fail';
return `${result.error}`;
}
class StandardCodeDialog extends OpDialog {
static create() {
return new StandardCodeDialog();
}
constructor() {
super(template$2, '通用提取码');
}
bindContext() {
super.bindContext();
this.hideError = this.hideError.bind(this);
this.updatePreview = this.updatePreview.bind(this);
this.parser = new DuParser();
}
bootstrap() {
this.jx_list = this.$('.jx_list');
this.jx_code = this.$('.jx_code');
this.jx_errmsg = this.$('.jx_errmsg');
this.jx_version = this.$('.jx_version');
this.jx_ondup = this.$('input[name="ondup"]');
this.ondup = this.root[0].elements.ondup;
this.ondupStore = this.createStore('ondup');
this.jx_ondup.filter(`[value="${this.ondupStore.value}"]`).prop('checked', true);
this.jx_code.on('blur input', debounce(this.updatePreview));
this.jx_code.on('focus', this.hideError);
}
hideError() {
this.jx_errmsg.addClass('jx_hide');
}
get versions() {
return Array.from(this.parser.versions).join('、');
}
get results() {
return this.parser.results;
}
updatePreview() {
const code = this.jx_code.val();
this.parser.reset();
this.parser.parse(code);
const hasResults = this.parser.hasResults();
// 如果输入框不为空却没有解析到任何内容
this.jx_errmsg.toggleClass('jx_hide', Boolean(!code || hasResults));
if (hasResults) {
this.jx_version.text(this.versions);
this.jx_list.html(this.results.map(itemInfo).map(wrapTag('li')).join(''));
} else {
this.jx_version.text('--');
this.jx_list.text('');
}
}
async onConfirm() {
this.hide();
const ondup = this.ondup.value;
this.ondupStore.value = ondup;
const totalCount = this.results.length;
let failed = 0;
let counter = 1;
for (const file of this.results) {
showTip({
mode: 'loading',
msg: `正在转存文件 (${counter}/${totalCount}), 请稍后 ..`,
autoClose: false,
});
const resp = await rapidUpload(getCurrentDirectory(), file, ondup);
file.success = resp.errno === 0;
file.errno = resp.errno;
file.error = resp.error;
file.resp = resp;
if (!file.success) {
failed++;
}
counter++;
}
refreshFileListView();
infoDialog({
title: `转存完毕 (失败 ${failed} 个, 共 ${totalCount} 个)!`,
body: `
${this.results.map((result) => `${itemInfo(result)}${statusHtml(result)}`).map(wrapTag('li')).join('')}
`,
cancel: false,
});
}
}
function registerPlugin() {
// 注入到 manifest 定义文件
window.define('function-widget:jixun/standard-code.js', (require, exports) => {
// require, exports, module
exports.start = StandardCodeDialog.create;
});
window.manifest = window.manifest.filter((plugin) => !pluginBlacklist.includes(plugin.name));
window.manifest.push({
name: '标准提取码插件',
group: 'moe.jixun.code',
version: '1.0',
type: '1',
description: '类似于 115 的标准提取码',
filesType: '*',
buttons: [{
index: 2,
disabled: 'none',
title: '标准提取码',
buttonStyle: 'normal',
pluginId: 'JIXUNSTDCODE',
position: 'tools',
}],
preload: false,
depsFiles: [],
entranceFile: 'function-widget:jixun/standard-code.js',
pluginId: 'JIXUNSTDCODE',
});
}
hook('disk-system:widget/system/uiRender/menu/listMenu.js', injectMenu);
hook('system-core:pluginHub/register/register.js', registerPlugin);
// ESC 将关闭所有漂浮窗口
document.addEventListener('keyup', (e) => {
if (e.keyCode === 0x1b) {
$('.dialog-close').click();
}
}, false);
}
const isGm = (typeof unsafeWindow !== 'undefined') && (unsafeWindow !== window);
if (isGm) {
const INFO = '[仓库助手]';
console.info('%s 以 GreaseMonkey 兼容模式执行。该脚本管理器所遇到的问题不能保证能够修复。', INFO);
unsafeWindow.eval(`;(${entryPoint})();`);
} else {
entryPoint();
}