Video Skill
Procesa y comparte videos usando ffmpeg, Deepgram Nova 3 y compartición S3/túnel.
Predeterminado: video más ligero, misma resolución
Por defecto, siempre vuelve a codificar a un archivo más pequeño en la resolución original de la fuente. Una copia comprimida a la misma resolución es casi siempre lo que el usuario desea: subidas más rápidas, comparticiones más ligeras, experiencia de visualización idéntica. Conviértelo en el valor predeterminado en cada flujo (silencioso, interactivo y la codificación de reproducción dev-video de Gemini); solo desvíate cuando el usuario lo indique explícitamente. Concretamente:
- Optimización predeterminada =
--resolution keep— vuelve a codificar con libx264 + CRF y sin filtro de escala, así la resolución no cambia y el archivo simplemente se hace más pequeño. Esta es la elección Q1 recomendada y el valor predeterminado del modo silencioso. - Solo reduce la resolución (por ejemplo, a 1080p) cuando la fuente es materialmente más grande que 1080p (≥1440p / 4K) o el usuario lo solicita. Nunca aumentes la resolución.
- Solo omite la recodificación (usa el original sin procesar / copia de flujo) cuando el usuario lo solicite explícitamente — p. ej., "conserva el original", "no recodifiques".
- Verificación de seguridad: tras la codificación, compara el tamaño de salida con la fuente. Si no es significativamente más pequeño (raro — p. ej., una fuente ya de baja tasa de bits), aumenta CRF (26–28) o recurre al original. Las grabaciones de pantalla se comprimen especialmente bien: CRF 24–26 con
preset slowsuele reducir un 70–80 % mientras mantiene el texto nítido. - Botones de descarga: la página muestra un único botón "Download Video" por defecto (apunta al video de reproducción). Solo añade un botón "Download Original" — es decir, pasa
render_page.py --original-filename <name>— cuando realmente subes el original sin procesar a la carpeta de salida con ese nombre exacto; de lo contrario, el botón enlaza a un archivo inexistente y da error 404. El flujo predeterminado de compresión-conservación no mantiene un original separado, así que no pases--original-filename.
Prerrequisitos
ffmpegyffprobedeben estar instalados- Python 3 debe estar disponible
- La CLI de
awsdebe estar disponible (para subidas a S3) - Clave API de Deepgram — para transcripción/subtítulos de audio (motor predeterminado)
- Clave API de OpenRouter — para el motor de análisis Gemini (modos
dev-video/transcript-cheap). Opcional; solo se necesita cuando se seleccionan esos modos.
Directorios
- Scripts:
<skill_dir>/scripts/— todos los scripts de Python y la plantilla player.html - Credenciales:
~/.config/video-skill/— persistente entre actualizaciones del plugindeepgram_token— clave API de Deepgram en una líneaopenrouter_token— clave API de OpenRouter en una línea (motor de análisis Gemini)s3_credentials— formato clave=valor (endpoint, bucket, access_key, secret_key)
- Preferencias:
~/.config/video-skill/preferences.json— elecciones del usuario guardadas entre sesiones
Configuración de credenciales
Si faltan credenciales cuando se necesitan, pregunta al usuario mediante AskUserQuestion:
Deepgram: Verifica la variable de entorno DEEPGRAM_API_KEY, luego el archivo ~/.config/video-skill/deepgram_token. Si ninguno existe, pregunta al usuario y guarda en el archivo.
OpenRouter: Verifica la variable de entorno OPENROUTER_TOKEN, luego el archivo ~/.config/video-skill/openrouter_token. Solo necesario para los modos de análisis dev-video/transcript-cheap. Si se selecciona un modo Gemini y falta el token, pregunta al usuario y guarda en el archivo.
S3: Verifica las variables de entorno (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_ENDPOINT, S3_BUCKET), luego ~/.config/video-skill/s3_credentials. Si faltan, pregunta al usuario por endpoint, bucket, access_key, secret_key y guarda.
Importante: Nunca pases credenciales como argumentos de CLI. Los scripts las leen internamente desde archivos mediante --credential-dir ~/.config/video-skill.
Preferencias
{
"language": "en",
"last_folder": "/Users/example/screencasts",
"share_folder": "/Users/example/screencasts",
"sharing_method": "s3",
"optimization": "compress-keep",
"crf": 23,
"preset": "medium",
"audio": "aac-128k",
"subtitles": "track",
"subtitle_style": "modern",
"subtitle_font": "Helvetica Neue",
"target_language": "ru",
"download_button": true,
"passcode": true,
"mode": "subtitles"
}
optimization: cómo se codifica el video de reproducción. El valor predeterminado compress-keep = recodificar más ligero a la resolución original (--resolution keep). Otros valores: web-1080p (reducir a 1080p — para fuentes ≥1440p/4K), custom, keep-original (sin recodificación — solo por solicitud explícita del usuario). Consulta "Predeterminado: video más ligero, misma resolución" arriba.
mode: un solo campo que decide el motor de transcripción/análisis. Uno de cuatro valores (el antiguo par analysis_mode + developer_analysis se fusiona en esto):
mode | Motor | Subtítulos | Análisis de desarrollador | Cuándo usarlo |
|---|---|---|---|---|
subtitles (predeterminado) | Deepgram | precisos | no | compartir normal, solo quiero subtítulos |
dev-audio | Deepgram | precisos | sí (del texto de la transcripción) | feedback de herramienta/error, quiero subtítulos limpios también |
dev-video | Gemini video | aproximados | sí + capturas de pantalla | feedback de herramienta/UX más rico (lee la pantalla) |
transcript-cheap | Gemini audio | aproximados | no | transcripción aproximada barata, sincronización no crítica |
Internamente: subtitles/dev-audio ejecutan process_and_share.py (el último con --developer-analysis); dev-video/transcript-cheap ejecutan el motor de Gemini (gemini_analyze.py). "Análisis de desarrollador" = el bloque de análisis en la página más el artefacto Markdown de análisis (consulta esa sección). Guía del motor (investigación 2026-06): mantén Deepgram para subtítulos precisos; usa Gemini-video para análisis, Gemini-audio para transcripciones aproximadas baratas. Para dev-video, donde también importan los subtítulos precisos, ejecuta adicionalmente una pasada de Deepgram para la pista.
Guardado: Después de cada elección interactiva, actualiza preferences.json. Siempre guarda last_folder después de cada ejecución.
Carga: Lee al inicio. Usa los valores guardados como valores predeterminados "(Recomendado)". En modo silencioso, úsalos directamente.
Referencia de scripts
Todos los scripts están en <skill_dir>/scripts/. Aceptan --credential-dir para credenciales e imprimen líneas [PROGRESS] para seguimiento de estado.
| Script | Propósito | Argumentos clave |
|---|---|---|
process_and_share.py | Flujo principal: optimizar + transcribir + renderizar + subir | ` --output-dir --share-folder --share s3 |
share_existing.py | Compartir una carpeta ya procesada | ` --share-folder --share s3 |
upload_s3.py | Subir carpeta a S3 | <folder> --key <key> --credential-dir |
render_page.py | Generar index.html a partir de plantilla | --output-dir --template --metadata |
manage_registry.py | CRUD del registro (añadir/eliminar/listar/obtener/migrar) | <subcommand> --share-folder |
partial_update.py | Re-renderizar + re-subir una carpeta compartida (resuelve clave del registro, reenvía código de acceso) | <output_folder> [--key] |
font_name.py | Imprimir el nombre de familia interno de un TTF (para Fontname de ASS) | <font.ttf> |
transcribe.py | Transcripción de Deepgram → SRT + VTT | <video> --credential-dir [--language] |
gemini_analyze.py | Motor Gemini: transcripción de audio O análisis de video + capturas de pantalla | ` --mode audio |
burn_subtitles.py | Quemar subtítulos en el video | <video> <srt> [--font --fontsize ...] |
share_server.py | Servidor HTTP local para compartición por túnel | <share_root> [--port] |
Flujo de trabajo
Paso 0: Analizar argumentos y detectar modo
Comandos:
/video→ Modo interactivo (Pasos 1-5)/video process <ruta>→ Modo interactivo para un archivo específico/video share→ Modo silencioso: procesa el último + comparte/video share <ruta>→ Modo silencioso: procesa archivo específico + comparte/video share <ruta> "contexto"→ Modo silencioso con contexto adicional para metadatos/video start→ Iniciar servidor de compartición + túnel/video stop→ Detener compartición/video status→ Listar videos compartidos/video copy <clave_o_nombre>→ Copiar enlace + código de acceso al portapapeles/video remove <clave_o_nombre>→ Eliminar del registro
Comandos de compartición (manejados directamente, sin procesamiento)
Registro de compartición: <share_folder>/.share_registry.json — gestionado por manage_registry.py.
Comando start:
- Leer preferencias →
share_folder. Si no está configurado, preguntar. - Verificar
pgrep -f share_server.py. Si se está ejecutando, mostrar estado. - Iniciar servidor:
python3 "<scripts>/share_server.py" "<share_folder>" --port 8080 & - Iniciar túnel:
ssh -p 443 -R0:localhost:<port> -o StrictHostKeyChecking=no a.pinggy.io 2>&1 & - Analizar URL del túnel. Mostrar: "Server running at <base_url>"
- Listar videos existentes con URLs completas (
<base_url>/v/<key>).
Comando stop:
pkill -f share_server.py; pkill -f "ssh.*pinggy"; pkill -f "ngrok http"
Comando status:
- Ejecutar
python3 "<scripts>/manage_registry.py" list --share-folder "<share_folder>" - Verificar
pgrep -f share_server.pypara estado del túnel. - Mostrar tabla: clave, título, URL S3, URL túnel, código de acceso, creado.
Comando copy:
- Ejecutar
python3 "<scripts>/manage_registry.py" get --share-folder "<share_folder>" --key "<consulta>" - Formatear:
<title>\n<url>\nPasscode: <code>→pbcopy
Comando remove:
Ejecutar python3 "<scripts>/manage_registry.py" remove --share-folder "<share_folder>" --key "<consulta>"
Modo silencioso (/video share)
Una confirmación, una ejecución de script, interacción mínima.
Flujo:
-
Identificar video (ruta del argumento o el más reciente en
last_folder/ directorio actual) -
Crear carpeta de salida
<share_folder>/<video_name>/ -
Generar código de acceso (6 dígitos aleatorios o preferencia guardada)
-
Mostrar confirmación:
Quick share: demo.mov → misma resolución · comprimido (CRF 23) · AAC 128k → Transcribir + subtítulos (pista) → Compartir mediante S3 (enlace permanente) → Código de acceso: 482910 ¿Continuar?Opciones: Continuar (Recomendado) / Cambiar a modo interactivo
Si
modeesdev-videootranscript-cheap, no ejecutesprocess_and_share.py— sigue la sección "Motor de análisis Gemini" en su lugar (silenciosamente, usando preferencias guardadas), luego aún sube + registra la compartición. -
Ejecutar el script del flujo principal. Pasa
--developer-analysiscuandomodeesdev-audio:python3 "<scripts>/process_and_share.py" "<video_path>" \ --output-dir "<output_folder>" \ --share-folder "<share_folder>" \ --credential-dir ~/.config/video-skill \ --resolution keep --crf 23 --preset medium --audio aac-128k \ --subtitles track \ --share s3 \ --passcode "<passcode>" \ [--developer-analysis] \ [--context "<user_context>"]Valor predeterminado
--resolution keep(comprimir, misma resolución). Usa--resolution 1080psolo si la fuente es ≥1440p/4K, o manejokeep-originalsi el usuario quiere explícitamente el archivo sin procesar. -
Monitorear stdout para
METADATA_READY:— cuando el script imprime este marcador: a. LeerTRANSCRIPT_PREVIEW:yMETADATA_INFO:que lo preceden. b. Generar título, descripción y 4-8 capítulos a partir de la vista previa de la transcripción. c. Simodeesdev-audio(análisis de desarrollador activado): construir el bloque de análisis y el Markdown de análisis a partir de la transcripción completa (leer el SRT/VTT en el directorio de salida, no la vista previa truncada). Consulta las secciones "referencia de metadata.json" y "Markdown de análisis" para la forma exacta y el contrato. Coincide con el idioma de la página (RU / DE / EN). d. Escribirmetadata.jsonen el directorio de salida según la referencia de metadata.json. e. El script detecta metadata.json y continúa automáticamente. -
El script finaliza. Muestra el resultado, l