# sora_video_tool

Package chính của **dsora-gen**: quản lý Chrome profiles, automation Sora, giao tiếp API và CLI.

---

## Cấu trúc

```
sora_video_tool/
├── cli/                    # CLI (dsg)
│   ├── __init__.py         # Entry: main group, đăng ký lệnh
│   ├── common.py           # Hằng, echo, image_src, ensure_playwright_browsers
│   ├── setup.py            # Lệnh setup
│   ├── run.py              # Lệnh run (mỗi profile claim SP từ API)
│   └── commands.py        # Lệnh check, open, update, help
├── config.py               # Load/save settings (~/.sora-tool/settings.json)
├── constants.py            # APP_DATA_DIR, API_BASE_URL, PRODUCTS_PER_PROFILE, ...
├── profile_manager.py      # Thư mục Chrome profile (~/.sora-tool/profiles/)
├── browser_launcher.py    # Launch Chrome (login / automation với CDP)
├── sora_bot.py             # Logic automation: fill_prompt, upload_image, click_create
├── api_client.py           # get_pending_products, mark_product_done
├── telegram_notifier.py    # Thông báo Telegram
└── run_tracker.py          # Lịch sử chạy (run_log)
```

Entry point: `dsg = "sora_video_tool.cli:main"` (trong `pyproject.toml`).

---

## Luồng chạy

1. **cmd_run** mở ThreadPoolExecutor, mỗi profile chạy `_process_profile`.
2. Mỗi profile: gọi `get_pending_products`, lọc bỏ SP đã nằm trong `claimed` (lock), lấy 1 SP → add vào `claimed` → mở Chrome, xử lý (fill_prompt, upload_image, configure_settings, click_create) → mark_product_done, notify → chờ N phút → lặp (tối đa PRODUCTS_PER_PROFILE).
3. **Claim** tránh trùng: nhiều profile cùng lúc chỉ cần không claim trùng id là được.
4. Nếu **VideoGenLimitReachedError** (tooltip "out of video gens"): notify, đóng Chrome profile đó, `break`; các profile khác tiếp tục lấy SP từ API.

---

## Development

```bash
# Từ repo (không cài package)
uv run dsg --help
uv run dsg check
```
