mirror of
https://github.com/fireinrain/JHS-enhance.git
synced 2026-09-28 07:36:38 +08:00
重构拆分
This commit is contained in:
+10962
File diff suppressed because one or more lines are too long
@@ -0,0 +1,228 @@
|
|||||||
|
# JHS-enhance
|
||||||
|
|
||||||
|
> Jav-鉴黄师 油猴脚本 — 工程化重构版本
|
||||||
|
|
||||||
|
基于 `vite-plugin-monkey` 脚手架,将原 10,000+ 行单体脚本拆分为 49 个可维护的 ES Module 模块,支持本地开发热更新、一键构建。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 功能概览
|
||||||
|
|
||||||
|
- **列表页增强**:作品状态标签(屏蔽/收藏/已下载/已观看)、一键打开待鉴定/已收藏作品、新作品检测、演员黑名单过滤
|
||||||
|
- **详情页增强**:磁力链接高亮、预览视频(DMM 多画质)、标题翻译、字幕搜索(SubTitleCat / 迅雷)、演员信息、相关清单
|
||||||
|
- **数据管理**:IndexedDB 本地存储、云盘备份/恢复(阿里云盘 / 115 网盘 / WebDAV)、跨 Tab 数据同步
|
||||||
|
- **自动化任务**:自动翻页、新作品检测、收藏演员同步、黑名单更新
|
||||||
|
- **UI 优化**:分类折叠、热榜 Top250、免 VIP 查看热播、以图识图、截图功能
|
||||||
|
- **多站点支持**:JavDB / JavBus / JavSee / SeeJav / FC2 / JavTrailers / SubTitleCat
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
JHS-enhance/
|
||||||
|
├── src/
|
||||||
|
│ ├── main.js # 入口文件:全局初始化、插件注册、页面启动
|
||||||
|
│ ├── core/ # 基础设施层
|
||||||
|
│ │ ├── constants.js # 全局常量、CSS 样式、页面类型判断
|
||||||
|
│ │ ├── base-plugin.js # 插件基类(含 SVG 图标、页面信息解析)
|
||||||
|
│ │ ├── plugin-manager.js # 插件管理器(注册、CSS/插件生命周期)
|
||||||
|
│ │ ├── globals.js # 全局依赖挂载(jQuery、localforage 等)
|
||||||
|
│ │ ├── storage.js # IndexedDB 存储管理器(localforage 封装)
|
||||||
|
│ │ ├── utils.js # 工具函数集(DOM 操作、弹窗、快捷键等)
|
||||||
|
│ │ └── gmHttp.js # GM_xmlhttpRequest 封装(带重试/并发控制)
|
||||||
|
│ ├── api/ # API 层
|
||||||
|
│ │ ├── javdb.js # JavDB API 封装(签名、搜索、评论等)
|
||||||
|
│ │ └── dmm.js # DMM 预览视频获取(多画质)
|
||||||
|
│ └── plugins/ # 插件层(38 个功能插件)
|
||||||
|
│ ├── list-page.js # 列表页过滤与状态标签
|
||||||
|
│ ├── list-page-button.js # 列表页功能按钮(待鉴定/已收藏/新作品/黑名单)
|
||||||
|
│ ├── detail-page.js # 详情页数据加载
|
||||||
|
│ ├── detail-page-button.js# 详情页操作按钮
|
||||||
|
│ ├── setting.js # 设置面板(Tabulator 表格)
|
||||||
|
│ ├── translate.js # 标题翻译(Google 翻译 API)
|
||||||
|
│ ├── preview-video.js # DMM 预览视频
|
||||||
|
│ ├── highlight-magnet.js # 磁力链接高亮匹配
|
||||||
|
│ ├── auto-page.js # 自动翻页 / 云盘备份
|
||||||
|
│ ├── blacklist.js # 黑名单管理(演员/番号)
|
||||||
|
│ ├── favorite-actresses.js# 收藏演员同步
|
||||||
|
│ ├── new-video.js # 新作品检测
|
||||||
|
│ ├── task.js # 后台任务调度
|
||||||
|
│ ├── history.js # 浏览历史
|
||||||
|
│ ├── wangpan-115.js # 115 网盘匹配
|
||||||
|
│ ├── wangpan-115-task.js # 115 网盘任务处理
|
||||||
|
│ ├── aliyun-pan.js # 阿里云盘
|
||||||
|
│ ├── fc2.js # FC2 页面处理
|
||||||
|
│ ├── fc2-by123av.js # FC2 通过 123AV 搜索
|
||||||
|
│ ├── actress-info.js # 演员信息展示
|
||||||
|
│ ├── related.js # 相关清单
|
||||||
|
│ ├── review.js # 评论展示
|
||||||
|
│ ├── cover-button.js # 封面按钮
|
||||||
|
│ ├── fold-category.js # 分类折叠
|
||||||
|
│ ├── hit-show.js # 热播榜单
|
||||||
|
│ ├── top250.js # Top250 排行榜
|
||||||
|
│ ├── nav-bar.js # JavDB 导航栏增强
|
||||||
|
│ ├── bus-nav-bar.js # JavBus 导航栏增强
|
||||||
|
│ ├── bus-detail-page.js # JavBus 详情页
|
||||||
|
│ ├── bus-img.js # JavBus 图片处理
|
||||||
|
│ ├── bus-preview-video.js # JavBus 预览视频
|
||||||
|
│ ├── image-recognition.js # 以图识图
|
||||||
|
│ ├── screenshot.js # 截图功能
|
||||||
|
│ ├── magnet-hub.js # MagnetHub 磁力搜索
|
||||||
|
│ ├── other-site.js # 第三方站点链接
|
||||||
|
│ ├── jav-trailers.js # JavTrailers 站点
|
||||||
|
│ ├── subtitle-cat.js # SubTitleCat 字幕搜索
|
||||||
|
│ ├── filter-title-keyword.js # 标题关键词过滤
|
||||||
|
│ └── want-watched.js # 想看/已看视频列表
|
||||||
|
├── vite.config.mjs # Vite + vite-plugin-monkey 配置
|
||||||
|
├── package.json
|
||||||
|
└── JHS-origin.js # 原始单体脚本(参考)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
| 类别 | 技术 |
|
||||||
|
|------|------|
|
||||||
|
| 构建工具 | Vite 6 + vite-plugin-monkey 5 |
|
||||||
|
| 模块系统 | ES Module |
|
||||||
|
| DOM 操作 | jQuery 3.7 |
|
||||||
|
| 数据存储 | localforage (IndexedDB) |
|
||||||
|
| 表格组件 | Tabulator 6 |
|
||||||
|
| 弹窗组件 | layui-layer |
|
||||||
|
| Toast 通知 | Toastify |
|
||||||
|
| 图片查看 | ViewerJS |
|
||||||
|
| 二维码 | QRCodeJS |
|
||||||
|
| 哈希 | blueimp-md5 |
|
||||||
|
| 代码风格 | 纯 JavaScript(无 TypeScript) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 开发模式
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
启动后会在终端输出一个本地代理服务器地址,将该地址填入 Tampermonkey 即可实现热更新开发。
|
||||||
|
|
||||||
|
### 生产构建
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
构建产物输出到 `dist/jhs-enhance.user.js`,可直接安装到 Tampermonkey。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 架构设计
|
||||||
|
|
||||||
|
### 三层架构
|
||||||
|
|
||||||
|
```
|
||||||
|
main.js (入口)
|
||||||
|
│
|
||||||
|
├── core/ 基础设施层
|
||||||
|
│ ├── 全局常量、CSS 样式
|
||||||
|
│ ├── 插件基类、插件管理器
|
||||||
|
│ ├── 存储、网络、工具函数
|
||||||
|
│ └── 全局依赖挂载
|
||||||
|
│
|
||||||
|
├── api/ API 层
|
||||||
|
│ ├── JavDB API(签名、搜索)
|
||||||
|
│ └── DMM 视频 API
|
||||||
|
│
|
||||||
|
└── plugins/ 插件层
|
||||||
|
├── 列表页插件(按站点分)
|
||||||
|
├── 详情页插件(按站点分)
|
||||||
|
├── 功能插件(翻译/黑名单/备份等)
|
||||||
|
└── 第三方站点插件
|
||||||
|
```
|
||||||
|
|
||||||
|
### 插件机制
|
||||||
|
|
||||||
|
每个插件继承 `BasePlugin`,实现以下生命周期方法:
|
||||||
|
|
||||||
|
- `getName()` — 返回插件唯一标识
|
||||||
|
- `initCss()` — 返回插件专属 CSS(可选)
|
||||||
|
- `handle()` — 插件主逻辑
|
||||||
|
|
||||||
|
插件通过 `PluginManager` 统一注册和管理,按站点类型(JavDB / JavBus)分两组注册,确保不同站点加载正确的插件。
|
||||||
|
|
||||||
|
### 页面类型判断
|
||||||
|
|
||||||
|
```
|
||||||
|
isDetailPage → 作品详情页
|
||||||
|
isListPage → 作品列表页
|
||||||
|
isFc2Page → FC2 搜索结果页
|
||||||
|
isSearchPage → 搜索页
|
||||||
|
```
|
||||||
|
|
||||||
|
插件在 `handle()` 中通过 `window.isDetailPage` 等全局变量判断当前页面类型,决定是否执行逻辑。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 开发指南
|
||||||
|
|
||||||
|
### 添加新插件
|
||||||
|
|
||||||
|
1. 在 `src/plugins/` 下创建 `my-plugin.js`
|
||||||
|
2. 继承 `BasePlugin`,实现 `getName()` 和 `handle()`
|
||||||
|
3. 在 `src/main.js` 中 import 并注册:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { MyPlugin } from './plugins/my-plugin.js';
|
||||||
|
// 在对应站点分支中注册
|
||||||
|
pluginManager.register(MyPlugin);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 访问全局服务
|
||||||
|
|
||||||
|
插件中可通过以下方式访问全局服务:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
await storageManager.getSetting('key'); // 存储
|
||||||
|
await storageManager.getCarList(); // 车辆列表
|
||||||
|
this.getBean('OtherPluginName'); // 获取其他插件实例
|
||||||
|
window.utils.q(event, '确认?', callback); // 确认弹窗
|
||||||
|
window.show.ok('操作成功'); // Toast 通知
|
||||||
|
```
|
||||||
|
|
||||||
|
### 样式注入
|
||||||
|
|
||||||
|
- **全局样式**:定义在 `core/constants.js` 的 `mainCss` 中,启动时自动注入
|
||||||
|
- **站点样式**:`javBusStyle` / `javdbStyle` 按站点条件注入
|
||||||
|
- **插件样式**:通过 `initCss()` 方法返回,由 PluginManager 统一注入
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 构建配置
|
||||||
|
|
||||||
|
`vite-plugin-monkey` 在 `vite.config.mjs` 中配置了:
|
||||||
|
|
||||||
|
- **match/include**:脚本匹配的 URL 模式
|
||||||
|
- **require**:CDN 外部依赖(jQuery、Tabulator 等)
|
||||||
|
- **connect**:GM_xmlhttpRequest 允许的跨域域名
|
||||||
|
- **grant**:GM_* API 权限声明
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 版本历史
|
||||||
|
|
||||||
|
- **v3.3.6** — 工程化重构版本,模块化拆分,支持 HMR 开发
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
+251
@@ -0,0 +1,251 @@
|
|||||||
|
好的,让我先全面分析这个 11000 行的脚本。我会分段读取,理解它的整体结构和功能模块。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The user wants me to analyze the JHS-origin.js file (about 11,000 lines) and provide a detailed report on how to modularize it. Let me first read through the entire file to understand its structure, then provide a comprehensive refactoring plan.
|
||||||
|
|
||||||
|
Since the file is 10,962 lines, I need to read it in chunks. Let me start by reading several sections to understand the code structure.
|
||||||
|
|
||||||
|
Let me read the file in multiple chunks to understand:
|
||||||
|
1. The beginning (already read some)
|
||||||
|
2. Key sections throughout
|
||||||
|
3. The end
|
||||||
|
|
||||||
|
I'll read multiple sections in parallel.
|
||||||
|
|
||||||
|
Let me continue reading more sections to get a complete picture of the codebase.
|
||||||
|
|
||||||
|
Let me also read the end of the file to see the initialization/entry point.
|
||||||
|
|
||||||
|
Now I have a very comprehensive understanding of the codebase. Let me also read the very end to see the initialization.
|
||||||
|
|
||||||
|
Now I have a comprehensive understanding of the entire codebase. Let me write a detailed analysis report.
|
||||||
|
|
||||||
|
The code is approximately 10,962 lines, with a well-defined plugin architecture:
|
||||||
|
- PluginManager: manages plugins
|
||||||
|
- BasePlugin: base class for all plugins
|
||||||
|
- ~40 plugins extending BasePlugin
|
||||||
|
|
||||||
|
The code also contains:
|
||||||
|
- Utility classes (Utils, gmHttp, StorageManager, show, clog, etc.)
|
||||||
|
- CSS styles
|
||||||
|
- Constants and configuration
|
||||||
|
- API interfaces (JavDbApi, etc.)
|
||||||
|
- A plugin system with registration and execution
|
||||||
|
|
||||||
|
Let me now write a comprehensive refactoring report.
|
||||||
|
现在我已经完整分析了整个代码库。以下是详细的结构分析报告:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 JHS-enhance 代码结构分析报告
|
||||||
|
|
||||||
|
### 📊 总体概况
|
||||||
|
|
||||||
|
| 指标 | 数据 |
|
||||||
|
|------|------|
|
||||||
|
| 总行数 | **10,962 行** |
|
||||||
|
| 核心类/插件 | **40+ 个** |
|
||||||
|
| 支持站点 | JavDB、JavBus、JavTrailers、SubTitleCat、阿里云盘、115网盘 |
|
||||||
|
| 外部依赖 | jQuery、Tabulator、layui-layer、MD5、Toastify、localForage、ViewerJS、QRCodeJS |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🏗️ 现有架构
|
||||||
|
|
||||||
|
代码已经有一个**不错的插件架构**,只是全部写在一个文件里:
|
||||||
|
|
||||||
|
```
|
||||||
|
入口(最后100行)
|
||||||
|
├── 初始化 pluginManager
|
||||||
|
├── 检测当前页面类型(isDetailPage / isListPage / isFc2Page)
|
||||||
|
├── 按站点注册插件
|
||||||
|
├── pluginManager.processCss() → 加载所有插件CSS
|
||||||
|
└── pluginManager.processPlugins() → 执行所有插件
|
||||||
|
```
|
||||||
|
|
||||||
|
插件基类 `BasePlugin` 提供了:
|
||||||
|
- `getName()` — 插件名
|
||||||
|
- `initCss()` — 返回CSS字符串
|
||||||
|
- `handle()` — 主逻辑入口
|
||||||
|
- `getPageInfo()` — 获取当前页面信息
|
||||||
|
- `getBean(name)` — 获取其他插件实例
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📦 代码功能模块划分
|
||||||
|
|
||||||
|
我将 11000 行代码按功能分为以下 **8 大模块**,建议拆分为独立文件:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 模块一:🛠️ 基础设施层(~1500 行)
|
||||||
|
**建议目录:`src/core/`**
|
||||||
|
|
||||||
|
| 文件 | 内容 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `utils.js` | `Utils` 类(~300行) | 通用工具函数:下载、滚动、剪贴板、URL解析、排序等 |
|
||||||
|
| `gmHttp.js` | `gmHttp` 类(~200行) | 基于 `GM_xmlhttpRequest` 的 HTTP 封装 |
|
||||||
|
| `storage.js` | `StorageManager` 类(~500行) | IndexedDB 存储管理:收藏、屏蔽、设置、演员等 |
|
||||||
|
| `show.js` | `show` / `clog` 对象(~100行) | Toast 消息提示、控制台日志 |
|
||||||
|
| `constants.js` | 所有常量(~200行) | 状态枚举、画质选项、翻译映射表、标签样式等 |
|
||||||
|
| `styles.js` | CSS 样式(~300行) | JavDB/JavBus 站点样式、全局样式、滚动条样式 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 模块二:🔌 插件系统(~200 行)
|
||||||
|
**建议目录:`src/core/`**
|
||||||
|
|
||||||
|
| 文件 | 内容 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `plugin-manager.js` | `PluginManager` 类 | 插件注册、CSS加载、插件执行 |
|
||||||
|
| `base-plugin.js` | `BasePlugin` 类 | 插件基类,提供 `getName()`、`handle()`、`initCss()` 等 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 模块三:🌐 API 接口层(~200 行)
|
||||||
|
**建议目录:`src/api/`**
|
||||||
|
|
||||||
|
| 文件 | 内容 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `javdb-api.js` | `javDbApi` 对象 | JavDB API:获取评论、搜索电影、电影详情、磁力链接 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 模块四:📋 列表页插件(~2500 行)
|
||||||
|
**建议目录:`src/plugins/list/`**
|
||||||
|
|
||||||
|
| 文件 | 类名 | 功能 |
|
||||||
|
|------|------|------|
|
||||||
|
| `list-page.js` | `ListPagePlugin` | 列表页核心:状态标签渲染、屏蔽过滤、演员屏蔽、排序 |
|
||||||
|
| `list-page-button.js` | `ListPageButtonPlugin` | 列表页工具栏按钮:一键屏蔽、收藏、随机打开等 |
|
||||||
|
| `auto-page.js` | `AutoPagePlugin` | 自动翻页 |
|
||||||
|
| `fold-category.js` | `FoldCategoryPlugin` | 折叠/展开分类标签区域 |
|
||||||
|
| `cover-button.js` | `CoverButtonPlugin` | 封面图上的操作按钮(屏蔽、收藏等) |
|
||||||
|
| `history.js` | `HistoryPlugin` | 鉴定记录面板 |
|
||||||
|
| `filter-title-keyword.js` | `FilterTitleKeywordPlugin` | 标题关键词屏蔽 |
|
||||||
|
| `blacklist.js` | `BlacklistPlugin` | 黑名单管理(屏蔽演员/标签) |
|
||||||
|
| `hit-show.js` | `HitShowPlugin` | 热播榜 |
|
||||||
|
| `top250.js` | `TOP250Plugin` | TOP250 排行榜 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 模块五:🎬 详情页插件(~2000 行)
|
||||||
|
**建议目录:`src/plugins/detail/`**
|
||||||
|
|
||||||
|
| 文件 | 类名 | 功能 |
|
||||||
|
|------|------|------|
|
||||||
|
| `detail-page.js` | `DetailPagePlugin` | 详情页核心:FC2/普通影片信息展示 |
|
||||||
|
| `detail-page-button.js` | `DetailPageButtonPlugin` | 详情页按钮:屏蔽、收藏、已下载、已观看、磁力搜索、字幕 |
|
||||||
|
| `bus-detail-page.js` | `BusDetailPagePlugin` | JavBus 详情页 |
|
||||||
|
| `review.js` | `ReviewPlugin` | 评论查看 |
|
||||||
|
| `related.js` | `RelatedPlugin` | 相关清单 |
|
||||||
|
| `highlight-magnet.js` | `HighlightMagnetPlugin` | 磁力链接高亮过滤 |
|
||||||
|
| `translate.js` | `TranslatePlugin` | 标题翻译(日→中) |
|
||||||
|
| `want-watched.js` | `WantAndWatchedVideosPlugin` | 想看/已看视频 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 模块六:🎥 视频与媒体插件(~1500 行)
|
||||||
|
**建议目录:`src/plugins/media/`**
|
||||||
|
|
||||||
|
| 文件 | 类名 | 功能 |
|
||||||
|
|------|------|------|
|
||||||
|
| `preview-video.js` | `PreviewVideoPlugin` | JavDB 预览视频播放 |
|
||||||
|
| `bus-preview-video.js` | `BusPreviewVideoPlugin` | JavBus 预览视频播放 |
|
||||||
|
| `screen-shot.js` | `ScreenShotPlugin` | 缩略图加载 |
|
||||||
|
| `bus-img.js` | `BusImgPlugin` | JavBus 图片处理 |
|
||||||
|
| `image-recognition.js` | `ImageRecognitionPlugin` | 以图识图 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 模块七:🔗 外部站点与工具插件(~2000 行)
|
||||||
|
**建议目录:`src/plugins/external/`**
|
||||||
|
|
||||||
|
| 文件 | 类名 | 功能 |
|
||||||
|
|------|------|------|
|
||||||
|
| `magnet-hub.js` | `MagnetHubPlugin` | 多站点磁力搜索聚合 |
|
||||||
|
| `other-site.js` | `OtherSitePlugin` | 其他站点入口(JavStore、MissAV等) |
|
||||||
|
| `fc2.js` | `Fc2Plugin` | FC2 影片页面 |
|
||||||
|
| `fc2-123av.js` | `Fc2By123AvPlugin` | 123AV 的 FC2 页面 |
|
||||||
|
| `wangpan-115.js` | `WangPan115Plugin` / `WangPan115TaskPlugin` / `WangPan115MatchPlugin` | 115网盘离线下载 |
|
||||||
|
| `aliyun-pan.js` | `AliyunPanPlugin` | 阿里云盘 |
|
||||||
|
| `jav-trailers.js` | `JavTrailersPlugin` | JavTrailers 站点 |
|
||||||
|
| `subtitle-cat.js` | `SubTitleCatPlugin` | SubTitleCat 字幕搜索 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 模块八:👤 演员与任务插件(~2000 行)
|
||||||
|
**建议目录:`src/plugins/actress/`**
|
||||||
|
|
||||||
|
| 文件 | 类名 | 功能 |
|
||||||
|
|------|------|------|
|
||||||
|
| `actress-info.js` | `ActressInfoPlugin` | 演员信息面板 |
|
||||||
|
| `favorite-actresses.js` | `FavoriteActressesPlugin` | 收藏演员管理 |
|
||||||
|
| `new-video.js` | `NewVideoPlugin` | 新作品检测 |
|
||||||
|
| `task.js` | `TaskPlugin` | 定时任务:检测黑名单、同步演员、新作品检测 |
|
||||||
|
| `nav-bar.js` | `NavBarPlugin` / `BusNavBarPlugin` | 导航栏增强 |
|
||||||
|
| `setting.js` | `SettingPlugin` | 设置面板 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🎯 建议的项目目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
JHS-enhance/
|
||||||
|
├── src/
|
||||||
|
│ ├── main.js # 入口:初始化 + 插件注册
|
||||||
|
│ ├── core/
|
||||||
|
│ │ ├── utils.js # 通用工具函数
|
||||||
|
│ │ ├── gmHttp.js # GM_xmlhttpRequest 封装
|
||||||
|
│ │ ├── storage.js # IndexedDB 存储管理
|
||||||
|
│ │ ├── show.js # Toast 消息提示
|
||||||
|
│ │ ├── constants.js # 所有常量
|
||||||
|
│ │ ├── styles.js # CSS 样式
|
||||||
|
│ │ ├── plugin-manager.js # 插件管理器
|
||||||
|
│ │ └── base-plugin.js # 插件基类
|
||||||
|
│ ├── api/
|
||||||
|
│ │ └── javdb-api.js # JavDB API 接口
|
||||||
|
│ ├── plugins/
|
||||||
|
│ │ ├── list/ # 列表页插件 (10个)
|
||||||
|
│ │ ├── detail/ # 详情页插件 (8个)
|
||||||
|
│ │ ├── media/ # 视频/媒体插件 (5个)
|
||||||
|
│ │ ├── external/ # 外部站点插件 (8个)
|
||||||
|
│ │ └── actress/ # 演员/任务插件 (6个)
|
||||||
|
│ └── styles/
|
||||||
|
│ └── ... (可选,如果CSS拆出来)
|
||||||
|
├── vite.config.mjs
|
||||||
|
├── package.json
|
||||||
|
└── JHS-origin.js # 保留原始文件作为参考
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ⚠️ 拆分时的注意事项
|
||||||
|
|
||||||
|
1. **全局变量依赖**:当前代码大量使用 `unsafeWindow.xxx = window.xxx`,拆分为 ES Module 后需要改为 `export`/`import`,同时通过 `window` 暴露给油猴全局作用域
|
||||||
|
|
||||||
|
2. **插件间依赖**:插件通过 `this.getBean(name)` 互相调用,拆分后需确保 `PluginManager` 先初始化
|
||||||
|
|
||||||
|
3. **CDN 外部依赖**:jQuery、Tabulator 等通过 `@require` 加载,在模块中直接使用 `$`、`Tabulator` 等全局变量即可
|
||||||
|
|
||||||
|
4. **CSS 注入**:`insertStyle()` 和 `initCss()` 需要 `document.head` 可用后才能执行
|
||||||
|
|
||||||
|
5. **循环依赖**:注意 `TaskPlugin` ↔ `BlacklistPlugin`、`ListPagePlugin` ↔ `BlacklistPlugin` 等之间的双向引用
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🚀 建议的实施顺序
|
||||||
|
|
||||||
|
| 优先级 | 步骤 | 预计工作量 |
|
||||||
|
|--------|------|-----------|
|
||||||
|
| P0 | 拆分 `core/` 基础设施(utils, gmHttp, storage, show, constants, styles) | 1-2小时 |
|
||||||
|
| P1 | 拆分插件系统(plugin-manager, base-plugin)和入口 `main.js` | 30分钟 |
|
||||||
|
| P2 | 拆分 API 层(javdb-api) | 15分钟 |
|
||||||
|
| P3 | 分批拆分插件,每批 3-5 个,逐个验证构建 | 3-5小时 |
|
||||||
|
| P4 | 清理全局变量,统一为 ES Module 导入导出 | 1小时 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
需要我开始执行拆分吗?建议从 **P0(基础设施层)** 开始,这是最独立、最不容易出错的模块。
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const allConstants = [
|
||||||
|
'isJavBus', 'isJavDb', 'isSearchPage', 'currentHref',
|
||||||
|
'Status_RUNNING', 'Status_SUCCESS', 'Status_FAIL', 'Status_LOADING',
|
||||||
|
'Status_FILTER', 'Status_FAVORITE', 'Status_HAS_DOWN', 'Status_HAS_WATCH',
|
||||||
|
'NO', 'YES'
|
||||||
|
];
|
||||||
|
|
||||||
|
const pluginsDir = 'src/plugins';
|
||||||
|
const files = fs.readdirSync(pluginsDir).filter(f => f.endsWith('.js'));
|
||||||
|
|
||||||
|
let fixed = 0;
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(pluginsDir, file);
|
||||||
|
let content = fs.readFileSync(filePath, 'utf8');
|
||||||
|
|
||||||
|
const needed = allConstants.filter(c => new RegExp('\\b' + c + '\\b').test(content));
|
||||||
|
if (needed.length === 0) continue;
|
||||||
|
|
||||||
|
const importMatch = content.match(/import\s*\{([^}]+)\}\s*from\s*['"][^'"]*constants[^'"]*['"]/);
|
||||||
|
|
||||||
|
if (importMatch) {
|
||||||
|
const existing = importMatch[1].split(',').map(s => s.trim()).filter(Boolean);
|
||||||
|
const missing = needed.filter(c => !existing.includes(c));
|
||||||
|
|
||||||
|
if (missing.length > 0) {
|
||||||
|
const newImports = [...existing, ...missing].join(', ');
|
||||||
|
const newImportLine = `import { ${newImports} } from '../core/constants.js';`;
|
||||||
|
content = content.replace(importMatch[0], newImportLine);
|
||||||
|
fs.writeFileSync(filePath, content);
|
||||||
|
console.log(`Fixed: ${file} +${missing.join(', ')}`);
|
||||||
|
fixed++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const newImportLine = `import { ${needed.join(', ')} } from '../core/constants.js';`;
|
||||||
|
const baseImportMatch = content.match(/import\s*\{[^}]*\}\s*from\s*['"][^'"]*base-plugin[^'"]*['"]/);
|
||||||
|
if (baseImportMatch) {
|
||||||
|
content = content.replace(baseImportMatch[0], baseImportMatch[0] + '\n' + newImportLine);
|
||||||
|
fs.writeFileSync(filePath, content);
|
||||||
|
console.log(`Fixed: ${file} +${needed.join(', ')} (new import)`);
|
||||||
|
fixed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\nTotal fixed: ${fixed} files`);
|
||||||
Generated
+1628
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "jhs-enhance",
|
||||||
|
"version": "3.3.6",
|
||||||
|
"description": "Jav-鉴黄师 油猴脚本 - 工程化版本",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^6.0.0",
|
||||||
|
"vite-plugin-monkey": "^5.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"blueimp-md5": "^2.19.0",
|
||||||
|
"jquery": "^4.0.0",
|
||||||
|
"layui-layer": "^1.0.9",
|
||||||
|
"localforage": "^1.10.0",
|
||||||
|
"qrcodejs": "^1.0.0",
|
||||||
|
"tabulator-tables": "^6.5.2",
|
||||||
|
"toastify-js": "^1.12.0",
|
||||||
|
"viewerjs": "^1.12.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
+181
@@ -0,0 +1,181 @@
|
|||||||
|
import { qualityOptions } from '../core/constants.js';
|
||||||
|
const selectDefaultQuality = (dmmVideoQualityList, intendedDefault) => {
|
||||||
|
if (!dmmVideoQualityList || 0 === dmmVideoQualityList.length) return null;
|
||||||
|
const availableSet = new Set(dmmVideoQualityList);
|
||||||
|
if (availableSet.has(intendedDefault)) return intendedDefault;
|
||||||
|
const priorityOrder = qualityOptions.map((option => option.quality)).reverse();
|
||||||
|
for (const quality of priorityOrder) if (availableSet.has(quality)) return quality;
|
||||||
|
return dmmVideoQualityList[0];
|
||||||
|
}, CACHE_KEY = "jhs_dmm_video";
|
||||||
|
|
||||||
|
class DmmVideoFetcher {
|
||||||
|
constructor(carNum2, showErrorMessages = !0) {
|
||||||
|
this.carNum = carNum2;
|
||||||
|
this.showErrorMessages = showErrorMessages;
|
||||||
|
}
|
||||||
|
_checkCache() {
|
||||||
|
const cachedData = localStorage.getItem(CACHE_KEY) ? JSON.parse(localStorage.getItem(CACHE_KEY)) : {};
|
||||||
|
if (cachedData[this.carNum]) {
|
||||||
|
clog.debug("缓存中存在预览视频信息", cachedData[this.carNum]);
|
||||||
|
return cachedData[this.carNum];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
_updateCache(videoMap) {
|
||||||
|
const cachedData = localStorage.getItem(CACHE_KEY) ? JSON.parse(localStorage.getItem(CACHE_KEY)) : {};
|
||||||
|
cachedData[this.carNum] = videoMap;
|
||||||
|
clog.debug("成功解析出预览视频并已缓存:", videoMap);
|
||||||
|
localStorage.setItem(CACHE_KEY, JSON.stringify(cachedData));
|
||||||
|
}
|
||||||
|
async _searchContentIds() {
|
||||||
|
const carNum2 = this.carNum, carNumNoHyphen = carNum2.replace(/-/g, ""), keywordAttempts = [ {
|
||||||
|
keyword: carNum2.replace("-", "00"),
|
||||||
|
name: "00-替换关键词"
|
||||||
|
}, {
|
||||||
|
keyword: carNum2,
|
||||||
|
name: "原始番号关键词"
|
||||||
|
}, {
|
||||||
|
keyword: carNumNoHyphen,
|
||||||
|
name: "无连字符关键词"
|
||||||
|
} ], carNumLower = carNum2.toLowerCase();
|
||||||
|
for (const attempt of keywordAttempts) {
|
||||||
|
const {keyword: keyword, name: name2} = attempt, currentTempCarNumLower = keyword.toLowerCase(), apiUrl2 = `https://api.dmm.com/affiliate/v3/ItemList?${new URLSearchParams({
|
||||||
|
api_id: "UrwskPfkqQ0DuVry2gYL",
|
||||||
|
affiliate_id: "10278-996",
|
||||||
|
output: "json",
|
||||||
|
site: "FANZA",
|
||||||
|
sort: "match",
|
||||||
|
keyword: keyword
|
||||||
|
}).toString()}`;
|
||||||
|
let response;
|
||||||
|
try {
|
||||||
|
response = await gmHttp.get(apiUrl2);
|
||||||
|
} catch (e) {
|
||||||
|
clog.error(`API 请求失败,跳过 ${name2}:`, e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!response || !response.result || !response.result.result_count) {
|
||||||
|
clog.debug(`使用 ${name2} (${keyword}) 进行 API 搜索 返回无结果,尝试下一个关键词。`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const newItems = [];
|
||||||
|
for (const item of response.result.items) {
|
||||||
|
if (newItems.length >= 2) break;
|
||||||
|
const contentId = item.content_id || "", makerProduct = item.maker_product || "";
|
||||||
|
if (contentId.includes(currentTempCarNumLower.replace("-", "")) || carNumLower === makerProduct.toLowerCase() || contentId.includes(carNumNoHyphen.toLowerCase())) {
|
||||||
|
newItems.push({
|
||||||
|
serviceCode: item.service_code,
|
||||||
|
floorCode: item.floor_code,
|
||||||
|
contentId: contentId,
|
||||||
|
pageUrl: item.URL
|
||||||
|
});
|
||||||
|
clog.debug(`[${name2}] cid|makerProduct 匹配成功:`, contentId, makerProduct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newItems.length > 0) {
|
||||||
|
clog.debug(`--- 成功通过 ${name2} 找到 Content IDs ---`);
|
||||||
|
const $btn2 = $("#fanzaBtn");
|
||||||
|
let url = `https://www.dmm.co.jp/search/=/searchstr=${keyword}`, type = "single";
|
||||||
|
if (newItems.length > 1) {
|
||||||
|
$btn2.attr("href", url);
|
||||||
|
$btn2.append('<span class="site-tag" style="top:-15px">多结果</span>');
|
||||||
|
$btn2.css("backgroundColor", "#7bc73b");
|
||||||
|
type = "multiple";
|
||||||
|
} else {
|
||||||
|
url = newItems[0].pageUrl;
|
||||||
|
$btn2.attr("href", url);
|
||||||
|
$btn2.css("backgroundColor", "#7bc73b");
|
||||||
|
}
|
||||||
|
const dmmCacheKey = "jhs_other_site_dmm", dmmCacheData = localStorage.getItem(dmmCacheKey) ? JSON.parse(localStorage.getItem(dmmCacheKey)) : {};
|
||||||
|
dmmCacheData[this.carNum] = {
|
||||||
|
type: type,
|
||||||
|
url: url
|
||||||
|
};
|
||||||
|
localStorage.setItem(dmmCacheKey, JSON.stringify(dmmCacheData));
|
||||||
|
return newItems;
|
||||||
|
}
|
||||||
|
clog.debug(`[${name2}] API 返回结果数 ${response.result.result_count},但无精确匹配的 Content ID。`);
|
||||||
|
}
|
||||||
|
clog.warn("所有关键词尝试均未找到匹配的Content ID, 解析Dmm视频失败");
|
||||||
|
const $btn = $("#fanzaBtn");
|
||||||
|
$btn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`);
|
||||||
|
$btn.attr("title", "未查询到, 点击前往搜索页");
|
||||||
|
$btn.css("backgroundColor", "#de3333");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
async _extractTrailerLinks({contentId: contentId, serviceCode: serviceCode, floorCode: floorCode}) {
|
||||||
|
const trailerPageUrl = `https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid=${contentId}/mtype=AhRVShI_/service=${serviceCode}/floor=${floorCode}/mode=/`, htmlContent = await gmHttp.get(trailerPageUrl, null, {
|
||||||
|
"accept-language": "ja-JP,ja;q=0.9",
|
||||||
|
Cookie: "age_check_done=1"
|
||||||
|
});
|
||||||
|
if ("string" != typeof htmlContent) {
|
||||||
|
clog.error(htmlContent);
|
||||||
|
throw new Error("解析播放页内容失败, 非文本内容");
|
||||||
|
}
|
||||||
|
if (htmlContent.includes("このサービスはお住まいの地域からは")) throw new Error("节点不可用,请将DMM域名分流到日本ip");
|
||||||
|
const match = htmlContent.match(/const\s+args\s+=\s+(.*);/);
|
||||||
|
if (!match) throw new Error("未在脚本中找到 const args = ... 变量");
|
||||||
|
let bitrates;
|
||||||
|
try {
|
||||||
|
({bitrates: bitrates} = JSON.parse(match[1]));
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(`解析播放器脚本 JSON 失败: ${e.message}`);
|
||||||
|
}
|
||||||
|
const finalQualityMap = {}, qualityKeys = qualityOptions.map((o => o.quality)).join("|"), qualityNameRegex = new RegExp(`(${qualityKeys})\\.mp4$`);
|
||||||
|
if (!Array.isArray(bitrates)) {
|
||||||
|
clog.error("解析画质链接失败: bitrates 字段不是一个数组或不存在");
|
||||||
|
throw new Error("解析画质链接失败: bitrates 字段不是一个数组或不存在");
|
||||||
|
}
|
||||||
|
clog.debug("原始数据返回:", bitrates);
|
||||||
|
for (const item of bitrates) {
|
||||||
|
const url = null == item ? void 0 : item.src;
|
||||||
|
if (!url || "string" != typeof url || !url.endsWith(".mp4")) continue;
|
||||||
|
const qualityMatch = url.match(qualityNameRegex);
|
||||||
|
let qualityKey = "";
|
||||||
|
qualityMatch && qualityMatch[1] && (qualityKey = qualityMatch[1]);
|
||||||
|
qualityKey && !finalQualityMap[qualityKey] && (finalQualityMap[qualityKey] = url);
|
||||||
|
}
|
||||||
|
if (0 === Object.keys(finalQualityMap).length) throw new Error("未找到匹配要求的预览画质视频");
|
||||||
|
return finalQualityMap;
|
||||||
|
}
|
||||||
|
async fetchVideo() {
|
||||||
|
const cachedResult = this._checkCache();
|
||||||
|
if (cachedResult) return cachedResult;
|
||||||
|
let contentItems;
|
||||||
|
try {
|
||||||
|
const testCarNum = this.carNum.toLowerCase();
|
||||||
|
if (testCarNum.startsWith("heyzo") || /^(n\d+|\d+(-\d+)*)$/.test(testCarNum) || /^n\d+$/.test(testCarNum)) throw new Error("无码番号类型, 取消dmm解析");
|
||||||
|
if (this.carNum.includes("VR-")) throw new Error("VR类型, 取消dmm解析");
|
||||||
|
contentItems = await this._searchContentIds();
|
||||||
|
} catch (e) {
|
||||||
|
clog.error("DMM API 搜索失败:", e);
|
||||||
|
const $btn = $("#fanzaBtn");
|
||||||
|
$btn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`);
|
||||||
|
$btn.attr("title", "未查询到, 点击前往搜索页");
|
||||||
|
$btn.css("backgroundColor", "#de3333");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!contentItems || 0 === contentItems.length) return null;
|
||||||
|
try {
|
||||||
|
const finalVideoMap = await Promise.any(contentItems.map((item => this._extractTrailerLinks(item))));
|
||||||
|
this._updateCache(finalVideoMap);
|
||||||
|
return finalVideoMap;
|
||||||
|
} catch (error) {
|
||||||
|
const errors = error.errors || [ error ];
|
||||||
|
if (errors.some((err => err.message.includes("节点不可用")))) this.showErrorMessages && show.error("节点不可用,请将DMM域名分流到日本ip"); else {
|
||||||
|
const displayError = errors[0].message || errors[0];
|
||||||
|
clog.error(`解析失败: ${displayError}`, errors);
|
||||||
|
this.showErrorMessages && show.error(`解析失败: ${displayError}`);
|
||||||
|
}
|
||||||
|
const $btn = $("#fanzaBtn");
|
||||||
|
$btn.attr("href", `https://www.dmm.co.jp/search/=/searchstr=${this.carNum}`);
|
||||||
|
$btn.attr("title", "未查询到, 点击前往搜索页");
|
||||||
|
$btn.css("backgroundColor", "#de3333");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDmmVideo = async (carNum2, showErrorMessages = !0) => new DmmVideoFetcher(carNum2, showErrorMessages).fetchVideo();
|
||||||
|
|
||||||
|
export { DmmVideoFetcher, getDmmVideo, selectDefaultQuality };
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import $ from 'jquery';
|
||||||
|
import localforage from 'localforage';
|
||||||
|
import Toastify from 'toastify-js';
|
||||||
|
import md5 from 'blueimp-md5';
|
||||||
|
import { TabulatorFull as Tabulator } from 'tabulator-tables';
|
||||||
|
import Viewer from 'viewerjs';
|
||||||
|
import QRCode from 'qrcodejs';
|
||||||
|
import { currentHref, isJavDb, isJavBus, isSearchPage, Status_RUNNING, Status_SUCCESS, Status_FAIL, Status_LOADING, Status_FILTER, Status_FAVORITE, Status_HAS_DOWN, Status_HAS_WATCH, NO, YES } from './constants.js';
|
||||||
|
|
||||||
|
window.$ = window.jQuery = $;
|
||||||
|
window.localforage = localforage;
|
||||||
|
window.Toastify = Toastify;
|
||||||
|
window.md5 = md5;
|
||||||
|
window.Tabulator = Tabulator;
|
||||||
|
window.Viewer = Viewer;
|
||||||
|
window.QRCode = QRCode;
|
||||||
|
|
||||||
|
window.currentHref = currentHref;
|
||||||
|
window.isJavDb = isJavDb;
|
||||||
|
window.isJavBus = isJavBus;
|
||||||
|
window.isSearchPage = isSearchPage;
|
||||||
|
window.Status_RUNNING = Status_RUNNING;
|
||||||
|
window.Status_SUCCESS = Status_SUCCESS;
|
||||||
|
window.Status_FAIL = Status_FAIL;
|
||||||
|
window.Status_LOADING = Status_LOADING;
|
||||||
|
window.Status_FILTER = Status_FILTER;
|
||||||
|
window.Status_FAVORITE = Status_FAVORITE;
|
||||||
|
window.Status_HAS_DOWN = Status_HAS_DOWN;
|
||||||
|
window.Status_HAS_WATCH = Status_HAS_WATCH;
|
||||||
|
window.NO = NO;
|
||||||
|
window.YES = YES;
|
||||||
|
|
||||||
|
import 'layui-layer';
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import monkey from 'vite-plugin-monkey';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
monkey({
|
||||||
|
entry: 'src/main.js',
|
||||||
|
userscript: {
|
||||||
|
name: 'JAV-JHS',
|
||||||
|
namespace: 'JAV-JHS',
|
||||||
|
version: '3.3.6-fix',
|
||||||
|
author: 'xie bro',
|
||||||
|
description: 'Jav-鉴黄师 收藏、屏蔽、标记已下载; 屏蔽标签、屏蔽演员、同步收藏演员、新作品检测; 免VIP查看热播、Top250排行榜、Fc2ppv、可查看所有评论信息、相关清单; 支持云盘备份; 以图识图; 字幕搜索; JavDb|JavBus',
|
||||||
|
license: 'MIT',
|
||||||
|
icon: 'https://www.google.com/s2/favicons?sz=64&domain=javdb.com',
|
||||||
|
match: [
|
||||||
|
'https://javdb.com/*',
|
||||||
|
'https://www.javbus.com/*',
|
||||||
|
],
|
||||||
|
include: [
|
||||||
|
'https://javdb*.com/*',
|
||||||
|
'https://*javbus*/*',
|
||||||
|
'https://*javsee*/*',
|
||||||
|
'https://*seejav*/*',
|
||||||
|
'https://javtrailers.com/*',
|
||||||
|
'https://subtitlecat.com/*',
|
||||||
|
'https://www.aliyundrive.com/*',
|
||||||
|
'https://www.alipan.com/*',
|
||||||
|
'https://115.com/*',
|
||||||
|
],
|
||||||
|
exclude: [
|
||||||
|
'https://*javbus*/forum/*',
|
||||||
|
'https://*javbus*/*actresses',
|
||||||
|
'https://*javsee*/forum/*',
|
||||||
|
'https://*javsee*/*actresses',
|
||||||
|
'https://*seejav*/forum/*',
|
||||||
|
'https://*seejav*/*actresses',
|
||||||
|
],
|
||||||
|
require: [
|
||||||
|
'https://raw.githubusercontent.com/Tampermonkey/utils/refs/heads/main/requires/gh_2215_make_GM_xhr_more_parallel_again.js',
|
||||||
|
'https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js',
|
||||||
|
'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min.js',
|
||||||
|
'https://cdn.jsdelivr.net/npm/layui-layer@1.0.9/dist/layer.min.js',
|
||||||
|
'https://cdn.jsdelivr.net/npm/blueimp-md5@2.19.0/js/md5.min.js',
|
||||||
|
'https://cdn.jsdelivr.net/npm/toastify-js@1.12.0/src/toastify.min.js',
|
||||||
|
'https://cdn.jsdelivr.net/npm/localforage@1.10.0/dist/localforage.min.js',
|
||||||
|
'https://cdn.jsdelivr.net/npm/viewerjs@1.11.1/dist/viewer.min.js',
|
||||||
|
'https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js',
|
||||||
|
],
|
||||||
|
connect: [
|
||||||
|
'xunlei.com',
|
||||||
|
'geilijiasu.com',
|
||||||
|
'aliyundrive.com',
|
||||||
|
'aliyundrive.net',
|
||||||
|
'ja.wikipedia.org',
|
||||||
|
'beta.magnet.pics',
|
||||||
|
'jdforrepam.com',
|
||||||
|
'cc3001.dmm.co.jp',
|
||||||
|
'cc3001.dmm.com',
|
||||||
|
'www.dmm.co.jp',
|
||||||
|
'www.dmm.com',
|
||||||
|
'api.dmm.com',
|
||||||
|
'special.dmm.co.jp',
|
||||||
|
'adult.contents.fc2.com',
|
||||||
|
'fc2ppvdb.com',
|
||||||
|
'123av.com',
|
||||||
|
'u3c3.com',
|
||||||
|
'u9a9.com',
|
||||||
|
'btsow.lol',
|
||||||
|
'sukebei.nyaa.si',
|
||||||
|
'javstore.net',
|
||||||
|
'javbest.net',
|
||||||
|
'missav.live',
|
||||||
|
'jable.tv',
|
||||||
|
'www.av.gl',
|
||||||
|
'jav.rs',
|
||||||
|
'javtrailers.com',
|
||||||
|
'javdb.com',
|
||||||
|
'javbus.com',
|
||||||
|
'supjav.com',
|
||||||
|
'115.com',
|
||||||
|
'jianguoyun.com',
|
||||||
|
'127.0.0.1',
|
||||||
|
'*',
|
||||||
|
],
|
||||||
|
grant: [
|
||||||
|
'GM_xmlhttpRequest',
|
||||||
|
'GM_openInTab',
|
||||||
|
'unsafeWindow',
|
||||||
|
],
|
||||||
|
'run-at': 'document-idle',
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
fileName: 'jhs-enhance.user.js',
|
||||||
|
externalGlobals: {
|
||||||
|
'jquery': '$',
|
||||||
|
'localforage': 'localforage',
|
||||||
|
'toastify-js': 'Toastify',
|
||||||
|
'blueimp-md5': 'md5',
|
||||||
|
'tabulator-tables': 'Tabulator',
|
||||||
|
'viewerjs': 'Viewer',
|
||||||
|
'qrcodejs': 'QRCode',
|
||||||
|
'layui-layer': 'layer',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user