Communitygithub.com

Tofuswang/video-subtitle-skill

Habilidad de Claude Code para añadir subtítulos a videos usando Whisper local + ffmpeg. 5★.

¿Qué es video-subtitle-skill?

Esta habilidad permite transcribir automáticamente el audio de un video a subtítulos en formato SRT utilizando modelos locales de Whisper (mlx-whisper para Apple Silicon u openai-whisper) y luego incrustar los subtítulos en el video mediante ffmpeg con soporte libass. Es útil para desarrolladores y creadores de contenido que desean añadir subtítulos de forma offline, rápida y sin depender de servicios externos. Soporta tanto el pipeline completo (transcripción + corrección + quema) como modos independientes (solo SRT o solo quema). Incluye detección automática de herramientas, selección del modelo Whisper más grande disponible, limpieza de alucinaciones en los subtítulos y opciones de estilo personalizables. Funciona en macOS Apple Silicon, Linux y otras plataformas con Python y ffmpeg instalados.

Compatible con✓Claude Code✓Codex CLI~Cursor
npx skills add Tofuswang/video-subtitle-skill

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

/video-subtitle — Herramienta de Subtítulos para Video

Transcribe el audio de un video a subtítulos SRT usando un modelo local de Whisper y luego los incrusta en el video.

Invocable por el usuario

Cuando el usuario escribe /video-subtitle, ejecuta esta habilidad.

Prerrequisitos

Esta habilidad requiere dos herramientas. Verifica la disponibilidad antes de proceder:

1. mlx-whisper (Apple Silicon) o openai-whisper

Detecta cuál está disponible:

which mlx_whisper whisper 2>/dev/null

Si no se encuentra ninguno, guía al usuario para instalar uno:

  • Mac con Apple Silicon (recomendado): pip install mlx-whisper
  • Cualquier plataforma: pip install openai-whisper

2. ffmpeg con libass

Verifica el soporte de libass:

ffmpeg -filters 2>&1 | grep subtitles

Si no hay salida (falta libass), el filtro subtitles no está disponible:

  • macOS: brew install ffmpeg-full (solo keg, usa /opt/homebrew/opt/ffmpeg-full/bin/ffmpeg)
  • Linux: sudo apt install ffmpeg (normalmente incluye libass)
  • Alternativa: Si el usuario tiene ffmpeg normal sin libass, incrusta el SRT como pista de subtítulos en lugar de quemarlo.

Selección del modelo Whisper

Descubre los modelos en caché:

ls ~/.cache/huggingface/hub/ 2>/dev/null | grep whisper

Prefiere el modelo más grande disponible. Si no hay ninguno en caché, usa:

  • mlx-whisper: mlx-community/whisper-large-v3-mlx
  • openai-whisper: large-v3

Modos

  • /video-subtitle ruta/al/video.mov → Pipeline completo (transcribir + corregir + quemar)
  • /video-subtitle srt ruta/al/video.mov → Solo SRT (transcribir, sin quemar)
  • /video-subtitle burn ruta/al/video.mov ruta/al/sub.srt → Solo quemar (usar SRT existente)
  • /video-subtitle (sin argumentos) → Interactivo, pedir la ruta del video

Pipeline Completo

Paso 1: Verificar video

Si no se proporciona ruta, preguntar con AskUserQuestion. Confirmar que el archivo existe y leer metadatos:

ffmpeg -i "<ruta_video>" 2>&1 | grep -E "Duration|Stream.*(Video|Audio)"

Informar al usuario sobre duración, resolución y tamaño del archivo.

Paso 2: Extraer audio

ffmpeg -i "<ruta_video>" -vn -acodec pcm_s16le -ar 16000 -ac 1 "<directorio_salida>/<nombre_base>_audio.wav" -y

WAV mono a 16kHz es el formato de entrada óptimo para Whisper.

Paso 3: Confirmar idioma

Preguntar al usuario con AskUserQuestion. Opciones comunes:

IdiomaFlag
Chino--language zh
Inglés--language en
Japonés--language ja
Detección automáticaomitir --language

Paso 4: Transcribir

mlx-whisper:

