From e995a596621e5405b55ace787a5efb354283c1f9 Mon Sep 17 00:00:00 2001 From: Dan Snyder Date: Sun, 16 Feb 2025 16:59:20 -0500 Subject: [PATCH] Initial version of the script --- reencode.sh | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 reencode.sh diff --git a/reencode.sh b/reencode.sh new file mode 100644 index 0000000..ea6803c --- /dev/null +++ b/reencode.sh @@ -0,0 +1,190 @@ +#!/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