Skip to content

Joseleelsuper/MKV-Translator

Repository files navigation

MKV Translator

Aplicación web (FastAPI + HTML/CSS/JS “vanilla”) para:

  • Traducir subtítulos en .srt con distintos proveedores (OpenAI / DeepSeek / Groq / DeepL).
  • Procesar .mkv: extrae la pista de subtítulos a SRT, la traduce, y vuelve a incrustarla en un MKV de salida.

La UI muestra logs en tiempo real y progreso mediante SSE (Server-Sent Events).

Nota sobre estáticos:

  • /templates/* sirve el frontend desde templates/ (CSS/JS/HTML).
  • /static/* es un alias por compatibilidad.
  • /assets/* se reserva para imágenes/iconos (por ejemplo page.webp, favicon.ico).

Ejecutar sin clonar (imagen Docker)

La imagen se publica automáticamente en GitHub Container Registry (GHCR):

  • ghcr.io/joseleelsuper/mkv-translator:latest (última versión)

Docker Compose (recomendado)

Con Docker instalado, basta con descargar/crear un docker-compose.yml como este (usa :latest):

services:
  mkv-translator:
    image: ghcr.io/joseleelsuper/mkv-translator:latest
    ports:
      - "8000:8000"
    environment:
      - PORT=8000
      - MKV_TRANSLATOR_DATA_DIR=/data
      - MKV_TRANSLATOR_TEMPLATES_DIR=/app/templates
    volumes:
      - ${MKV_TRANSLATOR_DATA_HOST_DIR:-./data}:/data
      - ${MKV_TRANSLATOR_TEMPLATES_HOST_DIR:-./templates}:/app/templates:ro
      - ${MKV_TRANSLATOR_ASSETS_HOST_DIR:-./assets}:/app/assets:ro
    restart: unless-stopped

Y levantarlo:

docker compose pull
docker compose up

Nota: evita --build en este modo (eso es para construir desde código local).

Abre: http://127.0.0.1:8000

¿Dónde se guardan los archivos?

  • En Docker/Compose, el ejemplo monta ./data (host) en /data (contenedor).
  • La app crea una carpeta por job dentro de ese directorio.
  • Puedes cambiarlo apuntando MKV_TRANSLATOR_DATA_DIR a otra ruta dentro del contenedor.

Layout recomendado (sin tener el repo al lado del compose)

Puedes tener una carpeta “runtime” en cualquier sitio, por ejemplo:

  • C:\\mkv-translator-runtime\\
    • docker-compose.yml
    • data\\ (salidas por job)
    • templates\\ (copias de templates/ del repo)
    • assets\\ (favicon, imágenes…)

Y arrancar desde ahí con:

docker compose up -d

Si el compose no está en la misma carpeta que templates/ y assets/, puedes usar rutas absolutas:

set MKV_TRANSLATOR_TEMPLATES_HOST_DIR=C:\\ruta\\a\\templates
set MKV_TRANSLATOR_ASSETS_HOST_DIR=C:\\ruta\\a\\assets
set MKV_TRANSLATOR_DATA_HOST_DIR=C:\\ruta\\a\\data
docker compose up -d

Docker (sin Compose)

docker run --rm -p 8000:8000 ghcr.io/joseleelsuper/mkv-translator:latest

Quickstart (Docker, clonando el repo)

Requisitos: tener Docker instalado.

Build de la imagen:

docker build -t mkv-translator:latest .

Ejecutar:

docker run --rm -p 8000:8000 mkv-translator:latest

Abre: http://127.0.0.1:8000

Notas:

  • El contenedor ya incluye ffmpeg y ffprobe, así que el procesamiento de .mkv funciona dentro de Docker.
  • La app escucha en 0.0.0.0 y usa ${PORT:-8000} (por defecto 8000).

Quickstart (Docker Compose)

Requisitos: Docker Compose v2 (docker compose).

Levantar el servicio:

docker compose up --build

Nota: este modo usa build local. Si quieres levantar sin clonar, usa el bloque de arriba (imagen :latest).

Parar:

docker compose down

Abre: http://127.0.0.1:8000

Por qué Railway en lugar de Vercel

Migrado de Vercel a Railway por limitaciones técnicas fundamentales:

Problemas con Vercel (serverless)

  • No incluye ffmpeg: Imposible procesar archivos .mkv sin binarios del sistema
  • Límite de 250MB por función: Los binarios estáticos de ffmpeg (~154MB) hacen inviable incluirlos
  • Jobs en memoria efímeros: Distintas requests van a instancias diferentes, rompiendo SSE
  • Timeouts estrictos: No apto para traducciones largas (>60s)

Ventajas de Railway

  • Soporte nativo de ffmpeg: Se instala con apt-get en el Dockerfile
  • Sin límites de tamaño: Contenedores completos, no funciones limitadas
  • Instancia persistente: Jobs + SSE funcionan correctamente
  • Sin timeouts problemáticos: Procesa archivos grandes sin interrupciones
  • Free tier generoso: 500 horas/mes + $5 crédito inicial

Conclusión: Railway es la plataforma ideal para apps que necesitan procesamiento de video/audio o cualquier dependencia del sistema.

Requisitos

  • Python 3.11+ (probado con 3.12)
  • ffmpeg + ffprobe (instalados automáticamente en Railway)

Dependencias del sistema (MKV)

En Linux (Debian/Ubuntu):

sudo apt update && sudo apt install -y ffmpeg

Comprueba:

ffmpeg -version
ffprobe -version

Instalación

python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
python -m uvicorn app.main:app --host 127.0.0.1 --port 8000

Abre http://127.0.0.1:8000.

Despliegue en Vercel

Este repo incluye configuración para desplegar en Vercel usando el runtime de Python:

  • api/index.py: entrypoint que exporta app (FastAPI).
  • vercel.json: rutas (catch-all) hacia la función serverless.

Pasos (resumen):

  1. Sube el repo a GitHub.
  2. En Vercel: New Project → importa el repo.
  3. Deploy.

Limitación: archivos MKV no funcionan en Vercel

  • El runtime serverless de Vercel no incluye ffmpeg/ffprobe y el límite de 250MB por función hace inviable incluir binarios estáticos (~154MB solo ffmpeg).
  • Solución: Extrae los subtítulos localmente antes de subirlos:
    ffmpeg -i video.mkv -map 0:s:0 subtitles.srt
    Luego sube el archivo .srt a la app en Vercel.

Limitaciones importantes (serverless)

La app está diseñada como proceso “largo” (jobs en memoria + SSE):

  • El repositorio de jobs es en memoria. En Vercel, distintas requests pueden ir a instancias diferentes, por lo que el endpoint de eventos (/api/jobs/{id}/events) podría no encontrar el job creado.
  • Los archivos y el estado son efímeros (no hay persistencia entre despliegues y no se debe confiar en el disco para almacenar resultados a largo plazo).
  • Hay límites de duración por ejecución (configurable desde el Dashboard de Vercel, pero sigue siendo un entorno con timeouts).

Si necesitas que funcione de forma fiable en Vercel “en producción”, lo normal es:

  • Persistir jobs/eventos en un store externo (por ejemplo Redis / Vercel KV).
  • Subir entradas/salidas a almacenamiento (por ejemplo Vercel Blob / S3).

Si quieres, puedo adaptar el JobRepository y la cola de eventos para usar Vercel KV/Redis.

Uso

  1. Selecciona el proveedor.
  2. Introduce tu API key.
  3. La app intenta cargar la lista de modelos desde la API del proveedor.
    • Si no puede, usa un fallback estático.
    • En la UI, para proveedores LLM, el fallback se interpreta como “API key inválida” (DeepL es la excepción porque no expone catálogo de modelos).
  4. Sube un .srt o .mkv.
  5. Inicia la traducción y sigue los logs/progreso.
  6. Descarga el resultado:
    • SRT Fuente (útil para depurar la extracción)
    • SRT Traducido
    • MKV Traducido (solo si subiste un .mkv)

Privacidad / claves

  • La clave se envía al backend para llamar al proveedor durante el job.
  • No se persiste en disco ni en una base de datos (los jobs son en memoria).
  • Aun así, evita ejecutar la app en entornos compartidos si vas a usar claves reales.

Estructura del proyecto (hexagonal)

  • mkv_translator/domain: parsing/ensamblado SRT y modelo Job (eventos/progreso)
  • mkv_translator/application: puertos + servicios de orquestación
  • mkv_translator/adapters:
    • ffmpeg/*: extracción/mux de subtítulos
    • llm/*: clientes de proveedores (OpenAI-compat / DeepL)
    • web/*: FastAPI + rutas HTTP
  • templates/html|css|js: frontend vanilla

El “composition root” es app/main.py: cablea adaptadores y servicios.

Cómo funciona (resumen)

  • Subes un .srt o .mkv desde la UI.
  • El backend crea un Job en memoria y lanza el trabajo en un thread.
  • La UI se conecta a /api/jobs/{id}/events (SSE) y va recibiendo:
    • log: mensajes de estado
    • progress: porcentaje
    • done / error
  • Descargas disponibles:
    • /api/jobs/{id}/download?kind=source_srt (SRT fuente)
    • /api/jobs/{id}/download?kind=srt (SRT traducido)
    • /api/jobs/{id}/download?kind=mkv (MKV traducido, solo si subiste MKV)

Troubleshooting

Local

  • Error al procesar MKV (ffmpeg/ffprobe no está instalado): instala ffmpeg y verifica que está en PATH.
  • "No subtitle streams found in MKV": el MKV no tiene pistas de subtítulos o están en un formato no detectable por ffprobe.

Railway

  • Build falla: Verifica que el Dockerfile existe en la raíz del proyecto
  • App no responde: Revisa los logs en Railway Dashboard → Deployments → Logs
  • Puerto incorrecto: Railway asigna $PORT automáticamente, no lo configures manualmente

Proveedores

  • Modelos no cargan: Verifica proveedor y API key
  • Si el proveedor cae o limita el endpoint de modelos, el backend hará fallback estático

Alternativas de deployment

Si Railway no te funciona, estas plataformas también soportan ffmpeg:

  • Fly.io: Similar a Railway, free tier con 3 VMs
  • Render: Web Services con Docker, más tradicional
  • VPS (Hetzner/DigitalOcean): Control total, desde €4.5/mes

About

Genera archivos de subtítulos en tu idioma preferido utilizando otros como base.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors