plugin/gif: `shfmt`

My apologies to future `git blame` hunters ♥
pull/2014/head
John D Pell 2022-01-08 08:43:17 -08:00
parent b1b08de626
commit ce22710e00
2 changed files with 273 additions and 250 deletions

View File

@ -90,6 +90,7 @@ plugins/available/cmd-returned-notify.plugin.bash
plugins/available/direnv.plugin.bash plugins/available/direnv.plugin.bash
plugins/available/dirs.plugin.bash plugins/available/dirs.plugin.bash
plugins/available/docker-machine.plugin.bash plugins/available/docker-machine.plugin.bash
plugins/available/gif.plugin.bash
plugins/available/git-subrepo.plugin.bash plugins/available/git-subrepo.plugin.bash
plugins/available/git.plugin.bash plugins/available/git.plugin.bash
plugins/available/go.plugin.bash plugins/available/go.plugin.bash

View File

@ -1,5 +1,4 @@
# shellcheck shell=bash # shellcheck shell=bash
cite about-plugin
about-plugin 'video to gif, gif to WebM helper functions' about-plugin 'video to gif, gif to WebM helper functions'
# Based loosely on: # Based loosely on:
@ -13,7 +12,7 @@ about-plugin 'video to gif, gif to WebM helper functions'
# Optional: if lossy is not important, Ubuntu has gifsicle packaged for apt-get, instead of giflossy # Optional: if lossy is not important, Ubuntu has gifsicle packaged for apt-get, instead of giflossy
# Optional: gifski (from `brew install gifski` or github.com/ImageOptim/gifski) # Optional: gifski (from `brew install gifski` or github.com/ImageOptim/gifski)
# for high quality huge files. # for high quality huge files.
function v2gif { function v2gif() {
about 'Converts a .mov/.avi/.mp4 file into an into an animated GIF.' about 'Converts a .mov/.avi/.mp4 file into an into an animated GIF.'
group 'gif' group 'gif'
param '1: MOV/AVI/MP4 file name(s)' param '1: MOV/AVI/MP4 file name(s)'
@ -31,25 +30,44 @@ function v2gif {
example '$ v2gif -dh *.avi' example '$ v2gif -dh *.avi'
example '$ v2gif -thw 600 *.avi *.mov' example '$ v2gif -thw 600 *.avi *.mov'
local convert="$(type -p convert)" ; [[ -x "$convert" ]] || { echo "No convert found!" ; return 2 ;} local convert ffmpeg mediainfo gifsicle getopt args gifski out_size
local ffmpeg="$(type -p ffmpeg)" ; [[ -x "$ffmpeg" ]] || { echo "No ffmpeg found!" ; return 2 ;}
local mediainfo="$(type -p mediainfo)" ; [[ -x "$mediainfo" ]] || { echo "No mediainfo found!" ; return 2 ;} convert="$(type -p convert)"
local gifsicle="$(type -p gifsicle)" ; [[ -x "$gifsicle" ]] || { echo "No gifsicle found!" ; return 2 ;} [[ -x "$convert" ]] || {
local getopt="$(type -p getopt)" echo "No convert found!"
return 2
}
ffmpeg="$(type -p ffmpeg)"
[[ -x "$ffmpeg" ]] || {
echo "No ffmpeg found!"
return 2
}
mediainfo="$(type -p mediainfo)"
[[ -x "$mediainfo" ]] || {
echo "No mediainfo found!"
return 2
}
gifsicle="$(type -p gifsicle)"
[[ -x "$gifsicle" ]] || {
echo "No gifsicle found!"
return 2
}
getopt="$(type -p getopt)"
if [[ "$OSTYPE" == "darwin"* ]]; then if [[ "$OSTYPE" == "darwin"* ]]; then
# Getopt on BSD is incompatible with GNU # Getopt on BSD is incompatible with GNU
getopt=/usr/local/opt/gnu-getopt/bin/getopt getopt=/usr/local/opt/gnu-getopt/bin/getopt
[[ -x "$getopt" ]] || { echo "No GNU-getopt found!" ; return 2 ;} [[ -x "$getopt" ]] || {
echo "No GNU-getopt found!"
return 2
}
fi fi
# Parse the options # Parse the options
local args=$($getopt -l "alert:" -l "lossy:" -l "width:" -l del,delete -l high -l tag -l "fps:" -l webm -o "a:l:w:f:dhmt" -- "$@") args=$("$getopt" -l "alert:" -l "lossy:" -l "width:" -l del,delete -l high -l tag -l "fps:" -l webm -o "a:l:w:f:dhmt" -- "$@") || {
if [ $? -ne 0 ]; then
echo 'Terminating...' >&2 echo 'Terminating...' >&2
return 2 return 2
fi }
eval set -- "$args" eval set -- "$args"
local use_gifski="" local use_gifski=""
@ -64,7 +82,7 @@ function v2gif {
local fps="" local fps=""
local make_webm="" local make_webm=""
local alert=5000 local alert=5000
while [ $# -ge 1 ]; do while [[ $# -ge 1 ]]; do
case "$1" in case "$1" in
--) --)
# No more options left. # No more options left.
@ -78,7 +96,11 @@ function v2gif {
;; ;;
-h | --high) -h | --high)
#High Quality, use gifski #High Quality, use gifski
local gifski="$(type -p gifski)" ; [[ -x "$gifski" ]] || { echo "No gifski found!" ; return 2 ; } gifski="$(type -p gifski)"
[[ -x "$gifski" ]] || {
echo "No gifski found!"
return 2
}
use_gifski=true use_gifski=true
giftag="${giftag}-h" giftag="${giftag}-h"
shift shift
@ -141,18 +163,18 @@ function v2gif {
local output_file="${file%.*}${giftag}.gif" local output_file="${file%.*}${giftag}.gif"
local del_after=$opt_del_after local del_after=$opt_del_after
if [[ "$make_webm" ]] ; then if [[ -n "$make_webm" ]]; then
$ffmpeg -loglevel panic -i "$file" \ $ffmpeg -loglevel panic -i "$file" \
-c:v libvpx -crf 4 -threads 0 -an -b:v 2M -auto-alt-ref 0 \ -c:v libvpx -crf 4 -threads 0 -an -b:v 2M -auto-alt-ref 0 \
-quality best -loop 0 "${file%.*}.webm" || return 2 -quality best -loop 0 "${file%.*}.webm" || return 2
fi fi
# Set FPS to match the video if possible, otherwise fallback to default. # Set FPS to match the video if possible, otherwise fallback to default.
if [[ "$infps" ]] ; then if [[ -n "$infps" ]]; then
fps=$infps fps=$infps
else else
fps=$defaultfps fps=$defaultfps
if [[ -x $mediainfo ]] ; then if [[ -x "$mediainfo" ]]; then
fps=$($mediainfo "$file" | grep "Frame rate " | sed 's/.*: \([0-9.]\+\) .*/\1/' | head -1) fps=$($mediainfo "$file" | grep "Frame rate " | sed 's/.*: \([0-9.]\+\) .*/\1/' | head -1)
[[ -z "$fps" ]] && fps=$($mediainfo "$file" | grep "Minimum frame rate" | sed 's/.*: \([0-9.]\+\) .*/\1/' | head -1) [[ -z "$fps" ]] && fps=$($mediainfo "$file" | grep "Minimum frame rate" | sed 's/.*: \([0-9.]\+\) .*/\1/' | head -1)
fi fi
@ -162,19 +184,19 @@ function v2gif {
if [[ "$use_gifski" = "true" ]]; then if [[ "$use_gifski" = "true" ]]; then
# I trust @pornel to do his own resizing optimization choices # I trust @pornel to do his own resizing optimization choices
$ffmpeg -loglevel panic -i "$file" -r $fps -vcodec png v2gif-tmp-%05d.png && \ $ffmpeg -loglevel panic -i "$file" -r "$fps" -vcodec png v2gif-tmp-%05d.png \
$gifski v2gif-tmp-*.png $maxwidthski --fps $(printf "%.0f" $fps) -o "$output_file" || return 2 && $gifski v2gif-tmp-*.png "$maxwidthski" --fps "$(printf "%.0f" "$fps")" -o "$output_file" || return 2
else else
$ffmpeg -loglevel panic -i "$file" $maxsize -r $fps -vcodec png v2gif-tmp-%05d.png && \ $ffmpeg -loglevel panic -i "$file" "$maxsize" -r "$fps" -vcodec png v2gif-tmp-%05d.png \
$convert +dither -layers Optimize v2gif-tmp-*.png GIF:- | \ && $convert +dither -layers Optimize v2gif-tmp-*.png GIF:- \
$gifsicle $lossiness --no-warnings --colors 256 --delay=$(echo "100/$fps"|bc) --loop --optimize=3 --multifile - > "$output_file" || return 2 | $gifsicle "$lossiness" --no-warnings --colors 256 --delay="$(echo "100/$fps" | bc)" --loop --optimize=3 --multifile - > "$output_file" || return 2
fi fi
rm v2gif-tmp-*.png rm v2gif-tmp-*.png
# Checking if the file is bigger than Twitter likes and warn # Checking if the file is bigger than Twitter likes and warn
if [[ $alert -gt 0 ]]; then if [[ $alert -gt 0 ]]; then
local out_size=$(wc --bytes < "$output_file") out_size=$(wc --bytes < "$output_file")
if [[ $out_size -gt $((alert * 1000)) ]]; then if [[ $out_size -gt $((alert * 1000)) ]]; then
echo "$(tput setaf 3)Warning: '$output_file' is $((out_size / 1000))kb.$(tput sgr 0)" echo "$(tput setaf 3)Warning: '$output_file' is $((out_size / 1000))kb.$(tput sgr 0)"
[[ "$del_after" == "true" ]] && echo "$(tput setaf 3)Warning: Keeping '$file' even though --del requested.$(tput sgr 0)" [[ "$del_after" == "true" ]] && echo "$(tput setaf 3)Warning: Keeping '$file' even though --del requested.$(tput sgr 0)"
@ -202,13 +224,13 @@ function any2webm() {
example '$ any2webm foo.gif' example '$ any2webm foo.gif'
example '$ any2webm *.mov -b 1.5M -s 600x480' example '$ any2webm *.mov -b 1.5M -s 600x480'
# Parse the options local args out_size
local args=$(getopt -l alert -l "bandwidth:" -l "width:" -l del,delete -l tag -l "fps:" -l webm -o "a:b:w:f:dt" -- "$@")
if [ $? -ne 0 ]; then # Parse the options
args=$(getopt -l alert -l "bandwidth:" -l "width:" -l del,delete -l tag -l "fps:" -l webm -o "a:b:w:f:dt" -- "$@") || {
echo 'Terminating...' >&2 echo 'Terminating...' >&2
return 2 return 2
fi }
eval set -- "$args" eval set -- "$args"
local opt_del_after="" local opt_del_after=""
@ -219,7 +241,7 @@ function any2webm() {
local fps="" local fps=""
local bandwidth="2M" local bandwidth="2M"
local alert=5000 local alert=5000
while [ $# -ge 1 ]; do while [[ $# -ge 1 ]]; do
case "$1" in case "$1" in
--) --)
# No more options left. # No more options left.
@ -278,12 +300,12 @@ function any2webm() {
echo "$(tput setaf 2)Creating '$output_file' ...$(tput sgr 0)" echo "$(tput setaf 2)Creating '$output_file' ...$(tput sgr 0)"
$ffmpeg -loglevel panic -i "$file" \ $ffmpeg -loglevel panic -i "$file" \
-c:v libvpx -crf 4 -threads 0 -an -b:v $bandwidth -auto-alt-ref 0 \ -c:v libvpx -crf 4 -threads 0 -an -b:v "$bandwidth" -auto-alt-ref 0 \
-quality best $fps $size -loop 0 -pix_fmt yuva420p "$output_file" || return 2 -quality best "$fps" "$size" -loop 0 -pix_fmt yuva420p "$output_file" || return 2
# Checking if the file is bigger than Twitter likes and warn # Checking if the file is bigger than Twitter likes and warn
if [[ $alert -gt 0 ]]; then if [[ $alert -gt 0 ]]; then
local out_size=$(wc --bytes < "$output_file") out_size=$(wc --bytes < "$output_file")
if [[ $out_size -gt $((alert * 1000)) ]]; then if [[ $out_size -gt $((alert * 1000)) ]]; then
echo "$(tput setaf 3)Warning: '$output_file' is $((out_size / 1000))kb.$(tput sgr 0)" echo "$(tput setaf 3)Warning: '$output_file' is $((out_size / 1000))kb.$(tput sgr 0)"
[[ "$del_after" == "true" ]] && echo "$(tput setaf 3)Warning: Keeping '$file' even though --del requested.$(tput sgr 0)" [[ "$del_after" == "true" ]] && echo "$(tput setaf 3)Warning: Keeping '$file' even though --del requested.$(tput sgr 0)"