|
|
@ -0,0 +1,274 @@ |
|
|
|
#!/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 |
|
|
|
HostName="Clementine" #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 |
|
|
|
ffmpeg -hide_banner -loglevel error -stats -re -i "$tmpFL" -map 0 -c copy \ |
|
|
|
-c:v libx265 -preset slow -x265-params crf=23 -map_metadata 0 \ |
|
|
|
-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 |
|
|
|
|
|
|
|
encode "$inFL" "$tmpFL" |
|
|
|
|
|
|
|
rm "$inFL" #SAVE SPACE |
|
|
|
|
|
|
|
#EVIDTNELY NECESSARY SO THAT FILES AREN'T 198+ HRS IN LEN. AT THE END |
|
|
|
#(not that I'd complain abt 200+ hrs of Tanya [test file /shrug]) |
|
|
|
local DURATION=$( ffprobe -loglevel error -show_entries format=duration \ |
|
|
|
-of default=noprint_wrappers=1:nokey=1 "$tmpFL" ) |
|
|
|
|
|
|
|
ffmpeg -hide_banner -loglevel error -stats -i "$tmpFL" \ |
|
|
|
-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 "$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 ffprobe &> /dev/null |
|
|
|
then |
|
|
|
echo "Need to have ffprobe (and ffmpeg) installed" |
|
|
|
exit 1 |
|
|
|
fi |
|
|
|
if ! command -v 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 -T $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 $( 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 |
|
|
|
encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME" |
|
|
|
else |
|
|
|
#TEST SUBTITLE TYPE; IF NOT PGS SKIP IT; FEEL FREE TO FILL IN |
|
|
|
if grep -qi "pgs" <<< $( 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=$( 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 |
|
|
|
SUBTITLEINDEX=$(expr $minINDEX - ${streamNUMBERS[0]}) |
|
|
|
#TEST FRAMES IN SUB TRACK, IF < 50% MAX MOST LIKELY ISN'T FOR. AUD. |
|
|
|
currFrames=$( 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.50"|bc ) ] |
|
|
|
then |
|
|
|
echo "BURNING STREAM $SUBTITLEINDEX (STREAM $minINDEX) from $fileNAME" |
|
|
|
#2 PASS 1ST ALTERS VIDEO 2ND DOES SUB BURNING yes this was done dumb |
|
|
|
#but in my defense I didn't know how to burn before this logic mess. |
|
|
|
burnSubs "$tmpDIR/$fileNAME" "$tmpDIR/TMP$fileNAME" "$workDIR/$fileNAME" $SUBTITLEINDEX |
|
|
|
else |
|
|
|
echo "MIN. SUB TRACK ($SUBTITLEINDEX [$minINDEX])) DUR. > 50% 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 -T "$workDIR/$fileNAME" $HostName:"$( echo $filePATH | sed "s/[][!@#$%^&*( ;)]/\\\&/g" )" |
|
|
|
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 "$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 |