mlx_whisper --model "<modelo>" --language <idioma> --output-format srt --output-dir "<directorio_salida>" "<audio_wav>"

openai-whisper:

whisper "<audio_wav>" --model large-v3 --language <idioma> --output_format srt --output_dir "<directorio_salida>"

Decir al usuario: "Transcribiendo, por favor espera..."

Paso 5: Limpiar SRT

Leer el SRT generado y corregir:

  1. Eliminar alucinaciones: Borrar entradas con marcas de tiempo de duración cero (ej. 00:00:57,640 --> 00:00:57,640) o texto vacío
  2. Corregir nombres propios: Whisper suele reconocer mal marcas y términos técnicos — usar contexto de la conversación para corregir
  3. Unir fragmentos: Combinar entradas más cortas de 0.5s que estén semánticamente conectadas
  4. Renumerar: Ejecutar este fragmento de Python para renumerar todas las entradas:
python3 -c "
import re
with open('<ruta_srt>', 'r') as f:
    content = f.read()
blocks = re.split(r'\n\n+', content.strip())
out = []
for i, block in enumerate(blocks, 1):
    lines = block.strip().split('\n')
    if len(lines) >= 2:
        lines[0] = str(i)
        out.append('\n'.join(lines))
with open('<ruta_srt>', 'w') as f:
    f.write('\n\n'.join(out) + '\n')
"

Presentar el SRT corregido al usuario y preguntar si se necesitan más ediciones antes de quemar.

Paso 6: Quemar subtítulos

Determinar el binario ffmpeg correcto (preferir ffmpeg-full si ffmpeg normal carece de libass):

FFMPEG="ffmpeg"
if ! ffmpeg -filters 2>&1 | grep -q subtitles; then
  if [ -x /opt/homebrew/opt/ffmpeg-full/bin/ffmpeg ]; then
    FFMPEG="/opt/homebrew/opt/ffmpeg-full/bin/ffmpeg"
  fi
fi

Luego quemar:

$FFMPEG \
  -i "<ruta_video>" \
  -vf "subtitles=<ruta_srt>:force_style='FontSize=24,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,MarginV=30'" \
  -c:v libx264 -preset medium -crf 23 \
  -c:a aac -b:a 128k \
  -pix_fmt yuv420p \
  "<directorio_salida>/<nombre_base>_subtitled.mp4" -y

Opciones de force_style:

ParámetroValor por defectoDescripción
FontSize24Tamaño de fuente
PrimaryColour&H00FFFFFFTexto blanco
OutlineColour&H00000000Contorno negro
Outline2Grosor del contorno
MarginV30Margen inferior

Importante: La ruta del archivo SRT no debe contener caracteres especiales que confundan el analizador de filtros de ffmpeg. Usar rutas relativas o enlaces simbólicos si es necesario.

Paso 7: Finalizado

Informar al usuario sobre la ruta y el tamaño del archivo de salida. Sugerir open <ruta> para previsualizar. Recordar al usuario que el archivo intermedio _audio.wav puede ser eliminado.


Solución de problemas

ProblemaCausaSolución
No such filter: 'subtitles'ffmpeg sin libassUsar ffmpeg-full o instalar libass
No such filter: 'drawtext'ffmpeg sin libfreetypeUsar ffmpeg-full
Entradas SRT duplicadas/vacíasAlucinación de WhisperLimpiar en el Paso 5
Caracteres chinos se muestran como cuadrosFalta fuente CJKmacOS: fallback automático a PingFang. Linux: apt install fonts-noto-cjk
Error parsing filterchainCaracteres especiales en la ruta del SRTUsar ruta relativa, evitar espacios

Reglas de calidad

  • Transcripción fiel: Solo transcribir lo que realmente se dijo — no añadir ni reescribir el significado
  • Corrección de nombres propios: Corregir errores comunes de Whisper, pero confirmar con el usuario
  • Ritmo de subtítulos: Máximo dos líneas por entrada, máximo ~20 caracteres CJK por línea
  • Limpieza: Recordar al usuario eliminar archivos intermedios (_audio.wav) al finalizar

Skills relacionados