Files
claude-skills/skills/using-yt-tools/SKILL.md
vitya 4956beba5f feat(using-yt-tools): SKILL.md body fill (2 flows) [0.1.0 → 0.2.0]
Fill the v0.1.0 stub body. Description rewritten to document two distinct flows
(was iterative-only, even though triggers already listed targeted-frames phrases):

- Flow A — iterative-watch (transcript → pick anchors → frames): for "what's
  in this video / summary / о чём ролик / video summary / youtube transcript"
- Flow B — targeted-frames (frames only, no transcript): for "посмотри 1:23 /
  покажи кадр на N / что показано на N" — user already named timestamps,
  transcript fetch would be pure waste

Body sections filled (6): When/Prereq/Inputs/Steps/Failure/Side/NOT — Flow A
and Flow B distinguished throughout. Failure modes table covers missing CLI,
missing yt-dlp/ffmpeg (with Windows winget+PATH note), network/private/age-
gated, subs-disabled. What NOT to do explicitly forbids the "always-iterative"
trap that the v0.1.0 description implicitly invited.

Bump version 0.1.0 → 0.2.0 (MINOR — documents new capability set). Description
744 chars (under 900-char soft budget; well below ~1024 hard limit). Installed
to ~/.claude/skills/using-yt-tools/ via scripts/install.ps1 — harness skill-
listing renders full description, not truncated to H1.

STATUS.md: closes new [using-yt-tools-skill-body-fill] 🟢 (filed+closed
in-place since this is one body-fill task, not a multi-session workstream).
[using-yt-tools-review] stays 🔵 — body-fill blocker removed, but still
blocked on [using-yt-tools-trigger-smoke-clean-session] (needs fresh CC
session). Caveat recorded: body-fill was done by implementer instead of the
'fresh agent' the review-task originally specified — explicit user approval.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:39:40 +03:00

110 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 пишут в `<cwd>/yt-cache/<video-id>/` по умолчанию.
## Steps
### Flow A — iterative-watch
```
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
```
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 <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 | Выведи 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-минутный ролик; кеш переиспользуется между запусками
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` только если юзер просил.