decided to actually go through git as was doing too many scripts... uses ffmpeg to transcode a list of files into AV1 format.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

283 lines
8.6 KiB

#!/bin/bash
#Is a 'slave' script to run an ffmpeg (and ffprobe) command. Generally it will
#take a file specified on the 'host' machine that has a list of files; copy a
#version down locally, transcode it, then replace the original file on the
#'host', and remove the temporary files.
#
#You will need to have both FFMPEG and FFPROBE installed (and will need
#to pray to St. Isidore... good luck if you encounter issues.
#Default operations, change if necessary
FFBIN="/usr/bin/" #if unusual install or a specific version
HostName="localhost" #if localhost then will do locally (removes ssh/scp cmds)
hostFile="/tmp/transcode/list.txt"
tmpDIR="$PWD/tmpTranscode"
workDIR="$PWD/transcode"
#DEFINE FUNCTIONS
function encode {
local tmpFL=$1
local outFL=$2
$FFBIN/ffmpeg -hide_banner -loglevel error -stats -re -i "$tmpFL" -map 0 \
-map_metadata 0 -c copy \
-c:v libx265 -preset slow -x265-params crf=23 \
-use_wallclock_as_timestamps 1 \
-map_chapters 0 -max_muxing_queue_size 9999 "$outFL"
}
function burnSubs {
local inFL=$1
local tmpFL=$2
local outFL=$3
local track=$4
#EVIDTNELY NECESSARY SO THAT FILES AREN'T 198+ HRS IN LEN. AT THE END
local DURATION=$( ffprobe -loglevel error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 "$inFL" )
$FFBIN/ffmpeg -hide_banner -loglevel error -stats -i "$inFL" \
-filter_complex "[0:v][0:s:$track]overlay[v]" -map "[v]" \
-map 0:a -c:a copy -map 0:s -map -0:s:$track -c:s copy \
-map_metadata 0 -map_chapters 0 -max_muxing_queue_size 9999 \
-t $DURATION "$tmpFL"
rm "$inFL" #SAVE SPACE
encode "$tmpFL" "$outFL"
}
#MAIN FUNCTION BEGINS
mkdir -p "$tmpDIR"
mkdir -p "$workDIR"
if [ -n "$1" ]
then
numIter=$1
iterLim="true"
else
numIter=20
iterLim="false"
fi
if ! command -v $FFBIN/ffprobe &> /dev/null
then
echo "Need to have ffprobe (and ffmpeg) installed"
exit 1
fi
if ! command -v $FFBIN/ffmpeg &> /dev/null
then
echo "Need to have ffmpeg (and ffprobe) installed"
exit 1
fi
if ! command -v bc &> /dev/null
then
echo "Need to have bc installed (foreign audio scan)"
exit 1
fi
i=0 #Total number of loops
j=0 #Failed to obtain job
k=0 #ffmpeg failed
declare -a langs #Subtitle Languages
while [ $numIter -gt 0 ] && [ $j -lt 50 ] && [ $k -lt 60 ]
do
if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
then
filePATH=$( ssh $HostName "head -n1 $hostFile;sed -i -e '1d' $hostFile" )
else
filePATH=$( head -n1 $hostFile;sed -i -e '1d' $hostFile )
fi
if [ -n "$filePATH" ]
then
j=0
fileNAME=$( basename "$filePATH" )
#PULL DOWN FILE
if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
then
scp $HostName:"$( echo $filePATH | sed "s/[][!@#$%^&*( ;)]/\\\&/g" )" "$tmpDIR"
else
rsync -a --progress "$filePATH" "$tmpDIR/"
fi
#RUN FFMPROBE/FFMPEG
echo "DOING $fileNAME"
unset langs
#DETERMINE THE NUMBER OF ENGLISH SUBTITLES (BURNING BEHAVIOUR)
for line in $( $FFBIN/ffprobe -loglevel error -select_streams s -show_entries\
stream=index:stream_tags=language -of csv=p=0 \
"$tmpDIR"/"$fileNAME" )
do
langs+=("$line")
done
unset line
engCounter=0
if [ ${#langs[@]} -gt 1 ]
then
#DETERMINE NUMBER OF ENGLISH-CONTAINING SUBTITLES
unset streamNUMBERS
declare -a streamNUMBERS
for language in "${langs[@]}"
do
if grep -iq "eng" <<< $language
then
let ++engCounter
delim=","
unset addNumber
addNumber=( "${language%%"$delim"*}" )
streamNUMBERS+=($addNumber)
fi
done
if [ $engCounter -lt 2 ]
then
#ONLY ONE ENG. SUB TRACK
echo "ONE ENG. SUB TRACK"
encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
else
#TEST SUBTITLE TYPE; IF NOT PGS SKIP IT; FEEL FREE TO FILL IN
if grep -qi "pgs" <<< $( $FFBIN/ffprobe -loglevel error -select_streams s \
-show_entries stream=codec_name \
-of csv=p=0 "$tmpDIR"/"$fileNAME" )
then
# MORE THAN ONE SUB TRACK; HAVE TO FIGURE OUT WHICH TO BURN
unset streamFRAMES
declare -a streamFRAMES
#Presuming the one to burn-in is the one with less frames
unset minFrames
unset maxFrames
unset indexITER
unset minINDEX
minFrames=0
maxFrames=0
indexITER=0
minINDEX=0
for index in ${streamNUMBERS[@]}
do
SUBINDEX=$(expr $index - ${streamNUMBERS[0]})
currFrames=$( $FFBIN/ffprobe -loglevel error -select_streams s:$SUBINDEX \
-show_entries stream_tags=NUMBER_OF_FRAMES-eng -of csv=p=0 \
"$tmpDIR/$fileNAME")
if [ $indexITER -lt 1 ]
then
minFrames=$currFrames
maxFrames=$currFrames
minINDEX=$index
let ++indexITER
elif [ $currFrames -lt $minFrames ]
then
minFrames=$currFrames
minINDEX=$index
let ++indexITER
elif [ $currFrames -gt $maxFrames ]
then
maxFrames=$currFrames
let ++indexITER
fi
done
unset SUBTITLEINDEX
SUBTITLEINDEX=$(expr $minINDEX - ${streamNUMBERS[0]})
#TEST FRAMES IN SUB TRACK, IF < 15% MAX MOST LIKELY ISN'T FOR. AUD.
#15% as LOTR dir. comm included, blows up the max number for them...
currFrames=$( $FFBIN/ffprobe -loglevel error -select_streams s:$SUBTITLEINDEX \
-show_entries stream_tags=NUMBER_OF_FRAMES-eng -of csv=p=0 \
"$tmpDIR/$fileNAME")
if [ $( echo "($currFrames / $maxFrames) < 0.25"|bc -l ) -gt 0 ]
then
echo "BURNING STREAM $SUBTITLEINDEX (STREAM $minINDEX) from $fileNAME"
burnSubs "$tmpDIR/$fileNAME" "$tmpDIR/TMP$fileNAME" "$workDIR/$fileNAME" $SUBTITLEINDEX
else
echo "MIN. SUB TRACK ($SUBTITLEINDEX [$minINDEX])) DUR. > 25% FILM, NOT BURNING"
encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
fi
else
#TODO expand foreign scan for more than pgs subtitles Need ass and
#subtitles filters; don't know how to differentiate at present time.
#I'm actually kinda missing a good example; I'm sure they're in there
#but I don't know which ones they are lol; lmk if you know one.
echo "NOT A PGS SUBTITLE TYPE; PASSING ALL THROUGH, FUTURE DEV."
encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
fi
fi
else
#ONE OR FEWER SUB TRACKS
encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
fi
if [ $? != 0 ] || [ $( stat -c%s "$workDIR/$fileNAME" ) -eq 0 ]
then
#RUN FAILED (EITHER NONZERO EXIT OR THE FILE IS 0 BYTES LARGE)
if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
then
ssh $HostName <<< "echo $( echo $filePATH | sed "s/[!@#$%^&*( ;)-]/\\\&/g" )>>$hostFile"
else
echo "$filePATH">>$hostFile
fi
let ++k
echo "RUN ($fileNAME) FAILED ($k/60)"
if [ $( stat -c%s "$workDIR/$fileNAME" ) -eq 0 ]
then
rm "$workDIR"/"$fileNAME"
fi
else
#UPLOAD AND REMOVE THE TRANSCODED FILE
if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
then
#scp "$workDIR/$fileNAME" $HostName:"$( echo $filePATH | sed "s/[][!@#$%^&*( ;)]/\\\&/g" )"
scp "$workDIR/$fileNAME" $HostName:"$filePATH"
else
rsync -a --progress "$workDIR/$fileNAME" "$filePATH"
fi
if [ $? != 0 ]
then
echo "UPLOAD OF $filePATH FAILED; EXITING"
if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
then
ssh $HostName <<< "echo $( echo $filePATH | sed "s/[!@#$%^&*( ;)-]/\\\&/g" )>>$hostFile"
else
echo "$filePATH">>$hostFile
fi
exit 1
else
rm "$workDIR"/"$fileNAME"
fi
k=0
fi
#REMOVE THE TEMP FILE (if necessary)
if ls "$workDIR"/"$fileNAME"
then
rm "$workDIR"/"$fileNAME"
else
echo "Workdir already cleaned"
fi
if ls "$tmpDIR"/"$fileNAME"
then
rm "$tmpDIR"/"$fileNAME"
elif ls "$tmpDIR"/"TMP$fileNAME"
then
rm "$tmpDIR"/"TMP$fileNAME"
else
echo "Already removed $tmpDIR/$fileNAME?"
fi
else
echo "OUT OF FILES!? (try number $j/50) ... sleeping 1 min"
let ++j
sleep 60
fi
#Increment if required
if [ $iterLim == "true" ]
then
let --numIter
fi
let ++i
echo "Done LOOP NUMBER $i!"
done
exit 0