Communitygithub.com

Vidéo récapitulative d'événement

Transformez un tas de photos/vidéos de votre téléphone issues d'un événement (conférence, voyage, retraite, mariage) en une vidéo récapitulative attrayante avec ffmpeg — un montage principal 16:9, une version 9:16 et un reel de ~45 s synchronisé sur le rythme.

Qu'est-ce que Vidéo récapitulative d'événement ?

Ce skill transforme une collection brute de photos et vidéos prises lors d'un événement en une vidéo récapitulative soignée, prête à être partagée. Il produit trois formats : un montage principal horizontal 16:9, une version verticale 9:16 pour les réseaux sociaux, et un reel court (~45 secondes) synchronisé sur le rythme de la musique. Le skill gère l'ensemble du flux de travail : analyse des fichiers bruts (EXIF, flou, luminosité, doublons, loudness), sélection guidée via des planches-contact, montage rythmé avec coupures dynamiques, et rendu final avec normalisation audio (loudnorm −14 LUFS). Il est testé de bout en bout sur une bibliothèque de 780 éléments et nécessite ffmpeg/ffprobe ainsi que Python 3.10+. Les fonctionnalités avancées incluent la synchronisation des coupes sur le temps, le ducking automatique de la musique sous les discours, et la création de reels optimisés pour les plateformes sociales. Le skill peut également extraire les médias depuis Google Photos via CDP, et propose un rendu alternatif pour les versions muettes ou sans musique afin d'éviter les problèmes de droits d'auteur.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/binay-py/claude-skills/tree/HEAD/skills/event-recap-video

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Que fait Vidéo récapitulative d'événement ?

Testé de bout en bout sur une bibliothèque de 780 éléments. Nécessite ffmpeg/ffprobe dans le PATH et Python 3.10+ avec pip install pillow pillow-heif numpy.

