OSDN Git Service

manicure: fix some output format issues in api generation
[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     end
315     
316     #Audio tracks
317     audioBitrates = ""
318     audioEncoders = ""
319     audioMixdowns = ""
320     audioSamplerates = ""
321     audioTracks = ""
322     audioTrackDRCs = ""
323     audioCount = hash["AudioList"].size
324     
325     hash["AudioList"].each do |audioTrack|
326       audioCount = audioCount - 1
327
328       #Bitrates
329       audioBitrates << audioTrack["AudioBitrate"]
330       
331       #Encoders
332       case audioTrack["AudioEncoder"]
333         when /AC3 /
334           audioEncoders << "ac3"
335         when /AAC/
336           audioEncoders << "faac"
337         when /Vorbis/
338           audioEncoders << "vorbis"
339         when /MP3/
340           audioEncoders << "lame"
341       end
342       
343       #Mixdowns
344       case audioTrack["AudioMixdown"]
345       when /Mono/
346         audioMixdowns << "mono"
347       when /Stereo/
348         audioMixdowns << "stereo"
349       when /Dolby Surround/
350         audioMixdowns << "dpl1"
351       when /Dolby Pro Logic II/
352         audioMixdowns << "dpl2"
353       when /discrete/
354         audioMixdowns << "6ch"
355       when /Passthru/
356         audioMixdowns << "auto"
357       end
358       
359       #Samplerates
360       audioSamplerates << audioTrack["AudioSamplerate"]
361       
362       #Tracks
363       audioTracks << audioTrack["AudioTrack"].to_s
364       
365       #DRC
366       audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s
367       
368       if audioCount > 0
369         audioBitrates << ","
370         audioEncoders << ","
371         audioMixdowns << ","
372         audioSamplerates << ","
373         audioTracks << ","
374         audioTrackDRCs << ","
375       end
376       
377     end
378     commandString << " -a " << audioTracks
379     commandString << " -E " << audioEncoders
380     commandString << " -B " << audioBitrates
381     commandString << " -6 " << audioMixdowns
382     commandString << " -R " << audioSamplerates
383     commandString << " -D " << audioTrackDRCs
384         
385     #Container
386     commandString << " -f "
387     case hash["FileFormat"]
388     when /MP4/
389       commandString << "mp4"
390     when /MKV/
391       commandString << "mkv"
392     end
393     
394     #iPod MP4 atom
395     if hash["Mp4iPodCompatible"].to_i == 1
396       commandString << " -I"
397     end
398     
399     # 64-bit files
400     if hash["Mp4LargeFile"] == 1
401       commandString << " -4"
402     end
403     
404     #Cropping
405     if hash["PictureAutoCrop"] == 0
406       commandString << " --crop "
407       commandString << hash["PictureTopCrop"].to_s
408       commandString << ":"
409       commandString << hash["PictureBottomCrop"].to_s
410       commandString << ":"
411       commandString << hash["PictureLeftCrop"].to_s
412       commandString << ":"
413       commandString << hash["PictureRightCrop"].to_s
414     end
415     
416     #Dimensions
417     if hash["PictureWidth"] != 0
418       commandString << " -X "
419       commandString << hash["PictureWidth"].to_s
420     end
421     if hash["PictureHeight"] != 0
422       commandString << " -Y "
423       commandString << hash["PictureHeight"].to_s
424     end
425     
426     #Subtitles
427     if hash["Subtitles"] && hash["Subtitles"] != "None"
428       if hash["Subtitles"] == "Autoselect"
429         commandString << " --subtitle-scan"
430       else
431         commandString << " -s "
432         commandString << hash["Subtitles"]
433       end
434     end
435
436     #Video Filters
437     if hash["UsesPictureFilters"] == 1
438       
439       case hash["PictureDeinterlace"]
440       when 2
441         commandString << " --deinterlace=\"fast\""
442       when 3
443         commandString << " --deinterlace=\slow\""
444       when 4
445         commandString << " --deinterlace=\"slower\""
446       when 5
447         commandString << " --deinterlace=\"slowest\""
448       end
449       
450       case hash["PictureDenoise"]
451       when 2
452         commandString << " --denoise=\"weak\""
453       when 3
454         commandString << " --denoise=\"medium\""
455       when 4
456         commandString << " --denoise=\"strong\""
457       end
458       
459       if hash["PictureDetelecine"] == 2 then commandString << " --detelecine" end
460       if hash["PictureDeblock"] != 0 then commandString << " --deblock=" << hash["PictureDeblock"].to_s end
461       if hash["PictureDecomb"] == 2 then commandString << " --decomb" end
462       
463     end
464     
465     #Anamorphic
466     if hash["PicturePAR"] == 1
467       commandString << " --strict-anamorphic"
468     elsif hash["PicturePAR"] == 2
469       commandString << " --loose-anamorphic"
470     elsif hash["PicturePAR"] == 3
471       commandString << " --custom-anamorphic"
472     end
473
474     #Booleans
475     if hash["ChapterMarkers"] == 1 then commandString << " -m" end
476     if hash["VideoGrayScale"] == 1 then commandString << " -g" end
477     if hash["VideoTwoPass"] == 1 then commandString << " -2" end
478     if hash["VideoTurboTwoPass"] == 1 then commandString << " -T" end
479
480     #x264 Options
481     if hash["x264Option"] != ""
482       commandString << " -x "
483       commandString << hash["x264Option"]
484     end
485     
486     # That's it, print to screen now
487     puts commandString
488     
489     #puts "*" * @columnWidth
490
491     puts  "\n"
492   end
493   
494   def generateCLIFolderParse( hash, depth ) # Shows the folder for wrappers to parse
495     commandString = ""
496     depth.times do
497       commandString << "   "
498     end
499     (depth+1).times do
500       commandString << "<"
501     end
502     commandString << " " << hash["PresetName"] << "\n\n"
503     puts commandString
504   end
505   
506   def generateCLIFolderCloserParse( depth )
507     commandString = ""
508     depth.times do
509       commandString << "   "
510     end
511     (depth+1).times do
512       commandString << ">"
513     end
514     commandString << "\n\n"
515     puts commandString
516   end
517   
518   def generateCLIParse(hash, depth) # Makes a CLI equivalent of all user presets, for wrappers to parse
519     commandString = ""
520     depth.times do
521       commandString << "   "
522     end
523     commandString << '+ ' << hash["PresetName"] << ":"
524         
525     #Video encoder
526     if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)"
527       commandString << " -e "
528       case hash["VideoEncoder"]
529       when /x264/
530         commandString << "x264"
531       when /Theora/
532         commandString << "theora"
533       end
534     end
535
536     #VideoRateControl
537     case hash["VideoQualityType"]
538     when 0
539       commandString << " -S " << hash["VideoTargetSize"]
540     when 1
541       commandString << " -b " << hash["VideoAvgBitrate"]
542     when 2
543       commandString << " -q " << hash["VideoQualitySlider"].to_s
544     end
545
546     #FPS
547     if hash["VideoFramerate"] != "Same as source"
548       if hash["VideoFramerate"] == "23.976 (NTSC Film)"
549         commandString << " -r " << "23.976"
550       elsif hash["VideoFramerate"] == "29.97 (NTSC Video)"
551         commandString << " -r " << "29.97"
552       elsif hash["VideoFramerate"] == "25 (PAL Film/Video)"
553         commandString << " -r " << "25"
554       else
555         commandString << " -r " << hash["VideoFramerate"]
556       end
557     end
558     
559     #Audio tracks
560     audioBitrates = ""
561     audioEncoders = ""
562     audioMixdowns = ""
563     audioSamplerates = ""
564     audioTracks = ""
565     audioTrackDRCs = ""
566     audioCount = hash["AudioList"].size
567     
568     hash["AudioList"].each do |audioTrack|
569       audioCount = audioCount - 1
570
571       #Bitrates
572       audioBitrates << audioTrack["AudioBitrate"]
573       
574       #Encoders
575       case audioTrack["AudioEncoder"]
576         when /AC3 /
577           audioEncoders << "ac3"
578         when /AAC/
579           audioEncoders << "faac"
580         when /Vorbis/
581           audioEncoders << "vorbis"
582         when /MP3/
583           audioEncoders << "lame"
584       end
585       
586       #Mixdowns
587       case audioTrack["AudioMixdown"]
588       when /Mono/
589         audioMixdowns << "mono"
590       when /Stereo/
591         audioMixdowns << "stereo"
592       when /Dolby Surround/
593         audioMixdowns << "dpl1"
594       when /Dolby Pro Logic II/
595         audioMixdowns << "dpl2"
596       when /discrete/
597         audioMixdowns << "6ch"
598       when /Passthru/
599         audioMixdowns << "auto"
600       end
601       
602       #Samplerates
603       audioSamplerates << audioTrack["AudioSamplerate"]
604       
605       #Tracks
606       audioTracks << audioTrack["AudioTrack"].to_s
607       
608       #DRC
609       audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s
610       
611       if audioCount > 0
612         audioBitrates << ","
613         audioEncoders << ","
614         audioMixdowns << ","
615         audioSamplerates << ","
616         audioTracks << ","
617         audioTrackDRCs << ","
618       end
619       
620     end
621     commandString << " -a " << audioTracks
622     commandString << " -E " << audioEncoders
623     commandString << " -B " << audioBitrates
624     commandString << " -6 " << audioMixdowns
625     commandString << " -R " << audioSamplerates
626     commandString << " -D " << audioTrackDRCs
627     
628     #Container
629     commandString << " -f "
630     case hash["FileFormat"]
631     when /MP4/
632       commandString << "mp4"
633     when /MKV/
634       commandString << "mkv"
635     end
636     
637     #iPod MP4 atom
638     if hash["Mp4iPodCompatible"].to_i == 1
639       commandString << " -I"
640     end
641     
642     # 64-bit files
643     if hash["Mp4LargeFile"] == 1
644       commandString << " -4"
645     end
646     
647     #Cropping
648     if hash["PictureAutoCrop"] == 0
649       commandString << " --crop "
650       commandString << hash["PictureTopCrop"].to_s
651       commandString << ":"
652       commandString << hash["PictureBottomCrop"].to_s
653       commandString << ":"
654       commandString << hash["PictureLeftCrop"].to_s
655       commandString << ":"
656       commandString << hash["PictureRightCrop"].to_s
657     end
658     
659     #Dimensions
660     if hash["PictureWidth"] != 0
661       commandString << " -X "
662       commandString << hash["PictureWidth"].to_s
663     end
664     if hash["PictureHeight"] != 0
665       commandString << " -Y "
666       commandString << hash["PictureHeight"].to_s
667     end
668     
669     #Subtitles
670     if hash["Subtitles"] && hash["Subtitles"] != "None"
671       if hash["Subtitles"] == "Autoselect"
672         commandString << " --subtitle-scan"
673       else
674         commandString << " -s "
675         commandString << hash["Subtitles"]
676       end
677     end
678     
679     #Video Filters
680     if hash["UsesPictureFilters"] == 1
681       
682       case hash["PictureDeinterlace"]
683       when 2
684         commandString << " --deinterlace=\"fast\""
685       when 3
686         commandString << " --deinterlace=\slow\""
687       when 4
688         commandString << " --deinterlace=\"slower\""
689       when 5
690         commandString << " --deinterlace=\"slowest\""
691       end
692       
693       case hash["PictureDenoise"]
694       when 2
695         commandString << " --denoise=\"weak\""
696       when 3
697         commandString << " --denoise=\"medium\""
698       when 4
699         commandString << " --denoise=\"strong\""
700       end
701       
702       if hash["PictureDetelecine"] == 2 then commandString << " --detelecine" end
703       if hash["PictureDeblock"] != 0 then commandString << " --deblock=" << hash["PictureDeblock"].to_s end
704       if hash["PictureDecomb"] == 2 then commandString << " --decomb" end
705     end
706
707     #Anamorphic
708     if hash["PicturePAR"] == 1
709       commandString << " --strict-anamorphic"
710     elsif hash["PicturePAR"] == 2
711       commandString << " --loose-anamorphic"
712     elsif hash["PicturePAR"] == 3
713       commandString << " --custom-anamorphic"
714     end
715     
716     #Booleans
717     if hash["ChapterMarkers"] == 1 then commandString << " -m" end
718     if hash["VideoGrayScale"] == 1 then commandString << " -g" end
719     if hash["VideoTwoPass"] == 1 then commandString << " -2" end
720     if hash["VideoTurboTwoPass"] == 1 then commandString << " -T" end
721
722     #x264 Options
723     if hash["x264Option"] != ""
724       commandString << " -x "
725       commandString << hash["x264Option"]
726     end
727     
728     # That's it, print to screen now
729     puts commandString
730     
731     #puts "*" * @columnWidth
732
733     puts  "\n"
734   end
735
736   def generateAPIcalls(hash) # Makes a C version of the preset ready for coding into the CLI
737     
738     commandString = "if (!strcmp(preset_name, \"" << hash["PresetName"] << "\"))\n{\n    "
739     
740     #Filename suffix
741     commandString << "if( !mux )\n    "
742     commandString << "{\n    "
743
744     case hash["FileFormat"]
745     when /MP4/
746       commandString << "    mux = " << "HB_MUX_MP4;\n    "
747     when /MKV/
748       commandString << "    mux = " << "HB_MUX_MKV;\n    "
749     end
750     commandString << "}\n    "
751     
752     #iPod MP4 atom
753     if hash["Mp4iPodCompatible"].to_i == 1
754       commandString << "job->ipod_atom = 1;\n    "
755     end
756     
757     # 64-bit files
758     if hash["Mp4LargeFile"] == 1
759       commandString << "job->largeFileSize = 1;\n    "
760     end
761     
762     #Video encoder
763     if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)"
764       commandString << "vcodec = "
765       case hash["VideoEncoder"]
766       when /x264/
767         commandString << "HB_VCODEC_X264;\n    "
768       when /Theora/
769         commandString << "HB_VCODEC_THEORA;\n    "        
770       end
771     end
772
773     #VideoRateControl
774     case hash["VideoQualityType"]
775     when 0
776       commandString << "size = " << hash["VideoTargetSize"] << ";\n    "
777     when 1
778       commandString << "job->vbitrate = " << hash["VideoAvgBitrate"] << ";\n    "
779     when 2
780       commandString << "job->vquality = " << hash["VideoQualitySlider"].to_s << ";\n    "
781     end
782
783     #FPS
784     if hash["VideoFramerate"] != "Same as source"
785       if hash["VideoFramerate"] == "23.976 (NTSC Film)"
786         commandString << "job->vrate_base = " << "1126125;\n    "
787       elsif hash["VideoFramerate"] == "29.97 (NTSC Video)"
788         commandString << "job->vrate_base = " << "900900;\n    "
789       elsif hash["VideoFramerate"] == "25 (PAL Film/Video)"
790         commandString << "job->vrate_base = " << "1080000\n    "
791       # Gotta add the rest of the framerates for completion's sake.
792       end
793       commandString << "job->cfr = 1;\n    "
794     end
795     
796     #Audio tracks
797     audioBitrates = ""
798     audioEncoders = ""
799     audioMixdowns = ""
800     audioSamplerates = ""
801     audioTracks = ""
802     audioTrackDRCs = ""
803     audioCount = hash["AudioList"].size
804
805     hash["AudioList"].each do |audioTrack|
806       audioCount = audioCount - 1
807
808       #Bitrates
809       audioBitrates << audioTrack["AudioBitrate"]
810
811       #Encoders
812       case audioTrack["AudioEncoder"]
813         when /AC3 /
814           audioEncoders << "ac3"
815         when /AAC/
816           audioEncoders << "faac"
817         when /Vorbis/
818           audioEncoders << "vorbis"
819         when /MP3/
820           audioEncoders << "lame"
821       end
822
823       #Mixdowns
824       case audioTrack["AudioMixdown"]
825       when /Mono/
826         audioMixdowns << "mono"
827       when /Stereo/
828         audioMixdowns << "stereo"
829       when /Dolby Surround/
830         audioMixdowns << "dpl1"
831       when /Dolby Pro Logic II/
832         audioMixdowns << "dpl2"
833       when /discrete/
834         audioMixdowns << "6ch"
835       when /Passthru/
836         audioMixdowns << "auto"
837       end
838
839       #Samplerates
840       audioSamplerates << audioTrack["AudioSamplerate"]
841
842       #Tracks
843       audioTracks << audioTrack["AudioTrack"].to_s
844
845       #DRC
846       audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s
847
848       if audioCount > 0
849         audioBitrates << ","
850         audioEncoders << ","
851         audioMixdowns << ","
852         audioSamplerates << ","
853         audioTracks << ","
854         audioTrackDRCs << ","
855       end
856
857     end
858     commandString << "if( !atracks )\n    "
859     commandString << "{\n    "
860     commandString << "    atracks = strdup(\"" << audioTracks
861     commandString << "\");\n    "
862     commandString << "}\n    "
863
864     commandString << "if( !acodecs )\n    "
865     commandString << "{\n    "
866     commandString << "    acodecs = strdup(\"" << audioEncoders
867     commandString << "\");\n    "
868     commandString << "}\n    "
869
870     commandString << "if( !abitrates )\n    "
871     commandString << "{\n    "
872     commandString << "    abitrates = strdup(\"" << audioBitrates
873     commandString << "\");\n    "
874     commandString << "}\n    "
875
876     commandString << "if( !mixdowns )\n    "
877     commandString << "{\n    "
878     commandString << "    mixdowns = strdup(\"" << audioMixdowns
879     commandString << "\");\n    "
880     commandString << "}\n    "
881
882     commandString << "if( !arates )\n    "
883     commandString << "{\n    "
884     commandString << "    arates = strdup(\"" << audioSamplerates
885     commandString << "\");\n    "
886     commandString << "}\n    "
887
888     commandString << "if( !dynamic_range_compression )\n    "
889     commandString << "{\n    "
890     commandString << "    dynamic_range_compression = strdup(\"" << audioTrackDRCs
891     commandString << "\");\n    "
892     commandString << "}\n    "
893     
894     #Cropping
895     if hash["PictureAutoCrop"] == 0
896       commandString << "job->crop[0] = " << hash["PictureTopCrop"].to_s << ";\n    "
897       commandString << "job->crop[1] = " << hash["PictureBottomCrop"].to_s << ";\n    "
898       commandString << "job->crop[2] = " << hash["PictureLeftCrop"].to_s << ";\n    "
899       commandString << "job->crop[4] = " << hash["PictureRightCrop"].to_s << ";\n    "
900     end
901     
902     #Dimensions
903     if hash["PictureWidth"] != 0
904       commandString << "maxWidth = "
905       commandString << hash["PictureWidth"].to_s << ";\n    "
906     end
907     if hash["PictureHeight"] != 0
908       commandString << "maxHeight = "
909       commandString << hash["PictureHeight"].to_s << ";\n    "
910     end
911     
912     #Subtitles
913     if hash["Subtitles"] != "None"
914       if hash["Subtitles"] == "Autoselect"
915         commandString << "subtitle_scan = 1;\n    "
916       else
917         commandString << "job->subtitle = "
918         commandString << ( hash["Subtitles"].to_i - 1).to_s << ";\n    "
919       end
920     end
921     
922     #x264 Options
923     if hash["x264Option"] != ""
924       commandString << "if( !x264opts )\n    "
925       commandString << "{\n    "
926       commandString << "    x264opts = strdup(\""
927       commandString << hash["x264Option"] << "\");\n    "
928       commandString << "}\n    "
929     end
930     
931     #Video Filters
932     if hash["UsesPictureFilters"] == 1
933       
934       case hash["PictureDeinterlace"]
935       when 2
936         commandString << "deinterlace = 1;\n    "
937         commandString << "deinterlace_opt = \"-1\";\n    "
938       when 3
939         commandString << "deinterlace = 1;\n    "
940         commandString << "deinterlace_opt = \"2\";\n    "
941       when 4
942         commandString << "deinterlace = 1;\n    "
943         commandString << "deinterlace_opt = \"0\";\n    "
944       when 5
945         commandString << "deinterlace = 1;\n    "
946         commandString << "deinterlace_opt = \"1:-1:1\";\n    "
947       end
948       
949       case hash["PictureDenoise"]
950       when 2
951         commandString << "denoise = 1;\n    "
952         commandString << "denoise_opt = \"2:1:2:3\";\n    "
953       when 3
954         commandString << "denoise = 1;\n    "
955         commandString << "denoise_opt = \"3:2:2:3\";\n    "
956       when 4
957         commandString << "denoise = 1;\n    "
958         commandString << "denoise_opt = \"7:7:5:5\";\n    "
959       end
960       
961       if hash["PictureDetelecine"] == 2 then commandString << "detelecine = 1;\n    " end
962       if hash["PictureDeblock"] != 0
963         then
964           commandString << "deblock = 1;\n    "
965           commandString << "deblock_opt = \"" << hash["PictureDeblock"].to_s << "\";\n    "
966         end
967       if hash["PictureDecomb"] == 2 then commandString << "decomb = 1;\n    " end
968       
969     end
970     
971     #Anamorphic
972     if hash["PicturePAR"] == 1
973       commandString << "anamorphic_mode = 1;\n    "
974     elsif hash["PicturePAR"] == 2
975       commandString << "anamorphic_mode = 2;\n    "
976     elsif hash["PicturePAR"] == 3
977       commandString << "anamorphic_mode = 3;\n    "
978     end
979     
980     #Booleans
981     if hash["ChapterMarkers"] == 1 then commandString << "job->chapter_markers = 1;\n    " end
982     if hash["VideoGrayScale"] == 1 then commandString << "job->grayscale = 1;\n    " end
983     if hash["VideoTwoPass"] == 1 then commandString << "twoPass = 1;\n    " end
984     if hash["VideoTurboTwoPass"] == 1 then commandString << "turbo_opts_enabled = 1;\n" end
985     commandString << "\n"
986     commandString << "}"
987     
988     # That's it, print to screen now
989     puts commandString
990     #puts "*" * @columnWidth
991     puts  "\n"
992   end
993   
994   def generateAPIFolderList( hash, depth )
995     commandString = ""
996     
997     commandString << "    printf(\"\\n"
998     depth.times do
999       commandString << "   "
1000     end
1001     (depth+1).times do
1002       commandString << "<"
1003     end
1004     commandString << " " << hash["PresetName"]
1005     commandString << "\\n\");\n\n"    
1006     puts commandString
1007   end
1008   
1009   def generateAPIFolderCloserList( depth )
1010     commandString = ""
1011     
1012     commandString << "    printf(\"\\n"
1013     depth.times do
1014       commandString << "   "
1015     end
1016     (depth+1).times do
1017       commandString << ">"
1018     end
1019     commandString << "\\n\");\n\n"    
1020     puts commandString
1021   end
1022   
1023   def generateAPIList(hash, depth) # Makes a list of the CLI options a built-in CLI preset uses, for wrappers to parse
1024     commandString = ""
1025     commandString << "    printf(\"\\n"
1026     depth.times do
1027       commandString << "   "
1028     end
1029            
1030     commandString << "+ " << hash["PresetName"] << ": "
1031         
1032     #Video encoder
1033     if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)"
1034       commandString << " -e "
1035       case hash["VideoEncoder"]
1036       when /x264/
1037         commandString << "x264 "
1038       when /Theora/
1039         commandString << "theora "
1040       end
1041     end
1042
1043     #VideoRateControl
1044     case hash["VideoQualityType"]
1045     when 0
1046       commandString << " -S " << hash["VideoTargetSize"]
1047     when 1
1048       commandString << " -b " << hash["VideoAvgBitrate"]
1049     when 2
1050       commandString << " -q " << hash["VideoQualitySlider"].to_s
1051     end
1052
1053     #FPS
1054     if hash["VideoFramerate"] != "Same as source"
1055       if hash["VideoFramerate"] == "23.976 (NTSC Film)"
1056         commandString << " -r " << "23.976"
1057       elsif hash["VideoFramerate"] == "29.97 (NTSC Video)"
1058         commandString << " -r " << "29.97"
1059       elsif hash["VideoFramerate"] == "25 (PAL Film/Video)"
1060         commandString << " -r " << "25"
1061       else
1062         commandString << " -r " << hash["VideoFramerate"]
1063       end
1064     end
1065     
1066     #Audio tracks
1067     audioBitrates = ""
1068     audioEncoders = ""
1069     audioMixdowns = ""
1070     audioSamplerates = ""
1071     audioTracks = ""
1072     audioTrackDRCs = ""
1073     audioCount = hash["AudioList"].size
1074     
1075     hash["AudioList"].each do |audioTrack|
1076       audioCount = audioCount - 1
1077
1078       #Bitrates
1079       audioBitrates << audioTrack["AudioBitrate"]
1080       
1081       #Encoders
1082       case audioTrack["AudioEncoder"]
1083         when /AC3 /
1084           audioEncoders << "ac3"
1085         when /AAC/
1086           audioEncoders << "faac"
1087         when /Vorbis/
1088           audioEncoders << "vorbis"
1089         when /MP3/
1090           audioEncoders << "lame"
1091       end
1092       
1093       #Mixdowns
1094       case audioTrack["AudioMixdown"]
1095       when /Mono/
1096         audioMixdowns << "mono"
1097       when /Stereo/
1098         audioMixdowns << "stereo"
1099       when /Dolby Surround/
1100         audioMixdowns << "dpl1"
1101       when /Dolby Pro Logic II/
1102         audioMixdowns << "dpl2"
1103       when /discrete/
1104         audioMixdowns << "6ch"
1105       when /Passthru/
1106         audioMixdowns << "auto"
1107       end
1108       
1109       #Samplerates
1110       audioSamplerates << audioTrack["AudioSamplerate"]
1111       
1112       #Tracks
1113       audioTracks << audioTrack["AudioTrack"].to_s
1114       
1115       #DRC
1116       audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s
1117       
1118       if audioCount > 0
1119         audioBitrates << ","
1120         audioEncoders << ","
1121         audioMixdowns << ","
1122         audioSamplerates << ","
1123         audioTracks << ","
1124         audioTrackDRCs << ","
1125       end
1126       
1127     end
1128     commandString << " -a " << audioTracks
1129     commandString << " -E " << audioEncoders
1130     commandString << " -B " << audioBitrates
1131     commandString << " -6 " << audioMixdowns
1132     commandString << " -R " << audioSamplerates
1133     commandString << " -D " << audioTrackDRCs
1134     
1135     #Container
1136     commandString << " -f "
1137     case hash["FileFormat"]
1138     when /MP4/
1139       commandString << "mp4"
1140     when /MKV/
1141       commandString << "mkv"
1142     end
1143     
1144     #iPod MP4 atom
1145     if hash["Mp4iPodCompatible"].to_i == 1
1146       commandString << " -I"
1147     end
1148     
1149     # 64-bit files
1150     if hash["Mp4LargeFile"] == 1
1151       commandString << " -4"
1152     end
1153     
1154     #Cropping
1155     if hash["PictureAutoCrop"] == 0
1156       commandString << " --crop "
1157       commandString << hash["PictureTopCrop"].to_s
1158       commandString << ":"
1159       commandString << hash["PictureBottomCrop"].to_s
1160       commandString << ":"
1161       commandString << hash["PictureLeftCrop"].to_s
1162       commandString << ":"
1163       commandString << hash["PictureRightCrop"].to_s
1164     end
1165     
1166     #Dimensions
1167     if hash["PictureWidth"] != 0
1168       commandString << " -X "
1169       commandString << hash["PictureWidth"].to_s
1170     end
1171     if hash["PictureHeight"] != 0
1172       commandString << " -Y "
1173       commandString << hash["PictureHeight"].to_s
1174     end
1175     
1176     #Subtitles
1177     if hash["Subtitles"] && hash["Subtitles"] != "None"
1178       if hash["Subtitles"] == "Autoselect"
1179         commandString << " --subtitle-scan"
1180       else
1181         commandString << " -s "
1182         commandString << hash["Subtitles"]
1183       end
1184     end
1185     
1186     #Video Filters
1187     if hash["UsesPictureFilters"] == 1
1188       
1189       case hash["PictureDeinterlace"]
1190       when 2
1191         commandString << " --deinterlace=\\\"fast\\\""
1192       when 3
1193         commandString << " --deinterlace=\\\slow\\\""
1194       when 4
1195         commandString << " --deinterlace=\\\"slower\\\""
1196       when 5
1197         commandString << " --deinterlace=\\\"slowest\\\""
1198       end
1199       
1200       case hash["PictureDenoise"]
1201       when 2
1202         commandString << " --denoise=\\\"weak\\\""
1203       when 3
1204         commandString << " --denoise=\\\"medium\\\""
1205       when 4
1206         commandString << " --denoise=\\\"strong\\\""
1207       end
1208       
1209       if hash["PictureDetelecine"] == 2 then commandString << " --detelecine" end
1210       if hash["PictureDeblock"] != 0 then commandString << " --deblock=" << hash["PictureDeblock"].to_s end
1211       if hash["PictureDecomb"] == 2 then commandString << " --decomb" end
1212     end
1213     
1214     #Anamorphic
1215     if hash["PicturePAR"] == 1
1216       commandString << " --strict-anamorphic"
1217     elsif hash["PicturePAR"] == 2
1218       commandString << " --loose-anamorphic"
1219     elsif hash["PicturePAR"] == 3
1220       commandString << " --custom-anamorphic"
1221     end
1222     
1223     #Booleans
1224     if hash["ChapterMarkers"] == 1 then commandString << " -m" end
1225     if hash["VideoGrayScale"] == 1 then commandString << " -g" end
1226     if hash["VideoTwoPass"] == 1 then commandString << " -2" end
1227     if hash["VideoTurboTwoPass"] == 1 then commandString << " -T" end
1228     
1229       #x264 Options
1230       if hash["x264Option"] != ""
1231         commandString << " -x "
1232         commandString << hash["x264Option"]
1233       end
1234     
1235     commandString << "\\n\");"
1236     
1237     # That's it, print to screen now
1238     puts commandString
1239     puts  "\n"
1240   end
1241   
1242 end
1243
1244 # First grab the specified CLI options
1245 options = readOptions
1246
1247 # Only run if one of the useful CLI flags have been passed
1248 if options.cliraw == true || options.cliparse == true || options.api == true || options.apilist == true
1249   # This line is the ignition -- generates hashes of
1250   # presets and then displays them to the screen
1251   # with the options the user selects on the CLI. 
1252   Display.new( Presets.new.hashMasterList, options )
1253 else
1254   # Direct the user to the help
1255   puts "\n\tUsage: manicure.rb [options]"
1256   puts "\tSee help with -h or --help"
1257 end