#!/bin/sh # # Section: Argument parsing # options="sim run full" if [ $# -ne 2 ]; then echo "reencode <$( echo "$options" | sed 's/ /|/g' )> " exit 1 fi mode="" for opt in $options; do if [ "$opt" = "$1" ]; then mode="$opt" fi done if [ "$mode" = "" ]; then echo "'$1' is not a valid option" exit 1 fi path="$2" cd "$path" if [ $? -ne 0 ]; then echo "Path does not exist: $path" exit 1 fi echo "Searching for MKVs in $( pwd )" # # Section: Functions # getCodec() { ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of compact=p=0:nk=1 "$1" } fileSize() { du -sb "$1" | awk '{print $1}' } getBitrate() { ffprobe -v quiet -select_streams v:0 -show_entries format=bit_rate -of compact=p=0:nk=1 "$1" } formatSize() { echo "$1" | numfmt --to=iec-i | awk '{print $1"B"}' } formatRate() { echo "$1" | numfmt --to=si | awk '{print $1"bps"}' } encodeFile() { process=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $1}' ) filesize=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $2}' ) bitrate=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $3}' ) codec=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $4}' ) infile=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $5}' | sed "s/^'\|'\$//g" ) outfile=$( echo $1 | awk -v FPAT="([^' ]+)|'([^']+)'" '{print $6}' | sed "s/^'\|'\$//g" ) if [ "$process" = "Ignore" ]; then return 1 fi tmpfile="$infile.bak" mv "$infile" "$tmpfile" if [ $? -ne 0 ]; then echo "Failed to make backup file: $infile" return 2 fi ffmpeg -nostdin -hide_banner -i "$tmpfile" -c:v hevc_nvenc -c:a copy -c:s copy -map 0 -vtag hvc1 "$outfile" if [ $? -ne 0 ]; then echo "FFMPEG re-encode failed: $infile" echo "Restoring from backup" mv -f "$tmpfile" "$infile" return 1 fi echo "Output file: $outfile" rm -f "$tmpfile" oldsize=$( echo "$filesize" | formatSize ) oldbitr=$( echo "$bitrate" | formatRate ) newsize=$( fileSize "$outfile" | formatSize ) newbitr=$( getBitrate "$outfile" | formatRate ) echo "Converted $infile:" >> summary.txt echo "\t$oldsize ($oldbitr) => $newsize ($newbitr)\n" >> summary.txt return 0 } getFileInfo() { # Args: # $1 - video file name # # Returns a single line: # filesize bitrate codec echo "$( fileSize "$1" ) $( getBitrate "$1" ) $( getCodec "$1" )" } selectFile() { # Arg: # $1 - filename # $2 - filesize # $3 - bitrate # $4 - codec # # Note: args line up with return values from getFileInfo # # Echo "Ignore" or "Process" with an optional reason file=$1 size=$2 bitrate=$3 codec=$4 #if [ "$codec" = "hevc" ]; then # echo "Ignore Already HEVC" # return #fi if [ $bitrate -lt 4000000 ]; then echo "Ignore bitrate too low" else echo "Process" fi } simFile() { # Arg: # $1 - video file name # # Prints out a line to simulate.txt formatted like so: # process filesize bitrate codec infile outfile fileinfo=$( getFileInfo "$1" ) selected=$( selectFile "$1" $fileinfo ) outputfile="${1%.*}.mkv" reason=${selected#* } selected=$( echo "$selected" | awk '{print $1}' ) if [ "$selected" = "Ignore" ]; then echo "$selected $fileinfo '$1' '$reason'" >> simulation.txt echo "Ignored $1" echo "\t => $reason" else echo "$selected $fileinfo '$1' '$outputfile' '$reason'" >> simulation.txt echo "Selected $1" fi } # # Section: Main code - do mode-specific stuff # if [ "$mode" != "run" ]; then # if mode is not run (sim or full) then we're doing a simulation rm -f simulation.txt find -type f \( -name "*.mkv" -o -name "*.mp4" \) | while read file; do simFile "$file" done fi if [ "$mode" != "sim" ]; then # if mode is not sim (run or full) then we're actually executing re-encodings rm -f output.mkv if [ ! -f "simulation.txt" ]; then echo "No simulation file found. Cannot proceed." exit 1 fi cat simulation.txt | while read line; do encodeFile "$line" if [ $? -ne 0 ]; then exit 2 fi done fi