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.

280 lines
8.4 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. #!/bin/bash
  2. #Is a 'slave' script to run an ffmpeg (and ffprobe) command. Generally it will
  3. #take a file specified on the 'host' machine that has a list of files; copy a
  4. #version down locally, transcode it, then replace the original file on the
  5. #'host', and remove the temporary files.
  6. #
  7. #You will need to have both FFMPEG and FFPROBE installed (and will need
  8. #to pray to St. Isidore... good luck if you encounter issues.
  9. #Default operations, change if necessary
  10. HostName="Clementine" #if localhost then will do locally (removes ssh/scp cmds)
  11. hostFile="/tmp/transcode/list.txt"
  12. tmpDIR="$PWD/tmpTranscode"
  13. workDIR="$PWD/transcode"
  14. #DEFINE FUNCTIONS
  15. function encode {
  16. local tmpFL=$1
  17. local outFL=$2
  18. ffmpeg -hide_banner -loglevel error -stats -re -i "$tmpFL" -map 0 \
  19. -map_metadata 0 -c copy \
  20. -c:v libx265 -preset slow -x265-params crf=23 \
  21. -use_wallclock_as_timestamps 1 \
  22. -map_chapters 0 -max_muxing_queue_size 9999 "$outFL"
  23. }
  24. function burnSubs {
  25. local inFL=$1
  26. local tmpFL=$2
  27. local outFL=$3
  28. local track=$4
  29. encode "$inFL" "$tmpFL"
  30. rm "$inFL" #SAVE SPACE
  31. #EVIDTNELY NECESSARY SO THAT FILES AREN'T 198+ HRS IN LEN. AT THE END
  32. local DURATION=$( ffprobe -loglevel error -show_entries format=duration \
  33. -of default=noprint_wrappers=1:nokey=1 "$tmpFL" )
  34. ffmpeg -hide_banner -loglevel error -stats -i "$tmpFL" \
  35. -filter_complex "[0:v][0:s:$track]overlay[v]" -map "[v]" \
  36. -map 0:a -c:a copy -map 0:s -map -0:s:$track -c:s copy \
  37. -map_metadata 0 -map_chapters 0 -max_muxing_queue_size 9999 \
  38. -t $DURATION "$outFL"
  39. }
  40. #MAIN FUNCTION BEGINS
  41. mkdir -p $tmpDIR
  42. mkdir -p $workDIR
  43. if [ -n "$1" ]
  44. then
  45. numIter=$1
  46. iterLim="true"
  47. else
  48. numIter=20
  49. iterLim="false"
  50. fi
  51. if ! command -v ffprobe &> /dev/null
  52. then
  53. echo "Need to have ffprobe (and ffmpeg) installed"
  54. exit 1
  55. fi
  56. if ! command -v ffmpeg &> /dev/null
  57. then
  58. echo "Need to have ffmpeg (and ffprobe) installed"
  59. exit 1
  60. fi
  61. if ! command -v bc &> /dev/null
  62. then
  63. echo "Need to have bc installed (foreign audio scan)"
  64. exit 1
  65. fi
  66. i=0 #Total number of loops
  67. j=0 #Failed to obtain job
  68. k=0 #ffmpeg failed
  69. declare -a langs #Subtitle Languages
  70. while [ $numIter -gt 0 ] && [ $j -lt 50 ] && [ $k -lt 60 ]
  71. do
  72. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  73. then
  74. filePATH=$( ssh $HostName "head -n1 $hostFile;sed -i -e '1d' $hostFile" )
  75. else
  76. filePATH=$( head -n1 $hostFile;sed -i -e '1d' $hostFile )
  77. fi
  78. if [ -n "$filePATH" ]
  79. then
  80. j=0
  81. fileNAME=$( basename "$filePATH" )
  82. #PULL DOWN FILE
  83. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  84. then
  85. scp $HostName:"$( echo $filePATH | sed "s/[][!@#$%^&*( ;)]/\\\&/g" )" "$tmpDIR"
  86. else
  87. rsync -a --progress "$filePATH" "$tmpDIR/"
  88. fi
  89. #RUN FFMPROBE/FFMPEG
  90. echo "DOING $fileNAME"
  91. unset langs
  92. #DETERMINE THE NUMBER OF ENGLISH SUBTITLES (BURNING BEHAVIOUR)
  93. for line in $( ffprobe -loglevel error -select_streams s -show_entries\
  94. stream=index:stream_tags=language -of csv=p=0 \
  95. "$tmpDIR"/"$fileNAME" )
  96. do
  97. langs+=("$line")
  98. done
  99. unset line
  100. engCounter=0
  101. if [ ${#langs[@]} -gt 1 ]
  102. then
  103. #DETERMINE NUMBER OF ENGLISH-CONTAINING SUBTITLES
  104. unset streamNUMBERS
  105. declare -a streamNUMBERS
  106. for language in "${langs[@]}"
  107. do
  108. if grep -iq "eng" <<< $language
  109. then
  110. let ++engCounter
  111. delim=","
  112. unset addNumber
  113. addNumber=( "${language%%"$delim"*}" )
  114. streamNUMBERS+=($addNumber)
  115. fi
  116. done
  117. if [ $engCounter -lt 2 ]
  118. then
  119. #ONLY ONE ENG. SUB TRACK
  120. echo "ONE ENG. SUB TRACK"
  121. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
  122. else
  123. #TEST SUBTITLE TYPE; IF NOT PGS SKIP IT; FEEL FREE TO FILL IN
  124. if grep -qi "pgs" <<< $( ffprobe -loglevel error -select_streams s \
  125. -show_entries stream=codec_name \
  126. -of csv=p=0 "$tmpDIR"/"$fileNAME" )
  127. then
  128. # MORE THAN ONE SUB TRACK; HAVE TO FIGURE OUT WHICH TO BURN
  129. unset streamFRAMES
  130. declare -a streamFRAMES
  131. #Presuming the one to burn-in is the one with less frames
  132. unset minFrames
  133. unset maxFrames
  134. unset indexITER
  135. unset minINDEX
  136. minFrames=0
  137. maxFrames=0
  138. indexITER=0
  139. minINDEX=0
  140. for index in ${streamNUMBERS[@]}
  141. do
  142. SUBINDEX=$(expr $index - ${streamNUMBERS[0]})
  143. currFrames=$( ffprobe -loglevel error -select_streams s:$SUBINDEX \
  144. -show_entries stream_tags=NUMBER_OF_FRAMES-eng -of csv=p=0 \
  145. "$tmpDIR/$fileNAME")
  146. if [ $indexITER -lt 1 ]
  147. then
  148. minFrames=$currFrames
  149. maxFrames=$currFrames
  150. minINDEX=$index
  151. let ++indexITER
  152. elif [ $currFrames -lt $minFrames ]
  153. then
  154. minFrames=$currFrames
  155. minINDEX=$index
  156. let ++indexITER
  157. elif [ $currFrames -gt $maxFrames ]
  158. then
  159. maxFrames=$currFrames
  160. let ++indexITER
  161. fi
  162. done
  163. unset SUBTITLEINDEX
  164. SUBTITLEINDEX=$(expr $minINDEX - ${streamNUMBERS[0]})
  165. #TEST FRAMES IN SUB TRACK, IF < 50% MAX MOST LIKELY ISN'T FOR. AUD.
  166. currFrames=$( ffprobe -loglevel error -select_streams s:$SUBTITLEINDEX \
  167. -show_entries stream_tags=NUMBER_OF_FRAMES-eng -of csv=p=0 \
  168. "$tmpDIR/$fileNAME")
  169. if [ $( echo "($currFrames / $maxFrames) < 0.50"|bc -l ) ]
  170. then
  171. echo "BURNING STREAM $SUBTITLEINDEX (STREAM $minINDEX) from $fileNAME"
  172. burnSubs "$tmpDIR/$fileNAME" "$tmpDIR/TMP$fileNAME" "$workDIR/$fileNAME" $SUBTITLEINDEX
  173. else
  174. echo "MIN. SUB TRACK ($SUBTITLEINDEX [$minINDEX])) DUR. > 50% FILM, NOT BURNING"
  175. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
  176. fi
  177. else
  178. #TODO expand foreign scan for more than pgs subtitles Need ass and
  179. #subtitles filters; don't know how to differentiate at present time.
  180. #I'm actually kinda missing a good example; I'm sure they're in there
  181. #but I don't know which ones they are lol; lmk if you know one.
  182. echo "NOT A PGS SUBTITLE TYPE; PASSING ALL THROUGH, FUTURE DEV."
  183. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
  184. fi
  185. fi
  186. else
  187. #ONE OR FEWER SUB TRACKS
  188. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
  189. fi
  190. if [ $? != 0 ] || [ $( stat -c%s "$workDIR/$fileNAME" ) -eq 0 ]
  191. then
  192. #RUN FAILED (EITHER NONZERO EXIT OR THE FILE IS 0 BYTES LARGE)
  193. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  194. then
  195. ssh $HostName <<< "echo $( echo $filePATH | sed "s/[!@#$%^&*( ;)-]/\\\&/g" )>>$hostFile"
  196. else
  197. echo "$filePATH">>$hostFile
  198. fi
  199. let ++k
  200. echo "RUN ($fileNAME) FAILED ($k/60)"
  201. if [ $( stat -c%s "$workDIR/$fileNAME" ) -eq 0 ]
  202. then
  203. rm "$workDIR"/"$fileNAME"
  204. fi
  205. else
  206. #UPLOAD AND REMOVE THE TRANSCODED FILE
  207. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  208. then
  209. scp "$workDIR/$fileNAME" $HostName:"$( echo $filePATH | sed "s/[][!@#$%^&*( ;)]/\\\&/g" )"
  210. else
  211. rsync -a --progress "$workDIR/$fileNAME" "$filePATH"
  212. fi
  213. if [ $? != 0 ]
  214. then
  215. echo "UPLOAD OF $filePATH FAILED; EXITING"
  216. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  217. then
  218. ssh $HostName <<< "echo $( echo $filePATH | sed "s/[!@#$%^&*( ;)-]/\\\&/g" )>>$hostFile"
  219. else
  220. echo "$filePATH">>$hostFile
  221. fi
  222. exit 1
  223. else
  224. rm "$workDIR"/"$fileNAME"
  225. fi
  226. k=0
  227. fi
  228. #REMOVE THE TEMP FILE (if necessary)
  229. if ls "$workDIR"/"$fileNAME"
  230. then
  231. rm "$workDIR"/"$fileNAME"
  232. else
  233. echo "Workdir already cleaned"
  234. fi
  235. if ls "$tmpDIR"/"$fileNAME"
  236. then
  237. rm "$tmpDIR"/"$fileNAME"
  238. elif ls "$tmpDIR"/"TMP$fileNAME"
  239. then
  240. rm "$tmpDIR"/"TMP$fileNAME"
  241. else
  242. echo "Already removed $tmpDIR/$fileNAME?"
  243. fi
  244. else
  245. echo "OUT OF FILES!? (try number $j/50) ... sleeping 1 min"
  246. let ++j
  247. sleep 60
  248. fi
  249. #Increment if required
  250. if [ $iterLim == "true" ]
  251. then
  252. let --numIter
  253. fi
  254. let ++i
  255. echo "Done LOOP NUMBER $i!"
  256. done
  257. exit 0