# Douyin Login Entry Design

## Goal

将当前“手动先开浏览器登录，再让 `Douyin.py` 附着到调试端口抓取”的隐式流程，固化为稳定、明确、可复用的两步式命令行入口。

## Current Context

- 现有抓取实现位于 `Douyin.py`。
- `Douyin.py` 已支持通过 `--browser-port` 附着到已启动的 Chrome 调试端口。
- 本次实测已经证明：用户先在可见 Chrome 中登录抖音并通过验证码后，`Douyin.py --browser-port 9223` 可以成功抓到 `web/aweme/post/` 接口并下载视频。
- 当前缺少一个明确的“登录准备入口”，导致可操作性依赖人工记忆和临时命令。

## Requirements

### Functional

1. 提供一个独立脚本，用于启动可见 Chrome，并固定：
   - 调试端口，默认 `9223`
   - 用户数据目录，默认使用一个项目约定路径
   - 打开的初始 URL，默认指向现有抖音博主页
2. 登录脚本只负责“打开浏览器并提示用户手动登录”，不负责抓取。
3. `Douyin.py` 继续负责抓取，并保持“附着已有浏览器”的职责边界。
4. 当 `Douyin.py` 指定了 `--browser-port` 但端口不可连通时，应给出清晰错误，提示先运行登录脚本。
5. 文档应给出最短可执行流程：
   - 第一步：启动浏览器并登录
   - 第二步：运行抓取命令

### Non-Functional

1. 不改变现有抓包、解析、下载的主逻辑。
2. 保持现有命令参数兼容。
3. 入口职责清晰，便于排查“登录问题”和“抓取问题”。
4. 新增行为应具备可自动化测试的核心单元。

## Chosen Approach

采用双脚本方案：

- 新增 `login_douyin.py`
  - 负责启动可见 Chrome
  - 固定 remote debugging port
  - 固定 profile 目录
  - 打开目标用户主页
  - 输出明确提示，引导用户完成手动登录和验证码
- 保留 `Douyin.py`
  - 继续承担附着浏览器、监听接口、下载视频的职责
  - 增强附着前检查与报错信息

## Rejected Alternatives

### Alternative 1: 将“启动浏览器”直接并入 `Douyin.py`

不采用。原因：

- 会让 `Douyin.py` 同时承担登录准备和抓取职责。
- 错误定位会变差，用户更难区分是登录失败还是抓取失败。
- 未来若需要“先登录、稍后再抓”，这种合并入口不灵活。

### Alternative 2: 只写 shell 脚本串联所有步骤

不采用。原因：

- 逻辑容易散落在 shell 中，测试性差。
- 浏览器启动参数、等待逻辑和抓取命令耦合度高。
- 后续若要扩展默认参数或跨平台兼容，shell 方案维护成本更高。

## Proposed CLI UX

### Step 1: 启动登录浏览器

```bash
./.venv/bin/python login_douyin.py
```

默认行为：

- 启动可见 Chrome
- 调试端口为 `9223`
- profile 目录为项目约定的本地路径
- 打开默认的抖音主页 URL
- 输出“请在浏览器中完成登录/验证码，然后再运行抓取命令”

可选扩展参数：

- `--browser-port`
- `--profile-dir`
- `--user-url`
- `--chrome-path`

### Step 2: 运行抓取

```bash
./.venv/bin/python Douyin.py --pages 1 --browser-port 9223
```

## Design Details

### `login_douyin.py`

建议拆分为可测试的小函数：

- `build_login_command(...)`
  - 输入 Chrome 路径、profile 目录、端口、URL
  - 输出适合 `subprocess.Popen(...)` 的参数列表
- `launch_browser(...)`
  - 调用 `subprocess.Popen(...)`
- `build_parser()`
  - 定义 CLI 参数
- `main()`
  - 解析参数
  - 启动浏览器
  - 打印下一步指引

### `Douyin.py`

新增一个显式的端口检查函数，例如：

- `ensure_browser_debug_port_ready(browser_port: int) -> None`

行为：

- 仅当用户传入 `--browser-port` 时执行
- 尝试连接 `127.0.0.1:<port>`
- 若失败，抛出清晰错误，提示：
  - 先启动 `login_douyin.py`
  - 确认 Chrome 仍在运行
  - 确认端口与抓取命令一致

## Error Handling

### 登录脚本

- Chrome 可执行文件不存在：直接报错并退出。
- 浏览器启动失败：输出异常原因并返回非零退出码。
- profile 目录不存在：自动创建。

### 抓取脚本

- 指定 `--browser-port` 但端口不可达：立即失败，不进入抓取流程。
- 登录未完成导致页面异常：保留现有抓包等待与警告逻辑。

## Testing Strategy

### Unit Tests

新增或扩展 `test_douyin.py`，覆盖：

1. `build_login_command()` 生成的命令参数正确。
2. 默认调试地址仍为 `127.0.0.1:<port>`。
3. `ensure_browser_debug_port_ready()` 在端口不可达时抛出可读错误。
4. `ensure_browser_debug_port_ready()` 在端口可达时正常返回。

如测试边界过大，可新增 `test_login_douyin.py`。

### Manual Verification

1. 运行 `./.venv/bin/python login_douyin.py`
2. 在打开的 Chrome 中登录抖音并通过验证码
3. 运行 `./.venv/bin/python Douyin.py --pages 1 --browser-port 9223`
4. 确认 `video/` 下生成新的 mp4 文件

## Implementation Boundaries

本次只做以下改动：

- 新增登录入口脚本
- 为抓取入口补充附着前端口检查
- 更新测试
- 更新使用文档

本次不做以下改动：

- 不重写抓取主流程
- 不改成单命令自动等待登录
- 不引入 Playwright 作为正式运行时依赖
- 不增加下载调度、断点续传或批量任务管理

## Risks

1. 本机 Chrome 路径可能与预设不同，因此需要保留 `--chrome-path` 覆盖能力。
2. profile 目录固定后，用户可能重复复用登录态，这是预期行为，但文档需说明。
3. 若目标端口被其他进程占用，登录脚本需要给出可诊断的失败信息或允许端口覆盖。

## Success Criteria

满足以下条件即视为完成：

1. 用户可以通过固定命令启动登录浏览器。
2. 用户登录完成后，可通过固定命令让 `Douyin.py` 成功附着并抓取。
3. 当浏览器未启动或端口错误时，抓取脚本会给出明确提示，而不是模糊失败。
