SHARE
TWEET

chuck

a guest Sep 28th, 2009 109 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env ruby
  2. require 'optparse'
  3.  
  4. # create an empty hash to hold the options
  5. options = {}
  6.  
  7. optparse = OptionParser.new do|opts|
  8.     opts.banner = "Usage: shift_subtitle [options] infile outfile"
  9.  
  10.     opts.on('-h', '--help', 'Display this screen') do
  11.         puts opts
  12.         exit
  13.     end
  14.     opts.on('-o', '--operation [add|sub]', 'What type of operation to use') do|o|
  15.         if o == 'add' or o == 'sub'
  16.             options[:operation] = o
  17.         else
  18.             puts "operation must be 'add' or 'sub'."
  19.             exit
  20.         end
  21.     end
  22.     opts.on('-t', '--time [HH:[MM:[SS,[mmm]]]]', 'Amount of time to shift') do|t|
  23.         options[:time] = t
  24.     end
  25. end
  26.  
  27. optparse.parse!
  28.  
  29. # make sure the files exist...
  30. ARGV[0] ? options[:file1] = ARGV[0] : exit
  31. ARGV[1] ? options[:file2] = ARGV[1] : exit
  32.  
  33. class SubtitleTime
  34.     attr_accessor :hours, :minutes, :seconds, :milliseconds
  35.  
  36.     # reverse char by char block
  37.     # at first comma, set milli
  38.     # at first : set seconds, etc.
  39.     def initialize(time, modifier='add')
  40.         num = ''
  41.         set_sec,set_min,set_hour= false
  42.         time.reverse.each_char do|char|
  43.             if num =~ /\d\d\d/
  44.                 @milliseconds = num.to_i
  45.                 num = ''
  46.                 set_sec = true
  47.             elsif char == ':' and set_sec
  48.                 @seconds = num.to_i
  49.                 num = ''
  50.                 set_sec = false
  51.                 set_min = true
  52.             elsif char == ':' and set_min
  53.                 @minutes = num.to_i
  54.                 num = ''
  55.                 set_min = false
  56.                 set_hour = true
  57.             elsif char == ':' and set_hour
  58.                 @hours = num.to_i
  59.                 num = ''
  60.             else
  61.                 num = char + num
  62.             end
  63.         end
  64.         if set_sec
  65.             @seconds = num.to_i
  66.         elsif set_min
  67.             @minutes = num.to_i
  68.         elsif set_hour
  69.             @hours = num.to_i
  70.         end
  71.         @milliseconds = @milliseconds || 0
  72.         @seconds = @seconds || 0
  73.         @minutes = @minutes || 0
  74.         @hours = @hours || 0
  75.         @modifier = modifier
  76.     end
  77.  
  78.     def change_hour(hours)
  79.         if @modifier == 'add'
  80.             @hours += hours
  81.         else
  82.             @hours -= hours
  83.             if @hours < 0
  84.                 @hours = 0
  85.             end
  86.         end
  87.     end
  88.  
  89.     def change_min(minutes)
  90.         if @modifier == 'add'
  91.             @minutes += minutes
  92.             if @minutes >= 60
  93.                 hours = @minutes/60
  94.                 change_hour(hours)
  95.                 @minutes %= 60
  96.             end
  97.         else
  98.             @minutes -= minutes
  99.             if @minutes < 0
  100.                 change_hour(1)
  101.                 @minutes += 60
  102.             end
  103.         end
  104.     end
  105.    
  106.     def change_sec(seconds)
  107.         if @modifier == 'add'
  108.             @seconds += seconds
  109.             if @seconds >= 60
  110.                 minutes = @seconds/60
  111.                 change_min(minutes)
  112.                 @seconds %= 60
  113.             end
  114.         else
  115.             @seconds -= seconds
  116.             if @seconds < 0
  117.                 change_min(1)
  118.                 @seconds += 60
  119.             end
  120.         end
  121.     end
  122.  
  123.     def change_milli(milli)
  124.         if @modifier == 'add'
  125.             @milliseconds += milli
  126.             if @milliseconds >= 1000
  127.                 seconds = @milliseconds/1000
  128.                 change_sec(seconds)
  129.                 @milliseconds %= 1000
  130.             end
  131.         else
  132.             @milliseconds -= milli
  133.             if @milliseconds < 0
  134.                 change_sec(1)
  135.                 @milliseconds += 1000
  136.             end
  137.         end
  138.     end
  139.    
  140.     def to_s
  141.         return sprintf("%02d:%02d:%02d,%03d", @hours, @minutes, @seconds, @milliseconds)
  142.     end
  143. end
  144.  
  145. # turn the input time into a SubtitleTime object
  146. time_mod = SubtitleTime.new(options[:time])
  147.  
  148.  
  149. out_file = File.new(options[:file2], "w")
  150.  
  151. # every line that has timestamps
  152. # take each time stamp split into h/m/s/ms
  153. # apply the operation
  154. # how to deal with carry overs?
  155. IO.foreach(options[:file1]) do|line|
  156.     if (line =~ /-->/)
  157.         first = SubtitleTime.new(line.split(/ --> /)[0], options[:operation])
  158.         second = SubtitleTime.new(line.split(/ --> /)[1], options[:operation])
  159.         first.change_hour(time_mod.hours)
  160.         first.change_min(time_mod.minutes)
  161.         first.change_sec(time_mod.seconds)
  162.         first.change_milli(time_mod.milliseconds)
  163.         second.change_hour(time_mod.hours)
  164.         second.change_min(time_mod.minutes)
  165.         second.change_sec(time_mod.seconds)
  166.         second.change_milli(time_mod.milliseconds)
  167.         out_file.syswrite("#{first.to_s} --> #{second.to_s}\n")
  168.     else
  169.         out_file.syswrite(line)
  170.     end
  171. end
RAW Paste Data
Top