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.
- data/.gitmodules +3 -0
- data/README +9 -6
- data/TODO +91 -41
- data/VERSION +1 -1
- data/bin/sensible-cinema +13 -1506
- data/bin/sensible-cinema-cli +156 -151
- data/change_log_with_feature_list.txt +17 -2
- data/developer_how_to_contribute_to_the_project.txt +3 -2
- data/documentation/upconversion.txt +4 -0
- data/history_and_related_works_list.txt +1 -0
- data/{play_with_inserted_scene.bat → legal/play_with_inserted_scene.bat} +0 -0
- data/{play_with_overlay.bat → legal/play_with_overlay.bat} +0 -0
- data/legal2 +2 -0
- data/lib/count_down_timer_jruby_swing.rb +3 -4
- data/lib/edl_parser.rb +345 -339
- data/lib/eight_three.rb +6 -1
- data/lib/gui/sensible-cinema-base.rb +671 -0
- data/lib/gui/sensible-cinema-create.rb +304 -0
- data/lib/{sensible-cinema-dependencies.rb → gui/sensible-cinema-dependencies.rb} +0 -0
- data/lib/gui/sensible-cinema-normal.rb +349 -0
- data/lib/gui/sensible-cinema-side-by-side.rb +27 -0
- data/lib/gui/sensible-cinema-upconvert.rb +254 -0
- data/lib/screen_tracker.rb +1 -0
- data/spec/edl_parser.spec.rb +6 -0
- data/spec/notes +107 -16
- data/spec/sensible_cinema_gui.spec.rb +63 -58
- data/todo.inventionzy.txt +12 -0
- data/todo.propaganda +1 -2
- data/todo.upconvert +3 -1
- data/upconvert_netflix/record_screen/record.bat +2 -0
- data/upconvert_netflix/record_screen/recording/1.png +0 -0
- data/upconvert_netflix/record_screen/recording/10.png +0 -0
- data/upconvert_netflix/record_screen/recording/2.png +0 -0
- data/upconvert_netflix/record_screen/recording/3.png +0 -0
- data/upconvert_netflix/record_screen/recording/4.png +0 -0
- data/upconvert_netflix/record_screen/recording/5.png +0 -0
- data/upconvert_netflix/record_screen/recording/6.png +0 -0
- data/upconvert_netflix/record_screen/recording/7.png +0 -0
- data/upconvert_netflix/record_screen/recording/8.png +0 -0
- data/upconvert_netflix/record_screen/recording/9.png +0 -0
- data/upconvert_netflix/record_screen/recording/d.png +0 -0
- data/www/content_editor.html +2 -2
- data/zamples/edit_decision_lists/dvds/edls_being_edited/cars_disney.txt +5 -7
- data/zamples/edit_decision_lists/dvds/innerspace.txt +77 -0
- data/zamples/edit_decision_lists/netflix_instant/avatar-last-air-bender-movie.txt +12 -0
- data/zamples/edit_decision_lists/netflix_instant/avatar-last-airbender-series.txt +1 -0
- data/zamples/players/netflix/netflix_firefox_non_maximized.txt +1 -1
- metadata +28 -11
- data/lib/file_chooser.rb +0 -46
- data/lib/swing_helpers.rb +0 -142
- data/www/monkey.png +0 -0
@@ -0,0 +1,304 @@
|
|
1
|
+
module SensibleSwing
|
2
|
+
|
3
|
+
class MainWindow
|
4
|
+
|
5
|
+
def setup_advanced_buttons
|
6
|
+
|
7
|
+
new_jbutton("Display the standard buttons") do
|
8
|
+
window = new_child_window
|
9
|
+
window.setup_normal_buttons
|
10
|
+
end
|
11
|
+
|
12
|
+
@mplayer_edl = new_jbutton( "Watch DVD edited (realtime) (mplayer)")
|
13
|
+
@mplayer_edl.on_clicked {
|
14
|
+
play_mplayer_edl_non_blocking nil, [], true, false
|
15
|
+
}
|
16
|
+
|
17
|
+
add_text_line 'Realtime/Create Options:'
|
18
|
+
|
19
|
+
@create_new_edl_for_current_dvd = new_jbutton("Create new Edit List for a DVD",
|
20
|
+
"If your DVD doesn't have an EDL created for it, this will be your first step--create an EDL file for it.")
|
21
|
+
@create_new_edl_for_current_dvd.on_clicked do
|
22
|
+
create_brand_new_edl
|
23
|
+
@display_dvd_info.simulate_click # for now...
|
24
|
+
end
|
25
|
+
|
26
|
+
@open_list = new_jbutton("Open/Edit a previously created Edit List file", "If your DVD has a previously existing EDL for it, you can open it to edit it with this button.")
|
27
|
+
@open_list.on_clicked {
|
28
|
+
filename = new_existing_file_selector_and_select_file( "Pick any file to open in editor", EdlParser::EDL_DIR)
|
29
|
+
open_file_to_edit_it filename
|
30
|
+
}
|
31
|
+
|
32
|
+
@play_smplayer = new_jbutton( "Watch full DVD unedited (realtime smplayer)")
|
33
|
+
@play_smplayer.tool_tip = <<-EOL
|
34
|
+
This will play the DVD unedited within smplayer.
|
35
|
+
NB it will default to title 1, so updated your EDL file that matches this DVD with the proper title if this doesn't work for you
|
36
|
+
i.e. if it just plays a single preview title or what not, and not the main title, you need to change this value.
|
37
|
+
This is useful if you want to just kind of watch the movie to enjoy it, and look for scenes to cut out.
|
38
|
+
You can use the built-in OSD (on-screen-display) to see what time frame the questionable scenes are at
|
39
|
+
(type "o" to toggle it). However, just realize that the OSD is in 30 fps, and our time stamps are all in 29.97
|
40
|
+
fps, so you'll need to convert it (the convert timestamp button) to be able to use it in a file.
|
41
|
+
EOL
|
42
|
+
@play_smplayer.on_clicked {
|
43
|
+
play_dvd_smplayer_unedited false, true, true
|
44
|
+
}
|
45
|
+
|
46
|
+
@play_mplayer_raw = new_jbutton( "Watch full DVD unedited (realtime mplayer)")
|
47
|
+
@play_mplayer_raw.tool_tip = <<-EOL
|
48
|
+
This is also useful for comparing subtitle files to see if they have accurate timings.
|
49
|
+
If you turn on subtitles (use the v button), then compare your srt file at say, the 1 hour mark, or 2 hour mark,
|
50
|
+
with the subtitles that mplayer displays, it *should* match exactly with the output in the command line,
|
51
|
+
like "V: 3600.0" should match your subtitle line "01:00:00,000 --> ..."
|
52
|
+
EOL
|
53
|
+
@play_mplayer_raw.on_clicked {
|
54
|
+
play_dvd_smplayer_unedited true, true, true
|
55
|
+
}
|
56
|
+
|
57
|
+
@parse_srt = new_jbutton("Scan a subtitle file (.srt) to detect profanity times automatically" )
|
58
|
+
@parse_srt.tool_tip = <<-EOL
|
59
|
+
You can download a .srt file and use it to automatically search for profanities.
|
60
|
+
Basically download it from opensubtitles.org (possibly from other sites, too),
|
61
|
+
(enter dvd name in the search box, click a result, click one from the list with an English flag, then click 'Download(zip)')
|
62
|
+
Once you download the zip, unzip it, and then compare the timestamps in it with those on the DVD (see the button "Watch DVD unedited (realtime mplayer)")
|
63
|
+
NB that you'll first want/need to *carefully* double check your subtitle
|
64
|
+
file with the actual DVD. (ex: smplayer, hit the 'o' button to display
|
65
|
+
the current timestamp, then go to the end, stop at some point with text
|
66
|
+
and hit the '.' key until a subtitle very first displays.
|
67
|
+
Next convert that number to 29.97 fps (using the button given).
|
68
|
+
The numbers should match precisely. If they don't, edit this file
|
69
|
+
so that it will have some offsets given.
|
70
|
+
EOL
|
71
|
+
|
72
|
+
@parse_srt.on_clicked do
|
73
|
+
filename = new_existing_file_selector_and_select_file("Pick srt file to scan for profanity:")
|
74
|
+
add_to_beginning = get_user_input("How much time to subtract from the beginning of each subtitle entry (ex: 1:00 -> 1:01 becomes 0:59 -> 1:01)", "0.0")
|
75
|
+
add_to_end = get_user_input("How much time to add to the end of each subtitle entry (ex: 1:00 -> 1:01 becomes 1:00 -> 1:02)", "0.0")
|
76
|
+
parsed = SubtitleProfanityFinder.edl_output filename, {}, add_to_beginning.to_f, add_to_end.to_f # flight: TODO necessary typically ??? 0.35, 0.25
|
77
|
+
File.write(EdlTempFile, "# add these into your mute section if you deem them mute-worthy\n" + parsed)
|
78
|
+
open_file_to_edit_it filename, true
|
79
|
+
sleep 0.3 if OS.mac? # add delay...
|
80
|
+
open_file_to_edit_it EdlTempFile
|
81
|
+
end
|
82
|
+
|
83
|
+
@display_dvd_info = new_jbutton( "Display information about current DVD (ID, etc.)" )
|
84
|
+
@display_dvd_info.tool_tip = "This is useful to setup a DVD's 'unique ID' within an EDL for it. \nIf your EDL doesn't have a line like disk_unique_id => \"...\" then you will want to run this to be able to add that line in."
|
85
|
+
@display_dvd_info.on_clicked {
|
86
|
+
drive, volume_name, dvd_id = choose_dvd_drive_or_file true # real DVD disk
|
87
|
+
# display it, allow them to copy and paste it out
|
88
|
+
title_lengths = nil
|
89
|
+
t = Thread.new { title_lengths= `mplayer dvdnav:// -nocache -dvd-device #{drive} -identify -frames 0 2>&1| grep LENGTH` }
|
90
|
+
id_string = "\"disk_unique_id\" => \"#{dvd_id}\", # #{volume_name}"
|
91
|
+
show_copy_pastable_string "#{drive} #{volume_name} for your copying+pasting pleasure (highlight, then ctrl+c to copy)\n
|
92
|
+
This is USED eventually to identify a disk to match it to its EDL, later.", id_string
|
93
|
+
t.join
|
94
|
+
File.write EdlTempFile, id_string + "\n" + title_lengths
|
95
|
+
open_file_to_edit_it EdlTempFile
|
96
|
+
id_string
|
97
|
+
}
|
98
|
+
|
99
|
+
@convert_seconds_to_ts = new_jbutton( "Convert 3600 <-> 1:00:00 style timestamps" )
|
100
|
+
@convert_seconds_to_ts.on_clicked {
|
101
|
+
input = get_user_input("Enter \"from\" timestamps, like 3600 or 1:40:00:", "1:00:00.1 or 3600.1")
|
102
|
+
while(input)
|
103
|
+
if input =~ /:/
|
104
|
+
output = EdlParser.translate_string_to_seconds input
|
105
|
+
else
|
106
|
+
output = EdlParser.translate_time_to_human_readable input.to_f, true
|
107
|
+
end
|
108
|
+
input = show_copy_pastable_string("Converted:", output)
|
109
|
+
end
|
110
|
+
}
|
111
|
+
|
112
|
+
@convert_timestamp = new_jbutton( "Convert timestamp from DVD player time to EDL time (30->29.97 fps)" )
|
113
|
+
@convert_timestamp.tool_tip=<<-EOL
|
114
|
+
Our EDL's assume 29.97 fps (which is what a DVD actually has). Unfortunately most hardware or commercial DVD players
|
115
|
+
think that the DVD is 30 fps, which means that if you use them for timestamps for your EDL's,
|
116
|
+
you will be slightly off (at the end of a 2 hour film, by 8 seconds). So all your edits will be wrong.
|
117
|
+
How to fix: convert your times from "DVD player" time to "EDL accurate" time by using this button.
|
118
|
+
This is necessary for all hardware DVD player timestamps, PowerDVD player (software), Windows Media Player (playing a DVD),
|
119
|
+
and mplayer's "on screen display" DVD timestamps.
|
120
|
+
It is not necessary for smplayer timestamps (or mplayer's "V: 3600" in the command line), which are already 29.97.
|
121
|
+
smplayer's on-screen-display (the 'o' key) is accurate (and doesn't suffer from dvd_mplayer_splits)
|
122
|
+
but is 30 fps, so timestamps would need to be converted.
|
123
|
+
Dont use VLC for DVD timestamps at all--it can get up to 30s off! VLC playing back a file is usually pretty accurate to 29.97.
|
124
|
+
In general, GUI's like VLC or smplayer are always a tidge off (maybe 0.3s) from the right timestamp, so take that into consideration.
|
125
|
+
Mplayers "V: 3600" is usually right on (29.97 fps), however.
|
126
|
+
EOL
|
127
|
+
@convert_timestamp.on_clicked {
|
128
|
+
thirty_fps = get_user_input("Enter your DVD (30 fps) timestamp, I'll convert it to 29.97 (usable in EDL's):", "1:00:00.1")
|
129
|
+
thirty_fps_in_seconds = EdlParser.translate_string_to_seconds thirty_fps
|
130
|
+
twenty_nine_seven_fps = ConvertThirtyFps.from_thirty(thirty_fps_in_seconds)
|
131
|
+
human_twenty_nine_seven = EdlParser.translate_time_to_human_readable twenty_nine_seven_fps, true
|
132
|
+
show_copy_pastable_string("Sensible cinema usable value (29.97 fps) for #{thirty_fps} would be: ", human_twenty_nine_seven)
|
133
|
+
}
|
134
|
+
|
135
|
+
@create_dot_edl = new_jbutton( "Create a side-by-side moviefilename.edl file")
|
136
|
+
@create_dot_edl.tool_tip = <<-EOL
|
137
|
+
Creates a moviefilename.edl file (corresponding to some moviefilename.some_ext file already existing)
|
138
|
+
XBMC/smplayer (smplayer can be used by WMC plugins, etc.) "automagically detect",
|
139
|
+
if it exists, and automatically use it .edl to show that file edited played back.
|
140
|
+
If you use smplayer, note that you'll need to download the "lord mulder mplayer"
|
141
|
+
version (which includes an updated version of mplayer that fixes some bugs in EDL playback)
|
142
|
+
EOL
|
143
|
+
@create_dot_edl.on_clicked {
|
144
|
+
choose_file_and_edl_and_create_sxs_or_play true
|
145
|
+
}
|
146
|
+
|
147
|
+
add_text_line 'Create Options with local intermediary file:'
|
148
|
+
|
149
|
+
new_jbutton("Show options with local intermediary file") do
|
150
|
+
window = new_child_window
|
151
|
+
window.add_options_that_use_local_files
|
152
|
+
end
|
153
|
+
|
154
|
+
# @reload = new_jbutton("reload bin/sensible-cinema code") do
|
155
|
+
# load $0
|
156
|
+
# end
|
157
|
+
|
158
|
+
end # advanced buttons
|
159
|
+
|
160
|
+
def add_options_that_use_local_files
|
161
|
+
add_text_line 'Create Options that first create/use a local intermediary file:'
|
162
|
+
|
163
|
+
@preview_section = new_jbutton( "Preview a certain time frame from fulli file (edited)" )
|
164
|
+
@preview_section.tool_tip = <<-EOL
|
165
|
+
This allows you to preview an edit easily.
|
166
|
+
It is the equivalent of saying \"watch this file edited from exactly minute x second y to minute z second q"
|
167
|
+
Typically if you want to test an edit, you can start a few seconds before, and end a few seconds after it, to test it precisely.
|
168
|
+
EOL
|
169
|
+
@preview_section.on_clicked {
|
170
|
+
do_create_edited_copy_via_file true
|
171
|
+
}
|
172
|
+
|
173
|
+
@preview_section_unedited = new_jbutton("Preview a certain time frame from fulli file (unedited)" )
|
174
|
+
@preview_section.tool_tip = "Allows you to view a certain time frame unedited (ex: 10:00 to 10:05), so you can narrow down to pinpoint where questionable scenes are, etc. This is the only way to view a specific scene if there are not cuts within that scene yet."
|
175
|
+
@preview_section_unedited.on_clicked {
|
176
|
+
do_create_edited_copy_via_file true, false, true
|
177
|
+
}
|
178
|
+
|
179
|
+
@rerun_preview = new_jbutton( "Re-run most recently watched preview time frame from fulli file" )
|
180
|
+
@rerun_preview.tool_tip = "This will re-run the preview that you most recently performed. Great for checking to see if you last edits were successful or not."
|
181
|
+
@rerun_preview.on_clicked {
|
182
|
+
repeat_last_copy_dvd_to_hard_drive
|
183
|
+
}
|
184
|
+
|
185
|
+
# Maybe this button should go too...
|
186
|
+
@fast_preview = new_jbutton("fast preview all from fulli file (smplayer EDL)")
|
187
|
+
@fast_preview.tool_tip = <<-EOL
|
188
|
+
Plays smplayer on a file with an EDL.
|
189
|
+
This gives you a rough estimate to see if your edits are accurate, and is really fast to seek, etc.
|
190
|
+
This is useful because you can't use mplayer on a DVD for accurate timestamps if it has any
|
191
|
+
timestamp splits in it [because some DVD's are buggy]
|
192
|
+
EOL
|
193
|
+
@fast_preview.on_clicked {
|
194
|
+
success, wrote_to_here_fulli = do_create_edited_copy_via_file false, true
|
195
|
+
sleep 0.5 # lodo take out ???
|
196
|
+
background_thread.join if background_thread # let it write out the original fulli, if necessary [?]
|
197
|
+
nice_file = wrote_to_here_fulli
|
198
|
+
run_smplayer_blocking nice_file, nil, "-edl #{normalize_path EdlTempFile}", false, true, false
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
def do_create_edited_copy_via_file should_prompt_for_start_and_end_times, exit_early_if_fulli_exists = false, watch_unedited = false
|
203
|
+
drive_or_file, dvd_volume_name, dvd_id, edit_list_path, descriptors = choose_dvd_or_file_and_edl_for_it
|
204
|
+
|
205
|
+
descriptors = parse_edl(edit_list_path)
|
206
|
+
if watch_unedited
|
207
|
+
# reset them
|
208
|
+
descriptors['mutes'] = descriptors['blank_outs'] = []
|
209
|
+
end
|
210
|
+
|
211
|
+
# LODO allow for spaces in the save_to filename
|
212
|
+
if should_prompt_for_start_and_end_times
|
213
|
+
# only show this message once :)
|
214
|
+
@show_block ||= show_blocking_message_dialog(<<-EOL, "Preview")
|
215
|
+
Ok, let's preview just a portion of it.
|
216
|
+
Note that you'll want to preview a section that wholly includes a deleted section in it.
|
217
|
+
For example, if it mutes from second 1 to second 10, you'll want to play from 00:00 to 00:12 or what not.
|
218
|
+
Also note that the first time you preview a section of a video, it will take a long time (like an hour) as it sets up the entire video for processing.
|
219
|
+
Subsequent previews will be faster, though, as long as you use the same filename, as it won't have to re-set it up for processing.
|
220
|
+
Also note that if you change your edit list, you'll need to close, and restart the video to be able to see it with your new settings.
|
221
|
+
EOL
|
222
|
+
old_start = LocalStorage['start_time']
|
223
|
+
start_time = get_user_input("At what point in the video would you like to start your preview? (like 01:00 for starting at 1 minute)", LocalStorage['start_time'])
|
224
|
+
default_end = LocalStorage['end_time']
|
225
|
+
if start_time and start_time != old_start
|
226
|
+
default_end = EdlParser.translate_string_to_seconds(start_time) + 10
|
227
|
+
default_end = EdlParser.translate_time_to_human_readable(default_end)
|
228
|
+
end
|
229
|
+
end_time = get_user_input("At what point in the video would you like to finish your preview? (like 02:00 for ending at the 2 minute mark)", default_end)
|
230
|
+
unless start_time and end_time
|
231
|
+
# this one is raw showMessageDialog...
|
232
|
+
JOptionPane.showMessageDialog(nil, " Please choose start and end", "Failed", JOptionPane::ERROR_MESSAGE)
|
233
|
+
return
|
234
|
+
end
|
235
|
+
LocalStorage['start_time'] = start_time
|
236
|
+
LocalStorage['end_time'] = end_time
|
237
|
+
end
|
238
|
+
dvd_friendly_name = descriptors['name']
|
239
|
+
unless dvd_friendly_name
|
240
|
+
drive_or_file, dvd_volume_name, dvd_id, edit_list_path, descriptors = choose_dvd_or_file_and_edl_for_it
|
241
|
+
descriptors = parse_edl(edit_list_path)
|
242
|
+
raise 'no dvd name in EDL?' + edit_list_path + File.read(edit_list_path)
|
243
|
+
end
|
244
|
+
|
245
|
+
dvd_title_track = get_title_track(descriptors)
|
246
|
+
if dvd_id == NonDvd
|
247
|
+
file_from = drive_or_file
|
248
|
+
else
|
249
|
+
file_from = get_grabbed_equivalent_filename_once dvd_friendly_name, dvd_title_track # we don't even care about the drive letter anymore...
|
250
|
+
end
|
251
|
+
show_blocking_message_dialog("warning: file #{file_from} is not a .mpg or .ts file--it may not work properly all the way--if it's mkv and fails consider first converting to ts by using tsmuxer.") unless file_from =~ /\.(ts|mpg|mpeg)$/i
|
252
|
+
save_to_edited = get_save_to_filename dvd_friendly_name
|
253
|
+
fulli = MencoderWrapper.calculate_fulli_filename save_to_edited
|
254
|
+
if exit_early_if_fulli_exists
|
255
|
+
if fulli_dot_done_file_exists? save_to_edited
|
256
|
+
return [true, fulli]
|
257
|
+
end
|
258
|
+
# make it create a dummy response file for us :)
|
259
|
+
start_time = "00:00"
|
260
|
+
end_time = "00:01"
|
261
|
+
end
|
262
|
+
should_run_mplayer = should_prompt_for_start_and_end_times || exit_early_if_fulli_exists
|
263
|
+
require_deletion_entry = true unless watch_unedited
|
264
|
+
generate_and_run_bat_file save_to_edited, edit_list_path, descriptors, file_from, dvd_friendly_name, start_time, end_time, dvd_title_track, should_run_mplayer, require_deletion_entry
|
265
|
+
[false, fulli] # false means it's running in a background thread :P
|
266
|
+
end
|
267
|
+
|
268
|
+
def create_brand_new_edl
|
269
|
+
drive, volume, dvd_id = choose_dvd_drive_or_file true
|
270
|
+
english_name = get_user_input("Enter a human readable DVD description for #{volume}", volume.gsub('_', ' ').downcase)
|
271
|
+
input = <<-EOL
|
272
|
+
# comments can go after a # on any line, for example this one.
|
273
|
+
"name" => "#{english_name}",
|
274
|
+
|
275
|
+
"mutes" => [
|
276
|
+
# an example line, uncomment the leading "#" to make it active
|
277
|
+
# "0:00:01.0", "0:00:02.0", "profanity", "da..",
|
278
|
+
],
|
279
|
+
|
280
|
+
"blank_outs" => [
|
281
|
+
# an example line, uncomment the leading "#" to make it active
|
282
|
+
# "00:03:00.0" , "00:04:00.0", "violence", "of some sort",
|
283
|
+
],
|
284
|
+
|
285
|
+
"volume_name" => "#{volume}",
|
286
|
+
"disk_unique_id" => "#{dvd_id}",
|
287
|
+
"dvd_title_track" => "1", # the "show DVD info" button will tell you title lengths (typically longest title is the title track)
|
288
|
+
# "dvd_title_track_length" => "9999", # length, on the DVD, of dvd_title_track (use the show DVD info button to get this number).
|
289
|
+
# "subtitle_url" => "1234567",
|
290
|
+
# "not edited out stuff" => "some...",
|
291
|
+
# "closing thoughts" => "only...",
|
292
|
+
# In mplayer, the DVD timestamp "resets" to zero for some reason, so you need to specify when if you want to use mplayer DVD realtime playback, or use mencoder -edl to split your file. See http://goo.gl/yMfqX
|
293
|
+
# "mplayer_dvd_splits" => ["59:59", "1:04:59"], # or [] if there are none. Additive currently. 12345.6 ok.
|
294
|
+
EOL
|
295
|
+
# TODO auto-ify above, move docs to a file in documentation.
|
296
|
+
filename = EdlParser::EDL_DIR + "/edls_being_edited/" + english_name.gsub(' ', '_') + '.txt'
|
297
|
+
filename.downcase!
|
298
|
+
File.write(filename, input) unless File.exist?(filename) # lodo let them choose name (?)
|
299
|
+
open_file_to_edit_it filename
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
end
|
304
|
+
end
|
File without changes
|
@@ -0,0 +1,349 @@
|
|
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
|
+
module SensibleSwing
|
21
|
+
|
22
|
+
class MainWindow < JFrame
|
23
|
+
|
24
|
+
attr_accessor :parent, :upconv_line
|
25
|
+
|
26
|
+
|
27
|
+
# converts to full path, 8.3 if on doze
|
28
|
+
def normalize_path path
|
29
|
+
path = File.expand_path path
|
30
|
+
path = EightThree.convert_path_to_8_3 path if OS.doze?
|
31
|
+
end
|
32
|
+
|
33
|
+
def setup_normal_buttons
|
34
|
+
add_text_line ""
|
35
|
+
|
36
|
+
@mplayer_edl = new_jbutton( "Watch DVD edited (realtime)")
|
37
|
+
@mplayer_edl.tool_tip = "This will watch your DVD in realtime from your computer while skipping/muting questionable scenes."
|
38
|
+
@mplayer_edl.on_clicked {
|
39
|
+
play_mplayer_edl_non_blocking
|
40
|
+
}
|
41
|
+
|
42
|
+
@create = new_jbutton( "Create edited copy of DVD/file on Your Hard Drive" )
|
43
|
+
@create.tool_tip = <<-EOL
|
44
|
+
This takes a file and creates a new file on your hard disk like dvd_name_edited.mpg that you can watch when it's done.
|
45
|
+
The file you create will contain the whole movie edited.
|
46
|
+
It takes quite awhile maybe 2 hours. Sometimes the progress bar will look paused--it typically continues eventually.
|
47
|
+
EOL
|
48
|
+
@create.on_clicked {
|
49
|
+
do_create_edited_copy_via_file false
|
50
|
+
}
|
51
|
+
|
52
|
+
@watch_file_edl = new_jbutton( "Watch movie file edited (realtime)" ) do
|
53
|
+
choose_file_and_edl_and_create_sxs_or_play false
|
54
|
+
end
|
55
|
+
|
56
|
+
if LocalStorage[UpConvertEnglish]
|
57
|
+
add_text_line ''
|
58
|
+
add_open_documentation_button
|
59
|
+
@upconv_line = add_text_line " #{get_current_upconvert_as_phrase}"
|
60
|
+
else
|
61
|
+
@upconv_line = add_text_line ''
|
62
|
+
add_open_documentation_button
|
63
|
+
end
|
64
|
+
|
65
|
+
add_change_upconvert_options_button
|
66
|
+
|
67
|
+
@progress_bar = JProgressBar.new(0, 100)
|
68
|
+
@progress_bar.set_bounds(44,@starting_button_y,@button_width,23)
|
69
|
+
@progress_bar.visible = false
|
70
|
+
@panel.add @progress_bar
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_open_documentation_button
|
75
|
+
@open_help_file = new_jbutton("View Sensible Cinema Documentation") do
|
76
|
+
show_in_explorer __DIR__ + "/../documentation" # TODO mac :)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def choose_file_and_edl_and_create_sxs_or_play just_create_dot_edl_file_instead_of_play
|
81
|
+
filename_mpg = new_existing_file_selector_and_select_file( "Pick moviefile (like moviename.mpg or video_ts/anything.ext)")
|
82
|
+
edl_filename = new_existing_file_selector_and_select_file( "Pick an EDL file to use with it", EdlParser::EDL_DIR)
|
83
|
+
assert_ownership_dialog
|
84
|
+
if just_create_dot_edl_file_instead_of_play
|
85
|
+
descriptors = EdlParser.parse_file edl_filename
|
86
|
+
# LODO these timings...DRY up...plus is XBMC the same? what about on a slower computer?
|
87
|
+
# NB these are just for the Side by side EDL's!
|
88
|
+
|
89
|
+
edl_contents = MplayerEdl.convert_to_edl descriptors, add_secs_end = MplayerEndBuffer, MplayerBeginingBuffer, splits = []
|
90
|
+
output_file = filename_mpg.gsub(/\.[^\.]+$/, '') + '.edl' # sanitize...
|
91
|
+
File.write(output_file, edl_contents)
|
92
|
+
raise unless File.exist?(output_file)
|
93
|
+
show_blocking_message_dialog("created #{output_file}")
|
94
|
+
else
|
95
|
+
play_mplayer_edl_non_blocking [filename_mpg, edl_filename]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def we_are_in_upconvert_mode
|
100
|
+
ARGV.index("--upconvert-mode")
|
101
|
+
end
|
102
|
+
|
103
|
+
def setup_default_buttons
|
104
|
+
if we_are_in_upconvert_mode
|
105
|
+
add_play_upconvert_buttons
|
106
|
+
else
|
107
|
+
|
108
|
+
if we_are_in_create_mode
|
109
|
+
setup_advanced_buttons
|
110
|
+
add_text_line 'Contact:'
|
111
|
+
else
|
112
|
+
setup_normal_buttons
|
113
|
+
end
|
114
|
+
|
115
|
+
@upload = new_jbutton("Submit Feedback/Upload new EDL's/Request Help") # keeps this one last! :)
|
116
|
+
@upload.tool_tip = "We welcome all feedback!\nQuestion, comments, request help.\nAlso if you create a new EDL, please submit it back to us so that others can benefit from it later!"
|
117
|
+
@upload.on_clicked {
|
118
|
+
system_non_blocking("start mailto:sensible-cinema@googlegroups.com")
|
119
|
+
system_non_blocking("start http://groups.google.com/group/sensible-cinema")
|
120
|
+
}
|
121
|
+
increment_button_location
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
@exit = new_jbutton("Exit", "Exits the application and kills any background processes that are running at all--don't exit unless you are done processing all the way!")
|
126
|
+
@exit.on_clicked {
|
127
|
+
Thread.new { self.close } # don't waste the time to close it :P
|
128
|
+
puts 'Thank you for using Sensible Cinema. Come again!'
|
129
|
+
System.exit 0
|
130
|
+
}
|
131
|
+
|
132
|
+
increment_button_location
|
133
|
+
increment_button_location
|
134
|
+
self
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
def repeat_last_copy_dvd_to_hard_drive
|
139
|
+
generate_and_run_bat_file *LocalStorage['last_params']
|
140
|
+
end
|
141
|
+
|
142
|
+
def parse_edl path
|
143
|
+
EdlParser.parse_file path
|
144
|
+
end
|
145
|
+
def get_freespace path
|
146
|
+
JFile.new(File.dirname(path)).get_usable_space
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
def get_title_track descriptors, use_default_of_one = true
|
151
|
+
given = descriptors["dvd_title_track"]
|
152
|
+
given ||= "1" if use_default_of_one
|
153
|
+
given
|
154
|
+
end
|
155
|
+
|
156
|
+
def get_grabbed_equivalent_filename_once dvd_title, dvd_title_track
|
157
|
+
@_get_grabbed_equivalent_filename_once ||=
|
158
|
+
begin
|
159
|
+
new_existing_file_selector_and_select_file "Please choose the file that is your ripped equivalent of #{dvd_title} (title track #{dvd_title_track}) (.mpg or .ts--see file documentation/how_to_get_files_from_dvd.txt)"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def get_save_to_filename dvd_title
|
164
|
+
@_get_save_to_filename ||=
|
165
|
+
begin
|
166
|
+
save_to_file_name = dvd_title + ' edited version'
|
167
|
+
save_to_file_name = save_to_file_name.gsub(' ', '_').gsub( /\W/, '') + ".avi" # no punctuation or spaces for now, to not complicate...
|
168
|
+
save_to = new_nonexisting_filechooser_and_go "Pick where to save #{dvd_title} edited version to", nil, get_drive_with_most_space_with_slash + save_to_file_name
|
169
|
+
raise 'no spaces allowed yet' if save_to =~ / /
|
170
|
+
begin
|
171
|
+
a = File.open(File.dirname(save_to) + "/test_file_to_see_if_we_have_permission_to_write_to_this_folder", "w")
|
172
|
+
a.close
|
173
|
+
File.delete a.path
|
174
|
+
rescue Errno::EACCES => e
|
175
|
+
show_blocking_message_dialog "unable to write to that directory, please pick again: " + e.to_s
|
176
|
+
raise 'pick again!'
|
177
|
+
end
|
178
|
+
freespace = get_freespace(save_to)
|
179
|
+
if freespace < 8_000_000_000
|
180
|
+
show_blocking_message_dialog("Warning: there may not be enough space on the disk for #{save_to}
|
181
|
+
(depending on DVD size, you may need around 10G free--you have #{freespace/1_000_000_000}GB free). Click OK to continue.")
|
182
|
+
end
|
183
|
+
save_to.gsub(/\.avi$/, '')
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
def get_drive_with_most_space_with_slash
|
189
|
+
DriveInfo.get_drive_with_most_space_with_slash
|
190
|
+
end
|
191
|
+
|
192
|
+
def fulli_dot_done_file_exists? save_to_edited
|
193
|
+
fulli = MencoderWrapper.calculate_fulli_filename save_to_edited
|
194
|
+
File.exist?(fulli + ".done") # stinky!
|
195
|
+
end
|
196
|
+
|
197
|
+
# to make it stubbable :)
|
198
|
+
def get_mencoder_commands descriptors, file_from, save_to, start_time, end_time, dvd_title_track, require_deletion_entry
|
199
|
+
delete_partials = true unless start_time # in case anybody wants to look really really close [?]
|
200
|
+
MencoderWrapper.get_bat_commands descriptors, file_from, save_to, start_time, end_time, dvd_title_track, delete_partials, require_deletion_entry
|
201
|
+
end
|
202
|
+
|
203
|
+
def generate_and_run_bat_file save_to, edit_list_path, descriptors, file_from, dvd_title, start_time, end_time, dvd_title_track, run_mplayer, require_deletion_entry
|
204
|
+
LocalStorage['last_params'] = [save_to, edit_list_path, descriptors, file_from, dvd_title, start_time, end_time, dvd_title_track, run_mplayer, require_deletion_entry]
|
205
|
+
begin
|
206
|
+
commands = get_mencoder_commands descriptors, file_from, save_to, start_time, end_time, dvd_title_track, require_deletion_entry
|
207
|
+
rescue MencoderWrapper::TimingError => e
|
208
|
+
show_blocking_message_dialog("Appears you chose a time frame with no deletion segment in it--please try again:" + e)
|
209
|
+
return
|
210
|
+
rescue Errno::EACCES => e
|
211
|
+
show_blocking_message_dialog("Appears a file on the system is locked: perhaps you need to close down some instance of mplayer?" + e)
|
212
|
+
return
|
213
|
+
end
|
214
|
+
temp_dir = Dir.tmpdir
|
215
|
+
temp_file = temp_dir + '/vlc.temp.bat'
|
216
|
+
File.write(temp_file, commands)
|
217
|
+
popup_message = <<-EOL
|
218
|
+
Applying #{File.basename edit_list_path}
|
219
|
+
to #{file_from} (#{dvd_title}).
|
220
|
+
Copying to #{save_to}.
|
221
|
+
EOL
|
222
|
+
if !fulli_dot_done_file_exists?(save_to)
|
223
|
+
popup_message += "This could take quite awhile (several hours), and will prompt you with a chime noise when it is done.\n
|
224
|
+
You can close this window and minimize sensible cinema and continue using your computer while it runs in the background.\n"
|
225
|
+
end
|
226
|
+
|
227
|
+
if !start_time
|
228
|
+
# assume a full run..
|
229
|
+
popup_message += <<-EOL
|
230
|
+
NB that the created file will be playable only with VLC (possibly also with smplayer),
|
231
|
+
but probably not with windows media player.
|
232
|
+
EOL
|
233
|
+
end
|
234
|
+
|
235
|
+
popup = show_non_blocking_message_dialog(popup_message, "OK")
|
236
|
+
|
237
|
+
# allow our popups to still be serviced while it is running
|
238
|
+
@background_thread = Thread.new { run_batch_file_commands_and_use_output_somehow commands, save_to, file_from, run_mplayer }
|
239
|
+
when_thread_done(@background_thread) { popup.dispose }
|
240
|
+
# LODO warn if they will overwrite a file in the end...
|
241
|
+
end
|
242
|
+
|
243
|
+
attr_accessor :background_thread, :buttons
|
244
|
+
|
245
|
+
def run_batch_file_commands_and_use_output_somehow batch_commands, save_to, file_from, run_mplayer_after_done
|
246
|
+
@buttons.each{|b| b.set_enabled false}
|
247
|
+
success = true
|
248
|
+
lines = batch_commands.lines.to_a
|
249
|
+
total_size = lines.length.to_f
|
250
|
+
@progress_bar.visible=true
|
251
|
+
@progress_bar.set_value(10) # start at 10% always, so they can see something.
|
252
|
+
lines.each_with_index{|line, idx|
|
253
|
+
if success
|
254
|
+
puts "running #{line}"
|
255
|
+
success = system_blocking(line, true)
|
256
|
+
if !success
|
257
|
+
puts "\n", 'line failed: ' + line + "\n" + ' see troubleshooting section in README.txt file! ignoring further processing commands...'
|
258
|
+
end
|
259
|
+
end
|
260
|
+
@progress_bar.set_value(10 + idx/total_size*90)
|
261
|
+
}
|
262
|
+
@progress_bar.visible=false
|
263
|
+
@buttons.each{|b| b.set_enabled true}
|
264
|
+
if success
|
265
|
+
saved_to = save_to + '.avi'
|
266
|
+
if run_mplayer_after_done
|
267
|
+
run_smplayer_non_blocking saved_to, nil, '', false, false, true
|
268
|
+
else
|
269
|
+
if File.exist?(saved_to) && (File.size(saved_to).to_f/File.size(file_from) < 0.5) # less than 50% size is suspicious...indeed...check if exists for unit tests.
|
270
|
+
show_blocking_message_dialog("Warning: file size differs by more than 50%--it's possible that transcoding failed somehow")
|
271
|
+
end
|
272
|
+
show_in_explorer saved_to
|
273
|
+
PlayAudio.play(File.expand_path(File.dirname(__FILE__)) + "/../vendor/music.wav")
|
274
|
+
msg = "Done--you may now watch file\n #{saved_to}\n in VLC player (or possibly smplayer)"
|
275
|
+
puts msg # for being able to tell it's done on the command line
|
276
|
+
show_blocking_message_dialog msg
|
277
|
+
show_in_explorer saved_to # and again, just for kicks [?]
|
278
|
+
end
|
279
|
+
else
|
280
|
+
SwingHelpers.show_blocking_message_dialog "Failed--please examine console output and report back!\nAlso consult the documentation/troubleshooting file.", "Failed", JOptionPane::ERROR_MESSAGE
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
NonDvd = 'non dvd has no dvdid' # we need it for convenience, say you want to go through your indexed vids and convert them all?
|
285
|
+
|
286
|
+
# returns e:\, volume_name, dvd_id
|
287
|
+
# or full_path.mkv, filename, ''
|
288
|
+
def choose_dvd_drive_or_file force_choose_only_dvd_drive
|
289
|
+
opticals = DriveInfo.get_dvd_drives_as_openstruct
|
290
|
+
if @saved_opticals == opticals && @_choose_dvd_drive_or_file
|
291
|
+
# memoize...if disks haven't changed :)
|
292
|
+
return @_choose_dvd_drive_or_file
|
293
|
+
else
|
294
|
+
@saved_opticals = opticals # save currently mounted disk list, so we know if we should re-select later...
|
295
|
+
# is this ok for os x?
|
296
|
+
end
|
297
|
+
|
298
|
+
has_at_least_one_dvd_inserted = opticals.find{|d| d.VolumeName }
|
299
|
+
if !has_at_least_one_dvd_inserted && force_choose_only_dvd_drive
|
300
|
+
show_blocking_message_dialog 'insert a dvd first'
|
301
|
+
raise 'no dvd found'
|
302
|
+
end
|
303
|
+
names = opticals.map{|d| d.Name + "\\" + " (" + (d.VolumeName || 'Insert DVD to use') + ")"}
|
304
|
+
if !force_choose_only_dvd_drive && !has_at_least_one_dvd_inserted
|
305
|
+
names += ['No DVD mounted so choose Local File (or insert DVD, re-try)'] # LODO cannot read it...
|
306
|
+
used_local_file_option = true
|
307
|
+
end
|
308
|
+
|
309
|
+
count = 0
|
310
|
+
opticals.each{|d| count += 1 if d.VolumeName}
|
311
|
+
if count == 1 && !used_local_file_option
|
312
|
+
# just choose it if there's only one disk available..
|
313
|
+
p 'selecting only disk present in the various DVD drives'
|
314
|
+
selected_idx = opticals.index{|d| d.VolumeName}
|
315
|
+
unless selected_idx
|
316
|
+
show_blocking_message_dialog "Please insert a disk first"
|
317
|
+
raise 'inset disk'
|
318
|
+
end
|
319
|
+
|
320
|
+
else
|
321
|
+
dialog = get_disk_chooser_window names
|
322
|
+
dialog.setSize 200, 125
|
323
|
+
dialog.show
|
324
|
+
selected_idx = dialog.selected_idx
|
325
|
+
end
|
326
|
+
|
327
|
+
if selected_idx
|
328
|
+
if used_local_file_option
|
329
|
+
raise unless selected_idx == 0 # it was our only option...
|
330
|
+
filename = new_existing_file_selector_and_select_file("Select yer previously grabbed from DVD file")
|
331
|
+
assert_ownership_dialog
|
332
|
+
return [filename, File.basename(filename), NonDvd]
|
333
|
+
else
|
334
|
+
disk = opticals[selected_idx]
|
335
|
+
out = show_non_blocking_message_dialog "calculating current disk's unique id...if this pauses more than 10s then clean your DVD..."
|
336
|
+
dvd_id = DriveInfo.md5sum_disk(disk.MountPoint)
|
337
|
+
out.dispose
|
338
|
+
@_choose_dvd_drive_or_file = [disk.MountPoint, opticals[selected_idx].VolumeName, dvd_id]
|
339
|
+
return @_choose_dvd_drive_or_file
|
340
|
+
end
|
341
|
+
else
|
342
|
+
raise 'did not select a drive...'
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|