# legado-source-generator
**Repository Path**: wzal/legado-source-generator
## Basic Information
- **Project Name**: legado-source-generator
- **Description**: 一个 Chrome 扩展,通过可视化点选页面元素来生成阅读 APP 的书源规则。
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2026-08-18
- **Last Updated**: 2026-08-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Legado 书源生成器
> ⚠️ **风险提示**:本项目完全由 AI 辅助生成(vibe coding),代码可能存在缺陷、安全漏洞或有害内容。作者不对使用本项目产生的任何后果负责。使用者在安装或使用前,请务必自行审查代码,确保安全。
一个 Chrome 扩展,通过可视化点选页面元素来生成[阅读](https://github.com/gedoor/legado) APP 的书源规则。
## 交流群
1101980180
## 想用ai自动化编写调试书源?
试试[legado-book-source-skill](https://github.com/z1131392774/legado-book-source-skill)
## 演示视频
[](https://www.bilibili.com/video/BV1ipDdBkEjA/)
> 👆 点击观看完整演示视频
## 功能特性
- **可视化元素选择**:点击选择页面上任意元素
- **智能选择器生成**:自动生成稳定的 CSS 选择器
- **分步工作流**:支持发现页、搜索页、详情页、目录页、正文页五种规则类型
- **列表交集算法**:选择两个同列表元素,自动提取公共 class 生成可复用选择器
- **错误检测**:自动检测 Shadow DOM、iframe、动态 class 等潜在问题
- **键盘导航**:支持 ↑↓←→ 键在 DOM 树中精确导航
- **导出 JSON**:一键生成可直接导入阅读 APP 的书源规则
- **自动填充**:一键从当前页面自动填充书源名称和 URL
- **检查更新**:自动对比 GitHub 最新版本
- **状态持久化**:所有填写内容自动保存,关闭浏览器后不丢失
- **发现页 URL 编辑**:支持可视化卡片编辑、页面收集、批量 URL 替换、样式模板管理
- **搜索 URL 编辑**:支持自动捕获搜索请求 URL,自动生成带占位符的搜索 URL
## 安装
### Chrome / Edge
1. 打开浏览器,访问 `chrome://extensions/`
2. 开启右上角的"开发者模式"
3. 点击"加载已解压的扩展程序",选择 `src` 目录
4. 建议固定扩展图标方便使用
### Firefox
> ⚠️ **注意**:本扩展主要基于 Chrome (MV3) 开发和测试,Firefox 版本(MV2)为适配移植版本,可能存在未知 bug。如遇问题,请优先使用 Chrome / Edge 版本。
#### 方式一:从扩展商店安装(推荐)
1. 打开 Firefox,访问 [Firefox 扩展商店](https://addons.mozilla.org/)
2. 搜索 **Legado Source Generator**
3. 点击"添加到 Firefox"完成安装
#### 方式二:手动加载(开发/测试)
1. 打开浏览器,访问 `about:debugging#/runtime/this-firefox`
2. 点击"临时载入附加组件"
3. 选择 `src-firefox/manifest.json` 文件
4. 点击工具栏扩展图标即可打开侧边栏
## 使用方法
### 规则页(发现页 / 搜索页 / 详情页 / 目录页 / 正文页)
1. 点击扩展图标打开侧边栏
2. 填写书源名称和基础 URL
3. 选择规则类型(发现页 / 搜索页 / 详情页 / 目录页 / 正文页)
4. 点击"选择元素"开始点选:
- **列表字段**(书籍列表/章节列表):选择两个同列表元素,自动取交集
- **普通字段**:直接点击目标元素
5. 使用键盘快捷键精确调整:
- `↑` 移动到父元素
- `↓` 移动到第一个子元素
- `←` 移动到上一个兄弟元素
- `→` 移动到下一个兄弟元素
- `Enter` 确认选择
- `Esc` 取消选择
6. 完成后点击"导出 JSON"获取书源规则
7. 导入到阅读 APP
### 捕获搜索 URL
如果当前页面有搜索功能,可以自动捕获搜索请求的 URL 格式。
1. 切换到"搜索URL"标签页
2. 点击 **🔍 捕获** 按钮
3. 页面提示"请点击网站的'搜索'按钮",此时**点击网站页面的搜索按钮**(无需手动输入)
4. 扩展会自动捕获请求,成功后表单自动填充:
- **请求方法**:GET / POST
- **charset**:自动检测(utf-8 / gbk / big5 等)
- **请求体**:POST 时显示,搜索词已替换为 `{{key}}`
- **搜索 URL**:自动生成 `{{key}}` 占位符
5. 如需分页,点击 **{{page}}** 按钮插入页码占位符
6. 表单内容实时同步到下方的搜索 URL 输入框
> **提示**:
> - GET 请求输出格式:`https://example.com/search?key={{key}}&page={{page}}`
> - POST 请求输出格式:`https://example.com/search,{"charset":"gbk","method":"POST","body":"kw={{key}}&page={{page}}"}`
> - 扩展支持多种字符编码(UTF-8、GBK、BIG5 等),捕获时自动检测
> - 如未检测到搜索表单,表单各字段可手动填写
### 发现页 URL
发现页 URL 用于配置阅读 APP 首页的分类导航入口,支持可视化编辑和页面收集两种模式。
#### 可视化编辑
1. 切换到"发现页"标签页
2. 点击"手动添加"逐条输入分类名称和 URL
3. 点击"插入分隔"添加分隔符
4. 卡片支持拖拽排序和拖拽调整宽度
5. 右侧属性面板可调整 Flexbox 布局属性(flexGrow、flexShrink、alignSelf、flexBasisPercent、wrapBefore)
6. 底部预览区实时显示生成的 JSON,支持"样式一"(每行 `title::url`)和"样式二"(JSON 数组)两种格式切换
#### 从页面收集
1. 在浏览器中打开目标网站(如小说网站的首页)
2. 在侧边栏发现页标签下点击"从页面收集元素"
3. 鼠标悬停在页面的分类/排行链接上,侧边栏预览区下方实时显示元素信息
4. 点击链接即可收集,已收集项会显示蓝色闪烁提示
5. 收集完成后按 `Enter` 完成收集,所有条目自动添加到列表
6. **重要**:生成的 URL 通常不带分页参数,需要手动在 URL 中添加 `{{page}}` 占位符,例如将 `https://example.com/category/1` 改为 `https://example.com/category/{{page}}`,否则翻页不会生效
#### 批量修改 URL
收集或手动添加完成后,通常需要批量修改 URL 以适配阅读 APP 的分页机制。扩展提供两种批量修改模式:**模板匹配**和**正则匹配**。
##### 前置操作
1. 在发现页 URL 编辑器中,点击工具栏的 **"开启复选"** 勾选框
2. 勾选需要修改 URL 的卡片(或使用 **"全选"** / **"反选"** 快速选择)
3. 点击 **"批量改 URL"** 打开批量修改弹窗
##### 模式一:模板匹配(推荐)
模板匹配模式通过分类占位符和翻页模板自动替换 URL,适用于网站 URL 有明确分类和分页规律的场景。
**字段说明:**
| 字段 | 说明 |
|------|------|
| **分类匹配模板** | 以"第一页 URL"为基准,将分类部分替换为 `分类` 占位符,其余保持不变 |
| **翻页模板** | 以"第二页(或分页页)URL"为基准,将分类部分替换为 `分类`,页码数字替换为 `页码` |
| **第一页差异** | 当第一页 URL 与分页 URL 结构不同时,填写第一页多出来的那一段(含页码) |
**规则 1:第一页与分页 URL 结构相同(仅页码数字不同)**
此时"第一页差异"留空。例如:
- 第一页:`https://www.example.com/fantasy/1`
- 第二页:`https://www.example.com/fantasy/2`
填写:
- 分类匹配模板:`https://www.example.com/分类/1`
- 翻页模板:`https://www.example.com/分类/页码`
- 第一页差异:(留空)
处理后:`https://www.example.com/fantasy/<,页码>` → 实际效果为 `https://www.example.com/fantasy/{{page}}`
**规则 2:第一页与分页 URL 结构不同**
当第一页没有页码变量时,"第一页差异"填写分页 URL 中多出来的那一段。例如:
- 第一页:`https://www.example.com/fantasy/`
- 第二页:`https://www.example.com/fantasy/index_2.html`
填写:
- 分类匹配模板:`https://www.example.com/分类/`
- 翻页模板:`https://www.example.com/分类/index_页码.html`
- 第一页差异:`index_页码.html`
处理后:`https://www.example.com/fantasy/<,index_{{page}}.html>`
**规则 3:分类和页码都在 URL 路径中**
例如:
- 第一页:`https://www.example.com/tags-150-0.html`(150 是分类 ID,0 表示第一页)
- 第二页:`https://www.example.com/tags-150-1.html`
填写:
- 分类匹配模板:`https://www.example.com/tags-分类-0.html`
- 翻页模板:`https://www.example.com/tags-分类-页码.html`
- 第一页差异:(留空)
处理后:`https://www.example.com/tags-150/<,{{page}}.html>`
##### 模式二:正则匹配
正则匹配模式使用自定义正则表达式进行 URL 替换,适用于更灵活或更复杂的替换需求。
**字段说明:**
| 字段 | 说明 |
|------|------|
| **正则表达式** | 匹配 URL 中需要替换的部分,如 `/sort/xuanhuan/` |
| **替换为** | 替换后的内容,如 `/sort/分类/` |
| **全局替换(g)** | 勾选后会替换所有匹配项(默认开启) |
| **忽略大小写(i)** | 勾选后不区分大小写 |
**示例:**
将多个分类 URL 中的具体分类名统一替换为 `分类` 占位符:
- 正则表达式:`xuanhuan|dushi|wuxia`
- 替换为:`分类`
- 全局替换:勾选
或将 URL 中的分类 ID 替换为占位符:
- 正则表达式:`/tags/(\d+)/`
- 替换为:`/tags/分类/`
##### 应用结果
点击 **"应用到已选"** 后,系统会提示已更新的 URL 数量。修改结果会实时同步到预览区,可在导出 JSON 前确认格式正确。
##### 批量修改 Layout 属性
除了 URL,还支持批量修改卡片的 Flexbox 布局属性:
1. 开启复选模式并选择目标卡片
2. 点击 **"批量改 layout"**
3. 勾选需要修改的属性并填写新值:
- `layout_flexGrow` — 卡片拉伸权重(默认 `1`)
- `layout_flexShrink` — 卡片收缩权重(默认 `0`)
- `layout_alignSelf` — 自对齐方式(默认 `auto`)
- `layout_flexBasisPercent` — 基础宽度百分比(`-1` 表示自动)
- `layout_wrapBefore` — 是否在此卡片前换行
4. 点击 **"应用到已选"** 生效
##### 样式模板管理
样式模板用于快速统一卡片的 Flexbox 布局风格,支持新增、编辑、删除和设置默认模板。
###### 新增模板
1. 点击工具栏的 **"模板管理"** 按钮
2. 在弹窗中点击 **"新增模板"**
3. 填写模板名称(如"三列紧凑"、"两列宽屏"等),并设置各 layout 属性值:
| 属性 | 说明 | 默认值 |
|------|------|--------|
| `layout_flexGrow` | 卡片拉伸权重,值越大占空间越多 | `1` |
| `layout_flexShrink` | 空间不足时的收缩权重 | `0` |
| `layout_alignSelf` | 自对齐方式(auto / flex-start / flex-end / center 等) | `auto` |
| `layout_flexBasisPercent` | 基础宽度占总宽度的百分比,`-1` 表示自动等分 | `-1` |
| `layout_wrapBefore` | 是否在此卡片前换行,可实现独占一行效果 | `false` |
4. 点击 **"保存模板"**
###### 模板管理与默认模板
在 **"模板管理"** 面板中:
- **搜索**:顶部搜索框支持按模板名称快速过滤
- **查看**:点击"查看"展开模板的详细属性
- **编辑**:点击"编辑"修改模板名称和属性值
- **设默认**:点击"设默认"将该模板标记为默认,后续手动添加的卡片将自动应用此模板的布局属性
- **删除**:点击"删除"移除模板(至少保留一个)
###### 应用样式模板
1. 在发现页 URL 编辑器中,点击工具栏的 **"应用样式"** 按钮
2. 在下拉菜单中选择目标模板
3. 如果开启了复选模式,模板将应用到所有已勾选的卡片;否则应用到当前选中的单个卡片
4. 点击 **"应用到已选"** 生效
> **提示**:模板仅修改 layout 布局属性,不会覆盖卡片的标题和 URL。
## 键盘快捷键
### 规则页元素选择
| 按键 | 操作 |
|------|------|
| Esc | 退出选择模式 |
| Enter | 确认选择(列表字段需选两次) |
| ↑ | 移动到父元素 |
| ↓ | 移动到第一个子元素 |
| ← | 移动到上一个兄弟元素 |
| → | 移动到下一个兄弟元素 |
### 发现页收集
| 按键 | 操作 |
|------|------|
| Enter | 完成收集 |
## 调试
### 连接设置
打开阅读 APP → 我的 → Web服务 → 填入 IP 和端口号。
### 调试关键字
| 格式 | 说明 |
|------|------|
| 普通文本 | 搜索 |
| 分类名::URL | 发现 |
| URL | 详情 |
| ++URL | 目录 |
| --URL | 正文 |
留空时默认关键字为"我的"。
### 日志调试(输入 / 输出)
**看输入** — 把这段加在规则最前面:
```
java.log("输入" + result);你的原规则
```
**看输出** — 把这段加在规则最后面:
```
你的原规则java.log("输出" + result);
```
> **向别人提问前一定要加上这两个再调试!!!** 调完删掉日志。
### webView 是什么,什么时候开
**webView 的作用**
很多网站内容是动态加载的。不开 webView 时,规则可能抓不到最终页面内容。开了 webView,相当于"让页面先跑起来再抓"。
**什么时候建议开**
- 规则看起来没错,但结果一直空
- 目录页、正文页总是抓不到
- 下一页链接存在,但翻页不生效
- 某字段不开拿不到,开了马上正常
**什么时候不要开**
- 已经能正常抓到,就不要开
- 全字段都开会变慢,优先只开有问题的字段
**新手推荐顺序**
1. 先全部不开,先调规则
2. 哪个字段有问题,只给哪个字段开 webView
> **一句话结论**:能不开就不开,出问题再精准开启。
### 过 Cloudflare 盾
部分小说网站使用了 Cloudflare(CF)5 秒盾防护,直接请求会返回 403 并要求人机验证。扩展提供了「开启过 Cloudflare 盾」选项,勾选后会在导出的书源中自动注入 `loginCheckJs` 规则。
**工作原理**
1. 请求返回内容后,检测响应体是否包含 CF 验证特征(`_cf_`、`ge_ua`、`verify.php`)且状态码 ≥ 403
2. 如果命中 CF 盾,清除已有 Cookie,调用 `java.startBrowserAwait()` 打开浏览器完成人机验证
3. 验证通过后获取真实页面内容,继续正常解析
**什么时候需要开**
- 调试时被cloudflare人机验证拦截,无法获取内容
- 普通请求能正常获取内容的网站**不需要开**
## 错误提示
选择器会自动检测潜在问题:
- **Shadow DOM**:元素在 Shadow DOM 内,选择器可能不生效
- **Iframe**:跨域限制可能影响选择
- **动态 Class**:自动生成的 class 名称可能不稳定
- **空选择器**:未选择有效元素
- **无匹配**:选择器返回零个元素
## 项目结构
```
src/ # Chrome / Edge 版本 (MV3)
├── manifest.json # 扩展配置
├── background.js # Service Worker(点击图标打开侧边栏)
├── content/
│ ├── picker.js # 元素选择器逻辑
│ └── picker.css # 选择器样式
├── popup/
│ ├── index.html # 侧边栏界面
│ ├── popup.js # 侧边栏逻辑(规则页状态管理、导出)
│ ├── popup.css # 侧边栏样式
│ ├── explore-url-editor.js # 发现页 URL 编辑器(收集、批量修改、样式模板)
│ └── batch-url-utils.js # 批量 URL 替换工具(模板匹配 / 正则匹配)
└── lib/
└── selector-generator.js # CSS 选择器生成算法
src-firefox/ # Firefox 版本 (MV2)
├── manifest.json # 扩展配置
├── background.js # 后台脚本
├── content/
│ ├── picker.js
│ └── picker.css
├── popup/
│ ├── index.html
│ ├── popup.js
│ ├── explore-url-editor.js
│ └── batch-url-utils.js
└── lib/
└── selector-generator.js
tests/ # 测试
└── batch-url-utils.test.js # 批量 URL 工具单元测试
```