Files
RoadTripsGenerator/Scripts/extraction_infos.sh
T
FabriceandClaude Opus 5.5 97b936fd3e Refonte : templates, balades, photos web, aperçus, carte globale
- Mise en page sortie du Python : Scripts/templates/ (Jinja2 + CSS/JS
  communs copiés dans assets/ de chaque voyage)
- Voyages rangés dans un sous-dossier (Balades/…) : rubriques sur
  l'accueil, 2 plus récents par rubrique, pages voyages.html et
  balades.html
- prepare_web.py : photos allégées (photos_web/) et images d'aperçu
  des vidéos (apercus/)
- Voyage d'une seule journée : la page du voyage est la carte du jour
- Carte globale de l'accueil (OpenStreetMap) : voyages du site + cartes
  Google My Maps récupérées (mymaps.txt, _mymaps/), moto par voyage
  (moto.txt)
- KML par voyage pour My Maps
- compress.sh : réencode une sortie illisible (encodage interrompu) ;
  repli automatique sur l'autre qualité dans la page
- Corrections : CSV vide (voyage sans photo), racine de genere_site.sh,
  fichiers ._ de macOS
- README réécrit, commentaires allégés

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mf2kATMtqVABHSYdxJMnim
2026-10-09 11:08:01 +00:00

225 lines
9.1 KiB
Bash
Executable File

