sensible-cinema 0.20.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/TODO +24 -6
- data/VERSION +1 -1
- data/bin/sensible-cinema +36 -25
- data/lib/edl_parser.rb +65 -45
- data/lib/mencoder_wrapper.rb +2 -2
- data/lib/mplayer_edl.rb +3 -3
- data/lib/overlayer.rb +4 -20
- data/sensible-cinema.gemspec +2 -2
- data/spec/edl_parser.spec.rb +49 -4
- data/spec/mplayer_edl.spec.rb +17 -14
- data/spec/notes +9 -0
- data/spec/sensible_cinema_gui.spec.rb +435 -409
- data/zamples/edit_decision_lists/dvds/Harry Potter 2.txt +2 -1
- data/zamples/edit_decision_lists/dvds/happiest baby on the block.txt +2 -1
- metadata +3 -3
data/TODO
CHANGED
|
@@ -2,18 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
== up next release ==
|
|
4
4
|
|
|
5
|
-
edl straight DVD replay:
|
|
5
|
+
edl straight DVD replay:
|
|
6
6
|
work cars
|
|
7
7
|
clear runnings
|
|
8
|
+
finalize
|
|
8
9
|
have ben and chris test it out
|
|
9
10
|
|
|
10
11
|
== slightly lower than that, somewhat ordered ==
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
test HP if I put the whole thing together (2 hour mark)
|
|
14
|
+
try it again with grabbing from DVD too
|
|
15
|
+
add "revision"
|
|
16
|
+
note: you need to offset your start times
|
|
17
|
+
change it to be aggressive sometimes yes, other times no
|
|
18
|
+
note: can make several different versions, with different filenames, and should rewatch the film after finalizing it (edited), like "grab to hard drive" and have a friend watch it, if desired.
|
|
19
|
+
make the other button work again (watch unedited while grabbing)
|
|
20
|
+
the "edited.avi" *must* be playable in WMP
|
|
15
21
|
don't exit program if they don't select a disk :)
|
|
16
|
-
if they type in a "new" start time, use that as the default end time input
|
|
22
|
+
if they type in a "new" start time, use that as the default end time input too
|
|
17
23
|
linearize edl's
|
|
18
24
|
don't use them linear, just linearize
|
|
19
25
|
mpeg is lossy (at least my current one pass conversion still is...) and smplayer can't play it right unedited
|
|
@@ -49,6 +55,10 @@
|
|
|
49
55
|
|
|
50
56
|
== DVD backlog (unordered, some very low prio, basically all never do) ==
|
|
51
57
|
|
|
58
|
+
@ffmpeg: do you get slower the farther into large files you are?
|
|
59
|
+
FHE friendly: always harddup, "watch as grabbed" button [plus other ramifications]
|
|
60
|
+
@ffmpeg: gop 12 for ntsc-dvd?
|
|
61
|
+
@ffmpeg: doesn't grab the right time frames?
|
|
52
62
|
@mplayer: why you can't play it when VLC can? huh? (audio sync)
|
|
53
63
|
can watch conference like a music video :)
|
|
54
64
|
can play "this section then that, with this one's audio
|
|
@@ -345,4 +355,12 @@ donate money to several projects I use/like :)
|
|
|
345
355
|
@mencoder: ripping like this results in an (avidemux, VLC) fourcc of 'ugh': mencoder2 dvdnav://1 -oac copy -ovc copy -o D:\raw_rip_mpeg_example.avi -endpos 20 -dvd-device E:\
|
|
346
356
|
|
|
347
357
|
@jruby: system("mencoder") from a button doesn't get interrupted by an exception [!]
|
|
348
|
-
@vlc: replay mp4's are too dark.
|
|
358
|
+
@vlc: replay mp4's are too dark.
|
|
359
|
+
|
|
360
|
+
@rspec: 1) EdlParser should raise for end before beginning
|
|
361
|
+
Failure/Error: proc{ go({"mutes"=>{105=>104.9}})}.should raise_error(/SyntaxError/)
|
|
362
|
+
expected Exception with message matching /SyntaxError/, got #<SyntaxError: warning--detected an end before a start 104.9 < 105.0>
|
|
363
|
+
# edl_parser.spec.rb:115
|
|
364
|
+
# :1
|
|
365
|
+
|
|
366
|
+
message confusing :)
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.20.
|
|
1
|
+
0.20.1
|
data/bin/sensible-cinema
CHANGED
|
@@ -107,9 +107,9 @@ module SensibleSwing
|
|
|
107
107
|
do_copy_dvd_to_hard_drive false
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
@mplayer_edl = new_jbutton( "Watch DVD on computer edited realtime
|
|
110
|
+
@mplayer_edl = new_jbutton( "Watch DVD on computer edited realtime", false )
|
|
111
111
|
@mplayer_edl.on_clicked {
|
|
112
|
-
do_mplayer_edl
|
|
112
|
+
do_mplayer_edl
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
@watch_unedited = new_jbutton("Watch a DVD unedited (while grabbing to hard drive)", true)
|
|
@@ -149,7 +149,7 @@ module SensibleSwing
|
|
|
149
149
|
old_prefs = File.read(smplayer_prefs_file)
|
|
150
150
|
new_prefs = old_prefs.gsub(/mplayer_additional_options=.*/, "mplayer_additional_options=-edl #{EdlTempFile}")
|
|
151
151
|
File.write(smplayer_prefs_file, new_prefs)
|
|
152
|
-
thread = do_mplayer_edl( "smplayer #{nice_file}"
|
|
152
|
+
thread = do_mplayer_edl( "smplayer #{nice_file}")
|
|
153
153
|
Thread.new { # XX do we need this?
|
|
154
154
|
begin
|
|
155
155
|
thread.join
|
|
@@ -189,7 +189,7 @@ module SensibleSwing
|
|
|
189
189
|
# "dvd_title_track" => "1", # most DVD's use title 1. Yours might not. If it plays anything except the main title, see http://goo.gl/QHLIF
|
|
190
190
|
# "not edited out stuff" => "",
|
|
191
191
|
# "closing thoughts" => "still a fairly dark movie",
|
|
192
|
-
|
|
192
|
+
# "mplayer_dvd_splits" => ["59:59", "1:04:59"], # find these by playing your dvd with smplayer, and noting where the timing switches [buggedly] back to zero in error--common on many DVD's. Setting it here lets the 'insta play' feature work right.
|
|
193
193
|
EOL
|
|
194
194
|
filename = EDL_DIR + "\\" + name.gsub(' ', '_') + '.txt'
|
|
195
195
|
filename.downcase!
|
|
@@ -239,21 +239,27 @@ EOL
|
|
|
239
239
|
|
|
240
240
|
EdlTempFile = Dir.tmpdir + '/mplayer.temp.edl'
|
|
241
241
|
|
|
242
|
-
def do_mplayer_edl
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
242
|
+
def do_mplayer_edl play_this_mplayer = nil, add_secs_end = 0, add_secs_beginning = 0.5
|
|
243
|
+
drive, dvd_volume_name, md5sum, edl_path, descriptors = choose_dvd_and_edl_for_it
|
|
244
|
+
descriptors = EdlParser.parse_file edl_path
|
|
245
|
+
splits = descriptors['mplayer_dvd_splits']
|
|
246
|
+
if splits == nil
|
|
247
|
+
show_blocking_message_dialog("warning: delete list does not contain mplayer replay information [mplayer_dvd_splits] so edits past a certain time period won't work (fixable...).")
|
|
248
|
+
splits = []
|
|
249
|
+
end
|
|
250
|
+
splits.map!{|s| EdlParser.translate_string_to_seconds(s) }
|
|
251
|
+
edl_contents = MplayerEdl.convert_to_edl descriptors, add_secs_end, add_secs_beginning, splits # add a sec to mutes to accomodate for mplayer's oddness...
|
|
252
|
+
File.write(EdlTempFile, edl_contents)
|
|
253
|
+
title_track = get_title_track(descriptors)
|
|
254
|
+
# oh the insanity of the console UI...LODO more user friendly player
|
|
255
|
+
@popup ||= NonBlockingDialog.new("Running mplayer. To control it, use space for pause.\n
|
|
256
|
+
Also right and left arrows to seek, F key for full screen, [, ] to control playback speed.
|
|
257
|
+
q or escape to quit.")
|
|
258
|
+
# LODO dry up mplayer dvd opts...
|
|
259
|
+
play_this_mplayer ||= "mplayer dvd://#{title_track}"
|
|
260
|
+
command = "#{play_this_mplayer} -nocache -alang en -sid 1000 -edl #{File.expand_path EdlTempFile} -dvd-device #{drive}"
|
|
261
|
+
p command
|
|
262
|
+
Thread.new { system_blocking command; @popup.dispose }
|
|
257
263
|
end
|
|
258
264
|
|
|
259
265
|
def show_blocking_license_accept_dialog program, license_name, license_url_should_also_be_embedded_by_you_in_message, title = 'Confirm Acceptance of License Agreement', message = nil
|
|
@@ -369,8 +375,8 @@ EOL
|
|
|
369
375
|
start_time = JOptionPane.showInputDialog(message, default)
|
|
370
376
|
end
|
|
371
377
|
|
|
372
|
-
def parse_edl path
|
|
373
|
-
EdlParser.parse_file path
|
|
378
|
+
def parse_edl path
|
|
379
|
+
EdlParser.parse_file path
|
|
374
380
|
end
|
|
375
381
|
|
|
376
382
|
def get_freespace path
|
|
@@ -431,10 +437,13 @@ EOL
|
|
|
431
437
|
end
|
|
432
438
|
end
|
|
433
439
|
|
|
434
|
-
def do_copy_dvd_to_hard_drive should_prompt_for_start_and_end_times, exit_early_if_fulli_exists = false,
|
|
440
|
+
def do_copy_dvd_to_hard_drive should_prompt_for_start_and_end_times, exit_early_if_fulli_exists = false, watch_unedited = false
|
|
435
441
|
drive, dvd_volume_name, md5sum, edit_list_path, descriptors = choose_dvd_and_edl_for_it
|
|
436
442
|
|
|
437
|
-
descriptors = parse_edl(edit_list_path
|
|
443
|
+
descriptors = parse_edl(edit_list_path)
|
|
444
|
+
if watch_unedited
|
|
445
|
+
descriptors['mutes'] = descriptors['blank_outs'] = []
|
|
446
|
+
end
|
|
438
447
|
|
|
439
448
|
# LODO allow for spaces in the save_to filename
|
|
440
449
|
if should_prompt_for_start_and_end_times
|
|
@@ -464,7 +473,8 @@ EOL
|
|
|
464
473
|
|
|
465
474
|
dvd_title_track = get_title_track(descriptors)
|
|
466
475
|
should_run_mplayer = should_prompt_for_start_and_end_times || exit_early_if_fulli_exists
|
|
467
|
-
|
|
476
|
+
require_deletion_entry = true unless watch_unedited
|
|
477
|
+
generate_and_run_bat_file save_to, edit_list_path, descriptors, drive, dvd_title, start_time, end_time, dvd_title_track, should_run_mplayer, require_deletion_entry
|
|
468
478
|
[false, fulli] # false means it's running in a background thread :P
|
|
469
479
|
end
|
|
470
480
|
|
|
@@ -474,7 +484,8 @@ EOL
|
|
|
474
484
|
|
|
475
485
|
# stubbable :)
|
|
476
486
|
def get_mencoder_commands descriptors, drive, save_to, start_time, end_time, dvd_title_track, require_deletion_entry
|
|
477
|
-
|
|
487
|
+
delete_partials = true unless start_time
|
|
488
|
+
MencoderWrapper.get_bat_commands descriptors, drive, save_to, start_time, end_time, dvd_title_track, delete_partials, require_deletion_entry # delete partials...
|
|
478
489
|
end
|
|
479
490
|
|
|
480
491
|
def generate_and_run_bat_file save_to, edit_list_path, descriptors, drive, dvd_title, start_time, end_time, dvd_title_track, run_mplayer, require_deletion_entry
|
data/lib/edl_parser.rb
CHANGED
|
@@ -24,8 +24,8 @@ class EdlParser
|
|
|
24
24
|
parse_string File.read(filename), filename, [], ignore_settings
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
# better eye-ball these before letting people run them, eh?
|
|
28
|
-
# but I couldn't think of any other way
|
|
27
|
+
# better eye-ball these before letting people run them, eh? XXXX
|
|
28
|
+
# but I couldn't think of any other way to parse the files tho
|
|
29
29
|
def self.parse_string string, filename, ok_categories_array = [], ignore_settings = false
|
|
30
30
|
string = '{' + string + "\n}"
|
|
31
31
|
if filename
|
|
@@ -47,6 +47,7 @@ class EdlParser
|
|
|
47
47
|
raw
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
# converts "blanks" => ["00:00:00", "00", "reason", "01", "01", "02", "02"] into sane arrays, also filters based on category, though disabled
|
|
50
51
|
def self.convert_to_timestamp_arrays array, ok_categories_array
|
|
51
52
|
out = []
|
|
52
53
|
while(single_element = extract_entry!(array))
|
|
@@ -76,60 +77,79 @@ class EdlParser
|
|
|
76
77
|
out
|
|
77
78
|
end
|
|
78
79
|
|
|
80
|
+
def self.get_secs timestamp_string_begin, timestamp_string_end, add_begin, add_end, splits
|
|
81
|
+
answers = []
|
|
82
|
+
for type, offset, multiplier in [[timestamp_string_begin, add_begin, -1], [timestamp_string_end, add_end, 1]]
|
|
83
|
+
original_secs = translate_string_to_seconds(type) + offset
|
|
84
|
+
# now if splits is 900 and we'are at 909, then we're just 9
|
|
85
|
+
closest_split_idx = splits.reverse.index{|t| t < original_secs}
|
|
86
|
+
if closest_split_idx
|
|
87
|
+
closest_split = splits.reverse[closest_split_idx]
|
|
88
|
+
# add some extra seconds onto these if they're "past" a split, too
|
|
89
|
+
original_secs = original_secs - closest_split + multiplier * (splits.length - closest_split_idx)
|
|
90
|
+
original_secs = [0, original_secs].max # no negatives allowed :)
|
|
91
|
+
end
|
|
92
|
+
answers << original_secs
|
|
93
|
+
end
|
|
94
|
+
answers
|
|
95
|
+
end
|
|
96
|
+
|
|
79
97
|
# divides up mutes and blanks so that they don't overlap, preferring blanks over mutes
|
|
80
98
|
# returns it like [[start,end,type], [s,e,t]...] type like :blank and :mute
|
|
81
|
-
def self.convert_incoming_to_split_sectors incoming, add_this_to_mutes_end = 0, add_this_to_mutes_beginning = 0
|
|
99
|
+
def self.convert_incoming_to_split_sectors incoming, add_this_to_mutes_end = 0, add_this_to_mutes_beginning = 0, splits = []
|
|
100
|
+
if splits != []
|
|
101
|
+
# allow it to do all the double checks we later skip, just in case :)
|
|
102
|
+
self.convert_incoming_to_split_sectors incoming
|
|
103
|
+
end
|
|
82
104
|
mutes = incoming["mutes"] || {}
|
|
83
105
|
blanks = incoming["blank_outs"] || {}
|
|
84
|
-
mutes = mutes.map{|k, v|
|
|
85
|
-
blanks = blanks.map{|k, v|
|
|
86
|
-
|
|
87
|
-
combined = (mutes+blanks).sort_by{|entry| entry[0,1]}
|
|
106
|
+
mutes = mutes.map{|k, v| get_secs(k, v, -add_this_to_mutes_beginning, add_this_to_mutes_end, splits) + [:mute]}
|
|
107
|
+
blanks = blanks.map{|k, v| get_secs(k, v, -add_this_to_mutes_beginning, add_this_to_mutes_end, splits) + [:blank]}
|
|
108
|
+
p mutes, blanks
|
|
88
109
|
combined = (mutes+blanks).sort
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
previous[1] = start # make it end when we start...
|
|
106
|
-
end
|
|
107
|
-
elsif type == :mute
|
|
108
|
-
if previous_end > start
|
|
109
|
-
|
|
110
|
-
if previous_end >= endy
|
|
111
|
-
combined[index] = [nil] # null it out...it's a mute subsumed by a blank apparently...
|
|
112
|
-
if previous_type == :mute
|
|
113
|
-
raise 'overlapping mute?'
|
|
114
|
-
end
|
|
115
|
-
next
|
|
116
|
-
else
|
|
117
|
-
# start mine when the last one ended...
|
|
118
|
-
combined[index] = [previous_end, endy, type]
|
|
119
|
-
end
|
|
120
|
-
|
|
110
|
+
|
|
111
|
+
previous = nil
|
|
112
|
+
combined.each_with_index{|current, idx|
|
|
113
|
+
s,e,t = current
|
|
114
|
+
if e < s
|
|
115
|
+
raise SyntaxError.new("detected an end before a start: #{e} < #{s}") if e < s unless splits.length > 0
|
|
116
|
+
end
|
|
117
|
+
if previous
|
|
118
|
+
ps, pe, pt = previous
|
|
119
|
+
if (s < pe)
|
|
120
|
+
raise SyntaxError.new("detected an overlap #{[s,e,t].join(' ')} #{previous.join(' ')}") unless splits.length > 0
|
|
121
|
+
# our start might be within the previous' in which case its their start, with (greater of our, their endig)
|
|
122
|
+
preferred_end = [e,pe].max
|
|
123
|
+
preferred_type = [t,pt].detect{|t| t == :blank} || :mute # prefer blank to mute
|
|
124
|
+
combined[idx-1] = [ps, preferred_end, preferred_type]
|
|
125
|
+
combined[idx] = nil # allow it to be culled later
|
|
121
126
|
end
|
|
122
|
-
|
|
123
|
-
raise 'unexpected'
|
|
127
|
+
|
|
124
128
|
end
|
|
125
|
-
previous =
|
|
129
|
+
previous = current
|
|
126
130
|
}
|
|
131
|
+
combined.compact
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def self.translate_string_to_seconds s
|
|
135
|
+
# might actually already be a float, or int, depending on the yaml
|
|
136
|
+
# int for 8 => 9 and also for 1:09 => 1:10
|
|
137
|
+
if s.is_a? Numeric
|
|
138
|
+
return s.to_f
|
|
139
|
+
end
|
|
127
140
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
# s is like 1:01:02.0
|
|
142
|
+
total = 0.0
|
|
143
|
+
seconds = s.split(":")[-1]
|
|
144
|
+
total += seconds.to_f
|
|
145
|
+
minutes = s.split(":")[-2] || "0"
|
|
146
|
+
total += 60 * minutes.to_i
|
|
147
|
+
hours = s.split(":")[-3] || "0"
|
|
148
|
+
total += 60* 60 * hours.to_i
|
|
149
|
+
total
|
|
131
150
|
end
|
|
132
151
|
|
|
152
|
+
|
|
133
153
|
end
|
|
134
154
|
|
|
135
155
|
# <= 1.8.7 Symbol compat
|
data/lib/mencoder_wrapper.rb
CHANGED
|
@@ -44,8 +44,8 @@ class MencoderWrapper
|
|
|
44
44
|
assert dvd_title_track
|
|
45
45
|
if start_here || end_here
|
|
46
46
|
raise 'need both' unless end_here && start_here
|
|
47
|
-
start_here =
|
|
48
|
-
end_here =
|
|
47
|
+
start_here = EdlParser.translate_string_to_seconds(start_here)
|
|
48
|
+
end_here = EdlParser.translate_string_to_seconds(end_here)
|
|
49
49
|
combined.select!{|start, endy, type| start > start_here && endy < end_here }
|
|
50
50
|
raise TimingError.new("unable to find deletion entry between #{start_here} and #{end_here}") if require_deletion_entry && combined.length == 0
|
|
51
51
|
# it's relative now, since we rip from not the beginning
|
data/lib/mplayer_edl.rb
CHANGED
|
@@ -20,9 +20,9 @@ require_relative 'overlayer'
|
|
|
20
20
|
require_relative 'edl_parser'
|
|
21
21
|
|
|
22
22
|
class MplayerEdl
|
|
23
|
-
def self.convert_to_edl specs, add_this_many_to_end = 0, add_this_many_to_beginning = 0
|
|
24
|
-
# simple re-map
|
|
25
|
-
combined = EdlParser.convert_incoming_to_split_sectors specs, add_this_many_to_end, add_this_many_to_beginning
|
|
23
|
+
def self.convert_to_edl specs, add_this_many_to_end = 0, add_this_many_to_beginning = 0, splits = []
|
|
24
|
+
# simple re-map to EDL style output
|
|
25
|
+
combined = EdlParser.convert_incoming_to_split_sectors specs, add_this_many_to_end, add_this_many_to_beginning, splits
|
|
26
26
|
out = ''
|
|
27
27
|
map = {:mute => 1, :blank => 0}
|
|
28
28
|
for start, endy, type in combined
|
data/lib/overlayer.rb
CHANGED
|
@@ -105,6 +105,7 @@ class OverLayer
|
|
|
105
105
|
@start_time = Time.now_f # assume they want to start immediately...
|
|
106
106
|
end
|
|
107
107
|
|
|
108
|
+
# note this is actually deprecated and won't work anymore <sigh> and needs to be updated.
|
|
108
109
|
def self.translate_yaml raw_yaml
|
|
109
110
|
begin
|
|
110
111
|
all = YAML.load(raw_yaml) || {}
|
|
@@ -120,8 +121,8 @@ class OverLayer
|
|
|
120
121
|
new = {}
|
|
121
122
|
maps.each{|start,endy|
|
|
122
123
|
# both are like 1:02.0
|
|
123
|
-
start2 = translate_string_to_seconds(start) if start
|
|
124
|
-
endy2 = translate_string_to_seconds(endy) if endy
|
|
124
|
+
start2 = EdlParser.translate_string_to_seconds(start) if start
|
|
125
|
+
endy2 = EdlParser.translate_string_to_seconds(endy) if endy
|
|
125
126
|
if start2 == 0 || endy2 == 0 || start == nil || endy == nil
|
|
126
127
|
p 'warning--possible error in the Edit Decision List file some line not parsed! (NB if you want one to start at time 0 please use 0.0001)', start, endy unless $AM_IN_UNIT_TEST
|
|
127
128
|
# drop this line into the bitbucket...
|
|
@@ -164,27 +165,10 @@ class OverLayer
|
|
|
164
165
|
@just_unblanked = false
|
|
165
166
|
p 'ignoring timestamp update ' + to_this_exact_string_might_be_nil.to_s if $VERBOSE
|
|
166
167
|
else
|
|
167
|
-
set_seconds
|
|
168
|
+
set_seconds EdlParser.translate_string_to_seconds(to_this_exact_string_might_be_nil) + delta if to_this_exact_string_might_be_nil
|
|
168
169
|
end
|
|
169
170
|
end
|
|
170
171
|
|
|
171
|
-
def self.translate_string_to_seconds s
|
|
172
|
-
# might actually already be a float, or int, depending on the yaml
|
|
173
|
-
# int for 8 => 9 and also for 1:09 => 1:10
|
|
174
|
-
if s.is_a? Numeric
|
|
175
|
-
return s.to_f
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
# s is like 1:01:02.0
|
|
179
|
-
total = 0.0
|
|
180
|
-
seconds = s.split(":")[-1]
|
|
181
|
-
total += seconds.to_f
|
|
182
|
-
minutes = s.split(":")[-2] || "0"
|
|
183
|
-
total += 60 * minutes.to_i
|
|
184
|
-
hours = s.split(":")[-3] || "0"
|
|
185
|
-
total += 60* 60 * hours.to_i
|
|
186
|
-
total
|
|
187
|
-
end
|
|
188
172
|
|
|
189
173
|
# returns seconds it's at currently...
|
|
190
174
|
def cur_time
|
data/sensible-cinema.gemspec
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{sensible-cinema}
|
|
8
|
-
s.version = "0.20.
|
|
8
|
+
s.version = "0.20.1"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Roger Pack"]
|
|
12
|
-
s.date = %q{2011-01-
|
|
12
|
+
s.date = %q{2011-01-04}
|
|
13
13
|
s.email = %q{rogerdpack@gmail.com}
|
|
14
14
|
s.executables = ["sensible-cinema", "sensible-cinema-cli"]
|
|
15
15
|
s.extensions = ["ext/mkrf_conf.rb"]
|
data/spec/edl_parser.spec.rb
CHANGED
|
@@ -89,6 +89,11 @@ describe EdlParser do
|
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
+
it "should parse mplayer_dvd_splits as floats" do
|
|
93
|
+
E.parse_string('"mplayer_dvd_splits" => []', 'fakename')['mplayer_dvd_splits'].should == []
|
|
94
|
+
E.parse_string('"mplayer_dvd_splits" => ["123.5","124.5"]', 'fakename')['mplayer_dvd_splits'].should == ["123.5","124.5"]
|
|
95
|
+
end
|
|
96
|
+
|
|
92
97
|
it "should reject misformatted files" do
|
|
93
98
|
proc {E.parse_string 'mutes=>["0:33", "0:34"]', 'filename'}.should raise_error(SyntaxError)
|
|
94
99
|
proc {E.parse_string '"mutes"=>["0:33", "0:34"]', 'filename'}.should_not raise_error
|
|
@@ -99,12 +104,52 @@ describe EdlParser do
|
|
|
99
104
|
end
|
|
100
105
|
|
|
101
106
|
it "should sort exactly overlapping segments" do
|
|
102
|
-
|
|
107
|
+
proc { go({"mutes"=>{105=>145}, "blank_outs"=>{105=>145}})}.should raise_error(SyntaxError)
|
|
108
|
+
proc { go({"mutes"=>{105=>145}, "blank_outs"=>{110=>130}})}.should raise_error(SyntaxError)
|
|
109
|
+
proc { go({"mutes"=>{105=>145}, "blank_outs"=>{110=>150}})}.should raise_error(SyntaxError)
|
|
103
110
|
end
|
|
104
111
|
|
|
105
112
|
it "should add to both ends" do
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
go({"mutes"=>{105=>145}}, 1).should == [[105.0, 146.0, :mute]]
|
|
114
|
+
go({"mutes"=>{105=>145}}, 1,1).should == [[104.0, 146.0, :mute]]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def go *args
|
|
118
|
+
EdlParser.convert_incoming_to_split_sectors *args
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "should raise for end before beginning" do
|
|
122
|
+
proc{ go({"mutes"=>{105=>104.9}})}.should raise_error(SyntaxError)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "should allow for splits in its parseage" do
|
|
126
|
+
go({ "mutes"=>{5=>6,105=>106}, "blank_outs" => {110 => 111} }, 0, 0, [103]).should ==
|
|
127
|
+
[[1.0, 4.0, :mute], [5.0, 6.0, :mute], [6.0, 9.0, :blank]]
|
|
108
128
|
end
|
|
109
129
|
|
|
110
|
-
|
|
130
|
+
it "should raise on poor overlap" do
|
|
131
|
+
proc{go({ "mutes"=>{5=>10, 6=>7}}, 0, 0, [1000])}.should raise_error(/overlap/i)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# I put down it at 10:00 it's at 10:00.5
|
|
135
|
+
# so...postludingers should be...too early now?
|
|
136
|
+
# change when complaints come in :P
|
|
137
|
+
it "should take the greater of the end and beginning on combined splits and greater of the blank versus mute" do
|
|
138
|
+
# so if I have a very long mute with a mute in the middle, it should turn into a very long mute
|
|
139
|
+
go({ "mutes"=>{5=>10, 103=>107}}, 0, 0, [100]).should == [[2.0, 10.0, :mute]]
|
|
140
|
+
go({ "mutes"=>{5=>10, 103=>110}}, 0, 0, [100]).should == [[2.0, 11.0, :mute]]
|
|
141
|
+
go({ "mutes"=>{5=>15, 103=>110}}, 0, 0, [100]).should == [[2.0, 15.0, :mute]]
|
|
142
|
+
go({ "mutes"=>{5=>10, 103=>111}}, 0, 0, [100]).should == [[2.0, 12.0, :mute]]
|
|
143
|
+
# now throw in blanks to the mix...
|
|
144
|
+
go({ "mutes"=>{5=>10}, "blank_outs" => {103=>110}}, 0, 0, [100]).should == [[2.0, 11.0, :blank]]
|
|
145
|
+
go({ "blank_outs"=>{5=>10}, "mutes" => {103=>110}}, 0, 0, [100]).should == [[2.0, 11.0, :blank]]
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it "should accomodate well for multiples, and zero" do
|
|
149
|
+
go({ "mutes"=>{5=>10, 75 => 76, 101 => 102}}, 0, 0, [50, 100]).should ==
|
|
150
|
+
[[0.0, 4.0, :mute], [5.0, 10.0, :mute], [24.0, 27.0, :mute]]
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it "should handle edge cases, like where an entry overlaps the divider, or the added stuff causes it to"
|
|
154
|
+
|
|
155
|
+
end
|