Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95183069ce | ||
|
|
dd0bc6a77c |
@@ -0,0 +1,4 @@
|
|||||||
|
complete -c copytime -f -a '(__fish_complete_path)' -d 'Source file'
|
||||||
|
complete -c copytime -f -a '(__fish_complete_path)' -d 'Destination file'
|
||||||
|
complete -c copytime -s d -l date -x -d 'Set container creation date directly (e.g. 2020-01-02 03:04:05)'
|
||||||
|
complete -c copytime -s h -l help -d 'Show help'
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
complete -c vrot -f -a '(__fish_complete_suffix .mp4 .mkv .mov .m4v .webm .avi .ts .mts .m2ts .flv .wmv .mpg .mpeg .vob .3gp)' -d 'Video file'
|
||||||
|
complete -c vrot -s h -l help -d 'Show help'
|
||||||
|
complete -c vrot -s r -l reencode -d 'Re-encode the video (rotate pixels, works everywhere)'
|
||||||
|
complete -c vrot -s a -l angle -x -a '90 180 270' -d 'Rotation angle (degrees clockwise)'
|
||||||
|
complete -c vrot -s p -l preset -x -a 'ultrafast superfast veryfast faster fast medium slow slower veryslow' -d 'x264/x265 encoder preset'
|
||||||
@@ -71,6 +71,7 @@ if test -e /usr/bin/nano
|
|||||||
echo "Usage: nanorm {FILE}"
|
echo "Usage: nanorm {FILE}"
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
rm $argv[1]
|
||||||
nano $argv[1]
|
nano $argv[1]
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -165,3 +165,12 @@ if test -e /usr/bin/reflector
|
|||||||
alias mirrord='sudo reflector --latest 50 --number 20 --sort delay --save /etc/pacman.d/mirrorlist'
|
alias mirrord='sudo reflector --latest 50 --number 20 --sort delay --save /etc/pacman.d/mirrorlist'
|
||||||
alias mirrors='sudo reflector --latest 50 --number 20 --sort score --save /etc/pacman.d/mirrorlist'
|
alias mirrors='sudo reflector --latest 50 --number 20 --sort score --save /etc/pacman.d/mirrorlist'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function pacman-autoremove
|
||||||
|
set -l orphans (pacman -Qtdq)
|
||||||
|
if test (count $orphans) -gt 0
|
||||||
|
sudo pacman -Rns $orphans
|
||||||
|
else
|
||||||
|
echo "No orphaned packages."
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
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
|
||||||
@@ -0,0 +1,319 @@
|
|||||||
|
function vrot -d 'Rotate a video with ffmpeg: metadata-only by default, re-encode with -r'
|
||||||
|
argparse -n vrot 'h/help' 'r/reencode' 'a/angle=' 'p/preset=' -- $argv
|
||||||
|
or return 2
|
||||||
|
|
||||||
|
if set -q _flag_help
|
||||||
|
__vrot_usage
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if test (count $argv) -lt 1
|
||||||
|
__vrot_usage
|
||||||
|
return 2
|
||||||
|
end
|
||||||
|
|
||||||
|
set -q _flag_angle; or set _flag_angle 90
|
||||||
|
set -q _flag_preset; or set _flag_preset medium
|
||||||
|
|
||||||
|
switch $_flag_angle
|
||||||
|
case 90 180 270
|
||||||
|
case '*'
|
||||||
|
__vrot_error "angle must be 90, 180 or 270 (got '$_flag_angle')"
|
||||||
|
return 2
|
||||||
|
end
|
||||||
|
|
||||||
|
__vrot_colors
|
||||||
|
|
||||||
|
set -l want_reencode 0
|
||||||
|
set -q _flag_reencode; and set want_reencode 1
|
||||||
|
|
||||||
|
set -l rc 0
|
||||||
|
for file in $argv
|
||||||
|
if not test -f "$file"
|
||||||
|
__vrot_error "no such file: '$file'"
|
||||||
|
set rc 1
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
__vrot_one "$file" "$_flag_angle" "$_flag_preset" "$want_reencode"
|
||||||
|
or set rc 1
|
||||||
|
end
|
||||||
|
return $rc
|
||||||
|
end
|
||||||
|
|
||||||
|
function __vrot_one
|
||||||
|
set -l file $argv[1]
|
||||||
|
set -l angle $argv[2]
|
||||||
|
set -l preset $argv[3]
|
||||||
|
set -l want_reencode $argv[4]
|
||||||
|
|
||||||
|
set -l name (path basename "$file")
|
||||||
|
set -l ext (path extension "$file")
|
||||||
|
set -l out (path change-extension '' "$file")_rot$ext
|
||||||
|
set -l outname (path basename "$out")
|
||||||
|
|
||||||
|
__vrot_banner "$name → $outname"
|
||||||
|
|
||||||
|
set -l lines (ffprobe -v error -select_streams v:0 \
|
||||||
|
-show_entries stream=codec_name,width,height,r_frame_rate,nb_frames:format=duration,bit_rate \
|
||||||
|
-of default=noprint_wrappers=1 "$file")
|
||||||
|
|
||||||
|
set -l codec (string match 'codec_name=*' -- $lines | string replace 'codec_name=' '')[1]
|
||||||
|
set -l width (string match 'width=*' -- $lines | string replace 'width=' '')[1]
|
||||||
|
set -l height (string match 'height=*' -- $lines | string replace 'height=' '')[1]
|
||||||
|
set -l fpsraw (string match 'r_frame_rate=*' -- $lines | string replace 'r_frame_rate=' '')[1]
|
||||||
|
set -l frames (string match 'nb_frames=*' -- $lines | string replace 'nb_frames=' '')[1]
|
||||||
|
set -l duration (string match 'duration=*' -- $lines | string replace 'duration=' '')[1]
|
||||||
|
set -l bitrate (string match 'bit_rate=*' -- $lines | string replace 'bit_rate=' '')[1]
|
||||||
|
|
||||||
|
set -l info "$width"x"$height"
|
||||||
|
if test -n "$codec"
|
||||||
|
set info "$info "(string upper "$codec")
|
||||||
|
end
|
||||||
|
if test -n "$fpsraw"; and string match -rq '^[0-9]+/[0-9]+$' "$fpsraw"; and not string match -q '*/0' "$fpsraw"
|
||||||
|
set info "$info "(math -s 2 "$fpsraw")" fps"
|
||||||
|
end
|
||||||
|
if test -n "$duration"; and string match -rq '^[0-9.]+$' "$duration"
|
||||||
|
set info "$info "(__vrot_fmtsecs "$duration")
|
||||||
|
end
|
||||||
|
if test -n "$bitrate"; and string match -rq '^[0-9.]+$' "$bitrate"
|
||||||
|
set info "$info "(math -s 1 "$bitrate/1000000")" Mbit/s"
|
||||||
|
end
|
||||||
|
echo "$vrot_c_dim $info$vrot_c_reset"
|
||||||
|
|
||||||
|
if test "$file" = "$out"
|
||||||
|
__vrot_error "output would overwrite input: '$out'"
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if test -e "$out"
|
||||||
|
read -l -P "vrot: '$out' exists. Overwrite? [y/N] " ans
|
||||||
|
if not string match -qi 'y' "$ans"
|
||||||
|
echo "$vrot_c_dim skipped: $out$vrot_c_reset"
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
rm -f "$out"
|
||||||
|
end
|
||||||
|
|
||||||
|
if test "$want_reencode" -eq 1
|
||||||
|
__vrot_reencode "$file" "$out" "$angle" "$preset" "$height" "$codec" "$duration" "$frames"
|
||||||
|
return $status
|
||||||
|
end
|
||||||
|
|
||||||
|
echo "$vrot_c_dim mode: metadata-only rotation (lossless, instant)$vrot_c_reset"
|
||||||
|
ffmpeg -hide_banner -loglevel error -nostdin -i "$file" -map 0 -c copy -ignore_unknown \
|
||||||
|
-movflags +faststart -metadata:s:v:0 rotate=$angle "$out"
|
||||||
|
if test $status -eq 0
|
||||||
|
__vrot_summary "$out"
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
echo "$vrot_c_warn ↷ dropping unsupported data/attachment tracks, retrying…$vrot_c_reset"
|
||||||
|
rm -f "$out"
|
||||||
|
ffmpeg -hide_banner -loglevel error -nostdin -i "$file" -map 0 -map '-0:d' -map '-0:t' \
|
||||||
|
-c copy -movflags +faststart -metadata:s:v:0 rotate=$angle "$out"
|
||||||
|
if test $status -eq 0
|
||||||
|
__vrot_summary "$out"
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
echo "$vrot_c_warn ↷ metadata rotation unsupported here, re-encoding instead…$vrot_c_reset"
|
||||||
|
rm -f "$out"
|
||||||
|
__vrot_reencode "$file" "$out" "$angle" "$preset" "$height" "$codec" "$duration" "$frames"
|
||||||
|
end
|
||||||
|
|
||||||
|
function __vrot_reencode
|
||||||
|
set -l file $argv[1]
|
||||||
|
set -l out $argv[2]
|
||||||
|
set -l angle $argv[3]
|
||||||
|
set -l preset $argv[4]
|
||||||
|
set -l height $argv[5]
|
||||||
|
set -l codec $argv[6]
|
||||||
|
set -l duration $argv[7]
|
||||||
|
set -l frames $argv[8]
|
||||||
|
|
||||||
|
test -n "$height"; or set height 1080
|
||||||
|
|
||||||
|
set -l enc libx264
|
||||||
|
switch "$codec"
|
||||||
|
case 'hevc*' 'h265*' 'h266*'
|
||||||
|
set enc libx265
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l crf 20
|
||||||
|
set -l maxrate 20M
|
||||||
|
set -l bufsize 40M
|
||||||
|
if test $height -ge 2160
|
||||||
|
set crf 22; set maxrate 40M; set bufsize 80M
|
||||||
|
else if test $height -ge 1440
|
||||||
|
set crf 21; set maxrate 30M; set bufsize 60M
|
||||||
|
else if test $height -ge 1080
|
||||||
|
set crf 20; set maxrate 20M; set bufsize 40M
|
||||||
|
else if test $height -ge 720
|
||||||
|
set crf 19; set maxrate 10M; set bufsize 20M
|
||||||
|
else
|
||||||
|
set crf 18; set maxrate 6M; set bufsize 12M
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l vf 'transpose=1'
|
||||||
|
switch $angle
|
||||||
|
case 180
|
||||||
|
set vf 'transpose=1,transpose=1'
|
||||||
|
case 270
|
||||||
|
set vf 'transpose=2'
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l faststart
|
||||||
|
switch (string lower (path extension "$out"))
|
||||||
|
case '.mp4' '.mov' '.m4v'
|
||||||
|
set faststart '-movflags' '+faststart'
|
||||||
|
end
|
||||||
|
|
||||||
|
echo "$vrot_c_dim mode: re-encode ($enc · crf $crf · cap $maxrate)$vrot_c_reset"
|
||||||
|
|
||||||
|
set -l total_frames ''
|
||||||
|
string match -rq '^\d+$' "$frames"; and test "$frames" -gt 0; and set total_frames $frames
|
||||||
|
|
||||||
|
set -l out_t ''
|
||||||
|
set -l frame 0
|
||||||
|
set -l fps_txt ''
|
||||||
|
set -l bitrate_txt ''
|
||||||
|
set -l speed_txt ''
|
||||||
|
|
||||||
|
ffmpeg -hide_banner -loglevel error -nostdin -progress pipe:1 -i "$file" \
|
||||||
|
-map 0:v -map '0:a?' -map '0:s?' -ignore_unknown -vf "$vf" -c:v $enc -crf $crf \
|
||||||
|
-maxrate $maxrate -bufsize $bufsize -preset $preset -c:a copy -c:s copy \
|
||||||
|
$faststart "$out" | while read -l line
|
||||||
|
switch "$line"
|
||||||
|
case 'frame=*'
|
||||||
|
set frame (string replace 'frame=' '' -- "$line")
|
||||||
|
case 'fps=*'
|
||||||
|
set fps_txt (string replace 'fps=' '' -- "$line")"fps"
|
||||||
|
case 'bitrate=*'
|
||||||
|
set bitrate_txt (string replace 'bitrate=' '' -- "$line")
|
||||||
|
if string match -q '*kbits/s' "$bitrate_txt"
|
||||||
|
set bitrate_txt (math -s 1 (string replace 'kbits/s' '' -- "$bitrate_txt") / 1000)"Mbit/s"
|
||||||
|
else if string match -q '*Mbits/s' "$bitrate_txt"
|
||||||
|
set bitrate_txt (string replace 'Mbits/s' 'Mbit/s' -- "$bitrate_txt")
|
||||||
|
end
|
||||||
|
case 'out_time=*'
|
||||||
|
set -l t (string replace 'out_time=' '' -- "$line")
|
||||||
|
set -l parts (string split ':' -- "$t")
|
||||||
|
if test (count $parts) -eq 3; and string match -rq '^\d+$' "$parts[1]"; and string match -rq '^\d+$' "$parts[2]"; and string match -rq '^[\d.]+$' "$parts[3]"
|
||||||
|
set out_t (math "$parts[1]*3600+$parts[2]*60+$parts[3]")
|
||||||
|
end
|
||||||
|
case 'speed=*'
|
||||||
|
set speed_txt (string replace 'speed=' '' -- "$line")
|
||||||
|
end
|
||||||
|
if isatty stdout
|
||||||
|
printf '\r\033[K'
|
||||||
|
set -l pct '--.-%'
|
||||||
|
set -l eta_txt ''
|
||||||
|
set -l bar (string repeat -n 24 '░')
|
||||||
|
set -l frac ''
|
||||||
|
if test -n "$total_frames"; and string match -rq '^\d+$' "$frame"; and test "$total_frames" -gt 0
|
||||||
|
set frac (math "min(1, $frame/$total_frames)")
|
||||||
|
else if test -n "$out_t"; and string match -rq '^[0-9.]+$' "$duration"; and not string match -rq '^0+(\.0*)?$' "$duration"
|
||||||
|
set frac (math "min(1, $out_t/$duration)")
|
||||||
|
end
|
||||||
|
if test -n "$frac"
|
||||||
|
set -l filled (math "floor($frac*24)")
|
||||||
|
set -l bar (string repeat -n $filled '█')
|
||||||
|
set bar "$bar"(string repeat -n (math "24-$filled") '░')
|
||||||
|
set pct (math -s 1 "$frac*100")%
|
||||||
|
set -l sp (string replace -r '[xX]$' '' -- "$speed_txt")
|
||||||
|
if test -n "$sp"; and string match -rq '^[0-9.]+$' "$sp"; and not string match -rq '^0+(\.0*)?$' "$sp"; and test -n "$out_t"; and string match -rq '^[0-9.]+$'
|
||||||
|
"$duration"
|
||||||
|
set eta_txt " ETA "(__vrot_fmtsecs (math "($duration - $out_t)/$sp"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
set -l frame_txt $frame
|
||||||
|
if test -n "$total_frames"
|
||||||
|
set frame_txt "$frame/$total_frames"
|
||||||
|
end
|
||||||
|
echo -n " $vrot_c_ok$bar$vrot_c_reset $pct frame=$frame_txt $fps_txt $bitrate_txt $speed_txt$eta_txt"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
set -l ff_status $pipestatus[1]
|
||||||
|
printf '\n'
|
||||||
|
|
||||||
|
if test $ff_status -ne 0
|
||||||
|
__vrot_error "encoding failed (ffmpeg exited $ff_status)"
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
__vrot_summary "$out"
|
||||||
|
end
|
||||||
|
|
||||||
|
function __vrot_summary
|
||||||
|
set -l out $argv[1]
|
||||||
|
set -l size ''
|
||||||
|
if command -q numfmt
|
||||||
|
set size (numfmt --to=iec --suffix=B -- (stat -c %s -- "$out") 2>/dev/null)
|
||||||
|
else
|
||||||
|
set size (du -h -- "$out" | string replace -r '\t.*' '')
|
||||||
|
end
|
||||||
|
set -l dims (ffprobe -v error -select_streams v:0 \
|
||||||
|
-show_entries stream=width,height -of default=noprint_wrappers=1:nokey=1 "$out" \
|
||||||
|
| string match -r '^\d+$' | string join '×')
|
||||||
|
set -l extra ''
|
||||||
|
if test -n "$dims"
|
||||||
|
set extra " · $dims"
|
||||||
|
end
|
||||||
|
echo "$vrot_c_ok ✔ $out$vrot_c_dim ($size$extra)$vrot_c_reset"
|
||||||
|
end
|
||||||
|
|
||||||
|
function __vrot_banner
|
||||||
|
set -l title $argv[1]
|
||||||
|
echo "$vrot_c_dim"(string repeat -n 58 '─')"$vrot_c_reset"
|
||||||
|
echo "$vrot_c_hi $title$vrot_c_reset"
|
||||||
|
end
|
||||||
|
|
||||||
|
function __vrot_colors
|
||||||
|
set -q vrot_colors_set; and return 0
|
||||||
|
set -g vrot_colors_set 1
|
||||||
|
if isatty stdout
|
||||||
|
set -g vrot_c_hi (set_color brwhite --bold)
|
||||||
|
set -g vrot_c_dim (set_color brblack)
|
||||||
|
set -g vrot_c_ok (set_color brgreen)
|
||||||
|
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 hi dim ok warn err reset
|
||||||
|
set -g vrot_c_$c ''
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function __vrot_fmtsecs
|
||||||
|
set -l s (math "max(0, round($argv[1]))")
|
||||||
|
set -l h (math "floor($s/3600)")
|
||||||
|
set -l m (math "floor($s%3600/60)")
|
||||||
|
set -l sec (math "$s%60")
|
||||||
|
if test $h -gt 0
|
||||||
|
printf '%02d:%02d:%02d' $h $m $sec
|
||||||
|
else
|
||||||
|
printf '%02d:%02d' $m $sec
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function __vrot_error
|
||||||
|
echo "$vrot_c_err""vrot: "$argv"$vrot_c_reset" >&2
|
||||||
|
end
|
||||||
|
|
||||||
|
function __vrot_usage
|
||||||
|
echo 'usage: vrot [options] <video> [<video> ...]'
|
||||||
|
echo
|
||||||
|
echo 'Rotates one or more videos and writes <name>_rot.<ext> next to each.'
|
||||||
|
echo
|
||||||
|
echo 'Default mode is metadata-only rotation: lossless and instant. Works for'
|
||||||
|
echo 'MP4/MOV/M4V (including GoPro files; unsupported data/timecode tracks are'
|
||||||
|
echo 'dropped automatically). If the container cannot carry the flag, vrot'
|
||||||
|
echo 'falls back to re-encoding, with a live progress bar. Players that'
|
||||||
|
echo 'ignore rotation flags need -r.'
|
||||||
|
echo
|
||||||
|
echo 'options:'
|
||||||
|
echo ' -a, --angle <90|180|270> clockwise angle (default 90)'
|
||||||
|
echo ' -r, --reencode rotate pixels by re-encoding'
|
||||||
|
echo ' -p, --preset <name> x264/x265 preset (default medium)'
|
||||||
|
echo ' -h, --help show this help'
|
||||||
|
end
|
||||||
@@ -47,4 +47,25 @@ if ping -c 1 -W 1 "100.64.0.3" >/dev/null 2>&1; then
|
|||||||
mount_cifs "//100.64.0.3/Apps" \
|
mount_cifs "//100.64.0.3/Apps" \
|
||||||
"/home/honney/mount/Apps" \
|
"/home/honney/mount/Apps" \
|
||||||
"credentials=/home/honney/.cred/trueNAS_credentials,vers=3.1.1,iocharset=utf8,rw,uid=1000,gid=1000,nounix,noperm,file_mode=0660,dir_mode=0770,hard,intr,cache=loose"
|
"credentials=/home/honney/.cred/trueNAS_credentials,vers=3.1.1,iocharset=utf8,rw,uid=1000,gid=1000,nounix,noperm,file_mode=0660,dir_mode=0770,hard,intr,cache=loose"
|
||||||
|
|
||||||
|
elif ping -c 1 -W 1 "192.168.188.122" >/dev/null 2>&1; then
|
||||||
|
# Mount Data (from fstab line 2)
|
||||||
|
mount_cifs "//192.168.188.122/Data" \
|
||||||
|
"/home/honney/mount/Data" \
|
||||||
|
"credentials=/home/honney/.cred/trueNAS_credentials,vers=3.1.1,iocharset=utf8,rw,uid=1000,gid=1000,nounix,noperm,file_mode=0660,dir_mode=0770,hard,intr,cache=loose"
|
||||||
|
|
||||||
|
# Mount Media (from fstab line 3)
|
||||||
|
mount_cifs "//192.168.188.122/Media" \
|
||||||
|
"/home/honney/mount/Media" \
|
||||||
|
"credentials=/home/honney/.cred/trueNAS_credentials,vers=3.1.1,iocharset=utf8,rw,uid=1000,gid=1000,nounix,noperm,file_mode=0660,dir_mode=0770,hard,intr,cache=loose"
|
||||||
|
|
||||||
|
# Mount Ripping (from fstab line 4)
|
||||||
|
mount_cifs "//192.168.188.122/Ripping" \
|
||||||
|
"/home/honney/mount/Ripping" \
|
||||||
|
"credentials=/home/honney/.cred/trueNAS_credentials,vers=3.1.1,iocharset=utf8,rw,uid=1000,gid=1000,nounix,noperm,file_mode=0660,dir_mode=0770,hard,intr,cache=loose"
|
||||||
|
|
||||||
|
# Mount Apps (from fstab line 5)
|
||||||
|
mount_cifs "//192.168.188.122/Apps" \
|
||||||
|
"/home/honney/mount/Apps" \
|
||||||
|
"credentials=/home/honney/.cred/trueNAS_credentials,vers=3.1.1,iocharset=utf8,rw,uid=1000,gid=1000,nounix,noperm,file_mode=0660,dir_mode=0770,hard,intr,cache=loose"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user