您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动登录账号、快捷寻找自己库被其他脚本引用、更新自己的脚本列表、库、优化图片浏览、美化页面、Markdown复制按钮
当前为
- // ==UserScript==
- // @name GreasyFork优化
- // @name:en-US GreasyFork Optimization
- // @namespace https://github.com/WhiteSevs/TamperMonkeyScript
- // @version 2024.7.23
- // @author WhiteSevs
- // @description 自动登录账号、快捷寻找自己库被其他脚本引用、更新自己的脚本列表、库、优化图片浏览、美化页面、Markdown复制按钮
- // @description:en-US Automatically log in to the account, quickly find your own library referenced by other scripts, update your own script list, library, optimize image browsing, beautify the page, Markdown copy button
- // @license GPL-3.0-only
- // @icon data:image/png;base64,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
- // @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues
- // @match *://greasyfork.org/*
- // @require https://update.greasyfork.org/scripts/494167/1413255/CoverUMD.js
- // @require https://fastly.jsdelivr.net/npm/qmsg@1.2.1/dist/index.umd.js
- // @require https://fastly.jsdelivr.net/npm/@whitesev/utils@1.9.3/dist/index.umd.js
- // @require https://fastly.jsdelivr.net/npm/@whitesev/domutils@1.1.2/dist/index.umd.js
- // @require https://fastly.jsdelivr.net/npm/@whitesev/pops@1.4.0/dist/index.umd.js
- // @require https://fastly.jsdelivr.net/npm/viewerjs@1.11.6/dist/viewer.min.js
- // @require https://fastly.jsdelivr.net/npm/i18next@23.12.2/i18next.min.js
- // @resource ViewerCSS https://fastly.jsdelivr.net/npm/viewerjs@1.11.6/dist/viewer.min.css
- // @connect greasyfork.org
- // @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
- // ==/UserScript==
- (t=>{function d(n){if(typeof n!="string")throw new TypeError("cssText must be a string");let e=document.createElement("style");return e.setAttribute("type","text/css"),e.innerHTML=n,document.head?document.head.appendChild(e):document.body?document.body.appendChild(e):document.documentElement.childNodes.length===0?document.documentElement.appendChild(e):document.documentElement.insertBefore(e,document.documentElement.childNodes[0]),e}if(typeof GM_addStyle=="function"){GM_addStyle(t);return}d(t)})(" .whitesev-hide{display:none}.whitesev-hide-important{display:none!important} ");
- (function (Qmsg, DOMUtils, Utils, i18next, pops, Viewer) {
- 'use strict';
- 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);
- var _a;
- var _GM_addStyle = /* @__PURE__ */ (() => typeof GM_addStyle != "undefined" ? GM_addStyle : 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 zh_CN_language = {
- GreasyFork优化: "GreasyFork优化",
- 请求取消: "请求取消",
- 请求超时: "请求超时",
- 请求异常: "请求异常",
- 通用: "通用",
- 账号: "账号",
- 密码: "密码",
- 语言: "语言",
- "账号/密码": "账号/密码",
- 请输入账号: "请输入账号",
- 请输入密码: "请输入密码",
- 自动登录: "自动登录",
- 自动登录当前保存的账号: "自动登录当前保存的账号",
- "清空账号/密码": "清空账号/密码",
- 点击清空: "点击清空",
- "确定清空账号和密码?": "确定清空账号和密码?",
- "已清空账号/密码": "已清空账号/密码",
- "源代码同步【脚本列表】": "源代码同步【脚本列表】",
- 一键同步: "一键同步",
- 前往用户主页: "前往用户主页",
- 获取当前已登录的用户主页失败: "获取当前已登录的用户主页失败",
- "源代码同步【未上架的脚本】": "源代码同步【未上架的脚本】",
- "源代码同步【库】": "源代码同步【库】",
- 论坛: "论坛",
- 功能: "功能",
- 过滤重复的评论: "过滤重复的评论",
- "过滤掉重复的评论数量(≥2)": "过滤掉重复的评论数量(≥2)",
- "过滤脚本(id)": "过滤脚本(id)",
- "请输入脚本id,每行一个": "请输入脚本id,每行一个",
- "过滤发布的用户(id)": "过滤发布的用户(id)",
- "请输入用户id,每行一个": "请输入用户id,每行一个",
- "过滤回复的用户(id)": "过滤回复的用户(id)",
- 优化: "优化",
- 固定当前语言: "固定当前语言",
- 无: "无",
- "如button、input、textarea": "如button、input、textarea",
- 更直观的查看版本迭代: "更直观的查看版本迭代",
- 美化上传图片按钮: "美化上传图片按钮",
- 放大上传区域: "放大上传区域",
- 优化图片浏览: "优化图片浏览",
- 使用Viewer浏览图片: "使用Viewer浏览图片",
- 覆盖图床图片跳转: "覆盖图床图片跳转",
- "配合上面的【优化图片浏览】更优雅浏览图片": "配合上面的【优化图片浏览】更优雅浏览图片",
- '需安装Greasyfork Beautify脚本,<a href="https://greasyfork.org/zh-CN/scripts/446849-greasyfork-beautify" target="_blank">🖐点我安装</a>': '需安装Greasyfork Beautify脚本,<a href="https://greasyfork.org/zh-CN/scripts/446849-greasyfork-beautify" target="_blank">🖐点我安装</a>',
- 代码: "代码",
- 添加复制代码按钮: "添加复制代码按钮",
- 更优雅的复制: "更优雅的复制",
- 快捷键: "快捷键",
- "【F】键全屏、【Alt+Shift+F】键宽屏": "【F】键全屏、【Alt+Shift+F】键宽屏",
- 库: "库",
- 脚本列表: "脚本列表",
- "请输入屏蔽规则,每行一个": "请输入屏蔽规则,每行一个",
- 请求admin内容失败: "请求admin内容失败",
- 解析admin的源代码同步表单失败: "解析admin的源代码同步表单失败",
- 源代码同步失败: "源代码同步失败",
- 获取用户信息失败: "获取用户信息失败",
- 获取用户的收藏集失败: "获取用户的收藏集失败",
- "解析Script Sets失败": "解析Script Sets失败",
- "获取收藏集{{setsId}}失败": "获取收藏集{{setsId}}失败",
- "获取表单元素#edit_script_set失败": "获取表单元素#edit_script_set失败",
- 更新收藏集表单请求失败: "更新收藏集表单请求失败",
- 请先在菜单中录入账号: "请先在菜单中录入账号",
- 请先在菜单中录入密码: "请先在菜单中录入密码",
- "获取csrf-token失败": "获取csrf-token失败",
- "正在登录中...": "正在登录中...",
- "登录失败,请在控制台查看原因": "登录失败,请在控制台查看原因",
- "登录成功,1s后自动跳转": "登录成功,1s后自动跳转",
- "登录失败,可能是账号/密码错误,请在控制台查看原因": "登录失败,可能是账号/密码错误,请在控制台查看原因",
- "美化 历史版本 页面": "美化 历史版本 页面",
- 未找到history_versions元素列表: "未找到history_versions元素列表",
- "yyyy年MM月dd日 HH:mm:ss": "yyyy-MM-dd HH:mm:ss",
- "美化 Greasyfork Beautify脚本": "美化 Greasyfork Beautify脚本",
- "❌ 最多同时长传5张图": "❌ 最多同时长传5张图片",
- "❌ 图片:{{name}} 大小:{{size}}": "❌ 图片:{{name}} 大小:{{size}}",
- "已过滤:{{oldCount}}": "已过滤:{{oldCount}}",
- 寻找引用: "寻找引用",
- 获取脚本id失败: "获取脚本id失败",
- 收藏: "收藏",
- 请先登录账号: "请先登录账号",
- 获取用户id失败: "获取用户id失败",
- "获取收藏夹中...": "获取收藏夹中...",
- 收藏集: "收藏集",
- "添加中...": "添加中...",
- "添加失败,{{selector}}元素不存在": "添加失败,{{selector}}元素不存在",
- "未找到{{selector}}元素": "未找到{{selector}}元素",
- 添加失败: "添加失败",
- 添加成功: "添加成功",
- "删除中...": "删除中...",
- 删除成功: "删除成功",
- 添加: "添加",
- 刪除: "刪除",
- "拦截跳转:": "拦截跳转:",
- 今日检查: "今日检查",
- 复制代码: "复制代码",
- "加载文件中...": "加载文件中...",
- 复制成功: "复制成功",
- "✅ 复制成功!": "✅ 复制成功!",
- "当前语言:{{currentLocaleLanguage}},,3秒后切换至:{{localeLanguage}}": "当前语言:{{currentLocaleLanguage}},,3秒后切换至:{{localeLanguage}}",
- "导航至:": "导航至:",
- "请先登录账号!": "请先登录账号!",
- "获取信息中,请稍后...": "获取信息中,请稍后...",
- "获取成功,共 {{count}} 个": "获取成功,共 {{count}} 个",
- "评分:": "评分:",
- "语言:": "语言:",
- "版本:": "版本:",
- "更新:": "更新:",
- 同步代码: "同步代码",
- "同步中...": "同步中...",
- 手动: "手动",
- 自动: "自动",
- "同步方式:{{syncMode}}": "同步方式:{{syncMode}}",
- 同步成功: "同步成功",
- 同步失败: "同步失败",
- 该脚本未设置同步信息: "该脚本未设置同步信息",
- "上次重载时间 {{time}},{{timeout}}秒内拒绝反复重载": "上次重载时间 {{time}},{{timeout}}秒内拒绝反复重载",
- "名称:": "名称:",
- "进度:": "进度:",
- "未获取到【脚本列表】": "未获取到【脚本列表】",
- "源代码同步成功,3秒后更新下一个": "源代码同步成功,3秒后更新下一个",
- 全部更新失败: "全部更新失败",
- "全部更新完毕<br >成功:{{successNums}}<br >失败:{{failedNums}}<br >总计:{{scriptUrlListLength}}": "全部更新完毕<br >成功:{{successNums}}<br >失败:{{failedNums}}<br >总计:{{scriptUrlListLength}}",
- "⚙ 设置": "⚙ 设置",
- "{{SCRIPT_NAME}}-设置": "{{SCRIPT_NAME}}-设置",
- 美化页面元素: "美化页面元素",
- 美化历史版本页面: "美化历史版本页面",
- "美化Greasyfork Beautify脚本": "美化Greasyfork Beautify脚本",
- 获取表单csrfToken失败: "获取表单csrfToken失败",
- Toast配置: "Toast配置",
- Toast位置: "Toast位置",
- 左上角: "左上角",
- 顶部: "顶部",
- 右上角: "右上角",
- 左边: "左边",
- 中间: "中间",
- 右边: "右边",
- 左下角: "左下角",
- 底部: "底部",
- 右下角: "右下角",
- Toast显示在页面九宫格的位置: "Toast显示在页面九宫格的位置",
- 最多显示的数量: "最多显示的数量",
- 限制Toast显示的数量: "限制Toast显示的数量",
- 逆序弹出: "逆序弹出",
- 修改Toast弹出的顺序: "修改Toast弹出的顺序",
- 该脚本已经在该收藏集中: "该脚本已经在该收藏集中",
- 其它错误: "其它错误",
- 启用: "启用",
- 开启后下面的过滤功能才会生效: "开启后下面的功能才会生效",
- 屏蔽脚本: "屏蔽脚本",
- 点击查看规则: "点击查看规则",
- 过滤: "过滤",
- 代码同步: "代码同步",
- 美化: "美化",
- 修复代码行号显示: "修复代码行号显示",
- 修复代码行数超过1k行号显示不全问题: "修复代码行数超过1k行号显示不全问题",
- "添加【寻找引用】按钮": "添加【寻找引用】按钮",
- "在脚本栏添加按钮,一般用于搜索引用该库的相关脚本": "在脚本栏添加按钮,一般用于搜索引用该库的相关脚本",
- "添加【收藏】按钮": "添加【收藏】按钮",
- "在脚本栏添加按钮,一般用于快捷收藏该脚本/库": "在脚本栏添加按钮,一般用于快捷收藏该脚本/库",
- 修复图片宽度显示问题: "修复图片宽度显示问题",
- 修复图片在移动端宽度超出浏览器宽度问题: "修复图片在移动端宽度超出浏览器宽度问题",
- "添加【今日检查】信息块": "添加【今日检查】信息块",
- "在脚本信息栏添加【今日检查】信息块": "在脚本信息栏添加【今日检查】信息块",
- "给Markdown添加【复制】按钮": "给Markdown添加【复制】按钮",
- "在Markdown内容右上角添加【复制】按钮,点击一键复制Markdown内容": "在Markdown内容右上角添加【复制】按钮,点击一键复制Markdown内容",
- 开启后下面的功能才会生效: "开启后下面的功能才会生效",
- 检测页面加载: "检测页面加载",
- "检测Greasyfork页面是否正常加载,如加载失败则自动刷新页面": "检测Greasyfork页面是否正常加载,如加载失败则自动刷新页面",
- 检测间隔: "检测间隔",
- "设置检测上次刷新页面的间隔时间,当距离上次刷新页面的时间超过设置的值,将不再刷新页面": "设置检测上次刷新页面的间隔时间,当距离上次刷新页面的时间超过设置的值,将不再刷新页面",
- 美化顶部导航栏: "美化顶部导航栏",
- "可能会跟Greasyfork Beautify脚本有冲突": "可能会跟Greasyfork Beautify脚本有冲突",
- 美化脚本列表: "美化脚本列表",
- "双列显示且添加脚本卡片操作项(安装、收藏)": "双列显示且添加脚本卡片操作项(安装、收藏)",
- 操作面板: "操作面板",
- "添加【操作面板】按钮": "添加【操作面板】按钮",
- "在脚本列表页面时为顶部导航栏添加【操作面板】按钮": "在脚本列表页面时为顶部导航栏添加【操作面板】按钮",
- 操作: "操作",
- 安装此脚本: "安装此脚本",
- 脚本: "脚本",
- 历史版本: "历史版本",
- 自定义已读颜色: "自定义已读颜色",
- 在讨论内生效: "在讨论内生效",
- 用户: "用户",
- 控制台: "控制台",
- "迁移【控制台】到顶部导航栏": "迁移【控制台】到顶部导航栏",
- "将【控制台】按钮移动到顶部导航栏,节省空间": "将【控制台】按钮移动到顶部导航栏,节省空间",
- "在版本下面添加【安装】、【查看代码】按钮": "在版本下面添加【安装】、【查看代码】按钮",
- 查看代码: "查看代码",
- 添加快捷操作按钮: "添加快捷操作按钮",
- "在每一行讨论的最后面添加【过滤】按钮,需开启过滤功能才会生效": "在每一行讨论的最后面添加【过滤】按钮,需开启过滤功能才会生效",
- 选择需要过滤的选项: "选择需要过滤的选项",
- "确定{{type}}:{{filterId}}?": "确定{{type}}:{{filterId}}?",
- "该收藏集未包含:{{scriptId}}": "该收藏集未包含:{{scriptId}}",
- 帮助文档: "帮助文档",
- "请输入规则,每行一个": "请输入规则,每行一个",
- 选择过滤的选项: "选择过滤的选项",
- "脚本id:{{text}}": "脚本id:{{text}}",
- "脚本名:{{text}}": "脚本名:{{text}}",
- "作者id:{{text}}": "作者id:{{text}}",
- "作者名:{{text}}": "作者名:{{text}}",
- "作用域:脚本、脚本搜索、用户主页": "作用域:脚本、脚本搜索、用户主页",
- "更新到 {{version}} 版本": "更新到 {{version}} 版本",
- "降级到 {{version}} 版本": "降级到 {{version}} 版本",
- "重新安装 {{version}} 版本": "重新安装 {{version}} 版本",
- "发布的用户id:{{text}}": "发布的用户id:{{text}}",
- 自定义快捷键: "自定义快捷键",
- 点击录入快捷键: "点击录入快捷键",
- 快捷键发表回复: "快捷键发表回复",
- "在输入框内按下快捷发表回复,例如:{{key}}": "在输入框内按下快捷发表回复,例如:{{key}}",
- 请先执行当前的录入操作: "请先执行当前的录入操作",
- 清空快捷键: "清空快捷键",
- "请按下快捷键...": "请按下快捷键...",
- 成功录入: "成功录入",
- "快捷键 {{key}} 已被 {{isUsedKey}} 占用": "快捷键 {{key}} 已被 {{isUsedKey}} 占用"
- };
- const en_US_language = {
- GreasyFork优化: "GreasyFork Optimization",
- 请求取消: "http request cancel",
- 请求超时: "http request timeout",
- 请求异常: "http request error",
- 通用: "General",
- 账号: "Account",
- 密码: "Password",
- 语言: "Language",
- "账号/密码": "Account/Password",
- 请输入账号: "Please enter your account number",
- 请输入密码: "Please enter password",
- 自动登录: "Auto Login",
- 自动登录当前保存的账号: "Automatically log in to the currently saved account",
- "清空账号/密码": "Clear account/password",
- 点击清空: "Clear",
- "确定清空账号和密码?": "Are you sure to clear your account and password?",
- "已清空账号/密码": "Account/password cleared",
- "源代码同步【脚本列表】": "Source Code Synchronization [Script List]",
- 一键同步: "Sync All",
- 前往用户主页: "Go to the user's homepage",
- 获取当前已登录的用户主页失败: "Failed to retrieve the currently logged in user's homepage",
- "源代码同步【未上架的脚本】": "Source code synchronization [Script not listed]",
- "源代码同步【库】": "Source code synchronization 【 Library 】",
- 论坛: "Forum",
- 功能: "Function",
- 过滤重复的评论: "Filter duplicate comments",
- "过滤掉重复的评论数量(≥2)": "Filter out duplicate comments (≥ 2)",
- "过滤脚本(id)": "Filter script (id)",
- "请输入脚本id,每行一个": "Please enter the script ID, one per line",
- "过滤发布的用户(id)": "Filter published users (id)",
- "请输入用户id,每行一个": "Please enter the user ID, one per line",
- "过滤回复的用户(id)": "User (ID) who filters replies",
- 优化: "Optimization",
- 固定当前语言: "Fix current language",
- 无: "nothing",
- "如button、input、textarea": "For example button、input、textarea",
- 更直观的查看版本迭代: "More intuitive viewing of version iterations",
- 美化上传图片按钮: "Beautify upload image button",
- 放大上传区域: "Enlarge the upload area",
- 优化图片浏览: "Optimize image browsing",
- 使用Viewer浏览图片: "Using Viewer to browse images",
- 覆盖图床图片跳转: "Overlay bed image jump",
- "配合上面的【优化图片浏览】更优雅浏览图片": "Collaborate with the optimization of image browsing above to browse images more elegantly",
- '需安装Greasyfork Beautify脚本,<a href="https://greasyfork.org/zh-CN/scripts/446849-greasyfork-beautify" target="_blank">🖐点我安装</a>': 'Greasyfork Beauty script needs to be installed,<a href="https://greasyfork.org/zh-CN/scripts/446849-greasyfork-beautify" target="_blank">🖐 Click me to install</a>',
- 代码: "Code",
- 添加复制代码按钮: "Add Copy Code Button",
- 更优雅的复制: "More elegant replication",
- 快捷键: "Shortcut keys",
- "【F】键全屏、【Alt+Shift+F】键宽屏": "【F】 Key full screen, [Alt+Shift+F] key wide screen",
- 库: "Library",
- 脚本列表: "Script List",
- "请输入屏蔽规则,每行一个": "Please enter a blocking rule, one per line",
- 请求admin内容失败: "Request for admin content failed",
- 解析admin的源代码同步表单失败: "Failed to parse the source code of admin and synchronize the form",
- 源代码同步失败: "Source code synchronization failed",
- 获取用户信息失败: "Failed to obtain user information",
- 获取用户的收藏集失败: "Failed to retrieve user's collection",
- "解析Script Sets失败": "Parsing Script Sets failed",
- "获取收藏集{{setsId}}失败": "Failed to retrieve collection {{setsId}}",
- "获取表单元素#edit_script_set失败": "Failed to retrieve form element #edit_script_set",
- 更新收藏集表单请求失败: "Update collection form request failed",
- 请先在菜单中录入账号: "Please enter your account in the menu first",
- 请先在菜单中录入密码: "Please enter your password in the menu first",
- "获取csrf-token失败": "Failed to obtain csrf token",
- "正在登录中...": "Logging in...",
- "登录失败,请在控制台查看原因": "Login failed, please check the reason in the console",
- "登录成功,1s后自动跳转": "Login successful, automatically redirect after 1 second",
- "登录失败,可能是账号/密码错误,请在控制台查看原因": "Login failed, possibly due to incorrect account/password. Please check the reason in the console",
- "美化 历史版本 页面": "Beautify the historical version page",
- 未找到history_versions元素列表: "History_versions element list not found",
- "yyyy年MM月dd日 HH:mm:ss": "yyyy-MM-dd HH:mm:ss",
- "美化 Greasyfork Beautify脚本": "Beautify Greasyfork Beauty Script",
- "❌ 最多同时长传5张图": "❌ Upload up to 5 images simultaneously",
- "❌ 图片:{{name}} 大小:{{size}}": "❌ Image:{{name}} Size:{{size}}",
- "已过滤:{{oldCount}}": "Filtered:{{oldCount}}",
- 寻找引用: "Find references",
- 获取脚本id失败: "Failed to obtain script ID",
- 收藏: "Collection",
- 请先登录账号: "Please log in to your account first",
- 获取用户id失败: "Failed to obtain user ID",
- "获取收藏夹中...": "Get in favorites...",
- 收藏集: "Collection",
- "添加中...": "Adding...",
- "添加失败,{{selector}}元素不存在": "Add failed, {{selector}} element does not exist",
- "未找到{{selector}}元素": "{{selector}} element not found",
- 添加失败: "Add failed",
- 添加成功: "Successfully added",
- "删除中...": "Deleting...",
- 删除成功: "Delete successful",
- 添加: "Add in deletion",
- 刪除: "Delete",
- "拦截跳转:": "Intercept jump:",
- 今日检查: "Today's inspection",
- 复制代码: "Copy Code",
- "加载文件中...": "Loading files...",
- 复制成功: "Copy successful",
- "✅ 复制成功!": "✅ Copy successful!",
- "当前语言:{{currentLocaleLanguage}},,3秒后切换至:{{localeLanguage}}": "Current language: {{currentLocaleLanguage}}, switch to {{localeLanguage}} in 3 seconds",
- "导航至:": "Navigation to:",
- "请先登录账号!": "Please log in to your account first!",
- "获取信息中,请稍后...": "Obtaining information, please wait...",
- "获取成功,共 {{count}} 个": "Successfully obtained, a total of {{count}}",
- "评分:": "Rating:",
- "语言:": "Language:",
- "版本:": "Version:",
- "更新:": "Update:",
- 同步代码: "Synchronize Code",
- "同步中...": "Synchronizing...",
- 手动: "Manual",
- 自动: "Automatic",
- "同步方式:{{syncMode}}": "Synchronization method: {{syncMode}}",
- 同步成功: "Sync successful",
- 同步失败: "Sync failed",
- 该脚本未设置同步信息: "The script has not set synchronization information",
- "上次重载时间 {{time}},{{timeout}}秒内拒绝反复重载": "Last reload time {{time}}, rejected repeated reloads within {{timeout}} seconds",
- "名称:": "Name:",
- "进度:": "Progress:",
- "未获取到【脚本列表】": "Unable to obtain [Script List]",
- "源代码同步成功,3秒后更新下一个": "Source code synchronization successful, update next one in 3 seconds",
- 全部更新失败: "All updates failed",
- "全部更新完毕<br >成功:{{successNums}}<br >失败:{{failedNums}}<br >总计:{{scriptUrlListLength}}": "All updates completed<br>Success: {{successNums}}<br>Failure: {{failed Nums}}<br>Total: {{scriptUrlListLength}}",
- "⚙ 设置": "⚙ Setting",
- "{{SCRIPT_NAME}}-设置": "{{SCRIPT_NAME}}-Setting",
- 美化页面元素: "Beautify page elements",
- 美化历史版本页面: "Beautify the historical version page",
- "美化Greasyfork Beautify脚本": "Beautify Greasyfork Beauty Script",
- 获取表单csrfToken失败: "Failed to obtain form csrfToken",
- Toast配置: "Toast Config",
- Toast位置: "Toast position",
- 左上角: "Top left",
- 顶部: "Top",
- 右上角: "Top right",
- 左边: "Left",
- 中间: "Center",
- 右边: "Right",
- 左下角: "Bottom left",
- 底部: "Bottom",
- 右下角: "Bottom right",
- Toast显示在页面九宫格的位置: "Toast is displayed in the nine grid position on the page",
- 最多显示的数量: "Maximum number of displays",
- 限制Toast显示的数量: "Limit the number of Toast displays",
- 逆序弹出: "Reverse pop-up",
- 修改Toast弹出的顺序: "Modify the order in which Toast pops up",
- 该脚本已经在该收藏集中: "The script is already in this collection",
- 其它错误: "Ohter Error",
- 启用: "Enable",
- 开启后下面的过滤功能才会生效: "The following filtering function will only take effect after it is enabled",
- 屏蔽脚本: "Block script",
- 点击查看规则: "Click to view rules",
- 过滤: "Filter",
- 代码同步: "Code synchronization",
- 美化: "Beautify",
- 修复代码行号显示: "Fix code line number display",
- 修复代码行数超过1k行号显示不全问题: "Fix the problem that the code line number display is not complete when the number of lines exceeds 1k",
- "添加【寻找引用】按钮": "Add the button to find references",
- "在脚本栏添加按钮,一般用于搜索引用该库的相关脚本": "Add a button to the script bar, generally used to search for scripts that reference this library",
- "添加【收藏】按钮": "Add the button to collect",
- "在脚本栏添加按钮,一般用于快捷收藏该脚本/库": "Add a button to the script bar, generally used to quickly collect this script / library",
- 修复图片宽度显示问题: " Fix the problem that the picture width display is not complete",
- 修复图片在移动端宽度超出浏览器宽度问题: "Fix the problem that the picture width exceeds the browser width on mobile",
- "添加【今日检查】信息块": "Add the block of information of today's inspection",
- "在脚本信息栏添加【今日检查】信息块": "Add the block of information of today's inspection to the script information bar",
- "给Markdown添加【复制】按钮": "Add the button to copy to Markdown",
- "在Markdown内容右上角添加【复制】按钮,点击一键复制Markdown内容": "Add the button to copy to the top right corner of the Markdown content, click to copy the Markdown content in one click",
- 开启后下面的功能才会生效: "The following functions will only take effect after it is enabled",
- 检测页面加载: "Detect page loading",
- "检测Greasyfork页面是否正常加载,如加载失败则自动刷新页面": "Detect whether the Greasyfork page is loaded normally. If the loading fails, the page will be automatically refreshed",
- 检测间隔: "Detection interval",
- "设置检测上次刷新页面的间隔时间,当距离上次刷新页面的时间超过设置的值,将不再刷新页面": "Set the interval time for detecting the last refresh page. If the time since the last refresh page exceeds the set value, the page will no longer be refreshed",
- 美化顶部导航栏: "Beautify the top navigation bar",
- "可能会跟Greasyfork Beautify脚本有冲突": "Possible conflict with Greasymfork Beautify script",
- 美化脚本列表: "Beautify Script List",
- "双列显示且添加脚本卡片操作项(安装、收藏)": "Double column display and add script card operation items (installation, bookmarking)",
- 操作面板: "Operation Panel",
- "添加【操作面板】按钮": "Add [Operation Panel] button",
- "在脚本列表页面时为顶部导航栏添加【操作面板】按钮": "Add an 'Operation Panel' button to the top navigation bar on the script list page",
- 操作: "Operation",
- 安装此脚本: "Install this script",
- 脚本: "Scripts",
- 历史版本: "Historical version",
- 自定义已读颜色: "Customize read colors",
- 在讨论内生效: "Effective within the discussion",
- 用户: "Users",
- 控制台: "Console",
- "迁移【控制台】到顶部导航栏": "Migration of Console to Top Navigation Bar",
- "将【控制台】按钮移动到顶部导航栏,节省空间": "Move the 'Console' button to the top navigation bar to save space",
- 添加额外的标签按钮: "Add additional label button",
- "在版本下面添加【安装】、【查看代码】按钮": "Add 【 Install 】 and 【 View Code 】 buttons under the version",
- 查看代码: "View Code",
- 添加快捷操作按钮: "Add shortcut operation button",
- "在每一行讨论的最后面添加【过滤】按钮,需开启过滤功能才会生效": "Add a 'Filter' button at the end of each discussion line. The filtering function needs to be enabled for it to take effect",
- 选择需要过滤的选项: "Select the options that need to be filtered",
- "确定{{type}}:{{filterId}}?": "Are you sure {{type}}:{{filterId}}?",
- "该收藏集未包含:{{scriptId}}": "This collection does not include:{{scriptId}}",
- 帮助文档: "Help document",
- "请输入规则,每行一个": "Please enter a rule, one per line",
- 选择过滤的选项: "Select filtering options",
- "脚本id:{{text}}": "Script Id: {{text}}",
- "脚本名:{{text}}": "Script Name: {{text}}",
- "作者id:{{text}}": "Author Id: {{text}}",
- "作者名:{{text}}": "Author Name: {{text}}",
- "作用域:脚本、脚本搜索、用户主页": "Scope: Script, Script Search, User Homepage",
- "更新到 {{version}} 版本": "Update To {{version}} Version",
- "降级到 {{version}} 版本": "Downgrade to {{version}} Version",
- "重新安装 {{version}} 版本": "Reinstall {{version}} Version",
- "发布的用户id:{{text}}": "Published user ID: {{text}}",
- 自定义快捷键: "Customize shortcut keys",
- 点击录入快捷键: "Click on the input shortcut key",
- 快捷键发表回复: "Shortcut key to post reply",
- "在输入框内按下快捷发表回复,例如:{{key}}": "Press the shortcut to post a reply in the input box, for example: {{key}}",
- 请先执行当前的录入操作: "Please perform the current input operation first",
- 清空快捷键: "Clear shortcut keys",
- "请按下快捷键...": "Please press the shortcut key...",
- 成功录入: "Successful entry",
- "快捷键 {{key}} 已被 {{isUsedKey}} 占用": "The shortcut key {{key}} is already used by {{isUsedKey}}"
- };
- const KEY = "GM_Panel";
- const ATTRIBUTE_INIT = "data-init";
- const ATTRIBUTE_KEY = "data-key";
- const ATTRIBUTE_DEFAULT_VALUE = "data-default-value";
- const LanguageInit = function() {
- let settingPanel = _GM_getValue(KEY, {});
- let lng = settingPanel["setting-language"] || "zh-CN";
- i18next.init({
- lng,
- // lng: "zh-CN",
- fallbackLng: "zh-CN",
- resources: {
- "zh-CN": {
- translation: { ...zh_CN_language }
- },
- "en-US": {
- translation: { ...en_US_language }
- }
- }
- });
- };
- LanguageInit();
- _GM_getValue(KEY, {});
- const _SCRIPT_NAME_ = i18next.t("GreasyFork优化");
- const utils = Utils.noConflict();
- const domUtils = DOMUtils.noConflict();
- const __pops = pops;
- const log = new utils.Log(
- _GM_info,
- _unsafeWindow.console || _monkeyWindow.console
- );
- const SCRIPT_NAME = ((_a = _GM_info == null ? void 0 : _GM_info.script) == null ? void 0 : _a.name) || _SCRIPT_NAME_;
- const DEBUG = false;
- log.config({
- debug: DEBUG,
- logMaxCount: 1e3,
- autoClearConsole: true,
- tag: true
- });
- Qmsg.config(
- Object.defineProperties(
- {
- html: true,
- autoClose: true,
- showClose: false
- },
- {
- position: {
- get() {
- return PopsPanel.getValue("qmsg-config-position", "bottom");
- }
- },
- maxNums: {
- get() {
- return PopsPanel.getValue("qmsg-config-maxnums", 5);
- }
- },
- showReverse: {
- get() {
- return PopsPanel.getValue("qmsg-config-showreverse", true);
- }
- },
- zIndex: {
- get() {
- let maxZIndex = Utils.getMaxZIndex();
- let popsMaxZIndex = pops.config.InstanceUtils.getPopsMaxZIndex(maxZIndex).zIndex;
- return Utils.getMaxValue(maxZIndex, popsMaxZIndex) + 100;
- }
- }
- }
- )
- );
- const GM_Menu = new utils.GM_Menu({
- GM_getValue: _GM_getValue,
- GM_setValue: _GM_setValue,
- GM_registerMenuCommand: _GM_registerMenuCommand,
- GM_unregisterMenuCommand: _GM_unregisterMenuCommand
- });
- const httpx = new utils.Httpx(_GM_xmlhttpRequest);
- httpx.interceptors.response.use(void 0, (data) => {
- log.error(["拦截器-请求错误", data]);
- if (data.type === "onabort") {
- Qmsg.warning(i18next.t("请求取消"));
- } else if (data.type === "onerror") {
- Qmsg.error(i18next.t("请求异常"));
- } else if (data.type === "ontimeout") {
- Qmsg.error(i18next.t("请求超时"));
- } else {
- Qmsg.error(i18next.t("其它错误"));
- }
- return data;
- });
- httpx.config({
- logDetails: DEBUG
- });
- ({
- Object: {
- defineProperty: _unsafeWindow.Object.defineProperty
- },
- Function: {
- apply: _unsafeWindow.Function.prototype.apply,
- call: _unsafeWindow.Function.prototype.call
- },
- Element: {
- appendChild: _unsafeWindow.Element.prototype.appendChild
- },
- setTimeout: _unsafeWindow.setTimeout
- });
- const addStyle = utils.addStyle;
- const UIButton = function(text, description, buttonText, buttonIcon, buttonIsRightIcon, buttonIconIsLoading, buttonType, clickCallBack) {
- let result = {
- text,
- type: "button",
- description,
- buttonIcon,
- buttonIsRightIcon,
- buttonIconIsLoading,
- buttonType,
- buttonText,
- callback(event) {
- if (typeof clickCallBack === "function") {
- clickCallBack(event);
- }
- },
- afterAddToUListCallBack: void 0
- };
- return result;
- };
- const UIInput = function(text, key, defaultValue, description, changeCallBack, placeholder = "", isNumber, isPassword) {
- let result = {
- text,
- type: "input",
- isNumber: Boolean(isNumber),
- isPassword: Boolean(isPassword),
- attributes: {},
- description,
- getValue() {
- let localValue = PopsPanel.getValue(key, defaultValue);
- return localValue;
- },
- callback(event, value) {
- PopsPanel.setValue(key, value);
- },
- placeholder
- };
- if (result.attributes) {
- result.attributes[ATTRIBUTE_KEY] = key;
- result.attributes[ATTRIBUTE_DEFAULT_VALUE] = defaultValue;
- }
- return result;
- };
- const UISwitch = function(text, key, defaultValue, clickCallBack, description) {
- let result = {
- text,
- type: "switch",
- description,
- attributes: {},
- getValue() {
- return Boolean(PopsPanel.getValue(key, defaultValue));
- },
- callback(event, value) {
- log.success(`${value ? "开启" : "关闭"} ${text}`);
- PopsPanel.setValue(key, Boolean(value));
- },
- afterAddToUListCallBack: void 0
- };
- if (result.attributes) {
- result.attributes[ATTRIBUTE_KEY] = key;
- result.attributes[ATTRIBUTE_DEFAULT_VALUE] = Boolean(defaultValue);
- }
- return result;
- };
- const GreasyforkApi = {
- /**
- * 获取代码搜索地址
- * @param url
- */
- getCodeSearchUrl(url) {
- return "https://greasyfork.org/zh-CN/scripts/code-search?c=" + url;
- },
- /**
- * 获取管理地址
- * @param url
- */
- getAdminUrl(url) {
- return url + "/admin";
- },
- /**
- * 从字符串中提取Id
- * @param text
- */
- getScriptId(text) {
- var _a2, _b;
- return (_b = (_a2 = text || window.location.pathname) == null ? void 0 : _a2.match(
- /\/scripts\/([\d]+)/i
- )) == null ? void 0 : _b[1];
- },
- /**
- * 从字符串中提取用户id
- * @param text
- */
- getUserId(text) {
- var _a2;
- return (_a2 = (text || window.location.pathname).match(/\/users\/([\d]+)/i)) == null ? void 0 : _a2[1];
- },
- /**
- * 从字符串中提取脚本名
- * @param text
- */
- getScriptName(text) {
- let pathname = window.location.pathname;
- if (text != null) {
- pathname = new URL(text).pathname;
- }
- pathname = decodeURIComponent(pathname);
- let pathnameSplit = pathname.split("/");
- for (const name of pathnameSplit) {
- let nameMatch = name.match(/[\d]+/);
- if (nameMatch && nameMatch.length) {
- return nameMatch[1];
- }
- }
- },
- /**
- * 获取需要切换语言的Url
- */
- getSwitchLanguageUrl(localeLanguage = "zh-CN") {
- let url = window.location.origin;
- let urlSplit = window.location.pathname.split("/");
- urlSplit[1] = localeLanguage;
- url = url + urlSplit.join("/");
- url += window.location.search;
- if (window.location.search === "") {
- url += "?locale_override=1";
- } else if (!window.location.search.includes("locale_override=1")) {
- url += "&locale_override=1";
- }
- return url;
- },
- /**
- * 获取脚本统计数据
- * @param scriptId
- */
- async getScriptStats(scriptId) {
- return new Promise(async (resolve) => {
- let scriptStatsRequest = await httpx.get({
- url: `https://greasyfork.org/scripts/${scriptId}/stats.json`,
- fetch: true,
- onerror() {
- },
- ontimeout() {
- }
- });
- if (!scriptStatsRequest.status) {
- resolve(null);
- return;
- }
- let scriptStatsJSON = scriptStatsRequest.data;
- resolve(scriptStatsJSON);
- });
- },
- /**
- * 解析并获取admin内的源代码同步的配置表单
- * @param scriptId
- */
- async getSourceCodeSyncFormData(scriptId) {
- let getResp = await httpx.get(
- `https://greasyfork.org/zh-CN/scripts/${scriptId}/admin`,
- {
- fetch: true
- }
- );
- log.success(getResp);
- if (!getResp.status) {
- Qmsg.error(i18next.t("请求admin内容失败"));
- return;
- }
- let adminHTML = getResp.data.responseText;
- let adminHTMLElement = domUtils.parseHTML(adminHTML, false, true);
- let formElement = adminHTMLElement.querySelector("form.edit_script");
- if (!formElement) {
- Qmsg.error(i18next.t("解析admin的源代码同步表单失败"));
- return;
- }
- let formData = new FormData(formElement);
- return formData;
- },
- /**
- * 进行源代码同步,要求先getSourceCodeSyncFormData
- * @param scriptId
- * @param data
- */
- async sourceCodeSync(scriptId, data) {
- let postResp = await httpx.post(
- `https://greasyfork.org/zh-CN/scripts/${scriptId}/sync_update`,
- {
- fetch: true,
- data
- }
- );
- log.success(postResp);
- if (!postResp.status) {
- Qmsg.error(i18next.t("源代码同步失败"));
- return;
- }
- return postResp;
- },
- /**
- * 获取用户的信息,包括脚本列表、未上架的脚本、库
- */
- async getUserInfo(userId) {
- let getResp = await httpx.get(
- `https://greasyfork.org/zh-CN/users/${userId}.json`,
- {
- fetch: true
- }
- );
- log.success(getResp);
- if (!getResp.status) {
- Qmsg.error(i18next.t("获取用户信息失败"));
- return;
- }
- let data = utils.toJSON(getResp.data.responseText);
- data["scriptList"] = [];
- data["scriptLibraryList"] = [];
- data["scripts"].forEach((scriptInfo) => {
- if (scriptInfo["code_url"].endsWith(".user.js")) {
- data["scriptList"].push(scriptInfo);
- } else {
- data["scriptLibraryList"].push(scriptInfo);
- }
- });
- return data;
- },
- /**
- * 获取用户的收藏集
- * @param userId
- */
- async getUserCollection(userId) {
- let getResp = await httpx.get(
- `https://greasyfork.org/zh-CN/users/${userId}`,
- {
- fetch: true
- }
- );
- log.info(["获取用户的收藏集", getResp]);
- if (!getResp.status) {
- Qmsg.error(i18next.t("获取用户的收藏集失败"));
- return;
- }
- let respText = getResp.data.responseText;
- let respDocument = domUtils.parseHTML(respText, true, true);
- let userScriptSets = respDocument.querySelector("#user-script-sets");
- if (!userScriptSets) {
- log.error("解析Script Sets失败");
- return;
- }
- let scriptSetsIdList = [];
- userScriptSets.querySelectorAll("li").forEach((liElement) => {
- var _a2;
- let $ele = liElement.querySelector("a:last-child");
- if (!$ele) {
- return;
- }
- let setsUrl = $ele.href;
- if (setsUrl.includes("?fav=1")) {
- return;
- }
- let setsName = liElement.querySelector("a").innerText;
- let setsId = (_a2 = setsUrl.match(/\/sets\/([\d]+)\//)) == null ? void 0 : _a2[1];
- scriptSetsIdList.push({
- id: setsId,
- name: setsName
- });
- });
- return scriptSetsIdList;
- },
- /**
- * 获取某个收藏集的信息
- * @param userId 用户id
- * @param setsId 收藏集id
- */
- async getUserCollectionInfo(userId, setsId) {
- let getResp = await httpx.get(
- `https://greasyfork.org/zh-CN/users/${userId}/sets/${setsId}/edit`,
- {
- fetch: true
- }
- );
- if (!getResp.status) {
- Qmsg.error(i18next.t("获取收藏集{{setsId}}失败", { setsId }));
- return;
- }
- let respText = getResp.data.responseText;
- let respDocument = domUtils.parseHTML(respText, true, true);
- let $edit_script_set_form = respDocument.querySelector(
- 'form[id^="edit_script_set"]'
- );
- if (!$edit_script_set_form) {
- Qmsg.error(i18next.t("获取表单元素#edit_script_set失败"));
- return;
- }
- let formData = new FormData($edit_script_set_form);
- let csrfToken = respDocument.querySelector(
- 'meta[name="csrf-token"]'
- );
- if (!csrfToken) {
- Qmsg.error(i18next.t("获取表单csrfToken失败"));
- return;
- }
- if (csrfToken.hasAttribute("content")) {
- let authenticity_token = csrfToken.getAttribute("content");
- if (authenticity_token) {
- formData.set("authenticity_token", authenticity_token);
- }
- }
- return formData;
- },
- /**
- * 更新用户的某个收藏集的表单信息
- * @param userId 用户id
- * @param setsId 收藏集id
- * @param data
- */
- async updateUserSetsInfo(userId, setsId, data) {
- let postResp = await httpx.post(
- `https://greasyfork.org/zh-CN/users/${userId}/sets/${setsId}`,
- {
- fetch: true,
- headers: {
- accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
- "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
- "cache-control": "no-cache",
- "content-type": "application/x-www-form-urlencoded",
- pragma: "no-cache"
- },
- fetchInit: {
- referrerPolicy: "strict-origin-when-cross-origin"
- },
- data
- }
- );
- if (!postResp.status) {
- Qmsg.error(i18next.t("更新收藏集表单请求失败"));
- return;
- }
- let respText = postResp.data.responseText;
- let respDocument = domUtils.parseHTML(respText, true, true);
- return respDocument;
- },
- /**
- * 切换语言
- * @param url
- */
- async switchLanguage(url) {
- let getResp = await httpx.get(url, {
- fetch: true,
- headers: {
- "Upgrade-Insecure-Requests": "1"
- }
- });
- if (!getResp.status) {
- return;
- }
- log.info(getResp);
- }
- };
- const GreasyforkRouter = {
- /**
- * 代码页面
- */
- isCode() {
- var _a2;
- return (_a2 = window.location.pathname.split("/")) == null ? void 0 : _a2.includes("code");
- },
- /**
- * (严格比较)代码页面
- */
- isCodeStrict() {
- return window.location.pathname.endsWith("/code");
- },
- /**
- * 版本页面
- */
- isVersion() {
- return window.location.pathname.endsWith("/versions");
- },
- /**
- * 用户主页
- */
- isUserHome() {
- return window.location.pathname.match(/\/.+\/users\/.+/gi);
- },
- /**
- * 脚本页面(单个脚本的页面)
- */
- isScript() {
- return window.location.pathname.includes("/scripts/");
- },
- /**
- * 脚本列表页面
- */
- isScriptList() {
- return window.location.pathname.endsWith("/scripts");
- },
- /**
- * 库列表页面
- */
- isScriptLibraryList() {
- return window.location.pathname.endsWith("/libraries");
- },
- /**
- * 脚本代码搜索页面
- */
- isScriptCodeSearch() {
- return window.location.pathname.endsWith("/code-search");
- },
- /**
- * 讨论页面
- */
- isDiscuessions() {
- return window.location.pathname.endsWith("/discussions");
- }
- };
- const GreasyforkMenu = {
- /**
- * @class
- */
- menu: GM_Menu,
- /**
- * 当前是否已登录
- */
- isLogin: false,
- /**
- * 初始化环境变量
- */
- initEnv() {
- let userLinkElement = this.getUserLinkElement();
- this.isLogin = Boolean(userLinkElement);
- },
- /**
- * 获取当前登录用户的a标签元素
- */
- getUserLinkElement() {
- return document.querySelector(
- "#nav-user-info span.user-profile-link a"
- );
- },
- /**
- * 更新脚本
- * @param scriptUrlList
- */
- async updateScript(scriptUrlList) {
- let getLoadingHTML = function(scriptName, progress = 1) {
- return `
- <div style="display: flex;flex-direction: column;align-items: flex-start;">
- <div style="height: 30px;line-height: 30px;">${i18next.t(
- "名称:"
- )}${scriptName}</div>
- <div style="height: 30px;line-height: 30px;">${i18next.t(
- "进度:"
- )}${progress}/${scriptUrlList.length}</div>
- </div>`;
- };
- if (utils.isNull(scriptUrlList)) {
- Qmsg.error(i18next.t("未获取到【脚本列表】"));
- } else {
- let loading = Qmsg.loading(
- getLoadingHTML(GreasyforkApi.getScriptName(scriptUrlList[0])),
- {
- html: true
- }
- );
- let successNums = 0;
- let failedNums = 0;
- for (let index = 0; index < scriptUrlList.length; index++) {
- let scriptUrl = scriptUrlList[index];
- let scriptId = GreasyforkApi.getScriptId(scriptUrl);
- log.success("更新:" + scriptUrl);
- let scriptName = GreasyforkApi.getScriptName(scriptUrl);
- loading.setHTML(getLoadingHTML(scriptName, index + 1));
- let codeSyncFormData = await GreasyforkApi.getSourceCodeSyncFormData(
- scriptId
- );
- if (codeSyncFormData) {
- let syncUpdateStatus = await GreasyforkApi.sourceCodeSync(
- scriptId,
- codeSyncFormData
- );
- if (syncUpdateStatus) {
- Qmsg.success(i18next.t("源代码同步成功,3秒后更新下一个"));
- await utils.sleep(3e3);
- successNums++;
- } else {
- Qmsg.error(i18next.t("源代码同步失败"));
- failedNums++;
- }
- } else {
- Qmsg.error(i18next.t("源代码同步失败"));
- failedNums++;
- }
- }
- loading.close();
- if (successNums === 0) {
- Qmsg.error(i18next.t("全部更新失败"));
- } else {
- Qmsg.success(
- i18next.t(
- "全部更新完毕<br >成功:{{successNums}}<br >失败:{{failedNums}}<br >总计:{{scriptUrlListLength}}",
- {
- successNums,
- failedNums,
- scriptUrlListLength: scriptUrlList.length
- }
- ),
- {
- html: true
- }
- );
- }
- }
- },
- /**
- * 处理本地的goto事件
- */
- handleLocalGotoCallBack() {
- if (PopsPanel.getValue("goto_updateSettingsAndSynchronize_scriptList")) {
- PopsPanel.deleteValue("goto_updateSettingsAndSynchronize_scriptList");
- if (!GreasyforkRouter.isUserHome()) {
- PopsPanel.setValue(
- "goto_updateSettingsAndSynchronize_scriptList",
- true
- );
- if (GreasyforkMenu.getUserLinkElement()) {
- Qmsg.success(i18next.t("前往用户主页"));
- window.location.href = GreasyforkMenu.getUserLinkElement().href;
- } else {
- Qmsg.error(i18next.t("获取当前已登录的用户主页失败"));
- }
- return;
- }
- let scriptUrlList = [];
- document.querySelectorAll(
- "#user-script-list-section li a.script-link"
- ).forEach((item) => {
- scriptUrlList = scriptUrlList.concat(
- GreasyforkApi.getAdminUrl(item.href)
- );
- });
- GreasyforkMenu.updateScript(scriptUrlList);
- } else if (PopsPanel.getValue("goto_updateSettingsAndSynchronize_unlistedScriptList")) {
- PopsPanel.deleteValue(
- "goto_updateSettingsAndSynchronize_unlistedScriptList"
- );
- if (!GreasyforkRouter.isUserHome()) {
- PopsPanel.setValue(
- "goto_updateSettingsAndSynchronize_unlistedScriptList",
- true
- );
- if (GreasyforkMenu.getUserLinkElement()) {
- Qmsg.success(i18next.t("前往用户主页"));
- window.location.href = GreasyforkMenu.getUserLinkElement().href;
- } else {
- Qmsg.error(i18next.t("获取当前已登录的用户主页失败"));
- }
- return;
- }
- let scriptUrlList = [];
- document.querySelectorAll(
- "#user-unlisted-script-list li a.script-link"
- ).forEach((item) => {
- scriptUrlList = scriptUrlList.concat(
- GreasyforkApi.getAdminUrl(item.href)
- );
- });
- GreasyforkMenu.updateScript(scriptUrlList);
- } else if (PopsPanel.getValue("goto_updateSettingsAndSynchronize_libraryScriptList")) {
- PopsPanel.deleteValue(
- "goto_updateSettingsAndSynchronize_libraryScriptList"
- );
- if (!GreasyforkRouter.isUserHome()) {
- PopsPanel.setValue(
- "goto_updateSettingsAndSynchronize_libraryScriptList",
- true
- );
- if (GreasyforkMenu.getUserLinkElement()) {
- Qmsg.success(i18next.t("前往用户主页"));
- window.location.href = GreasyforkMenu.getUserLinkElement().href;
- } else {
- Qmsg.error(i18next.t("获取当前已登录的用户主页失败"));
- }
- return;
- }
- let scriptUrlList = [];
- document.querySelectorAll(
- "#user-library-script-list li a.script-link"
- ).forEach((item) => {
- scriptUrlList = scriptUrlList.concat(
- GreasyforkApi.getAdminUrl(item.href)
- );
- });
- GreasyforkMenu.updateScript(scriptUrlList);
- }
- }
- };
- const UISelect = function(text, key, defaultValue, data, callback, description) {
- let selectData = [];
- if (typeof data === "function") {
- selectData = data();
- } else {
- selectData = data;
- }
- let result = {
- text,
- type: "select",
- description,
- attributes: {},
- getValue() {
- return PopsPanel.getValue(key, defaultValue);
- },
- callback(event, isSelectedValue, isSelectedText) {
- PopsPanel.setValue(key, isSelectedValue);
- if (typeof callback === "function") {
- callback(event, isSelectedValue, isSelectedText);
- }
- },
- data: selectData
- };
- if (result.attributes) {
- result.attributes[ATTRIBUTE_KEY] = key;
- result.attributes[ATTRIBUTE_DEFAULT_VALUE] = defaultValue;
- }
- return result;
- };
- const UIButtonShortCut = function(text, description, key, defaultValue, defaultButtonText, buttonType = "default", shortCut) {
- let __defaultButtonText = typeof defaultButtonText === "function" ? defaultButtonText() : defaultButtonText;
- if (typeof defaultValue === "object") {
- shortCut.initConfig(key, defaultValue);
- }
- let getButtonText = () => {
- return shortCut.getShowText(key, __defaultButtonText);
- };
- let result = UIButton(
- text,
- description,
- getButtonText,
- "keyboard",
- false,
- false,
- buttonType,
- async (event) => {
- var _a2;
- let $click = event.target;
- let $btn = (_a2 = $click.closest(".pops-panel-button")) == null ? void 0 : _a2.querySelector("span");
- if (shortCut.isWaitPress) {
- Qmsg.warning(i18next.t("请先执行当前的录入操作"));
- return;
- }
- if (shortCut.hasOptionValue(key)) {
- shortCut.emptyOption(key);
- Qmsg.success(i18next.t("清空快捷键"));
- } else {
- let loadingQmsg = Qmsg.loading(i18next.t("请按下快捷键..."), {
- showClose: true
- });
- let {
- status,
- option,
- key: isUsedKey
- } = await shortCut.enterShortcutKeys(key);
- loadingQmsg.close();
- if (status) {
- log.success(["成功录入快捷键", option]);
- Qmsg.success(i18next.t("成功录入"));
- } else {
- Qmsg.error(
- i18next.t(`快捷键 {{key}} 已被 {{isUsedKey}} 占用`, {
- key: shortCut.translateKeyboardValueToButtonText(option),
- isUsedKey
- })
- );
- }
- }
- $btn.innerHTML = getButtonText();
- }
- );
- result.attributes = {};
- Reflect.set(result.attributes, ATTRIBUTE_INIT, () => {
- return false;
- });
- return result;
- };
- class ShortCut {
- constructor(key) {
- /** 存储的键 */
- __publicField(this, "key", "short-cut");
- /** 是否存在等待按下的按键 */
- __publicField(this, "isWaitPress", false);
- if (typeof key === "string") {
- this.key = key;
- }
- }
- /**
- * 初始化配置默认值
- */
- initConfig(key, option) {
- if (this.hasOption(key)) ;
- else {
- this.setOption(key, option);
- }
- }
- /** 获取存储的键 */
- getStorageKey() {
- return this.key;
- }
- /**
- * 获取本地存储的所有值
- */
- getLocalAllOptions() {
- return _GM_getValue(this.key, []);
- }
- /**
- * 判断是否存在该配置
- * @param key 键
- */
- hasOption(key) {
- let localOptions = this.getLocalAllOptions();
- let findOption = localOptions.find((item) => item.key === key);
- return !!findOption;
- }
- /**
- * 判断是否存在该配置的value值
- * @param key 键
- */
- hasOptionValue(key) {
- if (this.hasOption(key)) {
- let option = this.getOption(key);
- return !((option == null ? void 0 : option.value) == null);
- } else {
- return false;
- }
- }
- /**
- * 获取配置
- * @param key 键
- * @param defaultValue 默认值
- */
- getOption(key, defaultValue) {
- let localOptions = this.getLocalAllOptions();
- let findOption = localOptions.find((item) => item.key === key);
- return findOption ?? defaultValue;
- }
- /**
- * 设置配置
- * @param key 键
- * @param value 配置
- */
- setOption(key, value) {
- let localOptions = this.getLocalAllOptions();
- let findIndex = localOptions.findIndex((item) => item.key === key);
- if (findIndex == -1) {
- localOptions.push({
- key,
- value
- });
- } else {
- Reflect.set(localOptions[findIndex], "value", value);
- }
- _GM_setValue(this.key, localOptions);
- }
- /**
- * 清空当前已有配置录入的值
- * @param key
- */
- emptyOption(key) {
- let result = false;
- let localOptions = this.getLocalAllOptions();
- let findIndex = localOptions.findIndex((item) => item.key === key);
- if (findIndex !== -1) {
- localOptions[findIndex].value = null;
- result = true;
- }
- _GM_setValue(this.key, localOptions);
- return result;
- }
- /**
- * 删除配置
- * @param key 键
- */
- deleteOption(key) {
- let result = false;
- let localValue = this.getLocalAllOptions();
- let findValueIndex = localValue.findIndex((item) => item.key === key);
- if (findValueIndex !== -1) {
- localValue.splice(findValueIndex, 1);
- result = true;
- }
- _GM_setValue(this.key, localValue);
- return result;
- }
- /**
- * 把配置的快捷键转成文字
- * @param keyboardValue
- * @returns
- */
- translateKeyboardValueToButtonText(keyboardValue) {
- let result = "";
- keyboardValue.ohterCodeList.forEach((ohterCodeKey) => {
- result += utils.stringTitleToUpperCase(ohterCodeKey, true) + " + ";
- });
- result += keyboardValue.keyName;
- return result;
- }
- /**
- * 获取快捷键显示的文字
- * @param key 本地存储的快捷键键名
- * @param defaultShowText 默认显示的文字
- */
- getShowText(key, defaultShowText) {
- if (this.hasOption(key)) {
- let localOption = this.getOption(key);
- if (localOption.value == null) {
- return defaultShowText;
- } else {
- return this.translateKeyboardValueToButtonText(localOption.value);
- }
- } else {
- return defaultShowText;
- }
- }
- /**
- * 录入快捷键
- * @param key 本地存储的快捷键键名
- */
- async enterShortcutKeys(key) {
- return new Promise((resolve) => {
- this.isWaitPress = true;
- let keyboardListener = utils.listenKeyboard(
- window,
- "keyup",
- (keyName, keyValue, ohterCodeList) => {
- let currentOption = {
- keyName,
- keyValue,
- ohterCodeList
- };
- let shortcutJSONString = JSON.stringify(currentOption);
- let allOptions = this.getLocalAllOptions();
- for (let index = 0; index < allOptions.length; index++) {
- let localValue = allOptions[index];
- if (localValue.key === key) {
- continue;
- }
- let isUsedByOtherOption = false;
- if (localValue.value != null && shortcutJSONString === JSON.stringify(localValue.value)) {
- isUsedByOtherOption = true;
- }
- if (isUsedByOtherOption) {
- this.isWaitPress = false;
- keyboardListener.removeListen();
- resolve({
- status: false,
- key: localValue.key,
- option: currentOption
- });
- return;
- }
- }
- this.setOption(key, currentOption);
- this.isWaitPress = false;
- keyboardListener.removeListen();
- resolve({
- status: true,
- key,
- option: currentOption
- });
- }
- );
- });
- }
- /**
- * 初始化全局键盘监听
- * @param shortCutOption 快捷键配置 一般是{ "键名": { callback: ()=>{}}},键名是本地存储的自定义快捷键的键名
- */
- initGlobalKeyboardListener(shortCutOption) {
- let localOptions = this.getLocalAllOptions();
- if (!localOptions.length) {
- log.warn("没有设置快捷键");
- return;
- }
- let that = this;
- function setListenKeyboard($ele, option) {
- utils.listenKeyboard(
- $ele,
- "keydown",
- (keyName, keyValue, ohterCodeList) => {
- if (that.isWaitPress) {
- return;
- }
- localOptions = that.getLocalAllOptions();
- let findShortcutIndex = localOptions.findIndex((item) => {
- let option2 = item.value;
- let tempOption = {
- keyName,
- keyValue,
- ohterCodeList
- };
- if (JSON.stringify(option2) === JSON.stringify(tempOption)) {
- return item;
- }
- });
- if (findShortcutIndex != -1) {
- let findShortcut = localOptions[findShortcutIndex];
- log.info(["调用快捷键", findShortcut]);
- if (findShortcut.key in option) {
- option[findShortcut.key].callback();
- }
- }
- }
- );
- }
- let WindowShortCutOption = {};
- let ElementShortCutOption = {};
- Object.keys(shortCutOption).forEach((localKey) => {
- let option = shortCutOption[localKey];
- if (option.target == null || typeof option.target === "string" && option.target === "") {
- option.target = "window";
- }
- if (option.target === "window") {
- Reflect.set(WindowShortCutOption, localKey, option);
- } else {
- Reflect.set(ElementShortCutOption, localKey, option);
- }
- });
- setListenKeyboard(window, WindowShortCutOption);
- domUtils.ready(() => {
- Object.keys(ElementShortCutOption).forEach(async (localKey) => {
- let option = ElementShortCutOption[localKey];
- if (typeof option.target === "string") {
- utils.waitNode(option.target, 1e4).then(($ele) => {
- if (!$ele) {
- return;
- }
- let __option = {};
- Reflect.set(__option, localKey, option);
- setListenKeyboard($ele, __option);
- });
- } else if (typeof option.target === "function") {
- let target = await option.target();
- if (target == null) {
- return;
- }
- let __option = {};
- Reflect.set(__option, localKey, option);
- setListenKeyboard(target, __option);
- } else {
- let __option = {};
- Reflect.set(__option, localKey, option);
- setListenKeyboard(option.target, __option);
- }
- });
- });
- }
- }
- const GreasyforkShortCut = {
- shortCut: new ShortCut(),
- shortOption: {
- "gf-quickReply": {
- target: () => {
- let $commentText = document.querySelector("#comment_text");
- let $replyBtn = document.querySelector(
- 'input[name="commit"][type="submit"]'
- );
- if (!$commentText) {
- log.error("页面不存在输入框");
- return;
- } else if (!$replyBtn) {
- log.error("页面不存在【发表回复】按钮");
- return;
- }
- return $commentText;
- },
- callback() {
- let $replyBtn = document.querySelector(
- 'input[name="commit"][type="submit"]'
- );
- if (!$replyBtn) {
- log.error("页面不存在【发表回复】按钮");
- return;
- }
- $replyBtn.click();
- }
- }
- },
- init() {
- this.shortCut.initGlobalKeyboardListener(this.shortOption);
- }
- };
- const SettingUIGeneral = {
- id: "greasy-fork-panel-config-account",
- title: i18next.t("通用"),
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- {
- text: i18next.t("Toast配置"),
- type: "deepMenu",
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- UISelect(
- i18next.t("Toast位置"),
- "qmsg-config-position",
- "bottom",
- [
- {
- value: "topleft",
- text: i18next.t("左上角")
- },
- {
- value: "top",
- text: i18next.t("顶部")
- },
- {
- value: "topright",
- text: i18next.t("右上角")
- },
- {
- value: "left",
- text: i18next.t("左边")
- },
- {
- value: "center",
- text: i18next.t("中间")
- },
- {
- value: "right",
- text: i18next.t("右边")
- },
- {
- value: "bottomleft",
- text: i18next.t("左下角")
- },
- {
- value: "bottom",
- text: i18next.t("底部")
- },
- {
- value: "bottomright",
- text: i18next.t("右下角")
- }
- ],
- (event, isSelectValue, isSelectText) => {
- log.info("设置当前Qmsg弹出位置" + isSelectText);
- },
- i18next.t("Toast显示在页面九宫格的位置")
- ),
- UISelect(
- i18next.t("最多显示的数量"),
- "qmsg-config-maxnums",
- 3,
- [
- {
- value: 1,
- text: "1"
- },
- {
- value: 2,
- text: "2"
- },
- {
- value: 3,
- text: "3"
- },
- {
- value: 4,
- text: "4"
- },
- {
- value: 5,
- text: "5"
- }
- ],
- void 0,
- i18next.t("限制Toast显示的数量")
- ),
- UISwitch(
- i18next.t("逆序弹出"),
- "qmsg-config-showreverse",
- false,
- void 0,
- i18next.t("修改Toast弹出的顺序")
- )
- ]
- }
- ]
- },
- UISelect(
- i18next.t("语言"),
- "setting-language",
- "zh-CN",
- [
- {
- value: "zh-CN",
- text: "中文"
- },
- {
- value: "en-US",
- text: "English"
- }
- ],
- (event, isSelectValue, isSelectText) => {
- log.info("改变语言:" + isSelectText);
- i18next.changeLanguage(isSelectValue);
- }
- )
- ]
- },
- {
- text: "",
- type: "forms",
- forms: [
- {
- text: i18next.t("账号/密码"),
- type: "deepMenu",
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- UIInput(
- i18next.t("账号"),
- "user",
- "",
- void 0,
- void 0,
- i18next.t("请输入账号")
- ),
- UIInput(
- i18next.t("密码"),
- "pwd",
- "",
- void 0,
- void 0,
- i18next.t("请输入密码"),
- false,
- true
- )
- ]
- },
- {
- text: "",
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("自动登录"),
- "autoLogin",
- true,
- void 0,
- i18next.t("自动登录当前保存的账号")
- ),
- UIButton(
- i18next.t("清空账号/密码"),
- void 0,
- i18next.t("点击清空"),
- void 0,
- void 0,
- false,
- "default",
- (event) => {
- if (confirm(i18next.t("确定清空账号和密码?"))) {
- PopsPanel.deleteValue("user");
- PopsPanel.deleteValue("pwd");
- Qmsg.success(i18next.t("已清空账号/密码"));
- let $shadowRoot = event.target.getRootNode();
- $shadowRoot.querySelector(
- `li[data-key="user"] .pops-panel-input input`
- ).value = "";
- $shadowRoot.querySelector(
- `li[data-key="pwd"] .pops-panel-input input`
- ).value = "";
- }
- }
- )
- ]
- }
- ]
- },
- {
- text: i18next.t("功能"),
- type: "deepMenu",
- forms: [
- {
- text: i18next.t("功能"),
- type: "forms",
- forms: [
- UISelect(
- i18next.t("固定当前语言"),
- "language-selector-locale",
- "",
- function() {
- let result = [
- {
- value: "",
- text: i18next.t("无")
- }
- ];
- document.querySelectorAll(
- "select#language-selector-locale option"
- ).forEach((element) => {
- let value = element.getAttribute("value");
- if (value === "help") {
- return;
- }
- let text = (element.innerText || element.textContent).trim();
- result.push({
- value,
- text
- });
- });
- return result;
- }()
- ),
- UISwitch(
- i18next.t("修复图片宽度显示问题"),
- "fixImageWidth",
- true,
- void 0,
- i18next.t("修复图片在移动端宽度超出浏览器宽度问题")
- ),
- UISwitch(
- i18next.t("优化图片浏览"),
- "optimizeImageBrowsing",
- true,
- void 0,
- i18next.t("使用Viewer浏览图片")
- ),
- UISwitch(
- i18next.t("覆盖图床图片跳转"),
- "overlayBedImageClickEvent",
- true,
- void 0,
- i18next.t("配合上面的【优化图片浏览】更优雅浏览图片")
- ),
- UISwitch(
- i18next.t("添加【操作面板】按钮"),
- "scripts-addOperationPanelBtnWithNavigator",
- true,
- void 0,
- i18next.t("在脚本列表页面时为顶部导航栏添加【操作面板】按钮")
- ),
- UISwitch(
- i18next.t("给Markdown添加【复制】按钮"),
- "addMarkdownCopyButton",
- true,
- void 0,
- i18next.t(
- "在Markdown内容右上角添加【复制】按钮,点击一键复制Markdown内容"
- )
- )
- ]
- },
- {
- text: i18next.t("检测页面加载"),
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("启用"),
- "checkPage",
- true,
- void 0,
- i18next.t(
- "检测Greasyfork页面是否正常加载,如加载失败则自动刷新页面"
- )
- ),
- UISelect(
- i18next.t("检测间隔"),
- "greasyfork-check-page-timeout",
- 5,
- (() => {
- let result = [];
- for (let index = 0; index < 5; index++) {
- result.push({
- value: index + 1,
- text: index + 1 + "s"
- });
- }
- return result;
- })(),
- void 0,
- i18next.t(
- "设置检测上次刷新页面的间隔时间,当距离上次刷新页面的时间超过设置的值,将不再刷新页面"
- )
- )
- ]
- },
- {
- text: i18next.t("代码同步"),
- type: "forms",
- forms: [
- UIButton(
- i18next.t("源代码同步【脚本列表】"),
- void 0,
- i18next.t("一键同步"),
- void 0,
- void 0,
- false,
- "primary",
- (event) => {
- if (!GreasyforkRouter.isUserHome()) {
- PopsPanel.setValue(
- "goto_updateSettingsAndSynchronize_scriptList",
- true
- );
- if (GreasyforkMenu.getUserLinkElement()) {
- Qmsg.success(i18next.t("前往用户主页"));
- window.location.href = GreasyforkMenu.getUserLinkElement().href;
- } else {
- Qmsg.error(i18next.t("获取当前已登录的用户主页失败"));
- }
- return;
- }
- let scriptUrlList = [];
- document.querySelectorAll(
- "#user-script-list-section li a.script-link"
- ).forEach((item) => {
- scriptUrlList = scriptUrlList.concat(
- GreasyforkApi.getAdminUrl(item.href)
- );
- });
- GreasyforkMenu.updateScript(scriptUrlList);
- }
- ),
- UIButton(
- i18next.t("源代码同步【未上架的脚本】"),
- void 0,
- i18next.t("一键同步"),
- void 0,
- void 0,
- false,
- "primary",
- (event) => {
- if (!GreasyforkRouter.isUserHome()) {
- PopsPanel.setValue(
- "goto_updateSettingsAndSynchronize_unlistedScriptList",
- true
- );
- if (GreasyforkMenu.getUserLinkElement()) {
- Qmsg.success(i18next.t("前往用户主页"));
- window.location.href = GreasyforkMenu.getUserLinkElement().href;
- } else {
- Qmsg.error(i18next.t("获取当前已登录的用户主页失败"));
- }
- return;
- }
- let scriptUrlList = [];
- document.querySelectorAll(
- "#user-unlisted-script-list li a.script-link"
- ).forEach((item) => {
- scriptUrlList = scriptUrlList.concat(
- GreasyforkApi.getAdminUrl(item.href)
- );
- });
- GreasyforkMenu.updateScript(scriptUrlList);
- }
- ),
- UIButton(
- i18next.t("源代码同步【库】"),
- void 0,
- i18next.t("一键同步"),
- void 0,
- void 0,
- false,
- "primary",
- (event) => {
- if (!GreasyforkRouter.isUserHome()) {
- PopsPanel.setValue(
- "goto_updateSettingsAndSynchronize_libraryScriptList",
- true
- );
- if (GreasyforkMenu.getUserLinkElement()) {
- Qmsg.success(i18next.t("前往用户主页"));
- window.location.href = GreasyforkMenu.getUserLinkElement().href;
- } else {
- Qmsg.error(i18next.t("获取当前已登录的用户主页失败"));
- }
- return;
- }
- let scriptUrlList = [];
- document.querySelectorAll(
- "#user-library-script-list li a.script-link"
- ).forEach((item) => {
- scriptUrlList = scriptUrlList.concat(
- GreasyforkApi.getAdminUrl(item.href)
- );
- });
- GreasyforkMenu.updateScript(scriptUrlList);
- }
- )
- ]
- }
- ]
- },
- {
- text: i18next.t("美化"),
- type: "deepMenu",
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("美化页面元素"),
- "beautifyPage",
- true,
- void 0,
- i18next.t("如button、input、textarea")
- ),
- UISwitch(
- i18next.t("美化上传图片按钮"),
- "beautifyUploadImage",
- true,
- void 0,
- i18next.t("放大上传区域")
- ),
- UISwitch(
- i18next.t("美化顶部导航栏"),
- "beautifyTopNavigationBar",
- true,
- void 0,
- i18next.t("可能会跟Greasyfork Beautify脚本有冲突")
- ),
- UISwitch(
- i18next.t("美化Greasyfork Beautify脚本"),
- "beautifyGreasyforkBeautify",
- true,
- void 0,
- i18next.t(
- '需安装Greasyfork Beautify脚本,<a href="https://greasyfork.org/zh-CN/scripts/446849-greasyfork-beautify" target="_blank">🖐点我安装</a>'
- )
- )
- ]
- }
- ]
- },
- {
- type: "deepMenu",
- text: i18next.t("自定义快捷键"),
- forms: [
- {
- type: "forms",
- text: "",
- forms: [
- UIButtonShortCut(
- i18next.t("快捷键发表回复"),
- i18next.t("在输入框内按下快捷发表回复,例如:{{key}}", {
- key: "Ctrl + Enter"
- }),
- "gf-quickReply",
- {
- keyName: "Enter",
- keyValue: "13",
- ohterCodeList: ["ctrl"]
- },
- i18next.t("点击录入快捷键"),
- void 0,
- GreasyforkShortCut.shortCut
- )
- ]
- }
- ]
- }
- ]
- }
- ]
- };
- const GreasyforkScriptsCode = {
- init() {
- PopsPanel.execMenuOnce("code-repairCodeLineNumber", () => {
- this.repairCodeLineNumber();
- });
- },
- /**
- * 修复代码的行号显示不够问题
- * 超过1w行不会高亮代码
- */
- repairCodeLineNumber() {
- log.info("修复代码的行号显示不够问题");
- PopsPanel.execMenuOnce("beautifyGreasyforkBeautify", () => {
- _GM_addStyle(
- /*css*/
- `
- .code-container pre code .marker{
- padding-left: 6px;
- }
- `
- );
- });
- utils.waitNode(
- "#script-content div.code-container pre.prettyprint ol"
- ).then(($prettyPrintOL) => {
- if ($prettyPrintOL.childElementCount >= 1e3) {
- log.success(
- `当前代码行数${$prettyPrintOL.childElementCount}行,超过1000行,优化行号显示问题`
- );
- _GM_addStyle(
- /*css*/
- `
- pre.prettyprint{
- padding-left: 26px;
- }
- `
- );
- }
- });
- }
- };
- const beautifyVersionsPageCSS = 'ul.history_versions,\r\nul.history_versions li {\r\n width: 100%;\r\n}\r\nul.history_versions li {\r\n display: flex;\r\n flex-direction: column;\r\n margin: 25px 0px;\r\n}\r\n.diff-controls input[type="radio"]:nth-child(2) {\r\n margin-left: 5px;\r\n}\r\n.flex-align-item-center {\r\n display: flex;\r\n align-items: center;\r\n}\r\n.script-tag {\r\n margin-bottom: 8px;\r\n}\r\n.script-tag-version a {\r\n color: #656d76;\r\n fill: #656d76;\r\n text-decoration: none;\r\n width: fit-content;\r\n width: -moz-fit-content;\r\n}\r\n.script-tag-version a:hover svg {\r\n color: #00a3f5;\r\n fill: #00a3f5;\r\n}\r\n.script-tag-version a > span {\r\n margin-left: 0.25rem;\r\n}\r\n.script-note-box-body {\r\n border-radius: 0.375rem;\r\n border-style: solid;\r\n border-width: max(1px, 0.0625rem);\r\n border-color: #d0d7de;\r\n color: #1f2328;\r\n padding: 16px;\r\n overflow-wrap: anywhere;\r\n}\r\n.script-note-box-body p {\r\n margin-bottom: unset;\r\n}\r\n';
- const CommonUtils = {
- /**
- * 添加屏蔽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 资源数据
- */
- setGMResourceCSS(resourceMapData) {
- let cssText = typeof _GM_getResourceText === "function" ? _GM_getResourceText(resourceMapData.keyName) : "";
- if (typeof cssText === "string" && cssText) {
- addStyle(cssText);
- } else {
- CommonUtils.addLinkNode(resourceMapData.url);
- }
- },
- /**
- * 添加<link>标签
- * @param url
- */
- async addLinkNode(url) {
- let $link = document.createElement("link");
- $link.rel = "stylesheet";
- $link.type = "text/css";
- $link.href = url;
- domUtils.ready(() => {
- document.head.appendChild($link);
- });
- return $link;
- },
- /**
- * 将url修复,例如只有search的链接/sss/xxx?sss=xxxx
- * @param url 需要修复的链接
- */
- fixUrl(url) {
- url = url.trim();
- if (url.match(/^http(s|):\/\//i)) {
- return url;
- } else {
- if (!url.startsWith("/")) {
- url += "/";
- }
- url = window.location.origin + url;
- return url;
- }
- }
- };
- const GreasyforkUrlUtils = {
- /**
- * 获取脚本安装的链接
- * @param scriptId
- * @param scriptVersion
- * @param scriptName
- * @returns
- */
- getInstallUrl(scriptId, scriptVersion, scriptName) {
- if (utils.isNotNull(scriptName)) {
- scriptName = "/" + scriptName;
- } else {
- scriptName = "";
- }
- return `https://update.greasyfork.org/scripts/${scriptId}/${scriptVersion}${scriptName}.user.js`;
- },
- /**
- * 获取脚本的代码页面链接
- * @param scriptId
- * @param scriptVersion
- * @returns
- */
- getCodeUrl(scriptId, scriptVersion) {
- if (utils.isNull(scriptVersion)) {
- scriptVersion = "";
- }
- return `https://greasyfork.org/scripts/${scriptId}/code?version=${scriptVersion}`;
- },
- /**
- * 获取脚本的信息
- * @param scriptId 脚本id
- */
- getScriptInfoUrl(scriptId) {
- return `https://greasyfork.org/scripts/${scriptId}.json`;
- }
- };
- const GreasyforkVersions = {
- init() {
- PopsPanel.execMenuOnce("beautifyHistoryVersionPage", () => {
- return this.beautifyHistoryVersionPage();
- });
- PopsPanel.execMenuOnce("scripts-versions-addExtraTagButton", () => {
- this.addExtraTagButton();
- });
- },
- /**
- * 美化 历史版本 页面
- */
- beautifyHistoryVersionPage() {
- log.info("美化 历史版本 页面");
- let result = [];
- result.push(_GM_addStyle(beautifyVersionsPageCSS));
- result.push(
- CommonUtils.addBlockCSS(
- ".version-number",
- ".version-date",
- ".version-changelog"
- )
- );
- domUtils.ready(function() {
- let $historyVersion = document.querySelector(
- "ul.history_versions"
- );
- if (!$historyVersion) {
- Qmsg.error(i18next.t("未找到history_versions元素列表"));
- return;
- }
- Array.from($historyVersion.children).forEach((liElement) => {
- var _a2, _b;
- let versionUrl = liElement.querySelector(".version-number a").href;
- let versionNumber = liElement.querySelector(
- ".version-number a"
- ).innerText;
- let versionDate = (_a2 = liElement.querySelector(".version-date")) == null ? void 0 : _a2.getAttribute("datetime");
- let updateNote = ((_b = liElement.querySelector(".version-changelog")) == null ? void 0 : _b.innerHTML) || "";
- let versionDateElement = domUtils.createElement("span", {
- className: "script-version-date",
- innerHTML: utils.formatTime(
- versionDate,
- i18next.t("yyyy年MM月dd日 HH:mm:ss")
- )
- });
- let tagElement = domUtils.createElement("div", {
- className: "script-tag",
- innerHTML: (
- /*html*/
- `
- <div class="script-tag-version">
- <a href="${versionUrl}" class="flex-align-item-center">
- <svg aria-label="Tag" role="img" height="16" viewBox="0 0 16 16" version="1.1" width="16">
- <path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path>
- </svg>
- <span>${versionNumber}</span>
- </a>
- </div>`
- )
- });
- let boxBodyElement = domUtils.createElement("div", {
- className: "script-note-box-body",
- innerHTML: updateNote
- });
- liElement.appendChild(versionDateElement);
- liElement.appendChild(tagElement);
- liElement.appendChild(boxBodyElement);
- });
- });
- return result;
- },
- /**
- * 添加额外的标签按钮
- */
- addExtraTagButton() {
- log.info("添加额外的标签按钮");
- domUtils.ready(() => {
- document.querySelectorAll(".script-tag-version").forEach(($tagVersion) => {
- var _a2, _b;
- let $anchor = $tagVersion.querySelector("a");
- if (!$anchor) {
- return;
- }
- let urlObj = new URL($anchor.href);
- let scriptId = (_a2 = urlObj.pathname.match(/\/scripts\/([\d]+)/)) == null ? void 0 : _a2[1];
- let scriptVersion = urlObj.searchParams.get("version");
- let scriptName = (_b = urlObj.pathname.match(/\/scripts\/[\d]+-(.+)/)) == null ? void 0 : _b[1];
- let installUrl = GreasyforkUrlUtils.getInstallUrl(
- scriptId,
- scriptVersion,
- scriptName
- );
- let codeUrl = GreasyforkUrlUtils.getCodeUrl(scriptId, scriptVersion);
- let $buttonTag = domUtils.createElement("div", {
- className: "scripts-tag-install",
- innerHTML: (
- /*html*/
- `
- <a class="script-btn-install install-link" data-install-format="js" target="_blank" href="${installUrl}">${i18next.t(
- "安装此脚本"
- )}</a>
- <a class="script-btn-see-code" target="_blank" href="${codeUrl}">${i18next.t(
- "查看代码"
- )}</a>
- `
- )
- });
- domUtils.after($tagVersion, $buttonTag);
- });
- });
- }
- };
- let userCollection = [];
- const GreasyforkScriptsCollectEvent = async function(scriptId) {
- log.info("当前脚本id:" + scriptId);
- if (!GreasyforkMenu.isLogin) {
- log.error("请先登录账号");
- Qmsg.error(i18next.t("请先登录账号"));
- return;
- }
- let userId = GreasyforkApi.getUserId(
- GreasyforkMenu.getUserLinkElement().href
- );
- if (userId == null) {
- log.error("获取用户id失败");
- Qmsg.error(i18next.t("获取用户id失败"));
- return;
- }
- if (!userCollection.length) {
- let loading = Qmsg.loading(i18next.t("获取收藏夹中..."));
- userCollection = await GreasyforkApi.getUserCollection(userId) || [];
- loading.close();
- if (!userCollection.length) {
- return;
- }
- }
- let alertHTML = "";
- userCollection.forEach((userCollectInfo) => {
- alertHTML += /*html*/
- `
- <li class="user-collect-item" data-id="${userCollectInfo.id}" data-name="${userCollectInfo.name}">
- <div class="user-collect-name">${userCollectInfo.name}</div>
- <div class="user-collect-btn-container">
- <div class="pops-panel-button collect-add-script-id">
- <button type="primary" data-icon="" data-righticon="">
- <span>${i18next.t("添加")}</span>
- </button>
- </div>
- <div class="pops-panel-button collect-delete-script-id">
- <button type="danger" data-icon="" data-righticon="">
- <span>${i18next.t("刪除")}</span>
- </button>
- </div>
- </div>
- </li>
- `;
- });
- let collectionDialog = __pops.alert({
- title: {
- text: i18next.t("收藏集"),
- position: "center"
- },
- content: {
- html: true,
- text: (
- /*html*/
- `<ul>${alertHTML}</ul>`
- )
- },
- mask: {
- enable: true,
- clickEvent: {
- toClose: true
- }
- },
- btn: {
- ok: {
- enable: false
- }
- },
- width: __pops.isPhone() ? "92vw" : "500px",
- height: "auto",
- drag: true,
- only: true,
- style: (
- /*css*/
- `
- .pops{
- --content-max-height: 400px;
- max-height: var(--content-max-height);
- }
- .pops[type-value=alert] .pops-alert-content {
- max-height: calc(var(--content-max-height) - var(--container-title-height) - var(--container-bottom-btn-height));
- }
- .user-collect-item{
- -webkit-user-select: none;
- user-select: none;
- padding: 5px 10px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- border-bottom: 1px dotted #c9c9c9;
- }
- .user-collect-name{
- }
- .user-collect-item:hover{
- }
- .user-collect-btn-container{
- margin-left: 10px;
- display: flex;
- }
- `
- )
- });
- domUtils.on(
- collectionDialog.$shadowRoot,
- "click",
- ".collect-add-script-id",
- async function(event) {
- let $userCollectItem = event.target.closest(
- ".user-collect-item"
- );
- let setsId = $userCollectItem.dataset.id;
- $userCollectItem.dataset.name;
- let loading = Qmsg.loading(i18next.t("添加中..."));
- let formData = await GreasyforkApi.getUserCollectionInfo(userId, setsId);
- if (!formData) {
- loading.close();
- return;
- }
- let editForm = utils.cloneFormData(formData);
- let saveEditForm = utils.cloneFormData(formData);
- let isCollect = false;
- for (const [key, value] of formData.entries()) {
- if (key === "scripts-included[]" && String(value).trim() === String(scriptId).trim()) {
- isCollect = true;
- break;
- } else {
- saveEditForm.append(key, value);
- editForm.append(key, value);
- }
- }
- if (isCollect) {
- Qmsg.warning(i18next.t("该脚本已经在该收藏集中"));
- loading.close();
- return;
- }
- editForm.set("add-script", scriptId.toString());
- editForm.set("script-action", "i");
- saveEditForm.append("scripts-included[]", scriptId.toString());
- saveEditForm.set("save", "1");
- let addFormDataSearchParams = new URLSearchParams(editForm);
- let saveFormDataSearchParams = new URLSearchParams(saveEditForm);
- let addData = Array.from(addFormDataSearchParams).map(
- // @ts-ignore
- ([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
- ).join("&");
- let saveData = Array.from(saveFormDataSearchParams).map(
- // @ts-ignore
- ([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
- ).join("&");
- log.info(["添加的数据", addData]);
- log.info(["保存的数据", saveData]);
- let addResult = await GreasyforkApi.updateUserSetsInfo(
- userId,
- setsId,
- addData
- );
- if (!addResult) {
- loading.close();
- return;
- }
- let changeScriptSet = addResult.querySelector(".change-script-set");
- if (!changeScriptSet) {
- Qmsg.error(
- i18next.t("添加失败,{{selector}}元素不存在", {
- selector: ".change-script-set"
- })
- );
- loading.close();
- return;
- }
- let section = changeScriptSet.querySelector("section");
- if (!section) {
- Qmsg.error(
- i18next.t("添加失败,{{selector}}元素不存在", {
- selector: "section"
- })
- );
- loading.close();
- return;
- }
- let alertElement = section.querySelector(".alert");
- if (alertElement) {
- __pops.alert({
- title: {
- text: i18next.t("添加失败"),
- position: "center"
- },
- content: {
- text: alertElement.innerHTML,
- html: true
- },
- mask: {
- enable: true,
- clickEvent: {
- toClose: true
- }
- },
- style: (
- /*css*/
- `
- .pops-alert-content{
- font-style: italic;
- background-color: #ffc;
- border: none;
- border-left: 6px solid #FFEB3B;
- padding: .5em;
- }
- `
- ),
- drag: true,
- dragLimit: true,
- width: __pops.isPhone() ? "88vw" : "400px",
- height: __pops.isPhone() ? "50vh" : "300px"
- });
- } else {
- await GreasyforkApi.updateUserSetsInfo(userId, setsId, saveData);
- Qmsg.success(i18next.t("添加成功"));
- }
- loading.close();
- }
- );
- domUtils.on(
- collectionDialog.$shadowRoot,
- "click",
- ".collect-delete-script-id",
- async function(event) {
- let $collectItem = event.target.closest(
- ".user-collect-item"
- );
- let setsId = $collectItem.dataset.id;
- $collectItem.dataset.name;
- let loading = Qmsg.loading(i18next.t("删除中..."));
- let formData = await GreasyforkApi.getUserCollectionInfo(userId, setsId);
- if (!formData) {
- loading.close();
- return;
- }
- let editForm = new FormData();
- let saveEditForm = new FormData();
- let isCollect = false;
- for (const [key, value] of formData.entries()) {
- if (String(key).trim() === "scripts-included[]" && String(value).trim() === String(scriptId).trim()) {
- isCollect = true;
- continue;
- }
- saveEditForm.append(key, value);
- editForm.append(key, value);
- }
- if (!isCollect) {
- Qmsg.warning(
- i18next.t("该收藏集未包含:{{scriptId}}", {
- scriptId
- })
- );
- loading.close();
- return;
- }
- editForm.set("remove-scripts-included[]", scriptId.toString());
- editForm.set("remove-selected-scripts", "i");
- editForm.delete("script-action");
- saveEditForm.set("save", "1");
- let deleteFormDataSearchParams = new URLSearchParams(editForm);
- let saveFormDataSearchParams = new URLSearchParams(saveEditForm);
- let removeData = Array.from(deleteFormDataSearchParams).map(
- // @ts-ignore
- ([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
- ).join("&");
- let saveData = Array.from(saveFormDataSearchParams).map(
- // @ts-ignore
- ([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
- ).join("&");
- log.info(["删除的数据", removeData]);
- log.info(["保存的数据", saveData]);
- let removeResult = await GreasyforkApi.updateUserSetsInfo(
- userId,
- setsId,
- removeData
- );
- if (!removeResult) {
- loading.close();
- return;
- }
- await GreasyforkApi.updateUserSetsInfo(userId, setsId, saveData);
- Qmsg.success(i18next.t("删除成功"));
- loading.close();
- }
- );
- };
- const GreasyforkScripts = {
- init() {
- if (GreasyforkRouter.isCode()) {
- GreasyforkScriptsCode.init();
- } else if (GreasyforkRouter.isVersion()) {
- GreasyforkVersions.init();
- }
- if (GreasyforkRouter.isCodeStrict()) {
- PopsPanel.execMenuOnce("fullScreenOptimization", () => {
- this.fullScreenOptimization();
- });
- PopsPanel.execMenuOnce("addCopyCodeButton", () => {
- this.addCopyCodeButton();
- });
- }
- PopsPanel.execMenuOnce("addCollectionButton", () => {
- this.addCollectionButton();
- });
- PopsPanel.execMenuOnce("addFindReferenceButton", () => {
- this.setFindCodeSearchBtn();
- });
- PopsPanel.execMenuOnce("scriptHomepageAddedTodaySUpdate", () => {
- this.scriptHomepageAddedTodaySUpdate();
- });
- },
- /**
- * 添加【收藏】按钮
- */
- addCollectionButton() {
- log.info("添加收藏按钮");
- utils.waitNode("ul#script-links li.current span").then(() => {
- let $collectBtn = domUtils.createElement("li", {
- innerHTML: `
- <a href="javascript:;">
- <span>${i18next.t("收藏")}</span>
- </a>`
- });
- domUtils.append(
- document.querySelector("ul#script-links"),
- $collectBtn
- );
- domUtils.on($collectBtn, "click", () => {
- let scriptIdMatch = window.location.pathname.match(/scripts\/([\d]+)/i);
- if (!scriptIdMatch) {
- log.error([scriptIdMatch, window.location.pathname]);
- Qmsg.error(i18next.t("获取脚本id失败"));
- return;
- }
- let scriptId = scriptIdMatch[scriptIdMatch.length - 1];
- GreasyforkScriptsCollectEvent(scriptId);
- });
- });
- },
- /**
- * F11全屏,F键代码全屏
- */
- fullScreenOptimization() {
- log.info("F11全屏,F键代码全屏");
- _GM_addStyle(
- /*css*/
- `
- .code-wide-screen{
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- margin: 0;
- padding: 0;
- width: 100%;
- height: 100%;
- min-width: 100%;
- min-height: 100%;
- max-width: 100%;
- max-height: 100%;
- z-index: 10000;
- }
- `
- );
- let isFullScreen = false;
- domUtils.keydown(
- _unsafeWindow,
- function(event) {
- if (event.key.toLowerCase() === "f") {
- let codeElement = document.querySelector(
- "#script-content div.code-container code"
- );
- if (event.altKey && event.shiftKey) {
- utils.preventEvent(event);
- if (codeElement.classList.contains("code-wide-screen")) {
- codeElement.classList.remove("code-wide-screen");
- } else {
- codeElement.classList.add("code-wide-screen");
- }
- } else if (!event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) {
- utils.preventEvent(event);
- if (isFullScreen) {
- utils.exitFullScreen(codeElement);
- isFullScreen = false;
- } else {
- utils.enterFullScreen(codeElement);
- isFullScreen = true;
- }
- }
- }
- },
- {
- capture: true
- }
- );
- },
- /**
- * 设置代码搜索按钮(对于库)
- */
- setFindCodeSearchBtn() {
- log.info("设置代码搜索按钮(对于库)");
- utils.waitNode("ul#script-links li.current span").then(() => {
- let searchBtn = domUtils.createElement("li", {
- innerHTML: `
- <a href="javascript:;">
- <span>${i18next.t("寻找引用")}</span>
- </a>`
- });
- domUtils.append(
- document.querySelector(
- "ul#script-links"
- ),
- searchBtn
- );
- domUtils.on(searchBtn, "click", async function() {
- let scriptIdMatch = window.location.pathname.match(/scripts\/([\d]+)/i);
- if (!scriptIdMatch) {
- log.error([scriptIdMatch, window.location.pathname]);
- Qmsg.error(i18next.t("获取脚本id失败"));
- return;
- }
- let scriptId = scriptIdMatch[scriptIdMatch.length - 1];
- window.location.href = GreasyforkApi.getCodeSearchUrl(
- `greasyfork.org/scripts/${scriptId}`
- );
- });
- });
- },
- /**
- * 脚本首页新增【今日检查】
- */
- async scriptHomepageAddedTodaySUpdate() {
- if (!document.querySelector("#install-area")) {
- return;
- }
- log.info("脚本首页新增【今日检查】");
- let scriptStatsJSONInfo = await GreasyforkApi.getScriptStats(
- GreasyforkApi.getScriptId()
- );
- if (!scriptStatsJSONInfo) {
- return;
- }
- let scriptStatsJSON = utils.toJSON(scriptStatsJSONInfo.responseText);
- log.info(["统计信息", scriptStatsJSON]);
- let todayStatsJSON = scriptStatsJSON[utils.formatTime(void 0, "yyyy-MM-dd")];
- if (!todayStatsJSON) {
- log.error("今日份的统计信息不存在");
- return;
- }
- let update_checks = todayStatsJSON["update_checks"];
- log.info(["今日统计信息", todayStatsJSON]);
- domUtils.after(
- "dd.script-show-daily-installs",
- domUtils.createElement("dt", {
- className: "script-show-daily-update_checks",
- innerHTML: `<span>${i18next.t("今日检查")}</span>`
- })
- );
- domUtils.after(
- "dt.script-show-daily-update_checks",
- domUtils.createElement("dd", {
- className: "script-show-daily-update_checks",
- innerHTML: "<span>" + update_checks + "</span>"
- })
- );
- },
- /**
- * 添加复制代码按钮
- */
- addCopyCodeButton() {
- log.info("添加复制代码按钮");
- utils.waitNode("div#script-content div.code-container").then(($codeContainer) => {
- let copyButton = domUtils.createElement(
- "button",
- {
- textContent: i18next.t("复制代码")
- },
- {
- style: "margin-bottom: 1em;"
- }
- );
- domUtils.on(copyButton, "click", async function() {
- let loading = Qmsg.loading(i18next.t("加载文件中..."));
- let getResp = await httpx.get(
- `https://greasyfork.org/zh-CN/scripts/${GreasyforkApi.getScriptId()}.json`,
- {
- fetch: true,
- responseType: "json"
- }
- );
- if (!getResp.status) {
- loading.close();
- return;
- }
- let respJSON = utils.toJSON(getResp.data.responseText);
- let code_url = respJSON["code_url"];
- log.success(["代码地址:", code_url]);
- let scriptJS = await httpx.get(code_url);
- if (!scriptJS.status) {
- loading.close();
- return;
- }
- loading.close();
- utils.setClip(scriptJS.data.responseText);
- Qmsg.success(i18next.t("复制成功"));
- });
- domUtils.before($codeContainer, copyButton);
- });
- }
- };
- const beautifyCenterContentCSS = '.sidebarred-main-content {\r\n max-width: unset;\r\n flex: unset;\r\n}\r\nol.script-list {\r\n display: flex;\r\n flex-wrap: wrap;\r\n border: none;\r\n gap: 20px;\r\n background: transparent;\r\n box-shadow: none;\r\n}\r\nol.script-list .script-description {\r\n overflow-wrap: anywhere;\r\n}\r\nol.script-list li {\r\n border: 1px solid rgb(221, 221, 221);\r\n border-radius: 5px;\r\n flex: 1 1 45%;\r\n box-shadow: rgb(221, 221, 221) 0px 0px 5px 2px;\r\n}\r\n/* 收藏按钮 */\r\n.script-collect-btn {\r\n color: #ffffff;\r\n border-color: #409eff;\r\n background-color: #409eff;\r\n}\r\n/* 评分按钮 */\r\n.script-list-rating-score[data-position="right"] {\r\n display: inline-block;\r\n min-width: 1em;\r\n text-align: center;\r\n padding: 0 0.25em;\r\n border: 1px solid #dddddd;\r\n border-radius: 10px;\r\n width: fit-content;\r\n}\r\n\r\n/* 加载圆圈动画 */\r\n.install-link.lum-lightbox-loader {\r\n position: relative;\r\n min-width: 4rem;\r\n min-height: 1rem;\r\n}\r\n.install-link.lum-lightbox-loader::before {\r\n margin-left: 1rem;\r\n}\r\n.install-link.lum-lightbox-loader::after {\r\n margin-right: 1rem;\r\n}\r\n.install-link.lum-lightbox-loader::before,\r\n.install-link.lum-lightbox-loader::after {\r\n width: 1em;\r\n height: 1em;\r\n margin-top: -0.5em;\r\n border-radius: 1em;\r\n background: hsla(0, 0%, 100%, 0.5);\r\n}\r\n';
- const GreasyforkCheckVersion = {
- /** 获取 TamperMonkey 暴露在window下的函数 */
- getTampermonkey: () => {
- var _a2;
- return (_a2 = _unsafeWindow.external) == null ? void 0 : _a2.Tampermonkey;
- },
- /** 获取 Violentmonkey 暴露在window下的函数 */
- getViolentmonkey: () => {
- var _a2;
- return (_a2 = _unsafeWindow.external) == null ? void 0 : _a2.Violentmonkey;
- },
- /** 获取 ScriptCat 暴露在window下的函数 */
- getScriptCat: () => {
- var _a2;
- return (_a2 = _unsafeWindow.external) == null ? void 0 : _a2.Scriptcat;
- },
- /**
- * 获取脚本容器启用状态
- */
- getScriptContainerStatus() {
- var _a2, _b, _c;
- let containerStatus = {
- Tampermonkey: false,
- Violentmonkey: false,
- ScriptCat: false
- };
- if ((_a2 = _unsafeWindow.external) == null ? void 0 : _a2.Tampermonkey) {
- containerStatus.Tampermonkey = true;
- }
- if ((_b = _unsafeWindow.external) == null ? void 0 : _b.Violentmonkey) {
- containerStatus.Violentmonkey = true;
- }
- if ((_c = _unsafeWindow.external) == null ? void 0 : _c.Scriptcat) {
- containerStatus.ScriptCat = true;
- }
- return containerStatus;
- },
- /**
- * 获取脚本安装的版本号
- * @param name 脚本名
- * @param namespace 脚本命名空间
- */
- getInstalledVersion(name, namespace) {
- return new Promise((resolve, reject) => {
- const tm = this.getTampermonkey();
- if (tm) {
- tm.isInstalled(name, namespace, function(data) {
- if (data.installed) {
- resolve(data.version);
- } else {
- resolve(null);
- }
- });
- return;
- }
- const vm = this.getViolentmonkey();
- if (vm) {
- vm.isInstalled(name, namespace).then(resolve);
- return;
- }
- const scriptCat = this.getScriptCat();
- if (scriptCat) {
- scriptCat.isInstalled(name, namespace, function(data) {
- if (data.installed) {
- resolve(data.version);
- } else {
- resolve(null);
- }
- });
- return;
- }
- reject(new TypeError("获取脚本容器暴露的external信息失败"));
- });
- },
- /**
- * https://developer.mozilla.org/en/docs/Toolkit_version_format
- *
- * 比较版本号
- * @param a 版本号
- * @param b 版本号
- * @returns
- * + -1 该版本号低
- * + 0 该版本号和比较的版本号相同
- * + 1 该版本号高
- */
- compareVersions(a, b) {
- if (a === b) {
- return 0;
- }
- const aParts = a.split(".");
- const bParts = b.split(".");
- for (let i = 0; i < aParts.length; i++) {
- const result = this.compareVersionPart(aParts[i], bParts[i]);
- if (result !== 0) {
- return result;
- }
- }
- return 0;
- },
- compareVersionPart(partA, partB) {
- const partAParts = this.parseVersionPart(partA);
- const partBParts = this.parseVersionPart(partB);
- for (let i = 0; i < partAParts.length; i++) {
- if (partAParts[i].length > 0 && partBParts[i].length === 0) {
- return -1;
- }
- if (partAParts[i].length === 0 && partBParts[i].length > 0) {
- return 1;
- }
- if (partAParts[i] > partBParts[i]) {
- return 1;
- }
- if (partAParts[i] < partBParts[i]) {
- return -1;
- }
- }
- return 0;
- },
- // It goes number, string, number, string. If it doesn't exist, then
- // 0 for numbers, empty string for strings.
- parseVersionPart(part) {
- if (!part) {
- return [0, "", 0, ""];
- }
- const partParts = /([0-9]*)([^0-9]*)([0-9]*)([^0-9]*)/.exec(part);
- return [
- partParts[1] ? parseInt(partParts[1]) : 0,
- partParts[2],
- partParts[3] ? parseInt(partParts[3]) : 0,
- partParts[4]
- ];
- },
- /**
- *
- * @param installButton 安装按钮
- * 必须属性
- * + data-update-label 按钮升级的文字
- * + data-downgrade-label 按钮降级的文字
- * + data-reinstall-label 按钮重装的文字
- * @param installedVersion 安装版本
- * @param version 版本号
- * @returns
- */
- handleInstallResult(installButton, installedVersion, version) {
- if (installedVersion == null) {
- return;
- }
- installButton.removeAttribute("data-ping-url");
- switch (this.compareVersions(installedVersion, version)) {
- case -1:
- installButton.textContent = installButton.getAttribute("data-update-label");
- break;
- case 1:
- installButton.textContent = installButton.getAttribute(
- "data-downgrade-label"
- );
- break;
- case 0:
- installButton.textContent = installButton.getAttribute(
- "data-reinstall-label"
- );
- break;
- }
- },
- /**
- * 检测js脚本的更新
- * @param installButton 安装按钮
- * 必须属性
- * + data-script-name 脚本名
- * + data-script-namespace 脚本命名空间
- * + data-script-version 脚本当前版本号
- * @param retry 重试
- */
- async checkForUpdatesJS(installButton, retry) {
- const name = installButton.getAttribute("data-script-name");
- const namespace = installButton.getAttribute("data-script-namespace");
- const version = installButton.getAttribute("data-script-version");
- try {
- let installedVersion = await this.getInstalledVersion(name, namespace);
- if (installedVersion == null) {
- return false;
- }
- this.handleInstallResult(installButton, installedVersion, version);
- return true;
- } catch (error) {
- if (retry) {
- await utils.sleep(1e3);
- try {
- return await this.checkForUpdatesJS(installButton, false);
- } catch (error2) {
- }
- }
- return false;
- }
- },
- /**
- * 检测css脚本的更新
- * @param installButton 安装按钮
- * 必须属性
- * + data-script-name 脚本名
- * + data-script-namespace 脚本命名空间
- */
- checkForUpdatesCSS(installButton) {
- const name = installButton.getAttribute("data-script-name");
- const namespace = installButton.getAttribute("data-script-namespace");
- postMessage(
- { type: "style-version-query", name, namespace, url: location.href },
- location.origin
- );
- }
- };
- const parseScriptListInfo = ($scriptList) => {
- let dataset = $scriptList.dataset;
- const info = {
- scriptId: parseInt(dataset.scriptId),
- scriptName: dataset.scriptName,
- scriptAuthors: [],
- scriptDailyInstalls: parseInt(dataset.scriptDailyInstalls),
- scriptTotalInstalls: parseInt(dataset.scriptTotalInstalls),
- scriptRatingScore: parseFloat(dataset.scriptRatingScore),
- scriptCreatedDate: new Date(dataset.scriptCreatedDate),
- scriptUpdatedDate: new Date(dataset.scriptUpdatedDate),
- scriptType: dataset.scriptType,
- scriptVersion: dataset.scriptVersion,
- sensitive: dataset.sensitive === "true",
- scriptLanguage: dataset.scriptLanguage,
- cssAvailableAsJs: dataset.cssAvailableAsJs === "true",
- codeUrl: dataset.codeUrl,
- scriptDescription: dataset.scriptDescription,
- scriptAuthorId: parseInt(dataset.scriptAuthorId),
- scriptAuthorName: dataset.scriptAuthorName
- };
- let scriptAuthorsObj = utils.toJSON(dataset.scriptAuthors);
- Object.keys(scriptAuthorsObj).forEach((authorId) => {
- let authorName = scriptAuthorsObj[authorId];
- info.scriptAuthors.push({
- authorId: parseInt(authorId),
- authorName
- });
- });
- if ((info.scriptAuthorName == null || isNaN(info.scriptAuthorId)) && info.scriptAuthors.length) {
- info.scriptAuthorName = info.scriptAuthors[0].authorName;
- info.scriptAuthorId = info.scriptAuthors[0].authorId;
- }
- if (info.scriptDescription == null) {
- let $description = $scriptList.querySelector(".script-description") || $scriptList.querySelector(".description");
- if ($description) {
- info.scriptDescription = $description.innerText || $description.textContent;
- }
- }
- return info;
- };
- const GreasyforkScriptsList = {
- init() {
- PopsPanel.execMenuOnce("gf-scripts-filter-enable", () => {
- GreasyforkScriptsFilter.init();
- });
- PopsPanel.execMenuOnce("beautifyCenterContent", () => {
- return this.beautifyCenterContent();
- });
- },
- /**
- * 美化脚本列表
- */
- beautifyCenterContent() {
- log.info("美化脚本列表");
- let result = [];
- result.push(_GM_addStyle(beautifyCenterContentCSS));
- DOMUtils.ready(async () => {
- let allScriptsList = GreasyforkScriptsFilter.getElementList();
- allScriptsList.forEach(($scriptList) => {
- if ($scriptList.querySelector(".script-list-operation")) {
- return;
- }
- let scriptInfo = parseScriptListInfo($scriptList);
- let $inlineStats = $scriptList.querySelector(
- ".inline-script-stats"
- );
- let code_url = scriptInfo.codeUrl;
- let $ratingScoreLeft = DOMUtils.createElement("dt", {
- className: "script-list-rating-score",
- innerHTML: `<span>${i18next.t("评分")}</span>`
- });
- let $ratingScoreRight = DOMUtils.createElement(
- "dd",
- {
- className: "script-list-rating-score",
- innerHTML: `<span>${scriptInfo.scriptRatingScore}</span>`
- },
- {
- "data-position": "right"
- }
- );
- let $goodRatingCount = $scriptList.querySelector(
- "dd.script-list-ratings .good-rating-count"
- );
- let $okRatingCount = $scriptList.querySelector(
- "dd.script-list-ratings .ok-rating-count"
- );
- let $badRatingCount = $scriptList.querySelector(
- "dd.script-list-ratings .bad-rating-count"
- );
- if ($goodRatingCount && $okRatingCount && $badRatingCount) {
- let goodRatingCount = parseInt($goodRatingCount.innerText);
- let okRatingCount = parseInt($okRatingCount.innerText);
- let badRatingCount = parseInt($badRatingCount.innerText);
- let totalRatingCount = goodRatingCount + okRatingCount + badRatingCount;
- if (totalRatingCount >= 10) {
- if (goodRatingCount / totalRatingCount >= 0.6) {
- $ratingScoreRight.classList.add("good-rating-count");
- } else {
- $ratingScoreRight.classList.add("bad-rating-count");
- }
- } else if (totalRatingCount == 0) {
- $ratingScoreRight.classList.add("good-rating-count");
- } else {
- if (goodRatingCount > okRatingCount + badRatingCount) {
- $ratingScoreRight.classList.add("good-rating-count");
- } else {
- $ratingScoreRight.classList.add("bad-rating-count");
- }
- }
- }
- let $versionLeft = DOMUtils.createElement("dt", {
- className: "script-list-version",
- innerHTML: (
- /*html*/
- `<span>${i18next.t("版本")}</span>`
- )
- });
- let $versionRight = DOMUtils.createElement(
- "dd",
- {
- className: "script-list-version",
- innerHTML: (
- /*html*/
- `<span>${scriptInfo.scriptVersion}</span>`
- )
- },
- {
- "data-position": "right"
- }
- );
- let $operationLeft = DOMUtils.createElement("dt", {
- className: "script-list-operation",
- innerHTML: `<span>${i18next.t("操作")}</span>`
- });
- let $operationRight = DOMUtils.createElement(
- "dd",
- {
- className: "script-list-operation",
- innerHTML: (
- /*html*/
- `
- <a
- target="_blank"
- class="install-link"
- data-install-format="js"
- data-script-name="${scriptInfo.scriptName}"
- data-script-namespace=""
- data-script-version="${scriptInfo.scriptVersion}"
- data-update-label="${i18next.t("更新到 {{version}} 版本", {
- version: scriptInfo.scriptVersion
- })}"
- data-downgrade-label="${i18next.t("降级到 {{version}} 版本", {
- version: scriptInfo.scriptVersion
- })}"
- data-reinstall-label="${i18next.t("重新安装 {{version}} 版本", {
- version: scriptInfo.scriptVersion
- })}"
- href="${code_url}"></a>
- <button class="script-collect-btn">${i18next.t("收藏")}</button>
- `
- )
- },
- {
- "data-position": "right",
- style: "gap:10px;display: flex;flex-wrap: wrap;align-items: center;"
- }
- );
- let $collect = $operationRight.querySelector(
- ".script-collect-btn"
- );
- let $installLink = $operationRight.querySelector(".install-link");
- $installLink["data-script-info"] = scriptInfo;
- $installLink.classList.add("lum-lightbox-loader");
- if (scriptInfo.scriptType === "library") {
- $installLink.remove();
- }
- DOMUtils.on($collect, "click", (event) => {
- utils.preventEvent(event);
- GreasyforkScriptsCollectEvent(scriptInfo.scriptId);
- });
- if (PopsPanel.getValue("gf-scripts-filter-enable")) {
- let $filter = DOMUtils.createElement("button", {
- className: "script-filter-btn",
- innerHTML: i18next.t("过滤")
- });
- let attr_filter_key = "data-filter-key";
- let attr_filter_value = "data-filter-value";
- DOMUtils.on($filter, "click", (event) => {
- utils.preventEvent(event);
- let $dialog = __pops.alert({
- title: {
- text: i18next.t("选择需要过滤的选项"),
- position: "center"
- },
- content: {
- text: (
- /*html*/
- `
- <button ${attr_filter_key}="scriptId" ${attr_filter_value}="^${scriptInfo.scriptId}$">${i18next.t("脚本id:{{text}}", {
- text: scriptInfo.scriptId
- })}</button>
- <button ${attr_filter_key}="scriptName" ${attr_filter_value}="^${utils.parseStringToRegExpString(
- scriptInfo.scriptName
- )}$">${i18next.t("脚本名:{{text}}", {
- text: scriptInfo.scriptName
- })}</button>
- `
- ),
- html: true
- },
- mask: {
- enable: true,
- clickEvent: {
- toClose: true
- }
- },
- width: "350px",
- height: "300px",
- drag: true,
- dragLimit: true,
- style: (
- /*css*/
- `
- .pops-alert-content{
- display: flex;
- flex-direction: column;
- gap: 20px;
- }
- .pops-alert-content button{
- text-wrap: wrap;
- padding: 8px;
- height: auto;
- text-align: left;
- }
- `
- )
- });
- let $content = $dialog.$shadowRoot.querySelector(
- ".pops-alert-content"
- );
- scriptInfo.scriptAuthors.forEach((scriptAuthorInfo) => {
- let $authorIdButton = DOMUtils.createElement("button", {
- innerHTML: i18next.t("作者id:{{text}}", {
- text: scriptAuthorInfo.authorId
- })
- });
- $authorIdButton.setAttribute(attr_filter_key, "scriptAuthorId");
- $authorIdButton.setAttribute(
- attr_filter_value,
- "^" + scriptAuthorInfo.authorId + "$"
- );
- let $authorNameButton = DOMUtils.createElement("button", {
- innerHTML: i18next.t("作者名:{{text}}", {
- text: scriptAuthorInfo.authorName
- })
- });
- $authorNameButton.setAttribute(
- attr_filter_key,
- "scriptAuthorName"
- );
- $authorNameButton.setAttribute(
- attr_filter_value,
- "^" + utils.parseStringToRegExpString(scriptAuthorInfo.authorName) + "$"
- );
- $content.appendChild($authorIdButton);
- $content.appendChild($authorNameButton);
- });
- DOMUtils.on(
- $dialog.$shadowRoot,
- "click",
- `button[${attr_filter_key}]`,
- (event2) => {
- utils.preventEvent(event2);
- let $click = event2.target;
- let key = $click.getAttribute(
- attr_filter_key
- );
- let value = $click.getAttribute(attr_filter_value);
- GreasyforkScriptsFilter.addValue(key, value);
- $dialog.close();
- GreasyforkScriptsFilter.filter();
- Qmsg.success(i18next.t("添加成功"));
- }
- );
- });
- $operationRight.appendChild($filter);
- }
- $inlineStats.appendChild($ratingScoreLeft);
- $inlineStats.appendChild($ratingScoreRight);
- $inlineStats.appendChild($versionLeft);
- $inlineStats.appendChild($versionRight);
- $inlineStats.appendChild($operationLeft);
- $inlineStats.appendChild($operationRight);
- });
- let $installLinkList = Array.from(
- document.querySelectorAll(
- ".install-link[data-install-format=js]"
- )
- );
- let scriptContainerStatus = GreasyforkCheckVersion.getScriptContainerStatus();
- let hasScriptContainer = Object.values(scriptContainerStatus).filter(
- Boolean
- );
- if (!scriptContainerStatus.Tampermonkey) {
- $installLinkList.forEach(async ($installLink) => {
- let result2 = await GreasyforkCheckVersion.checkForUpdatesJS(
- $installLink,
- true
- );
- $installLink.classList.remove("lum-lightbox-loader");
- if (!result2) {
- $installLink.textContent = i18next.t("安装此脚本");
- }
- });
- } else if (hasScriptContainer.length) {
- for (let index = 0; index < $installLinkList.length; index++) {
- let $installLink = $installLinkList[index];
- let scriptInfo = $installLink["data-script-info"];
- let getResp = await httpx.get(
- GreasyforkUrlUtils.getScriptInfoUrl(scriptInfo.scriptId),
- {
- fetch: true
- }
- );
- if (!getResp.status) {
- $installLink.textContent = i18next.t("安装此脚本");
- continue;
- }
- let data = utils.toJSON(
- getResp.data.responseText
- );
- $installLink.setAttribute("data-script-namespace", data.namespace);
- let result2 = await GreasyforkCheckVersion.checkForUpdatesJS(
- $installLink,
- true
- );
- $installLink.classList.remove("lum-lightbox-loader");
- if (!result2) {
- $installLink.textContent = i18next.t("安装此脚本");
- }
- await utils.sleep(150);
- }
- } else {
- log.error("未知的脚本容器");
- }
- });
- return result;
- }
- };
- const GreasyforkScriptsFilter = {
- /** 存储的键 */
- key: "gf-shield-rule",
- init() {
- log.info("脚本过滤");
- let lockFunction = new utils.LockFunction(() => {
- this.filter();
- }, 50);
- domUtils.ready(() => {
- utils.mutationObserver(document.body, {
- config: {
- subtree: true,
- childList: true
- },
- callback: () => {
- lockFunction.run();
- }
- });
- lockFunction.run();
- });
- },
- /**
- * 获取脚本列表元素
- */
- getElementList() {
- let scriptList = [];
- scriptList = scriptList.concat(
- Array.from(document.querySelectorAll("ol.script-list li"))
- );
- return scriptList;
- },
- /**
- * 对页面进行过滤
- */
- filter() {
- this.getElementList().forEach(($scriptList) => {
- let data = parseScriptListInfo($scriptList);
- let localValueSplit = this.getValue().split("\n");
- for (let index = 0; index < localValueSplit.length; index++) {
- let localRule = localValueSplit[index];
- let ruleSplit = localRule.split("##");
- let ruleName = ruleSplit[0];
- let ruleValue = ruleSplit[1];
- if (ruleName === "scriptRatingScore") {
- let userRatingScoreValue = parseFloat(ruleValue.slice(1));
- if (ruleValue.startsWith(">")) {
- if (data.scriptRatingScore > userRatingScoreValue) {
- log.info(["触发脚本过滤规则", [localRule, data]]);
- $scriptList.remove();
- break;
- }
- } else if (ruleValue.startsWith("<")) {
- if (data.scriptRatingScore < userRatingScoreValue) {
- log.info(["触发脚本过滤规则", [localRule, data]]);
- $scriptList.remove();
- break;
- }
- }
- } else if (ruleName in data || ruleName === "scriptDescription") {
- if (typeof ruleValue !== "string") {
- continue;
- }
- let ruleValueRegExp = new RegExp(ruleValue, "ig");
- let scriptInfoString = String(data[ruleName]);
- if (scriptInfoString.match(ruleValueRegExp)) {
- log.info(["触发脚本过滤规则", localRule, data]);
- $scriptList.remove();
- break;
- }
- }
- }
- });
- },
- setValue(value) {
- PopsPanel.setValue(this.key, value);
- },
- addValue(key, value) {
- let localValue = this.getValue();
- if (localValue.trim() !== "") {
- localValue += "\n";
- }
- if (utils.isNull(key)) {
- return;
- }
- key = key.toString().trim();
- let rule = key + "##" + value;
- localValue += rule;
- this.setValue(localValue);
- },
- getValue() {
- return PopsPanel.getValue(this.key, "");
- }
- };
- const SettingUIScripts = {
- id: "greasy-fork-panel-config-scripts",
- title: i18next.t("脚本"),
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- {
- text: i18next.t("代码"),
- type: "deepMenu",
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("添加复制代码按钮"),
- "addCopyCodeButton",
- true,
- void 0,
- i18next.t("更优雅的复制")
- ),
- UISwitch(
- i18next.t("快捷键"),
- "fullScreenOptimization",
- true,
- void 0,
- i18next.t("【F】键全屏、【Alt+Shift+F】键宽屏")
- ),
- UISwitch(
- i18next.t("修复代码行号显示"),
- "code-repairCodeLineNumber",
- true,
- void 0,
- i18next.t("修复代码行数超过1k行号显示不全问题")
- )
- ]
- }
- ]
- },
- {
- text: i18next.t("历史版本"),
- type: "deepMenu",
- forms: [
- {
- text: i18next.t("功能"),
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("添加额外的标签按钮"),
- "scripts-versions-addExtraTagButton",
- true,
- void 0,
- i18next.t("在版本下面添加【安装】、【查看代码】按钮")
- )
- ]
- },
- {
- text: i18next.t("美化"),
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("美化历史版本页面"),
- "beautifyHistoryVersionPage",
- true,
- void 0,
- i18next.t("更直观的查看版本迭代")
- )
- ]
- }
- ]
- }
- ]
- },
- {
- text: "",
- type: "forms",
- forms: [
- {
- text: i18next.t("功能"),
- type: "deepMenu",
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("添加【寻找引用】按钮"),
- "addFindReferenceButton",
- true,
- void 0,
- i18next.t("在脚本栏添加按钮,一般用于搜索引用该库的相关脚本")
- ),
- UISwitch(
- i18next.t("添加【收藏】按钮"),
- "addCollectionButton",
- true,
- void 0,
- i18next.t("在脚本栏添加按钮,一般用于快捷收藏该脚本/库")
- ),
- UISwitch(
- i18next.t("添加【今日检查】信息块"),
- "scriptHomepageAddedTodaySUpdate",
- true,
- void 0,
- i18next.t("在脚本信息栏添加【今日检查】信息块")
- )
- ]
- }
- ]
- },
- {
- text: i18next.t("美化"),
- type: "deepMenu",
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("美化脚本列表"),
- "beautifyCenterContent",
- true,
- void 0,
- i18next.t("双列显示且添加脚本卡片操作项(安装、收藏)")
- )
- ]
- }
- ]
- },
- {
- text: i18next.t("过滤"),
- type: "deepMenu",
- forms: [
- {
- text: `<a target="_blank" href="https://greasyfork.org/zh-CN/scripts/475722-greasyfork%E4%BC%98%E5%8C%96#:~:text=%E8%84%9A%E6%9C%AC%E8%BF%87%E6%BB%A4%E8%A7%84%E5%88%99">${i18next.t(
- "帮助文档"
- )}</a>`,
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("启用"),
- "gf-scripts-filter-enable",
- true,
- void 0,
- i18next.t("作用域:脚本、脚本搜索、用户主页")
- ),
- {
- type: "own",
- getLiElementCallBack(liElement) {
- let textareaDiv = domUtils.createElement(
- "div",
- {
- className: "pops-panel-textarea",
- innerHTML: `
- <textarea placeholder="${i18next.t(
- "请输入规则,每行一个"
- )}" style="height:200px;"></textarea>`
- },
- {
- style: "width: 100%;"
- }
- );
- let $textarea = textareaDiv.querySelector(
- "textarea"
- );
- $textarea.value = GreasyforkScriptsFilter.getValue();
- domUtils.on(
- $textarea,
- ["input", "propertychange"],
- void 0,
- utils.debounce(function(event) {
- GreasyforkScriptsFilter.setValue($textarea.value);
- }, 200)
- );
- liElement.appendChild(textareaDiv);
- return liElement;
- }
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- };
- const GreasyforkDiscussionsFilter = {
- /** 存储的键 */
- key: "gf-discuessions-filter-rule",
- $data: {
- /** 脚本 */
- FILTER_SCRIPT_KEY: "greasyfork-discussions-filter-script",
- /** 发布用户 */
- FILTER_POST_USER_KEY: "greasyfork-discussions-filter-post-user",
- /** 回复用户 */
- FILTER_REPLY_USER_KEY: "greasyfork-discussions-filter-reply-user"
- },
- init() {
- log.info("论坛-过滤");
- _GM_addStyle(
- /*css*/
- `
- .discussion-list-container {
- --discusstion-repeat-color: #ffa700;
- }
- .discussion-list-container a.discussion-title[data-repeat-tip-show]::before {
- content: attr(data-repeat-tip-show);
- color: var(--discusstion-repeat-color);
- border-radius: 5px;
- border: 2px solid var(--discusstion-repeat-color);
- padding: 2px 5px;
- font-weight: 800;
- font-size: 14px;
- }
- `
- );
- let lockFunction = new utils.LockFunction(() => {
- this.filter();
- }, 50);
- utils.mutationObserver(document.body, {
- config: {
- subtree: true,
- childList: true
- },
- callback: () => {
- lockFunction.run();
- }
- });
- lockFunction.run();
- },
- /**
- * 获取反馈列表元素
- */
- getElementList() {
- let discussionsListContainer = [];
- discussionsListContainer = discussionsListContainer.concat(
- Array.from(
- document.querySelectorAll(".discussion-list-container")
- )
- );
- return discussionsListContainer;
- },
- /**
- * 论坛-过滤
- */
- filter() {
- this.transformOldRule();
- const SNIPPET_MAP = /* @__PURE__ */ new Map();
- this.getElementList().forEach(($listContainer, index) => {
- const discussionInfo = this.parseDiscuessionListContainerInfo($listContainer);
- let localValueSplit = this.getValue().split("\n");
- if (SNIPPET_MAP.has(discussionInfo.snippet) && PopsPanel.getValue("greasyfork-discussions-filter-duplicate-comments")) {
- let discussionTitleElement = SNIPPET_MAP.get(
- discussionInfo.snippet
- ).querySelector("a.discussion-title");
- discussionTitleElement.setAttribute("data-repeat-tip-show", "true");
- let oldCount = 0;
- if (discussionTitleElement.hasAttribute("data-repeat-count")) {
- oldCount = parseInt(
- discussionTitleElement.getAttribute("data-repeat-count")
- );
- }
- oldCount++;
- discussionTitleElement.setAttribute(
- "data-repeat-count",
- oldCount.toString()
- );
- discussionTitleElement.setAttribute(
- "data-repeat-tip-show",
- i18next.t("已过滤:{{oldCount}}", { oldCount })
- );
- log.success([
- `过滤重复内容:${discussionInfo.snippet}`,
- discussionInfo
- ]);
- $listContainer.remove();
- return;
- }
- SNIPPET_MAP.set(discussionInfo.snippet, $listContainer);
- for (let index2 = 0; index2 < localValueSplit.length; index2++) {
- let localRule = localValueSplit[index2];
- let ruleSplit = localRule.split("##");
- let ruleName = ruleSplit[0];
- let ruleValue = ruleSplit[1];
- if (ruleName in discussionInfo) {
- let ruleValueRegExp = new RegExp(ruleValue, "ig");
- if (discussionInfo[ruleName] != null) {
- let scriptInfoString = String(discussionInfo[ruleName]);
- if (scriptInfoString.match(ruleValueRegExp)) {
- log.info(["触发论坛过滤规则", localRule, discussionInfo]);
- $listContainer.remove();
- return;
- }
- }
- }
- }
- });
- },
- /**
- * 解析出元素上的属性
- */
- parseDiscuessionListContainerInfo($listContainer) {
- var _a2, _b, _c, _d;
- const info = {
- /** 脚本名 */
- scriptName: $listContainer.querySelector(
- ".discussion-meta-item-script-name"
- ).innerText,
- /** 脚本主页地址 */
- scriptUrl: (_a2 = $listContainer.querySelector(
- ".discussion-meta-item-script-name a"
- )) == null ? void 0 : _a2.href,
- /** 脚本id */
- scriptId: GreasyforkApi.getScriptId(
- (_b = $listContainer.querySelector(
- ".discussion-meta-item-script-name a"
- )) == null ? void 0 : _b.href
- ),
- /** 发布的用户名 */
- postUserName: $listContainer.querySelector("a.user-link").innerText,
- /** 发布的用户主页地址 */
- postUserHomeUrl: $listContainer.querySelector("a.user-link").href,
- /** 发布的用户id */
- postUserId: GreasyforkApi.getUserId(
- $listContainer.querySelector("a.user-link").href
- ),
- /** 发布的时间 */
- postTimeStamp: new Date(
- $listContainer.querySelector("relative-time").getAttribute("datetime")
- ),
- /** 发布的地址*/
- snippetUrl: $listContainer.querySelector("a.discussion-title").href,
- /** 发布的内容片段*/
- snippet: ((_c = $listContainer.querySelector("span.discussion-snippet")) == null ? void 0 : _c.innerText) || "",
- /** (如果有)回复的用户名*/
- replyUserName: void 0,
- /** (如果有)回复的用户主页地址*/
- replyUserHomeUrl: void 0,
- /** (如果有)回复的用户id*/
- replyUserId: void 0,
- /** (如果有)回复的时间 */
- replyTimeStamp: void 0
- };
- if ($listContainer.querySelector(
- ".discussion-meta-item .discussion-meta-item"
- )) {
- info.replyUserName = $listContainer.querySelector(
- ".discussion-meta-item .discussion-meta-item a.user-link"
- ).innerText;
- info.replyUserHomeUrl = $listContainer.querySelector(
- ".discussion-meta-item .discussion-meta-item a.user-link"
- ).href;
- info.replyUserId = GreasyforkApi.getUserId(info.replyUserHomeUrl);
- info.replyTimeStamp = new Date(
- (_d = $listContainer.querySelector(
- ".discussion-meta-item .discussion-meta-item relative-time"
- )) == null ? void 0 : _d.getAttribute("datetime")
- );
- }
- return info;
- },
- /** 转换旧规则 @deprecated */
- transformOldRule() {
- if (Date.now() > (/* @__PURE__ */ new Date("2024-8-19")).getTime()) {
- return;
- }
- const FILTER_SCRIPT_KEY = "greasyfork-discussions-filter-script";
- const FILTER_POST_USER_KEY = "greasyfork-discussions-filter-post-user";
- const FILTER_REPLY_USER_KEY = "greasyfork-discussions-filter-reply-user";
- const filterScript = PopsPanel.getValue(FILTER_SCRIPT_KEY, "");
- const filterPostUser = PopsPanel.getValue(FILTER_POST_USER_KEY, "");
- const filterReplyUser = PopsPanel.getValue(FILTER_REPLY_USER_KEY, "");
- const filterScriptList = filterScript.trim() === "" ? [] : filterScript.split("\n");
- const filterPostUserList = filterPostUser.trim() === "" ? [] : filterPostUser.split("\n");
- const filterReplyUserList = filterReplyUser.trim() === "" ? [] : filterReplyUser.split("\n");
- filterScriptList.forEach((ruleValue) => {
- this.addValue(
- "scriptId",
- utils.parseStringToRegExpString("^" + ruleValue + "$")
- );
- });
- filterPostUserList.forEach((ruleValue) => {
- this.addValue(
- "postUserId",
- utils.parseStringToRegExpString("^" + ruleValue + "$")
- );
- });
- filterReplyUserList.forEach((ruleValue) => {
- this.addValue(
- "replyUserId",
- utils.parseStringToRegExpString("^" + ruleValue + "$")
- );
- });
- PopsPanel.deleteValue(FILTER_SCRIPT_KEY);
- PopsPanel.deleteValue(FILTER_POST_USER_KEY);
- PopsPanel.deleteValue(FILTER_REPLY_USER_KEY);
- },
- setValue(value) {
- PopsPanel.setValue(this.key, value);
- },
- addValue(key, value) {
- let localValue = this.getValue();
- if (localValue.trim() !== "") {
- localValue += "\n";
- }
- if (utils.isNull(key)) {
- return;
- }
- key = key.toString().trim();
- let rule = key + "##" + value;
- localValue += rule;
- this.setValue(localValue);
- },
- getValue() {
- return PopsPanel.getValue(this.key, "");
- }
- };
- const SettingUIDiscuessions = {
- id: "greasy-fork-panel-config-discussions",
- title: i18next.t("论坛"),
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- {
- text: i18next.t("功能"),
- type: "deepMenu",
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- {
- type: "own",
- attributes: {
- "data-key": "discussions-readBgColor",
- "data-default-value": "#e5e5e5"
- },
- getLiElementCallBack(liElement) {
- let key = "discussions-readBgColor";
- let $left = domUtils.createElement("div", {
- className: "pops-panel-item-left-text",
- innerHTML: `
- <p class="pops-panel-item-left-main-text">${i18next.t("自定义已读颜色")}</p>
- <p class="pops-panel-item-left-desc-text">${i18next.t("在讨论内生效")}</p>
- `
- });
- let $right = domUtils.createElement("div", {
- className: "pops-panel-item-right",
- innerHTML: `
- <input type="color" class="pops-color-choose" />
- `
- });
- let $color = $right.querySelector(
- ".pops-color-choose"
- );
- $color.value = PopsPanel.getValue(key);
- let $style = domUtils.createElement("style");
- domUtils.append(document.head, $style);
- domUtils.on(
- $color,
- ["input", "propertychange"],
- (event) => {
- log.info("选择颜色:" + $color.value);
- $style.innerHTML = `
- .discussion-read{
- background: ${$color.value} !important;
- }
- `;
- PopsPanel.setValue(key, $color.value);
- }
- );
- liElement.appendChild($left);
- liElement.appendChild($right);
- return liElement;
- }
- },
- UISwitch(
- i18next.t("添加快捷操作按钮"),
- "discussions-addShortcutOperationButton",
- true,
- void 0,
- i18next.t(
- "在每一行讨论的最后面添加【过滤】按钮,需开启过滤功能才会生效"
- )
- )
- ]
- }
- ]
- },
- {
- text: i18next.t("过滤"),
- type: "deepMenu",
- forms: [
- {
- text: `<a target="_blank" href="https://greasyfork.org/zh-CN/scripts/475722-greasyfork%E4%BC%98%E5%8C%96#:~:text=%E8%AE%BA%E5%9D%9B%E8%BF%87%E6%BB%A4%E8%A7%84%E5%88%99">${i18next.t(
- "帮助文档"
- )}</a>`,
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("启用"),
- "greasyfork-discussions-filter-enable",
- true,
- void 0,
- i18next.t("开启后下面的过滤功能才会生效")
- ),
- UISwitch(
- i18next.t("过滤重复的评论"),
- "greasyfork-discussions-filter-duplicate-comments",
- false,
- void 0,
- i18next.t("过滤掉重复的评论数量(≥2)")
- ),
- {
- type: "own",
- getLiElementCallBack(liElement) {
- let textareaDiv = domUtils.createElement(
- "div",
- {
- className: "pops-panel-textarea",
- innerHTML: `
- <textarea placeholder="${i18next.t(
- "请输入规则,每行一个"
- )}" style="height:200px;"></textarea>`
- },
- {
- style: "width: 100%;"
- }
- );
- let $textarea = textareaDiv.querySelector(
- "textarea"
- );
- $textarea.value = GreasyforkDiscussionsFilter.getValue();
- domUtils.on(
- $textarea,
- ["input", "propertychange"],
- void 0,
- utils.debounce(function(event) {
- GreasyforkDiscussionsFilter.setValue($textarea.value);
- }, 200)
- );
- liElement.appendChild(textareaDiv);
- return liElement;
- }
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- };
- const PopsPanelUISetting = {
- /**
- * 面板-脚本列表|库
- * @param type
- * @param event
- * @param rightHeaderElement
- * @param rightContainerElement
- * @returns
- */
- async UIScriptList(type, event, rightHeaderElement, rightContainerElement) {
- var _a2, _b, _c;
- if (!GreasyforkMenu.isLogin) {
- Qmsg.error(i18next.t("请先登录账号!"));
- return;
- }
- let userLinkElement = GreasyforkMenu.getUserLinkElement();
- let userLink = userLinkElement.href;
- let userId = (_c = (_b = (_a2 = userLink == null ? void 0 : userLink.split("/")) == null ? void 0 : _a2.pop()) == null ? void 0 : _b.match(/([0-9]+)/)) == null ? void 0 : _c[0];
- let loading = __pops.loading({
- mask: {
- enable: true
- },
- parent: rightContainerElement,
- content: {
- text: i18next.t("获取信息中,请稍后...")
- },
- addIndexCSS: false
- });
- let userInfo = await GreasyforkApi.getUserInfo(userId);
- loading.close();
- if (!userInfo) {
- return;
- }
- log.info(userInfo);
- let scriptList = type === "script-list" ? userInfo["scriptList"] : userInfo["scriptLibraryList"];
- Qmsg.success(
- i18next.t("获取成功,共 {{count}} 个", {
- count: scriptList.length
- })
- );
- for (const scriptInfo of scriptList) {
- let liElement = domUtils.createElement("li", {
- className: "w-script-list-item",
- innerHTML: (
- /*html*/
- `
- <div class="w-script-info">
- <div class="w-script-name">
- <a href="${scriptInfo["url"]}" target="_blank">${scriptInfo["name"]}</a>
- </div>
- <div class="w-script-fan-score">
- <p>${i18next.t("评分:")}${scriptInfo["fan_score"]}</p>
- </div>
- <div class="w-script-locale">
- <p>${i18next.t("语言:")}${scriptInfo["locale"]}</p>
- </div>
- <div class="w-script-version">
- <p>${i18next.t("版本:")}${scriptInfo["version"]}</p>
- </div>
- <div class="w-script-update-time">
- <p>${i18next.t("更新:")}${utils.getDaysDifference(
- new Date(scriptInfo["code_updated_at"]).getTime(),
- void 0,
- "auto"
- )}前</p>
- </div>
- </div>
- `
- )
- });
- let scriptInfoElement = liElement.querySelector(
- ".w-script-info"
- );
- let buttonElement = domUtils.createElement("div", {
- className: "pops-panel-button",
- innerHTML: (
- /*html*/
- `
- <button type="primary" data-icon="" data-righticon="false">
- <span>${i18next.t("同步代码")}</span>
- </button>
- `
- )
- });
- if (scriptInfo["deleted"]) {
- liElement.classList.add("w-script-deleted");
- buttonElement.querySelector("button").setAttribute("disabled", "true");
- }
- domUtils.on(buttonElement, "click", void 0, async function() {
- log.success(["同步", scriptInfo]);
- let btn = buttonElement.querySelector("button");
- let span = buttonElement.querySelector(
- "button span"
- );
- let iconElement = domUtils.createElement(
- "i",
- {
- className: "pops-bottom-icon",
- innerHTML: __pops.config.iconSVG.loading
- },
- {
- "is-loading": true
- }
- );
- btn.setAttribute("disabled", "true");
- btn.setAttribute("data-icon", "true");
- span.innerText = i18next.t("同步中...");
- domUtils.before(span, iconElement);
- let scriptId = scriptInfo == null ? void 0 : scriptInfo["id"];
- let codeSyncFormData = await GreasyforkApi.getSourceCodeSyncFormData(
- scriptId.toString()
- );
- if (codeSyncFormData) {
- const SCRIPT_SYNC_TYPE_ID_FORMDATA_KEY = "script[script_sync_type_id]";
- if (codeSyncFormData.has(SCRIPT_SYNC_TYPE_ID_FORMDATA_KEY)) {
- let syncTypeId = codeSyncFormData.get(
- SCRIPT_SYNC_TYPE_ID_FORMDATA_KEY
- );
- let syncMode = "";
- if (syncTypeId.toString() === "1") {
- syncMode = i18next.t("手动");
- } else if (syncTypeId.toString() === "2") {
- syncMode = i18next.t("自动");
- } else if (syncTypeId.toString() === "3") {
- syncMode = "webhook";
- }
- let oldSyncTypeElement = liElement.querySelector(
- ".w-script-sync-type"
- );
- if (oldSyncTypeElement) {
- oldSyncTypeElement.querySelector("p").innerText = i18next.t(
- "同步方式:{{syncMode}}",
- { syncMode }
- );
- } else {
- domUtils.append(
- scriptInfoElement,
- /*html*/
- `
- <div class="w-script-sync-type">
- <p>${i18next.t("同步方式:{{syncMode}}", {
- syncMode
- })}
- </p>
- </div>`
- );
- }
- let syncUpdateResponse = await GreasyforkApi.sourceCodeSync(
- scriptInfo["id"].toString(),
- codeSyncFormData
- );
- if (syncUpdateResponse) {
- Qmsg.success(i18next.t("同步成功"));
- } else {
- Qmsg.error(i18next.t("同步失败"));
- }
- } else {
- Qmsg.error(i18next.t("该脚本未设置同步信息"));
- }
- }
- btn.removeAttribute("disabled");
- btn.removeAttribute("data-icon");
- span.innerText = i18next.t("同步代码");
- iconElement.remove();
- });
- liElement.appendChild(buttonElement);
- rightContainerElement.appendChild(liElement);
- }
- }
- };
- const SettingUIScriptList = {
- id: "greasy-fork-panel-config-script-list",
- title: i18next.t("脚本列表"),
- callback(event, rightHeaderElement, rightContainerElement) {
- PopsPanelUISetting.UIScriptList(
- "script-list",
- event,
- rightHeaderElement,
- rightContainerElement
- );
- },
- forms: []
- };
- const SettingUIScriptLib = {
- id: "greasy-fork-panel-config-library",
- title: i18next.t("库"),
- callback(event, rightHeaderElement, rightContainerElement) {
- PopsPanelUISetting.UIScriptList(
- "script-library",
- event,
- rightHeaderElement,
- rightContainerElement
- );
- },
- forms: []
- };
- const UIScriptListCSS = '.w-script-list-item {\r\n padding: 10px 0;\r\n border-bottom: 1px solid #e5e5e5;\r\n font-size: 16px;\r\n text-align: left;\r\n}\r\n.w-script-version,\r\n.w-script-fan-score,\r\n.w-script-create-time,\r\n.w-script-update-time,\r\n.w-script-locale,\r\n.w-script-sync-type {\r\n font-size: 14px;\r\n color: #7c7c7c;\r\n}\r\n.w-script-fan-score {\r\n margin-left: unset !important;\r\n text-align: unset !important;\r\n max-width: unset !important;\r\n}\r\n.w-script-deleted {\r\n text-decoration: line-through;\r\n font-style: italic;\r\n color: red;\r\n}\r\n.w-script-deleted .w-script-name::before {\r\n content: "【删除】";\r\n}\r\n\r\nli[data-key="user"] .pops-panel-input,\r\nli[data-key="pwd"] .pops-panel-input {\r\n max-width: 200px;\r\n}\r\n';
- const SettingUIUsers = {
- id: "greasy-fork-panel-config-account",
- title: i18next.t("用户"),
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- {
- text: i18next.t("功能"),
- type: "deepMenu",
- forms: [
- {
- text: "",
- type: "forms",
- forms: [
- UISwitch(
- i18next.t("迁移【控制台】到顶部导航栏"),
- "users-changeConsoleToTopNavigator",
- true,
- void 0,
- i18next.t("将【控制台】按钮移动到顶部导航栏,节省空间")
- )
- ]
- }
- ]
- }
- ]
- }
- ]
- };
- const __PopsPanel__ = {
- data: null,
- oneSuccessExecMenu: null,
- onceExec: null,
- listenData: null
- };
- const PopsPanel = {
- /** 数据 */
- $data: {
- /**
- * 菜单项的默认值
- */
- get data() {
- if (__PopsPanel__.data == null) {
- __PopsPanel__.data = new utils.Dictionary();
- }
- return __PopsPanel__.data;
- },
- /**
- * 成功只执行了一次的项
- */
- get oneSuccessExecMenu() {
- if (__PopsPanel__.oneSuccessExecMenu == null) {
- __PopsPanel__.oneSuccessExecMenu = new utils.Dictionary();
- }
- return __PopsPanel__.oneSuccessExecMenu;
- },
- /**
- * 成功只执行了一次的项
- */
- get onceExec() {
- if (__PopsPanel__.onceExec == null) {
- __PopsPanel__.onceExec = new utils.Dictionary();
- }
- return __PopsPanel__.onceExec;
- },
- /** 脚本名,一般用在设置的标题上 */
- get scriptName() {
- return SCRIPT_NAME;
- },
- /** 菜单项的总值在本地数据配置的键名 */
- key: KEY,
- /** 菜单项在attributes上配置的菜单键 */
- attributeKeyName: ATTRIBUTE_KEY,
- /** 菜单项在attributes上配置的菜单默认值 */
- attributeDefaultValueName: ATTRIBUTE_DEFAULT_VALUE
- },
- /** 监听器 */
- $listener: {
- /**
- * 值改变的监听器
- */
- get listenData() {
- if (__PopsPanel__.listenData == null) {
- __PopsPanel__.listenData = new utils.Dictionary();
- }
- return __PopsPanel__.listenData;
- }
- },
- init() {
- this.initPanelDefaultValue();
- this.initExtensionsMenu();
- },
- initExtensionsMenu() {
- if (_unsafeWindow.top !== _unsafeWindow.self) {
- return;
- }
- GM_Menu.add([
- {
- key: "show_pops_panel_setting",
- text: i18next.t("⚙ 设置"),
- autoReload: false,
- isStoreValue: false,
- showText(text) {
- return text;
- },
- callback: () => {
- this.showPanel();
- }
- }
- ]);
- },
- /** 初始化本地设置默认的值 */
- initPanelDefaultValue() {
- let that = this;
- function initDefaultValue(config) {
- if (!config.attributes) {
- return;
- }
- let key = config.attributes[ATTRIBUTE_KEY];
- let defaultValue = config.attributes[ATTRIBUTE_DEFAULT_VALUE];
- let __attr_init__ = config.attributes[ATTRIBUTE_INIT];
- if (typeof __attr_init__ === "function") {
- let __attr_result__ = __attr_init__();
- if (typeof __attr_result__ === "boolean" && !__attr_result__) {
- return;
- }
- }
- if (key == null) {
- log.warn(["请先配置键", config]);
- return;
- }
- if (that.$data.data.has(key)) {
- log.warn("请检查该key(已存在): " + key);
- }
- that.$data.data.set(key, defaultValue);
- }
- function loopInitDefaultValue(configList) {
- for (let index = 0; index < configList.length; index++) {
- let configItem = configList[index];
- initDefaultValue(configItem);
- let childForms = configItem.forms;
- if (childForms && Array.isArray(childForms)) {
- loopInitDefaultValue(childForms);
- }
- }
- }
- let contentConfigList = this.getPanelContentConfig();
- for (let index = 0; index < contentConfigList.length; index++) {
- let leftContentConfigItem = contentConfigList[index];
- if (!leftContentConfigItem.forms) {
- continue;
- }
- let rightContentConfigList = leftContentConfigItem.forms;
- if (rightContentConfigList && Array.isArray(rightContentConfigList)) {
- loopInitDefaultValue(rightContentConfigList);
- }
- }
- },
- /**
- * 设置值
- * @param key 键
- * @param value 值
- */
- setValue(key, value) {
- let locaData = _GM_getValue(KEY, {});
- let oldValue = locaData[key];
- locaData[key] = value;
- _GM_setValue(KEY, locaData);
- if (this.$listener.listenData.has(key)) {
- this.$listener.listenData.get(key).callback(key, oldValue, value);
- }
- },
- /**
- * 获取值
- * @param key 键
- * @param defaultValue 默认值
- */
- getValue(key, defaultValue) {
- let locaData = _GM_getValue(KEY, {});
- let localValue = locaData[key];
- if (localValue == null) {
- if (this.$data.data.has(key)) {
- return this.$data.data.get(key);
- }
- return defaultValue;
- }
- return localValue;
- },
- /**
- * 删除值
- * @param key 键
- */
- deleteValue(key) {
- let locaData = _GM_getValue(KEY, {});
- let oldValue = locaData[key];
- Reflect.deleteProperty(locaData, key);
- _GM_setValue(KEY, locaData);
- if (this.$listener.listenData.has(key)) {
- this.$listener.listenData.get(key).callback(key, oldValue, void 0);
- }
- },
- /**
- * 监听调用setValue、deleteValue
- * @param key 需要监听的键
- * @param callback
- */
- addValueChangeListener(key, callback, option) {
- let listenerId = Math.random();
- this.$listener.listenData.set(key, {
- id: listenerId,
- key,
- callback
- });
- if (option) {
- if (option.immediate) {
- callback(key, this.getValue(key), this.getValue(key));
- }
- }
- return listenerId;
- },
- /**
- * 移除监听
- * @param listenerId 监听的id
- */
- removeValueChangeListener(listenerId) {
- let deleteKey = null;
- for (const [key, value] of this.$listener.listenData.entries()) {
- if (value.id === listenerId) {
- deleteKey = key;
- break;
- }
- }
- if (typeof deleteKey === "string") {
- this.$listener.listenData.delete(deleteKey);
- } else {
- console.warn("没有找到对应的监听器");
- }
- },
- /**
- * 判断该键是否存在
- * @param key 键
- */
- hasKey(key) {
- let locaData = _GM_getValue(KEY, {});
- return key in locaData;
- },
- /**
- * 自动判断菜单是否启用,然后执行回调
- * @param key
- * @param callback 回调
- */
- execMenu(key, callback) {
- if (typeof key !== "string") {
- throw new TypeError("key 必须是字符串");
- }
- if (!this.$data.data.has(key)) {
- log.warn(`${key} 键不存在`);
- return;
- }
- let value = PopsPanel.getValue(key);
- if (value) {
- callback(value);
- }
- },
- /**
- * 自动判断菜单是否启用,然后执行回调,只会执行一次
- * @param key
- * @param callback 回调
- */
- execMenuOnce(key, callback) {
- if (typeof key !== "string") {
- throw new TypeError("key 必须是字符串");
- }
- if (!this.$data.data.has(key)) {
- log.warn(`${key} 键不存在`);
- return;
- }
- if (this.$data.oneSuccessExecMenu.has(key)) {
- return;
- }
- this.$data.oneSuccessExecMenu.set(key, 1);
- let resultStyleList = [];
- let pushStyleNode = (style) => {
- let __value = PopsPanel.getValue(key);
- changeCallBack(__value, style);
- };
- let changeCallBack = (currentValue, resultStyle) => {
- let resultList = [];
- if (currentValue) {
- let result = resultStyle ?? callback(currentValue, pushStyleNode);
- if (result instanceof HTMLStyleElement) {
- resultList = [result];
- } else if (Array.isArray(result)) {
- resultList = [
- ...result.filter(
- (item) => item != null && item instanceof HTMLStyleElement
- )
- ];
- }
- }
- for (let index = 0; index < resultStyleList.length; index++) {
- let $css = resultStyleList[index];
- $css.remove();
- resultStyleList.splice(index, 1);
- index--;
- }
- resultStyleList = [...resultList];
- };
- this.addValueChangeListener(
- key,
- (__key, oldValue, newValue) => {
- changeCallBack(newValue);
- }
- );
- let value = PopsPanel.getValue(key);
- if (value) {
- changeCallBack(value);
- }
- },
- /**
- * 根据key执行一次
- * @param key
- */
- onceExec(key, callback) {
- if (typeof key !== "string") {
- throw new TypeError("key 必须是字符串");
- }
- if (this.$data.onceExec.has(key)) {
- return;
- }
- callback();
- this.$data.onceExec.set(key, 1);
- },
- /**
- * 显示设置面板
- */
- showPanel() {
- __pops.panel({
- title: {
- text: i18next.t("{{SCRIPT_NAME}}-设置", { SCRIPT_NAME }),
- position: "center",
- html: false,
- style: ""
- },
- content: this.getPanelContentConfig(),
- mask: {
- enable: true,
- clickEvent: {
- toClose: true,
- toHide: false
- }
- },
- isMobile: this.isMobile(),
- width: this.getWidth(),
- height: this.getHeight(),
- drag: true,
- only: true,
- style: `
- ${UIScriptListCSS}
- `
- });
- },
- isMobile() {
- return window.outerWidth < 550;
- },
- /**
- * 获取设置面板的宽度
- */
- getWidth() {
- if (window.outerWidth < 550) {
- return "92vw";
- } else {
- return "550px";
- }
- },
- /**
- * 获取设置面板的高度
- */
- getHeight() {
- if (window.outerHeight > 450) {
- return "80vh";
- } else {
- return "450px";
- }
- },
- /**
- * 获取配置内容
- */
- getPanelContentConfig() {
- let configList = [
- SettingUIGeneral,
- SettingUIScripts,
- SettingUIDiscuessions,
- SettingUIUsers,
- SettingUIScriptList,
- SettingUIScriptLib
- ];
- return configList;
- }
- };
- const beautifyMarkdownCSS = 'code {\r\n font-family: Menlo, Monaco, Consolas, "Courier New", monospace;\r\n font-size: 0.85em;\r\n color: #000;\r\n background-color: #f0f0f0;\r\n border-radius: 3px;\r\n padding: 0.2em 0;\r\n}\r\ntable {\r\n text-indent: initial;\r\n}\r\ntable {\r\n margin: 10px 0 15px 0;\r\n border-collapse: collapse;\r\n border-spacing: 0;\r\n display: block;\r\n width: 100%;\r\n overflow: auto;\r\n word-break: normal;\r\n word-break: keep-all;\r\n}\r\ncode,\r\npre {\r\n color: #333;\r\n background: 0 0;\r\n font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;\r\n text-align: left;\r\n white-space: pre;\r\n word-spacing: normal;\r\n word-break: normal;\r\n word-wrap: normal;\r\n line-height: 1.4;\r\n -moz-tab-size: 8;\r\n -o-tab-size: 8;\r\n tab-size: 8;\r\n -webkit-hyphens: none;\r\n -moz-hyphens: none;\r\n -ms-hyphens: none;\r\n hyphens: none;\r\n}\r\npre {\r\n padding: 0.8em;\r\n overflow: auto;\r\n border-radius: 3px;\r\n background: #f5f5f5;\r\n}\r\n:not(pre) > code {\r\n padding: 0.1em;\r\n border-radius: 0.3em;\r\n white-space: normal;\r\n background: #f5f5f5;\r\n}\r\nhtml body {\r\n font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans,\r\n sans-serif;\r\n font-size: 16px;\r\n line-height: 1.6;\r\n color: #333;\r\n background-color: #fff;\r\n overflow: initial;\r\n box-sizing: border-box;\r\n word-wrap: break-word;\r\n}\r\nhtml body > :first-child {\r\n margin-top: 0;\r\n}\r\nhtml body h1,\r\nhtml body h2,\r\nhtml body h3,\r\nhtml body h4,\r\nhtml body h5,\r\nhtml body h6 {\r\n line-height: 1.2;\r\n margin-top: 1em;\r\n margin-bottom: 16px;\r\n color: #000;\r\n}\r\nhtml body h1 {\r\n font-size: 2.25em;\r\n font-weight: 300;\r\n padding-bottom: 0.3em;\r\n}\r\nhtml body h2 {\r\n font-size: 1.75em;\r\n font-weight: 400;\r\n padding-bottom: 0.3em;\r\n}\r\nhtml body h3 {\r\n font-size: 1.5em;\r\n font-weight: 500;\r\n}\r\nhtml body h4 {\r\n font-size: 1.25em;\r\n font-weight: 600;\r\n}\r\nhtml body h5 {\r\n font-size: 1.1em;\r\n font-weight: 600;\r\n}\r\nhtml body h6 {\r\n font-size: 1em;\r\n font-weight: 600;\r\n}\r\nhtml body h1,\r\nhtml body h2,\r\nhtml body h3,\r\nhtml body h4,\r\nhtml body h5 {\r\n font-weight: 600;\r\n}\r\nhtml body h5 {\r\n font-size: 1em;\r\n}\r\nhtml body h6 {\r\n color: #5c5c5c;\r\n}\r\nhtml body strong {\r\n color: #000;\r\n}\r\nhtml body del {\r\n color: #5c5c5c;\r\n}\r\nhtml body a:not([href]) {\r\n color: inherit;\r\n}\r\nhtml body a {\r\n text-decoration: underline;\r\n text-underline-offset: 0.2rem;\r\n}\r\nhtml body a:hover {\r\n color: #00a3f5;\r\n}\r\nhtml body img {\r\n max-width: 100%;\r\n}\r\nhtml body > p {\r\n margin-top: 0;\r\n margin-bottom: 16px;\r\n word-wrap: break-word;\r\n}\r\nhtml body > ol,\r\nhtml body > ul {\r\n margin-bottom: 16px;\r\n}\r\nhtml body ol,\r\nhtml body ul {\r\n padding-left: 2em;\r\n}\r\nhtml body ol.no-list,\r\nhtml body ul.no-list {\r\n padding: 0;\r\n list-style-type: none;\r\n}\r\nhtml body ol ol,\r\nhtml body ol ul,\r\nhtml body ul ol,\r\nhtml body ul ul {\r\n margin-top: 0;\r\n margin-bottom: 0;\r\n}\r\nhtml body li {\r\n margin-bottom: 0;\r\n}\r\nhtml body li.task-list-item {\r\n list-style: none;\r\n}\r\nhtml body li > p {\r\n margin-top: 0;\r\n margin-bottom: 0;\r\n}\r\nhtml body .task-list-item-checkbox {\r\n margin: 0 0.2em 0.25em -1.8em;\r\n vertical-align: middle;\r\n}\r\nhtml body .task-list-item-checkbox:hover {\r\n cursor: pointer;\r\n}\r\nhtml body blockquote {\r\n margin: 16px 0;\r\n font-size: inherit;\r\n padding: 0 15px;\r\n color: #5c5c5c;\r\n background-color: #f0f0f0;\r\n border-left: 4px solid #d6d6d6 !important;\r\n}\r\nhtml body blockquote > :first-child {\r\n margin-top: 0;\r\n}\r\nhtml body blockquote > :last-child {\r\n margin-bottom: 0;\r\n}\r\nhtml body hr {\r\n height: 4px;\r\n margin: 32px 0;\r\n background-color: #d6d6d6;\r\n border: 0 none;\r\n}\r\nhtml body table {\r\n margin: 10px 0 15px 0;\r\n border-collapse: collapse;\r\n border-spacing: 0;\r\n display: block;\r\n width: 100%;\r\n overflow: auto;\r\n word-break: normal;\r\n word-break: keep-all;\r\n}\r\nhtml body table th {\r\n font-weight: 700;\r\n color: #000;\r\n}\r\nhtml body table td,\r\nhtml body table th {\r\n border: 1px solid #d6d6d6;\r\n padding: 6px 13px;\r\n}\r\nhtml body dl {\r\n padding: 0;\r\n}\r\nhtml body dl dt {\r\n padding: 0;\r\n margin-top: 16px;\r\n font-size: 1em;\r\n font-style: italic;\r\n font-weight: 700;\r\n}\r\nhtml body dl dd {\r\n padding: 0 16px;\r\n margin-bottom: 16px;\r\n}\r\nhtml body code {\r\n font-family: Menlo, Monaco, Consolas, "Courier New", monospace;\r\n font-size: 0.85em;\r\n color: #000;\r\n background-color: #f0f0f0;\r\n border-radius: 3px;\r\n padding: 0.2em 0;\r\n}\r\nhtml body code::after,\r\nhtml body code::before {\r\n letter-spacing: -0.2em;\r\n content: "\\00a0";\r\n}\r\nhtml body pre > code {\r\n padding: 0;\r\n margin: 0;\r\n word-break: normal;\r\n white-space: pre;\r\n background: 0 0;\r\n border: 0;\r\n}\r\nhtml body .highlight {\r\n margin-bottom: 16px;\r\n}\r\nhtml body .highlight pre,\r\nhtml body pre {\r\n padding: 1em;\r\n overflow: auto;\r\n line-height: 1.45;\r\n border: #d6d6d6;\r\n border-radius: 3px;\r\n}\r\nhtml body .highlight pre {\r\n margin-bottom: 0;\r\n word-break: normal;\r\n}\r\nhtml body pre code,\r\nhtml body pre tt {\r\n display: inline;\r\n max-width: initial;\r\n padding: 0;\r\n margin: 0;\r\n overflow: initial;\r\n line-height: inherit;\r\n word-wrap: normal;\r\n background-color: transparent;\r\n border: 0;\r\n}\r\nhtml body pre code:after,\r\nhtml body pre code:before,\r\nhtml body pre tt:after,\r\nhtml body pre tt:before {\r\n content: normal;\r\n}\r\nhtml body blockquote,\r\nhtml body dl,\r\nhtml body ol,\r\nhtml body p,\r\nhtml body pre,\r\nhtml body ul {\r\n margin-top: 0;\r\n margin-bottom: 16px;\r\n}\r\nhtml body kbd {\r\n color: #000;\r\n border: 1px solid #d6d6d6;\r\n border-bottom: 2px solid #c7c7c7;\r\n padding: 2px 4px;\r\n background-color: #f0f0f0;\r\n border-radius: 3px;\r\n}\r\n@media print {\r\n html body {\r\n background-color: #fff;\r\n }\r\n html body h1,\r\n html body h2,\r\n html body h3,\r\n html body h4,\r\n html body h5,\r\n html body h6 {\r\n color: #000;\r\n page-break-after: avoid;\r\n }\r\n html body blockquote {\r\n color: #5c5c5c;\r\n }\r\n html body pre {\r\n page-break-inside: avoid;\r\n }\r\n html body table {\r\n display: table;\r\n }\r\n html body img {\r\n display: block;\r\n max-width: 100%;\r\n max-height: 100%;\r\n }\r\n html body code,\r\n html body pre {\r\n word-wrap: break-word;\r\n white-space: pre;\r\n }\r\n}\r\n/* 强制换行 */\r\ncode {\r\n text-wrap: wrap !important;\r\n}\r\n\r\n.scrollbar-style::-webkit-scrollbar {\r\n width: 8px;\r\n}\r\n.scrollbar-style::-webkit-scrollbar-track {\r\n border-radius: 10px;\r\n background-color: transparent;\r\n}\r\n.scrollbar-style::-webkit-scrollbar-thumb {\r\n border-radius: 5px;\r\n background-color: rgba(150, 150, 150, 0.66);\r\n border: 4px solid rgba(150, 150, 150, 0.66);\r\n background-clip: content-box;\r\n}\r\n';
- const beautifyButtonCSS = '/* 美化按钮 */\r\ninput[type="submit"],\r\nbutton {\r\n display: inline-flex;\r\n justify-content: center;\r\n align-items: center;\r\n line-height: 1;\r\n height: 32px;\r\n white-space: nowrap;\r\n cursor: pointer;\r\n /* color: #606266; */\r\n text-align: center;\r\n box-sizing: border-box;\r\n outline: none;\r\n transition: 0.1s;\r\n font-weight: 500;\r\n user-select: none;\r\n vertical-align: middle;\r\n appearance: none;\r\n -webkit-appearance: none;\r\n background-color: #ffffff;\r\n border: 1px solid #dcdfe6;\r\n border-color: #dcdfe6;\r\n padding: 8px 15px;\r\n font-size: 14px;\r\n border-radius: 4px;\r\n}\r\n\r\ninput[type="submit"]:hover,\r\ninput[type="submit"]:focus,\r\nbutton:hover,\r\nbutton:focus {\r\n color: #409eff;\r\n border-color: #c6e2ff;\r\n background-color: #ecf5ff;\r\n outline: none;\r\n}\r\n\r\ninput[type="url"] {\r\n position: relative;\r\n font-size: 14px;\r\n display: inline-flex;\r\n line-height: 32px;\r\n box-sizing: border-box;\r\n vertical-align: middle;\r\n appearance: none;\r\n -webkit-appearance: none;\r\n /* color: #606266; */\r\n padding: 0;\r\n outline: none;\r\n border: none;\r\n background: none;\r\n flex-grow: 1;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 1px 11px;\r\n background-color: #ffffff;\r\n background-image: none;\r\n border-radius: 4px;\r\n cursor: text;\r\n transition: box-shadow 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);\r\n transform: translateZ(0);\r\n box-shadow: 0 0 0 1px #dcdfe6 inset;\r\n\r\n width: 100%;\r\n width: -moz-available;\r\n width: -webkit-fill-available;\r\n width: fill-available;\r\n}\r\n\r\ninput[type="url"]::placeholder {\r\n color: #a8abb2;\r\n}\r\n\r\ninput[type="url"]:hover {\r\n box-shadow: 0 0 0 1px #c0c4cc inset;\r\n}\r\n\r\ninput[type="url"]:focus {\r\n box-shadow: 0 0 0 1px #409eff inset;\r\n}\r\n';
- const beautifyRadioCSS = 'label.radio-label {\r\n font-weight: 500;\r\n position: relative;\r\n cursor: pointer;\r\n display: inline-flex;\r\n align-items: center;\r\n white-space: normal;\r\n outline: none;\r\n font-size: 14px;\r\n user-select: none;\r\n margin-right: 32px;\r\n height: 32px;\r\n padding: 4px;\r\n border-radius: 4px;\r\n box-sizing: border-box;\r\n}\r\nlabel:has(input[type="radio"]:checked),\r\nlabel:has(input[type="radio"]:checked) a {\r\n color: #409eff;\r\n}\r\nlabel.radio-label input[type="radio"] {\r\n margin-right: 4px;\r\n width: 14px;\r\n height: 14px;\r\n}\r\nlabel.radio-label input[type="radio"]:checked {\r\n -webkit-appearance: none;\r\n -moz-appearance: none;\r\n appearance: none;\r\n border-radius: 50%;\r\n width: 14px;\r\n height: 14px;\r\n outline: none;\r\n border: 4px solid #409eff;\r\n cursor: pointer;\r\n}\r\nlabel.radio-label input[type="radio"]:checked + span {\r\n color: #409eff;\r\n}\r\n';
- const beautifyInputCSS = 'input[type="search"],\r\ninput[type="text"],\r\ninput[type="password"] {\r\n justify-content: center;\r\n align-items: center;\r\n /* line-height: 1; */\r\n /* height: 32px; */\r\n white-space: nowrap;\r\n cursor: text;\r\n text-align: center;\r\n box-sizing: border-box;\r\n outline: 0;\r\n transition: 0.1s;\r\n /* font-weight: 500; */\r\n user-select: none;\r\n -webkit-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n vertical-align: middle;\r\n -webkit-appearance: none;\r\n appearance: none;\r\n background-color: transparent;\r\n border: 0;\r\n padding: 8px 8px;\r\n /* font-size: 14px; */\r\n text-align: start;\r\n /* width: 100%; */\r\n flex: 1;\r\n border: 1px solid #dcdfe6;\r\n border-radius: 4px;\r\n}\r\ninput[type="search"]:hover,\r\ninput[type="text"]:hover,\r\ninput[type="password"]:hover {\r\n box-shadow: 0 0 0 1px #c0c4cc;\r\n}\r\ninput[type="search"]:focus,\r\ninput[type="text"]:focus,\r\ninput[type="password"]:focus {\r\n outline: 0;\r\n border: 1px solid #409eff;\r\n border-radius: 4px;\r\n box-shadow: none;\r\n}\r\n';
- const beautifyTextAreaCSS = "textarea {\r\n display: block;\r\n position: relative;\r\n /*vertical-align: bottom;*/\r\n position: relative;\r\n resize: vertical;\r\n padding: 5px 11px;\r\n line-height: 1.5;\r\n box-sizing: border-box;\r\n width: 100%;\r\n font-size: inherit;\r\n font-family: inherit;\r\n /* color: #606266; */\r\n background-color: #ffffff;\r\n background-image: none;\r\n appearance: none;\r\n -webkit-appearance: none;\r\n box-shadow: 0 0 0 1px #dcdfe6 inset;\r\n border-radius: 4px;\r\n transition: box-shadow 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);\r\n border: none;\r\n}\r\ntextarea:focus {\r\n outline: none;\r\n box-shadow: 0 0 0 1px #409eff inset;\r\n}\r\n";
- const beautifyUploadImageCSS = '/* 隐藏 添加: */\r\nlabel[for="discussion_comments_attributes_0_attachments"],\r\nlabel[for="comment_attachments"] {\r\n display: none;\r\n}\r\ninput[type="file"] {\r\n width: 100%;\r\n font-size: 20px;\r\n background: #e2e2e2;\r\n padding: 40px 0px;\r\n border-radius: 10px;\r\n text-align-last: center;\r\n}\r\n';
- const compatibleBeautifyCSS = "#main-header {\r\n background-color: #670000 !important;\r\n background-image: linear-gradient(#670000, #990000) !important;\r\n}\r\n#site-nav-vue {\r\n flex-wrap: wrap;\r\n justify-content: flex-end;\r\n}\r\n.open-sidebar {\r\n border-width: 1px;\r\n border-radius: 3px;\r\n margin-right: 0;\r\n}\r\ninput.search-submit {\r\n transform: translateY(-5%) !important;\r\n margin-left: 10px;\r\n}\r\n#script-content code {\r\n word-wrap: break-word;\r\n}\r\n.code-container ::selection {\r\n background-color: #3d4556 !important;\r\n}\r\n";
- const beautifyTopNavigationBarCSS = "#language-selector {\r\n display: none;\r\n}\r\n@media screen and (min-width: 600px) {\r\n body {\r\n --header-height: 50px;\r\n --el-gap: 20px;\r\n }\r\n\r\n header#main-header {\r\n height: var(--header-height);\r\n position: fixed;\r\n top: 0;\r\n width: 100%;\r\n z-index: 55555;\r\n padding: unset;\r\n display: flex;\r\n justify-content: space-around;\r\n }\r\n\r\n header#main-header + div {\r\n margin-top: calc(var(--header-height) + 35px);\r\n }\r\n\r\n header#main-header .width-constraint {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--el-gap);\r\n padding: unset;\r\n margin: unset;\r\n max-width: unset;\r\n }\r\n\r\n header#main-header a {\r\n text-decoration: none;\r\n text-wrap: nowrap;\r\n }\r\n\r\n header#main-header .sign-out-link a {\r\n text-decoration: underline;\r\n }\r\n\r\n header#main-header #site-name {\r\n display: flex;\r\n align-items: center;\r\n }\r\n\r\n header#main-header #site-name img {\r\n width: calc(var(--header-height) - 5px);\r\n height: calc(var(--header-height) - 5px);\r\n }\r\n\r\n /* 隐藏Greasyfork文字 */\r\n header#main-header #site-name-text {\r\n display: none;\r\n }\r\n\r\n header#main-header #site-nav {\r\n display: flex;\r\n flex-direction: row-reverse;\r\n align-items: center;\r\n flex: 1;\r\n justify-content: space-between;\r\n height: 100%;\r\n gap: var(--el-gap);\r\n }\r\n\r\n header#main-header #site-nav nav li {\r\n padding: 0 0.5em;\r\n display: flex;\r\n align-items: center;\r\n height: var(--header-height);\r\n min-width: 30px;\r\n justify-content: center;\r\n }\r\n\r\n header#main-header #site-nav nav li:hover {\r\n background: #5f0101;\r\n }\r\n\r\n header#main-header #nav-user-info {\r\n max-width: 150px;\r\n }\r\n\r\n header#main-header #nav-user-info > span {\r\n flex: 1;\r\n }\r\n\r\n header#main-header #nav-user-info,\r\n header#main-header #nav-user-info + nav {\r\n position: unset;\r\n width: unset;\r\n display: flex;\r\n flex-wrap: nowrap;\r\n align-items: center;\r\n }\r\n}\r\n";
- const GreasyforkBeautify = {
- init() {
- PopsPanel.execMenuOnce("beautifyPage", () => {
- return this.beautifyPageElement();
- });
- PopsPanel.execMenuOnce("beautifyGreasyforkBeautify", () => {
- return this.beautifyGreasyforkBeautify();
- });
- PopsPanel.execMenuOnce("beautifyUploadImage", () => {
- return this.beautifyUploadImage();
- });
- PopsPanel.execMenuOnce("beautifyTopNavigationBar", () => {
- return this.beautifyTopNavigationBar();
- });
- },
- /**
- * 美化页面元素
- */
- beautifyPageElement() {
- log.info("美化页面元素");
- let result = [];
- result.push(_GM_addStyle(beautifyMarkdownCSS));
- result.push(_GM_addStyle(beautifyButtonCSS));
- result.push(_GM_addStyle(beautifyRadioCSS));
- result.push(_GM_addStyle(beautifyInputCSS));
- result.push(_GM_addStyle(beautifyTextAreaCSS));
- result.push(
- _GM_addStyle(
- /*css*/
- `
- p:has(input[type="submit"][name="update-and-sync"]){
- margin-top: 10px;
- }
- `
- )
- );
- domUtils.ready(function() {
- let markupChoiceELement = document.querySelector(
- 'a[target="markup_choice"][href*="daringfireball.net"]'
- );
- if (markupChoiceELement) {
- markupChoiceELement.parentElement.replaceChild(
- domUtils.createElement("span", {
- textContent: "Markdown"
- }),
- markupChoiceELement
- );
- }
- if (globalThis.location.pathname.endsWith("/admin") && !document.querySelector('input[type="submit"][name="update-only"]')) {
- result.push(
- _GM_addStyle(
- /*css*/
- `
- .indented{
- padding-left: unset;
- }
- `
- )
- );
- }
- });
- return result;
- },
- /**
- * 美化 Greasyfork Beautify脚本
- */
- beautifyGreasyforkBeautify() {
- log.info("美化 Greasyfork Beautify脚本");
- let result = [];
- result.push(_GM_addStyle(compatibleBeautifyCSS));
- if (utils.isPhone()) {
- result.push(
- _GM_addStyle(
- /*css*/
- `
- section#script-info,
- section.text-content,
- div.width-constraint table.text-content.log-table{
- margin-top: 80px;
- }
- div.width-constraint div.sidebarred{
- padding-top: 80px;
- }
- div.width-constraint div.sidebarred .sidebar{
- top: 80px;
- }`
- )
- );
- } else {
- result.push(
- _GM_addStyle(
- /*css*/
- `
- section#script-info{
- margin-top: 10px;
- }`
- )
- );
- }
- return result;
- },
- /**
- * 美化上传图片
- */
- beautifyUploadImage() {
- log.info("美化上传图片");
- let result = [];
- result.push(_GM_addStyle(beautifyUploadImageCSS));
- domUtils.ready(() => {
- function clearErrorTip(element) {
- while (element.nextElementSibling) {
- element.parentElement.removeChild(element.nextElementSibling);
- }
- }
- let $fileInputList = document.querySelectorAll('input[type="file"]');
- $fileInputList.forEach(($input) => {
- if ($input.getAttribute("name") === "code_upload") {
- return;
- }
- if ($input.hasAttribute("accept") && $input.getAttribute("accept").includes("javascript")) {
- return;
- }
- domUtils.on($input, ["propertychange", "input"], function(event) {
- clearErrorTip(event.target);
- let chooseImageFiles = event.currentTarget.files;
- if (!chooseImageFiles) {
- return;
- }
- if (chooseImageFiles.length === 0) {
- return;
- }
- log.info(["选择的图片", chooseImageFiles]);
- if (chooseImageFiles.length > 5) {
- domUtils.after(
- $input,
- domUtils.createElement("p", {
- textContent: i18next.t(`❌ 最多同时长传5张图片`)
- })
- );
- }
- let notAllowImage = [];
- Array.from(chooseImageFiles).forEach((imageFile) => {
- if (imageFile.size > 204800 || !imageFile.type.match(/png|jpg|jpeg|gif|apng|webp/i)) {
- notAllowImage.push(imageFile);
- }
- });
- if (notAllowImage.length === 0) {
- return;
- }
- notAllowImage.forEach((imageFile) => {
- domUtils.after(
- $input,
- domUtils.createElement("p", {
- textContent: i18next.t("❌ 图片:{{name}} 大小:{{size}}", {
- name: imageFile.name,
- size: imageFile.size
- })
- })
- );
- });
- });
- });
- let $textAreaSelectorString = [
- /* 某条反馈内的回复框 */
- "textarea#comment_text",
- /* 反馈页面的回复框 */
- "textarea.comment-entry"
- ];
- $textAreaSelectorString.forEach((selector) => {
- domUtils.on(selector, "paste", (event) => {
- log.info(["触发粘贴事件", event]);
- setTimeout(() => {
- domUtils.trigger($fileInputList, "input");
- }, 100);
- });
- });
- });
- return result;
- },
- /**
- * 美化顶部导航栏
- */
- beautifyTopNavigationBar() {
- log.info("美化顶部导航栏");
- let result = [];
- result.push(_GM_addStyle(beautifyTopNavigationBarCSS));
- if (window.outerWidth > 550) {
- result.push(CommonUtils.addBlockCSS(".with-submenu"));
- domUtils.ready(() => {
- let $siteNav = document.querySelector("#site-nav");
- let $siteNavNav = $siteNav.querySelector("nav");
- document.querySelectorAll(".with-submenu nav li").forEach(($ele) => {
- $siteNavNav.appendChild($ele);
- });
- });
- }
- return result;
- }
- };
- const GreasyforkAccount = {
- init() {
- PopsPanel.execMenu("autoLogin", () => {
- this.autoLogin();
- });
- },
- /**
- * 自动登录
- */
- autoLogin() {
- utils.waitNode("span.sign-in-link a[rel=nofollow]").then(async () => {
- let user = PopsPanel.getValue("user");
- let pwd = PopsPanel.getValue("pwd");
- if (utils.isNull(user)) {
- Qmsg.error(i18next.t("请先在菜单中录入账号"));
- return;
- }
- if (utils.isNull(pwd)) {
- Qmsg.error(i18next.t("请先在菜单中录入密码"));
- return;
- }
- let csrfToken = document.querySelector("meta[name='csrf-token']");
- if (!csrfToken) {
- Qmsg.error(i18next.t("获取csrf-token失败"));
- return;
- }
- let loginTip = Qmsg.loading(i18next.t("正在登录中..."));
- let postResp = await httpx.post(
- "https://greasyfork.org/zh-CN/users/sign_in",
- {
- fetch: true,
- data: encodeURI(
- `authenticity_token=${csrfToken.getAttribute(
- "content"
- )}&user[email]=${user}&user[password]=${pwd}&user[remember_me]=1&commit=登录`
- ),
- headers: {
- "Content-Type": "application/x-www-form-urlencoded"
- }
- }
- );
- loginTip.destroy();
- if (!postResp.status) {
- log.error(postResp);
- Qmsg.error(i18next.t("登录失败,请在控制台查看原因"));
- return;
- }
- let respText = postResp.data.responseText;
- let parseLoginHTMLNode = domUtils.parseHTML(respText, true, true);
- if (parseLoginHTMLNode.querySelectorAll(
- ".sign-out-link a[rel=nofollow][data-method='delete']"
- ).length) {
- Qmsg.success(i18next.t("登录成功,1s后自动跳转"));
- setTimeout(() => {
- window.location.reload();
- }, 1e3);
- } else {
- log.error(postResp);
- log.error(`当前账号:${user}`);
- log.error(`当前密码:${pwd}`);
- Qmsg.error(
- i18next.t("登录失败,可能是账号/密码错误,请在控制台查看原因")
- );
- }
- });
- }
- };
- const GreasyforkForum = {
- init() {
- this.readBgColor();
- domUtils.ready(() => {
- PopsPanel.execMenuOnce("greasyfork-discussions-filter-enable", () => {
- this.filterEnable();
- });
- PopsPanel.execMenuOnce("discussions-addShortcutOperationButton", () => {
- this.addShortcutOperationButton();
- });
- });
- },
- /**
- * 启用Greasyfork论坛过滤器
- */
- filterEnable() {
- log.info("启用Greasyfork论坛过滤器");
- GreasyforkDiscussionsFilter.init();
- },
- /**
- * 设置已读背景颜色
- */
- readBgColor() {
- log.info("设置已读背景颜色");
- let color = PopsPanel.getValue("discussions-readBgColor");
- _GM_addStyle(
- /*css*/
- `
- .discussion-read{
- background: ${color} !important;
- }
- `
- );
- },
- /**
- * 添加快捷操作按钮
- */
- addShortcutOperationButton() {
- log.info("添加快捷操作按钮");
- GreasyforkDiscussionsFilter.getElementList().forEach(($listContainer) => {
- if ($listContainer.querySelector(
- ".discussion-filter-button"
- )) {
- return;
- }
- let $listItem = $listContainer.querySelector(
- ".discussion-list-item"
- );
- let $meta = $listItem.querySelector(".discussion-meta");
- let $ownMetaItem = domUtils.createElement("div", {
- className: "discussion-meta-item",
- innerHTML: `
- <button class="discussion-filter-button">${i18next.t("过滤")}</button>
- `
- });
- let $button = $ownMetaItem.querySelector(
- ".discussion-filter-button"
- );
- $meta.appendChild($ownMetaItem);
- domUtils.on($button, "click", (event) => {
- var _a2, _b, _c;
- utils.preventEvent(event);
- const discussionInfo = GreasyforkDiscussionsFilter.parseDiscuessionListContainerInfo(
- $listContainer
- );
- let attr_filter_key = "data-filter-key";
- let attr_filter_value = "data-filter-value";
- let $dialog = __pops.alert({
- title: {
- text: i18next.t("选择需要过滤的选项"),
- position: "center",
- html: false
- },
- content: {
- text: (
- /*html*/
- `
- <button ${attr_filter_key}="scriptId" ${attr_filter_value}="^${discussionInfo.scriptId}$">${i18next.t("脚本id:{{text}}", {
- text: discussionInfo.scriptId
- })}</button>
- <button ${attr_filter_key}="scriptName" ${attr_filter_value}="^${utils.parseStringToRegExpString(
- discussionInfo.scriptName
- )}$">${i18next.t("脚本名:{{text}}", {
- text: discussionInfo.scriptName
- })}</button>
- <button ${attr_filter_key}="postUserId" ${attr_filter_value}="^${utils.parseStringToRegExpString(
- discussionInfo.postUserId
- )}$">${i18next.t("发布的用户id:{{text}}", {
- text: discussionInfo.postUserId
- })}</button>
- `
- ),
- html: true
- },
- mask: {
- enable: true,
- clickEvent: {
- toClose: true
- }
- },
- drag: true,
- dragLimit: true,
- width: "350px",
- height: "300px",
- style: (
- /*css*/
- `
- .pops-alert-content{
- display: flex;
- flex-direction: column;
- gap: 20px;
- }
- .pops-alert-content button{
- text-wrap: wrap;
- padding: 8px;
- height: auto;
- text-align: left;
- }
- `
- )
- });
- let $content = $dialog.$shadowRoot.querySelector(
- ".pops-alert-content"
- );
- if (discussionInfo.scriptId == null) {
- (_a2 = $content.querySelector(`button[${attr_filter_key}="scriptId"]`)) == null ? void 0 : _a2.remove();
- }
- if (discussionInfo.scriptName == null) {
- (_b = $content.querySelector(`button[${attr_filter_key}="scriptName"]`)) == null ? void 0 : _b.remove();
- }
- if (discussionInfo.postUserId == null) {
- (_c = $content.querySelector(`button[${attr_filter_key}="postUserId"]`)) == null ? void 0 : _c.remove();
- }
- if (discussionInfo.replyUserId != null) {
- let $replyUserIdButton = domUtils.createElement("button", {
- innerHTML: i18next.t("作者id:{{text}}", {
- text: discussionInfo.replyUserId
- })
- });
- $replyUserIdButton.setAttribute(attr_filter_key, "scriptAuthorId");
- $replyUserIdButton.setAttribute(
- attr_filter_value,
- "^" + discussionInfo.replyUserId + "$"
- );
- $content.appendChild($replyUserIdButton);
- }
- domUtils.on(
- $dialog.$shadowRoot,
- "click",
- `button[${attr_filter_key}]`,
- (event2) => {
- utils.preventEvent(event2);
- let $click = event2.target;
- let key = $click.getAttribute(
- attr_filter_key
- );
- let value = $click.getAttribute(attr_filter_value);
- GreasyforkDiscussionsFilter.addValue(key, value);
- $dialog.close();
- GreasyforkDiscussionsFilter.filter();
- Qmsg.success(i18next.t("添加成功"));
- }
- );
- });
- });
- }
- };
- const GreasyforkUsers = {
- init() {
- PopsPanel.execMenuOnce("users-changeConsoleToTopNavigator", () => {
- this.changeConsoleToTopNavigator();
- });
- PopsPanel.execMenuOnce("gf-scripts-filter-enable", () => {
- GreasyforkScriptsFilter.init();
- });
- PopsPanel.execMenuOnce("beautifyCenterContent", () => {
- return GreasyforkScriptsList.beautifyCenterContent();
- });
- },
- /**
- * 迁移【控制台】到顶部导航栏
- */
- changeConsoleToTopNavigator() {
- log.info("迁移【控制台】到顶部导航栏");
- CommonUtils.addBlockCSS("#about-user");
- domUtils.ready(() => {
- let $aboutUser = document.querySelector("#about-user");
- let $siteNav = document.querySelector("#site-nav nav");
- if (!$aboutUser) {
- log.error("#about-user元素不存在");
- return;
- }
- if (!$siteNav) {
- log.error("#site-nav nav元素不存在");
- return;
- }
- $aboutUser = $aboutUser.cloneNode(true);
- let $consoleNav = domUtils.createElement("li", {
- className: "scripts-console",
- innerHTML: `<a href="javascript:;">${i18next.t("控制台")}</a>`
- });
- domUtils.on($consoleNav, "click", (event) => {
- utils.preventEvent(event);
- let $drawer = __pops.drawer({
- title: {
- enable: false
- },
- content: {
- text: "",
- html: true
- },
- size: "auto",
- direction: "top",
- zIndex: utils.getMaxZIndex(100),
- style: (
- /*css*/
- `
- .text-content{
- list-style-type: none;
- box-shadow: rgb(221, 221, 221) 0px 0px 5px;
- background-color: rgb(255, 255, 255);
- box-sizing: border-box;
- border-width: 1px;
- border-style: solid;
- border-color: rgb(187, 187, 187);
- border-image: initial;
- border-radius: 5px;
- margin: 14px 0px;
- padding: 10px 40px;
- }
- a.report-link{
- position: absolute;
- right: 0px;
- font-size: smaller;
- margin-right: 16px;
- margin-top: 8px;
- }
- `
- )
- });
- let $drawerContent = $drawer.$shadowRoot.querySelector(
- ".pops-drawer-content"
- );
- $drawerContent.appendChild($aboutUser);
- });
- $siteNav.appendChild($consoleNav);
- });
- }
- };
- const Greasyfork = {
- init() {
- PopsPanel.execMenu("checkPage", () => {
- this.checkPage();
- });
- GreasyforkBeautify.init();
- GreasyforkShortCut.init();
- if (GreasyforkRouter.isScript()) {
- GreasyforkScripts.init();
- }
- if (GreasyforkRouter.isScriptList() || GreasyforkRouter.isScriptLibraryList() || GreasyforkRouter.isScriptCodeSearch()) {
- GreasyforkScriptsList.init();
- }
- if (GreasyforkRouter.isDiscuessions()) {
- GreasyforkForum.init();
- }
- if (GreasyforkRouter.isUserHome()) {
- GreasyforkUsers.init();
- }
- PopsPanel.execMenuOnce("scripts-addOperationPanelBtnWithNavigator", () => {
- this.addOperationPanelBtnWithNavigator();
- });
- domUtils.ready(() => {
- GreasyforkMenu.initEnv();
- GreasyforkAccount.init();
- GreasyforkMenu.handleLocalGotoCallBack();
- PopsPanel.execMenuOnce("fixImageWidth", () => {
- Greasyfork.fixImageWidth();
- });
- Greasyfork.languageSelectorLocale();
- PopsPanel.execMenuOnce("optimizeImageBrowsing", () => {
- Greasyfork.optimizeImageBrowsing();
- });
- PopsPanel.execMenuOnce("overlayBedImageClickEvent", () => {
- Greasyfork.overlayBedImageClickEvent();
- });
- if (!GreasyforkRouter.isCodeStrict()) {
- PopsPanel.execMenuOnce("addMarkdownCopyButton", () => {
- Greasyfork.addMarkdownCopyButton();
- });
- }
- });
- },
- /**
- * 修复图片宽度显示问题
- */
- fixImageWidth() {
- if (window.innerWidth < window.innerHeight) {
- log.info("修复图片显示问题");
- _GM_addStyle(
- /*css*/
- `
- img.lum-img{
- width: 100% !important;
- height: 100% !important;
- }
- `
- );
- }
- },
- /**
- * 优化图片浏览
- */
- optimizeImageBrowsing() {
- log.info("优化图片浏览");
- {
- _GM_addStyle(_GM_getResourceText("ViewerCSS"));
- }
- _GM_addStyle(
- /*css*/
- `
- @media (max-width: 460px) {
- .lum-lightbox-image-wrapper {
- display:flex;
- overflow: auto;
- -webkit-overflow-scrolling: touch
- }
- .lum-lightbox-caption {
- width: 100%;
- position: absolute;
- bottom: 0
- }
- .lum-lightbox-position-helper {
- margin: auto
- }
- .lum-lightbox-inner img {
- max-width:100%;
- max-height:100%;
- }
- }
- `
- );
- function viewIMG(imgList = [], _index_ = 0) {
- let viewerULNodeHTML = "";
- imgList.forEach((item) => {
- viewerULNodeHTML += `<li><img data-src="${item}" loading="lazy"></li>`;
- });
- let viewerULNode = domUtils.createElement("ul", {
- innerHTML: viewerULNodeHTML
- });
- let viewer = new Viewer(viewerULNode, {
- inline: false,
- url: "data-src",
- zIndex: utils.getMaxZIndex() + 100,
- hidden: () => {
- viewer.destroy();
- }
- });
- _index_ = _index_ < 0 ? 0 : _index_;
- viewer.view(_index_);
- viewer.zoomTo(1);
- viewer.show();
- }
- function getImgElementSrc(element) {
- return element.getAttribute("data-src") || element.getAttribute("src") || element.getAttribute("alt");
- }
- domUtils.on(
- document,
- "click",
- "img",
- function(event) {
- var _a2;
- let imgElement = event.target;
- if (((_a2 = imgElement.parentElement) == null ? void 0 : _a2.localName) === "a" && imgElement.hasAttribute("data-screenshots")) {
- return;
- }
- if (imgElement.closest(".viewer-container")) {
- return;
- }
- if (imgElement.closest(".lum-lightbox-position-helper")) {
- return;
- }
- let userContentElement = imgElement.closest(".user-content");
- let imgList = [];
- let imgIndex = 0;
- let imgElementList = [];
- let currentImgSrc = getImgElementSrc(imgElement);
- if (currentImgSrc == null ? void 0 : currentImgSrc.startsWith("https://img.shields.io")) {
- return;
- }
- if (userContentElement) {
- userContentElement.querySelectorAll("img").forEach((childImgElement) => {
- imgElementList.push(childImgElement);
- let imgSrc = getImgElementSrc(childImgElement);
- let $parent = childImgElement.parentElement;
- if (($parent == null ? void 0 : $parent.localName) === "a") {
- imgSrc = $parent.getAttribute("data-href") || $parent.href;
- }
- imgList.push(imgSrc);
- });
- imgIndex = imgElementList.indexOf(imgElement);
- if (imgIndex === -1) {
- imgIndex = 0;
- }
- } else {
- imgList.push(currentImgSrc);
- imgIndex = 0;
- }
- log.success(["点击浏览图片👉", imgList, imgIndex]);
- viewIMG(imgList, imgIndex);
- }
- );
- document.querySelectorAll(".user-screenshots").forEach((element) => {
- let linkElement = element.querySelector("a");
- if (!linkElement) {
- return;
- }
- let imgSrc = linkElement.getAttribute("data-href") || linkElement.getAttribute("href");
- let imgElement = element.querySelector("img");
- if (!imgElement) {
- return;
- }
- imgElement.setAttribute("data-screenshots", "true");
- imgElement.setAttribute("data-src", imgSrc);
- linkElement.setAttribute("href", "javascript:;");
- domUtils.after(linkElement, imgElement);
- linkElement.remove();
- });
- },
- /**
- * 覆盖图床图片的parentElement的a标签
- */
- overlayBedImageClickEvent() {
- log.info("覆盖图床图片的parentElement的a标签");
- document.querySelectorAll(".user-content a>img").forEach((imgElement) => {
- let linkElement = imgElement.parentElement;
- let url = linkElement.getAttribute("href");
- linkElement.setAttribute("data-href", url);
- linkElement.removeAttribute("href");
- domUtils.on(linkElement, "click", () => {
- Qmsg.warning(
- /*html*/
- `<div style="overflow-wrap: anywhere;">${i18next.t(
- "拦截跳转:"
- )}<a href="${url}" target="_blank">${url}</a></div>`,
- {
- html: true,
- zIndex: utils.getMaxZIndex() + 105
- }
- );
- });
- });
- },
- /**
- * 在Markdown右上角添加复制按钮
- */
- addMarkdownCopyButton() {
- log.info("在Markdown右上角添加复制按钮");
- _GM_addStyle(
- /*css*/
- `
- pre{
- position: relative;
- margin-bottom: 0px !important;
- width: 100%;
- }
- `
- );
- _GM_addStyle(
- /*css*/
- `
- .snippet-clipboard-content{
- display: flex;
- justify-content: space-between;
- background: rgb(246, 248, 250);
- margin-bottom: 16px;
- }
- .zeroclipboard-container {
- /* right: 0;
- top: 0;
- position: absolute; */
- box-sizing: border-box;
- display: flex;
- font-size: 16px;
- line-height: 24px;
- text-size-adjust: 100%;
- overflow-wrap: break-word;
- width: fit-content;
- height: fit-content;
- }
- .zeroclipboard-container svg{
- vertical-align: text-bottom;
- display: inline-block;
- overflow: visible;
- fill: currentColor;
- margin: 8px;
- }
- .zeroclipboard-container svg[aria-hidden="true"]{
- display: none;
- }
- clipboard-copy.js-clipboard-copy {
- position: relative;
- padding: 0px;
- color: rgb(36, 41, 47);
- background-color: rgb(246, 248, 250);
- transition: 80ms cubic-bezier(0.33, 1, 0.68, 1);
- transition-property: color,background-color,box-shadow,border-color;
- display: inline-block;
- font-size: 14px;
- line-height: 20px;
- white-space: nowrap;
- vertical-align: middle;
- cursor: pointer;
- -webkit-user-select: none;
- user-select: none;
- border: 1px solid rgba(31, 35, 40, 0.15);
- -webkit-appearance: none;
- appearance: none;
- box-shadow: rgba(31, 35, 40, 0.04) 0px 1px 0px 0px, rgba(255, 255, 255, 0.25) 0px 1px 0px 0px inset;
- margin: 8px;
- overflow-wrap: break-word;
- text-wrap: nowrap;
- border-radius: 6px;
- }
- clipboard-copy.js-clipboard-copy[success]{
- border-color: rgb(31, 136, 61);
- box-shadow: 0 0 0 0.2em rgba(52,208,88,.4);
- }
- clipboard-copy.js-clipboard-copy:hover{
- background-color: rgb(243, 244, 246);
- border-color: rgba(31, 35, 40, 0.15);
- transition-duration: .1s;
- }
- clipboard-copy.js-clipboard-copy:active{
- background-color: rgb(235, 236, 240);
- border-color: rgba(31, 35, 40, 0.15);
- transition: none;
- }
- `
- );
- _GM_addStyle(
- /*css*/
- `
- .pops-tip.github-tooltip {
- border-radius: 6px;
- padding: 6px 8px;
- }
- .pops-tip.github-tooltip, .pops-tip.github-tooltip .pops-tip-arrow::after {
- background: rgb(36, 41, 47);
- color: #fff;
- }
- .pops-tip.github-tooltip .pops-tip-arrow::after {
- width: 8px;
- height: 8px;
- }
- `
- );
- function getCopyElement() {
- let copyElement = domUtils.createElement("div", {
- className: "zeroclipboard-container",
- innerHTML: (
- /*html*/
- `
- <clipboard-copy class="js-clipboard-copy">
- <svg height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon-copy">
- <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
- </svg>
- <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon-check-copy">
- <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
- </svg>
- </clipboard-copy>
- `
- )
- });
- let clipboardCopyElement = copyElement.querySelector(
- ".js-clipboard-copy"
- );
- let octiconCopyElement = copyElement.querySelector(
- ".octicon-copy"
- );
- let octiconCheckCopyElement = copyElement.querySelector(
- ".octicon-check-copy"
- );
- domUtils.on(copyElement, "click", function() {
- let codeElement = copyElement.parentElement.querySelector("code");
- if (!codeElement && copyElement.parentElement.className.includes("prettyprinted")) {
- codeElement = copyElement.parentElement;
- }
- if (!codeElement) {
- Qmsg.error(i18next.t("未找到{{selector}}元素", { selector: "code" }));
- return;
- }
- utils.setClip(codeElement.innerText || codeElement.textContent);
- clipboardCopyElement.setAttribute("success", "true");
- octiconCopyElement.setAttribute("aria-hidden", "true");
- octiconCheckCopyElement.removeAttribute("aria-hidden");
- let tooltip = __pops.tooltip({
- target: clipboardCopyElement,
- content: i18next.t("✅ 复制成功!"),
- position: "left",
- className: "github-tooltip",
- alwaysShow: true
- });
- setTimeout(() => {
- clipboardCopyElement.removeAttribute("success");
- octiconCheckCopyElement.setAttribute("aria-hidden", "true");
- octiconCopyElement.removeAttribute("aria-hidden");
- tooltip.close();
- }, 2e3);
- });
- return copyElement;
- }
- document.querySelectorAll("pre").forEach((preElement) => {
- let zeroclipboardElement = preElement.querySelector(
- "div.zeroclipboard-container"
- );
- if (zeroclipboardElement) {
- return;
- }
- let copyElement = getCopyElement();
- let snippetClipboardContentElement = domUtils.createElement("div", {
- className: "snippet-clipboard-content"
- });
- domUtils.before(preElement, snippetClipboardContentElement);
- snippetClipboardContentElement.appendChild(preElement);
- snippetClipboardContentElement.appendChild(copyElement);
- });
- },
- /**
- * 固定当前语言
- */
- languageSelectorLocale() {
- let localeLanguage = PopsPanel.getValue("language-selector-locale");
- let currentLocaleLanguage = window.location.pathname.split("/").filter((item) => Boolean(item))[0];
- log.success("选择语言:" + localeLanguage);
- log.success("当前语言:" + currentLocaleLanguage);
- if (utils.isNull(localeLanguage)) {
- return;
- }
- if (localeLanguage === currentLocaleLanguage) {
- return;
- } else {
- let timer = null;
- let url = GreasyforkApi.getSwitchLanguageUrl(localeLanguage);
- GreasyforkApi.switchLanguage(url);
- log.success("新Url:" + url);
- Qmsg.loading(
- i18next.t(
- "当前语言:{{currentLocaleLanguage}},,3秒后切换至:{{localeLanguage}}",
- {
- currentLocaleLanguage,
- localeLanguage
- }
- ),
- {
- timeout: 3e3,
- showClose: true,
- onClose() {
- clearTimeout(timer);
- }
- }
- );
- Qmsg.info(i18next.t("导航至:") + url, {
- timeout: 3e3
- });
- timer = setTimeout(() => {
- window.location.href = url;
- }, 3e3);
- }
- },
- /**
- * 检测gf页面是否正确加载,有时候会出现
- * We're down for maintenance. Check back again soon.
- */
- checkPage() {
- log.info("检测gf页面是否正确加载,有时候会出现");
- domUtils.ready(() => {
- if (document.body.firstElementChild && document.body.firstElementChild.localName === "p" && document.body.firstElementChild.innerText.includes(
- "We're down for maintenance. Check back again soon."
- )) {
- let latestRefreshPageTime = parseInt(
- _GM_getValue(
- "greasyfork-check-page-time",
- 0
- )
- );
- let checkPageTimeout = PopsPanel.getValue(
- "greasyfork-check-page-timeout",
- 5
- );
- let checkPageTimeoutStamp = checkPageTimeout * 1e3;
- if (latestRefreshPageTime && Date.now() - latestRefreshPageTime < checkPageTimeoutStamp) {
- Qmsg.warning(
- i18next.t("上次重载时间 {{time}},{{timeout}}秒内拒绝反复重载", {
- time: utils.formatTime(
- latestRefreshPageTime,
- "yyyy-MM-dd HH:mm:ss"
- ),
- timeout: checkPageTimeout
- })
- );
- return;
- }
- _GM_setValue("greasyfork-check-page-time", Date.now());
- window.location.reload();
- }
- });
- },
- /**
- * 在顶部导航栏添加【操作面板】按钮
- */
- addOperationPanelBtnWithNavigator() {
- log.info("添加【操作面板】按钮");
- CommonUtils.addBlockCSS(
- ".sidebarred .sidebar",
- ".sidebarred-main-content .open-sidebar"
- );
- _GM_addStyle(
- /*css*/
- `
- .sidebarred .sidebarred-main-content{
- max-width: 100%;
- }
- `
- );
- domUtils.ready(() => {
- let $nav = document.querySelector("#site-nav nav");
- let $subNav = document.querySelector(
- "#site-nav .with-submenu nav"
- );
- let $scriptsOptionGroups = document.querySelector("#script-list-option-groups") || document.querySelector(".list-option-groups");
- if (!$scriptsOptionGroups) {
- log.warn("不存在右侧面板元素#script-list-option-groups");
- return;
- }
- $scriptsOptionGroups = $scriptsOptionGroups.cloneNode(
- true
- );
- $scriptsOptionGroups.classList.add("option-panel-groups");
- if (!$nav) {
- log.error("元素#site-nav nav不存在");
- return;
- }
- let $filterBtn = domUtils.createElement("li", {
- className: "filter-scripts",
- innerHTML: `
- <a href="javascript:;">${i18next.t("操作面板")}</a>
- `
- });
- domUtils.on($filterBtn, "click", (event) => {
- utils.preventEvent(event);
- let $drawer = __pops.drawer({
- title: {
- enable: false
- },
- content: {
- text: "",
- html: true
- },
- direction: "top",
- size: "80%",
- zIndex: utils.getMaxZIndex(100),
- style: (
- /*css*/
- `
- .pops-drawer-content div:first-child{
- margin: 20px 0 0 0;
- }
- .option-panel-groups > div{
- }
- .option-panel-groups ul{
- margin: .5em 0 0;
- list-style-type: none;
- padding: 1em 0;
- box-shadow: 0 0 5px #ddd;
- border: 1px solid #BBBBBB;
- border-radius: 5px;
- background-color: #fff;
- }
- .option-panel-groups ul li{
- }
- li.list-current{
- border-left: 7px solid #800;
- box-shadow: inset 0 1px #0000001a, inset 0 -1px #0000001a;
- margin: 0 0 0 -4px;
- padding: .4em 1em .4em calc(1em - 3px);
- background: linear-gradient(#fff, #eee);
- }
- .list-option-group a {
- padding: .35em 1em;
- display: block;
- }
- .list-option-group {
- margin-bottom: 1em;
- }
- form.sidebar-search{
- display: flex;
- align-items: center;
- gap: 10px;
- }
- form.sidebar-search input[type="search"]{
- display: inline-flex;
- justify-content: center;
- align-items: center;
- line-height: 1;
- height: 32px;
- white-space: nowrap;
- cursor: text;
- text-align: center;
- box-sizing: border-box;
- outline: 0;
- transition: 0.1s;
- font-weight: 500;
- user-select: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- vertical-align: middle;
- -webkit-appearance: none;
- appearance: none;
- background-color: transparent;
- border: 0;
- padding: 8px 8px;
- font-size: 14px;
- text-align: start;
- /* width: 100%; */
- // flex: 1;
- display: flex;
- align-items: center;
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- background-color: #ffffff;
- }
- form.sidebar-search input[type="submit"]{
- width: 32px;
- height: 32px;
- }
- `
- )
- });
- let $drawerContent = $drawer.$shadowRoot.querySelector(
- ".pops-drawer-content"
- );
- $drawerContent.appendChild($scriptsOptionGroups);
- });
- if ($subNav && $subNav.children.length) {
- $subNav.appendChild($filterBtn);
- } else {
- $nav.appendChild($filterBtn);
- }
- });
- }
- };
- PopsPanel.init();
- Greasyfork.init();
- })(Qmsg, DOMUtils, Utils, i18next, pops, Viewer);