- 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
6.5 KiB
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):
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):
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.