Prerequisites: explicit table with two options (activate venv vs full-path). Steps: added step 0 (venv activation) to both Flow A and Flow B. Acceptance: agent can now invoke CLI without "command not found" error. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
124 lines
9.9 KiB
Markdown
124 lines
9.9 KiB
Markdown
---
|
||
name: using-yt-tools
|
||
version: 0.2.3
|
||
description: Two flows for YouTube content. **Iterative-watch** (summary/exploration): transcript with [mm:ss] anchors → pick moments → extract frames. **Targeted-frames** (specific timestamps): extract frames directly, no transcript. Triggers: "что в ролике", "о чём видео", "video summary", "youtube transcript", "покажи кадр на N", или любой youtube.com URL. CLI в `~/projects/.common/lib/yt-tools/`. YouTube-only; для Vimeo/Twitch/local — другие тулзы.
|
||
---
|
||
|
||
# using-yt-tools
|
||
|
||
Iterative-watching YouTube для агента: clean-markdown транскрипт с `[mm:ss]`-якорями → агент решает, какие моменты интересны → targeted frame extraction по таймкодам → агент видит кадры через `Read`. Альтернативный flow — если юзер уже назвал таймкоды, идём прямо за кадрами без транскрипта.
|
||
|
||
## When to use
|
||
|
||
Два различных flow, выбор по user intent:
|
||
|
||
**Flow A — iterative-watch** (exploration / summary):
|
||
- Юзер спрашивает что в ролике, хочет summary, хочет узнать о чём видео.
|
||
- Шаги: fetch transcript → read → pick interesting moments → extract those frames → Read frames.
|
||
- Trigger phrases: «что в этом ролике», «о чём ролик», «расшифровка YouTube», «video summary», «youtube transcript», «watch this video».
|
||
|
||
**Flow B — targeted-frames** (specific moments):
|
||
- Юзер уже назвал конкретные таймкоды; транскрипт — лишняя работа.
|
||
- Шаги: extract frames at given timestamps → Read frames.
|
||
- Trigger phrases: «покажи кадр на N», «посмотри момент N», «что показано на N», «show frame at N».
|
||
|
||
Оба flow предполагают, что `yt-tools` CLI установлен из `~/projects/.common/lib/yt-tools/`. Если `yt-transcript` / `yt-frames` отсутствуют на PATH — abort с install-hint (см. Prerequisites).
|
||
|
||
## Prerequisites
|
||
|
||
**CLI invocation** — один из двух вариантов (выбери по ситуации):
|
||
|
||
| Вариант | Команда | Trade-off |
|
||
|---|---|---|
|
||
| **A. Активация venv** | Windows: `& ~/projects/.common/lib/yt-tools/.venv/Scripts/Activate.ps1`<br>Linux/macOS: `source ~/projects/.common/lib/yt-tools/.venv/bin/activate` | Одна команда, но меняет shell state |
|
||
| **B. Full-path** | `~/projects/.common/lib/yt-tools/.venv/Scripts/yt-frames.exe URL ...` (Windows)<br>`~/projects/.common/lib/yt-tools/.venv/bin/yt-frames URL ...` (Linux/macOS) | Изолированно, но длиннее в каждом вызове |
|
||
|
||
После активации или full-path доступны:
|
||
- `yt-transcript`, `yt-frames`, `yt-watch`, `yt-tools`
|
||
|
||
**Внешние бинари** (любая ОС):
|
||
- `yt-dlp` — fetches metadata + source mp4
|
||
- `ffmpeg` — muxes streams + extracts frames
|
||
|
||
Полный install per-OS — в `~/projects/.common/lib/yt-tools/README.md`. **Windows-gotcha:** после `winget install Gyan.FFmpeg` или `winget install yt-dlp.yt-dlp` нужен restart терминала (и Claude Code session) — winget пишет в per-user PATH, который текущий shell не перечитывает.
|
||
|
||
## Inputs
|
||
|
||
| Flow | Required | Optional |
|
||
|---|---|---|
|
||
| A — iterative-watch | YouTube URL или bare 11-char video id | `--lang ru,en` для non-English subs; `--out PATH` |
|
||
| B — targeted-frames | YouTube URL + timestamps (`mm:ss`, `h:mm:ss`, или bare seconds: `123` → 2:03) | `--no-cache-source` (stream вместо кеша source.mp4); `--out DIR` |
|
||
|
||
Оба flow пишут в `<cwd>/yt-cache/<video-id>/` по умолчанию.
|
||
|
||
## Steps
|
||
|
||
### Flow A — iterative-watch
|
||
|
||
```
|
||
0. Activate venv: & ~/projects/.common/lib/yt-tools/.venv/Scripts/Activate.ps1 (Windows) или source ~/projects/.common/lib/yt-tools/.venv/bin/activate (Linux/macOS)
|
||
1. yt-transcript <url> → ./yt-cache/<vid>/transcript.md
|
||
2. Read transcript.md, find [mm:ss] anchors that match the question
|
||
3. yt-frames <url> --timestamps 1:23,4:56,… → ./yt-cache/<vid>/frames/frame_*.jpg
|
||
4. Read each frame_*.jpg via the vision tool
|
||
5. Answer the user, citing both transcript paragraph and frame contents
|
||
```
|
||
|
||
Альтернатива: skip шаг 0, используй full-path в каждом вызове (см. Prerequisites).
|
||
|
||
**Stdout contract per CLI** (бери последнюю строку, формат зависит от CLI):
|
||
|
||
- `yt-transcript`, `yt-watch` — одна строка на stdout: bare absolute path артефакта (`<abs>/transcript.md` или `<abs>/watch.md`).
|
||
- `yt-frames` — **N строк** формата `Wrote: <abs path>`, одна на каждый извлечённый кадр. Strip префикс `"Wrote: "` чтобы получить путь. Дизайн осознан: per-line output чтобы caller'ы пайпили / скрейпили без парсинга summary в конце.
|
||
|
||
Warnings и errors уходят в stderr (`warning: …`, `error: …`); stdout остаётся машинно-парсимым.
|
||
|
||
### Flow B — targeted-frames
|
||
|
||
```
|
||
0. Activate venv: & ~/projects/.common/lib/yt-tools/.venv/Scripts/Activate.ps1 (Windows) или source ~/projects/.common/lib/yt-tools/.venv/bin/activate (Linux/macOS)
|
||
1. Parse user's timestamps (mm:ss / h:mm:ss / bare seconds — все работают)
|
||
2. yt-frames <url> --timestamps 1:23,4:56,… → ./yt-cache/<vid>/frames/frame_*.jpg
|
||
3. Read each frame_*.jpg
|
||
4. Answer the user, referencing each frame by its [mm:ss] label
|
||
```
|
||
|
||
Без transcript fetch. Если потом юзер спросит «что говорилось в тот момент?», переключайся на Flow A на том же URL — `source.mp4` cache переиспользуется, повторного download нет.
|
||
|
||
## Failure modes
|
||
|
||
Все failures abort cleanly; никогда не оставляй наполовину готовое состояние.
|
||
|
||
| Symptom | Cause | Action |
|
||
|---|---|---|
|
||
| `yt-transcript` / `yt-frames` not on PATH | yt-tools pkg не pip-installed | Скажи юзеру install per `~/projects/.common/lib/yt-tools/README.md`; стоп |
|
||
| `yt-dlp not found on PATH` | Внешний бин отсутствует | Дай install command для ОС юзера; стоп |
|
||
| `ffmpeg not found on PATH` | Внешний бин отсутствует | То же; на Windows после `winget install Gyan.FFmpeg` юзер должен restart терминала + CC session |
|
||
| `yt-dlp source download failed (exit N) \| stderr: …` | Network / private / age-gated / region-locked / malformed URL | Выведи captured stderr verbatim; не retry |
|
||
| `yt-dlp --dump-json failed` | То же, но на metadata step | То же |
|
||
| `Subtitles disabled` от `youtube-transcript-api` | Канал отключил CC | Для Flow A это fatal — скажи юзеру, предложи Flow B с явными таймкодами если уместно |
|
||
| Юзер дал не-YouTube URL (Vimeo / Twitch / local mp4) | Out of scope | Стоп; скажи что скил YouTube-only |
|
||
|
||
## Side effects
|
||
|
||
- Writes под `<cwd>/yt-cache/<video-id>/`:
|
||
- `transcript.md` (Flow A)
|
||
- `source.mp4` (≤720p, оба flow если без `--no-cache-source`)
|
||
- `frames/frame_<mmss>.jpg` per extracted frame
|
||
- Network: yt-dlp вытягивает metadata + опционально source.mp4; `youtube-transcript-api` вытягивает subs
|
||
- Никакого внешнего state не мутируется — чисто local-fs side effects
|
||
- `source.mp4` может быть ~50-200 MB на 720p / 10-минутный ролик; кеш переиспользуется между запусками. **Warning:** cumulative — 20 роликов = 1-4 GB на диске.
|
||
|
||
Cache hygiene: `yt-tools cache list` показывает usage, `yt-tools cache prune --older-than 7d` чистит.
|
||
|
||
## What NOT to do
|
||
|
||
- **Не запускай Flow A когда юзер уже дал таймкоды.** «Посмотри 1:23 и 4:56» → сразу Flow B. Fetching transcript first — чистая трата.
|
||
- **Не bulk-extract «на всякий случай».** Flow A берёт кадры из транскрипта, Flow B — из явного user input. Никогда `--mode interval --interval 5s` «to be safe».
|
||
- **Не используй `yt-watch` как default Flow A renderer.** `yt-watch` комбинирует transcript + scene-frames в один doc — тяжелее (требует ffmpeg scene-detect pass на source.mp4). Бери только когда юзер хочет один self-contained document.
|
||
- **Не shell-quote URLs в одну command строку.** Используй CLI list-form (он уже list-form в `subprocess.run`); YouTube URLs содержат `?` и `&`, которые ломают naive quoting.
|
||
- **Не retry на yt-dlp failures.** Failure здесь значит видео реально недоступно (private / region / age) или у юзера broken auth. Retries — трата токенов.
|
||
- **Не пересказывай / не переводи transcript в свой ответ молча.** Артефакт — для твоего reasoning; цитируй с `[mm:ss]`-якорем когда приводишь пассаж.
|
||
- **Не вызывай скил на non-YouTube URL.** Vimeo / Twitch / TikTok / local mp4 — out of scope. Бери другие тулзы (или yt-dlp напрямую).
|
||
- **Не пиши результаты в произвольные пути.** По умолчанию `<cwd>/yt-cache/<vid>/`; явный `--out` только если юзер просил.
|