--- name: using-yt-tools version: 0.2.0 description: Two flows for accessing YouTube content. **Iterative-watch** (для «что в этом ролике / о чём ролик / video summary»): markdown transcript with [mm:ss] anchors → pick moments → extract frames as JPGs → Read them. **Targeted-frames** (для «покажи кадр на N / посмотри момент N / что показано на N»): extract specific frames at user-given timestamps, no transcript. Also triggers on "транскрипт видео", "расшифровка YouTube", "youtube transcript", "watch this video", or any youtube.com URL WebFetch can't reach. Wraps yt-dlp + youtube-transcript-api + PySceneDetect + ffmpeg via CLI in `~/projects/.common/lib/yt-tools/`. Skip for non-YouTube (Vimeo/Twitch/local mp4), audio podcasts (no STT here), pure-download workflows (use yt-dlp directly). --- # 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 entry-points на PATH (из `pip install -e ~/projects/.common/lib/yt-tools/` внутри venv): - `yt-transcript`, `yt-frames`, `yt-watch`, `yt-tools` Внешние бинари (любая ОС): - `yt-dlp` — fetches metadata + source mp4 - `ffmpeg` — muxes streams + extracts frames Если что-то отсутствует, CLI выдаёт явное `"X not found on PATH"`. Скажи юзеру и стоп. Полный 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 + comma-separated `mm:ss` / `h:mm:ss` / bare seconds | `--no-cache-source` (stream вместо кеша source.mp4); `--out DIR` | Оба flow пишут в `/yt-cache//` по умолчанию. ## Steps ### Flow A — iterative-watch ``` 1. yt-transcript → ./yt-cache//transcript.md 2. Read transcript.md, find [mm:ss] anchors that match the question 3. yt-frames --timestamps 1:23,4:56,… → ./yt-cache//frames/frame_*.jpg 4. Read each frame_*.jpg via the vision tool 5. Answer the user, citing both transcript paragraph and frame contents ``` Last line каждого CLI's stdout — absolute path артефакта. Не парси текст вокруг, бери конец stdout. ### Flow B — targeted-frames ``` 1. Parse user's timestamps (mm:ss / h:mm:ss / bare seconds — все работают) 2. yt-frames --timestamps 1:23,4:56,… → ./yt-cache//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 | Выведи 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 под `/yt-cache//`: - `transcript.md` (Flow A) - `source.mp4` (≤720p, оба flow если без `--no-cache-source`) - `frames/frame_.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-минутный ролик; кеш переиспользуется между запусками 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 напрямую). - **Не пиши результаты в произвольные пути.** По умолчанию `/yt-cache//`; явный `--out` только если юзер просил.