fant0men

SRT (subtitle) centisecond rounding script

Jan 16th, 2020
128
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/bin/bash
  2. # This script will round all the centiseconds in an SRT subtitle file.
  3. # Every start time and end time of a subtitle will now end in ,?00
  4. #
  5. # Example:
  6. # 00:20:47,500 --> 00:20:52,600
  7. #
  8. # Instead of:
  9. # 00:20:47,457 --> 00:20:52,611
  10. #
  11. # This makes it a lot easier to edit the subtitle in for example Gnome Subtitles, if needed.
  12. # Even if you're not going to edit the subtitle afterwards, it just looks better using whole centiseconds.
  13. #
  14. # The output filename is the same as the input filename, only a random number is added to the name.
  15. # The start and end times of every subtitle line are adjusted so they don't overlap. They will all differ by at least 1 centisecond.
  16.  
  17. regex_p='[0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3}'
  18. regex_f="${regex_p} --> ${regex_p}"
  19.  
  20. usage () {
  21.     echo -e "Usage: $(basename "$0") [SRT]\n"
  22.     exit
  23. }
  24.  
  25. if=$(readlink -f "$1" 2>&-)
  26. of_tmp="${if%.srt}"
  27. of="${of_tmp}-${RANDOM}.srt"
  28.  
  29. if [[ ! -f $if ]]; then
  30.     usage
  31. fi
  32.  
  33. mapfile -t lines < <(cat "$if")
  34.  
  35. declare -a duration
  36.  
  37. # Creates a function called 'time_break', which breaks the 'time line' up in parts ($h $m $s $cs).
  38. time_break () {
  39.  
  40.     time="$1"
  41.  
  42.     h=$(sed -E -e 's/^([0-9]{2}).*$/\1/' -e 's/^0{1}//' <<<"$time")
  43.     m=$(sed -E -e 's/^[0-9]{2}\:([0-9]{2}).*$/\1/' -e 's/^0{1}//' <<<"$time")
  44.     s=$(sed -E -e 's/^[0-9]{2}\:[0-9]{2}\:([0-9]{2}).*$/\1/' -e 's/^0{1}//' <<<"$time")
  45.     cs=$(sed -E -e 's/^.*,([0-9]{3}).*$/\1/' -e 's/^0{1,2}//' <<<"$time")
  46.  
  47.     echo "$h $m $s $cs"
  48.  
  49. }
  50.  
  51. # Creates a function called 't_time_break', which will be used by the 't_time_calc' function to figure out if the time value of the previous 'time line' is equal to (or greater than) the current one.
  52. t_time_break () {
  53.  
  54.     h="$1"
  55.     m="$2"
  56.     s="$3"
  57.     cs="$4"
  58.  
  59.     # Converts all the numbers to centiseconds, because those kind of values will be easier to compare in the 't_time_calc' function.
  60.     h=$(( h * 60 * 60 * 1000 ))
  61.     m=$(( m * 60 * 1000 ))
  62.     s=$(( s * 1000 ))
  63.  
  64.     total_time=$(( h + m + s + cs ))
  65.  
  66.     echo "$total_time"
  67. }
  68.  
  69. # Creates a function called 'cs_calc', which will calculate the total number of centiseconds.
  70. cs_calc () {
  71.  
  72.     cs_in="$1"
  73.  
  74.     # Saves the last 2 (or 1) digits of $cs_in in $cs_tmp
  75.     cs_tmp=$(sed -E -e 's/.*(..)$/\1/' -e 's/^0*//' <<<"$cs_in")
  76.  
  77.     # If $cs_tmp is greater than 50, round it up, and if not, round it down.
  78.     if [[ $cs_tmp -ge 50 ]]; then
  79.         cs=$(( (cs_in - cs_tmp) + 100 ))
  80.     else
  81.         cs=$(( cs_in - cs_tmp ))
  82.     fi
  83.  
  84.     echo "$cs"
  85. }
  86.  
  87. # Creates a function called 'c_time_calc', which will calculate the total time of the current 'time line'.
  88. c_time_calc () {
  89.  
  90.     h="$1"
  91.     m="$2"
  92.     s="$3"
  93.     cs="$4"
  94.  
  95.     cs=$(cs_calc "$cs")
  96.  
  97.     # While $cs (centiseconds) is equal to (or greater than) 1000, clear the $cs variable and add 1 to the $s (seconds) variable.
  98.     while [[ $cs -ge 1000 ]]; do
  99.         s=$(( s + 1 ))
  100.         cs=$(( cs - 1000 ))
  101.     done
  102.  
  103.     # While $s (seconds) is equal to (or greater than) 60, clear the $s variable and add 1 to the $m (minutes) variable.
  104.     while [[ $s -ge 60 ]]; do
  105.         m=$(( m + 1 ))
  106.         s=$(( s - 60 ))
  107.     done
  108.  
  109.     # While $m (minutes) is equal to (or greater than) 60, clear the $m variable and add 1 to the $h (hours) variable.
  110.     while [[ $m -ge 60 ]]; do
  111.         h=$(( h + 1 ))
  112.         m=$(( m - 60 ))
  113.     done
  114.  
  115.     # While $h (hours) is equal to 100 (or greater than), clear the $h variable.
  116.     while [[ $h -ge 100 ]]; do
  117.         h=$(( h - 100 ))
  118.     done
  119.  
  120.     echo "$h $m $s $cs"
  121. }
  122.  
  123. # Creates a function called 't_time_calc', which will add the total time of the previous 'time line' to the current 'time line', plus a centisecond if centiseconds are identical with previous 'time line'.
  124. t_time_calc () {
  125.  
  126.     total_start_time=($1 $2 $3 $4)
  127.     total_stop_time=($5 $6 $7 $8)
  128.  
  129.     # Converts previous and current 'time line' to centiseconds...
  130.     c_tmp=$(t_time_break ${total_start_time[@]})
  131.     p_tmp=$(t_time_break ${total_stop_time[@]})
  132.  
  133.     # Until the value of the current 'time_line' is higher than the previous, add 1 centisecond.
  134.     until [[ $c_tmp -gt $p_tmp ]]; do
  135.         total_start_time[3]=$(( ${total_start_time[3]} + 100 ))
  136.         c_tmp=$(t_time_break ${total_start_time[@]})
  137.     done
  138.  
  139.     total_start_time=( $(c_time_calc ${total_start_time[@]}) )
  140.  
  141.     echo "${total_start_time[@]}"
  142. }
  143.  
  144. for (( i = 0; i < ${#lines[@]}; i++ )); do
  145.  
  146.     line="${lines[${i}]}"
  147.  
  148.     if [[ ! $line =~ $regex_f ]]; then
  149.         continue
  150.     fi
  151.  
  152.     mapfile -d' ' -t duration < <(sed -E 's/ --> / /' <<<"$line")
  153.     duration[0]=$(tr -d '[:blank:]' <<<"${duration[0]}")
  154.     duration[1]=$(tr -d '[:blank:]' <<<"${duration[1]}")
  155.  
  156.     c_total_start_time=( $(time_break "${duration[0]}") )
  157.     c_total_start_time=( $(c_time_calc ${c_total_start_time[@]}) )
  158.  
  159.     c_total_stop_time=( $(time_break "${duration[1]}") )
  160.     c_total_stop_time=( $(c_time_calc ${c_total_stop_time[@]}) )
  161.  
  162.     if [[ ${p_total_stop_time[0]} ]]; then
  163.         c_total_start_time=( $(t_time_calc ${c_total_start_time[@]} ${p_total_stop_time[@]}) )
  164.     fi
  165.  
  166.     p_total_stop_time=(${c_total_stop_time[@]})
  167.  
  168.     start_h="${c_total_start_time[0]}"
  169.     start_m="${c_total_start_time[1]}"
  170.     start_s="${c_total_start_time[2]}"
  171.     start_cs="${c_total_start_time[3]}"
  172.  
  173.     stop_h="${c_total_stop_time[0]}"
  174.     stop_m="${c_total_stop_time[1]}"
  175.     stop_s="${c_total_stop_time[2]}"
  176.     stop_cs="${c_total_stop_time[3]}"
  177.  
  178.     finished_line_start=$(printf "%02d:%02d:%02d,%03d" $start_h $start_m $start_s $start_cs)
  179.     finished_line_stop=$(printf "%02d:%02d:%02d,%03d" $stop_h $stop_m $stop_s $stop_cs)
  180.     finished_line="${finished_line_start} --> ${finished_line_stop}"
  181.     lines[${i}]="$finished_line"
  182.  
  183.     echo '***'
  184.     echo "$finished_line"
  185. done
  186.  
  187. touch "$of"
  188.  
  189. # Writes the array to $of (output file).
  190. for (( i = 0; i < ${#lines[@]}; i++ )); do
  191.     echo "${lines[${i}]}" >> "$of"
  192. done
RAW Paste Data