Compétence Vidéo
Traitez et partagez des vidéos en utilisant ffmpeg, Deepgram Nova 3 et S3/partage par tunnel.
Par défaut : vidéo plus légère, même résolution
Toujours ré-encoder en un fichier plus petit à la résolution source par défaut. Une copie compressée à la même résolution est presque toujours ce que l'utilisateur souhaite : téléchargements plus rapides, partages plus légers, expérience visuelle identique. Faites-en la valeur par défaut dans chaque flux (silencieux, interactif, et le codage de lecture dev-video de Gemini) ; ne dérogez que si l'utilisateur le demande explicitement. Concrètement :
- Optimisation par défaut =
--resolution keep— ré-encoder avec libx264 + CRF et aucun filtre d'échelle, de sorte que la résolution reste inchangée et que le fichier devienne simplement plus petit. C'est le choix Q1 recommandé et la valeur par défaut en mode silencieux. - Ne réduire la résolution (par exemple en 1080p) que si la source est matériellement plus grande que 1080p (≥1440p / 4K) ou si l'utilisateur le demande. Ne jamais augmenter la résolution.
- Ne sauter le ré-encodage (utiliser l'original non touché / copie de flux) que si l'utilisateur demande explicitement l'original — par exemple « garder l'original », « ne pas ré-encoder ».
- Vérification de sécurité : après le codage, comparer la taille de sortie à la source. Si elle n'est pas significativement plus petite (rare — par exemple une source déjà à faible débit), augmentez le CRF (26–28) ou revenez à l'original. Les enregistrements d'écran se compressent particulièrement bien : CRF 24–26 avec
preset slowréduit régulièrement de 70 à 80 % tout en gardant le texte à l'écran net. - Boutons de téléchargement : la page affiche un seul bouton « Télécharger la vidéo » par défaut (il pointe vers la vidéo de lecture). N'ajoutez un bouton « Télécharger l'original » — c'est-à-dire passez
render_page.py --original-filename <nom>— que si vous téléchargez réellement l'original non touché dans le dossier de sortie sous ce nom exact ; sinon le bouton renvoie à un fichier manquant et génère une erreur 404. Le flux de compression par défaut ne conserve pas d'original séparé, donc ne passez pas--original-filename.
Prérequis
ffmpegetffprobedoivent être installés- Python 3 doit être disponible
- La CLI
awsdoit être disponible (pour les téléchargements S3) - Clé API Deepgram — pour la transcription audio / les sous-titres (moteur par défaut)
- Clé API OpenRouter — pour le moteur d'analyse Gemini (modes
dev-video/transcript-cheap). Optionnel ; nécessaire uniquement lorsque ces modes sont sélectionnés.
Répertoires
- Scripts :
<skill_dir>/scripts/— tous les scripts Python et le modèle player.html - Identifiants :
~/.config/video-skill/— persistants lors des mises à jour du plugindeepgram_token— clé API Deepgram sur une seule ligneopenrouter_token— clé API OpenRouter sur une seule ligne (moteur d'analyse Gemini)s3_credentials— format clé=valeur (endpoint, bucket, access_key, secret_key)
- Préférences :
~/.config/video-skill/preferences.json— choix utilisateur sauvegardés entre les sessions
Configuration des identifiants
Si des identifiants manquent quand ils sont nécessaires, demandez à l'utilisateur via AskUserQuestion :
Deepgram : Vérifiez la variable d'environnement DEEPGRAM_API_KEY, puis le fichier ~/.config/video-skill/deepgram_token. Si aucun n'existe, demandez à l'utilisateur et sauvegardez dans le fichier.
OpenRouter : Vérifiez la variable d'environnement OPENROUTER_TOKEN, puis le fichier ~/.config/video-skill/openrouter_token. Nécessaire uniquement pour les modes d'analyse dev-video / transcript-cheap. Si un mode Gemini est sélectionné et que le jeton est manquant, demandez à l'utilisateur et sauvegardez dans le fichier.
S3 : Vérifiez les variables d'environnement (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_ENDPOINT, S3_BUCKET), puis ~/.config/video-skill/s3_credentials. Si manquants, demandez à l'utilisateur le endpoint, bucket, access_key, secret_key et sauvegardez.
Important : Ne jamais passer les identifiants comme arguments CLI. Les scripts les lisent depuis les fichiers en interne via --credential-dir ~/.config/video-skill.
Préférences
{
"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 : comment la vidéo de lecture est encodée. Par défaut compress-keep = ré-encoder plus léger à la résolution source (--resolution keep). Autres valeurs : web-1080p (réduire en 1080p — pour les sources ≥1440p/4K), custom, keep-original (pas de ré-encodage — uniquement sur demande explicite de l'utilisateur). Voir « Par défaut : vidéo plus légère, même résolution » ci-dessus.
mode : un champ unique qui décide du moteur de transcription/analyse. L'une des quatre valeurs suivantes (l'ancienne paire analysis_mode + developer_analysis est fusionnée en celle-ci) :
mode | Moteur | Sous-titres | Analyse développeur | Quand l'utiliser |
|---|---|---|---|---|
subtitles (défaut) | Deepgram | précis | non | partage normal, juste des légendes |
dev-audio | Deepgram | précis | oui (à partir du texte transcrit) | feedback outil/bogue, vouloir aussi des légendes propres |
dev-video | Gemini vidéo | grossier | oui + captures d'écran | feedback outil/UX le plus riche (lit l'écran) |
transcript-cheap | Gemini audio | grossier | non | transcription approximative bon marché, timing non critique |
En interne : subtitles/dev-audio exécutent process_and_share.py (le second avec --developer-analysis) ; dev-video/transcript-cheap exécutent le moteur Gemini (gemini_analyze.py). « Analyse développeur » = le bloc d'analyse dans la page plus l'artefact Markdown d'analyse (voir cette section). Recommandations moteur (recherche 2026-06) : gardez Deepgram pour les sous-titres précis ; utilisez Gemini-vidéo pour l'analyse, Gemini-audio pour les transcriptions approximatives bon marché. Pour dev-video où les légendes précises comptent aussi, exécutez en plus un passage Deepgram pour la piste.
Sauvegarde : Après chaque choix interactif, mettez à jour preferences.json. Toujours sauvegarder last_folder après chaque exécution.
Chargement : Lire au démarrage. Utiliser les valeurs sauvegardées comme valeurs par défaut « (Recommandé) ». En mode silencieux, les utiliser directement.
Référence des scripts
Tous les scripts se trouvent dans <skill_dir>/scripts/. Ils acceptent --credential-dir pour les identifiants et impriment des lignes [PROGRESS] pour le suivi de statut.
| Script | Objectif | Arguments clés |
|---|---|---|
process_and_share.py | Flux principal : optimiser + transcrire + rendre + télécharger | <video> --output-dir --share-folder --share s3|tunnel |
share_existing.py | Partager un dossier pré-traité | <folder> --share-folder --share s3|tunnel |
upload_s3.py | Télécharger un dossier vers S3 | <folder> --key <key> --credential-dir |
render_page.py | Générer index.html à partir du modèle | --output-dir --template --metadata |
manage_registry.py | CRUD du registre (ajouter/supprimer/lister/obtenir/migrer) | <subcommand> --share-folder |
partial_update.py | Re-rendre + re-télécharger un dossier partagé (résout la clé depuis le registre, transmet le code d'accès) | <output_folder> [--key] |
font_name.py | Afficher le nom de famille interne d'un TTF (pour ASS Fontname) | <font.ttf> |
transcribe.py | Transcription Deepgram → SRT + VTT | <video> --credential-dir [--language] |
gemini_analyze.py | Moteur Gemini : transcription audio OU analyse vidéo + captures d'écran | <video> --mode audio|video --output-dir --credential-dir [--key] |
burn_subtitles.py | Incruster les sous-titres dans la vidéo | <video> <srt> [--font --fontsize ...] |
share_server.py | Serveur HTTP local pour le partage par tunnel | <share_root> [--port] |
Flux de travail
Étape 0 : Analyser les arguments et détecter le mode
Commandes :
/video→ Mode interactif (Étapes 1-5)/video process <chemin>→ Mode interactif pour un fichier spécifique/video share→ Mode silencieux : traiter le dernier + partager/video share <chemin>→ Mode silencieux : traiter un fichier spécifique + partager/video share <chemin> "contexte"→ Mode silencieux avec contexte supplémentaire pour les métadonnées/video start→ Démarrer le serveur de partage + tunnel/video stop→ Arrêter le partage/video status→ Lister les vidéos partagées/video copy <clé_ou_nom>→ Copier le lien + code d'accès dans le presse-papiers/video remove <clé_ou_nom>→ Supprimer du registre
Commandes de partage (traitées directement, sans traitement)
Registre de partage : <share_folder>/.share_registry.json — géré par manage_registry.py.
Commande start :
- Lire les préférences →
share_folder. Si non défini, demander. - Vérifier
pgrep -f share_server.py. Si en cours d'exécution, afficher le statut. - Démarrer le serveur :
python3 "<scripts>/share_server.py" "<share_folder>" --port 8080 & - Démarrer le tunnel :
ssh -p 443 -R0:localhost:<port> -o StrictHostKeyChecking=no a.pinggy.io 2>&1 & - Analyser l'URL du tunnel. Afficher : « Serveur en cours d'exécution à <base_url> »
- Lister les vidéos existantes avec les URLs complètes (
<base_url>/v/<key>).
Commande stop :
pkill -f share_server.py; pkill -f "ssh.*pinggy"; pkill -f "ngrok http"
Commande status :
- Exécuter
python3 "<scripts>/manage_registry.py" list --share-folder "<share_folder>" - Vérifier
pgrep -f share_server.pypour le statut du tunnel. - Afficher un tableau : clé, titre, URL S3, URL tunnel, code d'accès, créé.
Commande copy :
- Exécuter
python3 "<scripts>/manage_registry.py" get --share-folder "<share_folder>" --key "<requête>" - Formater :
<titre>\n<url>\nCode d'accès : <code>→pbcopy
Commande remove :
Exécuter python3 "<scripts>/manage_registry.py" remove --share-folder "<share_folder>" --key "<requête>"
Mode silencieux (/video share)
Une confirmation, une exécution de script, interaction minimale.
Flux :
-
Identifier la vidéo (chemin d'argument ou la plus récente dans
last_folder/ répertoire courant) -
Créer le dossier de sortie
<share_folder>/<nom_vidéo>/ -
Générer un code d'accès (aléatoire à 6 chiffres ou préférence sauvegardée)
-
Afficher la confirmation :
Partager rapidement : demo.mov → même résolution · compressé (CRF 23) · AAC 128k → Transcrire + sous-titres (piste) → Partager via S3 (lien permanent) → Code d'accès : 482910 Continuer ?Options : Continuer (Recommandé) / Passer en mode interactif
Si
modeestdev-videooutranscript-cheap, ne pas exécuterprocess_and_share.py— suivre plutôt la section « Moteur d'analyse Gemini » (en silence, en utilisant les préférences sauvegardées), puis toujours télécharger + enregistrer le partage. -
Exécuter le script de flux principal. Passer
--developer-analysislorsquemodeestdev-audio:python3 "<scripts>/process_and_share.py" "<chemin_vidéo>" \ --output-dir "<dossier_sortie>" \ --share-folder "<dossier_partage>" \ --credential-dir ~/.config/video-skill \ --resolution keep --crf 23 --preset medium --audio aac-128k \ --subtitles track \ --share s3 \ --passcode "<code_accès>" \ [--developer-analysis] \ [--context "<contexte_utilisateur>"]--resolution keeppar défaut (compresser, même résolution). Utiliser--resolution 1080puniquement si la source est ≥1440p/4K, ou la gestionkeep-originalsi l'utilisateur veut explicitement le fichier non touché. -
Surveiller stdout pour
METADATA_READY:— lorsque le script imprime ce marqueur : a. Lire lesTRANSCRIPT_PREVIEW:etMETADATA_INFO:qui l'ont précédé. b. Générer le titre, la description et 4 à 8 chapitres à partir de l'aperçu de la transcription. c. Simodeestdev-audio(analyse développeur activée) : construire le bloc d'analyse et le Markdown d'analyse à partir de la transcription complète (lire les fichiers SRT/VTT dans le dossier de sortie, pas l'aperçu tronqué). Voir les sections « Référence metadata.json » et « Markdown d'analyse » pour la forme exacte et le contrat. Adapter la langue de la page (RU / DE / EN). d. Écriremetadata.jsondans le dossier de sortie conformément à la référence metadata.json. e. Le script détecte metadata.json et continue automatiquement. -
Le script se termine. Afficher le résultat, lien...
(Le contenu a été tronqué par l'entrée, mais a été localisé jusqu'au point de troncature.)