Skip to content

Instantly share code, notes, and snippets.

/ChuckHa Secret

Created October 5, 2009 01:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/f776754f514f54bbeb26 to your computer and use it in GitHub Desktop.
Save anonymous/f776754f514f54bbeb26 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'optparse'
# create an empty hash to hold the options
options = {}
optparse = OptionParser.new do|opts|
opts.banner = "Usage: shift_subtitle [options] infile outfile"
opts.on('-h', '--help', 'Display this screen') do
puts opts
exit
end
opts.on('-o', '--operation [add|sub]', 'What type of operation to use') do|o|
if o == 'add' or o == 'sub'
options[:operation] = o
else
puts "operation must be 'add' or 'sub'."
exit
end
end
opts.on('-t', '--time [HH:[MM:[SS,[mmm]]]]', 'Amount of time to shift') do|t|
options[:time] = t
end
end
optparse.parse!
# make sure the files exist...
ARGV[0] ? options[:file1] = ARGV[0] : exit
ARGV[1] ? options[:file2] = ARGV[1] : exit
class SubtitleTime
attr_accessor :hours, :minutes, :seconds, :milliseconds
# reverse char by char block
# at first comma, set milli
# at first : set seconds, etc.
def initialize(time, modifier='add')
num = ''
set_sec,set_min,set_hour= false
time.reverse.each_char do|char|
if num =~ /\d\d\d/
@milliseconds = num.to_i
num = ''
set_sec = true
elsif char == ':' and set_sec
@seconds = num.to_i
num = ''
set_sec = false
set_min = true
elsif char == ':' and set_min
@minutes = num.to_i
num = ''
set_min = false
set_hour = true
elsif char == ':' and set_hour
@hours = num.to_i
num = ''
else
num = char + num
end
end
if set_sec
@seconds = num.to_i
elsif set_min
@minutes = num.to_i
elsif set_hour
@hours = num.to_i
end
@milliseconds = @milliseconds || 0
@seconds = @seconds || 0
@minutes = @minutes || 0
@hours = @hours || 0
@modifier = modifier
end
def change_hour(hours)
if @modifier == 'add'
@hours += hours
else
@hours -= hours
if @hours < 0
@hours = 0
end
end
end
def change_min(minutes)
if @modifier == 'add'
@minutes += minutes
if @minutes >= 60
hours = @minutes/60
change_hour(hours)
@minutes %= 60
end
else
@minutes -= minutes
if @minutes < 0
change_hour(1)
@minutes += 60
end
end
end
def change_sec(seconds)
if @modifier == 'add'
@seconds += seconds
if @seconds >= 60
minutes = @seconds/60
change_min(minutes)
@seconds %= 60
end
else
@seconds -= seconds
if @seconds < 0
change_min(1)
@seconds += 60
end
end
end
def change_milli(milli)
if @modifier == 'add'
@milliseconds += milli
if @milliseconds >= 1000
seconds = @milliseconds/1000
change_sec(seconds)
@milliseconds %= 1000
end
else
@milliseconds -= milli
if @milliseconds < 0
change_sec(1)
@milliseconds += 1000
end
end
end
def to_s
return sprintf("%02d:%02d:%02d,%03d", @hours, @minutes, @seconds, @milliseconds)
end
end
# turn the input time into a SubtitleTime object
time_mod = SubtitleTime.new(options[:time])
out_file = File.new(options[:file2], "w")
# every line that has timestamps
# take each time stamp split into h/m/s/ms
# apply the operation
# how to deal with carry overs?
IO.foreach(options[:file1]) do|line|
if (line =~ /-->/)
first = SubtitleTime.new(line.split(/ --> /)[0], options[:operation])
second = SubtitleTime.new(line.split(/ --> /)[1], options[:operation])
first.change_hour(time_mod.hours)
first.change_min(time_mod.minutes)
first.change_sec(time_mod.seconds)
first.change_milli(time_mod.milliseconds)
second.change_hour(time_mod.hours)
second.change_min(time_mod.minutes)
second.change_sec(time_mod.seconds)
second.change_milli(time_mod.milliseconds)
out_file.syswrite("#{first.to_s} --> #{second.to_s}\n")
else
out_file.syswrite(line)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment