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.

281 lines
8.5 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
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="localhost" #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. #EVIDTNELY NECESSARY SO THAT FILES AREN'T 198+ HRS IN LEN. AT THE END
  30. local DURATION=$( ffprobe -loglevel error -show_entries format=duration \
  31. -of default=noprint_wrappers=1:nokey=1 "$inFL" )
  32. ffmpeg -hide_banner -loglevel error -stats -i "$inFL" \
  33. -filter_complex "[0:v][0:s:$track]overlay[v]" -map "[v]" \
  34. -map 0:a -c:a copy -map 0:s -map -0:s:$track -c:s copy \
  35. -map_metadata 0 -map_chapters 0 -max_muxing_queue_size 9999 \
  36. -t $DURATION "$tmpFL"
  37. rm "$inFL" #SAVE SPACE
  38. encode "$tmpFL" "$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 < 15% MAX MOST LIKELY ISN'T FOR. AUD.
  166. #15% as LOTR dir. comm included, blows up the max number for them...
  167. currFrames=$( ffprobe -loglevel error -select_streams s:$SUBTITLEINDEX \
  168. -show_entries stream_tags=NUMBER_OF_FRAMES-eng -of csv=p=0 \
  169. "$tmpDIR/$fileNAME")
  170. if [ $( echo "($currFrames / $maxFrames) < 0.15"|bc -l ) -gt 0 ]
  171. then
  172. echo "BURNING STREAM $SUBTITLEINDEX (STREAM $minINDEX) from $fileNAME"
  173. burnSubs "$tmpDIR/$fileNAME" "$tmpDIR/TMP$fileNAME" "$workDIR/$fileNAME" $SUBTITLEINDEX
  174. else
  175. echo "MIN. SUB TRACK ($SUBTITLEINDEX [$minINDEX])) DUR. > 15% FILM, NOT BURNING"
  176. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
  177. fi
  178. else
  179. #TODO expand foreign scan for more than pgs subtitles Need ass and
  180. #subtitles filters; don't know how to differentiate at present time.
  181. #I'm actually kinda missing a good example; I'm sure they're in there
  182. #but I don't know which ones they are lol; lmk if you know one.
  183. echo "NOT A PGS SUBTITLE TYPE; PASSING ALL THROUGH, FUTURE DEV."
  184. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
  185. fi
  186. fi
  187. else
  188. #ONE OR FEWER SUB TRACKS
  189. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
  190. fi
  191. if [ $? != 0 ] || [ $( stat -c%s "$workDIR/$fileNAME" ) -eq 0 ]
  192. then
  193. #RUN FAILED (EITHER NONZERO EXIT OR THE FILE IS 0 BYTES LARGE)
  194. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  195. then
  196. ssh $HostName <<< "echo $( echo $filePATH | sed "s/[!@#$%^&*( ;)-]/\\\&/g" )>>$hostFile"
  197. else
  198. echo "$filePATH">>$hostFile
  199. fi
  200. let ++k
  201. echo "RUN ($fileNAME) FAILED ($k/60)"
  202. if [ $( stat -c%s "$workDIR/$fileNAME" ) -eq 0 ]
  203. then
  204. rm "$workDIR"/"$fileNAME"
  205. fi
  206. else
  207. #UPLOAD AND REMOVE THE TRANSCODED FILE
  208. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  209. then
  210. scp "$workDIR/$fileNAME" $HostName:"$( echo $filePATH | sed "s/[][!@#$%^&*( ;)]/\\\&/g" )"
  211. else
  212. rsync -a --progress "$workDIR/$fileNAME" "$filePATH"
  213. fi
  214. if [ $? != 0 ]
  215. then
  216. echo "UPLOAD OF $filePATH FAILED; EXITING"
  217. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  218. then
  219. ssh $HostName <<< "echo $( echo $filePATH | sed "s/[!@#$%^&*( ;)-]/\\\&/g" )>>$hostFile"
  220. else
  221. echo "$filePATH">>$hostFile
  222. fi
  223. exit 1
  224. else
  225. rm "$workDIR"/"$fileNAME"
  226. fi
  227. k=0
  228. fi
  229. #REMOVE THE TEMP FILE (if necessary)
  230. if ls "$workDIR"/"$fileNAME"
  231. then
  232. rm "$workDIR"/"$fileNAME"
  233. else
  234. echo "Workdir already cleaned"
  235. fi
  236. if ls "$tmpDIR"/"$fileNAME"
  237. then
  238. rm "$tmpDIR"/"$fileNAME"
  239. elif ls "$tmpDIR"/"TMP$fileNAME"
  240. then
  241. rm "$tmpDIR"/"TMP$fileNAME"
  242. else
  243. echo "Already removed $tmpDIR/$fileNAME?"
  244. fi
  245. else
  246. echo "OUT OF FILES!? (try number $j/50) ... sleeping 1 min"
  247. let ++j
  248. sleep 60
  249. fi
  250. #Increment if required
  251. if [ $iterLim == "true" ]
  252. then
  253. let --numIter
  254. fi
  255. let ++i
  256. echo "Done LOOP NUMBER $i!"
  257. done
  258. exit 0