media#

mediautils.media.gather_yes_no(in_dir: str | PathLike = 'in', out_dir: str | PathLike = 'out') list[Path][source]#

Copy culled files from nested yes/no subdirectories to output buckets.

Recursively scans in_dir for files whose immediate parent directory is named yes or no, and copies them to out_dir/yes or out_dir/no respectively. Files in any other directory (e.g. temp) are ignored.

Parameters:
  • in_dir (str | os.PathLike) – Root directory to scan recursively.

  • out_dir (str | os.PathLike) – Output root. yes and no subdirectories are created as needed.

Returns:

Paths to the copied output files.

Return type:

list[Path]

mediautils.media.process_camera_timezone(camera_timezone: str, in_dir: str | PathLike = 'in', out_dir: str | PathLike = 'out', real_timezone: str = 'Europe/Paris') list[Path][source]#

Correct photos from a camera left on a foreign time zone.

For a camera whose clock was never switched from camera_timezone while actually being used in real_timezone, corrects every file in in_dir with a standardized name (YYYYMMDD_HHMMSS...): the datetime encoded in the file name’s prefix is reinterpreted as a camera_timezone wall-clock reading, then converted — via the IANA time zone database, so daylight-saving time is resolved per the photo’s own date — to the corresponding real_timezone wall-clock time and UTC offset.

Unlike process_timezone_shift(), no reference photo is needed: both time zones are known upfront, so the correction is computed directly and stays correct even if in_dir spans a DST transition in either zone (the US and the EU do not switch to/from DST on the same dates, so the gap between them is not always the same number of hours).

For each file, writes a copy to out_dir with:

  • the file name’s YYYYMMDD_HHMMSS prefix replaced by the corrected datetime — anything after the prefix (e.g. the camera’s own original file name, kept as an identifier back to the source device) is left untouched, see replace_datetime_prefix();

  • for JPEG/RAW images, datetime_original/DateTimeOriginal and offset_time_original/OffsetTimeOriginal set to the corrected real_timezone datetime and UTC offset; videos have their creation_time set via set_time() (no offset tag);

  • the copy’s filesystem creation, modification and access times set to match, for the same reasons as process_clock_shift().

.xmp sidecars are not supported: the text-substitution approach used by process_clock_shift() assumes the offset embedded in the file does not change, which is false for a genuine time zone correction.

Parameters:
  • camera_timezone (str) – IANA time zone the camera’s clock was left on (e.g. "America/New_York").

  • in_dir (str | os.PathLike) – Directory containing the files to correct, with standardized names.

  • out_dir (str | os.PathLike) – Directory where corrected copies are saved.

  • real_timezone (str) – IANA time zone the photos were actually taken in.

Returns:

Paths to the output files.

Return type:

list[Path]

Raises:

ValueError – If a file has an unsupported extension, including .xmp.

mediautils.media.process_clock_shift(delta: timedelta, in_dir: str | PathLike = 'in', out_dir: str | PathLike = 'out') list[Path][source]#

Correct a flat camera clock drift/error affecting a batch of files.

For each file in in_dir with a standardized name (YYYYMMDD_HHMMSS...), adds delta to the datetime encoded in the file name, then writes a copy to out_dir with:

  • the file name’s YYYYMMDD_HHMMSS prefix replaced by the corrected datetime (see replace_datetime_prefix());

  • the metadata timestamp set to the corrected datetime, dispatched by file extension like set_time() (EXIF datetime_original for images and RAW files, MP4/MOV creation_time for videos); .xmp sidecar files (e.g. Lightroom edits) are instead handled by shifting their embedded dates via text substitution, see _shift_xmp_datetimes();

  • the copy’s filesystem creation, modification and access times set to match (see set_file_creation_time()), since tools like FastStone Image Viewer’s rename feature read those instead of the EXIF metadata, and to give every tool the best chance of sorting the files chronologically.

Unlike process_timezone_shift(), this does not touch any EXIF timezone/offset tag: it corrects a clock drift (the camera’s wall-clock reading was wrong), not a timezone error, so an existing offset tag is still correct and is left untouched.

Parameters:
  • delta (timedelta) – Amount to add to every timestamp. Use a negative value if the camera’s clock was ahead of the real time.

  • in_dir (str | os.PathLike) – Directory containing the files to correct, with standardized names.

  • out_dir (str | os.PathLike) – Directory where corrected copies are saved.

