sensible-cinema 0.26.0 → 0.26.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.gitmodules +3 -0
  2. data/README +9 -6
  3. data/TODO +91 -41
  4. data/VERSION +1 -1
  5. data/bin/sensible-cinema +13 -1506
  6. data/bin/sensible-cinema-cli +156 -151
  7. data/change_log_with_feature_list.txt +17 -2
  8. data/developer_how_to_contribute_to_the_project.txt +3 -2
  9. data/documentation/upconversion.txt +4 -0
  10. data/history_and_related_works_list.txt +1 -0
  11. data/{play_with_inserted_scene.bat → legal/play_with_inserted_scene.bat} +0 -0
  12. data/{play_with_overlay.bat → legal/play_with_overlay.bat} +0 -0
  13. data/legal2 +2 -0
  14. data/lib/count_down_timer_jruby_swing.rb +3 -4
  15. data/lib/edl_parser.rb +345 -339
  16. data/lib/eight_three.rb +6 -1
  17. data/lib/gui/sensible-cinema-base.rb +671 -0
  18. data/lib/gui/sensible-cinema-create.rb +304 -0
  19. data/lib/{sensible-cinema-dependencies.rb → gui/sensible-cinema-dependencies.rb} +0 -0
  20. data/lib/gui/sensible-cinema-normal.rb +349 -0
  21. data/lib/gui/sensible-cinema-side-by-side.rb +27 -0
  22. data/lib/gui/sensible-cinema-upconvert.rb +254 -0
  23. data/lib/screen_tracker.rb +1 -0
  24. data/spec/edl_parser.spec.rb +6 -0
  25. data/spec/notes +107 -16
  26. data/spec/sensible_cinema_gui.spec.rb +63 -58
  27. data/todo.inventionzy.txt +12 -0
  28. data/todo.propaganda +1 -2
  29. data/todo.upconvert +3 -1
  30. data/upconvert_netflix/record_screen/record.bat +2 -0
  31. data/upconvert_netflix/record_screen/recording/1.png +0 -0
  32. data/upconvert_netflix/record_screen/recording/10.png +0 -0
  33. data/upconvert_netflix/record_screen/recording/2.png +0 -0
  34. data/upconvert_netflix/record_screen/recording/3.png +0 -0
  35. data/upconvert_netflix/record_screen/recording/4.png +0 -0
  36. data/upconvert_netflix/record_screen/recording/5.png +0 -0
  37. data/upconvert_netflix/record_screen/recording/6.png +0 -0
  38. data/upconvert_netflix/record_screen/recording/7.png +0 -0
  39. data/upconvert_netflix/record_screen/recording/8.png +0 -0
  40. data/upconvert_netflix/record_screen/recording/9.png +0 -0
  41. data/upconvert_netflix/record_screen/recording/d.png +0 -0
  42. data/www/content_editor.html +2 -2
  43. data/zamples/edit_decision_lists/dvds/edls_being_edited/cars_disney.txt +5 -7
  44. data/zamples/edit_decision_lists/dvds/innerspace.txt +77 -0
  45. data/zamples/edit_decision_lists/netflix_instant/avatar-last-air-bender-movie.txt +12 -0
  46. data/zamples/edit_decision_lists/netflix_instant/avatar-last-airbender-series.txt +1 -0
  47. data/zamples/players/netflix/netflix_firefox_non_maximized.txt +1 -1
  48. metadata +28 -11
  49. data/lib/file_chooser.rb +0 -46
  50. data/lib/swing_helpers.rb +0 -142
  51. data/www/monkey.png +0 -0
