268 lines
8.2 KiB
Fish
268 lines
8.2 KiB
Fish
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 <source> <destination> [<destination> ...]'
|
|
echo ' copytime --date <DATE> <video> [<video> ...]'
|
|
echo
|
|
echo 'Copies the access and modified timestamps from <source> to each'
|
|
echo '<destination> (same semantics as `touch -r`). On macOS the filesystem'
|
|
echo 'creation time is copied too (requires SetFile).'
|
|
echo
|
|
echo 'For media files (mp4, mkv, mov, webm, ...), the creation date stored'
|
|
echo 'inside the container - the one apps like Plex and photo managers show -'
|
|
echo 'is copied from source to destination and printed. Data/timecode tracks'
|
|
echo 'are dropped while remuxing (lossless, no re-encode).'
|
|
echo
|
|
echo 'options:'
|
|
echo ' -d, --date <DATE> set the container creation date of the given video(s)'
|
|
echo ' directly, e.g. "2020-01-02 03:04:05"'
|
|
echo ' -h, --help show this help'
|
|
end
|