- 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
111 lines
6.5 KiB
Markdown
111 lines
6.5 KiB
Markdown
# 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.
|