# 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.