import { Cryptojs, DOMUtils, httpx, log, pops, SCRIPT_NAME, utils } from "@/env"; import { NetDiskRuleDataKEY } from "@/main/data/NetDiskRuleDataKey"; import { NetDiskHandlerAccessCodeRule } from "@/main/handler/accesscode-handler/NetDiskHandlerAccessCode"; import { NetDiskAuthorizationRule } from "@/main/handler/authorization/NetDiskAuthorization"; import { NetDiskAutoFillAccessCodeRule } from "@/main/handler/auto-fill-accesscode/NetDiskAutoFillAccessCode"; import { NetDiskCheckLinkValidity } from "@/main/handler/check-valid/NetDiskCheckLinkValidity"; import { NetDiskCheckLinkValidityStatus } from "@/main/handler/check-valid/NetDiskCheckLinkValidityStatus"; import { NetDiskParseRule } from "@/main/handler/parse/NetDiskParse"; import { NetDiskPops } from "@/main/pops/NetDiskPops"; import { NetDiskRuleUtils } from "@/main/rule/NetDiskRuleUtils"; import { NetDiskView } from "@/main/view/NetDiskView"; import { UIInput } from "@components/setting/components/ui-input"; import { PROPS_STORAGE_API } from "@components/setting/panel-config"; import { PanelUISize } from "@components/setting/panel-ui-size"; import type { RulePanelContentOption, RuleSubscribeOption } from "@components/utils/RulePanelView"; import { StorageUtils } from "@components/utils/StorageUtils"; import type { UtilsDictionary } from "@whitesev/utils/dist/types/src/Dictionary.js"; import Qmsg from "qmsg"; import { GM_deleteValue, GM_getValue, GM_setValue, unsafeWindow } from "ViteGM"; import { NetDiskRequire } from "./NetDiskRequire"; import { NetDiskRuleReplacePlaceholder_html, NetDiskRuleReplacePlaceholder_text, } from "../NetDiskRuleReplacePlaceholder"; import { NetDiskUserRuleSubscribeRule } from "./NetDiskUserRuleSubscribeRule"; import { NetDiskUserRuleUI } from "./NetDiskUserRuleUI"; import { ParseFileCore } from "@/main/handler/parse/NetDiskParseAbstract"; import { NetDiskFilterScheme } from "@/main/scheme/NetDiskFilterScheme"; const NetDiskUserRuleStorageApi = new StorageUtils("userRule"); /** 用户规则上下文存储的数据 */ const NetDiskUserRuleBindContextStorageApi = new StorageUtils("userRuleBindContext"); /** 网盘-链接识别规则 */ export const NetDiskUserRule = { $data: { STORAGE_KEY: "rule", EXPORT_CONFIG_KEY: "rule-export-config", __userRule: null as any as UtilsDictionary, get userRule() { if (this.__userRule == null) { this.__userRule = new utils.Dictionary(); } return this.__userRule; }, }, /** * 初始化 */ init() { // 把旧的数据转换 const oldUserRule = GM_getValue("userRule"); if (Array.isArray(oldUserRule)) { GM_deleteValue("userRule"); this.setRule(oldUserRule); } // 先把本地规则进行转换 let userRule = this.parseRule(this.getAllRule()); // 再把订阅规则进行转换 const subscribeRule = this.parseRule(NetDiskUserRuleSubscribeRule.getAllSubscribeRule()); userRule = userRule.concat(subscribeRule); for (let i = 0; i < userRule.length; i++) { const item = userRule[i]; this.$data.userRule.set(item.setting.key, item); } }, /** * 把输入的规则字符串解析为规则对象 */ parseRuleStrToRule(ruleText: string | NetDiskUserCustomRule) { /** * 检测regexp项是否符合规定 * @param ruleRegExp */ function checkRegExp(ruleRegExp: NetDiskUserCustomRuleRegexp) { if (typeof ruleRegExp["link_innerText"] !== "string") { return { success: false, msg: "regexp缺失的键名: link_innerText,类型: string", }; } if (typeof ruleRegExp["link_innerHTML"] !== "string") { return { success: false, msg: "regexp缺失的键名: link_innerHTML,类型: string", }; } if (typeof ruleRegExp["shareCode"] !== "string") { return { success: false, msg: "regexp缺失的键名: shareCode,类型: string", }; } if ( typeof ruleRegExp["shareCodeNeedRemoveStr"] !== "string" && !Array.isArray(ruleRegExp["shareCodeNeedRemoveStr"]) ) { return { success: false, msg: "regexp缺失的键名: shareCodeNeedRemoveStr,类型: string|string[]", }; } if (typeof ruleRegExp["uiLinkShow"] !== "string") { return { success: false, msg: "regexp缺失的键名: uiLinkShow,类型: string", }; } if (typeof ruleRegExp["blank"] !== "string") { return { success: false, msg: "regexp缺失的键名: blank,类型: string", }; } if (typeof ruleRegExp["copyUrl"] !== "string") { return { success: false, msg: "regexp缺失的键名: copyUrl,类型: string", }; } if ( typeof ruleRegExp["accessCode"] === "string" && typeof ruleRegExp["checkAccessCode"] !== "string" && !Array.isArray(ruleRegExp["checkAccessCode"]) ) { return { success: false, msg: "regexp设置了accessCode但是没有设置checkAccessCode", }; } if ( typeof ruleRegExp["accessCode"] !== "string" && typeof ruleRegExp["checkAccessCode"] === "string" && !Array.isArray(ruleRegExp["checkAccessCode"]) ) { return { success: false, msg: "regexp设置了checkAccessCode但是没有设置accessCode", }; } return { success: true, msg: "校验rule成功", }; } /** * 检测设置项是否符合规定 * @param ruleSetting */ function checkSetting(ruleSetting: NetDiskUserCustomRuleSetting) { if (typeof ruleSetting["name"] !== "string") { return { success: false, msg: "setting缺失的键名: name,类型: string", }; } if (typeof ruleSetting["enable"] !== "boolean") { return { success: false, msg: "setting缺失的键名: enable,类型: boolean", }; } return { success: true, msg: "校验setting成功", }; } try { let ruleJSON = typeof ruleText === "string" ? utils.toJSON(ruleText) : ruleText; log.info(`解析出的规则对象:`, ruleJSON); if (typeof ruleJSON !== "object") { return { success: false, msg: "该规则不是object类型", }; } if (Object.keys(ruleJSON).length === 0) { return { success: false, msg: "该规则为空", }; } if (typeof ruleJSON["key"] !== "string") { return { success: false, msg: "缺失的键名: key,类型: string", }; } if (typeof ruleJSON["regexp"] !== "object") { return { success: false, msg: "缺失的键名: regexp,类型: object|Arrany", }; } if (typeof ruleJSON["setting"] !== "object") { return { success: false, msg: "缺失的键名: setting,类型: object", }; } if (Array.isArray(ruleJSON["regexp"])) { for (let i = 0; i < ruleJSON["regexp"].length; i++) { const regexpItem = ruleJSON["regexp"][i]; const result = checkRegExp(regexpItem); if (!result.success) { return result; } } } else { const result = checkRegExp(ruleJSON["regexp"]); if (!result.success) { return result; } } const checkSettingResult = checkSetting(ruleJSON["setting"]); if (!checkSettingResult.success) { return checkSettingResult; } return { success: true, msg: "解析成功", data: ruleJSON, }; } catch (error: any) { log.error(error); return { success: false, msg: error.message, }; } }, /** * 上下文环境 * @param rule */ getBindContext(rule: NetDiskUserCustomRule): NetDiskUserCustomRuleContext { return { subscribeUUID: rule.subscribeUUID, rule: rule, NetDiskRequire: NetDiskRequire, CryptoJS: Cryptojs, httpx: httpx, utils: utils, DOMUtils: DOMUtils, window: window, unsafeWindow: unsafeWindow, NetDiskCheckLinkValidity: NetDiskCheckLinkValidity, NetDiskCheckLinkValidityStatus: NetDiskCheckLinkValidityStatus, NetDiskFilterScheme: NetDiskFilterScheme, NetDiskView: { showOneFileView: NetDiskView.$inst.linearChainDialogView.oneFile.bind(NetDiskView.$inst.linearChainDialogView), showMoreFileView: NetDiskView.$inst.linearChainDialogView.moreFile.bind( NetDiskView.$inst.linearChainDialogView ), }, log: log, Qmsg: Qmsg, pops: pops, setValue: NetDiskUserRuleBindContextStorageApi.set.bind(NetDiskUserRuleBindContextStorageApi), getValue: NetDiskUserRuleBindContextStorageApi.get.bind(NetDiskUserRuleBindContextStorageApi), deleteValue: NetDiskUserRuleBindContextStorageApi.delete.bind(NetDiskUserRuleBindContextStorageApi), }; }, /** * 把用户链接识别规则进行转换成脚本规则 * @param localRule 用户的规则 */ parseRule(localRule: NetDiskUserCustomRule[]): NetDiskRuleOption[] { /** * 这里是第1步骤的处理函数 * * 规则转换 * * 把字符串类型的转为正则 * @param ruleKey 规则键 * @param userRuleConfig 用户规则配置 * @param ruleRegExp 用户的匹配规则 */ function parseUserRuleToScriptRule( ruleKey: string, userRuleConfig: NetDiskUserCustomRule, ruleRegExp: NetDiskUserCustomRuleRegexp ): NetDiskMatchRuleConfig { let { shareCode, shareCodeNeedRemoveStr, shareCodeNotMatch, checkAccessCode, accessCode, acceesCodeNotMatch, accessCodeNeedRemoveStr, paramMatch, ...otherRuleParams } = ruleRegExp; // 这里的值需要获取最新的,而不是配置默认值 let netDiskRegularOption = { ...otherRuleParams, } as NetDiskMatchRuleConfig; // 处理link_innerText // 处理link_innerHTML // 把某些关键字参数替换为规定的数值 netDiskRegularOption.link_innerText = NetDiskRuleUtils.replacePlaceholder( netDiskRegularOption.link_innerText, NetDiskRuleReplacePlaceholder_text(ruleKey) ); netDiskRegularOption.link_innerHTML = NetDiskRuleUtils.replacePlaceholder( netDiskRegularOption.link_innerText, NetDiskRuleReplacePlaceholder_html(ruleKey) ); if (typeof shareCode === "string") { netDiskRegularOption.shareCode = new RegExp(shareCode, "gi"); } if (shareCodeNeedRemoveStr) { if (typeof shareCodeNeedRemoveStr === "string") { shareCodeNeedRemoveStr = [shareCodeNeedRemoveStr]; } if (Array.isArray(shareCodeNeedRemoveStr)) { // 字符串转正则 if (Array.isArray(netDiskRegularOption.shareCodeNeedRemoveStr)) { netDiskRegularOption.shareCodeNeedRemoveStr.length = 0; } else { netDiskRegularOption.shareCodeNeedRemoveStr = []; } for (let i = 0; i < shareCodeNeedRemoveStr.length; i++) { const shareCodeNeedRemoveStrItem = shareCodeNeedRemoveStr[i]; if (typeof shareCodeNeedRemoveStrItem === "string") { const shareCodeNeedRemoveStrItemRegExp = new RegExp(shareCodeNeedRemoveStrItem, "gi"); netDiskRegularOption.shareCodeNeedRemoveStr.push(shareCodeNeedRemoveStrItemRegExp); } } } } if (shareCodeNotMatch) { if (typeof shareCodeNotMatch === "string") { shareCodeNotMatch = [shareCodeNotMatch]; } if (Array.isArray(shareCodeNotMatch)) { // 字符串转正则 if (Array.isArray(netDiskRegularOption.shareCodeNotMatch)) { netDiskRegularOption.shareCodeNotMatch.length = 0; } else { netDiskRegularOption.shareCodeNotMatch = []; } for (let i = 0; i < shareCodeNotMatch.length; i++) { const shareCodeNotMatchItem = shareCodeNotMatch[i]; if (typeof shareCodeNotMatchItem === "string") { const shareCodeNotMatchItemRegExp = new RegExp(shareCodeNotMatchItem, "gi"); netDiskRegularOption.shareCodeNotMatch.push(shareCodeNotMatchItemRegExp); } } } } if (typeof checkAccessCode === "string") { netDiskRegularOption.checkAccessCode = new RegExp(checkAccessCode, "gi"); } if (typeof accessCode === "string") { netDiskRegularOption.accessCode = new RegExp(accessCode, "gi"); } if (acceesCodeNotMatch) { if (typeof acceesCodeNotMatch === "string") { acceesCodeNotMatch = [acceesCodeNotMatch]; } if (Array.isArray(acceesCodeNotMatch)) { // 字符串转正则 if (Array.isArray(netDiskRegularOption.acceesCodeNotMatch)) { netDiskRegularOption.acceesCodeNotMatch.length = 0; } else { netDiskRegularOption.acceesCodeNotMatch = []; } for (let i = 0; i < acceesCodeNotMatch.length; i++) { const acceesCodeNotMatchItem = acceesCodeNotMatch[i]; if (typeof acceesCodeNotMatchItem === "string") { const acceesCodeNotMatchItemRegExp = new RegExp(acceesCodeNotMatchItem, "gi"); netDiskRegularOption.acceesCodeNotMatch.push(acceesCodeNotMatchItemRegExp); } } } } if (accessCodeNeedRemoveStr) { if (typeof accessCodeNeedRemoveStr === "string") { accessCodeNeedRemoveStr = [accessCodeNeedRemoveStr]; } if (Array.isArray(accessCodeNeedRemoveStr)) { // 字符串转正则 if (Array.isArray(netDiskRegularOption.accessCodeNeedRemoveStr)) { netDiskRegularOption.accessCodeNeedRemoveStr.length = 0; } else { netDiskRegularOption.accessCodeNeedRemoveStr = []; } for (let i = 0; i < accessCodeNeedRemoveStr.length; i++) { const accessCodeNeedRemoveStrItem = accessCodeNeedRemoveStr[i]; if (typeof accessCodeNeedRemoveStrItem === "string") { const accessCodeNeedRemoveStrItemRegExp = new RegExp(accessCodeNeedRemoveStrItem, "gi"); netDiskRegularOption.accessCodeNeedRemoveStr.push(accessCodeNeedRemoveStrItemRegExp); } } } } if (typeof paramMatch === "string") { netDiskRegularOption.paramMatch = new RegExp(paramMatch, "i"); } return netDiskRegularOption; } let netDiskRuleConfigList: NetDiskRuleOption[] = []; // 遍历传入的规则 for (let i = 0; i < localRule.length; i++) { const userRuleItemConfig = localRule[i]; // 得配置全初始项 let netDiskRuleConfig: NetDiskRuleOption = { subscribeUUID: userRuleItemConfig.subscribeUUID, rule: [], setting: { name: userRuleItemConfig.setting.name, key: userRuleItemConfig.key, configurationInterface: >{ matchRange_text: {}, matchRange_html: {}, function: {}, linkClickMode_openBlank: {}, schemeUri: {}, ownFormList: [], }, }, isUserRule: true, afterRenderUrlBox: void 0, }; // 规则 const userRuleList = userRuleItemConfig.regexp; // 唯一键 const ruleKey = userRuleItemConfig.key; // 1. 转换rule if (Array.isArray(userRuleList)) { for (let i = 0; i < userRuleList.length; i++) { const userRuleItem = userRuleList[i]; netDiskRuleConfig.rule.push(parseUserRuleToScriptRule(ruleKey, userRuleItemConfig, userRuleItem)); } } else { netDiskRuleConfig.rule.push(parseUserRuleToScriptRule(ruleKey, userRuleItemConfig, userRuleList)); } // 2. 转换setting if (userRuleItemConfig.setting) { // 其它的规则,也就是界面设置的规则 // 是否启用,初始化默认值 this.initDefaultValue(NetDiskRuleDataKEY.function.enable(ruleKey), Boolean(userRuleItemConfig.setting.enable)); // 添加默认值 netDiskRuleConfig.setting!.configurationInterface!.function!.enable = Boolean( userRuleItemConfig.setting.enable ); if (typeof userRuleItemConfig.setting["isBlank"] === "boolean") { // 新标签页打开(旧) this.initDefaultValue(NetDiskRuleDataKEY.function.linkClickMode(ruleKey), "openBlank"); netDiskRuleConfig.setting!.configurationInterface!.function!.linkClickMode = { openBlank: { default: true, enable: true, }, }; } if (typeof userRuleItemConfig.setting.linkClickMode === "object") { // 点击动作 let data = utils.assign( NetDiskRuleUtils.getDefaultLinkClickMode(), userRuleItemConfig.setting.linkClickMode || {} ); let default_value: null | NetDiskRuleSettingConfigurationInterface_linkClickMode = null; let selectData: { value: string; text: string; }[] = []; const dataKeys = Object.keys(data); for (let i = 0; i < dataKeys.length; i++) { const keyName = dataKeys[i]; let itemData = data[keyName as keyof typeof data]; if (!itemData.enable) { continue; } if (itemData.default) { default_value = keyName as keyof typeof data; } selectData.push({ value: keyName, text: itemData.text!, }); } if (default_value == null) { // 直接取可选菜单的第一个值 default_value = selectData[0].value as NetDiskRuleSettingConfigurationInterface_linkClickMode; } this.initDefaultValue(NetDiskRuleDataKEY.function.linkClickMode(ruleKey), default_value); netDiskRuleConfig.setting!.configurationInterface!.function!.linkClickMode = data; } if (typeof userRuleItemConfig.setting["openBlankWithCopyAccessCode"] === "boolean") { // 跳转时复制访问码 this.initDefaultValue( NetDiskRuleDataKEY.linkClickMode_openBlank.openBlankWithCopyAccessCode(ruleKey), Boolean(userRuleItemConfig.setting["openBlankWithCopyAccessCode"]) ); netDiskRuleConfig.setting!.configurationInterface!.linkClickMode_openBlank!.openBlankWithCopyAccessCode = Boolean(userRuleItemConfig.setting["openBlankWithCopyAccessCode"]); } if (typeof userRuleItemConfig.setting["openBlankAutoFilleAccessCode"] === "boolean") { // 自动填充访问码 this.initDefaultValue( NetDiskRuleDataKEY.linkClickMode_openBlank.openBlankAutoFilleAccessCode(ruleKey), Boolean(userRuleItemConfig.setting["openBlankAutoFilleAccessCode"]) ); netDiskRuleConfig.setting.configurationInterface!.linkClickMode_openBlank!.openBlankAutoFilleAccessCode = Boolean(userRuleItemConfig.setting["openBlankAutoFilleAccessCode"]); } if (typeof userRuleItemConfig.setting["checkLinkValidity"] === "boolean") { // 用于验证链接有效性 this.initDefaultValue( NetDiskRuleDataKEY.function.checkLinkValidity(ruleKey), Boolean(userRuleItemConfig.setting["checkLinkValidity"]) ); netDiskRuleConfig.setting!.configurationInterface!.function!.checkLinkValidity = Boolean( userRuleItemConfig.setting["checkLinkValidity"] ); } if (typeof userRuleItemConfig.setting["checkLinkValidityHoverTip"] === "boolean") { // 用于验证链接有效性结果的悬停提示 this.initDefaultValue( NetDiskRuleDataKEY.function.checkLinkValidityHoverTip(ruleKey), Boolean(userRuleItemConfig.setting["checkLinkValidityHoverTip"]) ); } if (typeof userRuleItemConfig.setting["isForward"] === "boolean") { // 直接进行scheme转发链接 this.initDefaultValue( NetDiskRuleDataKEY.schemeUri.enable(ruleKey), Boolean(userRuleItemConfig.setting["isForward"]) ); netDiskRuleConfig.setting!.configurationInterface!.schemeUri!.enable = Boolean( userRuleItemConfig.setting["isForward"] ); } if (typeof userRuleItemConfig.setting["schemeUri"] === "string") { // scheme转发的字符串格式 this.initDefaultValue(NetDiskRuleDataKEY.schemeUri.uri(ruleKey), userRuleItemConfig.setting["schemeUri"]); netDiskRuleConfig.setting!.configurationInterface!.schemeUri!.uri = userRuleItemConfig.setting["schemeUri"]; } if (typeof userRuleItemConfig.setting["innerTextAccessCodeBeforeMaxRange"] === "number") { // text-提取码间隔前的字符长度 this.initDefaultValue( NetDiskRuleDataKEY.matchRange_text.before(ruleKey), userRuleItemConfig.setting["innerTextAccessCodeBeforeMaxRange"] ); netDiskRuleConfig.setting!.configurationInterface!.matchRange_text!.before = userRuleItemConfig.setting["innerTextAccessCodeBeforeMaxRange"]; } if (typeof userRuleItemConfig.setting["innerTextAccessCodeAfterMaxRange"] === "number") { // text-提取码间隔后的字符长度 this.initDefaultValue( NetDiskRuleDataKEY.matchRange_text.after(ruleKey), userRuleItemConfig.setting["innerTextAccessCodeAfterMaxRange"] ); netDiskRuleConfig.setting!.configurationInterface!.matchRange_text!.after = userRuleItemConfig.setting["innerTextAccessCodeAfterMaxRange"]; } if (typeof userRuleItemConfig.setting["innerHTMLAccessCodeBeforeMaxRange"] === "number") { // html-提取码间隔前的字符长度 this.initDefaultValue( NetDiskRuleDataKEY.matchRange_html.before(ruleKey), userRuleItemConfig.setting["innerHTMLAccessCodeBeforeMaxRange"] ); netDiskRuleConfig.setting!.configurationInterface!.matchRange_html!.before = userRuleItemConfig.setting["innerHTMLAccessCodeBeforeMaxRange"]; } if (typeof userRuleItemConfig.setting["innerHTMLAccessCodeAfterMaxRange"] === "number") { // html-提取码间隔后的字符长度 this.initDefaultValue( NetDiskRuleDataKEY.matchRange_html.after(ruleKey), userRuleItemConfig.setting["innerHTMLAccessCodeAfterMaxRange"] ); netDiskRuleConfig.setting!.configurationInterface!.matchRange_html!.after = userRuleItemConfig.setting["innerHTMLAccessCodeAfterMaxRange"]; } } // 3. 配置图标字典数据 if (typeof userRuleItemConfig.icon === "string") { // 配置图标 let ruleIcon = userRuleItemConfig.icon; NetDiskView.$inst.icon.addIcon(ruleKey, ruleIcon); } // 把规则的自定义解析函数进行转换 const toAsyncFunction = Object.getPrototypeOf(async function () {}).constructor; const toFunction = Object.getPrototypeOf(function () {}).constructor; if (typeof userRuleItemConfig.checkLinkValidityFunction === "string") { // 自定义校验链接有效性函数 try { let context = this.getBindContext(userRuleItemConfig); Reflect.set(NetDiskCheckLinkValidity.ruleCheckValidFunction, ruleKey, { init: new toAsyncFunction( "netDiskInfo", userRuleItemConfig.checkLinkValidityFunction // 绑定作用域 ).bind(context), }); } catch (error) { log.error(error); } } if (typeof userRuleItemConfig.accessCodeHandler === "string") { // 自定义处理提取码函数 try { const context = this.getBindContext(userRuleItemConfig); // 删除没必要的属性 // NetDiskCheckLinkValidity是有效性校验函数中需要的 Reflect.deleteProperty(context, "NetDiskCheckLinkValidity" as keyof typeof context); NetDiskHandlerAccessCodeRule[ruleKey] = new toAsyncFunction( userRuleItemConfig.accessCodeHandler, "netDiskInfo", "handlerConfig", "accessCode" ).bind( // 绑定作用域 context ); } catch (error) { log.error(error); } } if (typeof userRuleItemConfig.AuthorizationFunction === "string") { // 自定义鉴权函数 try { const context = this.getBindContext(userRuleItemConfig); // 删除没必要的属性 // NetDiskCheckLinkValidity是有效性校验函数中需要的,这里不需要 Reflect.deleteProperty(context, "NetDiskCheckLinkValidity" as keyof typeof context); NetDiskAuthorizationRule[ruleKey] = new toAsyncFunction(userRuleItemConfig.AuthorizationFunction).bind( // 绑定作用域 context ); } catch (error) { log.error(error); } } if (typeof userRuleItemConfig.AutoFillAccessCodeFunction === "string") { // 自定义填充访问码函数 try { const context = this.getBindContext(userRuleItemConfig); // 删除没必要的属性 // NetDiskCheckLinkValidity是有效性校验函数中需要的 Reflect.deleteProperty(context, "NetDiskCheckLinkValidity" as keyof typeof context); NetDiskAutoFillAccessCodeRule[ruleKey] = new toAsyncFunction( "netDiskInfo", userRuleItemConfig.AutoFillAccessCodeFunction // 绑定作用域 ).bind(context); } catch (error) { log.error(error); } } if (typeof userRuleItemConfig.parseFunction === "string") { // 自定义文件解析函数 try { const context = this.getBindContext(userRuleItemConfig); // 删除没必要的属性 // NetDiskCheckLinkValidity是有效性校验函数中需要的 Reflect.deleteProperty(context, "NetDiskCheckLinkValidity" as keyof typeof context); const tofn: () => any = new toFunction(userRuleItemConfig.parseFunction).bind(context); const fn: Function | object = tofn(); const target = class Parser extends ParseFileCore { async init(netDiskInfo: ParseFileInitConfig) { super.init(netDiskInfo); if (typeof fn === "object" && fn != null) { // @ts-expect-error return await fn.init.bind(context)(netDiskInfo); } else if (typeof fn === "function") { // 先new // @ts-expect-error const __fn__: Function = new fn(netDiskInfo); // @ts-expect-error return await __fn__.init.bind(context)(netDiskInfo); } else { log.error({ parserFunctionResult: fn, parserFunction: userRuleItemConfig.parseFunction, }); Qmsg.error("解析函数的返回值的类型错误"); } } }; Reflect.set(NetDiskParseRule, ruleKey, target); } catch (error) { log.error(error); } } if (typeof userRuleItemConfig.afterRenderUrlBox === "string") { // 渲染后的链接元素触发的回调 try { const context = this.getBindContext(userRuleItemConfig); // 删除没必要的属性 // NetDiskCheckLinkValidity是有效性校验函数中需要的 Reflect.deleteProperty(context, "NetDiskCheckLinkValidity" as keyof typeof context); netDiskRuleConfig.afterRenderUrlBox = new toAsyncFunction( "option", userRuleItemConfig.afterRenderUrlBox // 绑定作用域 ).bind(context); } catch (error) { log.error(error); } } // 检测已处理的规则中是否存在重复key的规则 // 存在 => 追加新的rule let findValue = netDiskRuleConfigList.find((item) => item.setting.key === netDiskRuleConfig.setting.key); if (findValue) { // 已存在相同key规则,追加新的 findValue.rule = findValue.rule.concat(netDiskRuleConfig.rule); } else { netDiskRuleConfigList.push(netDiskRuleConfig); } } return netDiskRuleConfigList; }, /** * 获取配置 */ getNetDiskRuleConfig() { return this.$data.userRule.values(); }, /** * 初始化默认值 */ initDefaultValue(key: string, value?: any) { let localValue = GM_getValue(key); if (localValue == null) { GM_setValue(key, value); } }, /** * 获取模板规则 */ getTemplateRule() { const templateRule = { key: "规则名", icon: "图标链接字符串或图片的base64字符串", regexp: [ { link_innerText: "", link_innerHTML: "", shareCode: "", shareCodeNeedRemoveStr: "", uiLinkShow: "", blank: "", copyUrl: "", }, ], setting: { name: "设置界面的名字", enable: true, linkClickMode: "openBlank", openBlankWithCopyAccessCode: true, }, }; return templateRule; }, /** * 获取规则面板视图的配置 * @param quickAddData 用于快速添加数据 */ getRulePanelViewOption(quickAddData?: NetDiskUserCustomRule) { const addData = () => { return quickAddData ?? this.getTemplateRule(); }; const rulePanelViewOption: RulePanelContentOption = { id: "user-rule", title: "链接识别", headerTitle: "链接识别规则", ruleOption: { btnControls: { add: { enable: true, callback(option) { NetDiskUserRuleUI.show(false, void 0, () => { this.updateRuleContaienrElement(rulePanelViewOption.ruleOption, void 0, option.$section); }); return false; }, }, filter: { enable: true, option: [ { name: "全部", value: "", selectedCallBack() { // GM_setValue("customRule-search-before-selectedOptionValue", config.value); }, filterCallBack() { return true; }, }, { name: "已启用", value: "enable", selectedCallBack() { // GM_setValue("customRule-search-before-selectedOptionValue", config.value); }, filterCallBack(data) { return data.setting.enable; }, }, { name: "未启用", value: "notEnable", selectedCallBack() { // GM_setValue("customRule-search-before-selectedOptionValue", config.value); }, filterCallBack(data) { return !data.setting.enable; }, }, ], inputOption: [ { name: "规则名", value: "name", selectedCallBack() { // GM_setValue("customRule-search-selectedOptionValue", config.value); }, filterCallBack(data, searchText) { return Boolean(data.setting.name.match(searchText)); }, }, { name: "键", value: "key", selectedCallBack() { // GM_setValue("customRule-search-selectedOptionValue", config.value); }, filterCallBack(data, searchText) { return Boolean(data.key.match(searchText)); }, }, ], }, clearAll: { enable: true, callback: () => { this.clearRule(); }, }, import: { enable: true, callback: (updateView) => { this.importRule(() => { updateView(); }); }, }, export: { enable: true, callback: () => { this.exportRule(SCRIPT_NAME + "-链接识别规则.json", SCRIPT_NAME + "-链接识别规则-订阅模式.json"); }, }, ruleEdit: { enable: true, callback(option) { NetDiskUserRuleUI.show(true, option.ruleData.key, async (rule) => { let $ruleItem = await option.context.updateRuleItemElement( option.option, option.subscribeOption, rule, option.$ruleItem, option.$section ); option.$ruleItem = $ruleItem; }); return false; }, }, ruleDelete: { enable: true, deleteCallBack: (data) => { return this.deleteRule(data.key); }, }, }, data: () => { return this.getAllRule(); }, getAddData: () => { return addData(); }, getData: (data) => { let allData = this.getAllRule(); let findValue = allData.find((item) => item.key === data.key); return findValue ?? data; }, getDataItemName: (data) => { return data.setting.name; }, updateData: (data) => { return this.updateRule(data.key, data); }, deleteData: (data) => { return this.deleteRule(data.key); }, }, subscribe: { enable: true, data() { return NetDiskUserRuleSubscribeRule.getAllSubscribe(); }, getData: (data) => { let findValue = NetDiskUserRuleSubscribeRule.getSubscribe(data.uuid); return findValue ?? data; }, getDataItemName(subscribeOption) { return /*html*/ ` `; }, addData: (data) => { return NetDiskUserRuleSubscribeRule.addSubscribe(data); }, updateData: (data) => { return NetDiskUserRuleSubscribeRule.updateSubscribe(data); }, deleteData: (data) => { return NetDiskUserRuleSubscribeRule.deleteSubscribe(data); }, btnControls: { add: { enable: true, }, filter: { enable: true, option: [ { name: "全部", value: "", selectedCallBack() { // GM_setValue("customRule-subscribe-search-before-selectedOptionValue", config.value); }, filterCallBack() { return true; }, }, { name: "已启用", value: "enable", selectedCallBack() { // GM_setValue("customRule-subscribe-search-before-selectedOptionValue", config.value); }, filterCallBack(data) { return data.data.enable; }, }, { name: "未启用", value: "notEnable", selectedCallBack() { // GM_setValue("customRule-subscribe-search-before-selectedOptionValue", config.value); }, filterCallBack(data) { return !data.data.enable; }, }, ], inputOption: [ { name: "标题", value: "name", selectedCallBack() { // GM_setValue("customRule-subscribe-search-selectedOptionValue", config.value); }, filterCallBack(data, searchText) { let flag = false; if (typeof data.data.title === "string") { flag = Boolean(data.data.title.match(searchText)); } if (!flag && typeof data.subscribeData.title === "string") { flag = Boolean(data.subscribeData.title.match(searchText)); } return flag; }, }, { name: "订阅地址", value: "url", selectedCallBack() { // GM_setValue("customRule-subscribe-search-selectedOptionValue", config.value); }, filterCallBack(data, searchText) { return Boolean(data.data.url.match(searchText)); }, }, ], }, clearAll: { enable: true, callback: () => { NetDiskUserRuleSubscribeRule.deleteAllSubscribe(); }, }, ruleEnable: { enable: true, getEnable(data) { return data.data.enable; }, async callback(data, enable) { data.data.enable = enable; NetDiskUserRuleSubscribeRule.updateSubscribe(data); }, }, ruleEdit: { enable: true, callback: (option) => { let subscribeUUID = option.ruleData.uuid; option.enterDeepMenu({ headerTitle: // 自己重新命名的 option.ruleData.data.title || // 订阅的规则自带的 option.ruleData.subscribeData.title || // 订阅的链接 option.ruleData.data.url, data() { let currentData = NetDiskUserRuleSubscribeRule.getSubscribe(subscribeUUID); return currentData?.subscribeData?.ruleData ?? option.ruleData.subscribeData.ruleData; }, getData(data) { let currentData = NetDiskUserRuleSubscribeRule.getSubscribeRule(subscribeUUID, data.key); return currentData ?? data; }, getDataItemName(data) { return data.setting.name; }, addData() { // TODO return true; }, updateData(data) { return NetDiskUserRuleSubscribeRule.updateSubscribeRule(subscribeUUID, data); }, deleteData(data) { return NetDiskUserRuleSubscribeRule.deleteSubscribeRule(subscribeUUID, data); }, btnControls: { filter: { enable: true, option: [ { name: "全部", value: "", selectedCallBack() { // GM_setValue("customRule-subscribeData-search-before-selectedOptionValue", config.value); }, filterCallBack() { return true; }, }, { name: "已启用", value: "enable", selectedCallBack() { // GM_setValue("customRule-subscribeData-search-before-selectedOptionValue", config.value); }, filterCallBack(data) { return data.setting.enable; }, }, { name: "未启用", value: "notEnable", selectedCallBack() { // GM_setValue("customRule-subscribeData-search-before-selectedOptionValue", config.value); }, filterCallBack(data) { return !data.setting.enable; }, }, ], inputOption: [ { name: "规则名", value: "name", selectedCallBack() { // GM_setValue("customRule-subscribeData-search-selectedOptionValue", config.value); }, filterCallBack(data, searchText) { return Boolean(data.setting.name.match(searchText)); }, }, { name: "键", value: "key", selectedCallBack() { // GM_setValue("customRule-subscribeData-search-selectedOptionValue", config.value); }, filterCallBack(data, searchText) { return Boolean(data.key.match(searchText)); }, }, ], }, clearAll: { enable: true, callback: () => { NetDiskUserRuleSubscribeRule.clearSubscribe(subscribeUUID); }, }, ruleEdit: { enable: true, callback(option) { NetDiskUserRuleUI.showSubscribe(subscribeUUID, option.ruleData.key, async (subscribeRule) => { // 更新视图 const $ruleItem = await option.context.updateRuleItemElement( option.option, option.subscribeOption, subscribeRule, option.$ruleItem, option.$section ); option.$ruleItem = $ruleItem; }); return false; }, }, ruleDelete: { enable: true, deleteCallBack(data) { return NetDiskUserRuleSubscribeRule.deleteSubscribeRule(subscribeUUID, data); }, }, }, }); return false; }, }, ruleDelete: { enable: true, deleteCallBack: (data) => { return NetDiskUserRuleSubscribeRule.deleteSubscribe(data); }, }, import: { enable: true, callback(updateView) { NetDiskUserRuleSubscribeRule.importSubscribe(() => { updateView(); }); }, }, export: { enable: true, callback() { NetDiskUserRuleSubscribeRule.exportSubscribe(SCRIPT_NAME + "-网站规则-订阅.json"); }, }, }, getSubscribeInfo: NetDiskUserRuleSubscribeRule.getSubscribeInfo.bind(NetDiskUserRuleSubscribeRule), }, }; return rulePanelViewOption; }, /** * 添加规则 * @param userRule */ addRule(userRule: NetDiskUserCustomRule) { const localRule = this.getAllRule(); localRule.push(userRule); this.setRule(localRule); }, /** * 设置规则到本地 * @param oldRuleKey 旧规则的键名 * @param userRule */ setRule(userRule: NetDiskUserCustomRule[] | NetDiskUserCustomRule) { userRule = Array.isArray(userRule) ? userRule : [userRule]; NetDiskUserRuleStorageApi.set(this.$data.STORAGE_KEY, userRule); }, /** * 更新规则 */ updateRule(key: string, rule: NetDiskUserCustomRule) { const localRule = this.getAllRule(); const findRuleIndex = localRule.findIndex((item) => item.key === key); if (findRuleIndex !== -1) { localRule.splice(findRuleIndex, 1, rule); this.setRule(localRule); return true; } else { return false; } }, /** * 删除单条规则 * @param ruleKey 规则的key名 */ deleteRule(ruleKey: string) { const localRule = this.getAllRule(); const findIndex = localRule.findIndex((rule) => rule.key === ruleKey); if (findIndex !== -1) { localRule.splice(findIndex, 1); this.setRule(localRule); return true; } else { return false; } }, /** * 清空规则 */ clearRule() { NetDiskUserRuleStorageApi.delete(this.$data.STORAGE_KEY); }, /** * 获取本地所有的规则 */ getAllRule() { const result = NetDiskUserRuleStorageApi.get(this.$data.STORAGE_KEY, []); return result; }, /** * 获取规则 */ getRule(key: string) { const localRule = this.getAllRule(); return localRule.find((item) => item.key === key); }, /** * 获取格式化后的规则 * @param rule */ getFormatRule(rule?: NetDiskUserCustomRule) { return JSON.stringify(rule || this.getAllRule(), void 0, 4); }, /** * 导出规则 */ exportRule(fileName = "rule.json", subscribeFileName = "rule-subscribe.json") { const $alert = NetDiskPops.alert({ title: { text: "请选择导出方式", position: "center", }, content: { text: /*html*/ `
导出规则
导出订阅规则
`, html: true, }, btn: { ok: { enable: false }, close: { enable: true, callback(details) { details.close(); }, }, }, mask: { enable: true }, drag: true, width: PanelUISize.info.width, height: PanelUISize.info.height, style: /*css*/ ` .btn-control{ display: inline-block; margin: 10px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; cursor: pointer; } .btn-control:hover{ color: #409eff; border-color: #c6e2ff; background-color: #ecf5ff; }`, }); /** 仅导出规则 */ const $onlyExportRuleList = $alert.$shadowRoot.querySelector( ".btn-control[data-mode='only-export-rule-list']" )!; /** 导出为订阅规则 */ const $exportToSubscribe = $alert.$shadowRoot.querySelector( ".btn-control[data-mode='export-to-subscribe']" )!; /** * 导出文件 */ const exportFile = (__fileName__: string, __data__: any) => { const blob = new Blob([JSON.stringify(__data__, null, 4)]); const blobUrl = window.URL.createObjectURL(blob); const $a = document.createElement("a"); $a.href = blobUrl; $a.download = __fileName__; $a.click(); setTimeout(() => { window.URL.revokeObjectURL(blobUrl); }, 1500); }; // 仅导出规则 DOMUtils.on($onlyExportRuleList, "click", (event) => { DOMUtils.preventEvent(event); try { const allRule = this.getAllRule(); if (allRule.length === 0) { Qmsg.warning("规则为空,无需导出"); return; } exportFile(fileName, allRule); $alert.close(); } catch (error: any) { Qmsg.error(error.toString(), { consoleLogContent: true }); } }); // 导出为订阅规则 DOMUtils.on($exportToSubscribe, "click", (event) => { DOMUtils.preventEvent(event); $alert.close(); try { const allRule = this.getAllRule(); if (allRule.length === 0) { Qmsg.warning("规则为空,无需导出"); return; } const panelHandlerComponents = pops.fn.PanelHandlerComponents(); /** * 自定义存储api的配置 * @param uuid */ const generateStorageApi = function (data: any) { return { get(key: string, defaultValue: any) { return data[key] ?? defaultValue; }, set: (key: string, value: any) => { data[key] = value; NetDiskUserRuleStorageApi.set(NetDiskUserRule.$data.EXPORT_CONFIG_KEY, data); }, }; }; /** * 按下导出的按钮的回调 */ const exportCallBack = () => { const configData = NetDiskUserRuleStorageApi.get< Partial["subscribeData"]> >(this.$data.EXPORT_CONFIG_KEY, {}); if (configData?.title === "" || configData.title == null) { Qmsg.error("订阅标题不能为空"); return; } if (configData.version == null) { Qmsg.error("版本号不能为空"); return; } else { configData.version = Number(configData.version); } if (configData.homePage == null) { configData.homePage = void 0; } configData.lastModified = Date.now(); configData.ruleData = this.getAllRule(); exportFile(subscribeFileName, configData); $exportSubscribeDialog.close(); }; const $exportSubscribeDialog = NetDiskPops.alert({ title: { text: "请填写导出配置", position: "center", }, content: { text: /*html*/ ` `, html: true, }, btn: { ok: { enable: true, text: "导出", callback() { exportCallBack(); }, }, close: { enable: true, callback(details) { details.close(); }, }, }, mask: { enable: true, }, drag: true, width: PanelUISize.info.width, height: PanelUISize.info.height, style: /*css*/ ` ${pops.config.cssText.panelCSS} .pops-alert-content li{ list-style-type: none; display: flex; align-items: center; justify-content: space-between; margin: 10px; } `, }); const $content = $exportSubscribeDialog.$shadowRoot.querySelector(".pops-alert-content")!; const configData = NetDiskUserRuleStorageApi.get< Partial["subscribeData"]> >(this.$data.EXPORT_CONFIG_KEY, {}); // 订阅名称 const title_template = UIInput("订阅标题", "title", ""); Reflect.set(title_template.props!, PROPS_STORAGE_API, generateStorageApi(configData)); const $title = panelHandlerComponents.createSectionContainerItem_input(title_template).$el; // 版本号 const version_template = UIInput("版本号", "version", ""); Reflect.set(version_template.props!, PROPS_STORAGE_API, generateStorageApi(configData)); const $version = panelHandlerComponents.createSectionContainerItem_input(version_template).$el; // 主页地址 const homePage_template = UIInput("主页地址", "homePage", "", "", void 0, "选填"); Reflect.set(homePage_template.props!, PROPS_STORAGE_API, generateStorageApi(configData)); const $homePage = panelHandlerComponents.createSectionContainerItem_input(homePage_template).$el; DOMUtils.append($content, $title); DOMUtils.append($content, $version); DOMUtils.append($content, $homePage); } catch (error: any) { Qmsg.error(error.toString(), { consoleLogContent: true }); } }); }, /** * 导入规则 * @param importEndCallBack 导入完毕后的回调 */ importRule(importEndCallBack?: () => void) { const $alert = NetDiskPops.alert({ title: { text: "请选择导入方式", position: "center", }, content: { text: /*html*/ `
本地导入
网络导入
剪贴板导入
`, html: true, }, btn: { ok: { enable: false }, close: { enable: true, callback(details) { details.close(); }, }, }, mask: { enable: true }, drag: true, width: PanelUISize.info.width, height: PanelUISize.info.height, style: /*css*/ ` .btn-control{ display: inline-block; margin: 10px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; cursor: pointer; } .btn-control:hover{ color: #409eff; border-color: #c6e2ff; background-color: #ecf5ff; } `, }); /** 本地导入 */ const $local = $alert.$shadowRoot.querySelector(".btn-control[data-mode='local']")!; /** 网络导入 */ const $network = $alert.$shadowRoot.querySelector(".btn-control[data-mode='network']")!; /** 剪贴板导入 */ const $clipboard = $alert.$shadowRoot.querySelector(".btn-control[data-mode='clipboard']")!; /** * 将获取到的规则更新至存储 */ const updateRuleToStorage = (data: NetDiskUserCustomRule[]) => { let allData = this.getAllRule(); const addNewData: typeof allData = []; for (let index = 0; index < data.length; index++) { const dataItem = data[index]; let findIndex = allData.findIndex((it) => it.key === dataItem.key); if (findIndex !== -1) { // 存在相同的规则 } else { // 追加 addNewData.push(dataItem); } } allData = allData.concat(addNewData); if (addNewData.length) { NetDiskUserRuleStorageApi.set(this.$data.STORAGE_KEY, allData); log.info("新增的规则:", addNewData); Qmsg.success(`共 ${data.length} 条规则,新增 ${addNewData.length} 条`); } else { Qmsg.error("未新增规则,请删除旧规则再重新导入"); } importEndCallBack?.(); }; /** * @param subscribeText 订阅文件文本 */ const importFile = (subscribeText: string) => { return new Promise((resolve) => { let data: NetDiskUserCustomRule[] | NetDiskUserCustomRule = utils.toJSON(subscribeText); if (Array.isArray(data)) { if (!data.length) { Qmsg.error("导入失败,解析出的数据为空", { consoleLogContent: true, }); resolve(false); return; } } else { // 单个规则 data = [data]; } const checkedData: NetDiskUserCustomRule[] = []; for (let index = 0; index < data.length; index++) { const dataItem = data[index]; const parseResult = this.parseRuleStrToRule(dataItem); if (!parseResult.success) { if (data.length === 1) { Qmsg.error(parseResult.msg, { timeout: 4000 }); return; } continue; } if (parseResult.data) { checkedData.push(parseResult.data); } } const notCheckedRuleCount = data.length - checkedData.length; if (notCheckedRuleCount > 0) { if (notCheckedRuleCount === data.length) { Qmsg.error("所有规则均未通过规则检查,请检查规则", { timeout: 4000, }); } else { Qmsg.warning(`检测到有 ${notCheckedRuleCount}条未通过规则检查的规则,已忽略`, { timeout: 4000, }); } } if (!checkedData.length) { return; } updateRuleToStorage(checkedData); resolve(true); }); }; // 本地导入 DOMUtils.on($local, "click", (event) => { DOMUtils.preventEvent(event); $alert.close(); const $input = DOMUtils.createElement("input", { type: "file", accept: ".json", }); DOMUtils.on($input, ["propertychange", "input"], () => { if (!$input.files?.length) { return; } const uploadFile = $input.files![0]; const fileReader = new FileReader(); fileReader.onload = () => { importFile(fileReader.result as string); }; fileReader.readAsText(uploadFile, "UTF-8"); }); $input.click(); }); // 网络导入 DOMUtils.on($network, "click", (event) => { DOMUtils.preventEvent(event); $alert.close(); const $prompt = NetDiskPops.prompt({ title: { text: "网络导入", position: "center", }, content: { text: "", placeholder: "请填写URL", focus: true, }, btn: { close: { enable: true, callback(details) { details.close(); }, }, ok: { text: "导入", callback: async (eventDetails) => { const url = eventDetails.text; if (utils.isNull(url)) { Qmsg.error("请填入完整的url"); return; } const $loading = Qmsg.loading("正在获取配置..."); const response = await httpx.get(url, { allowInterceptConfig: false, }); $loading.close(); if (!response.status) { log.error(response); Qmsg.error("获取配置失败", { consoleLogContent: true }); return; } const flag = await importFile(response.data.responseText); if (!flag) { return; } eventDetails.close(); }, }, cancel: { enable: false, }, }, mask: { enable: true }, drag: true, width: PanelUISize.info.width, height: "auto", }); const $promptInput = $prompt.$shadowRoot.querySelector("input")!; const $promptOk = $prompt.$shadowRoot.querySelector(".pops-prompt-btn-ok")!; DOMUtils.on($promptInput, ["input", "propertychange"], () => { const value = DOMUtils.val($promptInput); if (value === "") { DOMUtils.attr($promptOk, "disabled", "true"); } else { DOMUtils.removeAttr($promptOk, "disabled"); } }); DOMUtils.onKeyboard($promptInput, "keydown", (keyName, keyValue, otherCodeList) => { if (keyName === "Enter" && otherCodeList.length === 0) { const value = DOMUtils.val($promptInput); if (value !== "") { DOMUtils.emit($promptOk, "click"); } } }); DOMUtils.emit($promptInput, "input"); }); // 剪贴板导入 DOMUtils.on($clipboard, "click", async (event) => { DOMUtils.preventEvent(event); $alert.close(); const clipboardInfo = await utils.getClipboardInfo(); if (clipboardInfo.error != null) { Qmsg.error(clipboardInfo.error.toString()); return; } if (clipboardInfo.content.trim() === "") { Qmsg.warning("获取到的剪贴板内容为空"); return; } const flag = await importFile(clipboardInfo.content); if (!flag) { return; } }); }, };