urieljareth 06497299ab feat: integrated audio player + animated transcript follower
- 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.
2026-07-27 00:00:28 -06:00

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.

S
Description
No description provided
Readme
331 KiB
Languages
HTML 68.3%
Python 22%
JavaScript 6.6%
CSS 1.7%
PowerShell 0.8%
Other 0.6%