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.

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