No he escrito en dev.to desde el 2022. Ha habido muchos cambios en estos 4 años. Nuevos empleos, nuevos proyectos, nuevas tecnologías, etc. He regresado con un proyecto que me ha causado mucho interes
Tabla de Contenido
Introducción
¿Alguna vez has querido eliminar una o varias pistas de audio de un video?
Quizas tienes una pelicula o el episodio de alguna serie con mas de un audio pero quieres conservarlo solo con la pista de audio que te interesa. O tambien esta la posibilidad de que quisieras dejarlo sin pistas de audio para poder editarlo o por motivos de accesibilidad
para esa cuestión ejecutaba un comando como este:
ffmpeg -i test-video.1080p-Dual.mkv -map 0:v -map 0:a:1 -c copy D:test-video.es.mkv
¿Qué hace el comando?
| Parte | Explicación |
|---|---|
ffmpeg |
El programa que ejecuta el comando |
-i test-video.1080p-Dual.mkv |
Archivo de entrada (el video original) |
-map 0:v |
Selecciona todas las pistas de video del archivo 0 |
-map 0:a:1 |
Selecciona la pista de audio número 1 del archivo 0 (en este caso, español) |
-c copy |
Copia los codecs (sin re-codificar) |
D:test-video.es.mkv |
Archivo de salida (el video procesado) |
El Problema
Los archivos de video suelen contener múltiples pistas de audio:
- Diferentes idiomas (inglés, español, francés, etc.)
- Pistas de comentarios
- Descripciones de audio para accesibilidad
- Múltiples formatos o bitrates
La mayoría de los editores de video son excesivos para esta tarea. Quería una herramienta ligera, rápida y gratuita que:
- Funcione localmente (sin subir archivos a la nube)
- Procese varios videos a la vez
- Muestre el progreso en tiempo real
- Recuerde las selecciones de pistas por video
- Tenga una interfaz limpia y fácil de usar
Tecnologías
| Capa (Layer) | Tecnología |
|---|---|
| Frontend | React, TypeScript, Vite |
| Backend | Node.js, Express, TypeScript |
| Procesamiento de Video | FFmpeg (fluent-ffmpeg) |
| Actualizaciones en Tiempo Real | Server-Sent Events (SSE) |
| Colas | Cola de procesamiento en memoria |
| Tests | Vitest |
Retos y Soluciones
1. Procesar videos sin subirlos
Como esta es una herramienta local, no quería subir archivos a un servidor. El backend lee los videos directamente del sistema de archivos usando la ruta configurada en .env.
// config.ts
const getVideoFolder = (): string => {
const envPath = process.env.VIDEO_FOLDER_PATH;
return envPath ? path.resolve(envPath) : path.join(__dirname, '../videos');
};
¿Por qué importa? La herramienta es 100% local. No hay subidas, no hay límites de tamaño, no hay dependencia de internet y tus archivos nunca salen de tu computadora.
2. Progreso en tiempo real con SSE
FFmpeg emite eventos de progreso, pero necesitaba transmitirlos al frontend. Elegí Server-Sent Events en lugar de WebSockets porque es más simple para comunicación unidireccional.
// Backend - emitiendo eventos de progreso
command.on('progress', (progress) => {
const percent = Math.round(progress.percent || 0);
this.emit('job-progress', item, percent);
});
// Frontend - escuchando eventos
const eventSource = new EventSource(`/api/events?jobId=${jobId}`);
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
setProcessProgress(data.progress);
};
¿Por qué SSE? Está integrado en los navegadores, maneja reconexiones automáticamente y es perfecto para actualizaciones servidor-cliente.
3. Persistencia de selección de pistas por video
Necesitaba recordar qué pistas seleccionó el usuario para cada video. Usé un Map en el estado del frontend:
const [selectedTracksMap, setSelectedTracksMap] = useState<Map<string, number[]>>(new Map());
Al cambiar entre videos, las pistas seleccionadas/deseleccionadas se mantienen.
4. Procesamiento por lotes con cola
Procesar varios videos simultáneamente saturaría el sistema. Por lo que implementé una cola simple en memoria
5. Manejo de videos sin pistas de audio
Quise colocar la opción de poder eliminar todas las pistas de audio solo para probar. El backend soporta tracksToKeep: [] usando el flag -an de FFmpeg.
Conclusión
Este proyecto empezo como una solucion personal a un problema, ejecutar manualmente comandos para eliminar pistas de audio o tener que crear scripts para lotes de videos era muy repetitivo. Este proyecto termino siendo un ejercicio practico para construir una aplicacion local.
Lo que hace este proyecto interesante:
- Integracion con FFmpeg – Trabajar con una herramienta CLI desde Node.js me enseñó a como manejar subprocesos, analiza la salida, y streamear eventos de progreso.
- comunicación en tiempo real – Los eventos Server-sent demostraron ser una simple pero efectiva alternativa a websockets, es el segundo proyecto donde hago uso de esa herramienta.
- Architectura – Separar el frontend en componentes y custom hooks, y el backend en controladores y servicios hace que el codigo sea mantenible y escalable.
- Local-first – Desde mi punto de vista tiene mucho valor haber construido una herramienta útil como esta que se ejecuta completamente en la máquina del usuario sin depender de la nube.
El proyecto es de código abierto. Siéntete libre de usarlo, modificarlo, o aprender de el.
Contacto
Si te ha parecido interesante este proyecto y estás buscando un desarrollador Full Stack, no dudes en contactarme.
- GitHub: github.com/rtagliaviaz
- Telegram: @rtagliajs
-
Discord:
appulino - Email: rtagliavia.pp@gmail.com
¡Gracias por leer! 🙌
Top comments (0)