# 视频号（weixin_video）同步作品逻辑说明

## 一、整体流程

```
作品管理「同步作品」 / 任务队列 sync_works
    → WorkService.syncWorks(userId, accountId?, platform?)
    → 按账号筛选后，对每个账号调用 HeadlessBrowserService.fetchAccountInfo(platform, cookies, ...)
    → 若平台在 supportedPlatforms 内（含 weixin_video），优先用 Python 拉作品
    → fetchWorksViaPython('weixin_video', cookies, onProgress)
    → 请求 Python 服务 POST /works，platform 映射为 'weixin'
    → Python platforms/weixin.py WeixinPublisher.get_works(cookies, page, page_size)
    → 返回 works + total + has_more，Node 据此分页循环
    → 拿到全量 works 后，再调 fetchAccountInfoWithPlaywright 补账号信息（头像、粉丝等）
    → WorkService 用返回的 works 与 DB 做比对：新增/更新/删除本地作品
```

## 二、Node 端（HeadlessBrowserService）

- **平台映射**：`weixin_video` → 请求 Python 时用 `platform: 'weixin'`（`pythonPlatform = platform === 'weixin_video' ? 'weixin' : platform`）。
- **分页方式**：视频号**不用**游标分页，用**页码**：
  - `useCursorPagination = platform === 'xiaohongshu' || platform === 'douyin'` → 视频号为 false。
  - 因此 `pageParam = pageIndex`（0, 1, 2, ...），每次请求带 `page`、`page_size`。
- **每页条数**：非小红书/非抖音统一 `pageSize = 50`。
- **停止条件**：`!result.has_more || pageWorks.length === 0 || newCount === 0` 时结束循环。

## 三、Python 端（platforms/weixin.py）

- **入口**：`get_works(cookies, page=0, page_size=20)`，由 `run_get_works` 调用（app.py 的 /works 路由传 page、page_size）。
- **当前实现要点**：
  1. 打开固定页面：`https://channels.weixin.qq.com/platform/post/list`，等待 `div.post-feed-item`。
  2. 用 `self.page.locator('div.post-feed-item')` 取当前 DOM 下所有作品项，`item_count = await post_items.count()`。
  3. 只遍历前 `min(item_count, page_size)` 条，解析封面、标题、时间、播放/点赞/评论/分享/收藏等。
  4. **未使用参数 `page`**：没有根据 page 做滚动、点击「加载更多」或请求下一页接口，每次请求都是同一页 DOM。
  5. 返回值：
     - `total = len(works)`（当前批数量，非平台总作品数）；
     - `has_more = item_count > page_size`（仅表示当前屏 DOM 条数是否大于 page_size）。

## 四、存在的问题

1. **分页未实现**
   - Node 会按 `has_more` 继续请求 page=1, 2, …，但 Python 每次都是同一页、同一批 DOM，第二页起通常会返回重复数据，Node 端 `newCount === 0` 后停止。
   - 实际效果：**只能拿到首屏/首批作品**（约几十条），列表若为虚拟滚动，首屏 DOM 条数有限，总数会更少。

2. **work_id 不稳定**
   - 使用 `work_id = f"weixin_{i}_{hash(title)}_{hash(publish_time)}"`，同一作品在不同批次或重试中可能 i 不同，且 hash 可能碰撞；若页面有唯一 ID（如接口或 data 属性），应用真实 ID 更稳妥。

3. **total / has_more 含义与 Node 预期不一致**
   - Node 用 `declaredTotal`、`has_more` 决定是否继续请求；Python 的 `total` 只是本批条数，`has_more` 只反映当前屏是否多于 page_size，不能代表「平台是否还有更多作品」。

4. **调试代码未清理**
   - 存在 `print("1111111111111111")` 等调试输出，以及大段 DOM 打印，建议移除或改为可配置日志。

## 五、改进方向建议

1. **实现真实分页**
   - 若视频号创作者后台有「加载更多」或滚动加载：在 `get_works` 里根据 `page` 做多次滚动或点击，再采集当前屏新增的 `div.post-feed-item`，并去重。
   - 若有列表接口（如类似抖音 work_list）：改为请求接口并解析 cursor/offset 分页，返回 `next_page` 供 Node 按游标请求（需同步改 Node 对 weixin_video 的分页策略）。
2. **使用稳定作品 ID**
   - 从 DOM 或接口中取作品唯一 ID（若有），作为 `work_id`，便于去重与和本地库一致对应。
3. **清理调试并规范日志**
   - 去掉无意义 print，DOM 打印改为 debug 级别或环境变量控制。

---

文档基于当前代码整理，若 weixin.py 或 HeadlessBrowserService 有改动，以实际代码为准。
