release: 0.2.0421.2

This commit is contained in:
2026-04-21 17:10:06 +08:00
parent 55324a5bb7
commit 968cc88c62
19 changed files with 2832 additions and 178 deletions
@@ -0,0 +1,217 @@
# Market Export Range Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add configurable CSV export ranges for the Xingtu market plugin, defaulting to the first 5 pages and supporting current page, preset ranges, all pages, and custom page counts.
**Architecture:** Keep filter and sort scoped to the current page, and introduce a dedicated batch-export path that only runs when exporting. Extend the toolbar with export-range controls, extract page-navigation/signature helpers, and add a focused controller that iterates pages, harvests lazy-loaded DOM fields, merges records by `authorId`, and returns a single record set for CSV generation.
**Tech Stack:** TypeScript, Vitest, jsdom, Chrome MV3 content script
---
### Task 1: Extend Toolbar Controls For Export Range
**Files:**
- Modify: `src/content/market/plugin-toolbar.ts`
- Test: `tests/market-content-entry.test.ts`
- [ ] **Step 1: Write the failing tests**
Add tests that assert:
- the toolbar defaults to `前5页`
- selecting `自定义` shows and uses a page-count input
- invalid custom values prevent export
- export mode disables toolbar controls during a running task
- [ ] **Step 2: Run tests to verify they fail**
Run: `npm test -- tests/market-content-entry.test.ts -t "export range"`
Expected: FAIL because the toolbar has no range selector or custom input behavior.
- [ ] **Step 3: Write the minimal implementation**
Update `plugin-toolbar.ts` to:
- add an export-range `<select>`
- add a custom page-count `<input>`
- add status text support
- expose helpers for reading range state and toggling disabled/running UI
- [ ] **Step 4: Run tests to verify they pass**
Run: `npm test -- tests/market-content-entry.test.ts -t "export range"`
Expected: PASS
- [ ] **Step 5: Commit**
```bash
git add src/content/market/plugin-toolbar.ts tests/market-content-entry.test.ts
git commit -m "feat: add export range toolbar controls"
```
### Task 2: Add Batch Export Coverage
**Files:**
- Modify: `tests/market-content-entry.test.ts`
- Modify: `tests/market-dom-sync.test.ts`
- Test: `tests/market-content-entry.test.ts`
- [ ] **Step 1: Write the failing tests**
Add tests that assert:
- `当前页` exports only the current page
- `前5页` iterates through pages until it reaches page 5 or runs out of pages
- `全部` stops when the next-page control is no longer usable
- repeated authors across pages are merged by `authorId`
- empty fields from later pages do not erase existing populated fields
- page export waits for page signature change before harvesting the next page
- [ ] **Step 2: Run tests to verify they fail**
Run: `npm test -- tests/market-content-entry.test.ts`
Expected: FAIL on the new batch-export expectations.
- [ ] **Step 3: Write the minimal implementation scaffolding**
Only introduce the minimum new helpers/types needed to make the tests compile:
- export range type(s)
- page signature helpers
- harness utilities in tests
- [ ] **Step 4: Run tests to verify the failures are now behavioral**
Run: `npm test -- tests/market-content-entry.test.ts`
Expected: FAIL because batch export logic is still missing, not because types/selectors are missing.
- [ ] **Step 5: Commit**
```bash
git add tests/market-content-entry.test.ts tests/market-dom-sync.test.ts src/content/market/types.ts
git commit -m "test: cover multi-page export behavior"
```
### Task 3: Implement Batch Export Controller
**Files:**
- Create: `src/content/market/export-range-controller.ts`
- Modify: `src/content/market/types.ts`
- Modify: `src/content/market/dom-sync.ts`
- Modify: `src/content/market/result-store.ts`
- Test: `tests/market-content-entry.test.ts`
- Test: `tests/market-dom-sync.test.ts`
- [ ] **Step 1: Write the failing tests**
Add focused tests for:
- reading a page signature from current DOM
- detecting/using the next-page control
- merging rows by `authorId` with non-empty-field preference
- [ ] **Step 2: Run tests to verify they fail**
Run: `npm test -- tests/market-dom-sync.test.ts`
Expected: FAIL because these helpers/controller do not exist yet.
- [ ] **Step 3: Write the minimal implementation**
Implement `export-range-controller.ts` to:
- normalize export targets (`current`, `count`, `all`)
- harvest current page rows with the existing lazy-load scroll path
- read page signatures
- click/advance pagination and wait for signature change
- merge pages by `authorId` without overwriting non-empty fields
- return a final `MarketRecord[]`
Keep `dom-sync.ts` focused on DOM reads:
- page signature
- next-page element lookup
- next-page enabled check
- [ ] **Step 4: Run tests to verify they pass**
Run:
- `npm test -- tests/market-dom-sync.test.ts`
- `npm test -- tests/market-content-entry.test.ts`
Expected: PASS
- [ ] **Step 5: Commit**
```bash
git add src/content/market/export-range-controller.ts src/content/market/dom-sync.ts src/content/market/result-store.ts src/content/market/types.ts tests/market-content-entry.test.ts tests/market-dom-sync.test.ts
git commit -m "feat: add multi-page export controller"
```
### Task 4: Wire Controller Into Market Entry
**Files:**
- Modify: `src/content/market/index.ts`
- Modify: `src/content/market/plugin-toolbar.ts`
- Test: `tests/market-content-entry.test.ts`
- [ ] **Step 1: Write the failing tests**
Add tests that assert:
- `导出CSV` uses the selected range
- progress text updates while exporting
- controls are re-enabled on success and failure
- invalid custom input blocks export without calling CSV builder
- [ ] **Step 2: Run tests to verify they fail**
Run: `npm test -- tests/market-content-entry.test.ts`
Expected: FAIL because `market/index.ts` still always exports current-page records.
- [ ] **Step 3: Write the minimal implementation**
Update `market/index.ts` to:
- parse toolbar export range
- keep current-page export for `当前页`
- delegate batch modes to `export-range-controller.ts`
- update toolbar running/error/progress state
- preserve existing current-page lazy-load harvest path
- [ ] **Step 4: Run tests to verify they pass**
Run: `npm test -- tests/market-content-entry.test.ts`
Expected: PASS
- [ ] **Step 5: Commit**
```bash
git add src/content/market/index.ts src/content/market/plugin-toolbar.ts tests/market-content-entry.test.ts
git commit -m "feat: wire export range selection into market export"
```
### Task 5: Verify End-To-End
**Files:**
- Modify: `docs/superpowers/plans/2026-04-21-market-export-range.md`
- [ ] **Step 1: Run targeted regression tests**
Run:
- `npm test -- tests/market-content-entry.test.ts`
- `npm test -- tests/market-dom-sync.test.ts`
Expected: PASS
- [ ] **Step 2: Run the full suite**
Run: `npm test`
Expected: PASS with all test files green.
- [ ] **Step 3: Run the build**
Run: `npm run build`
Expected: PASS and emit updated `dist/` bundles.
- [ ] **Step 4: Mark the plan status**
Update this documents checkboxes to reflect completed steps.
- [ ] **Step 5: Commit**
```bash
git add docs/superpowers/plans/2026-04-21-market-export-range.md
git commit -m "docs: record export range implementation progress"
```
@@ -0,0 +1,257 @@
# 星图市场导出范围设计
## 背景
当前插件的 `导出CSV` 只导出当前页数据,并在星图默认列后追加两列:
- `单视频看后搜率`
- `个人视频看后搜率`
现阶段用户希望把导出范围扩展为可配置页数,而不是固定当前页。同时需要保留当前默认列导出逻辑,避免重新引入之前“全量扫描导致页面闪动、卡顿、排序异常”的问题。
## 目标
- 支持导出范围配置,默认导出前 `5` 页。
- 支持以下范围选项:
- `当前页`
- `前5页`
- `前10页`
- `全部`
- `自定义`
- 保留当前 CSV 规则:
- 先导出星图页面默认列
- 末尾追加两列插件字段
- 批量导出时真实翻页采集当前筛选结果页,不改变当前页面筛选条件来源。
- 保持当前“筛选/排序只作用当前页”的行为,不重新绑定多页扫描逻辑。
## 非目标
- 不改为直接调用星图列表接口拉多页数据。
- 不让插件筛选或排序自动跨页生效。
- 不处理“导出后自动回到最初分页位置”的复杂恢复,首版只要求滚动位置恢复到单页采集前。
## 交互设计
在插件工具栏中保留一个 `导出CSV` 按钮,同时新增导出范围控件。
### 范围控件
- 默认值:`前5页`
- 可选项:
- `当前页`
- `前5页`
- `前10页`
- `全部`
- `自定义`
- 选择 `自定义` 时,展示页数输入框
- 仅接受正整数
- 无效值时禁止导出并提示错误
### 任务状态
- 导出开始后:
- `导出CSV` 按钮禁用
- 筛选按钮、排序按钮、范围控件、自定义输入框一并禁用
- 按钮文案根据任务模式更新:
- 当前页:`导出中...`
- 前 N 页:`导出中 3/5 页...`
- 全部:`导出中 第3页...`
- 全部导出时额外显示轻提示:
- `全部导出可能耗时较长,页面会自动翻页。`
### 失败反馈
- 任一页采集失败时直接终止
- 通过按钮附近状态文本或 `alert` 提示:
- `第 N 页导出失败,请稍后重试`
- 失败时不下载残缺 CSV
## 执行流程
### 当前页导出
当前页模式沿用现有逻辑:
1. 等待当前页表格可读取
2. 自动滚动当前页一次,补齐懒加载字段
3. 读取当前页星图默认列
4. 合并插件两列
5. 生成 CSV 并下载
### 多页导出
多页模式仅在导出任务中启用,不影响平时筛选和排序。
1. 读取导出范围配置
2. 初始化批量任务状态与结果聚合器
3. 对当前页执行:
- 等待表格稳定
- 自动滚动当前页以采全默认列
- 读取当前页记录
-`authorId` 合并入结果集
4. 判断是否达到目标页数
5. 若未完成,则点击下一页
6. 等待“页切换完成”信号
7. 重复步骤 3 到 6
8. 汇总所有记录,生成单个 CSV 下载
### 全部导出停止条件
`全部` 模式从当前页开始向后翻页,直到任一条件成立:
- 下一页按钮不可点击
- 当前页签名不再变化
- 页面无法继续翻页并达到超时阈值
## 页切换判定
批量导出不能只依赖固定 `setTimeout`。翻页完成需要同时满足至少一个强信号:
- 当前页作者 ID 集合发生变化
- 当前页首行作者 ID 变化
- 当前页活动分页按钮变化
- 下一页按钮状态变化
为避免误判,翻页流程需要:
1. 记录翻页前页签名
2. 点击下一页
3. 轮询直到签名变化或超时
4. 签名变化后再执行一次当前页表格稳定等待
## 当前页采集策略
当前页导出已知存在懒加载问题:页面初加载时后半段行的默认列为空,滚动后才补齐。
因此无论当前页导出还是多页导出,每一页都必须执行:
1. 初次读取当前页快照并写入 store
2. 查找当前市场列表滚动容器
3. 逐步向下滚动直到该页底部
4. 每次滚动后等待 DOM 稳定,再采集一轮
5. 恢复滚动位置并再采集一轮
这一步只针对“当前已打开的页”,不跨页扫描。
## 数据合并规则
### 去重键
- 使用 `authorId` 去重
### 字段合并
- 新页记录有值时,补充到已有记录
- 新页记录为空时,不覆盖已有非空值
- 插件两列沿用当前已有的合并规则
### CSV 表头
- 先保留星图默认列顺序
- 再追加:
- `单视频看后搜率`
- `个人视频看后搜率`
## 错误处理
### 单页失败
以下情况视为单页失败:
- 找不到表格根节点
- 找不到下一页按钮但目标尚未完成
- 翻页后页签名未变化且超时
- 当前页采集过程中出现异常
处理方式:
- 立即终止任务
- 恢复工具栏控件状态
- 显示页级错误信息
- 不触发下载
### 用户干预
首版不额外提供取消按钮,但应防御以下情况:
- 用户手动切换筛选
- 用户手动翻页
- 用户再次点击导出
处理方式:
- 导出期间禁用插件控件
- 对关键节点重新校验表格和页签名
- 如环境已被破坏,终止任务并报错
## 实现建议
建议按以下边界组织实现:
### `plugin-toolbar`
- 新增导出范围选择器
- 新增自定义页数输入框
- 新增导出过程中的状态展示
### `market/index`
- 保留当前页导出逻辑作为单页模式
- 新增批量导出入口
- 管理任务状态、按钮禁用、进度回写
### 新建批量导出控制器
建议新增类似 `export-range-controller.ts` 的模块,职责包括:
- 读取当前页记录
- 控制翻页
- 等待页切换
- 聚合多页数据
- 统一返回最终 `MarketRecord[]`
这样可以避免把 `market/index.ts` 继续堆大。
### `dom-sync` 或新辅助模块
- 提供读取当前页签名
- 提供定位下一页按钮
- 提供判断下一页是否可点击
## 测试策略
### 单元测试
- 默认导出范围为前 5 页
- 选择 `当前页` 时只导出一页
- 选择 `前10页` 时最多导出 10 页
- `自定义` 输入非法值时不启动导出
- `全部` 模式在没有下一页时停止
- 多页合并时按 `authorId` 去重
- 空字段不会覆盖已有非空字段
### 集成测试
- 批量导出时会依次点击下一页
- 翻页后等待新页签名再采集
- 每一页在导出前都会执行滚动采集
- 中途某页失败时不生成 CSV
- 导出期间工具栏控件被禁用
## 风险
- 星图分页 DOM 结构可能不稳定,下一页按钮定位需要做降级兼容。
- 全部导出在高页数场景下耗时会较长。
- 页面中途刷新或筛选重算可能打断批量任务。
## 推荐实施顺序
1. 工具栏新增范围选择与自定义输入
2. 抽出批量导出控制器
3. 实现前 N 页导出
4. 在前 N 页能力稳定后开放 `全部`
5. 补齐全部相关失败与超时测试
## 决策结论
采用“一个导出按钮 + 范围选择器”的方案,默认导出前 `5` 页,支持 `全部``自定义`。批量模式通过真实翻页逐页采集当前筛选结果,不把多页扫描重新引入到筛选和排序链路中。