Class: EdlParser

Inherits:
Object show all
Defined in:
lib/edl_parser.rb

Constant Summary collapse

EDL_DIR =
File.expand_path(__DIR__  + "/../zamples/edit_decision_lists/dvds")

Class Method Summary collapse

Class Method Details

.all_edl_files_parsed(use_all_not_just_dvds) ⇒ Object



288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/edl_parser.rb', line 288

def self.all_edl_files_parsed use_all_not_just_dvds
  dir = EDL_DIR
  dir += "/.." if use_all_not_just_dvds
  Dir[dir + '/**/*.txt'].map{|filename|
      begin
        parsed = parse_file(filename)
        [filename, parsed]
      rescue SyntaxError => e
        # ignore poorly formed edit lists for the auto choose phase...
        p 'warning, unable to parse a file:' + filename + " " + e.to_s
        nil
      end
   }.compact
end

.convert_incoming_to_split_sectors(incoming, add_this_to_all_ends = 0, subtract_this_from_beginnings = 0, splits = []) ⇒ Object

called later, from external divides up mutes and blanks so that they don’t overlap, preferring blanks over mutes returns it like [[start,end,type], [s,e,t]…] type like either :blank and :mute

[70.0, 73.0, :blank], [378.0, 379.1, :mute]


203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/edl_parser.rb', line 203

def self.convert_incoming_to_split_sectors incoming, add_this_to_all_ends = 0, subtract_this_from_beginnings = 0, splits = []
  raise if subtract_this_from_beginnings < 0
  raise if add_this_to_all_ends < 0
  if splits != []
    # allow it to do all the double checks we later skip, just in case :)
    self.convert_incoming_to_split_sectors incoming
  end
  mutes = incoming["mutes"] || {}
  blanks = incoming["blank_outs"] || {}
  mutes = mutes.map{|k, v| get_secs(k, v, -subtract_this_from_beginnings, add_this_to_all_ends, splits) + [:mute]}
  blanks = blanks.map{|k, v| get_secs(k, v, -subtract_this_from_beginnings, add_this_to_all_ends, splits) + [:blank]}
  combined = (mutes+blanks).sort
  
  # detect overlap...
  previous = nil
  combined.each_with_index{|current, idx|
    s,e,t = current
    if e < s
     raise SyntaxError.new("detected an end before a start: #{e} < #{s}") if e < s unless splits.length > 0
    end
    if previous
      ps, pe, pt = previous
      if (s < pe)
        raise SyntaxError.new("detected an overlap #{[s,e,t].join(' ')} #{previous.join(' ')}") unless splits.length > 0
        # our start might be within the previous' in which case its their start, with (greater of our, their ending)
        preferred_end = [e,pe].max
        preferred_type = [t,pt].detect{|t| t == :blank} || :mute # prefer blank to mute
        combined[idx-1] = [ps, preferred_end, preferred_type]
        combined[idx] = nil # allow it to be culled later
      end
      
    end
    previous = current
  }
  combined.compact
end

.find_single_edit_list_matching(use_all = false) ⇒ Object

returns single matching filename



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/edl_parser.rb', line 304

def self.find_single_edit_list_matching use_all = false
  matching = all_edl_files_parsed(use_all).map{|filename, parsed|
    yield(parsed) ? filename : nil
  }.compact
  if matching.length == 1
    file = matching[0]
    p "selecting the one only matching EDL: #{file}"
    file
  elsif matching.length > 1
    p "found multiple matches for media? #{matching.inspect}"
    nil
  else
    nil
  end
end

.parse_file(filename, expand = true) ⇒ Object

returns => [[“00:00”, “00:00”, string1, string2, …], …], “blank_outs” -> […], “url” => …



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/edl_parser.rb', line 28

def self.parse_file filename, expand = true
  output = parse_string File.read(filename), filename, []
  # now respect a few options
  if relative = output["take_from_relative_file"]
    new_filename = File.dirname(filename) + '/' + relative
    new_input = parse_file new_filename
    output.merge! new_input
  end
  
  require_relative 'gui/sensible-cinema-dependencies' # for download method...
  
  if expand
  
    if output["from_url"] # replacement
      downloaded = SensibleSwing::MainWindow.download_to_string(output["from_url"])
      output = parse_string downloaded # full replacement
    end
    
    if imdb_id = output["imdb_id"]
      parse_imdb output, imdb_id
    end
  end
  output