#!/bin/bash
# =============================================================================
# EXTRACTION DES POSITIONS GPS — photos (EXIF) et rushs GoPro (GPS embarqué)
#
# Produit deux CSV sans en-tête, lus par genere_carte.py :
# export_photos.csv : fichier, date, lat, lon, alt
# export_videos.csv : fichier, date GPS, lat, lon, alt, vitesse
#
# Usage : ./extraction_infos.sh [dossier_voyage]
#
# Variables :
# VIDEO_GPS=first (défaut) premier point GPS de chaque rush, c'est là que
# genere_carte.py pose le marqueur. Rapide.
# VIDEO_GPS=full toute la trace de chaque rush. Lit les fichiers en entier :
# plusieurs minutes par rush sur un disque externe.
# VARIANTE=D|A|B|C force le mode d'extraction vidéo (voir plus bas)
# =============================================================================
set -uo pipefail
shopt -s nocaseglob nullglob
BASE_DIR="${1:-.}"
PHOTOS_DIR="$BASE_DIR/photos"
RUSHS_DIR="$BASE_DIR/rushs"
CSV_PHOTOS="$BASE_DIR/export_photos.csv"
CSV_VIDEOS="$BASE_DIR/export_videos.csv"
VIDEO_GPS="${VIDEO_GPS:-first}"
VARIANTE="${VARIANTE:-}"
if ! command -v exiftool >/dev/null 2>&1; then
echo "❌ exiftool introuvable. Installe-le : brew install exiftool"
exit 1
fi
echo "--- EXTRACTION DES MÉTADONNÉES ---"
echo "📂 Répertoire : $BASE_DIR"
TMPD="$(mktemp -d "${TMPDIR:-/tmp}/extr.XXXXXX")"
ERRLOG="$TMPD/err.log"
: > "$ERRLOG"
trap 'rm -rf "$TMPD"' EXIT
nlines() { awk 'END{print NR+0}' "$1" 2>/dev/null || echo 0; }
# =============================================================================
# FORMATS
#
# `exiftool -p` supprime toute la ligne dès qu'un seul tag du format manque.
# Sur un rush GoPro, le document principal porte la position mais pas
# GPSDateTime (qui est dans [Doc1]) : un format qui réclame la date ne
# produit alors rien. Ne PAS ajouter -f pour forcer : avec -ee, -f fait perdre
# l'itération par document et ne sort plus qu'une ligne vide.
#
# D'où quatre modes, essayés sur les premiers rushs ; on garde le premier qui
# produit quelque chose :
# D = lecture des tags un par un, analysée par awk (atteint [Doc1])
# A = format complet (date, lat, lon, alt, vitesse)
# B = format réduit (date, lat, lon)
# C = format réduit + -ee3 (sous-documents détaillés)
# =============================================================================
FMT_PHOTOS='"$FileName",$DateTimeOriginal,$GPSLatitude,$GPSLongitude,$GPSAltitude'
FMT_PHOTOS_MIN='"$FileName",$DateTimeOriginal,$GPSLatitude,$GPSLongitude'
FMT_V_COMPLET='"$FileName",$GPSDateTime,$GPSLatitude,$GPSLongitude,$GPSAltitude,$GPSSpeed'
FMT_V_MINIMAL='"$FileName",$GPSDateTime,$GPSLatitude,$GPSLongitude'
# Reconstruit des lignes CSV depuis la sortie « Tag : valeur » d'exiftool
# (noms longs ou courts, avec ou sans préfixe de groupe [Doc1]).
PARSE_GPS='
{
ligne = $0
sub(/^\[[^]]*\][ \t]*/, "", ligne)
if (index(ligne, ":") == 0) next
tag = ligne; sub(/[ \t]*:.*/, "", tag); gsub(/[ \t]/, "", tag)
val = ligne; sub(/^[^:]*:[ \t]*/, "", val); gsub(/[ \t]+$/, "", val)
if (tag == "GPSDateTime" && dt == "") dt = val
else if (tag == "CreateDate" && cd == "") cd = val
else if (tag == "GPSLatitude") lat = val
else if (tag == "GPSLongitude") {
if (lat != "") {
n++
if (mode == "full") { plat[n] = lat; plon[n] = val }
else if (flat == "") { flat = lat; flon = val }
lat = ""
}
}
else if (tag == "GPSAltitude") { if (mode == "full" && n > 0) palt[n] = val }
else if (tag == "GPSSpeed") { if (mode == "full" && n > 0) pspd[n] = val }
# Mode rapide : on sort dès qu on a une date et une position ; exiftool
# reçoit alors SIGPIPE et arrête de lire le fichier.
if (mode != "full" && flat != "" && dt != "") {
print f "," dt "," flat "," flon ",,"; emis = 1; exit
}
}
END {
d = (dt != "" ? dt : cd)
if (d == "") exit
if (mode == "full") { for (i = 1; i <= n; i++) print f "," d "," plat[i] "," plon[i] "," palt[i] "," pspd[i] }
else if (!emis && flat != "") print f "," d "," flat "," flon ",,"
}
'
# extrait_video <mode> <fichier> -> lignes CSV sur stdout
extrait_video() {
local m="$1" f="$2" nom
nom=$(basename "$f")
case "$m" in
D) exiftool -ee -n -q -s -api largefilesupport=1 \
-GPSDateTime -GPSLatitude -GPSLongitude -GPSAltitude -GPSSpeed -CreateDate \
"$f" 2>>"$ERRLOG" \
| awk -v f="\"$nom\"" -v mode="$VIDEO_GPS" "$PARSE_GPS" ;;
A) exiftool -ee -n -q -api largefilesupport=1 -p "$FMT_V_COMPLET" "$f" 2>>"$ERRLOG" ;;
B) exiftool -ee -n -q -api largefilesupport=1 -p "$FMT_V_MINIMAL" "$f" 2>>"$ERRLOG" | awk '{print $0 ",,"}' ;;
C) exiftool -ee3 -n -q -api largefilesupport=1 -p "$FMT_V_MINIMAL" "$f" 2>>"$ERRLOG" | awk '{print $0 ",,"}' ;;
esac
}
# --- 1. PHOTOS ---------------------------------------------------------------
: > "$CSV_PHOTOS"
if [ -d "$PHOTOS_DIR" ]; then
echo "📸 Photos : analyse en cours…"
# Un seul appel exiftool pour tout le dossier : chaque lancement coûte
# ~200 ms (Perl). Seconde passe au format réduit pour rattraper les photos
# sans altitude, écartées par la première.
exiftool -n -q -ext jpg -ext jpeg -p "$FMT_PHOTOS" "$PHOTOS_DIR" \
2>>"$ERRLOG" > "$TMPD/p1.csv"
exiftool -n -q -ext jpg -ext jpeg -p "$FMT_PHOTOS_MIN" "$PHOTOS_DIR" \
2>>"$ERRLOG" | awk '{print $0 ","}' > "$TMPD/p2.csv"
# Fusion : tout p1, plus les photos de p2 absentes de p1.
cat "$TMPD/p1.csv" > "$CSV_PHOTOS"
awk -F, 'NR==FNR {vu[$1]=1; next} !($1 in vu)' "$TMPD/p1.csv" "$TMPD/p2.csv" >> "$CSV_PHOTOS"
n1=$(nlines "$TMPD/p1.csv"); nt=$(nlines "$CSV_PHOTOS")
printf "📸 Photos : %d ligne(s)" "$nt"
[ "$nt" -gt "$n1" ] && printf " (dont %d récupérée(s) sans altitude)" "$((nt - n1))"
echo
else
echo "⚠️ Dossier photos non trouvé, étape ignorée."
fi
# --- 2. VIDÉOS ---------------------------------------------------------------
: > "$CSV_VIDEOS"
if [ ! -d "$RUSHS_DIR" ]; then
echo "⚠️ Dossier rushs non trouvé, étape ignorée."
else
rushs=()
for f in "$RUSHS_DIR"/*.mp4 "$RUSHS_DIR"/*.mov; do
[ -e "$f" ] || continue
# « ._nom » : métadonnées que macOS dépose sur les disques non-HFS (exFAT).
case "$(basename "$f")" in ._*) continue ;; esac
rushs+=("$f")
done
total="${#rushs[@]}"
if [ "$total" -eq 0 ]; then
echo "⚠️ Aucun rush trouvé dans $RUSHS_DIR"
else
if [ "$VIDEO_GPS" = "full" ]; then
echo "🎬 Vidéos : $total rush(s), trace GPS COMPLÈTE"
echo " ⏳ Chaque fichier est lu intégralement."
else
echo "🎬 Vidéos : $total rush(s), premier point GPS seulement"
echo " (VIDEO_GPS=full pour dérouler la trace entière)"
fi
# Choix du mode, testé sur 3 rushs au plus.
if [ -z "$VARIANTE" ]; then
echo " 🔎 recherche du mode d'extraction…"
for essai in D A B C; do
k=0
for f in "${rushs[@]}"; do
k=$((k + 1)); [ "$k" -gt 3 ] && break
if [ -n "$(extrait_video "$essai" "$f" | head -n 1)" ]; then
VARIANTE="$essai"; break
fi
done
[ -n "$VARIANTE" ] && break
done
fi
case "${VARIANTE:-}" in
D) echo " ✔ mode D : lecture directe des tags (atteint [Doc1])" ;;
A) echo " ✔ mode A : format complet (date, lat, lon, alt, vitesse)" ;;
B) echo " ✔ mode B : format réduit (date, lat, lon)" ;;
C) echo " ✔ mode C : format réduit + -ee3 (sous-documents détaillés)" ;;
*) echo " ⚠️ Aucun mode ne donne de résultat sur les 3 premiers rushs."
echo " Diagnostic : exiftool -ee -G3 -n <un_rush> | grep -i gps"
VARIANTE=A ;;
esac
i=0; avec=0; sans=0
T0=$(date +%s)
for f in "${rushs[@]}"; do
i=$((i + 1))
printf " [%3d/%3d] %-28s " "$i" "$total" "$(basename "$f")"
avant=$(nlines "$CSV_VIDEOS")
if [ "$VIDEO_GPS" = "full" ]; then
extrait_video "$VARIANTE" "$f" >> "$CSV_VIDEOS"
else
# head ferme le tuyau : exiftool s'arrête sans lire la fin du fichier.
extrait_video "$VARIANTE" "$f" | head -n 1 >> "$CSV_VIDEOS"
fi
ajoutes=$(( $(nlines "$CSV_VIDEOS") - avant ))
if [ "$ajoutes" -gt 0 ]; then
if [ "$VIDEO_GPS" = "full" ]; then printf "✓ %d points\n" "$ajoutes"; else echo "✓"; fi
avec=$((avec + 1))
else
echo "— pas de GPS"; sans=$((sans + 1))
fi
done
T1=$(date +%s); EL=$((T1 - T0))
printf "🎬 Vidéos : %d point(s) GPS, %d rush(s) localisé(s)" "$(nlines "$CSV_VIDEOS")" "$avec"
[ "$sans" -gt 0 ] && printf ", %d sans GPS" "$sans"
printf " — %d min %02d s\n" $((EL / 60)) $((EL % 60))
fi
fi
echo "✅ Générés : $CSV_PHOTOS et $CSV_VIDEOS"