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).
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
# AUDIT · Oportunidades de extensión
|
||||
|
||||
> Análisis de features, comandos y opciones que se pueden construir sobre la infraestructura actual.
|
||||
> Cada item incluye: valor, esfuerzo estimado, dependencias y comando propuesto.
|
||||
|
||||
---
|
||||
|
||||
## Infraestructura disponible (lo que ya tenemos)
|
||||
|
||||
| Recurso | Estado | Reutilizable para |
|
||||
|---|---|---|
|
||||
| `yt-dlp` instalado | ✅ v2026.7.4 | Audio/video download, thumbnails, metadata enriquecida |
|
||||
| SQLite 3.49 con FTS5 | ✅ verificado | Búsqueda full-text sobre transcripciones |
|
||||
| SQLite JSON1 | ✅ verificado | Queries estructuradas sobre metadatos |
|
||||
| 33 transcripciones parseadas | ✅ en `data/state.db` | Análisis, estadísticas, búsqueda |
|
||||
| Markdown con frontmatter YAML | ✅ 842 KB en `data/markdown/` | Obsidian, Pandoc, static site generators |
|
||||
| Pipeline modular | ✅ 8 módulos | Insertar nuevos pasos sin romper nada |
|
||||
|
||||
---
|
||||
|
||||
## TIER 1 · Alto valor, bajo esfuerzo (1-3 h c/u)
|
||||
|
||||
### 1. `search` — Búsqueda full-text en transcripciones
|
||||
|
||||
```bash
|
||||
yt-scraper search "vaporwave"
|
||||
yt-scraper search "dragon ball" --channel UCmhcYyPg7fsxMzQsY0RJBjw
|
||||
```
|
||||
|
||||
**Qué hace:** busca texto dentro de las transcripciones ya scrapeadas y devuelve vídeo + timestamp exacto.
|
||||
|
||||
**Implementación:**
|
||||
- Nueva tabla `transcript_segments(video_id, start, text)` poblada durante el scrape
|
||||
- Índice `USING fts5(text)` sobre esa tabla
|
||||
- Comando `search` que hace `SELECT ... WHERE transcript_segments MATCH ?`
|
||||
- **Esfuerzo:** 1-2 h. Sin dependencias nuevas.
|
||||
|
||||
### 2. `stats` — Estadísticas del canal
|
||||
|
||||
```bash
|
||||
yt-scraper stats
|
||||
yt-scraper stats --channel UCmhcYyPg7fsxMzQsY0RJBjw
|
||||
```
|
||||
|
||||
**Qué muestra:**
|
||||
```
|
||||
Nostal Vlad (@Nostal-Vlad)
|
||||
Videos: 33 scrapeados / 37 totales
|
||||
Duración total: 11.2 horas
|
||||
Palabras totales: 89,432
|
||||
Fecha rango: 2019-04-28 → 2026-07-26
|
||||
Views promedio: 45,231
|
||||
Likes promedio: 3,201
|
||||
Top tags: videojuegos (12), 2000s (10), nostalgia (8)
|
||||
```
|
||||
|
||||
**Implementación:** queries SQL agregadas + presentación con Rich tables.
|
||||
- **Esfuerzo:** 1 h.
|
||||
|
||||
### 3. `export` — Export multi-formato
|
||||
|
||||
```bash
|
||||
yt-scraper export --format json # un JSON con todo
|
||||
yt-scraper export --format csv # CSV de metadatos
|
||||
yt-scraper export --format srt # subtítulos SRT estándar
|
||||
yt-scraper export --format html # galería navegable
|
||||
```
|
||||
|
||||
**Implementación:**
|
||||
- JSON: serializar `Store.get_all()` + leer transcripciones de los `.md`
|
||||
- CSV: `csv.writer` sobre metadatos
|
||||
- SRT: ya tenemos `{start, end, text}` en `Segment` — conversión trivial
|
||||
- HTML: plantilla Jinja2 con tarjetas por vídeo (thumbnail + título + link)
|
||||
- **Esfuerzo:** 2-3 h los 4 formatos.
|
||||
|
||||
### 4. `clip` — Extracción de segmento por timestamp
|
||||
|
||||
```bash
|
||||
yt-scraper clip gOUyxFwWQqA --from 01:38 --to 03:20
|
||||
```
|
||||
|
||||
**Qué hace:** devuelve el texto de la transcripción entre dos timestamps, listo para citar.
|
||||
|
||||
**Implementación:** cargar el `.md`, parsear segmentos, filtrar por rango.
|
||||
- **Esfuerzo:** 30 min.
|
||||
|
||||
### 5. `audio` — Descarga de audio (podcast)
|
||||
|
||||
```bash
|
||||
yt-scraper --channel "https://www.youtube.com/@Nostal-Vlad/videos" --download-audio
|
||||
```
|
||||
|
||||
**Qué hace:** descarga el audio MP3 de cada vídeo junto a la transcripción.
|
||||
|
||||
**Implementación:** añadir a `extract.py`:
|
||||
```python
|
||||
ydl_opts["format"] = "bestaudio/best"
|
||||
ydl_opts["postprocessors"] = [{"key": "FFmpegExtractAudio", "preferredcodec": "mp3", "preferredquality": "128"}]
|
||||
ydl_opts["outtmpl"] = str(output_dir / "%(title)s.%(ext)s")
|
||||
```
|
||||
Requiere `ffmpeg` instalado.
|
||||
- **Esfuerzo:** 1 h.
|
||||
|
||||
### 6. `re-render` — Regenerar Markdown tras cambiar plantilla
|
||||
|
||||
```bash
|
||||
yt-scraper re-render
|
||||
```
|
||||
|
||||
**Qué hace:** re-procesa todos los `.md` usando la plantilla actual sin re-descargar nada de YouTube. Útil cuando cambias `video.md.j2`.
|
||||
|
||||
**Implementación:** guardar `segments` y `chapters` en SQLite (columnas JSON), o re-parsear los `.md` existentes.
|
||||
- **Esfuerzo:** 1-2 h.
|
||||
|
||||
---
|
||||
|
||||
## TIER 2 · Alto valor, esfuerzo medio (3-8 h c/u)
|
||||
|
||||
### 7. Multi-canal — Gestión de varios canales
|
||||
|
||||
```bash
|
||||
yt-scraper channels add "https://www.youtube.com/@otro-canal"
|
||||
yt-scraper channels list
|
||||
yt-scraper --channel @nostal-vlad search "vaporwave"
|
||||
yt-scraper --all-channels stats
|
||||
```
|
||||
|
||||
**Implementación:** tabla `channels` ya existe; ampliar CLI con subcomandos `channels add/list/remove`. El `Store` ya soporta multi-canal (PK por `channel_id`).
|
||||
- **Esfuerzo:** 3-4 h.
|
||||
|
||||
### 8. `watch` — Monitoreo de nuevos vídeos
|
||||
|
||||
```bash
|
||||
yt-scraper watch --interval 6h
|
||||
```
|
||||
|
||||
**Qué hace:** ejecuta discovery periódicamente, y si hay vídeos nuevos los procesa automáticamente.
|
||||
|
||||
**Implementación:** loop con `time.sleep(interval)` + `discover_channel()`. En Windows se puede dejar corriendo o usar Task Scheduler.
|
||||
- **Esfuerzo:** 2-3 h.
|
||||
|
||||
### 9. Análisis de contenido
|
||||
|
||||
```bash
|
||||
yt-scraper analyze --wordcloud
|
||||
yt-scraper analyze --top-words 50
|
||||
yt-scraper analyze --timeline "vaporwave"
|
||||
```
|
||||
|
||||
**Qué hace:**
|
||||
- Nube de palabras (matplotlib + wordcloud)
|
||||
- Frecuencia de términos con gráfico
|
||||
- Timeline: cuándo se mencionó un tema a lo largo del tiempo
|
||||
|
||||
**Dependencias nuevas:** `matplotlib`, `wordcloud`, `nltk` (o regex simple para español).
|
||||
- **Esfuerzo:** 4-5 h.
|
||||
|
||||
### 10. `thumbnails` — Descarga masiva de miniaturas
|
||||
|
||||
```bash
|
||||
yt-scraper thumbnails --size maxres
|
||||
```
|
||||
|
||||
**Implementación:** ya tenemos `thumbnail` URL en el frontmatter. Un `requests.get` por vídeo + guardar en `data/thumbnails/`.
|
||||
- **Esfuerzo:** 30 min.
|
||||
|
||||
### 11. Traducción de transcripciones
|
||||
|
||||
```bash
|
||||
yt-scraper --channel @nostal-vlad --translate-to en
|
||||
```
|
||||
|
||||
**Qué hace:** traduce cada transcripción al idioma especificado antes de renderizar el Markdown.
|
||||
|
||||
**Opciones:**
|
||||
- Google Translate (gratis, vía `deep-translator`): rápido, baja calidad
|
||||
- LLM (OpenAI/Anthropic): calidad alta, requiere API key
|
||||
- **Esfuerzo:** 3-4 h (cualquier ruta).
|
||||
|
||||
---
|
||||
|
||||
## TIER 3 · Features avanzadas (8+ h)
|
||||
|
||||
### 12. LLM Summaries — Resúmenes por vídeo
|
||||
|
||||
```bash
|
||||
yt-scraper --channel @nostal-vlad --summarize
|
||||
```
|
||||
|
||||
**Qué hace:** genera un resumen de 3-5 párrafos por vídeo usando un LLM. Se añade al Markdown como campo `summary` en el frontmatter.
|
||||
|
||||
**Implementación:**
|
||||
- Nuevo módulo `summarize.py`
|
||||
- Usa la transcripción completa como contexto
|
||||
- Modelos: OpenAI `gpt-4o-mini` ($0.015 por vídeo de 20 min), Anthropic Claude Haiku, o modelo local con `ollama`
|
||||
- Guardar resumen en SQLite para no re-ejecutar
|
||||
- **Esfuerzo:** 4-6 h.
|
||||
|
||||
**Dependencias:** `openai` o `anthropic` o `ollama` (local, gratis).
|
||||
|
||||
### 13. Q&A / RAG — Preguntas sobre el canal
|
||||
|
||||
```bash
|
||||
yt-scraper ask "¿Qué dijo Vlad sobre los juegos flash?"
|
||||
```
|
||||
|
||||
**Qué hace:** busca en todas las transcripciones y responde con citas + timestamps exactos.
|
||||
|
||||
**Implementación:**
|
||||
- **RAG simple:** FTS5 search → mandar top-K segmentos al LLM como contexto
|
||||
- **RAG con embeddings:** `sentence-transformers` → ChromaDB/FAISS → recuperación semántica
|
||||
- **Esfuerzo:** RAG simple 4-5 h, con embeddings 8-10 h.
|
||||
|
||||
### 14. Extracción de entidades (NER)
|
||||
|
||||
```bash
|
||||
yt-scraper analyze --entities
|
||||
```
|
||||
|
||||
**Qué hace:** detecta personas, marcas, lugares, videojuegos mencionados a lo largo de todos los vídeos.
|
||||
|
||||
**Output:** tabla `entities(video_id, type, name, count)` → "Pokémon mencionado en 8 vídeos", "Sonic en 5 vídeos".
|
||||
|
||||
**Implementación:** `spaCy` (modelo `es_core_news_sm`) o LLM con prompt estructurado.
|
||||
- **Esfuerzo:** 4-6 h.
|
||||
|
||||
### 15. Speaker diarization — Separación de hablantes
|
||||
|
||||
**Qué hace:** distingue "narrador" de "entrevistado" o "invitado" en la transcripción.
|
||||
|
||||
**Implementación:** el audit del Web Clipper ya documenta esto (`groupBySpeaker` en `YoutubeExtractor`). Se puede portar a Python o usar `pyannote-audio`.
|
||||
- **Esfuerzo:** port del algoritmo 2-3 h; con modelo de audio 8+ h.
|
||||
|
||||
---
|
||||
|
||||
## Matriz de prioridades
|
||||
|
||||
| # | Feature | Valor | Esfuerzo | ROI |
|
||||
|---|---|---|---|---|
|
||||
| 1 | `search` (FTS5) | 🔥🔥🔥 | 1-2 h | ⭐⭐⭐ |
|
||||
| 2 | `stats` | 🔥🔥 | 1 h | ⭐⭐⭐ |
|
||||
| 3 | `export json/srt/html` | 🔥🔥 | 2-3 h | ⭐⭐⭐ |
|
||||
| 4 | `clip` | 🔥 | 30 min | ⭐⭐ |
|
||||
| 5 | `audio` download | 🔥🔥 | 1 h | ⭐⭐⭐ |
|
||||
| 6 | `re-render` | 🔥 | 1-2 h | ⭐⭐ |
|
||||
| 7 | Multi-canal | 🔥🔥 | 3-4 h | ⭐⭐ |
|
||||
| 8 | `watch` mode | 🔥🔥 | 2-3 h | ⭐⭐ |
|
||||
| 9 | Análisis (wordcloud) | 🔥 | 4-5 h | ⭐ |
|
||||
| 10 | `thumbnails` | 🔥 | 30 min | ⭐⭐⭐ |
|
||||
| 11 | Traducción | 🔥🔥 | 3-4 h | ⭐⭐ |
|
||||
| 12 | LLM summaries | 🔥🔥🔥 | 4-6 h | ⭐⭐⭐ |
|
||||
| 13 | Q&A / RAG | 🔥🔥🔥 | 4-10 h | ⭐⭐ |
|
||||
| 14 | NER (entidades) | 🔥 | 4-6 h | ⭐ |
|
||||
| 15 | Speaker diarization | 🔥 | 2-8 h | ⭐ |
|
||||
|
||||
---
|
||||
|
||||
## Dependencias Python adicionales por feature
|
||||
|
||||
```bash
|
||||
# Tier 1 — sin dependencias nuevas (solo stdlib)
|
||||
# search, stats, export, clip, re-render usan SQLite + Jinja2 ya instalados
|
||||
|
||||
# Tier 2
|
||||
pip install matplotlib wordcloud # análisis / wordcloud
|
||||
pip install deep-translator # traducción gratuita
|
||||
|
||||
# Tier 3
|
||||
pip install openai # LLM summaries / Q&A
|
||||
pip install sentence-transformers # embeddings para RAG semántico
|
||||
pip install spacy && python -m spacy download es_core_news_sm # NER
|
||||
pip install pyannote.audio # speaker diarization (requiere GPU idealmente)
|
||||
|
||||
# Audio download
|
||||
# Requiere ffmpeg instalado en el sistema:
|
||||
# winget install ffmpeg
|
||||
# o: choco install ffmpeg
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comandos compuestos propuestos (pipelines)
|
||||
|
||||
```bash
|
||||
# Pipeline completo: scrapear + buscar + extraer clip
|
||||
yt-scraper --channel @nostal-vlad scrape
|
||||
yt-scraper search "frutiger aero"
|
||||
yt-scraper clip 8tMQMtIBfTE --from 02:15 --to 04:30 > clip.md
|
||||
|
||||
# Pipeline de análisis
|
||||
yt-scraper stats > stats.txt
|
||||
yt-scraper export --format html > index.html
|
||||
yt-scraper analyze --top-words 30 > palabras.csv
|
||||
|
||||
# Pipeline LLM
|
||||
yt-scraper --channel @nostal-vlad --summarize
|
||||
yt-scraper ask "¿Qué opina Vlad sobre la cultura otaku?"
|
||||
```
|
||||
Reference in New Issue
Block a user