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

yt-channel-scraper

Scraper local de canales de YouTube: descubre los vídeos de cada canal con yt-dlp, extrae metadatos y transcripciones, guarda todo en SQLite (con búsqueda full-text) y genera una nota Markdown por vídeo, lista para un vault de Obsidian. Se maneja desde el CLI yt-scraper o desde una webapp local (FastAPI + Alpine) con gestión de canales, jobs en vivo, lector de transcripciones y vault de cookies.

100% local: sin API keys, sin deploy remoto, sin telemetría.

Arquitectura

              ┌───────────────────────────────────────────────┐
              │               webapp (FastAPI)                │
              │  canales · jobs SSE · lector · cookies · UI   │
              └───────────────────────┬───────────────────────┘
                                      │
 CLI (Click)                          ▼
 yt-scraper ──►  pipeline:  discover ─► extract ─► parse ─► store ─► render
                          (yt-dlp     (player +   (JSON3/   (SQLite   (Jinja2
                           flat)      subtítulos)  VTT)      + FTS5)   → .md)
                                                                        │
                                  data/state.db ◄───────────────────────┘
                                  data/markdown/<Canal>/<fecha>_<slug>.md
  • discover lista el canal (1 petición por página); extract baja metadatos + subtítulos (~2 peticiones por vídeo); parse convierte JSON3/VTT en segmentos; store persiste en SQLite con FTS5; render escribe el .md con frontmatter YAML.
  • CLI, webapp y watch son fachadas sobre el mismo pipeline: una feature se implementa una vez y se expone en ambas.

Requisitos

  • Python >= 3.10 (3.12 recomendado).
  • ffmpeg (opcional): solo para yt-scraper audio y el job de audio de la webapp.
  • Un runtime JS (node, deno o bun; opcional pero recomendado): yt-dlp lo usa para resolver los challenges de YouTube.
  • Plataforma: Windows, macOS (incl. Apple Silicon; todas las dependencias publican wheels arm64) o Linux.
Herramienta Windows (winget) macOS (brew) Debian/Ubuntu (apt)
Python 3.12 winget install Python.Python.3.12 brew install [email protected] sudo apt install python3 python3-venv
ffmpeg winget install Gyan.FFmpeg brew install ffmpeg sudo apt install ffmpeg
node winget install OpenJS.NodeJS.LTS brew install node sudo apt install nodejs

Instalación rápida

Ejecuta siempre los comandos desde la raíz del repo: las rutas de config.yaml (data/, templates/, la BD) se resuelven relativas al directorio de trabajo.

# Opción A: uv (recomendado, respeta uv.lock)
uv sync --all-extras

# Opción B: pip
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -e ".[dev,web,analysis]"

Extras: dev (pytest, pytest-cov, httpx), web (fastapi, uvicorn, sse-starlette, python-multipart), analysis (matplotlib, wordcloud).

Máquina nueva desde cero: docs/GETTING-STARTED.md (paso a paso por OS, con troubleshooting).

Arranque

Webapp

Windows — doble clic en start-server.bat:

  • La primera vez pasa por scripts/doctor.ps1, que prepara el entorno si falta (Python 3.12 vía winget + pip install -e ".[web]").
  • scripts/start-server.ps1 busca un puerto libre (8000–8100), arranca uvicorn, registra el proceso en .run/server.info (reutilizable), comprueba /healthz y abre el navegador.
  • Para parar: stop-server.bat (mata el proceso registrado y libera el puerto).

macOS / Linux:

make setup    # primera vez: scripts/bootstrap.sh (python/ffmpeg/node vía brew si faltan + deps)
make serve    # scripts/start-server.sh
make stop     # scripts/stop-server.sh
# O directamente, sin Makefile:
scripts/bootstrap.sh && scripts/start-server.sh

Manual (debug):

python -m uvicorn yt_scraper.webapp.app:app --host 127.0.0.1 --port 8000

CLI

El entry point es yt-scraper. OJO: sin subcomando ejecuta un scrape completo del canal de config.yaml. Los flags de scrape van en el subcomando:

yt-scraper scrape                       # scrape del canal de config.yaml (incremental)
yt-scraper -c "https://www.youtube.com/@Nostal-Vlad/videos" scrape   # otro canal sin tocar config

# Discovery sin descargar nada (ver qué encontraría)
yt-scraper scrape --dry-run --limit 10

# Solo vídeos desde una fecha / limitar la tirada
yt-scraper scrape --since 2025-01-01 --limit 5

# Reintentar vídeos en error/no_subtitles y continuar
yt-scraper scrape --reset-errors

# Recorrer el canal entero (ignora la ventana incremental)
yt-scraper scrape --full

Flags del grupo raíz (aplican a todo): --config, --channel/-c, --all-channels, --cookies, --cookies-from-browser, --verbose/-v.

Canales (multi-canal):

yt-scraper channels add "https://www.youtube.com/@Fazt"
yt-scraper channels list
yt-scraper channels remove "@Fazt"
yt-scraper --all-channels scrape        # aplica el subcomando a todos los canales

