Files
yt-channel-scraper/docs/CONFIG.md
T
urieljareth 450aee216d docs: documentacion completa para humanos y agentes IA
- README reescrito: ejemplos CLI corregidos (flags van en el subcomando scrape),
  webapp+doctor documentados, requisitos por OS, cookies, datos generados, migracion de maquina
- CLAUDE.md actualizado: conteo de tests, refs de linea reparadas, scripts nuevos,
  checklist de actualizacion de docs
- AGENTS.md nuevo: entrada estandar para cualquier agente de codigo (mapa de modulos,
  comandos, reglas de oro, punteros a docs)
- docs/GETTING-STARTED.md: de cero a webapp por OS con troubleshooting
- docs/CONFIG.md: referencia completa de las ~25 claves de config
- docs/COOKIES.md: adquisicion, import (web/navegador/CLI), rotacion y seguridad
- docs/backlog.md reemplaza OPPORTUNITIES.md (distilado: shipped vs pendiente)
- auditorias movidas a docs/audits/ y CLIPPER-COMPARISON-AUDIT.md versionado
2026-09-10 00:32:32 -06:00

111 lines
6.5 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.
# Referencia de configuración (`config.yaml`)
`config.yaml` es tu configuración privada (gitignored). La plantilla versionada `config.example.yaml` documenta todas las claves y es el punto de partida (`cp config.example.yaml config.yaml`). Todas las rutas del archivo se resuelven **relativas al CWD** — ejecuta siempre desde la raíz del repo.
Los defaults que siguen son los de `config.example.yaml` (entre paréntesis, cuando difiere, el default del código en `src/yt_scraper/config.py`).
## Bloque raíz — canal, idiomas y filtros
| Clave | Tipo | Default | Qué afecta |
|---|---|---|---|
| `channel_url` | str | `"https://www.youtube.com/@Nostal-Vlad/videos"` | Canal por defecto de `yt-scraper scrape` / webapp. Se ignora si pasas `--channel`/`-c`. Acepta URL completa, `/channel/UC...` o handle |
| `languages` | dict \| list | `{es: any, es-419: any, en: any}` | Idiomas de subtítulos aceptables y su modo (ver abajo). Forma legacy: lista `["es","en"]` — todos con el modo de `prefer_manual`; evítala, un canal solo-auto quedaría en `no_subtitles` |
| `prefer_manual` | bool | `true` | En modo `any`: prueba subtítulos manuales antes que los automáticos |
| `include_shorts` | bool | `false` | Descubrir/procesar Shorts. En CLI: `--include-shorts` / `--no-shorts` |
| `include_live` | bool | `true` | Procesar directos. En CLI: `--no-live` |
| `min_duration_sec` | int | `30` (código: `0`) | Duración mínima del vídeo en segundos; filtra en discovery |
Modos por idioma de `languages`:
| Valor | Significado |
|---|---|
| `manual` | **Solo** subtítulos subidos por el creador; si solo hay automáticos → `no_subtitles` |
| `auto` | **Solo** subtítulos automáticos (ASR) |
| `any` | Manuales primero (según `prefer_manual`), automáticos como fallback. **Recomendado** |
Nota: `languages` es una preferencia entre idiomas que sabes leer, no una orden de traducir. El idioma hablado del vídeo siempre gana si está en la lista; nunca se guarda una traducción automática si existe el transcript original.
## Bloque `delay` — pacing y rate-limit
YouTube no publica límites; el techo práctico conocido (wiki de yt-dlp) es ~300 vídeos/hora en sesión sin cuenta. Estos valores apuntan por debajo. Con los defaults conservadores, una tirada real cuesta **del orden de 12–13 s por vídeo** (~270 vídeos/hora).
| Clave | Tipo | Default | Qué afecta |
|---|---|---|---|
| `min_seconds` | float | `1.5` | Pausa aleatoria mínima entre vídeos (el gap real se sortea entre `min` y `max`) |
| `max_seconds` | float | `3.5` | Pausa aleatoria máxima entre vídeos |
| `backoff_base` | float | `2.0` | Backoff tras un rate-limit: `min(base * 2**n + jitter, cap)`, con n = fallos consecutivos |
| `backoff_cap` | float | `60.0` | Techo del backoff en segundos |
| `throttle_threshold` | int | `3` | Rate-limits **consecutivos** que hacen parar la tirada (circuit breaker). Lo no procesado queda `pending` y es recuperable |
| `min_request_interval` | float | `0.0` (example) | Separación mínima entre **cualquier** dos peticiones a YouTube del proceso (Pacer global, incluye los `/api/tools/*` fuera del job runner). `0` = desactivado. Es la única palanca que actúa en todas partes a la vez |
| `audio_rate_limit` | int | `0` | Techo de bytes/segundo para descargas de audio (ratelimit de yt-dlp). `0` = ilimitado |
Referencia práctica: la config real del autor usa `min_request_interval: 2.5` para ser aún más conservador cuando la webapp y el CLI conviven.
## Bloque `yt_dlp` — reintentos y timeouts
| Clave | Tipo | Default | Qué afecta |
|---|---|---|---|
| `retries` | int | `10` | Reintentos de descarga; solo muerde en el camino de audio (el extractor de YouTube de yt-dlp no reintenta 403/429) |
| `sleep_subrequests` | float | `2` | Segundos entre las peticiones HTTP **dentro** de una extracción (watch page, llamada player, continuations). Se reenvía a yt-dlp como `sleep_interval_requests` (nombre interno del proyecto; el yt-dlp no tiene ninguna opción llamada `sleep_subrequests`) |
| `extractor_retries` | int | `3` | Reintentos durante la extracción (solo 5xx y red) |
| `socket_timeout` | float | `30.0` | Timeout de socket; sin él una conexión colgada bloquea el worker para siempre |
## Bloque `sync` — discovery incremental
Re-escanear un canal trackeado lee la pestaña `/videos` (cronológica inversa) y corta al ver `overlap` vídeos ya conocidos: un sync rutinario cuesta 1 página, no el canal entero.
| Clave | Tipo | Default | Qué afecta |
|---|---|---|---|
| `incremental` | bool | `true` | Activar el modo ventana. `false` (o `--full` / "Full rescan" en la webapp) recorre todo el canal |
| `window` | int | `30` | Entradas leídas en la primera pasada |
| `max_window` | int | `300` | Techo: si TODA la ventana resulta nueva, se duplica hasta aquí antes de declarar el scan truncado (aviso "usa `--full`") |
| `overlap` | int | `3` | Vídeos conocidos consecutivos que dan la sincronización por alcanzada |
## Rutas y plantillas
| Clave | Tipo | Default | Qué afecta |
|---|---|---|---|
| `database_path` | str | `"data/state.db"` | Ruta de la BD SQLite (WAL). Relativa al CWD |
| `output_dir` | str | `"data/markdown"` | Directorio de notas; el resto de datos (`audio/`, `thumbnails/`, ...) se deriva de su padre |
| `template_path` | str | `"templates/video.md.j2"` | Plantilla Jinja2 de la nota. OJO: el formato del `.md` es un contrato bidireccional (los regex de `segments.py` lo re-lean) |
| `filename_template` | str | `"{upload_date}_{slug}"` | Patrón del nombre de las notas. Placeholders: `{upload_date}` (fecha de subida; `unknown-date` si se desconoce), `{slug}` (slug del título, máx 60), `{title}` (título crudo), `{video_id}` (id estable de YouTube — útil porque título y fecha son inestables) |
## Ejemplos
**Mínima** (defaults razonables, primer contacto):
```yaml
channel_url: "https://www.youtube.com/@MiCanal/videos"
languages:
es: any
```
**Conservadora** (muchos vídeos, webapp y CLI a la vez, o historial de rate-limits):
```yaml
channel_url: "https://www.youtube.com/@MiCanal/videos"
languages:
es: any
es-419: any
en: any
prefer_manual: true
include_shorts: false
min_duration_sec: 30
delay:
min_seconds: 1.5
max_seconds: 3.5
backoff_base: 2.0
backoff_cap: 60.0
throttle_threshold: 3
min_request_interval: 2.5 # pacer global: la palanca más eficaz contra el bot-wall
sync:
incremental: true
window: 30
max_window: 300
overlap: 3
```
Si cambias los tiempos, vuelve a medir sobre tu canal: la constante es ~3 peticiones a `youtube.com` por vídeo y de ahí sale todo lo demás.