Llevo meses construyendo un ecosistema de automatización que ejecuta pipelines de vídeo, bots de IA, scrapers de noticias y ahora un generador de ideas de proyectos — todo auto-hospedado con Docker y sin que yo tenga que mover un dedo. Lo que empezó como un grabador de directos de Twitch se ha convertido en una suite de 7+ herramientas interconectadas que funcionan 24/7.
Mi motivación: Quería automatizar lo repetitivo: grabar directos, comprimirlos, subirlos a Telegram, descargar de YouTube, generar contenido de programación con IA, scrapear noticias de cine… y ahora también que me salgan ideas de proyectos para programar sin tener que pensarlas yo. Todo ejecutándose solo.
El problema real
Cada herramienta existente resolvía un trozo:
- TwitchRecorder grababa pero no comprimía ni subía
- ffmpeg convertía pero no monitorizaba
- yt-dlp descargaba de YouTube pero no subía a Telegram
- Bots de Telegram existían pero sin IA ni descargas
- Scrapers scrapeaban pero no enviaban resultados
- Ideas de proyectos → yo mismo pensando, buscando, filtrando…
Necesitaba conectar todo en pipelines automáticos. Y que las ideas de proyectos me llegaran solas, sin buscarlas.
Arquitectura completa (actualizada)
┌─────────────────────────────────────────────────────────────────────┐
│ DEVJOBS AUTOMATION SUITE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │TwitchRecorder│──▶│ ffmpeg-yt-dlp │──▶│ Uploader │ │
│ │ (grabar) │ │ (comprimir) │ │ (subir) │ │
│ └─────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ └──────────────────┴──────────────────┘ │
│ │ │
│ data/pipeline/ │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 160 canales │──▶│ download.py │──▶│ upload.py │ │
│ │ YouTube │ │ (descargar) │ │ (subir) │ │
│ └─────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ └──────────────────┴──────────────────┘ │
│ │ │
│ data/yt-pipeline/ │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ @jorbencas │──▶│ Gemini │──▶│ Scrapers │ │
│ │ bot │ │ IA │ │ (noticias) │ │
│ └─────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Project │──▶│ Gemini/ │──▶│ Telegram │ │
│ │ Generator │ │ Deterministic│ │ (canal) │ │
│ └─────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Novedad (24/09/2026): Añadido el Project Generator — un workflow de GitHub Actions que usa workflow_call (nativo, sin PAT) para generar ideas de proyectos con IA (Gemini/OpenAI/Anthropic) o plantillas determinísticas, y enviarlas directo a un canal privado de Telegram. Cero secrets extra, cero cross-repo.
Pipeline 1: Twitch → Telegram (Sendo Sama)
Automatización completa que graba directos de sendo sama, los comprime a 720p y los sube a un grupo de Telegram con temas organizados por serie.
Detalle técnico completo: Telegram Ultimate Toolbox: Descargador Masivo, Clonador, Vigilante y Uploader con Docker
El grupo de Telegram y el sistema de temas
El grupo “Stream Tecnologia” usa el sistema de foro/temas de Telegram. Cada tema es un hilo independiente dedicado a una serie. Cuando subo un vídeo de “One Piece”, aparece en el tema de “One Piece”, no en el chat general. Mantiene todo ordenado: cada serie su hilo, los usuarios siguen lo que les interesa.
Configuración por canal (actualizada)
Cada canal tiene su config de horarios, plataformas y comportamiento. Cambio importante (24/09): mourdev ahora graba en YouTube sin problemas (arreglado deno + remote-components para yt-dlp), y tanto él como midudev tienen detectar: false, corte: false — es decir, se graba el directo completo, se comprime y se sube sin recortar ni detectar episodios.
{
"channels": {
"sendosama": {
"platform": [
{ "platform": "web", "url": "https://watch.sendosama.net/", "detectar": false, "corte": false },
{ "platform": "youtube", "channel": "sendosenpai" },
{ "platform": "twitch", "detectar": false, "corte": false },
{ "platform": "kick", "detectar": false, "corte": false }
],
"start_time": { "Sunday": "19:00", "*": "21:30" },
"dias_plataforma": {
"Sunday": ["youtube", "web", "kick", "twitch"],
"*": ["web"]
}
},
"midudev": {
"platform": [
{ "platform": "youtube", "detectar": false, "corte": false },
{ "platform": "twitch", "detectar": false, "corte": false }
],
"days": ["Monday"],
"start_time": "18:00"
},
"mouredev": {
"platform": [
{ "platform": "youtube", "detectar": false, "corte": false },
{ "platform": "twitch", "detectar": false, "corte": false }
],
"days": ["Thursday"],
"start_time": "18:00"
}
},
"record_path": "/recordings",
"check_every": 30,
"max_duration": "24:00:00",
"retry_interval": 1,
"copy_to_test": true,
"test_path": "/recordings/test"
}
Qué cambió en YouTube (24/09):
- Problema: yt-dlp pedía JS runtime (deno) para extraer formatos de YouTube, fallaba con “No supported JavaScript runtime could be found”
- Solución: Dockerfile instala deno en
/home/appuser/.deno(accesible al user 1000), y enrecorder.py+youtube.pyse pasan--js-runtimes deno --remote-components ejs:githuba yt-dlp - Resultado: YouTube detection + extraction funcionan. mourdev graba en Twitch ahora mismo (YouTube no está live) pero si estuviera live, pillarías YouTube sin errores
Flujo paso a paso (sin cambios)
El pipeline de Twitch → Telegram son 6 pasos encadenados, patrón watcher: cada servicio vigila la carpeta donde el anterior deja su resultado.
Twitch live
│
▼
① twitchrecorder-sendo ──► título → nombre (keyword)
│ data/pipeline/grabaciones/test/*_completed.mp4
▼
② ffmpeg_monitor-sendo ──► 720p, CRF 28, 2 pasadas si >1900MB
│ data/out/*_720p.mp4
▼
③ OCR (ffmpeg_monitor-sendo) ──► detecta serie por imagen del frame
│
▼
④ telegram-uploader-sendo ──► sube a temas de Telegram por keyword
▼
Serie correcta (tema/foro)
- Grabar —
twitchrecorder-sendograba con calidad original - Keyword — extrae título del directo y lo pone en el nombre (para ruteo). Para web, el título viene siempre de la API real (Kick
session_titleo Twitch), no del HTML - Cola — vídeo espera en
data/pipeline/grabaciones/test/como*_completed.mp4 - Comprimir — a 720p (CRF 28) porque Telegram límite 2GB
- OCR — detecta episodios por imagen del frame
- Subir — rutea por keyword a temas de Telegram
Salto de plataforma a mitad: si el directo empieza en Twitch y se cambia a YouTube/web a mitad, el pipeline no se rompe. Detecta playlist congelada, cierra parte actual, abre
__parte2con misma keyword. Al final concatena todo → uploader ve un único vídeo con la serie correcta.
Contenedores Docker
| Contenedor | Servicio | Función |
|---|---|---|
twitchrecorder-sendo | Grabador | Detecta directos, graba calidad original, concatena partes |
ffmpeg_monitor-sendo | Compresor | Convierte a 720p, detecta episodios por OCR, gestiona sidecars |
telegram-uploader-sendo | Subidor | Rutea por keyword, sube a temas de Telegram, limpia residuos |
Resultado
Un directo a las 21:00 aparece comprimido y subido a su tema/serie sin que yo haga nada. Funciona 24/7: si hay directo a las 3am, se graba, comprime y aparece en Telegram al día siguiente.
# Arrancar todo el pipeline
pipe_up
# Ver logs de los 3 a la vez
plogs
# Parar todo
pipe_down
Pipeline 2: YouTube → Telegram (160 canales)
Pipeline diario que descarga vídeos de 160 canales de YouTube, los convierte a 720p y los sube a Telegram con temas por canal.
Por qué 160 canales
Cada canal tiene contenido distinto: tutoriales, noticias, entrevistas. El pipeline baja lo nuevo de cada canal y lo organiza en “Stream Tecnologia” por canal/tema. Midudev en su tema, MoureDev en otro, Carlos Azaustre en otro…
Configuración (producción)
- Canales: 160 en
channels.json(6 habilitados por defecto) - Temas: 160 (uno por canal en “Stream Tecnologia”)
- Calidad: 720p H.264/AAC — balance calidad/tamaño (límite 50MB bot)
- Cron: 01:00 → 18:00 — horario nocturno
- Límite: 1 vídeo por canal (
max_videos: 1)
Flujo
01:00 Cron arranca
↓
download.py (descarga 160 canales)
↓
convert.py (convierte a 720p, 95% target size)
↓
upload.py (sube a Telegram con topic_id)
↓
18:00 Cron para
# Ver logs del cron
cat data/yt-pipeline/logs/cron_$(date +%Y%m%d).log
# Parar manualmente
cd yt-to-telegram && docker compose down
Project Generator (NUEVO 24/09)
Generador automático de ideas de proyectos que se ejecuta via GitHub Actions y te manda los resultados a Telegram.
Qué hace
- Niveles: Junior / Semisenior / Senior
- Scopes: Miniproyecto (1-2 sem) / Proyecto (3-6 sem) / Multiproyecto (6+ sem)
- Lenguajes: Python, JavaScript, TypeScript, C#, Go, Rust
- Tipos: Web, API, CLI, Mobile, Desktop, Fullstack, Microservicio, Bot, IA/ML, Datos, DevOps, Testing, Seguridad
- Tech stack detallado: Frameworks, libs, BD, infra, IA/ML, testing con justificación
por_quepor herramienta - IA integrada: Especifica cuándo y por qué usar IA (OpenAI, Anthropic, Gemini, local)
- Anti-duplicados: Hash MD5 para no repetir proyectos
- Fuentes inspiración: Tips de Telegram, tuweb.dev (scraper), plantillas determinísticas
- Mobile: ✅ Flutter, React Native, MAUI — ❌ NO solo iOS nativo
Arquitectura (sin PAT — workflow_call nativo)
devjobs (cron lunes 9am / manual)
│
▼ workflow_call (github.token nativo)
generate-projects-internal.yml
│
├── checkout devjobs (github.token)
├── pip install
├── python -m src.main generate --send-telegram
│ └── secrets: TELEGRAM_BOT_TOKEN, TELEGRAM_REPORTS_PROYECTOS_CHANNEL_ID, GEMINI_API_KEY
├── Sends to Telegram
├── Commits history a devjobs (github.token)
▼
Ventaja clave: Cero GH_PAT. Usa github.token nativo porque el workflow reutilizable (workflow_call) está en el mismo repo. Antes hacía repository_dispatch cross-repo y necesitaba 2 PATs. Ahora: un repo, un token nativo, listo.
Ejemplo de proyecto generado
{
"titulo": "Sistema de Gestión de Ensayos para Bandas de Música",
"descripcion_corta": "App móvil + panel web para gestionar ensayos, convocatorias y asistencia",
"nivel": "semisenior",
"scope": "proyecto",
"tipo": ["mobile", "web", "api"],
"tech_stack": {
"lenguaje_principal": "typescript",
"frameworks": [
{"nombre": "React Native (Expo)", "por_que": "Cross-platform iOS/Android, hot reload"},
{"nombre": "Next.js", "por_que": "Panel web SSR, API routes, optimizado para SEO"}
],
"librerias": [
{"nombre": "Zustand", "por_que": "Simple, sin boilerplate, TypeScript nativo"},
{"nombre": "React Query", "por_que": "Cache, sync, optimistic updates para API"}
],
"bases_datos": [
{"nombre": "PostgreSQL", "por_que": "Relacional, JSONB para metadata flexible, multi-tenant nativo"}
],
"ia_ml": [
{"nombre": "OpenAI Embeddings", "por_que": "Búsqueda semántica de repertorios, clustering de músicos"}
],
"testing": [
{"nombre": "Jest + React Testing Library", "por_que": "Unit + integration, coverage, snapshot"}
]
},
"funcionalidades_clave": [
"CRUD ensayos/actuaciones con repertorio",
"Convocatoria por cuerda/instrumento/individuo",
"Respuesta asistencia con estados (pendiente/confirmado/rechazado)",
"Notificaciones push (FCM/APNs) + email transaccional",
"Panel junta: calendario, lista, transporte, uniformes",
"App músico: agenda personal, chat interno, encuestas anónimas"
],
"por_que_ia": "Clasificación automática de disponibilidad por patrones históricos + generación de resúmenes de actas con LLM",
"cliente_ia_sugerido": "openai",
"complejidad_estimada": "media",
"tiempo_estimado_semanas": 4
}
Secrets necesarios en devjobs
| Secret | Valor |
|---|---|
TELEGRAM_BOT_TOKEN | Copiar de test_githubActions |
TELEGRAM_REPORTS_PROYECTOS_CHANNEL_ID | -1004497081221 |
GEMINI_API_KEY | Copiar de test_githubActions |
OPENAI_API_KEY / ANTHROPIC_API_KEY | Opcionales |
Probar manual
Actions → [PROJECTS] Generate Projects → Run workflow → elegir parámetros → Run
El historial se guarda en devjobs/project_generator/data/generated_projects.json.
Bot de Telegram (@jorbencas_bot)
Bot interactivo con comandos, botones inline y contenido IA.
Detalle técnico: Telegram Ultimate Toolbox
Comandos
| Comando | Qué hace |
|---|---|
/descarga URL | Descarga vídeo de cualquier plataforma, convierte y envía |
/tip | Tip de programación (Gemini + DB) |
/concepto | Concepto con código de ejemplo |
/tool | Herramienta IA (2108 recursos migrados del blog) |
/noticias | Últimas noticias tech (scrapers 80+ fuentes) |
Características técnicas
- Descarga multicapa — yt-dlp primero; fallback HLS para streams directos
- Formato
bv+ba/b— baja vídeo y audio por separado y los fusiona (YouTube sirve streams separados) - Timeout 30 min — vídeos grandes tardan
- Conversión H.264/AAC 720p, 2 pasadas si >50MB — lo que Telegram espera
- IA Gemini — tips, conceptos, noticias dinámicas sin repetir
- Scrapers 80+ fuentes españolas — noticias tech agregadas
Scrapers Automatizados
Detalle técnico: Tech Pulse: Dashboard Automatizado de Noticias Tech con IA
Eixam (Película)
Scraper dedicado a “Eixam” (Enjambre) de Óscar Bernàcer: reseñas, noticias, tráilers, póster. 80 elementos archivados.
Tips Generator
Base de datos de 283 conceptos de programación con preguntas de entrevista (JS, Python, Testing, IA/ML, LLMs, Linux, Design Patterns, Soft Skills, DevOps). Scraping Wikipedia EN, mapeo español→inglés, fallback Gemini, fallback simple.
Sistema de Aliases: Control desde cualquier Terminal
Una sola instalación (bash servicios/instalar_aliases.sh) pone 40+ aliases en ~/.bashrc que funcionan desde cualquier carpeta.
Convención (clave para no perderse)
| Prefijo | Significado | Ejemplo |
|---|---|---|
pipe_* | Los 3 daemons del pipeline a la vez | pipe_up, pipe_down, plogs |
*_logs | Ver logs de un daemon | ff_logs, tw_logs, tg_logs |
*_stop | Parar un daemon | ff_stop, tw_stop, tg_stop |
*_restart | Reiniciar | ff_restart, tw_restart |
*_manual_* | Versión para probar a mano | ff_midu, tw_run |
*_down | Parar TODO el proyecto | tg_down, tw_down |
tg_bot_* | Bot API | tg_bot, tg_bot_logs |
*_sys_* | Control vía systemd | pipe_sys_start, tg_bot_sys_status |
Ejemplos reales
# Pipeline completo Twitch
pipe_up # Arrancar los 3 daemons
plogs # Ver logs de los 3 a la vez (colores)
pipe_down # Parar los 3
pipe_ps # Estado de los 3 contenedores
pipe_recreate # Recrear (aplica cambios de CONFIG)
pipe_rebuild # Rebuild + recrear (cambios de CÓDIGO)
# Un proyecto individual
ff_logs # Logs del monitor ffmpeg
ff_stop # Parar el monitor
ff_restart # Reiniciar el monitor
ff_midu # Lanzar midu.sh interactivo
# Bot de Telegram
tg_bot # Arrancar el bot
tg_bot_logs # Ver logs
tg_bot_stop # Parar
tg_bot_rebuild # Rebuild imagen + arrancar
Systemd: Auto-arranque al Boot
Los servicios systemd levantan el pipeline y el bot solos al encender el PC.
Servicios
| Servicio | Qué hace |
|---|---|
twitch-stream-pipeline.service | Arranca los 3 daemons del pipeline |
telegram-bot.service | Arranca el bot API |
Gestión
# Pipeline
sudo systemctl status twitch-stream-pipeline.service
sudo systemctl restart twitch-stream-pipeline.service
sudo systemctl stop twitch-stream-pipeline.service
# Bot
sudo systemctl status telegram-bot.service
sudo systemctl restart telegram-bot.service
# O con aliases (sin sudo)
pipe_sys_start # Arrancar pipeline
pipe_sys_stop # Parar pipeline
pipe_sys_status # Ver estado
tg_bot_sys_start # Arrancar bot
tg_bot_sys_stop # Parar bot
Al encender el PC: systemd → docker compose up -d → daemons vigilan carpetas → si hay directo, graba → si hay vídeos en cola, comprime → si hay comprimidos, sube a Telegram.
Bootstrap en máquina nueva (Windows + WSL2)
# Opción A (recomendada)
bash <(curl -fsSL https://raw.githubusercontent.com/jorbencas/devjobs/main/servicios/bootstrap_instalar.sh)
# Opción B
curl -fsSL -o bootstrap_instalar.sh https://raw.githubusercontent.com/jorbencas/devjobs/main/servicios/bootstrap_instalar.sh
chmod +x bootstrap_instalar.sh
./bootstrap_instalar.sh
El script: comprueba Docker/WSL2, clona repo, ajusta rutas, crea carpetas, revisa secretos, build imágenes, instala systemd, añade aliases.
Docker Help: Cheatsheet Completo
docker_help.txt (482 líneas) con todo el ecosistema. Alias docker_help.
Secciones
| Sección | Contenido |
|---|---|
| 1. Docker general | Imágenes, contenedores, limpieza, build, run, red |
| 2. Docker compose | Comandos genéricos |
| 3. Proyectos | Cada proyecto con sus alias |
| 4. Pipeline | Los 3 daemons a la vez (pipe_*) |
| 5. Systemd | Auto-arranque al boot |
| 6. Montar en otra máquina | Script bootstrap Windows + WSL2 |
| 7. Utilidades | Estado, disco, comandos útiles |
Cron Pipeline: Automatización Diaria
Pipeline de YouTube con cron 01:00 → 18:00.
# Cron
0 1 * * * /home/jorge/dev/devjobs/yt-to-telegram/scripts/run_pipeline_cron.sh
El script: marca timestamp, calcula hora parada, docker compose up, bucle cada 5 min (¿sigue corriendo? ¿es hora de parar?), 18:00 docker compose down, resumen.
# Ver logs de hoy
cat data/yt-pipeline/logs/cron_$(date +%Y%m%d).log
# Ejecutar manualmente
bash /home/jorge/dev/devjobs/yt-to-telegram/scripts/run_pipeline_cron.sh
# Parar
cd yt-to-telegram && docker compose down
Si el cron se para antes (apagas PC), vídeos pendientes se guardan en pending_videos.log y la próxima vez continúa desde ahí.
Backup YouTube y herramientas bajo demanda
| Herramienta | Qué hace | Alias |
|---|---|---|
| backup_youtube.sh | Archiva canales enteros en disco (idempotente, metadatos) | backup_youtube.sh <URL> |
| pdfmanager | Desbloquear, unir, dividir, comprimir PDFs | pdf_run |
| hdfull-downloader | Descarga películas/series HDFull (VNC captcha) | hd_run |
| aula-downloader | Descarga Moodle/Vimeo (cursos aula virtual) | al_run |
| kick_download.py | Descarga Kick.com por slug + video_id | kick_dl |
| discord_monitor.py | Graba streams/llamadas Discord con OBS | discord_monitor |
Todas comparten la misma config de ffmpeg.
Herramientas Docker
Contenedores
| Contenedor | Proyecto | Función |
|---|---|---|
twitchrecorder-sendo | TwitchRecorder | Graba directos (Twitch/YouTube/Kick/web), concatena partes |
ffmpeg_monitor-sendo | ffmpeg-yt-dlp | Comprime a 720p, detecta episodios por OCR |
telegram-uploader-sendo | downloader_telegram | Sube a Telegram por keyword/temas |
telegram-downloader | downloader_telegram | CLI interactivo (a demanda) |
telegram-bot | downloader_telegram | Bot API interactivo |
yt-pipeline | yt-to-telegram | Pipeline YouTube (cron 01:00 → 18:00) |
yt-download / yt-convert / yt-upload | yt-to-telegram | Fases sueltas para depurar |
Ojo con el monitor: no existe
monitor.json. El monitorffmpeg_monitor-sendose configura por variables de entorno y flags en sudocker-compose.yml(CRF 28, preset fast,--completed-only,POLL_INTERVAL…). Lo que sí hay son JSON de estado (pipeline_status.json,pipeline_logs.json) que escribe encomprimidos/.pipeline/(IPC para el bot).
Volúmenes de datos
data/
├── pipeline/ ← Pipeline Twitch
│ ├── grabaciones/2026/ Grabaciones en bruto por fecha
│ ├── grabaciones/test/ Cola *_completed.mp4
│ ├── comprimidos/ Listos para subir *_compressed.mp4
│ ├── comprimidos/.processed/ Originales ya comprimidos
│ ├── comprimidos/.pipeline/ IPC monitor ↔ bot: *_status.json, *_logs.json
│ ├── partes/ Partes divididas (>2GB)
│ └── backups/ Backups de config
├── yt-pipeline/ ← Pipeline YouTube
│ ├── downloads/ Vídeos descargados 160 canales
│ ├── converted/ Convertidos a 720p
│ ├── uploaded/ Histórico subidos
│ └── logs/ Logs uploads/conversiones
└── jorbencas_bot/ ← Bot Telegram
├── *.mp4 Descargas del bot (/descarga)
└── .test_githubActions/ Código AI (tips, tools, noticias)
Conversión unificada (todos los pipelines)
ffmpeg -c:v libx264 -crf 28 -preset fast -vf scale=-2:720
-c:a aac -b:a 128k -map 0:v:0 -map 0:a:0
-map_metadata 0 -movflags +faststart -f mp4
# 2 pasadas si >50MB (bot Telegram) o >1900MB (monitor/uploader)
Stack técnico
| Tecnología | Uso |
|---|---|
| Docker | Todos los servicios (7 contenedores + fases on-demand) |
| Python | Bots, scrapers, pipelines, project generator |
| ffmpeg | Conversión vídeo (720p, CRF 28) |
| yt-dlp | Descarga vídeos (1000+ sitios) |
| Telethon | Cliente Telegram (uploader, CLI) |
| python-telegram-bot | Bot API Telegram |
| Gemini API | Generación contenido IA |
| BeautifulSoup | Web scraping (noticias, cine) |
| Rich | CLI con progreso y paneles |
| InquirerPy | Menús interactivos |
| Systemd | Auto-arranque al boot |
| Cron | Ejecución diaria pipeline YouTube |
| GitHub Actions | CI/CD + Project Generator (workflow_call) |
Lo que aprendí (actualizado)
- Pipelines complejos: Conectar 3+ servicios comunicándose por archivos (watcher pattern)
- Docker en producción: Volumes para persistencia, restart policies, health checks
- Bots Telegram: Comandos, botones inline, archivos >50MB con compresión auto
- Scraping robusto: Múltiples fuentes, fallbacks, deduplicación, envío a Telegram
- Automatización 24/7: Cron jobs, systemd, aliases para control fácil
- IA en producción: Gemini/OpenAI/Anthropic para generación, fallback a DB local
- Sistema de aliases: Convención clara que hace 40+ comandos fáciles de recordar
- GitHub Actions nativo:
workflow_call+github.token= cross-repo sin PATs (este fue el “click” final) - yt-dlp + deno: YouTube cambió y ahora pide JS runtime; instalar deno en user-space y pasar flags a yt-dlp soluciona todo
Instalación
¿Cómo montar todo desde cero? Consulta la guía de instalación completa — paso a paso desde credenciales hasta auto-arranque, con cada archivo, comando y caso de uso (config.json, monitor FFmpeg, backup_youtube.sh, aliases, systemd, project generator…).
Repositorio
Código completo en github.com/jorbencas/devjobs.