Búsqueda y export (sobre lo ya scrapeado, sin tocar la red):

yt-scraper search "vaporwave"                       # FTS5 en transcripciones, con timestamp
yt-scraper -c "@Fazt" search "typescript" -l 50
yt-scraper export --format json                     # json | csv | srt | html → data/exports/
yt-scraper --all-channels export --format srt

Recuperación (DB ↔ disco):

yt-scraper reset                        # error/no_subtitles → pending (pregunta antes)
yt-scraper reset --status error --yes
yt-scraper reconcile                    # re-escanea data/markdown y cuadra la DB con el disco
yt-scraper reconcile --prune            # además devuelve a pending los done sin .md
yt-scraper re-render                    # regenera .md desde segmentos guardados (0 descargas)
yt-scraper re-render --backfill         # antes importa segmentos desde los .md existentes

Audio, monitoreo y análisis:

yt-scraper audio --limit 5              # MP3 de los done (requiere ffmpeg) → data/audio/
yt-scraper watch --interval 6h          # discovery periódico y procesa lo nuevo
yt-scraper watch --once                 # una sola pasada
yt-scraper analyze --top-words 50       # frecuencia → data/analysis/top_words.{csv,png}
yt-scraper analyze --wordcloud          # + data/analysis/wordcloud.png
yt-scraper analyze --timeline "ia"      # menciones de un término por mes

Configuración

Copia la plantilla y edita:

cp config.example.yaml config.yaml      # Windows: copy config.example.yaml config.yaml

config.yaml es privado y está gitignored; la plantilla versionada (config.example.yaml) documenta todas las claves. Bloques principales:

Bloque Qué controla
raíz (channel_url, languages, include_shorts, ...) canal por defecto, idiomas de subtítulos (modo manual/auto/any por idioma), filtros de shorts/live/duración
delay pacing: pausas entre vídeos, backoff ante rate-limit, circuit breaker, intervalo mínimo global entre peticiones
yt_dlp reintentos, pausa entre sub-peticiones, timeouts de yt-dlp
sync discovery incremental: ventana inicial, máximo y solapamiento que da la sincronización por alcanzada
database_path, output_dir, template_path, filename_template rutas (relativas al CWD) y patrón del nombre de las notas

Referencia completa de cada clave con tipos y defaults: docs/CONFIG.md.

Cookies

Las cookies de sesión de YouTube (formato Netscape) sirven para acceder a vídeos de membresía y reducir los bot-checks. El vault (cookies/) admite varias, con exactamente una activa; se pueden importar:

  • Webapp: arrastrar y soltar un cookies.txt, o importar directamente desde el navegador local (Brave).
  • CLI: yt-scraper --cookies ruta/cookies.txt scrape o --cookies-from-browser brave (chrome|firefox|edge|brave).

Cómo exportarlas desde tu navegador y cómo rotarlas: docs/COOKIES.md. Son equivalentes a tu contraseña: nunca las commitees (están en .gitignore).

Datos generados

data/
├── state.db              # SQLite (WAL): vídeos, canales, segmentos, FTS5, jobs, cookies_meta
├── markdown/<Canal>/     # una nota .md por vídeo: <fecha>_<slug>.md con frontmatter YAML
├── thumbnails/<id>.jpg   # miniaturas
├── avatars/              # avatares de canal
├── audio/                # MP3 descargados (webapp: <video_id>.mp3; CLI: por título)
├── videos/<id>/          # descargas de vídeo completas (.webm)
├── exports/              # export json/csv/srt/html
└── analysis/             # wordcloud, top_words, timeline
cookies/                  # vault de cookies Netscape (gitignored, SENSIBLE)
.run/                     # estado del servidor (puerto, PID)

Estados de un vídeo en la BD: pending (descubierto, sin procesar), done (transcripción + .md), no_subtitles (sin pista válida según la política de idiomas), error (fallo: privado, bloqueo, ...).

data/, cookies/, config.yaml y .run/ están gitignored: contienen tu biblioteca y tu sesión. No los commitees.

Tests

uv run python -m pytest -q     # o: python -m pytest -q (dentro del venv)

Suite hermética (~240 tests en 24 archivos, sin red): todo con tmp_path + monkeypatch; yt_dlp.YoutubeDL se sustituye por un fake.

Migrar el repo a otra máquina

  • Las rutas se resuelven relativas al CWD: sigue ejecutando todo desde la raíz del repo.
  • Si mueves o clonas el repo, la instalación editable apunta a la ruta vieja: re-ejecuta uv sync --all-extras (o pip install -e ".[dev,web,analysis]") y recrea el venv si hace falta.
  • config.yaml y cookies/ no viajan en el clon: recréalos desde config.example.yaml y re-exporta las cookies.

Licencia

TBD.

S
Description
No description provided
Readme
1.1 MiB
Languages
Python 63.9%
HTML 15.5%
JavaScript 12.4%
PowerShell 3.1%
CSS 2.3%
Other 2.7%