diff --git a/docs/superpowers/plans/2026-08-31-stopmotion-script.md b/docs/superpowers/plans/2026-08-31-stopmotion-script.md index 0de63c1..a6cbb53 100644 --- a/docs/superpowers/plans/2026-08-31-stopmotion-script.md +++ b/docs/superpowers/plans/2026-08-31-stopmotion-script.md @@ -31,7 +31,7 @@ - Consumes: rien (première tâche). - Produces: script exécutable avec variables globales `INPUT`, `OUTPUT`, `FPS`, `SIZE`, `ASSUME_YES` (définies par `getopts` et validées), fonction `usage`. Task 2 appende la logique après les garde-fous. -- [ ] **Step 1 : Écrire le squelette du script** +- [x] **Step 1 : Écrire le squelette du script** Créer `stopmotion.sh` avec exactement ce contenu : @@ -93,13 +93,13 @@ if [ ! -d "$INPUT" ]; then fi ``` -- [ ] **Step 2 : Rendre le script exécutable** +- [x] **Step 2 : Rendre le script exécutable** ```bash chmod +x stopmotion.sh ``` -- [ ] **Step 3 : Tester l'aide et les erreurs** +- [x] **Step 3 : Tester l'aide et les erreurs** ```bash ./stopmotion.sh -h @@ -141,7 +141,7 @@ Attendu : `Erreur : ffmpeg est introuvable. Installation : brew install ffmpeg`, ``` Attendu : `Erreur : le dossier d'images 'dossier_inexistant' n'existe pas.`, `exit=1`. -- [ ] **Step 4 : Commit** +- [x] **Step 4 : Commit** ```bash git add stopmotion.sh @@ -159,7 +159,7 @@ git commit -m "feat: squelette stopmotion.sh (options, validation, garde-fous)" - Consumes: variables `INPUT`, `OUTPUT`, `FPS`, `SIZE`, `ASSUME_YES` et fonction `usage` définies en Task 1 (noms exacts). - Produces: script complet conforme à la spec ; sortie vidéo MP4 encodée + message récapitulatif `Vidéo créée : ( images, fps, s, )`. -- [ ] **Step 1 : Ajouter la découverte des images et la gestion d'écrasement** +- [x] **Step 1 : Ajouter la découverte des images et la gestion d'écrasement** Après la ligne `fi` du garde-fou sur `$INPUT` (fin de Task 1), ajouter : @@ -186,7 +186,7 @@ if [ -e "$OUTPUT" ] && [ "$ASSUME_YES" -ne 1 ]; then fi ``` -- [ ] **Step 2 : Ajouter la génération ffconcat et l'encodage** +- [x] **Step 2 : Ajouter la génération ffconcat et l'encodage** À la suite, ajouter : @@ -198,7 +198,6 @@ trap 'rm -f "$LIST_FILE"' EXIT quote_ffconcat() { local s=$1 - s=${s//\\/\\\\} s=${s//\'/\'\\\'\'} printf "file '%s'\n" "$s" } @@ -228,7 +227,7 @@ SIZE_HUMAN=$(du -h "$OUT_DIR/$OUT_NAME" | cut -f1 | tr -d ' ') echo "Vidéo créée : $OUT_NAME ($COUNT images, ${FPS} fps, ${DURATION_VIDEO} s, ${SIZE_HUMAN})" ``` -- [ ] **Step 3 : Tester le scénario de référence** +- [x] **Step 3 : Tester le scénario de référence** ```bash ./stopmotion.sh -y -o test_output.mp4; echo "exit=$?" @@ -249,7 +248,7 @@ ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames -of default= ``` Attendu : `42` (identique au test_output.mp4). -- [ ] **Step 4 : Tester le refus d'écrasement** +- [x] **Step 4 : Tester le refus d'écrasement** ```bash before=$(stat -f %m test_output.mp4) @@ -259,7 +258,7 @@ after=$(stat -f %m test_output.mp4) ``` Attendu : prompt `'test_output.mp4' existe déjà. L'écraser ? [o/N]`, puis `Abandon.`, `exit=0`, `fichier intact`. -- [ ] **Step 5 : Tester les erreurs de dossier de sortie et dossier vide** +- [x] **Step 5 : Tester les erreurs de dossier de sortie et dossier vide** ```bash ./stopmotion.sh -y -o dossier_inexistant/out.mp4; echo "exit=$?" @@ -271,14 +270,14 @@ mkdir -p /tmp/stopmotion_vide && ./stopmotion.sh -y -i /tmp/stopmotion_vide -o t ``` Attendu : `Erreur : aucune image (jpg, jpeg, png, heic) trouvée dans '/tmp/stopmotion_vide'.`, `exit=1`. -- [ ] **Step 6 : Vérifier le nettoyage du fichier temporaire** +- [x] **Step 6 : Vérifier le nettoyage du fichier temporaire** ```bash ls -a | grep -c '^\.stopmotion\.' || echo "aucun fichier temporaire résiduel" ``` Attendu : `aucun fichier temporaire résiduel` (le trap EXIT a supprimé la liste ffconcat). -- [ ] **Step 7 : Nettoyer et commit** +- [x] **Step 7 : Nettoyer et commit** ```bash rm -f test_output.mp4 diff --git a/docs/superpowers/specs/2026-08-31-stopmotion-script-design.md b/docs/superpowers/specs/2026-08-31-stopmotion-script-design.md index ba87522..d70ab3e 100644 --- a/docs/superpowers/specs/2026-08-31-stopmotion-script-design.md +++ b/docs/superpowers/specs/2026-08-31-stopmotion-script-design.md @@ -39,6 +39,8 @@ Objectif : un script réutilisable pour regénérer la vidéo depuis n'importe q 5. Encode avec ffmpeg : `-f concat -safe 0`, `libx264`, `yuv420p`, `-movflags +faststart`, `-r FPS`, filtre `scale=S:S:force_original_aspect_ratio=decrease:force_divisible_by=2`. 6. Affiche un récapitulatif : nombre d'images, fps, durée de la vidéo, taille du fichier de sortie. +Pour des fps élevés (ex. `-f 30`), le mapping CFR peut dupliquer une image (arrondi au créneau le plus proche face à la timebase 1/25 des HEIC) sans jamais en perdre ; les valeurs `-f` 12/15/20/24 ont été vérifiées exactes sur le corpus de référence. + ## Gestion des erreurs - Options inconnues ou valeur manquante → usage + exit 1. diff --git a/stopmotion.sh b/stopmotion.sh index e580ce6..8cb46b2 100755 --- a/stopmotion.sh +++ b/stopmotion.sh @@ -36,6 +36,8 @@ while getopts ":i:o:f:s:yh" opt; do esac done +OUTPUT=${OUTPUT%/} + if ! [[ $FPS =~ ^[0-9]+([.][0-9]+)?$ ]] || ! awk -v f="$FPS" 'BEGIN{exit !(f>0)}'; then echo "Erreur : -f doit être un nombre strictement positif (reçu : $FPS)" >&2 exit 1 @@ -82,7 +84,6 @@ trap 'rm -f "$LIST_FILE"' EXIT quote_ffconcat() { local s=$1 - s=${s//\\/\\\\} s=${s//\'/\'\\\'\'} printf "file '%s'\n" "$s" }