end

.parse_imdb(output, imdb_id) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/edl_parser.rb', line 53

def self.parse_imdb output, imdb_id
      require_relative 'convert_thirty_fps'
      url = "http://www.imdb.com/title/#{imdb_id}/parentalguide"
      all = SensibleSwing::MainWindow.download_to_string(url)
      
      header, violence_word, violence_section, profanity_word, profanity_section, alcohol_word, alcohol_section, frightening_word, frightening_section = 
      sections = all.split(/<span>(Violence|Profanity|Alcohol|Frightening)/)
      header = sections.shift
      all ={}
      while(!sections.empty?) # my klugey to_hash method
        word_type = sections.shift
        settings = sections.shift
        assert word_type.in? ['Violence', 'Profanity', 'Alcohol', 'Frightening']
        all[word_type] = settings
      end
      # blank_outs or mutes for each...
      # TODO make the -> optional
      split_into_timestamps = /([\d:]+(?:\.\d+|))\W*-&gt;\W*([\d:]+(?:\.\d+|))([^\d\n]+)/
      for type, settings in all
        settings.scan(split_into_timestamps) do |begin_ts, end_ts, description|
          puts "parsing from wiki imdb  entry violence: #{begin_ts} #{end_ts} #{description} #{type}"
          start_seconds = translate_string_to_seconds begin_ts
          end_seconds = translate_string_to_seconds end_ts
          # convert from 30 to 29.97 fps ... we presume ...
          start_seconds = ConvertThirtyFps.from_twenty_nine_nine_seven start_seconds
          start_seconds = ("%.02f" % start_seconds).to_f # round
          start_seconds = translate_time_to_human_readable start_seconds, true
          end_seconds = ConvertThirtyFps.from_twenty_nine_nine_seven end_seconds
          end_seconds = ("%.02f" % end_seconds).to_f # round
          end_seconds = translate_time_to_human_readable end_seconds, true
          p end_seconds
          if type == 'Profanity'
            output['mutes'] << [start_seconds, end_seconds]
          else
            output['blank_outs'] << [start_seconds, end_seconds]
          end
        end
      end
end

.single_edit_list_matches_dvd(dvd_id) ⇒ Object



320
321
322
323
324
325
# File 'lib/edl_parser.rb', line 320

def self.single_edit_list_matches_dvd dvd_id
  return nil unless dvd_id
  find_single_edit_list_matching {|parsed|
    parsed["disk_unique_id"] == dvd_id
  }
end

.translate_string_to_seconds(s) ⇒ Object

its reverse: translate_time_to_human_readable



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/edl_parser.rb', line 241

def self.translate_string_to_seconds s
  # might actually already be a float, or int, depending on the yaml
  # int for 8 => 9 and also for 1:09 => 1:10
  if s.is_a? Numeric
    return s.to_f
  end
  
  # s is like 1:01:02.0
  total = 0.0
  seconds = nil
  begin
    seconds = s.split(":")[-1]
  rescue Exception => e
   p 'failed!', s
   raise e
  end
  total += seconds.to_f
  minutes = s.split(":")[-2] || "0"
  total += 60 * minutes.to_i
  hours = s.split(":")[-3] || "0"
  total += 60* 60 * hours.to_i
  total
end

.translate_time_to_human_readable(seconds, force_hour_stamp = false) ⇒ Object

its reverse: translate_string_to_seconds



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/edl_parser.rb', line 266

def self.translate_time_to_human_readable seconds, force_hour_stamp = false
  # 3600 => "1:00:00"
  out = ''
  hours = seconds.to_i / 3600
  if hours > 0 || force_hour_stamp
    out << "%d" % hours
    out << ":"
  end
  seconds = seconds - hours*3600
  minutes = seconds.to_i / 60
  out << "%02d" % minutes
  seconds = seconds - minutes * 60
  out << ":"
  
  # avoid an ugly .0 at the end
  if seconds == seconds.to_i
    out << "%02d" % seconds
  else
    out << "%05.2f" % seconds # man that printf syntax is tricky...
  end
end