From 456717f6399456596d6a05ebf0304bf06a2163ca Mon Sep 17 00:00:00 2001 From: Antoine Van Elstraete Date: Tue, 10 Feb 2026 16:30:06 +0100 Subject: [PATCH] Ajout option --set-file-date pour modifier le mtime des fichiers Permet de modifier la date de modification des fichiers images selon la date de prise de vue du frame, utile pour le tri par date dans les gestionnaires de fichiers. Utilise os.utime() pour modifier atime et mtime. Co-Authored-By: Claude Opus 4.5 --- CLAUDE.md | 7 ++--- json_to_metadata/cli.py | 57 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index eb2f1d3..1653d02 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,9 +39,10 @@ source venv/bin/activate python -m json_to_metadata -d # Options CLI -# -v, --verbose Mode verbeux (DEBUG) -# --dry-run Affiche sans exécuter -# --force-xmp Force création XMP même pour TIFF/JPEG +# -v, --verbose Mode verbeux (DEBUG) +# --dry-run Affiche sans exécuter +# --force-xmp Force création XMP même pour TIFF/JPEG +# --set-file-date Modifie le mtime des fichiers selon la date de prise de vue # Tests pytest tests/ -v diff --git a/json_to_metadata/cli.py b/json_to_metadata/cli.py index ad8de47..6e3753c 100644 --- a/json_to_metadata/cli.py +++ b/json_to_metadata/cli.py @@ -7,7 +7,9 @@ des métadonnées EXIF. import argparse import logging +import os import sys +from datetime import datetime from pathlib import Path from . import __version__ @@ -18,7 +20,7 @@ from .exif_writer import ( write_exif_with_fallback, ) from .json_parser import ValidationError, load_json, validate_roll -from .metadata_mapper import map_frame_to_exif +from .metadata_mapper import map_frame_to_exif, parse_date from .xmp_writer import write_xmp_sidecar # Configuration du logging @@ -45,6 +47,35 @@ def setup_logging(verbose: bool = False) -> None: ) +def set_file_mtime(filepath: Path, dt: datetime, dry_run: bool = False) -> bool: + """ + Modifie la date de modification (mtime) d'un fichier. + + Args: + filepath: Chemin vers le fichier. + dt: Date/heure à appliquer. + dry_run: Si True, affiche sans modifier. + + Returns: + True si la modification a réussi. + """ + try: + timestamp = dt.timestamp() + + if dry_run: + logger.info(f"[DRY-RUN] Modification date fichier : {filepath.name} → {dt}") + return True + + # Modifie atime et mtime + os.utime(filepath, (timestamp, timestamp)) + logger.debug(f"Date fichier modifiée : {filepath.name} → {dt}") + return True + + except (OSError, ValueError) as e: + logger.warning(f"Impossible de modifier la date du fichier {filepath.name} : {e}") + return False + + def find_image_for_frame( frame: dict, directory: Path, @@ -95,7 +126,8 @@ def process_roll( roll: dict, image_dir: Path, dry_run: bool = False, - force_xmp: bool = False + force_xmp: bool = False, + set_file_date: bool = False ) -> tuple[int, int, int]: """ Traite un roll complet : valide et écrit les métadonnées pour chaque frame. @@ -105,6 +137,7 @@ def process_roll( image_dir: Répertoire contenant les images. dry_run: Mode simulation. force_xmp: Force la création de fichiers XMP. + set_file_date: Modifie la date de modification du fichier. Returns: Tuple (succès, échecs, images non trouvées). @@ -144,10 +177,12 @@ def process_roll( continue # Écrire les métadonnées + write_success = False try: if force_xmp: xmp_path = write_xmp_sidecar(image_path, tags, dry_run) if xmp_path: + write_success = True success_count += 1 logger.info(f"Frame {frame_id} : XMP créé ({image_path.name})") else: @@ -158,6 +193,7 @@ def process_roll( dry_run ) if success: + write_success = True success_count += 1 logger.info(f"Frame {frame_id} : métadonnées écrites via {method}") else: @@ -171,6 +207,14 @@ def process_roll( logger.error(f"Erreur I/O pour le frame {frame_id} : {e}") failure_count += 1 + # Modifier la date du fichier si demandé + if write_success and set_file_date and frame.get('date'): + try: + frame_date = parse_date(frame['date']) + set_file_mtime(image_path, frame_date, dry_run) + except ValueError as e: + logger.warning(f"Date invalide pour le frame {frame_id} : {e}") + return success_count, failure_count, not_found_count @@ -221,6 +265,12 @@ def main(args: list[str] | None = None) -> int: help='Force la création de fichiers XMP même pour les formats supportant EXIF' ) + parser.add_argument( + '--set-file-date', + action='store_true', + help='Modifie la date de modification des fichiers selon la date de prise de vue' + ) + parser.add_argument( '--version', action='version', @@ -302,7 +352,8 @@ def main(args: list[str] | None = None) -> int: roll, image_dir, dry_run=parsed_args.dry_run, - force_xmp=parsed_args.force_xmp + force_xmp=parsed_args.force_xmp, + set_file_date=parsed_args.set_file_date ) total_success += success total_failure += failure