-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathautohb.rb
executable file
·933 lines (860 loc) · 31.9 KB
/
autohb.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
#!/usr/bin/env ruby
require 'bundler/setup'
require 'open3'
require 'optparse'
require 'duration'
require 'tmpdir'
require 'taglib'
require 'mattscilipoti-rdialog'
class AutoHB
def initialize
@options = {
:device => nil,
:directory => nil,
:output => Dir.home+"/Videos",
:subtitles => nil,
:default_subtitles => "eng",
:subtitles_forced => true,
:subtitles_burned => true,
:title => nil,
:default_title => nil,
:season => nil,
:default_season => nil,
:first_episode => nil,
:default_first_episode => "1",
:eject => true,
:preset => "Normal",
:min_duration => nil,
:extension => "mp4",
:no_flatpak => false
}
@curTitle = Title.new
@titles = Array.new
@disc_title = ''
@contentType = nil
@episode_groups = Array.new
@titles_to_rip = Array.new
@subtitle_to_rip = nil
@queue = Array.new
@dialog = RDialog.new
@zenity = false
if !ENV['DISPLAY'].nil? and File.exist? '/usr/bin/gdialog'
@dialog.path_to_dialog = '/usr/bin/gdialog'
@zenity = true
end
@dialog.backtitle = "Auto Handbrake"
@queuepath = Dir.tmpdir() + '/autohb-queue'
@append = false
self.parse_options
begin
hb = `HandBrakeCLI --version 2>/dev/null`
rescue
hb = ''
end
begin
flatpak = `flatpak run --command=HandBrakeCLI fr.handbrake.ghb --version 2>/dev/null`
rescue
flatpak = ''
end
if !@options[:no_flatpak] and !flatpak.empty?
@command = 'flatpak run --command=HandBrakeCLI fr.handbrake.ghb'
elsif !hb.empty?
@command = 'HandBrakeCLI'
else
@dialog.msgbox 'HandBrakeCLI could not be found. Please install it.'
exit
end
if @options[:device].nil? and @options[:directory].nil?
validsource = false
default = self.detect_device
while !validsource
question = 'Enter drive or directory:'
answer = @dialog.inputbox(question, 0, 0, "\"#{default}\"").strip
if File.blockdev?(answer)
@options[:device] = answer
validsource = true
elsif File.directory?(answer)
@options[:directory] = answer
validsource = true
else
default = answer
end
end
end
if @options[:directory].nil?
self.verify_device
else
self.verify_directory
@options[:eject] = false
end
end
def detect_device
device = Dir["/dev/dvd*"].pop
if device.nil?
device = Dir["/dev/cdrom*"].pop
end
return device
end
def verify_device
if @options[:device].nil?
@dialog.msgbox "No DVD drive was found, and none specified. Exiting."
exit
end
end
def verify_directory
if !Dir.exist? @options[:directory]
@dialog.msgbox "Specified directory was not found."
exit
end
files = Array.new
Dir.new(@options[:directory]).each do |filename|
path = @options[:directory] + '/' + filename
if File.file?(path) && File.readable?(path)
mime_type = `file --mime -b "#{path}"`.chomp
if mime_type.start_with? 'video/'
files.push filename
end
end
end
if files.empty?
@dialog.msgbox "No videos found in directory. Exiting."
end
@files = files
end
def parse_options
optparse = OptionParser.new do |opts|
opts.banner = "Usage: autohb [options]"
opts.on('-i', "--input DEVICE", "Input device (DVD or Blu-Ray drive) [Default: detect]") do |device|
@options[:device] = device
end
opts.on('-d', "--directory DIR", "Input directory containing videos to convert") do |directory|
@options[:directory] = directory
end
opts.on('-o', "--output DIR", "Base directory for output files [Default: ~/Videos]") do |output|
@options[:output] = output
end
opts.on('--file FILE', 'example input file') do |file|
@options[:file] = file
end
opts.on('-S', '--subtitles LANG', "Subtitle language (3 letter code, don\'t ask agaain)") do |lang|
@options[:subtitles] = lang
end
opts.on('-s', '--default-subtitles LANG', "Subtitle language (3 letter code) [default: eng]") do |lang|
@options[:default_subtitles] = lang
end
opts.on('-f', '--[no-]subtitles-forced', "Only include forced subtitles [default: true]") do |f|
@options[:subtitles_forced] = f
end
opts.on('-b', '--[no-]subtitles-burned', "Burn-in subtitles [default: true]") do |b|
@options[:subtitles_burned] = b
end
opts.on('-T', '--title TITLE', "Title for file naming (won't ask again)") do |title|
@options[:title] = title
end
opts.on('-t', '--default-title TITLE', "Default title for file naming [default: read from disc]") do |title|
@options[:default_title] = title
end
opts.on('-S', '--season NUMBER', "Season number for file naming (won't ask again)") do |season|
@options[:season] = season
end
opts.on('-s', '--default-season NUMBER', "Default season number for file naming [default: read from disc or ask]") do |season|
@options[:default_season] = season
end
opts.on('-E', '--episode NUMBER', "First episode number for file naming (won't ask again)") do |episode|
@options[:first_episode] = episode
end
opts.on('-e', '--default-episode EPISODE', "Default first episode number for file naming [default: 1]") do |episode|
@options[:default_episode] = episode
end
opts.on('--preset PRESET', "Handbrake preset to use (list with `HandBrakeCLI -z`), or custom preset exported from Handbrake GUI as a JSON file [default: Normal]") do |preset|
@options[:preset] = preset
end
opts.on('--[no-]eject', "Eject disc when done [default: true]") do |eject|
@options[:eject] = eject
end
opts.on('-m', '--min-duration [DURATION]', "Min duration") do |duration|
@options[:min_duration] = duration
end
opts.on('--extension EXTENSION', "File extension for output file [default: mp4]") do |extension|
@options[:extension] = extension
end
opts.on('--no-flatpak', "Dont use the Flatpak version of HandBrakeCLI, even if its installed.") do |no_flatpak|
@options[:no_flatpak] = true
end
end
optparse.parse!
end
def append_title
if @curTitle.number
@titles[@curTitle.number.to_i] = @curTitle
@curTitle = Title.new
end
end
def scan(input)
if @options[:file]
f = File.open @options[:file]
f.read
else
min_duration = ""
if @options[:min_duration]
min_duration = " --min-duration #{@options[:min_duration]}"
end
`#{@command} -i "#{input}"#{min_duration} -t 0 --scan 2>&1`
end
end
def parse_disc_title(line)
parts = line.split
rawtitle = parts.pop
titleparts = Array.new
if rawtitle.include? "SEASON"
titleparts = rawtitle.split "SEASON"
title = titleparts[0]
elsif rawtitle.include? "SERIES"
titleparts = rawtitle.split "SERIES"
title = titleparts[0]
else
title = rawtitle
end
if titleparts != Array.new
@disc_season = titleparts[1].match(/\d+/)[0]
end
@disc_title = title.split("_").map {|words| words.capitalize}.join(" ").strip
end
def parse_duration(duration)
parts = duration.to_s.split ':'
Duration.new :hours => parts[0].to_i, :minutes => parts[1].to_i, :seconds => parts[2].to_i
end
def parse_output(data)
isin = ParseFlags.new
data.each_line do |line|
if !line.include? '+'
if line.include? "DVD Title:"
self.parse_disc_title line
else
next
end
end
parts = line.strip.split
if line.start_with? "+"
self.append_title
@curTitle.number = line.match(/title (\d+):/)[1]
isin.meta = true;
elsif line.start_with? " +"
case parts[1]
when 'duration:'
@curTitle.duration = self.parse_duration parts[2]
when 'Main'
@curTitle.ismain = true
when 'angle(s)'
@curTitle.angles = parts[3].to_i
when 'chapters:'
isin.chapters = true
when 'audio'
isin.audios = true
when 'subtitle'
isin.subtitles = true
end
elsif line.start_with? " +"
if isin.chapters
number = parts[1].sub(':', '').to_i
duration = self.parse_duration parts[3]
chapter = Chapter.new number, duration
@curTitle.chapters[number] = chapter
elsif isin.audios
number = parts[1].sub(',', '').to_i
lang = parts[2]
mode = nil
description = nil
line.scan /\((.+?)\)/ do |m|
if m[0].end_with? 'ch'
mode = m[0]
elsif m[0] != 'AC3' and !m[0].start_with? 'iso'
description = m[0]
end
end
@curTitle.audios[number] = Audio.new number, lang, mode, description
elsif isin.subtitles
number = parts[1].sub(',', '').to_i
lang = parts[2]
@curTitle.subtitles[number] = Subtitle.new number, lang
end
end
end
self.append_title
end
def find_episode_groups
durations = Hash.new
@main = nil
mainduration = nil
cumulative = Duration.new
previous = nil
episode_threshold = 140
total_threshold = 20
@episode_groups = Array.new
group = nil
longest_title = nil
@titles.each do |title|
if !title.nil?
if title.ismain
@main = title.number
mainduration = title.duration
else
if title.duration > durations[longest_title]
longest_title = title.number
end
end
durations[title.number] = title.duration
end
end
if @main.nil?
@main = longest_title
mainduration = durations[@main]
end
durations = durations.sort {|a,b|
b[1] <=> a[1]
}
durations.each do |number,duration|
if duration != mainduration
if cumulative == Duration.new
cumulative = duration
group = Array[Hash[:number => number, :duration => duration]]
else
if !group.empty? and duration < group[0][:duration]-episode_threshold
self.push_group cumulative, mainduration, total_threshold, group
group = Array.new
cumulative = Duration.new
end
cumulative = cumulative+duration
group.push Hash[:number => number, :duration => duration]
end
end
end
self.push_group cumulative, mainduration, total_threshold, group
end
def push_group cumulative, maintime, total_threshold, group
begin
if cumulative >= maintime-total_threshold and cumulative <= maintime+total_threshold
@episode_groups.push group.sort {|a,b| a[:number] <=> b[:number]}
end
rescue NoMethodError
@dialog.msgbox "Could not find titles, probably due to an error reading the disc. Try cleaning the disc or check your optical drive. If the problem persists, you can debug further by running '#{@command} -i /dev/cdrom -t 0' and analysing the output."
exit
end
end
def confirm_episode_group group
message = "One Episode Group Found:\n"
message += self.get_group_listing group
message += "Rip these titles?"
@dialog.yesno message
end
def select_episode_group
message = "Multiple possible episode groups found.\n"
message += "Which group do you want to rip? (Cancel for none)\n"
groups = Array.new
@episode_groups.each_with_index do |group,index|
groups.push [index.to_s, self.get_group_listing(group)]
end
answer = @dialog.radiolist message, groups
if answer
return answer
else
return nil
end
end
def get_group_listing group
listing = ""
group.each do |episode|
listing += self.get_title_listing episode[:number], episode[:duration], ","
end
listing
end
def get_title_listing number, duration, separator = "\n"
ismain = ""
if number == @main
ismain = "(Main Feature)"
end
"Title #{number} [%02d:%02d:%02d] #{ismain}#{separator}" % [duration.hours, duration.minutes, duration.seconds]
end
def confirm_main_title
maintime = @titles[@main.to_i].duration
message = "Single main feature found:\n"
message += "Title #{@main} [#{maintime}]\n"
message += "Rip this feature?"
@dialog.yesno message
end
def rip_episode_group group
group.each do |episode|
@titles_to_rip.push episode[:number]
end
end
def rip_main_title
@titles_to_rip.push @main
end
def select_titles
message = "No titles selected. The following titles were found.\nSelect the titles you wish to rip."
numbers = Array.new
@titles.each do |title|
if !title.nil?
numbers.push [' '+title.number, self.get_title_listing(title.number, title.duration)]
end
end
begin
answer = @dialog.checklist message, numbers
if answer == false
exit
else
answer.each do |title| title.lstrip! end
@titles_to_rip = answer
end
rescue
exit
end
end
def add_subtitles?
message = "Add subtitles with default settings?\n"
lang = @options[:default_subtitles]
forced = @options[:subtitles_forced] ? "yes" : "no"
burned = @options[:subtitles_burned] ? "yes" : "no"
message += "(Language #{lang}, Forced Only: #{forced}, Burned in: #{burned}) \n"
if @dialog.yesno message
@subtitle_to_rip = "scan -N #{@options[:default_subtitles]}"
else
return false
end
end
def get_subtitle_track lang
if lang == "scan"
return lang
end
subtitles = @titles[@titles_to_rip.first].subtitles
subtitles.each do |subtitle|
if subtitle.lang == lang
return subtitle.number
end
end
end
def get_subtitles
title = @titles_to_rip.first ? @titles_to_rip.first.to_i : 1
subtitles = @titles[title].subtitles
message = "The following subtitle tracks were found,\n"
default = nil
numbers = Array.new
subtitles.each do |subtitle|
if subtitle.nil?
next
end
if default.nil? and subtitle.lang == @options[:default_subtitle]
default = subtitle.number
end
numbers.push [' ' + subtitle.number.to_s, subtitle.lang, default == subtitle.number]
end
message += "select the track you want to rip."
begin
answer = @dialog.radiolist message, numbers
return answer.strip.to_s
rescue
exit
end
end
def get_title
if @options[:default_title].nil?
if @options[:directory]
default = @options[:directory].split('/').pop
else
default = @disc_title
end
else
default = @options[:default_title]
end
message = "Enter the title for file and folder naming."
invalid = " Enter a valid filename (Letters, numbers, _ - or ., not starting with - or .)"
valid = nil
while valid != true do
question = message
if valid == false
question += invalid
end
answer = @dialog.inputbox(question, 0, 0, "\"#{default}\"")
validation = /^[A-Za-z_0-9][A-Za-z_0-9\-. ]*$/.match answer
if !validation.nil?
valid = true
answer = answer.strip()
else
valid = false
default = answer
end
end
return answer
end
def get_season
message = "Enter season number for episode naming (Leave blank for none)."
invalid = "\nPlease enter numbers only"
default = @options[:default_season]
if default.nil?
default = ''
end
valid = nil
while valid != true do
question = message
if valid == false
question += invalid
end
begin
answer = @dialog.inputbox(message, 0, 0, default)
validation = /^[0-9]*$/.match answer
if !validation.nil?
valid = true
answer = answer.to_i
else
valid = false
default = answer
end
rescue
answer = ''
end
end
return answer
end
def get_first_episode
message = "Enter first episode number for episode naming"
invalid = "\nPlease enter a number"
default = @options[:default_first_episode]
if default.nil?
default = ''
end
valid = nil
while valid != true do
question = message
if valid == false
question += invalid
end
begin
answer = @dialog.inputbox(message, 0, 0, default)
validation = /^[0-9]+$/.match answer
if !validation.nil?
valid = true
answer = answer.to_i
else
valid = false
default = answer
end
rescue
answer = ''
end
end
return answer
end
def check_existing_queue
if File.exists? @queuepath
question = 'Queue file exists. Append to this queue, or replace it with a new one?'
answers = [['Append'], ['Replace']]
answer = @dialog.radiolist question, answers, 10, 50
if answer == false
exit
end
if answer.strip == 'Append'
@append = true
end
end
end
def main
self.check_existing_queue
if @files == nil
data = self.scan @options[:device]
self.parse_output data
self.find_episode_groups
if @episode_groups.length > 0
if @episode_groups.length > 1
# Display groups and prompt for choice
group = @episode_groups[self.select_episode_group.to_i]
if group.nil?
if self.confirm_main_title
self.rip_main_title
end
else
self.rip_episode_group group
end
else
# Display group and confirm
group = @episode_groups.pop
if self.confirm_episode_group group
self.rip_episode_group group
end
end
else
# Display main title and confirm
if self.confirm_main_title
self.rip_main_title
end
end
if @titles_to_rip.length == 0
self.select_titles
end
if @titles_to_rip.length == 0
@dialog.msgbox "No titles selected, exiting\n"
exit
end
else
path = @options[:directory] + '/' + @files[0]
data = self.scan path
self.parse_output data
end
if @options[:subtitles].nil?
if !self.add_subtitles?
@subtitle_to_rip = self.get_subtitles
end
else
@subtitle_to_rip = self.get_subtitle_track @options[:subtitles]
end
if @options[:title].nil?
@options[:title] = self.get_title
end
multipletitles = (@titles_to_rip.length > 1 or @files.length > 1 or !@options[:first_episode].nil?)
if multipletitles and @options[:season].nil?
@options[:season] = self.get_season
end
if multipletitles and @options[:first_episode].nil?
@options[:first_episode] = self.get_first_episode
end
# Build commands to rip titles
subtitle = ""
if !@subtitle_to_rip.nil?
subtitle += "--subtitle #{@subtitle_to_rip}"
if @options[:subtitles_forced]
subtitle += " -F"
end
if @options[:subtitles_burned]
subtitle += " --subtitle-burn"
end
end
if @options[:preset].end_with? ".json"
preset = "--preset-import-file \"#{@options[:preset]}\" --preset=\"#{File.basename(@options[:preset], ".json")}\""
elsif
preset = "--preset=\"#{@options[:preset]}\""
end
folder_name = "#{@options[:output]}/#{@options[:title]}"
if !File.exists? folder_name
Dir.mkdir folder_name
end
episode = " "
if !@options[:season].nil?
episode += "S%02d" % @options[:season]
end
if !@options[:first_episode].nil?
episode_number = @options[:first_episode].to_i
episode += "E%02d"
end
if episode == " "
episode = ""
end
outputtemplate = "#{folder_name}/#{@options[:title]}#{episode}.#{@options[:extension]}"
if @options[:directory].nil?
@titles_to_rip.each do |title_number|
outputpath = outputtemplate % episode_number
if !episode_number.nil?
episode_number += 1
end
title = @titles[title_number.to_i]
command = "#{@command} -i #{@options[:device]} -o \"#{outputpath}\" #{preset} -t #{title_number} #{subtitle}"
@queue.push command
end
else
@files.each do |file|
outputpath = outputtemplate % episode_number
if !episode_number.nil?
episode_number += 1
end
inputpath = @options[:directory] + '/' + file
command = "#{@command} -i \"#{inputpath}\" -o \"#{outputpath}\" #{preset} -t 1 #{subtitle}"
@queue.push command
end
end
if @append
commandqueue = "Existing queue found.\n"
commandqueue += @queue.join("\n")
commandqueue += "\n\nAdd these commands to the queue?"
if @dialog.yesno commandqueue.gsub('"', '\"'), @queue.length + 8, 80
File.open(@queuepath, 'a') do |queuefile|
@queue.each do |command|
queuefile.write command, "\n"
end
end
else
@dialog.msgbox "Command not added to queue, exiting"
end
else
commandqueue = "Command Queue Created:\n"
commandqueue += @queue.join("\n")
commandqueue += "\n\nProcess this command queue?"
if @dialog.yesno commandqueue.gsub('"', '\"'), @queue.length + 8, 80
# Run Commands, yay!
# Write the commands to the queue.
File.open(@queuepath, 'w') do |queuefile|
@queue.each do |command|
queuefile.write command, "\n"
end
end
finished = false
while finished == false do
commands = []
command = ''
# Read the next command from the file.
File.open(@queuepath, 'r') do |queuefile|
commands = queuefile.readlines
command = commands.shift.strip
end
# Run the command.
Open3.popen3 command do |stdin, stdout, stderr, status_thread|
status = ''
percent = 0
filepath = command.match(/-o "([^"]+)"/).captures[0]
filename = Pathname.new(filepath).basename
# Set up a progress bar.
# rdialog's gague implementation doesn't let us update the percentage, and the gdialog/zenity wrapper
# misses some arguments, so we'll call zenity or dialog ourselves in this case.
title = "Processing #{filename} (Queue remaining: #{commands.length})"
if @zenity
gaugecommand = "zenity --title '#{title}' --progress --auto-close --auto-kill"
else
gaugecommand = "dialog --title '#{title}' --gauge 'Processing #{filename}' 10 100 0"
end
Open3.popen2 gaugecommand do |gaugein, gaugeout, gauge_thread|
if !@zenity
# Output progress in text mode.
outputthread = Thread.new do
gaugeout.each_char do |c|
print c
end
end
end
# Update the progress bar each time the percentage is output.
stdout.each_char do |char|
status += char
if char == '%'
statusparts = status.split(' ')
percent = statusparts[-2].to_i
messageparts = statusparts.slice(-7, 7)
currenttask = messageparts[2].to_i
totaltasks = messageparts[4].to_i
# Dont let the progress bar get killed if there's more tasks to process.
if percent == 100 and currenttask < totaltasks
percent = 99
end
message = messageparts.join(' ')
begin
if @zenity
gaugein.write "##{message}\n"
else
gaugein.write "XXX\n"
gaugein.write "#{message}\n"
gaugein.write "XXX\n"
end
gaugein.write "#{percent}\n"
rescue
next
end
status = ''
percent = 0
end
end
end
raise "Encode failed" unless status_thread.value.success?
end
# Make sure the title tag matches the name used for the file.
outputpath = /-o "(.+?)" /.match(command)[1]
fileref = TagLib::FileRef.new outputpath
fileref.tag.title = File.basename outputpath, ".#{@options[:extension]}"
fileref.save()
fileref.close()
# Re-read the file in case someone added to it while we were working,
# and remove the command we just processed.
File.open(@queuepath, 'r') do |queuefile|
commands = queuefile.readlines
commands.shift
end
if commands.length == 0
finished = true
else
File.open(@queuepath, 'w') do |queuefile|
queuefile.write commands.join
end
end
end
File.delete(@queuepath)
@dialog.msgbox "Queue complete!"
else
@dialog.msgbox "Queue not processed, exiting"
end
end
if @options[:eject]
system "eject #{@options[:device]}"
end
system "clear" or system "cls"
end
end
class Title
attr_accessor :number, :ismain, :duration, :size, :chapters, :audios, :subtitles, :angles
def initialize
@number = nil
@ismain = false
@duration = nil
@size = nil
@chapters = Array.new
@audios = Array.new
@subtitles = Array.new
@angles = 1
end
end
class Chapter
attr_accessor :number, :duration
def initialize(number, duration)
@number = number
@duration = duration
end
end
class Audio
attr_accessor :number, :lang, :description, :mode
def initialize(number, lang, mode, description='')
@number = number
@lang = lang
@mode = mode
@description = description
end
end
class Subtitle
attr_accessor :number, :lang
def initialize(number, lang)
@number = number
@lang = lang
end
end
class ParseFlags
attr_reader :meta, :chapters, :audios, :subtitles
def initialize
self.setfalse
end
def setfalse
@meta = false
@chapters = false
@audios = false
@subtitles = false
end
def meta=(val)
self.setfalse
@meta = val
end
def chapters=(val)
self.setfalse
@chapters = val
end
def audios=(val)
self.setfalse
@audios = val
end
def subtitles=(val)
self.setfalse
@subtitles = val
end
end
program = AutoHB.new()
program.main