Returns:

Paths to the output files.

Return type:

list[Path]

mediautils.media.process_date_subdirs(in_dir: str | PathLike = 'in', out_dir: str | PathLike = 'out') list[Path][source]#

Process files organized in date-named subdirectories.

Each subdirectory of in_dir must have a name starting with YYYYMMDD. Files inside each subdirectory are assigned timestamps near end of day (incrementing by one second per file), renamed to YYYYMMDD_HHMMSS_originalname, and written to out_dir with updated metadata.

Parameters:
  • in_dir (str | os.PathLike) – Directory containing date-named subdirectories.

  • out_dir (str | os.PathLike) – Directory where processed files are saved.

Returns:

Paths to the output files.

Return type:

list[Path]

mediautils.media.process_datetime_filenames(in_dir: str | PathLike = 'in', out_dir: str | PathLike = 'out') list[Path][source]#

Process files with standardized names: set timestamps from file names.

For each file in in_dir whose name starts with YYYYMMDD_HHMMSS, writes a copy to out_dir with metadata matching the datetime encoded in the file name.

Parameters:
  • in_dir (str | os.PathLike) – Directory containing media files with standardized names.

  • out_dir (str | os.PathLike) – Directory where processed files are saved.

Returns:

Paths to the output files.

Return type:

list[Path]

mediautils.media.process_timezone_shift(phone_reference: str | PathLike, in_dir: str | PathLike = 'in', out_dir: str | PathLike = 'out', home_timezone: str = 'Europe/Paris') list[Path][source]#

Correct the recorded time of images from a camera left on the wrong timezone.

For a trip where the camera’s clock was never updated from home_timezone while the phone auto-updated to the destination’s local time, phone_reference (any photo taken on the phone during the trip, with correct local time and an offset_time_original EXIF tag) is enough to derive both the destination’s UTC offset and the camera’s clock error: the true instant of phone_reference is computed from its own datetime and offset, then compared to what a home_timezone clock would have displayed at that same instant. That gap, plus the destination offset, are applied to every image in in_dir: for each one, reads its datetime_original, shifts it by the gap, and writes a copy to out_dir with the corrected datetime and the destination offset_time_original. The copy’s filesystem creation, modification and access times are also set to match (see set_file_creation_time()), since tools like FastStone Image Viewer’s rename feature read those instead of the EXIF metadata. File names are left untouched.

Parameters:
  • phone_reference (str | os.PathLike) – Path to any phone photo taken during the trip, with correct local time and an offset_time_original EXIF tag.

  • in_dir (str | os.PathLike) – Directory containing the camera images to correct.

  • out_dir (str | os.PathLike) – Directory where corrected copies are saved.

  • home_timezone (str) – IANA timezone the camera’s clock was left on (e.g. "Europe/Paris").

Returns:

Paths to the output files.

Return type:

list[Path]

Raises:
  • ValueError – If in_dir contains no files, or if phone_reference has no offset_time_original EXIF tag.

  • NotImplementedError – If not running on Windows.

mediautils.media.process_whatsapp_files(in_dir: str | PathLike = 'in', out_dir: str | PathLike = 'out') list[Path][source]#

Process WhatsApp media files: set timestamps and rename.

For each file in in_dir, extracts the date from the WhatsApp file name, assigns a time near end of day (incrementing by one second per file within the same date), renames to YYYYMMDD_HHMMSS_originalname, and writes the result to out_dir with updated metadata.

Parameters:
  • in_dir (str | os.PathLike) – Directory containing WhatsApp media files.

  • out_dir (str | os.PathLike) – Directory where processed files are saved.

Returns:

Paths to the output files.

Return type:

list[Path]

mediautils.media.set_time(path: str | PathLike, dt: datetime, out_dir: str | PathLike = 'out', out_name: str | None = None) Path[source]#

Write a copy of an image or video with its timestamps set to dt.

Dispatches to set_time_image() or set_time_video() based on the file extension.

Parameters:
  • path (str | os.PathLike) – Path to the source file.

  • dt (datetime) – The datetime to write into the metadata.

  • out_dir (str | os.PathLike) – Directory where the modified copy is saved. Created if it does not exist.

  • out_name (str | None) – Output file name. If None, the original file name is kept.

Returns:

Path to the output file.

Return type:

Path

Raises:

ValueError – If the file extension is not supported.