Les scripts se trouvent à côté de ce fichier. Copiez-les dans le projet :

  • scripts/analyze.py, build.py, reel.py, motion.py, fonts.py → racine du projet
  • scripts/work/*.py → <projet>/work/
  • examples/*.json → racine du projet, puis modifiez-les

Structure du projet : raw/ (originaux non modifiés), music/, work/ (cache), output/, edit.json (le montage complet). Les polices sont trouvées automatiquement sur Windows/macOS/Linux ; remplacez avec FONT_SERIF, FONT_SERIF_BOLD, FONT_SANS_BOLD, FONT_BLACK, FONT_EMOJI.

1. Obtenir les médias

  • Placez chaque export/zip dans son propre dossier sous raw/. Ne modifiez jamais les originaux.
  • Google Photos n'a pas d'API pour une bibliothèque existante : pilotez le navigateur connecté de l'utilisateur via CDP (voir le skill brave-cdp dans ce dépôt). Les éléments de la grille sont a[href*="/photo/"] ; les en-têtes de jour sont [role=checkbox][aria-label^="Select all photos from"].
  • Sélectionnez les en-têtes de jour avec de VRAIS événements souris (Input.dispatchMouseEvent), vérifiez le texte "N selected", appuyez sur Shift+D. L'onglet doit être au premier plan (Page.bringToFront) sinon la grille reste grise.
  • Google efface la sélection après un téléchargement et l'attribut aria-checked des en-têtes peut devenir obsolète ; rechargez avant de resélectionner.
  • Browser.setDownloadBehavior avec allowAndName enregistre le zip sous son GUID sans extension ; surveillez Browser.downloadProgress pour l'état completed.

2. Analyser et choisir

  • python analyze.py → work/media.json (heure de capture depuis EXIF / creation_time vidéo en fuseau horaire local, flou, luminosité, doublons, loudness) + planches-contact par jour dans work/sheets/.
  • python work/vsheets.py → bandes de 3 images par vidéo. REGARDEZ chaque planche. Ignorez les clips qui tournent pendant l'enregistrement, les plans de poche et les clips de nuit sombres.
  • python work/loudest.py ID:secondes ... trouve la fenêtre la plus forte (chant, discours, acclamations). Vérifiez avec une bande d'images à 1 ips avant de recadrer.
  • Les fichiers partagés/transférés n'ont pas de date de capture (retour à la date de modification) — placez-les manuellement.

3. Montage (ce que le public a aimé)

  • Commencez par la VIDÉO (~90% des clips) ; les photos uniquement pour les plans de groupe forts. Les montages chargés en photos semblent lents.
  • Accroche d'ouverture : 8–10 clips de 1,2–1,8 s, hook_xf 0,1 coupures quasi-sèches, puis le carton titre. Ensuite, les jours dans l'ordre avec un petit "label": "Jour N · date" sur le premier clip de chaque jour, coupures de 3–4 s, et quelques moments de 9–12 s marqués "speech": true (la musique baisse sous eux).
  • La musique fait ou défait l'accroche. Enchaînez 2 morceaux de tempo similaire ("music": [a, b], fondu enchaîné de 3 s) plutôt que d'en boucler un seul. python work/bpm.py fichier.mp3 estime le tempo.
  • Clés de edit.json : title, subtitle, closing, closing_sub, title_bg / closing_bg (+ _bg_at pour les ids vidéo), music / vertical_music, music_volume, duck_volume, ambient_volume, photo_seconds, hook_xf, closing_seconds, horizontal_hook, horizontal, vertical_hook, vertical. Segment : {"id", "at" (centre 0–1) | "start", "dur", "speech", "label", "xf"}.
  • python work/shortlist.py → output/shortlist.jpg (une image à chaque coupure). Montrez-la à l'utilisateur avant de rendre.

4. Rendu et contrôle qualité

  • python build.py [horizontal|vertical|vertical-full] — cache par segment dans work/seg, chaîne xfade, loudnorm −14 LUFS, x264.
  • EDIT=autre.json OUT_SUFFIX=-v2 python build.py rend un montage alternatif sans toucher au principal.
  • Contrôle qualité de chaque rendu : nb_frames == duration*30 (les chaînes xfade peuvent perdre des images), nombre de blackdetect = 0, ebur128 ≈ −14 LUFS, et une planche d'images (fps=1/5,tile=8x6) pour vérifier la rotation et les titres coupés.
  • ffmpeg 7+ préfère -/filter_complex file au -filter_complex_script déprécié.

5. Reel synchronisé sur le rythme (IG / TikTok / FB) — reel.py + reel.json

  • python reel.py → output/reel.mp4 (~45 s), construit sur le renderer de segments de build.py.
  • Les coupures tombent exactement sur la grille de temps (bpm indice, phase automatique, temps de coupure arrondis à l'image). Vérifiez le tempo : les estimateurs naïfs renvoient souvent la moitié/double (85 vs 154).
  • Première seconde = le moment le plus surprenant, avec une ligne "POV: …". Coupures de 4 temps, 6–8 temps sur les moments forts, léger zoom avant sur chaque clip, flash blanc au début des sections.
  • Texte : sans sérif gras, blanc avec contour noir épais, ~24% depuis le haut (hors des boutons TikTok/IG), apparition glissée avec fondu. 5–7 lignes courtes au total ; la dernière est le nom de l'événement.

6. Coupe mème / mouvement — motion.py + motion.json (uniquement si l'utilisateur demande des mèmes/autocollants)

  • Beaucoup trouvent ce style trop chargé pour un événement sincère. Par défaut, utilisez les sections 3–5.
  • Une seule piste longue et stable (~3 min) au lieu d'enchaîner ; grille de temps via recherche par filtre en peigne.
  • Par clip : beats, speed (0,5 ralenti / 2 avance rapide), freeze (temps ; arrêt sur bande + silence + désaturation), autocollant cap (boîte arrondie, inclinaison, pop élastique, emoji couleur), titres day percutants + whoosh, title, verse, shake, punch, flash, zoom.
  • Si un rendu est tué, supprimez les fichiers de clip qui échouent à ffprobe avant de relancer (le cache les réutiliserait).

7. Livraison verticale et pour les réseaux sociaux

  • Lorsque quelqu'un approuve le montage 16:9 et demande du 9:16, donnez-lui le MÊME montage en vertical (python build.py vertical-full). Ne restylez pas un montage approuvé ; « rendez-le plus attrayant » signifie seulement peaufiner.
  • Les plateformes (surtout Facebook) coupent le son des publications avec de la musique non licenciée. Proposez une version son original (un montage avec "music": null) et/ou une copie silencieuse (ffmpeg -i in.mp4 -an -c copy out.mp4) pour que la musique puisse être ajoutée depuis la bibliothèque licenciée de la plateforme.
  • Polissage final : eq=contrast=1.07:saturation=1.2:gamma=0.97,colorbalance=rm=0.03:bm=-0.03:rh=0.02:bh=-0.02,unsharp=5:5:0.45,vignette=angle=PI/5.5 + audio highpass=80,dynaudnorm,acompressor,loudnorm=I=-14.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Skills associés