data/lib/eight_three.rb CHANGED
@@ -17,7 +17,12 @@ DWORD WINAPI GetShortPathName(
17
17
  def self.convert_path_to_8_3 path
18
18
  out = FFI::MemoryPointer.new 256 # bytes
19
19
  path_to_8_3(path, out, out.length)
20
- out.get_string
20
+ out = out.get_string
21
+ if out.size == 0
22
+ raise 'unable to convert--probably file does not exist yet ' + path
23
+ else
24
+ out
25
+ end
21
26
  end
22
27
 
23
28
  end
@@ -0,0 +1,671 @@
1
+ #!/usr/bin/ruby # so my editor will like the file...
2
+ =begin
3
+ Copyright 2010, Roger Pack
4
+ This file is part of Sensible Cinema.
5
+
6
+ Sensible Cinema is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ Sensible Cinema is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with Sensible Cinema. If not, see <http://www.gnu.org/licenses/>.
18
+ =end
19
+
20
+
21
+ alias system_original system
22
+ require 'fileutils'
23
+
24
+ class String
25
+ def snake_case
26
+ self.gsub(/::/, '/').
27
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
28
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
29
+ tr("-", "_").
30
+ downcase
31
+ end
32
+ end
33
+
34
+ require_relative '../jruby-swing-helpers/swing_helpers'
35
+
36
+ # attempt to load on demand...i.e. faster...
37
+ for kls in [:MencoderWrapper, :MplayerEdl, :PlayAudio, :SubtitleProfanityFinder, :ConvertThirtyFps, :RubyClip, :DriveInfo]
38
+ autoload kls, "./lib/#{kls.to_s.snake_case}"
39
+ end
40
+
41
+ # a few I'll always need eventually...
42
+ require_relative '../storage'
43
+ require_relative '../edl_parser'
44
+ require 'tmpdir'
45
+ require 'whichr'
46
+ require 'os'
47
+ if OS.doze?
48
+ autoload :WMI, 'ruby-wmi'
49
+ autoload :EightThree, './lib/eight_three'
50
+ end
51
+
52
+
53
+ if OS.windows?
54
+ vendor_cache = File.expand_path(File.dirname(__FILE__)) + '/../../vendor/cache'
55
+ for name in ['.', 'mencoder', 'ffmpeg']
56
+ # put them all before the old path
57
+ ENV['PATH'] = (vendor_cache + '/' + name).to_filename + ';' + ENV['PATH']
58
+ end
59
+
60
+ installed_smplayer_folders = Dir['{c,d,e,f,g}:/program files*/MPlayer for Windows*'] # sometimes ends with UI? huh?
61
+
62
+ for folder in installed_smplayer_folders
63
+ ENV['PATH'] = ENV['PATH'] + ";#{folder.gsub('/', "\\")}"
64
+ end
65
+
66
+ else
67
+ ENV['PATH'] = ENV['PATH'] + ':' + '/opt/local/bin' # add macports' bin in, just in case...
68
+ end
69
+
70
+ import 'javax.swing.ImageIcon'
71
+ require_relative './sensible-cinema-dependencies'
72
+
73
+ module SensibleSwing
74
+ include SwingHelpers # various swing classes
75
+ JFrame
76
+ VERSION = File.read(File.dirname(__FILE__) + "/../../VERSION").strip
77
+ puts "v. " + VERSION
78
+
79
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()) # <sigh>
80
+
81
+ class MainWindow < JFrame
82
+ include SwingHelpers # work-around?
83
+
84
+ def initialize be_visible = true
85
+ super "Sensible-Cinema #{VERSION} (GPL)"
86
+ force_accept_license_first
87
+ setDefaultCloseOperation JFrame::EXIT_ON_CLOSE # default is exit on close
88
+ @panel = JPanel.new
89
+ @buttons = []
90
+ @panel.set_layout nil
91
+ add @panel # why can't I just slap these down? panel? huh?
92
+ @starting_button_y = 40
93
+ @button_width = 400
94
+
95
+ add_text_line "Welcome to Sensible Cinema!"
96
+ @starting_button_y += 10 # kinder ugly...
97
+ add_text_line " Rest mouse over buttons for \"help\" type descriptions (tooltips)."
98
+ add_text_line ""
99
+
100
+ setIconImage(ImageIcon.new(__DIR__ + "/../vendor/profs.png").getImage())
101
+ check_for_various_dependencies
102
+ set_visible be_visible
103
+ end
104
+
105
+ def we_are_in_create_mode
106
+ ARGV.index("--create-mode")
107
+ end
108
+
109
+ def new_jbutton title, tooltip = nil
110
+ button = JButton.new title
111
+ button.tool_tip = tooltip
112
+ button.set_bounds(44, @starting_button_y, @button_width, 23)
113
+ @panel.add button
114
+ @buttons << button
115
+ if block_given? # allow for new_jbutton("xx") do ... end [this is possible through some miraculous means LOL]
116
+ button.on_clicked { yield }
117
+ end
118
+ increment_button_location
119
+ button
120
+ end
121
+
122
+ def add_text_line line
123
+ jlabel = JLabel.new line
124
+ happy = Font.new("Tahoma", Font::PLAIN, 11)
125
+ jlabel.setFont(happy)
126
+ jlabel.set_bounds(44,@starting_button_y ,460,14)
127
+ @panel.add jlabel
128
+ increment_button_location 18
129
+ jlabel
130
+ end
131
+
132
+ def increment_button_location how_much = 30
133
+ @starting_button_y += how_much
134
+ setSize @button_width+80, @starting_button_y + 50
135
+ end
136
+
137
+ def force_accept_license_first
138
+ if !(LocalStorage['main_license_accepted'] == VERSION)
139
+ require_blocking_license_accept_dialog 'Sensible Cinema', 'gplv3', 'http://www.gnu.org/licenses/gpl.html', 'Sensible Cinema license agreement',
140
+ "Sensible Cinema is distributed under the gplv3 (http://www.gnu.org/licenses/gpl.html).\nBY CLICKING \"accept\" YOU SIGNIFY THAT YOU HAVE READ, UNDERSTOOD AND AGREED TO ABIDE BY THE TERMS OF THIS AGREEMENT"
141
+ require_blocking_license_accept_dialog 'Sensible Cinema', 'is_it_legal_to_copy_dvds.txt file', File.expand_path(File.dirname(__FILE__) + "/../documentation/is_it_legal_to_copy_dvds.txt"),
142
+ 'is_it_legal_to_copy_dvds.txt file', 'I acknowledge that I have read, understand, accept and agree to abide by the implications noted in the documentation/is_it_legal_to_copy_dvds.txt file'
143
+ LocalStorage['main_license_accepted'] = VERSION
144
+ end
145
+ end
146
+
147
+ LocalStorage = Storage.new("sensible_cinema_storage")
148
+
149
+ def when_thread_done(thread)
150
+ Thread.new {thread.join; yield }
151
+ end
152
+
153
+
154
+ # a window that when closed doesn't bring the whole app down
155
+ def new_child_window
156
+ child = MainWindow.new
157
+ child.setDefaultCloseOperation(JFrame::DISPOSE_ON_CLOSE)
158
+ child.parent=self # this should have failed in the PPL
159
+ # make both windows visible z-wise
160
+ x, y = self.get_location.x, self.get_location.y
161
+ child.set_location(x + 100, y + 100)
162
+ child
163
+ end
164
+
165
+ def run_smplayer_non_blocking *args
166
+ pp caller
167
+ @background_thread = Thread.new {
168
+ run_smplayer_blocking *args
169
+ }
170
+ end
171
+
172
+ def run_smplayer_blocking play_this, title_track_maybe_nil, passed_in_extra_options, force_use_mplayer, show_subs, start_full_screen
173
+ unless File.exist?(File.expand_path(play_this))
174
+ raise play_this + ' non existing?' # till these go away in mac :)
175
+ end
176
+
177
+ extra_options = ""
178
+ # -framedrop is for slow CPU's
179
+ # same with -autosync to try and help it stay in sync... -mc 0.03 is to A/V correct 1s audio per 2s video
180
+ # -hardframedrop might help but hurts just too much
181
+ extra_options << " -framedrop "
182
+ # ?? extra_mplayer_commands << "-mc 0.016" ??
183
+ extra_options << " -autosync 15 "
184
+
185
+ unless show_subs
186
+ # disable subtitles
187
+ extra_options << " -nosub -noautosub -forcedsubsonly -sid 1000 "
188
+ end
189
+ extra_options << " -alang en "
190
+ extra_options += " -slang en "
191
+
192
+ parent_parent = File.basename(File.dirname(play_this))
193
+ force_use_mplayer ||= OS.mac?
194
+ if parent_parent == 'VIDEO_TS'
195
+ # case d:\yo\VIDEO_TS\title0.vob
196
+ dvd_device_dir = normalize_path(File.dirname(play_this))
197
+ if force_use_mplayer
198
+ extra_options += " -dvd-device \"#{dvd_device_dir}/..\""
199
+ else
200
+ # smplayer
201
+ raise if dvd_device_dir =~ / / && OS.mac? # not accomodated <sniff>
202
+ extra_options += " -dvd-device #{dvd_device_dir}/.."
203
+ end
204
+ play_this = "dvdnav://#{title_track_maybe_nil}"
205
+ elsif File.exist?(play_this + '/VIDEO_TS')
206
+ # case d:\ where d:\VIDEO_TS exists [DVD mounted in drive] or mac's /Volumes/YO
207
+ raise if play_this =~ / / # unexpected
208
+ extra_options += " -nocache -dvd-device #{play_this}"
209
+ play_this = "dvdnav://#{title_track_maybe_nil}"
210
+ else
211
+ # case g:\video\filename.mpg
212
+ # leave it the same...
213
+ end
214
+ if play_this =~ /dvdnav/ && title_track_maybe_nil
215
+ extra_options << " -msglevel identify=4 " # prevent smplayer from using *forever* to look up info on DVD's with -identify ...
216
+ end
217
+
218
+ extra_options += " -mouse-movements #{get_upconvert_secondary_settings} " # just in case smplayer also needs -mouse-movements... :) LODO
219
+ extra_options += " -lavdopts threads=#{OS.cpu_count} " # just in case this helps [supposed to with h.264] # fast *crashes* doze...
220
+ if force_use_mplayer
221
+ show_mplayer_instructions_once
222
+ conf_file = File.expand_path './mplayer_input_conf'
223
+ File.write conf_file, "ENTER {dvdnav} dvdnav select\nMOUSE_BTN0 {dvdnav} dvdnav select\nMOUSE_BTN0_DBL vo_fullscreen\nMOUSE_BTN2 vo_fullscreen\nKP_ENTER dvdnav select\n" # that KP_ENTER doesn't actually work. Nor the MOUSE_BTN0 on windows. Weird.
224
+ extra_options += " -font #{File.expand_path('subfont.ttf')} "
225
+ extra_options += " -volume 100 " # why start low? mplayer why oh why LODO
226
+ if OS.windows?
227
+ # direct3d for windows 7 old nvidia cards' sake [yipes] and also dvdnav sake
228
+ extra_options += " -vo direct3d "
229
+ conf_file = conf_file[2..-1] # strip off drive letter, which it doesn't seem to like no sir
230
+ end
231
+ if start_full_screen
232
+ extra_options += " -fs "
233
+ upconv = get_upconvert_vf_settings
234
+ upconv = "-vf #{upconv}" if upconv.present?
235
+ else
236
+ upconv = ""
237
+ end
238
+ c = "mplayer #{extra_options} #{upconv} -input conf=\"#{conf_file}\" #{passed_in_extra_options} \"#{play_this}\" "
239
+ else
240
+ if OS.windows?
241
+ extra_options += " -vo direct3d " # more light nvidia...should be ok...
242
+ end
243
+ set_smplayer_opts extra_options + " " + passed_in_extra_options, get_upconvert_vf_settings, show_subs
244
+ c = "smplayer_portable \"#{play_this}\" -config-path \"#{File.dirname SMPlayerIniFile}\" "
245
+ c += " -fullscreen " if start_full_screen
246
+ if !we_are_in_create_mode
247
+ #c += " -close-at-end " # we're still too unstable, mate...
248
+ end
249
+ end
250
+ puts c
251
+ system_blocking c
252
+ end
253
+
254
+ SMPlayerIniFile = File.expand_path("~/.smplayer/smplayer.ini")
255
+
256
+ def set_smplayer_opts to_this, video_, show_subs = false
257
+ p 'set smplayer extra opts to this:' + to_this
258
+ old_prefs = File.read(SMPlayerIniFile) rescue ''
259
+ unless old_prefs.length > 0
260
+ # LODO double check the rest here...
261
+ old_prefs = "[advanced]\nmplayer_additional_options=\nmplayer_additional_video_filters=\n[subtitles]\nautoload_sub=false\n[performance]\npriority=3"
262
+ end
263
+ raise to_this if to_this =~ /"/ # unexpected, unfortunately... <smplayer bug>
264
+ assert new_prefs = old_prefs.gsub(/mplayer_additional_options=.*/, "mplayer_additional_options=#{to_this}")
265
+ assert new_prefs.gsub!(/autoload_sub=.*$/, "autoload_sub=#{show_subs.to_s}")
266
+ raise if get_upconvert_vf_settings =~ /"/
267
+ assert new_prefs.gsub!(/mplayer_additional_video_filters=.*$/, "mplayer_additional_video_filters=\"#{get_upconvert_vf_settings}\"")
268
+ new_prefs.gsub!(/priority=.*$/, "priority=3") # normal priority...scary otherwise! lodo tell smplayer...
269
+ # enable dvdnav navigation, just for kicks I guess.
270
+ new_prefs.gsub!(/use_dvdnav=.*$/, "use_dvdnav=true")
271
+
272
+ FileUtils.mkdir_p File.dirname(SMPlayerIniFile) # case it doesn't yet exist
273
+ File.write(SMPlayerIniFile, new_prefs)
274
+ new_prefs.each_line{|l| print l if l =~ /additional_video/} # debug
275
+ end
276
+ def system_blocking command, low_prio = false
277
+ return true if command =~ /^@rem/ # JRUBY-5890 bug
278
+ if low_prio
279
+ out = IO.popen(command) # + " 2>&1"
280
+ low_prio = 64 # from msdn
281
+
282
+ if command =~ /(ffmpeg|mencoder)/
283
+ # XXXX not sure if there's a better way...because some *are* complex and have ampersands...
284
+ # unfortunately have to check for nil because it could exit too early [?]
285
+ exe_name = $1 + '.exe'
286
+ begin
287
+ p = proc{ ole = WMI::Win32_Process.find(:first, :conditions => {'Name' => exe_name}); sleep 1 unless ole; ole }
288
+ piddy = p.call || p.call || p.call # we actually do need this to loop...guess we're too quick
289
+ # but the first time through this still inexplicably fails all 3...odd
290
+ piddys = WMI::Win32_Process.find(:all, :conditions => {'Name' => exe_name})
291
+ for piddy in piddys
292
+ # piddy.SetPriority low_prio # this call can seg fault at times...JRUBY-5422
293
+ pid = piddy.ProcessId # this doesn't seg fault, tho
294
+ system_original("vendor\\setpriority -lowest #{pid}") # uses PID for the command line
295
+ end
296
+ rescue Exception => e
297
+ p 'warning, got exception trying to set priority [jruby prob? ...]', e
298
+ end
299
+ end
300
+ print out.read # let it finish
301
+ out.close
302
+ $?.exitstatus == 0 # 0 means success
303
+ else
304
+ raise command + " failed env #{ENV['PATH']}" unless system_original command
305
+ end
306
+ end
307
+
308
+ def system_non_blocking command
309
+ @background_thread = Thread.new { system_original command }
310
+ end
311
+
312
+ # make them choose which system call to use explicitly
313
+ undef system
314
+
315
+ def play_dvd_smplayer_unedited use_mplayer_instead, show_instructions, show_subs
316
+ drive_or_file, dvd_volume_name, dvd_id, edl_path_maybe_nil, descriptors_maybe_nil = choose_dvd_or_file_and_edl_for_it false
317
+ if descriptors_maybe_nil
318
+ title_track_maybe_nil = get_title_track(descriptors_maybe_nil, false)
319
+ end
320
+ if show_instructions
321
+ # want these even with smplayer sometimes I guess, if in power user mode anyway
322
+ show_mplayer_instructions_once
323
+ end
324
+ run_smplayer_non_blocking drive_or_file, title_track_maybe_nil, "-osd-fractions 2", use_mplayer_instead, show_subs, false
325
+ end
326
+
327
+ if OS.doze? # avoids spaces in filenames :)
328
+ EdlTempFile = EightThree.convert_path_to_8_3(Dir.tmpdir) + '\\mplayer.temp.edl'
329
+ else
330
+ raise if Dir.tmpdir =~ / / # that would be unexpected, and probably cause problems...
331
+ EdlTempFile = Dir.tmpdir + '/mplayer.temp.edl'
332
+ end
333
+
334
+ def show_mplayer_instructions_once
335
+ @_show_mplayer_instructions_once ||= show_non_blocking_message_dialog <<-EOL
336
+ About to run mplayer. To control it, use
337
+ spacebar : pause,
338
+ double clicky/right click : toggle full screen,
339
+ arrow keys (left, right, up down, pg up, pg dn) to seek/scan
340
+ / and * : inc/dec volume.
341
+ 'o' key: turn on on-screen-display timestamps (note: the OSD timestamps [upper left] are 30 fps so will need to be converted to use).
342
+ 'v' key: turn off subtitles.
343
+ '.' key: step one frame.
344
+ # key: change audio language track
345
+ EOL
346
+ end
347
+
348
+
349
+ def choose_dvd_or_file_and_edl_for_it force_choose_edl_file_if_no_easy_match = true
350
+ drive_or_file, dvd_volume_name, dvd_id = choose_dvd_drive_or_file false
351
+
352
+ unless @_edit_list_path # cache file selection...
353
+ edit_list_path = EdlParser.single_edit_list_matches_dvd(dvd_id)
354
+ if !edit_list_path && force_choose_edl_file_if_no_easy_match
355
+ edit_list_path = new_existing_file_selector_and_select_file("Please pick a DVD Edit List File (none or more than one were found that seem to match #{dvd_volume_name})--may need to create one for it", EdlParser::EDL_DIR)
356
+ raise 'cancelled choosing an EDL' unless edit_list_path
357
+ end
358
+ @_edit_list_path = edit_list_path
359
+ end
360
+ p 'reloading'
361
+ if @_edit_list_path
362
+ # reload it every time just in case it has changed on disk
363
+ descriptors = nil
364
+ begin
365
+ descriptors = parse_edl @_edit_list_path
366
+ rescue SyntaxError => e
367
+ show_non_blocking_message_dialog("this file has an error--please fix then hit ok: \n" + @_edit_list_path + "\n " + e)
368
+ raise e
369
+ end
370
+ end
371
+ [drive_or_file, dvd_volume_name, dvd_id, @_edit_list_path, descriptors]
372
+ end
373
+
374
+ MplayerBeginingBuffer = 1.0
375
+ MplayerEndBuffer = 0.0
376
+
377
+ def play_mplayer_edl_non_blocking optional_file_with_edl_path = nil, extra_mplayer_commands_array = [], force_mplayer = false, start_full_screen = true
378
+ if optional_file_with_edl_path
379
+ drive_or_file, edl_path = optional_file_with_edl_path
380
+ dvd_id = NonDvd # fake it out...LODO a bit smelly
381
+ else
382
+ drive_or_file, dvd_volume_name, dvd_id, edl_path, descriptors = choose_dvd_or_file_and_edl_for_it
383
+ end
384
+ start_add_this_to_all_ts = 0
385
+ if edl_path # some don't care...
386
+ descriptors = EdlParser.parse_file edl_path
387
+ title_track = get_title_track(descriptors)
388
+ splits = descriptors['mplayer_dvd_splits']
389
+ end
390
+
391
+ if dvd_id == NonDvd && !(File.basename(File.dirname(drive_or_file)) == 'VIDEO_TS') # VOB's...always start at 0
392
+ # check if starts offset...
393
+ all = `ffmpeg -i "#{drive_or_file}" 2>&1`
394
+ # Duration: 01:35:49.59, start: 600.000000
395
+ all =~ /Duration.*start: ([\d\.]+)/
396
+ start = $1.to_f
397
+ if start > 1 # LODO huh? dvd's themselves start at 0.3 [sintel]?
398
+ show_non_blocking_message_dialog "Warning: file seems to start at an extra offset, adding it to the timestamps... #{start}
399
+ maybe not compatible with XBMC, if that's what you use, and you probably don't" # TODO test it XBMC...
400
+ start_add_this_to_all_ts = start
401
+ end
402
+ splits = []
403
+ else
404
+ if splits == nil
405
+ show_blocking_message_dialog("warning: edit list does not contain mplayer replay information [mplayer_dvd_splits] so edits past a certain time period might not won't work ( http://goo.gl/yMfqX ).")
406
+ splits = []
407
+ end
408
+ end
409
+
410
+ if edl_path
411
+ splits.map!{|s| EdlParser.translate_string_to_seconds(s) }
412
+ edl_contents = MplayerEdl.convert_to_edl descriptors, add_secs_end = MplayerEndBuffer, add_secs_begin = MplayerBeginingBuffer, splits, start_add_this_to_all_ts # add a sec to mutes to accomodate for mplayer's oddness..
413
+ File.write(EdlTempFile, edl_contents)
414
+ extra_mplayer_commands_array << "-edl #{File.expand_path EdlTempFile}"
415
+ end
416
+
417
+ run_smplayer_non_blocking drive_or_file, title_track, extra_mplayer_commands_array.join(' '), force_mplayer, false, start_full_screen
418
+ end
419
+
420
+ def assert_ownership_dialog
421
+ message = "Do you certify you own the DVD this came of and have it in your possession?"
422
+ title = "Verify ownership"
423
+ returned = JOptionPane.show_select_buttons_prompt(message, {})
424
+ assert_confirmed_dialog returned, nil
425
+ end
426
+
427
+ def require_blocking_license_accept_dialog program, license_name, license_url_should_also_be_embedded_by_you_in_message,
428
+ title = 'Confirm Acceptance of License Agreement', message = nil
429
+ puts 'Please confirm license agreement in open window.'
430
+ # cancel button stays the same...
431
+
432
+ message ||= "Sensible Cinema requires a separately installed program (#{program}), not yet installed.
433
+ You can install this program manually to the vendor/cache subdirectory, or Sensible Cinema can download it for you.
434
+ By clicking accept, below, you are confirming that you have read and agree to be bound by the
435
+ terms of its license (the #{license_name}), located at #{license_url_should_also_be_embedded_by_you_in_message}.
436
+ Click 'View License' to view it. If you do not agree to these terms, click 'Cancel'. You also agree that this is a
437
+ separate program, with its own distribution, license, ownership and copyright.
438
+ You agree that you are responsible for the download and use of this program, within sensible cinema or otherwise."
439
+ answer = JOptionPane.show_select_buttons_prompt message, :yes => 'Accept', :no => "View #{license_name}"
440
+ assert_confirmed_dialog answer, license_url_should_also_be_embedded_by_you_in_message
441
+ p 'confirmation of sensible cinema related license saved of: ' + license_name
442
+ throw unless returned == 0
443
+
444
+ end
445
+
446
+ def assert_confirmed_dialog answer, license_url_should_also_be_embedded_by_you_in_message
447
+ # :yes, :no, :cancel
448
+ # 1 is view button was clicked
449
+ # 0 is accept
450
+ # 2 is cancel
451
+ if returned == :no
452
+ if license_url_should_also_be_embedded_by_you_in_message
453
+ system_non_blocking("start #{license_url_should_also_be_embedded_by_you_in_message}")
454
+ puts "Please restart after reading license agreement, to be able to then accept it."
455
+ end
456
+ System.exit 0
457
+ elsif returned == :cancel
458
+ p 'license not accepted...exiting'
459
+ System.exit 1
460
+ elsif returned == :exited
461
+ p 'license exited early...exiting'
462
+ System.exit 1
463
+ elsif returned == :yes
464
+ # ok
465
+ else
466
+ raise 'unknown'
467
+ end
468
+ end
469
+
470
+ def print *args
471
+ Kernel.print *args # avoid bin\sensible-cinema.rb:83:in `system_blocking': cannot convert instance of class org.jruby.RubyString to class java.awt.Graphics (TypeError)
472
+ end
473
+
474
+ def download_7zip
475
+ Dir.mkdir('./vendor/cache') unless File.directory? 'vendor/cache' # development may not have it created yet... [?]
476
+ unless File.exist? 'vendor/cache/7za.exe'
477
+ Dir.chdir('vendor/cache') do
478
+ print 'downloading unzipper (7zip--400K) ...'
479
+ MainWindow.download("http://downloads.sourceforge.net/project/sevenzip/7-Zip/9.20/7za920.zip", "7za920.zip")
480
+ system_blocking("../unzip.exe -o 7za920.zip") # -o means "overwrite" without prompting
481
+ end
482
+ end
483
+ end
484
+
485
+ def download_zip_file_and_extract english_name, url, to_this
486
+ download_7zip
487
+ Dir.chdir('vendor/cache') do
488
+ file_name = url.split('/')[-1]
489
+ print "downloading #{english_name} ..."
490
+ MainWindow.download(url, file_name)
491
+ system_blocking("7za e #{file_name} -y -o#{to_this}")
492
+ puts 'done ' + english_name
493
+ # creates vendor/cache/mencoder/mencoder.exe...
494
+ end
495
+ end
496
+
497
+ def check_for_exe windows_full_loc, unix_name
498
+ # in windows, that exe *at that location* must exist...
499
+ if OS.windows?
500
+ File.exist?(windows_full_loc)
501
+ else
502
+ require 'lib/check_installed_mac.rb'
503
+ if !CheckInstalledMac.check_for_installed(unix_name)
504
+ exit 1 # it'll have already displayed a message...
505
+ else
506
+ true
507
+ end
508
+ end
509
+ end
510
+
511
+ def check_for_various_dependencies
512
+ if we_are_in_create_mode
513
+ if !check_for_exe('vendor/cache/mencoder/mencoder.exe', 'mencoder')
514
+ require_blocking_license_accept_dialog 'mplayer', 'gplv2', 'http://www.gnu.org/licenses/gpl-2.0.html', "Appears that you need to install a dependency: mplayer with mencoder."
515
+ download_zip_file_and_extract "Mplayer/mencoder (6MB)", "http://sourceforge.net/projects/mplayer-win32/files/MPlayer%20and%20MEncoder/revision%2033883/MPlayer-rtm-svn-33883.7z", "mencoder"
516
+ end
517
+ end
518
+
519
+ # runtime dependencies, at least as of today...
520
+ ffmpeg_exe_loc = File.expand_path('vendor/cache/ffmpeg/ffmpeg.exe')
521
+ if !check_for_exe(ffmpeg_exe_loc, 'ffmpeg')
522
+ require_blocking_license_accept_dialog 'ffmpeg', 'gplv2', 'http://www.gnu.org/licenses/gpl-2.0.html', "Appears that you need to install a dependency: ffmpeg."
523
+ download_zip_file_and_extract "ffmpeg (5MB)", "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-git-335bbe4-win32-static.7z", "ffmpeg"
524
+ end
525
+ if OS.mac?
526
+ check_for_exe("mplayer", "mplayer") # mencoder and mplayer are separate for mac... [this checks for mac's mplayerx, too]
527
+ else
528
+ path = RubyWhich.new.which('smplayer_portable')
529
+ if(path.length == 0)
530
+ # this one has its own installer...
531
+ show_blocking_message_dialog("It appears that you need to install a pre-requisite dependency: MPlayer for Windows (MPUI).
532
+ Click ok to be directed to its download website, where you can download and install it (recommend: MPUI....Full-Package.exe),
533
+ then restart sensible cinema. NB that it takes awhile to install. Sorry about that.",
534
+ "Lacking dependency", JOptionPane::ERROR_MESSAGE)
535
+ open_url_to_view_it_non_blocking "http://code.google.com/p/mulder/downloads/list?can=2&q=MPlayer&sort=-uploaded&colspec=Filename%20Summary%20Type%20Uploaded%20Size%20DownloadCount"
536
+ System.exit 0
537
+ end
538
+ end
539
+ end
540
+
541
+ def open_url_to_view_it_non_blocking url
542
+ if OS.windows?
543
+ system_non_blocking("start #{url.gsub('&', '^&')}") # LODO would launchy help/work here with the full url?
544
+ else
545
+ system_non_blocking "#{OS.open_file_command} \"#{url}\"" # LODO test
546
+ end
547
+ end
548
+
549
+ def open_file_to_edit_it filename, start_minimized=false
550
+ if OS.windows?
551
+ if start_minimized
552
+ system_non_blocking "start /min notepad \"#{filename}\""
553
+ else
554
+ system_non_blocking "notepad \"#{filename}\""
555
+ end
556
+ else
557
+ system_non_blocking "open -a TextEdit \"#{filename}\""
558
+ end
559
+ end
560
+
561
+ def new_nonexisting_filechooser_and_go title = nil, default_dir = nil, default_file = nil
562
+ JFileChooser.new_nonexisting_filechooser_and_go title, default_dir, default_file
563
+ end
564
+
565
+ def show_blocking_message_dialog(message, title = message.split("\n")[0], style= JOptionPane::INFORMATION_MESSAGE)
566
+ SwingHelpers.show_blockiing_message_dialog message, title, style
567
+ end
568
+
569
+ # call dispose on this to close it if it hasn't been canceled yet...
570
+ def show_non_blocking_message_dialog message, close_button_text = 'Close'
571
+ # lodo NonBlockingDialog it can get to the top instead of being so buried...
572
+ NonBlockingDialog.new(message, close_button_text)
573
+ end
574
+
575
+ include_class javax.swing.UIManager
576
+
577
+ def get_user_input(message, default = '', cancel_ok = false)
578
+ SwingHelpers.get_user_input message, default, cancel_ok
579
+ end
580
+
581
+ def show_copy_pastable_string(message, value)
582
+ RubyClip.set_clipboard value
583
+ get_user_input message + " (has been copied to clipboard)", value, true
584
+ end
585
+
586
+ # also caches directory previously selected ...
587
+ def new_existing_file_selector_and_select_file title, dir = nil
588
+ dir ||= LocalStorage[caller.inspect] = File.dirname(got)
589
+ got = FileDialog.new_previously_existing_file_selector_and_go title, dir
590
+ LocalStorage[caller.inspect] = File.dirname(got)
591
+ got
592
+ end
593
+
594
+ def show_in_explorer filename
595
+ SwingHelpers.show_in_explorer filename
596
+ end
597
+
598
+ def get_disk_chooser_window names
599
+ GetDisk.new(self, names)
600
+ end
601
+
602
+ end
603
+
604
+ class GetDisk < JDialog
605
+ attr_reader :selected_idx
606
+ def initialize parent, options_array
607
+ super parent, true
608
+
609
+ box = JComboBox.new
610
+ box.add_action_listener do |e|
611
+ idx = box.get_selected_index
612
+ if idx != 0
613
+ # don't count choosing the first as a real entry
614
+ @selected_idx = box.get_selected_index - 1
615
+ dispose
616
+ end
617
+ end
618
+
619
+ box.add_item "Click to select DVD drive" # put something in index 0
620
+ options_array.each{|drive|
621
+ box.add_item drive
622
+ }
623
+ add box
624
+ pack # how do you get this arbitrary size? what the...
625
+ end
626
+ end
627
+ end
628
+
629
+ # LODO move to sane :) also remove the andand dep.
630
+ class String
631
+ def present?
632
+ length > 0
633
+ end
634
+ end
635
+
636
+ class NilClass
637
+ def present?
638
+ false
639
+ end
640
+ end
641
+ class Object
642
+ def present?
643
+ true
644
+ end
645
+ end
646
+
647
+ class Array
648
+ def present?
649
+ length > 0
650
+ end
651
+ end
652
+
653
+
654
+ class File
655
+ def self.get_root_dir this_path
656
+ this_path = File.expand_path this_path
657
+ if OS.doze?
658
+ this_path[0..2]
659
+ else
660
+ this_path.split('/')[0]
661
+ end
662
+ end
663
+
664
+ def self.strip_drive_windows this_complete_path
665
+ if OS.doze?
666
+ this_complete_path[2..-1]
667
+ else
668
+ this_complete_path
669
+ end
670
+ end
671
+ end