Posted By


plexus on 12/22/07

Tagged


Statistics


Viewed 357 times
Favorited by 1 user(s)

Resync .srt subtitles


/ Published in: Ruby
Save to your folder(s)



Copy this code and paste it in your HTML
  1. #!/usr/bin/ruby
  2.  
  3. =begin doc
  4. Arne Brasseur, http://www.arnebrasseur.net
  5. Copyright 2007
  6. Freely available under the terms of the BSD licence
  7.  
  8. Suppose you have a .srt file with subtitles,
  9. it's a textfile that looks like this:
  10.  
  11.  
  12. 1
  13. 00:00:54,788 --> 00:00:57,222
  14. Besides the constant urge and inability to pee...
  15.  
  16. 2
  17. 00:00:57,290 --> 00:00:59,087
  18. Are there other symptoms?
  19.  
  20. 3
  21. 00:01:08,835 --> 00:01:10,700
  22. I'll just have a look.
  23.  
  24.  
  25. You also have a movie file, you try to play it with
  26. mplayer the subs using mplayer but they're badly out of sync.
  27.  
  28. Play the movie again with mplayer and pause it (space)
  29. at a point in the beginning where you know a certain
  30. subtitle should start, e.g. subtitle 3 : "I'll just have a look"
  31.  
  32. Now look at your terminal, the last line looks like this:
  33.  
  34. A:12.2 V:12.2 A-V: 0.000 ct: 0.048 30580/30580 4% 0% 1.1% 0 0
  35.  
  36. That first number 12.2 is the current position in seconds, take note of this.
  37.  
  38. Repeat this but this time for a subtitle somewhere at the end of the movie.
  39.  
  40. Now use subscale.rb to reposition the subtitles:
  41.  
  42. subscale.rb Filename.srt 3 12.2 1130 5357.4 > new_subtitles.srt
  43.  
  44. =end
  45.  
  46.  
  47. module SubScaler
  48. class <<self
  49. def scale(filename, percentage)
  50. puts( SubList.load(filename) * Float(percentage) )
  51. end
  52.  
  53. def reposition(filename, id1, time1, id2, time2)
  54. id1, id2, time1, time2 = Integer(id1), Integer(id2), Float(time1), Float(time2)
  55. subs = SubList.load(filename)
  56.  
  57. orig_diff = subs[id2].from.value - subs[id1].from.value
  58. new_diff = time2 - time1
  59. subs *= (new_diff / orig_diff)
  60. subs += time1 - subs[id1].from.value
  61.  
  62. puts subs
  63. end
  64. end
  65.  
  66. class Time
  67. REGEX = /(\d{2}):(\d{2}):(\d{2}),(\d{3})/
  68.  
  69. attr_reader :value
  70.  
  71. class <<self
  72. def parse(str)
  73. hh,mm,ss,ms = str.scan(REGEX).flatten.map{|i| Float(i)}
  74. value = ((((hh*60)+mm)*60)+ss) + ms/1000
  75. self.new(value)
  76. end
  77. end
  78.  
  79. def initialize(value)
  80. @value = value
  81. end
  82.  
  83. def *(factor)
  84. Time.new(@value * factor)
  85. end
  86.  
  87. def +(term)
  88. Time.new(@value + term)
  89. end
  90.  
  91. def to_s
  92. ss = @value.floor
  93. ms = ((@value - ss)*1000).to_i
  94.  
  95. mm = ss / 60
  96. ss = ss - mm * 60
  97.  
  98. hh = mm / 60
  99. mm = mm - hh * 60
  100.  
  101. "%02i:%02i:%02i,%03i" % [hh, mm, ss, ms]
  102. end
  103. end
  104.  
  105. class Sub < Struct.new(:index, :from, :to, :sub)
  106. def *(factor)
  107. Sub.new(self.index, self.from * factor, self.to * factor, self.sub)
  108. end
  109.  
  110. def +(term)
  111. Sub.new(self.index, self.from + term, self.to + term, self.sub)
  112. end
  113.  
  114. def to_s
  115. "#{self.index}
  116. #{self.from} --> #{self.to}
  117. #{self.sub}
  118.  
  119. "
  120. end
  121. end
  122.  
  123. class SubList
  124. TSREGEX = /\d{2}:\d{2}:\d{2},\d{3}/
  125. REGEX = /(\d+)
  126. (#{TSREGEX}) --> (#{TSREGEX})
  127. (.*?)
  128.  
  129. /m
  130.  
  131. attr_accessor :subs
  132.  
  133. class <<self
  134. def load(fn)
  135. subs = IO.read(fn).scan(REGEX).map do |r|
  136. Sub.new(r[0], Time.parse(r[1]), Time.parse(r[2]), r[3])
  137. end
  138. self.new subs
  139. end
  140. end
  141.  
  142. def initialize(subs)
  143. @subs = subs
  144. end
  145.  
  146. def *(factor)
  147. SubList.new(@subs.map {|s| s * factor})
  148. end
  149.  
  150. def +(term)
  151. SubList.new(@subs.map {|s| s + term})
  152. end
  153.  
  154. def [](i)
  155. @subs[i-1]
  156. end
  157.  
  158. def to_s
  159. @subs.map {|s| s.to_s}.join
  160. end
  161. end
  162. end
  163.  
  164. if __FILE__ == $0
  165. if ARGV.length == 2
  166. SubScaler.scale(ARGV[0], ARGV[1])
  167. elsif ARGV.length == 5
  168. SubScaler.reposition(*ARGV[0..5])
  169. else
  170. puts %{
  171. Usage:
  172. #{File.basename $0} filename percentage
  173. #{File.basename $0} filename index1 time1 index2 time2
  174. }
  175. end
  176. end

URL: http://www.arnebrasseur.net

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.