- Video detail (done videos): added 'Download audio' button; removed the
manual 'Thumbnail' button (thumbnails auto-download now, so it was redundant).
- New 'GET /api/videos/{id}/audio' endpoint (also serves HEAD for probing),
serving data/audio/<video_id>.mp3. Audio job outtmpl switched to %(id)s so
files are addressable per video.
- Integrated <audio> player appears in the detail view once the MP3 is present
(probed via HEAD on openVideo; polled after a download job until ready).
- Synced transcript follower: as audio plays, the matching segment is
highlighted (seg-active) and auto-scrolled into view like a karaoke/lyrics
tracker. Clicking any segment timestamp or chapter seeks the audio to that
point (falls back to scroll when no audio). Playback indicator pulses while
playing.
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.