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.

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