commit 526f064e17bf862344c43fad92896f72ba62dd8b Author: rbeck4 Date: Wed Mar 3 11:31:58 2021 -0800 Version 3.1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..a4c330d --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +V3.1 +README COMING SOON diff --git a/transcode.sh b/transcode.sh new file mode 100644 index 0000000..7ec221d --- /dev/null +++ b/transcode.sh @@ -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