#!/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 # do_ffprobe() { ffprobe -v quiet -select_streams v:0 -show_entries $1 -of csv=p=0:nk=1 "$2" } get_codec() { do_ffprobe stream=codec_name "$1" } get_bitrate() { do_ffprobe format=bit_rate "$1" } get_resolution() { do_ffprobe stream=height,width "$1" } file_size() { du -sb "$1" | awk '{print $1}' } format_size() { echo "$1" | numfmt --to=iec-i | awk '{print $1"B"}' } format_rate() { echo "$1" | numfmt --to=si | awk '{print $1"bps"}' } encode_file() { 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" ffmpeg -nostdin -hide_banner -i "$infile" -c:v hevc_nvenc -c:a copy -c:s copy -map 0 -vtag hvc1 output.mkv if [ $? -ne 0 ]; then echo "FFMPEG re-encode failed: $infile" return 1 fi mv "$infile" "$tmpfile" if [ $? -ne 0 ]; then echo "Failed to make backup file: $infile" rm output.mkv return 2 fi mv output.mkv "$outfile" if [ $? -ne 0 ]; then echo "Failed final move to: $outfile" mv -f "$tmpfile" "$infile" rm output.mkv return 2 fi echo "Output file: $outfile" rm "$tmpfile" oldsize=$( format_size $filesize ) oldbitr=$( format_rate $bitrate ) newsize=$( format_size $( file_size "$outfile" ) ) newbitr=$( format_rate $( get_bitrate "$outfile" ) ) echo "Converted $infile:" >> summary.txt echo "\t$oldsize ($oldbitr) => $newsize ($newbitr)\n" >> summary.txt return 0 } get_file_info() { # Args: # $1 - video file name # # Returns a single line: # filesize bitrate codec echo "$( file_size "$1" ) $( get_bitrate "$1" ) $( get_codec "$1" )" } select_file() { # Arg: # $1 - filename # $2 - filesize # $3 - bitrate # $4 - codec # # Note: args line up with return values from get_file_info # # 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 } simulate_file() { # Arg: # $1 - video file name # # Prints out a line to simulate.txt formatted like so: # process filesize bitrate codec infile outfile fileinfo=$( get_file_info "$1" ) selected=$( select_file "$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 simulate_file "$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 encode_file "$line" if [ $? -eq 2 ]; then exit 2 fi done fi