Files
yt-channel-scraper/README.md
T
urieljareth 621bbc5f5c feat: local content-mining platform for YouTube creator scraping
Scraper de canales de YouTube hacia notas Markdown para base de conocimiento
(Obsidian-ready), con plataforma web local.

Engine + CLI (Workstream A):
- Modular pipeline: discover/extract/parse/chapters/render/store + ratelimit
- SQLite store con migración idempotente: FTS5 (transcript search), columnas
  de metadata enriquecida, tablas cookies_meta y scrape_jobs
- Módulos: segments, cookies (Netscape vault), export (json/csv/srt/html),
  analysis (word freq/timeline/wordcloud), monitor (watch loop), pipeline
- CLI Click group: search, export, audio, channels, watch, analyze, re-render
- Fix del bug de scoping de cookies en cli.py

Webapp local (Workstream B):
- FastAPI backend: dashboard, channels, videos facetado, transcript, search
  FTS, analysis, scrape jobs con SSE, cookies drag-and-drop, exports,
  folders (abrir en OS), tools (re-render, formato)
- SPA no-build (Alpine.js + Tailwind + Chart.js por CDN): 9 vistas, tema
  dark command-center con acento rojo→rosa, cookie vault drag-drop,
  consola de scrapeo con progreso live vía SSE

Launcher + subagentes (Workstream C):
- start-server.bat / stop-server.bat con auto port-scan + browser open
- .opencode/agent/webapp-builder.md + .opencode/goals/webapp-build.md

Tests: 38 pytest verdes. Sin funcionalidad de IA (enfoque data-mining).
2026-07-26 23:19:34 -06:00

4.3 KiB

yt-channel-scraper

Scraper de canales de YouTube que extrae transcripciones, capítulos y metadatos completos, generando notas Markdown listas para Obsidian.

Basado en la ingeniería inversa de Obsidian Web Clipper — usa yt-dlp internamente, que implementa el mismo mecanismo InnerTube (youtubei/v1/player con clientes ANDROID/IOS/WEB) que la extensión audita.

Instalación

cd yt-channel-scraper
pip install -e ".[dev]"

Requiere Python ≥ 3.10.

Uso

Scrape completo de un canal

yt-scraper --channel "https://www.youtube.com/@Nostal-Vlad/videos"

Dry run (ver qué descubriría sin descargar)

yt-scraper --channel "https://www.youtube.com/@Nostal-Vlad/videos" --dry-run --limit 10

Solo vídeos recientes

yt-scraper --channel "https://www.youtube.com/@Nostal-Vlad/videos" --since 2025-01-01

Reanudar tras interrupción

yt-scraper --channel "https://www.youtube.com/@Nostal-Vlad/videos"

El estado se guarda en data/state.db (SQLite). Los vídeos ya procesados se saltan automáticamente.

Reintentar vídeos con error

yt-scraper --channel "https://www.youtube.com/@Nostal-Vlad/videos" --reset-errors

Opciones

Flag Descripción Default
--channel, -c URL del canal de config.yaml
--config Ruta al YAML de configuración config.yaml
--limit N Procesar solo N vídeos sin límite
--since DATE Solo vídeos desde YYYY-MM-DD sin filtro
--languages, -l Idiomas preferidos (coma-sep) es,en
--no-auto Ignorar subtítulos auto-generados false
--no-shorts Excluir Shorts de config
--include-shorts Incluir Shorts de config
--resume/--no-resume Saltar procesados --resume
--dry-run Solo discovery, no descargar false
--reset-errors Reintentar vídeos con error false
--verbose, -v Logging DEBUG false

Configuración

Copia config.example.yaml a config.yaml y edita:

channel_url: "https://www.youtube.com/@Nostal-Vlad/videos"
languages: ["es", "es-419", "en"]
prefer_manual: true
include_shorts: false
min_duration_sec: 30

delay:
  min_seconds: 1.5
  max_seconds: 3.5

Output

Cada vídeo genera un archivo Markdown en data/markdown/@canal/:

data/markdown/Nostal Vlad/
├── 2026-07-26_asi-era-ser-una-adolescente-edgy-en-los-2000.md
├── 2026-07-12_la-estetica-que-romantiza-ser-un-perdedor-losercore.md
└── ...

Formato de cada nota:

---
video_id: gOUyxFwWQqA
title: "La Estética Que ROMANTIZA ser un \"PERDEDOR\" | Losercore"
channel: Nostal Vlad
upload_date: 2026-07-12
duration: 1069
url: https://www.youtube.com/watch?v=gOUyxFwWQqA
transcript_lang: es-orig
transcript_src: auto
views: 100523
likes: 8196
---

# La Estética Que ROMANTIZA ser un "PERDEDOR" | Losercore

> [Ver en YouTube](https://www.youtube.com/watch?v=gOUyxFwWQqA)

## Transcripcion

### Intro (00:15)

**00:15** · Una de las estéticas que ha cobrado más relevancia últimamente...
**00:28** · que hacer esto. Y es que el loser core como tal es muy difuso...

### Losercore (01:38)

**01:38** · ...

Estados en SQLite

Status Significado
pending Descubierto, sin procesar
done Transcripción extraída y Markdown generado
no_subtitles El vídeo no tiene subtítulos (ni manuales ni auto)
error Error al procesar (miembros-only, privado, bloqueo, etc.)

Arquitectura

cli.py          Orquestador (Click + Rich progress)
├── discover.py   yt-dlp --flat-playlist → lista de videoIds
├── store.py      SQLite: estado, resume, dedup
├── extract.py    yt-dlp.extract_info → metadata + subtítulos
├── parse.py      JSON3/VTT → segmentos {start, end, text}
├── chapters.py   align_chapters: capítulos ↔ segmentos
├── render.py     Jinja2 → Markdown con frontmatter YAML
└── ratelimit.py  delays aleatorios + backoff exponencial

Tests

python -m pytest tests/ -v

Mantenimiento

Si la extracción falla tras una actualización de YouTube:

yt-dlp -U          # actualizar yt-dlp
pip install -U yt-dlp

Las versiones de cliente InnerTube (ANDROID 20.10.x, IOS 20.10.x, WEB 2.2024xxxx) rotan mensualmente. yt-dlp las mantiene actualizadas.