function copytime -d 'Copy timestamps between files; for media files also copies the container creation date' argparse -n copytime 'h/help' 'd/date=' -- $argv or return 2 if set -q _flag_help __copytime_usage return 0 end if test (count $argv) -lt 1 __copytime_usage return 2 end __copytime_colors if set -q _flag_date set -l rc 0 for f in $argv __copytime_setdate "$f" "$_flag_date" or set rc 1 end return $rc end if test (count $argv) -lt 2 __copytime_usage return 2 end set -l src $argv[1] set -l dsts $argv[2..-1] if not test -e "$src" __copytime_error "no such source: '$src'" return 1 end switch (uname -s) case Linux __copytime_linux "$src" $dsts case Darwin __copytime_darwin "$src" $dsts case '*' __copytime_error "unsupported platform '(uname -s)'" return 1 end end function __copytime_linux set -l src $argv[1] set -l rc 0 set -l mtime (stat -c '%y' -- "$src" | string replace -r '\.[0-9]+' '') set -l atime (stat -c '%x' -- "$src" | string replace -r '\.[0-9]+' '') echo "$vrot_c_dim source: $src$vrot_c_reset" echo "$vrot_c_dim modified: $mtime$vrot_c_reset" echo "$vrot_c_dim accessed: $atime$vrot_c_reset" set -l birth (stat -c '%w' -- "$src") if test -n "$birth"; and string match -q '*[-Unknown]*' "$birth" set birth '' end if test -n "$birth" set -l btime (string replace -r '\.[0-9]+' '' -- "$birth") echo "$vrot_c_dim created: $btime (filesystem creation time cannot be set on Linux)$vrot_c_reset" end set -l created (__copytime_mediadate "$src") if test -n "$created" set -l ctime (string replace 'T' ' ' -- "$created" | string replace -r '\.\d+Z?$' '') echo "$vrot_c_dim container created: $ctime$vrot_c_reset" end for dst in $argv[2..-1] if not test -e "$dst" __copytime_error "skipping missing destination: '$dst'" set rc 1 continue end touch -a -m -r "$src" "$dst" if test $status -ne 0 __copytime_error "failed to copy timestamps to '$dst'" set rc 1 continue end set -l dm (stat -c '%y' -- "$dst" | string replace -r '\.[0-9]+' '') echo "$vrot_c_ok ✔ $dst$vrot_c_dim ← modified $dm$vrot_c_reset" if test -n "$created" __copytime_meta "$dst" "$created" or set rc 1 end end return $rc end function __copytime_darwin set -l src $argv[1] set -l rc 0 set -l mtime (stat -f '%Sm' -t '%Y-%m-%d %H:%M:%S' -- "$src") set -l btime (stat -f '%SB' -t '%Y-%m-%d %H:%M:%S' -- "$src") echo "$vrot_c_dim source: $src$vrot_c_reset" echo "$vrot_c_dim modified: $mtime$vrot_c_reset" echo "$vrot_c_dim created: $btime$vrot_c_reset" set -l created (__copytime_mediadate "$src") if test -n "$created" set -l ctime (string replace 'T' ' ' -- "$created" | string replace -r '\.\d+Z?$' '') echo "$vrot_c_dim container created: $ctime$vrot_c_reset" end set -l birth (stat -f '%SB' -t '%m/%d/%Y %H:%M:%S' -- "$src") for dst in $argv[2..-1] if not test -e "$dst" __copytime_error "skipping missing destination: '$dst'" set rc 1 continue end touch -a -m -r "$src" "$dst" if test $status -ne 0 set rc 1 continue end if command -q SetFile SetFile -d "$birth" "$dst" if test $status -ne 0 __copytime_error "failed to set creation time on '$dst'" set rc 1 end else echo "$vrot_c_warn ⚠ SetFile not found — creation time not copied to $dst$vrot_c_reset" >&2 end set -l db (stat -f '%SB' -t '%Y-%m-%d %H:%M:%S' -- "$dst") echo "$vrot_c_ok ✔ $dst$vrot_c_dim ← created $db$vrot_c_reset" if test -n "$created" __copytime_meta "$dst" "$created" or set rc 1 end end return $rc end function __copytime_mediadate if not command -q ffprobe return 0 end if not __copytime_media "$argv[1]" return 0 end set -l d (ffprobe -v error -show_entries format_tags=creation_time \ -of default=noprint_wrappers=1:nokey=1 "$argv[1]")[1] string match -rq '^[0-9]{4}-[0-9]{2}-[0-9]{2}' "$d"; and echo "$d" end function __copytime_meta set -l dst $argv[1] set -l date $argv[2] if not command -q ffmpeg return 0 end if not __copytime_media "$dst" return 0 end set -l tmp (string join '' "$dst" .ct. (random) (path extension "$dst")) ffmpeg -hide_banner -loglevel error -y -i "$dst" -map 0 -map '-0:d' -map '-0:t' \ -c copy -metadata creation_time="$date" "$tmp" if test $status -ne 0 rm -f "$tmp" __copytime_error "failed to copy container creation date to '$dst'" return 1 end mv -f -- "$tmp" "$dst" if test $status -ne 0 rm -f "$tmp" __copytime_error "failed to replace '$dst'" return 1 end set -l ctime (string replace 'T' ' ' -- "$date" | string replace -r '\.\d+Z?$' '') echo "$vrot_c_dim container created: $ctime$vrot_c_reset" end function __copytime_setdate set -l file $argv[1] set -l date $argv[2] if not test -e "$file" __copytime_error "no such file: '$file'" return 1 end if not __copytime_media "$file" __copytime_error "'$file' is not a supported media file" return 1 end if not command -q ffmpeg __copytime_error "ffmpeg is required to set container dates" return 1 end set -l tmp (string join '' "$file" .ct. (random) (path extension "$file")) ffmpeg -hide_banner -loglevel error -y -i "$file" -map 0 -map '-0:d' -map '-0:t' \ -c copy -metadata creation_time="$date" "$tmp" if test $status -ne 0 rm -f "$tmp" __copytime_error "failed to write creation date to '$file'" return 1 end mv -f -- "$tmp" "$file" if test $status -ne 0 rm -f "$tmp" __copytime_error "failed to replace '$file'" return 1 end set -l dsp (string replace 'T' ' ' -- "$date") echo "$vrot_c_ok ✔ $file$vrot_c_dim ← container creation date $dsp$vrot_c_reset" end function __copytime_media set -l ext (string lower (path extension "$argv[1]")) switch "$ext" case '.mp4' '.mov' '.m4v' '.mkv' '.webm' '.avi' '.ts' '.mts' '.m2ts' '.flv' '.wmv' '.mpg' '.mpeg' '.3gp' '.vob' '.ogv' return 0 end return 1 end function __copytime_colors set -q vrot_colors_set; and return 0 set -g vrot_colors_set 1 if isatty stdout set -g vrot_c_ok (set_color brgreen) set -g vrot_c_dim (set_color brblack) set -g vrot_c_warn (set_color bryellow) set -g vrot_c_err (set_color brred) set -g vrot_c_reset (set_color normal) else for c in ok dim warn err reset set -g vrot_c_$c '' end end end function __copytime_error echo "$vrot_c_err""copytime: "$argv"$vrot_c_reset" >&2 end function __copytime_usage echo 'usage: copytime [ ...]' echo ' copytime --date