Class: EdlParser

Inherits:
Object
  • 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



301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/edl_parser.rb', line 301

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...
        puts '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 = [], subtract_this_from_ends = 0) ⇒ Object

called later, from external files 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], …


243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/edl_parser.rb', line 243

def self.convert_incoming_to_split_sectors incoming, add_this_to_all_ends = 0, subtract_this_from_beginnings = 0, splits = [], subtract_this_from_ends = 0
  raise if subtract_this_from_beginnings < 0
  raise if add_this_to_all_ends < 0
  raise if subtract_this_from_ends < 0
  add_this_to_all_ends -= subtract_this_from_ends # now we allow negative :)
 # raise if splits.size > 0 # just ignore them for now
  mutes = incoming["mutes"] || {}
  blanks = incoming["blank_outs"] || {}
  mutes = mutes.map{|k, v| [k,v,:mute]}
  blanks = blanks.map{|k, v| [k,v,:blank]}
  combined = (mutes+blanks).map{|s,e,type|  [translate_string_to_seconds(s),  translate_string_to_seconds(e), type]}.sort
  
  # detect any weirdness...
  previous = nil
  combined.map!{ |current|
    s,e,type = current
    if e < s || !s || !e || !type
  p caller
     raise SyntaxError.new("detected an end before a start or other weirdness: #{s} > #{e}")
    end
    if previous
      ps, previous_end, pt = previous
      if (s < previous_end)
        raise SyntaxError.new("detected an overlap current #{s} < #{previous_end} of current: #{current.join(' ')} previous: #{previous.join(' ')}")
      end
    end
    previous = current
    # do the math later to allow for ones that barely hit into each other 1.0 2.0, 2.0 3.0
    [s-subtract_this_from_beginnings, e+add_this_to_all_ends,type]
  }
  combined
end

.convert_to_dvd_nav_times(combined, start_type, start_mpeg_time, dvd_nav_packet_offsets, time_multiplier) ⇒ Object



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/edl_parser.rb', line 344

def self.convert_to_dvd_nav_times combined, start_type, start_mpeg_time, dvd_nav_packet_offsets, time_multiplier
  start_dvdnav_time = dvd_nav_packet_offsets[1] - dvd_nav_packet_offsets[0]
  raise unless start_type == 'dvd_start_offset' # for now :P
  out = []
  add_this_to_all_of_them = start_dvdnav_time - start_mpeg_time
  #[[70.0, 73.0, :blank], [378.0, 379.1, :mute]]
  for start, endy, type in combined
   if time_multiplier == 30
     # ok
   elsif time_multiplier == 29.97
     start = ConvertThirtyFps.from_twenty_nine_nine_seven start
     endy  = ConvertThirtyFps.from_twenty_nine_nine_seven endy
  else
    raise time_multiplier
  end
  start += start_dvdnav_time
  endy += start_dvdnav_time
  out << [start, endy, type]
 end
 out
end

.find_single_edit_list_matching(use_all_not_just_dvd_dir = false, return_first_if_there_are_several = false) ⇒ Object

returns single matching filename requires a block



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/edl_parser.rb', line 318

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

.on_any_file_changed_single_cached_thread(&this_block) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/edl_parser.rb', line 24

def self.on_any_file_changed_single_cached_thread &this_block
  raise unless this_block
  get_files_hash = proc {
    glob = EDL_DIR + '/../**/*'
    Dir[glob].map{|f|
      [f, File.mtime(f)]
    }.sort
  }
  old_value = get_files_hash.call
  @@checking_thread ||= Thread.new {
    loop {
      current_value = get_files_hash.call
      if current_value != old_value
        print 'detected some file was changed! Re-parsing to update...'
        old_value = current_value
        this_block.call
        puts 'done.'
      end
      sleep 2 # 0.02 for size 70, so...hopefully this is ok...
    }
  }
end

.parse_file(filename, expand = true) ⇒ Object

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



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/edl_parser.rb', line 78

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/dependencies' # for download methods...
  
  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



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/edl_parser.rb', line 103

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, return_first_if_there_are_several = false) ⇒ Object



337
338
339
340
341
342
# File 'lib/edl_parser.rb', line 337

def self.single_edit_list_matches_dvd dvd_id, return_first_if_there_are_several = false
  return nil unless dvd_id
  find_single_edit_list_matching(false, return_first_if_there_are_several)  {|parsed|
    parsed["disk_unique_id"] == dvd_id
  }
end

.translate_string_to_seconds(s) ⇒ Object

this one is 1:01:02.0 => 36692.0 its reverse is this: translate_time_to_human_readable



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/edl_parser.rb', line 49

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 # easy out.
  end
  
  s = s.strip
  # s is like 1:01:02.0
  total = 0.0
  seconds = nil
  seconds = s.split(":")[-1]
  raise 'does not look like a timestamp? ' + seconds.inspect unless seconds =~ /^\d+(|[,.]\d+)$/
  seconds.gsub!(',', '.')
  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



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/edl_parser.rb', line 278

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