OSDN Git Service

MacGui: Remove Target Size as a rate control option as it doesn't really work correct...
[handbrake-jp/handbrake-jp-git.git] / scripts / manicure.rb
1 #! /usr/bin/ruby
2 # manincure.rb version 0.66
3
4 # This file is part of the HandBrake source code.
5 # Homepage: <http://handbrake.m0k.org/>.
6 # It may be used under the terms of the GNU General Public License.
7
8 # This script parses HandBrake's Mac presets into hashes, which can
9 # be displayed in various formats for use by the CLI and its wrappers.
10
11 # For handling command line arguments to the script
12 require 'optparse'
13 require 'ostruct'
14 require 'rubygems'
15 require 'plist'
16
17 # CLI options: (code based on http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/index.html )
18 def readOptions
19   
20   # --[no-]cli-raw, -r gives raw CLI for wiki
21   # --cli-parse, -p gives CLI strings for wrappers
22   # --api, -a gives preset code for test.c
23   # --api-list, -A gives CLI strings for --preset-list display
24   # --[no-]header, -h turns off banner display
25   options = OpenStruct.new
26   options.cliraw = false
27   options.cliparse = false
28   options.api = false
29   options.apilist = false
30   options.header = false
31   
32   opts = OptionParser.new do |opts|
33     opts.banner = "Usage: manicure.rb [options]"
34     
35     opts.separator ""
36     opts.separator "Options:"
37     
38     opts.on("-r", "--cli-raw", "Gives example strings for the HB wiki") do |raw|
39       options.cliraw = raw
40       option_set = true
41     end
42     
43     opts.on("-p", "--cli-parse", "Gives presets as wrapper-parseable CLI", " option strings") do |par|
44       options.cliparse = par
45     end
46     
47     opts.on("-a", "--api", "Gives preset code for test.c") do |api|
48       options.api = api
49     end
50     
51     opts.on("-A", "--api-list", "Gives code for test.c's --preset-list", " options") do |alist|
52       options.apilist = alist
53     end
54     
55     opts.on("-H", "--Header", "Display a banner before each preset") do |head|
56       options.header = head
57     end
58     
59     opts.on_tail("-h", "--help", "Show this message") do
60         puts opts
61         exit
62     end
63   end.parse!
64   
65   return options
66   
67 end
68
69 # These arrays contain all the other presets and hashes that are going to be used.
70 # Yeah, they're global variables. In an object-oriented scripting language.
71 # Real smooth, huh?
72
73 # This class parses the user's presets .plist into an array of hashes
74 class Presets
75   
76   attr_reader :hashMasterList
77   
78   # Running initialization runs everything.
79   # Calling it will also call the parser
80   # and display output.
81   def initialize
82     
83    # Grab the user's home path
84    homeLocation = `echo $HOME`.chomp
85    
86    # Use that to build a path to the presets .plist
87    inputFile = homeLocation+'/Library/Application Support/HandBrake/UserPresets.plist'
88    
89     # Parse the presets into hashes
90     @hashMasterList = Plist::parse_xml( inputFile )
91     
92   end
93
94 end
95
96 # This class displays the presets to stdout in various formats.
97 class Display
98   
99   def initialize(hashMasterList, options)
100   
101     @hashMasterList = hashMasterList
102     @options = options
103
104     # A width of 40 gives nice, compact output.
105     @columnWidth=40
106     
107     # Print to screen.
108     displayCommandStrings
109     
110   end
111   
112   def displayCommandStrings # prints everything to screen
113     
114     # Iterate through the hashes.    
115     @hashMasterList.each do |hash|
116     
117       # Check to see whether we've got a preset or afolder
118       if !hash["Folder"]
119         # It's a top-level preset
120        displayIndividualPreset(hash, 0) 
121       else
122         # It's a folder, yay
123         displayFolder( hash, 0 )
124         hash["ChildrenArray"].each do |subhash|
125           # Drill down to see its contents
126           if !subhash["Folder"]
127             # It's a preset
128             displayIndividualPreset(subhash, 1)
129           else
130             # It's a folder
131             displayFolder( subhash, 1 )
132             subhash["ChildrenArray"].each do |subsubhash|
133               # At this point we're far enough down we won't try to drill further
134               if !subsubhash["Folder"]
135                 displayIndividualPreset(subsubhash, 2)
136               end
137             end
138             displayFolderCloser( 1 )
139           end
140         end
141         displayFolderCloser( 0 )
142       end
143     end
144   end
145   
146   def displayIndividualPreset(hash, depth)
147     if @options.header == true
148       # First throw up a header to make each preset distinct
149       displayHeader(hash)
150     end
151     
152     if @options.cliraw == true
153       # Show the preset's full CLI string equivalent
154       generateCLIString(hash, depth)
155     end
156     
157     if @options.cliparse == true
158       generateCLIParse(hash, depth)
159     end
160     
161     if @options.api == true
162       # Show the preset as code for test/test.c, HandBrakeCLI
163       generateAPIcalls(hash)
164     end
165     
166     if @options.apilist == true
167       # Show the preset as print statements, for CLI wrappers to parse.
168       generateAPIList(hash, depth) 
169     end
170   end
171   
172   def displayHeader(hash) # A distinct banner to separate each preset
173     
174     # Print a line of asterisks
175     puts "*" * @columnWidth
176     
177     # Print the name, centered
178     puts '* '+hash["PresetName"].to_s.center(@columnWidth-4)+' *'
179     
180     # Print a line of dashes
181     puts '~' * @columnWidth
182     
183     # Print the description, centered and word-wrapped
184     puts hash["PresetDescription"].to_s.center(@columnWidth).gsub(/\n/," ").scan(/\S.{0,#{@columnWidth-2}}\S(?=\s|$)|\S+/)
185     
186     # Print another line of dashes
187     puts '~' * @columnWidth
188     
189     # Print the formats the preset uses
190     puts "#{hash["FileCodecs"]}".center(@columnWidth)
191     
192     # Note if the preset isn't built-in
193     if hash["Type"] == 1
194       puts "Custom Preset".center(@columnWidth)
195     end
196
197     # Note if the preset is marked as default.
198     if hash["Default"] == 1
199       puts "This is your default preset.".center(@columnWidth)
200     end
201     
202     # End with a line of tildes.  
203     puts "~" * @columnWidth
204     
205   end
206   
207   def displayFolder( hash, depth )
208
209     if @options.cliraw == true
210       # Show the folder's full in a format that matches the CLI equivalents
211       generateCLIFolderString(hash, depth)
212     end
213     
214     if @options.cliparse == true
215       # Show the folder in a format that matches the CLI wrapper equivalents
216       generateCLIFolderParse(hash, depth)
217     end
218     
219     if @options.apilist == true
220       # Show the folder as print statements, for CLI wrappers to parse.
221       generateAPIFolderList(hash, depth) 
222     end
223     
224   end
225   
226   def displayFolderCloser( depth )
227     if @options.cliraw == true
228       # Show the folder's full in a format that matches the CLI equivalents
229       generateCLIFolderCloserString( depth )
230     end
231     
232     if @options.cliparse == true
233       # Show the folder in a format that matches the CLI wrapper equivalents
234       generateCLIFolderCloserParse( depth )
235     end
236     
237     if @options.apilist == true
238       # Show the folder as print statements, for CLI wrappers to parse.
239       generateAPIFolderCloserList( depth ) 
240     end
241   end
242   
243   def generateCLIFolderString( hash, depth ) # Shows the folder for the CLI equivalents
244     commandString = ""
245     depth.times do
246       commandString << "   "
247     end
248     (depth+1).times do
249       commandString << "<"
250     end
251     commandString << " " << hash["PresetName"] << "\n\n"
252     puts commandString
253   end
254   
255   def generateCLIFolderCloserString( depth )
256     commandString = ""
257     depth.times do
258       commandString << "   "
259     end
260     (depth+1).times do
261       commandString << ">"
262     end
263     commandString << "\n\n"
264     puts commandString
265   end
266   
267   def generateCLIString(hash, depth) # Makes a full CLI equivalent of a preset
268     commandString = ""
269     depth.times do
270       commandString << "   "
271     end
272     commandString << './HandBrakeCLI -i DVD -o ~/Movies/movie.'
273     
274     #Filename suffix
275     case hash["FileFormat"]
276     when /MP4/
277       commandString << "mp4 "
278     when /MKV/
279       commandString << "mkv "
280     end
281     
282     #Video encoder
283     if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)"
284       commandString << " -e "
285       case hash["VideoEncoder"]
286       when /x264/
287         commandString << "x264"
288       when /Theora/
289         commandString << "theora"
290       end
291     end
292
293     #VideoRateControl
294     case hash["VideoQualityType"]
295     when 0
296       commandString << " -S " << hash["VideoTargetSize"]
297     when 1
298       commandString << " -b " << hash["VideoAvgBitrate"]
299     when 2
300       commandString << " -q " << hash["VideoQualitySlider"].to_s
301     end
302
303     #FPS
304     if hash["VideoFramerate"] != "Same as source"
305       if hash["VideoFramerate"] == "23.976 (NTSC Film)"
306         commandString << " -r " << "23.976"
307       elsif hash["VideoFramerate"] == "29.97 (NTSC Video)"
308         commandString << " -r " << "29.97"
309       elsif hash["VideoFramerate"] == "25 (PAL Film/Video)"
310         commandString << " -r " << "25"
311       else
312         commandString << " -r " << hash["VideoFramerate"]
313       end
314       
315       if hash["VideoFrameratePFR"] == 1
316         commandString << " --pfr "
317       end
318     end
319     
320     #Audio tracks
321     audioBitrates = ""
322     audioEncoders = ""
323     audioMixdowns = ""
324     audioSamplerates = ""
325     audioTracks = ""
326     audioTrackDRCs = ""
327     audioCount = hash["AudioList"].size
328     
329     hash["AudioList"].each do |audioTrack|
330       audioCount = audioCount - 1
331
332       #Bitrates
333       audioBitrates << audioTrack["AudioBitrate"]
334       
335       #Encoders
336       case audioTrack["AudioEncoder"]
337         when /AC3 Pass/
338           audioEncoders << "copy:ac3"
339         when /AC3/
340           audioEncoders << "ac3"
341         when /AAC/
342           audioEncoders << "faac"
343         when /Vorbis/
344           audioEncoders << "vorbis"
345         when /MP3/
346           audioEncoders << "lame"
347       end
348       
349       #Mixdowns
350       case audioTrack["AudioMixdown"]
351       when /Mono/
352         audioMixdowns << "mono"
353       when /Stereo/
354         audioMixdowns << "stereo"
355       when /Dolby Surround/
356         audioMixdowns << "dpl1"
357       when /Dolby Pro Logic II/
358         audioMixdowns << "dpl2"
359       when /discrete/
360         audioMixdowns << "6ch"
361       when /Passthru/
362         audioMixdowns << "auto"
363       end
364       
365       #Samplerates
366       audioSamplerates << audioTrack["AudioSamplerate"]
367       
368       #Tracks
369       audioTracks << audioTrack["AudioTrack"].to_s
370       
371       #DRC
372       audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s
373       
374       if audioCount > 0
375         audioBitrates << ","
376         audioEncoders << ","
377         audioMixdowns << ","
378         audioSamplerates << ","
379         audioTracks << ","
380         audioTrackDRCs << ","
381       end
382       
383     end
384     commandString << " -a " << audioTracks
385     commandString << " -E " << audioEncoders
386     commandString << " -B " << audioBitrates
387     commandString << " -6 " << audioMixdowns
388     commandString << " -R " << audioSamplerates
389     commandString << " -D " << audioTrackDRCs
390         
391     #Container
392     commandString << " -f "
393     case hash["FileFormat"]
394     when /MP4/
395       commandString << "mp4"
396     when /MKV/
397       commandString << "mkv"
398     end
399     
400     #iPod MP4 atom
401     if hash["Mp4iPodCompatible"].to_i == 1
402       commandString << " -I"
403     end
404     
405     # 64-bit files
406     if hash["Mp4LargeFile"] == 1
407       commandString << " -4"
408     end
409     
410     #Cropping
411     if hash["PictureAutoCrop"] == 0
412       commandString << " --crop "
413       commandString << hash["PictureTopCrop"].to_s
414       commandString << ":"
415       commandString << hash["PictureBottomCrop"].to_s
416       commandString << ":"
417       commandString << hash["PictureLeftCrop"].to_s
418       commandString << ":"
419       commandString << hash["PictureRightCrop"].to_s
420     end
421     
422     #Dimensions
423     if hash["PictureWidth"] != 0
424       commandString << " -X "
425       commandString << hash["PictureWidth"].to_s
426     end
427     if hash["PictureHeight"] != 0
428       commandString << " -Y "
429       commandString << hash["PictureHeight"].to_s
430     end
431     
432     #Subtitles
433     if hash["Subtitles"] && hash["Subtitles"] != "None"
434       if hash["Subtitles"] == "Autoselect"
435         commandString << " --subtitle-scan"
436       else
437         commandString << " -s "
438         commandString << hash["Subtitles"]
439       end
440     end
441
442     #Video Filters
443     if hash["UsesPictureFilters"] == 1
444       
445       case hash["PictureDeinterlace"]
446       when 2
447         commandString << " --deinterlace=\"fast\""
448       when 3
449         commandString << " --deinterlace=\slow\""
450       when 4
451         commandString << " --deinterlace=\"slower\""
452       when 5
453         commandString << " --deinterlace=\"slowest\""
454       end
455       
456       case hash["PictureDenoise"]
457       when 2
458         commandString << " --denoise=\"weak\""
459       when 3
460         commandString << " --denoise=\"medium\""
461       when 4
462         commandString << " --denoise=\"strong\""
463       end
464       
465       if hash["PictureDetelecine"] == 2 then commandString << " --detelecine" end
466       if hash["PictureDeblock"] != 0 then commandString << " --deblock=" << hash["PictureDeblock"].to_s end
467       if hash["PictureDecomb"] == 2 then commandString << " --decomb" end
468       
469     end
470     
471     #Anamorphic
472     if hash["PicturePAR"] == 1
473       commandString << " --strict-anamorphic"
474     elsif hash["PicturePAR"] == 2
475       commandString << " --loose-anamorphic"
476     elsif hash["PicturePAR"] == 3
477       commandString << " --custom-anamorphic"
478     end
479
480     #Booleans
481     if hash["ChapterMarkers"] == 1 then commandString << " -m" end
482     if hash["VideoGrayScale"] == 1 then commandString << " -g" end
483     if hash["VideoTwoPass"] == 1 then commandString << " -2" end
484     if hash["VideoTurboTwoPass"] == 1 then commandString << " -T" end
485
486     #x264 Options
487     if hash["x264Option"] != ""
488       commandString << " -x "
489       commandString << hash["x264Option"]
490     end
491     
492     # That's it, print to screen now
493     puts commandString
494     
495     #puts "*" * @columnWidth
496
497     puts  "\n"
498   end
499   
500   def generateCLIFolderParse( hash, depth ) # Shows the folder for wrappers to parse
501     commandString = ""
502     depth.times do
503       commandString << "   "
504     end
505     (depth+1).times do
506       commandString << "<"
507     end
508     commandString << " " << hash["PresetName"] << "\n\n"
509     puts commandString
510   end
511   
512   def generateCLIFolderCloserParse( depth )
513     commandString = ""
514     depth.times do
515       commandString << "   "
516     end
517     (depth+1).times do
518       commandString << ">"
519     end
520     commandString << "\n\n"
521     puts commandString
522   end
523   
524   def generateCLIParse(hash, depth) # Makes a CLI equivalent of all user presets, for wrappers to parse
525     commandString = ""
526     depth.times do
527       commandString << "   "
528     end
529     commandString << '+ ' << hash["PresetName"] << ":"
530         
531     #Video encoder
532     if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)"
533       commandString << " -e "
534       case hash["VideoEncoder"]
535       when /x264/
536         commandString << "x264"
537       when /Theora/
538         commandString << "theora"
539       end
540     end
541
542     #VideoRateControl
543     case hash["VideoQualityType"]
544     when 0
545       commandString << " -S " << hash["VideoTargetSize"]
546     when 1
547       commandString << " -b " << hash["VideoAvgBitrate"]
548     when 2
549       commandString << " -q " << hash["VideoQualitySlider"].to_s
550     end
551
552     #FPS
553     if hash["VideoFramerate"] != "Same as source"
554       if hash["VideoFramerate"] == "23.976 (NTSC Film)"
555         commandString << " -r " << "23.976"
556       elsif hash["VideoFramerate"] == "29.97 (NTSC Video)"
557         commandString << " -r " << "29.97"
558       elsif hash["VideoFramerate"] == "25 (PAL Film/Video)"
559         commandString << " -r " << "25"
560       else
561         commandString << " -r " << hash["VideoFramerate"]
562       end
563       
564       if hash["VideoFrameratePFR"] == 1
565         commandString << " --pfr "
566       end
567     end
568     
569     #Audio tracks
570     audioBitrates = ""
571     audioEncoders = ""
572     audioMixdowns = ""
573     audioSamplerates = ""
574     audioTracks = ""
575     audioTrackDRCs = ""
576     audioCount = hash["AudioList"].size
577     
578     hash["AudioList"].each do |audioTrack|
579       audioCount = audioCount - 1
580
581       #Bitrates
582       audioBitrates << audioTrack["AudioBitrate"]
583       
584       #Encoders
585       case audioTrack["AudioEncoder"]
586         when /AC3 Pass/
587           audioEncoders << "copy:ac3"
588         when /AC3/
589           audioEncoders << "ac3"
590         when /AAC/
591           audioEncoders << "faac"
592         when /Vorbis/
593           audioEncoders << "vorbis"
594         when /MP3/
595           audioEncoders << "lame"
596       end
597       
598       #Mixdowns
599       case audioTrack["AudioMixdown"]
600       when /Mono/
601         audioMixdowns << "mono"
602       when /Stereo/
603         audioMixdowns << "stereo"
604       when /Dolby Surround/
605         audioMixdowns << "dpl1"
606       when /Dolby Pro Logic II/
607         audioMixdowns << "dpl2"
608       when /discrete/
609         audioMixdowns << "6ch"
610       when /Passthru/
611         audioMixdowns << "auto"
612       end
613       
614       #Samplerates
615       audioSamplerates << audioTrack["AudioSamplerate"]
616       
617       #Tracks
618       audioTracks << audioTrack["AudioTrack"].to_s
619       
620       #DRC
621       audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s
622       
623       if audioCount > 0
624         audioBitrates << ","
625         audioEncoders << ","
626         audioMixdowns << ","
627         audioSamplerates << ","
628         audioTracks << ","
629         audioTrackDRCs << ","
630       end
631       
632     end
633     commandString << " -a " << audioTracks
634     commandString << " -E " << audioEncoders
635     commandString << " -B " << audioBitrates
636     commandString << " -6 " << audioMixdowns
637     commandString << " -R " << audioSamplerates
638     commandString << " -D " << audioTrackDRCs
639     
640     #Container
641     commandString << " -f "
642     case hash["FileFormat"]
643     when /MP4/
644       commandString << "mp4"
645     when /MKV/
646       commandString << "mkv"
647     end
648     
649     #iPod MP4 atom
650     if hash["Mp4iPodCompatible"].to_i == 1
651       commandString << " -I"
652     end
653     
654     # 64-bit files
655     if hash["Mp4LargeFile"] == 1
656       commandString << " -4"
657     end
658     
659     #Cropping
660     if hash["PictureAutoCrop"] == 0
661       commandString << " --crop "
662       commandString << hash["PictureTopCrop"].to_s
663       commandString << ":"
664       commandString << hash["PictureBottomCrop"].to_s
665       commandString << ":"
666       commandString << hash["PictureLeftCrop"].to_s
667       commandString << ":"
668       commandString << hash["PictureRightCrop"].to_s
669     end
670     
671     #Dimensions
672     if hash["PictureWidth"] != 0
673       commandString << " -X "
674       commandString << hash["PictureWidth"].to_s
675     end
676     if hash["PictureHeight"] != 0
677       commandString << " -Y "
678       commandString << hash["PictureHeight"].to_s
679     end
680     
681     #Subtitles
682     if hash["Subtitles"] && hash["Subtitles"] != "None"
683       if hash["Subtitles"] == "Autoselect"
684         commandString << " --subtitle-scan"
685       else
686         commandString << " -s "
687         commandString << hash["Subtitles"]
688       end
689     end
690     
691     #Video Filters
692     if hash["UsesPictureFilters"] == 1
693       
694       case hash["PictureDeinterlace"]
695       when 2
696         commandString << " --deinterlace=\"fast\""
697       when 3
698         commandString << " --deinterlace=\slow\""
699       when 4
700         commandString << " --deinterlace=\"slower\""
701       when 5
702         commandString << " --deinterlace=\"slowest\""
703       end
704       
705       case hash["PictureDenoise"]
706       when 2
707         commandString << " --denoise=\"weak\""
708       when 3
709         commandString << " --denoise=\"medium\""
710       when 4
711         commandString << " --denoise=\"strong\""
712       end
713       
714       if hash["PictureDetelecine"] == 2 then commandString << " --detelecine" end
715       if hash["PictureDeblock"] != 0 then commandString << " --deblock=" << hash["PictureDeblock"].to_s end
716       if hash["PictureDecomb"] == 2 then commandString << " --decomb" end
717     end
718
719     #Anamorphic
720     if hash["PicturePAR"] == 1
721       commandString << " --strict-anamorphic"
722     elsif hash["PicturePAR"] == 2
723       commandString << " --loose-anamorphic"
724     elsif hash["PicturePAR"] == 3
725       commandString << " --custom-anamorphic"
726     end
727     
728     #Booleans
729     if hash["ChapterMarkers"] == 1 then commandString << " -m" end
730     if hash["VideoGrayScale"] == 1 then commandString << " -g" end
731     if hash["VideoTwoPass"] == 1 then commandString << " -2" end
732     if hash["VideoTurboTwoPass"] == 1 then commandString << " -T" end
733
734     #x264 Options
735     if hash["x264Option"] != ""
736       commandString << " -x "
737       commandString << hash["x264Option"]
738     end
739     
740     # That's it, print to screen now
741     puts commandString
742     
743     #puts "*" * @columnWidth
744
745     puts  "\n"
746   end
747
748   def generateAPIcalls(hash) # Makes a C version of the preset ready for coding into the CLI
749     
750     commandString = "if (!strcmp(preset_name, \"" << hash["PresetName"] << "\"))\n{\n    "
751     
752     #Filename suffix
753     commandString << "if( !mux )\n    "
754     commandString << "{\n    "
755
756     case hash["FileFormat"]
757     when /MP4/
758       commandString << "    mux = " << "HB_MUX_MP4;\n    "
759     when /MKV/
760       commandString << "    mux = " << "HB_MUX_MKV;\n    "
761     end
762     commandString << "}\n    "
763     
764     #iPod MP4 atom
765     if hash["Mp4iPodCompatible"].to_i == 1
766       commandString << "job->ipod_atom = 1;\n    "
767     end
768     
769     # 64-bit files
770     if hash["Mp4LargeFile"] == 1
771       commandString << "job->largeFileSize = 1;\n    "
772     end
773     
774     #Video encoder
775     if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)"
776       commandString << "vcodec = "
777       case hash["VideoEncoder"]
778       when /x264/
779         commandString << "HB_VCODEC_X264;\n    "
780       when /Theora/
781         commandString << "HB_VCODEC_THEORA;\n    "        
782       end
783     end
784
785     #VideoRateControl
786     case hash["VideoQualityType"]
787     when 0
788       commandString << "size = " << hash["VideoTargetSize"] << ";\n    "
789     when 1
790       commandString << "job->vbitrate = " << hash["VideoAvgBitrate"] << ";\n    "
791     when 2
792       commandString << "job->vquality = " << hash["VideoQualitySlider"].to_s << ";\n    "
793     end
794
795     #FPS
796     if hash["VideoFramerate"] != "Same as source"
797       if hash["VideoFramerate"] == "23.976 (NTSC Film)"
798         commandString << "job->vrate_base = " << "1126125;\n    "
799       elsif hash["VideoFramerate"] == "29.97 (NTSC Video)"
800         commandString << "job->vrate_base = " << "900900;\n    "
801       elsif hash["VideoFramerate"] == "25 (PAL Film/Video)"
802         commandString << "job->vrate_base = " << "1080000\n    "
803       # Gotta add the rest of the framerates for completion's sake.
804       end
805       
806       if hash["VideoFrameratePFR"] == 1
807         commandString << "job->cfr = 2;\n    "
808       else
809         commandString << "job->cfr = 1;\n    "
810       end
811     end
812     
813     #Audio tracks
814     audioBitrates = ""
815     audioEncoders = ""
816     audioMixdowns = ""
817     audioSamplerates = ""
818     audioTracks = ""
819     audioTrackDRCs = ""
820     audioCount = hash["AudioList"].size
821
822     hash["AudioList"].each do |audioTrack|
823       audioCount = audioCount - 1
824
825       #Bitrates
826       audioBitrates << audioTrack["AudioBitrate"]
827
828       #Encoders
829       case audioTrack["AudioEncoder"]
830         when /AC3 Pass/
831           audioEncoders << "copy:ac3"
832         when /AC3/
833           audioEncoders << "ac3"
834         when /AAC/
835           audioEncoders << "faac"
836         when /Vorbis/
837           audioEncoders << "vorbis"
838         when /MP3/
839           audioEncoders << "lame"
840       end
841
842       #Mixdowns
843       case audioTrack["AudioMixdown"]
844       when /Mono/
845         audioMixdowns << "mono"
846       when /Stereo/
847         audioMixdowns << "stereo"
848       when /Dolby Surround/
849         audioMixdowns << "dpl1"
850       when /Dolby Pro Logic II/
851         audioMixdowns << "dpl2"
852       when /discrete/
853         audioMixdowns << "6ch"
854       when /Passthru/
855         audioMixdowns << "auto"
856       end
857
858       #Samplerates
859       audioSamplerates << audioTrack["AudioSamplerate"]
860
861       #Tracks
862       audioTracks << audioTrack["AudioTrack"].to_s
863
864       #DRC
865       audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s
866
867       if audioCount > 0
868         audioBitrates << ","
869         audioEncoders << ","
870         audioMixdowns << ","
871         audioSamplerates << ","
872         audioTracks << ","
873         audioTrackDRCs << ","
874       end
875
876     end
877     commandString << "if( !atracks )\n    "
878     commandString << "{\n    "
879     commandString << "    atracks = strdup(\"" << audioTracks
880     commandString << "\");\n    "
881     commandString << "}\n    "
882
883     commandString << "if( !acodecs )\n    "
884     commandString << "{\n    "
885     commandString << "    acodecs = strdup(\"" << audioEncoders
886     commandString << "\");\n    "
887     commandString << "}\n    "
888
889     commandString << "if( !abitrates )\n    "
890     commandString << "{\n    "
891     commandString << "    abitrates = strdup(\"" << audioBitrates
892     commandString << "\");\n    "
893     commandString << "}\n    "
894
895     commandString << "if( !mixdowns )\n    "
896     commandString << "{\n    "
897     commandString << "    mixdowns = strdup(\"" << audioMixdowns
898     commandString << "\");\n    "
899     commandString << "}\n    "
900
901     commandString << "if( !arates )\n    "
902     commandString << "{\n    "
903     commandString << "    arates = strdup(\"" << audioSamplerates
904     commandString << "\");\n    "
905     commandString << "}\n    "
906
907     commandString << "if( !dynamic_range_compression )\n    "
908     commandString << "{\n    "
909     commandString << "    dynamic_range_compression = strdup(\"" << audioTrackDRCs
910     commandString << "\");\n    "
911     commandString << "}\n    "
912     
913     #Cropping
914     if hash["PictureAutoCrop"] == 0
915       commandString << "job->crop[0] = " << hash["PictureTopCrop"].to_s << ";\n    "
916       commandString << "job->crop[1] = " << hash["PictureBottomCrop"].to_s << ";\n    "
917       commandString << "job->crop[2] = " << hash["PictureLeftCrop"].to_s << ";\n    "
918       commandString << "job->crop[4] = " << hash["PictureRightCrop"].to_s << ";\n    "
919     end
920     
921     #Dimensions
922     if hash["PictureWidth"] != 0
923       commandString << "maxWidth = "
924       commandString << hash["PictureWidth"].to_s << ";\n    "
925     end
926     if hash["PictureHeight"] != 0
927       commandString << "maxHeight = "
928       commandString << hash["PictureHeight"].to_s << ";\n    "
929     end
930     
931     #Subtitles
932     if hash["Subtitles"] != "None"
933       if hash["Subtitles"] == "Autoselect"
934         commandString << "subtitle_scan = 1;\n    "
935       else
936         commandString << "job->subtitle = "
937         commandString << ( hash["Subtitles"].to_i - 1).to_s << ";\n    "
938       end
939     end
940     
941     #x264 Options
942     if hash["x264Option"] != ""
943       commandString << "if( !x264opts )\n    "
944       commandString << "{\n    "
945       commandString << "    x264opts = strdup(\""
946       commandString << hash["x264Option"] << "\");\n    "
947       commandString << "}\n    "
948     end
949     
950     #Video Filters
951     if hash["UsesPictureFilters"] == 1
952       
953       case hash["PictureDeinterlace"]
954       when 2
955         commandString << "deinterlace = 1;\n    "
956         commandString << "deinterlace_opt = \"-1\";\n    "
957       when 3
958         commandString << "deinterlace = 1;\n    "
959         commandString << "deinterlace_opt = \"2\";\n    "
960       when 4
961         commandString << "deinterlace = 1;\n    "
962         commandString << "deinterlace_opt = \"0\";\n    "
963       when 5
964         commandString << "deinterlace = 1;\n    "
965         commandString << "deinterlace_opt = \"1:-1:1\";\n    "
966       end
967       
968       case hash["PictureDenoise"]
969       when 2
970         commandString << "denoise = 1;\n    "
971         commandString << "denoise_opt = \"2:1:2:3\";\n    "
972       when 3
973         commandString << "denoise = 1;\n    "
974         commandString << "denoise_opt = \"3:2:2:3\";\n    "
975       when 4
976         commandString << "denoise = 1;\n    "
977         commandString << "denoise_opt = \"7:7:5:5\";\n    "
978       end
979       
980       if hash["PictureDetelecine"] == 2 then commandString << "detelecine = 1;\n    " end
981       if hash["PictureDeblock"] != 0
982         then
983           commandString << "deblock = 1;\n    "
984           commandString << "deblock_opt = \"" << hash["PictureDeblock"].to_s << "\";\n    "
985         end
986       if hash["PictureDecomb"] == 2 then commandString << "decomb = 1;\n    " end
987       
988     end
989     
990     #Anamorphic
991     if hash["PicturePAR"] != 0
992       commandString << "if( !anamorphic_mode )\n    "
993       commandString << "{\n    "
994       if hash["PicturePAR"] == 1
995         commandString << "    anamorphic_mode = 1;\n    "
996       elsif hash["PicturePAR"] == 2
997         commandString << "    anamorphic_mode = 2;\n    "
998       elsif hash["PicturePAR"] == 3
999         commandString << "    anamorphic_mode = 3;\n    "
1000       end
1001       commandString << "}\n    "
1002     end
1003     
1004     #Booleans
1005     if hash["ChapterMarkers"] == 1 then commandString << "job->chapter_markers = 1;\n    " end
1006     if hash["VideoGrayScale"] == 1 then commandString << "job->grayscale = 1;\n    " end
1007     if hash["VideoTwoPass"] == 1 then commandString << "twoPass = 1;\n    " end
1008     if hash["VideoTurboTwoPass"] == 1 then commandString << "turbo_opts_enabled = 1;\n" end
1009     commandString << "\n"
1010     commandString << "}"
1011     
1012     # That's it, print to screen now
1013     puts commandString
1014     #puts "*" * @columnWidth
1015     puts  "\n"
1016   end
1017   
1018   def generateAPIFolderList( hash, depth )
1019     commandString = ""
1020     
1021     commandString << "    printf(\"\\n"
1022     depth.times do
1023       commandString << "   "
1024     end
1025     (depth+1).times do
1026       commandString << "<"
1027     end
1028     commandString << " " << hash["PresetName"]
1029     commandString << "\\n\");\n\n"    
1030     puts commandString
1031   end
1032   
1033   def generateAPIFolderCloserList( depth )
1034     commandString = ""
1035     
1036     commandString << "    printf(\"\\n"
1037     depth.times do
1038       commandString << "   "
1039     end
1040     (depth+1).times do
1041       commandString << ">"
1042     end
1043     commandString << "\\n\");\n\n"    
1044     puts commandString
1045   end
1046   
1047   def generateAPIList(hash, depth) # Makes a list of the CLI options a built-in CLI preset uses, for wrappers to parse
1048     commandString = ""
1049     commandString << "    printf(\"\\n"
1050     depth.times do
1051       commandString << "   "
1052     end
1053            
1054     commandString << "+ " << hash["PresetName"] << ": "
1055         
1056     #Video encoder
1057     if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)"
1058       commandString << " -e "
1059       case hash["VideoEncoder"]
1060       when /x264/
1061         commandString << "x264 "
1062       when /Theora/
1063         commandString << "theora "
1064       end
1065     end
1066
1067     #VideoRateControl
1068     case hash["VideoQualityType"]
1069     when 0
1070       commandString << " -S " << hash["VideoTargetSize"]
1071     when 1
1072       commandString << " -b " << hash["VideoAvgBitrate"]
1073     when 2
1074       commandString << " -q " << hash["VideoQualitySlider"].to_s
1075     end
1076
1077     #FPS
1078     if hash["VideoFramerate"] != "Same as source"
1079       if hash["VideoFramerate"] == "23.976 (NTSC Film)"
1080         commandString << " -r " << "23.976"
1081       elsif hash["VideoFramerate"] == "29.97 (NTSC Video)"
1082         commandString << " -r " << "29.97"
1083       elsif hash["VideoFramerate"] == "25 (PAL Film/Video)"
1084         commandString << " -r " << "25"
1085       else
1086         commandString << " -r " << hash["VideoFramerate"]
1087       end
1088       
1089       if hash["VideoFrameratePFR"] == 1
1090         commandString << " --pfr "
1091       end
1092     end
1093     
1094     #Audio tracks
1095     audioBitrates = ""
1096     audioEncoders = ""
1097     audioMixdowns = ""
1098     audioSamplerates = ""
1099     audioTracks = ""
1100     audioTrackDRCs = ""
1101     audioCount = hash["AudioList"].size
1102     
1103     hash["AudioList"].each do |audioTrack|
1104       audioCount = audioCount - 1
1105
1106       #Bitrates
1107       audioBitrates << audioTrack["AudioBitrate"]
1108       
1109       #Encoders
1110       case audioTrack["AudioEncoder"]
1111         when /AC3 Pass/
1112           audioEncoders << "copy:ac3"
1113         when /AC3/
1114           audioEncoders << "ac3"
1115         when /AAC/
1116           audioEncoders << "faac"
1117         when /Vorbis/
1118           audioEncoders << "vorbis"
1119         when /MP3/
1120           audioEncoders << "lame"
1121       end
1122       
1123       #Mixdowns
1124       case audioTrack["AudioMixdown"]
1125       when /Mono/
1126         audioMixdowns << "mono"
1127       when /Stereo/
1128         audioMixdowns << "stereo"
1129       when /Dolby Surround/
1130         audioMixdowns << "dpl1"
1131       when /Dolby Pro Logic II/
1132         audioMixdowns << "dpl2"
1133       when /discrete/
1134         audioMixdowns << "6ch"
1135       when /Passthru/
1136         audioMixdowns << "auto"
1137       end
1138       
1139       #Samplerates
1140       audioSamplerates << audioTrack["AudioSamplerate"]
1141       
1142       #Tracks
1143       audioTracks << audioTrack["AudioTrack"].to_s
1144       
1145       #DRC
1146       audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s
1147       
1148       if audioCount > 0
1149         audioBitrates << ","
1150         audioEncoders << ","
1151         audioMixdowns << ","
1152         audioSamplerates << ","
1153         audioTracks << ","
1154         audioTrackDRCs << ","
1155       end
1156       
1157     end
1158     commandString << " -a " << audioTracks
1159     commandString << " -E " << audioEncoders
1160     commandString << " -B " << audioBitrates
1161     commandString << " -6 " << audioMixdowns
1162     commandString << " -R " << audioSamplerates
1163     commandString << " -D " << audioTrackDRCs
1164     
1165     #Container
1166     commandString << " -f "
1167     case hash["FileFormat"]
1168     when /MP4/
1169       commandString << "mp4"
1170     when /MKV/
1171       commandString << "mkv"
1172     end
1173     
1174     #iPod MP4 atom
1175     if hash["Mp4iPodCompatible"].to_i == 1
1176       commandString << " -I"
1177     end
1178     
1179     # 64-bit files
1180     if hash["Mp4LargeFile"] == 1
1181       commandString << " -4"
1182     end
1183     
1184     #Cropping
1185     if hash["PictureAutoCrop"] == 0
1186       commandString << " --crop "
1187       commandString << hash["PictureTopCrop"].to_s
1188       commandString << ":"
1189       commandString << hash["PictureBottomCrop"].to_s
1190       commandString << ":"
1191       commandString << hash["PictureLeftCrop"].to_s
1192       commandString << ":"
1193       commandString << hash["PictureRightCrop"].to_s
1194     end
1195     
1196     #Dimensions
1197     if hash["PictureWidth"] != 0
1198       commandString << " -X "
1199       commandString << hash["PictureWidth"].to_s
1200     end
1201     if hash["PictureHeight"] != 0
1202       commandString << " -Y "
1203       commandString << hash["PictureHeight"].to_s
1204     end
1205     
1206     #Subtitles
1207     if hash["Subtitles"] && hash["Subtitles"] != "None"
1208       if hash["Subtitles"] == "Autoselect"
1209         commandString << " --subtitle-scan"
1210       else
1211         commandString << " -s "
1212         commandString << hash["Subtitles"]
1213       end
1214     end
1215     
1216     #Video Filters
1217     if hash["UsesPictureFilters"] == 1
1218       
1219       case hash["PictureDeinterlace"]
1220       when 2
1221         commandString << " --deinterlace=\\\"fast\\\""
1222       when 3
1223         commandString << " --deinterlace=\\\slow\\\""
1224       when 4
1225         commandString << " --deinterlace=\\\"slower\\\""
1226       when 5
1227         commandString << " --deinterlace=\\\"slowest\\\""
1228       end
1229       
1230       case hash["PictureDenoise"]
1231       when 2
1232         commandString << " --denoise=\\\"weak\\\""
1233       when 3
1234         commandString << " --denoise=\\\"medium\\\""
1235       when 4
1236         commandString << " --denoise=\\\"strong\\\""
1237       end
1238       
1239       if hash["PictureDetelecine"] == 2 then commandString << " --detelecine" end
1240       if hash["PictureDeblock"] != 0 then commandString << " --deblock=" << hash["PictureDeblock"].to_s end
1241       if hash["PictureDecomb"] == 2 then commandString << " --decomb" end
1242     end
1243     
1244     #Anamorphic
1245     if hash["PicturePAR"] == 1
1246       commandString << " --strict-anamorphic"
1247     elsif hash["PicturePAR"] == 2
1248       commandString << " --loose-anamorphic"
1249     elsif hash["PicturePAR"] == 3
1250       commandString << " --custom-anamorphic"
1251     end
1252     
1253     #Booleans
1254     if hash["ChapterMarkers"] == 1 then commandString << " -m" end
1255     if hash["VideoGrayScale"] == 1 then commandString << " -g" end
1256     if hash["VideoTwoPass"] == 1 then commandString << " -2" end
1257     if hash["VideoTurboTwoPass"] == 1 then commandString << " -T" end
1258     
1259       #x264 Options
1260       if hash["x264Option"] != ""
1261         commandString << " -x "
1262         commandString << hash["x264Option"]
1263       end
1264     
1265     commandString << "\\n\");"
1266     
1267     # That's it, print to screen now
1268     puts commandString
1269     puts  "\n"
1270   end
1271   
1272 end
1273
1274 # First grab the specified CLI options
1275 options = readOptions
1276
1277 # Only run if one of the useful CLI flags have been passed
1278 if options.cliraw == true || options.cliparse == true || options.api == true || options.apilist == true
1279   # This line is the ignition -- generates hashes of
1280   # presets and then displays them to the screen
1281   # with the options the user selects on the CLI. 
1282   Display.new( Presets.new.hashMasterList, options )
1283 else
1284   # Direct the user to the help
1285   puts "\n\tUsage: manicure.rb [options]"
1286   puts "\tSee help with -h or --help"
1287 end