#! /usr/bin/ruby # manincure.rb version 0.66 # This file is part of the HandBrake source code. # Homepage: . # It may be used under the terms of the GNU General Public License. # This script parses HandBrake's Mac presets into hashes, which can # be displayed in various formats for use by the CLI and its wrappers. # For handling command line arguments to the script require 'optparse' require 'ostruct' require 'rubygems' require 'plist' # CLI options: (code based on http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/index.html ) def readOptions # --[no-]cli-raw, -r gives raw CLI for wiki # --cli-parse, -p gives CLI strings for wrappers # --api, -a gives preset code for test.c # --api-list, -A gives CLI strings for --preset-list display # --[no-]header, -h turns off banner display options = OpenStruct.new options.cliraw = false options.cliparse = false options.api = false options.apilist = false options.header = false opts = OptionParser.new do |opts| opts.banner = "Usage: manicure.rb [options]" opts.separator "" opts.separator "Options:" opts.on("-r", "--cli-raw", "Gives example strings for the HB wiki") do |raw| options.cliraw = raw option_set = true end opts.on("-p", "--cli-parse", "Gives presets as wrapper-parseable CLI", " option strings") do |par| options.cliparse = par end opts.on("-a", "--api", "Gives preset code for test.c") do |api| options.api = api end opts.on("-A", "--api-list", "Gives code for test.c's --preset-list", " options") do |alist| options.apilist = alist end opts.on("-H", "--Header", "Display a banner before each preset") do |head| options.header = head end opts.on_tail("-h", "--help", "Show this message") do puts opts exit end end.parse! return options end # These arrays contain all the other presets and hashes that are going to be used. # Yeah, they're global variables. In an object-oriented scripting language. # Real smooth, huh? # This class parses the user's presets .plist into an array of hashes class Presets attr_reader :hashMasterList # Running initialization runs everything. # Calling it will also call the parser # and display output. def initialize # Grab the user's home path homeLocation = `echo $HOME`.chomp # Use that to build a path to the presets .plist inputFile = homeLocation+'/Library/Application Support/HandBrake/UserPresets.plist' # Parse the presets into hashes @hashMasterList = Plist::parse_xml( inputFile ) end end # This class displays the presets to stdout in various formats. class Display def initialize(hashMasterList, options) @hashMasterList = hashMasterList @options = options # A width of 40 gives nice, compact output. @columnWidth=40 # Print to screen. displayCommandStrings end def displayCommandStrings # prints everything to screen # Iterate through the hashes. @hashMasterList.each do |hash| # Check to see whether we've got a preset or afolder if !hash["Folder"] # It's a top-level preset displayIndividualPreset(hash, 0) else # It's a folder, yay displayFolder( hash, 0 ) hash["ChildrenArray"].each do |subhash| # Drill down to see its contents if !subhash["Folder"] # It's a preset displayIndividualPreset(subhash, 1) else # It's a folder displayFolder( subhash, 1 ) subhash["ChildrenArray"].each do |subsubhash| # At this point we're far enough down we won't try to drill further if !subsubhash["Folder"] displayIndividualPreset(subsubhash, 2) end end displayFolderCloser( 1 ) end end displayFolderCloser( 0 ) end end end def displayIndividualPreset(hash, depth) if @options.header == true # First throw up a header to make each preset distinct displayHeader(hash) end if @options.cliraw == true # Show the preset's full CLI string equivalent generateCLIString(hash, depth) end if @options.cliparse == true generateCLIParse(hash, depth) end if @options.api == true # Show the preset as code for test/test.c, HandBrakeCLI generateAPIcalls(hash) end if @options.apilist == true # Show the preset as print statements, for CLI wrappers to parse. generateAPIList(hash, depth) end end def displayHeader(hash) # A distinct banner to separate each preset # Print a line of asterisks puts "*" * @columnWidth # Print the name, centered puts '* '+hash["PresetName"].to_s.center(@columnWidth-4)+' *' # Print a line of dashes puts '~' * @columnWidth # Print the description, centered and word-wrapped puts hash["PresetDescription"].to_s.center(@columnWidth).gsub(/\n/," ").scan(/\S.{0,#{@columnWidth-2}}\S(?=\s|$)|\S+/) # Print another line of dashes puts '~' * @columnWidth # Print the formats the preset uses puts "#{hash["FileCodecs"]}".center(@columnWidth) # Note if the preset isn't built-in if hash["Type"] == 1 puts "Custom Preset".center(@columnWidth) end # Note if the preset is marked as default. if hash["Default"] == 1 puts "This is your default preset.".center(@columnWidth) end # End with a line of tildes. puts "~" * @columnWidth end def displayFolder( hash, depth ) if @options.cliraw == true # Show the folder's full in a format that matches the CLI equivalents generateCLIFolderString(hash, depth) end if @options.cliparse == true # Show the folder in a format that matches the CLI wrapper equivalents generateCLIFolderParse(hash, depth) end if @options.apilist == true # Show the folder as print statements, for CLI wrappers to parse. generateAPIFolderList(hash, depth) end end def displayFolderCloser( depth ) if @options.cliraw == true # Show the folder's full in a format that matches the CLI equivalents generateCLIFolderCloserString( depth ) end if @options.cliparse == true # Show the folder in a format that matches the CLI wrapper equivalents generateCLIFolderCloserParse( depth ) end if @options.apilist == true # Show the folder as print statements, for CLI wrappers to parse. generateAPIFolderCloserList( depth ) end end def generateCLIFolderString( hash, depth ) # Shows the folder for the CLI equivalents commandString = "" depth.times do commandString << " " end (depth+1).times do commandString << "<" end commandString << " " << hash["PresetName"] << "\n\n" puts commandString end def generateCLIFolderCloserString( depth ) commandString = "" depth.times do commandString << " " end (depth+1).times do commandString << ">" end commandString << "\n\n" puts commandString end def generateCLIString(hash, depth) # Makes a full CLI equivalent of a preset commandString = "" depth.times do commandString << " " end commandString << './HandBrakeCLI -i DVD -o ~/Movies/movie.' #Filename suffix case hash["FileFormat"] when /MP4/ commandString << "mp4 " when /MKV/ commandString << "mkv " end #Video encoder if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" commandString << " -e " case hash["VideoEncoder"] when /x264/ commandString << "x264" when /Theora/ commandString << "theora" when /MPEG/ commandString << "ffmpeg2" end end #VideoRateControl case hash["VideoQualityType"] when 0 commandString << " -S " << hash["VideoTargetSize"] when 1 commandString << " -b " << hash["VideoAvgBitrate"] when 2 commandString << " -q " << hash["VideoQualitySlider"].to_s end #FPS if hash["VideoFramerate"] != "Same as source" if hash["VideoFramerate"] == "23.976 (NTSC Film)" commandString << " -r " << "23.976" elsif hash["VideoFramerate"] == "29.97 (NTSC Video)" commandString << " -r " << "29.97" elsif hash["VideoFramerate"] == "25 (PAL Film/Video)" commandString << " -r " << "25" else commandString << " -r " << hash["VideoFramerate"] end # not same as source: pfr, else default (cfr) if hash["VideoFramerateMode"] == "pfr" commandString << " --pfr " end # same as source: cfr, else default (vfr) elsif hash["VideoFramerateMode"] == "cfr" commandString << " --cfr " end #Audio tracks audioBitrates = "" audioEncoders = "" audioMixdowns = "" audioSamplerates = "" audioTracks = "" audioTrackDRCs = "" audioCount = hash["AudioList"].size hash["AudioList"].each do |audioTrack| audioCount = audioCount - 1 #Bitrates audioBitrates << audioTrack["AudioBitrate"] #Encoders case audioTrack["AudioEncoder"] when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ audioEncoders << "ffac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" when "AAC (ffmpeg)" audioEncoders << "ffaac" when /AAC/ audioEncoders << "faac" when /Vorbis/ audioEncoders << "vorbis" when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ audioEncoders << "lame" when /FLAC/ audioEncoders << "ffflac" when /Auto Pass/ audioEncoders << "copy" end #Mixdowns case audioTrack["AudioMixdown"] when /Mono/ audioMixdowns << "mono" when /Stereo/ audioMixdowns << "stereo" when /Dolby Surround/ audioMixdowns << "dpl1" when /Dolby Pro Logic II/ audioMixdowns << "dpl2" when /discrete/ audioMixdowns << "6ch" when /None/ audioMixdowns << "auto" end #Samplerates audioSamplerates << audioTrack["AudioSamplerate"] #Tracks audioTracks << audioTrack["AudioTrack"].to_s #DRC audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s if audioCount > 0 audioBitrates << "," audioEncoders << "," audioMixdowns << "," audioSamplerates << "," audioTracks << "," audioTrackDRCs << "," end end commandString << " -a " << audioTracks commandString << " -E " << audioEncoders commandString << " -B " << audioBitrates commandString << " -6 " << audioMixdowns commandString << " -R " << audioSamplerates commandString << " -D " << audioTrackDRCs #Auto Passthru Mask audioCopyMask = "" if hash["AudioAllowAACPass"].to_i == 1 audioCopyMask << "aac" end if hash["AudioAllowAC3Pass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "ac3" end if hash["AudioAllowDTSHDPass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "dtshd" end if hash["AudioAllowDTSPass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "dts" end if hash["AudioAllowMP3Pass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "mp3" end if audioCopyMask.size > 0 commandString << " --audio-copy-mask " << audioCopyMask end #Auto Passthru Fallback audioEncoderFallback = "" case hash["AudioEncoderFallback"] when /AC3/ audioEncoderFallback << "ffac3" when "AAC (ffmpeg)" audioEncoderFallback << "ffaac" when /AAC/ audioEncoderFallback << "faac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ audioEncoderFallback << "lame" when /FLAC/ audioEncoderFallback << "ffflac" end if audioEncoderFallback.size > 0 commandString << " --audio-fallback " << audioEncoderFallback end #Container commandString << " -f " case hash["FileFormat"] when /MP4/ commandString << "mp4" when /MKV/ commandString << "mkv" end #iPod MP4 atom if hash["Mp4iPodCompatible"].to_i == 1 commandString << " -I" end # 64-bit files if hash["Mp4LargeFile"] == 1 commandString << " -4" end #MP4 Optimize for HTTP Streaming if hash["Mp4HttpOptimize"].to_i == 1 commandString << " -O" end #Cropping if hash["PictureAutoCrop"] == 0 commandString << " --crop " commandString << hash["PictureTopCrop"].to_s commandString << ":" commandString << hash["PictureBottomCrop"].to_s commandString << ":" commandString << hash["PictureLeftCrop"].to_s commandString << ":" commandString << hash["PictureRightCrop"].to_s end #Dimensions if hash["PictureWidth"] != 0 commandString << " -X " commandString << hash["PictureWidth"].to_s end if hash["PictureHeight"] != 0 commandString << " -Y " commandString << hash["PictureHeight"].to_s end #Subtitles if hash["Subtitles"] && hash["Subtitles"] != "None" if hash["Subtitles"] == "Autoselect" commandString << " --subtitle-scan" else commandString << " -s " commandString << hash["Subtitles"] end end #Video Filters if hash["UsesPictureFilters"] == 1 case hash["PictureDeinterlace"] when 1 commandString << " --deinterlace=" << hash["PictureDeinterlaceCustom"].to_s when 2 commandString << " --deinterlace=fast" when 3 commandString << " --deinterlace=slow" when 4 commandString << " --deinterlace=slower" when 5 commandString << " --deinterlace=bob" end case hash["PictureDenoise"] when 1 commandString << " --denoise=" << hash["PictureDenoiseCustom"].to_s when 2 commandString << " --denoise=weak" when 3 commandString << " --denoise=medium" when 4 commandString << " --denoise=strong" end case hash["PictureDecomb"] when 1 commandString << " --decomb=" << hash["PictureDecombCustom"].to_s when 2 commandString << " --decomb" when 3 commandString << " --decomb=fast" when 4 commandString << " --decomb=bob" end case hash["PictureDetelecine"] when 1 commandString << " --detelecine=" << hash["PictureDetelecineCustom"].to_s when 2 commandString << " --detelecine" end if hash["PictureDeblock"] != 0 commandString << " --deblock=" << hash["PictureDeblock"].to_s end end #Anamorphic if hash["PicturePAR"] == 1 commandString << " --strict-anamorphic" elsif hash["PicturePAR"] == 2 commandString << " --loose-anamorphic" elsif hash["PicturePAR"] == 3 commandString << " --custom-anamorphic" end #Modulus if hash["PictureModulus"] commandString << " --modulus " << hash["PictureModulus"].to_s end #Booleans if hash["ChapterMarkers"] == 1 then commandString << " -m" end if hash["VideoGrayScale"] == 1 then commandString << " -g" end if hash["VideoTwoPass"] == 1 then commandString << " -2" end if hash["VideoTurboTwoPass"] == 1 then commandString << " -T" end #Advanced Options if hash["x264Option"] != "" commandString << " -x " commandString << hash["x264Option"] end # That's it, print to screen now puts commandString #puts "*" * @columnWidth puts "\n" end def generateCLIFolderParse( hash, depth ) # Shows the folder for wrappers to parse commandString = "" depth.times do commandString << " " end (depth+1).times do commandString << "<" end commandString << " " << hash["PresetName"] << "\n\n" puts commandString end def generateCLIFolderCloserParse( depth ) commandString = "" depth.times do commandString << " " end (depth+1).times do commandString << ">" end commandString << "\n\n" puts commandString end def generateCLIParse(hash, depth) # Makes a CLI equivalent of all user presets, for wrappers to parse commandString = "" depth.times do commandString << " " end commandString << '+ ' << hash["PresetName"] << ":" #Video encoder if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" commandString << " -e " case hash["VideoEncoder"] when /x264/ commandString << "x264" when /Theora/ commandString << "theora" when /MPEG/ commandString << "ffmpeg2" end end #VideoRateControl case hash["VideoQualityType"] when 0 commandString << " -S " << hash["VideoTargetSize"] when 1 commandString << " -b " << hash["VideoAvgBitrate"] when 2 commandString << " -q " << hash["VideoQualitySlider"].to_s end #FPS if hash["VideoFramerate"] != "Same as source" if hash["VideoFramerate"] == "23.976 (NTSC Film)" commandString << " -r " << "23.976" elsif hash["VideoFramerate"] == "29.97 (NTSC Video)" commandString << " -r " << "29.97" elsif hash["VideoFramerate"] == "25 (PAL Film/Video)" commandString << " -r " << "25" else commandString << " -r " << hash["VideoFramerate"] end # not same as source: pfr, else default (cfr) if hash["VideoFramerateMode"] == "pfr" commandString << " --pfr " end # same as source: cfr, else default (vfr) elsif hash["VideoFramerateMode"] == "cfr" commandString << " --cfr " end #Audio tracks audioBitrates = "" audioEncoders = "" audioMixdowns = "" audioSamplerates = "" audioTracks = "" audioTrackDRCs = "" audioCount = hash["AudioList"].size hash["AudioList"].each do |audioTrack| audioCount = audioCount - 1 #Bitrates audioBitrates << audioTrack["AudioBitrate"] #Encoders case audioTrack["AudioEncoder"] when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ audioEncoders << "ffac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" when "AAC (ffmpeg)" audioEncoders << "ffaac" when /AAC/ audioEncoders << "faac" when /Vorbis/ audioEncoders << "vorbis" when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ audioEncoders << "lame" when /FLAC/ audioEncoders << "ffflac" when /Auto Pass/ audioEncoders << "copy" end #Mixdowns case audioTrack["AudioMixdown"] when /Mono/ audioMixdowns << "mono" when /Stereo/ audioMixdowns << "stereo" when /Dolby Surround/ audioMixdowns << "dpl1" when /Dolby Pro Logic II/ audioMixdowns << "dpl2" when /discrete/ audioMixdowns << "6ch" when /None/ audioMixdowns << "auto" end #Samplerates audioSamplerates << audioTrack["AudioSamplerate"] #Tracks audioTracks << audioTrack["AudioTrack"].to_s #DRC audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s if audioCount > 0 audioBitrates << "," audioEncoders << "," audioMixdowns << "," audioSamplerates << "," audioTracks << "," audioTrackDRCs << "," end end commandString << " -a " << audioTracks commandString << " -E " << audioEncoders commandString << " -B " << audioBitrates commandString << " -6 " << audioMixdowns commandString << " -R " << audioSamplerates commandString << " -D " << audioTrackDRCs #Auto Passthru Mask audioCopyMask = "" if hash["AudioAllowAACPass"].to_i == 1 audioCopyMask << "aac" end if hash["AudioAllowAC3Pass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "ac3" end if hash["AudioAllowDTSHDPass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "dtshd" end if hash["AudioAllowDTSPass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "dts" end if hash["AudioAllowMP3Pass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "mp3" end if audioCopyMask.size > 0 commandString << " --audio-copy-mask " << audioCopyMask end #Auto Passthru Fallback audioEncoderFallback = "" case hash["AudioEncoderFallback"] when /AC3/ audioEncoderFallback << "ffac3" when "AAC (ffmpeg)" audioEncoderFallback << "ffaac" when /AAC/ audioEncoderFallback << "faac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ audioEncoderFallback << "lame" when /FLAC/ audioEncoderFallback << "ffflac" end if audioEncoderFallback.size > 0 commandString << " --audio-fallback " << audioEncoderFallback end #Container commandString << " -f " case hash["FileFormat"] when /MP4/ commandString << "mp4" when /MKV/ commandString << "mkv" end #iPod MP4 atom if hash["Mp4iPodCompatible"].to_i == 1 commandString << " -I" end # 64-bit files if hash["Mp4LargeFile"] == 1 commandString << " -4" end #MP4 Optimize for HTTP Streaming if hash["Mp4HttpOptimize"].to_i == 1 commandString << " -O" end #Cropping if hash["PictureAutoCrop"] == 0 commandString << " --crop " commandString << hash["PictureTopCrop"].to_s commandString << ":" commandString << hash["PictureBottomCrop"].to_s commandString << ":" commandString << hash["PictureLeftCrop"].to_s commandString << ":" commandString << hash["PictureRightCrop"].to_s end #Dimensions if hash["PictureWidth"] != 0 commandString << " -X " commandString << hash["PictureWidth"].to_s end if hash["PictureHeight"] != 0 commandString << " -Y " commandString << hash["PictureHeight"].to_s end #Subtitles if hash["Subtitles"] && hash["Subtitles"] != "None" if hash["Subtitles"] == "Autoselect" commandString << " --subtitle-scan" else commandString << " -s " commandString << hash["Subtitles"] end end #Video Filters if hash["UsesPictureFilters"] == 1 case hash["PictureDeinterlace"] when 1 commandString << " --deinterlace=" << hash["PictureDeinterlaceCustom"].to_s when 2 commandString << " --deinterlace=fast" when 3 commandString << " --deinterlace=slow" when 4 commandString << " --deinterlace=slower" when 5 commandString << " --deinterlace=bob" end case hash["PictureDenoise"] when 1 commandString << " --denoise=" << hash["PictureDenoiseCustom"].to_s when 2 commandString << " --denoise=weak" when 3 commandString << " --denoise=medium" when 4 commandString << " --denoise=strong" end case hash["PictureDecomb"] when 1 commandString << " --decomb=" << hash["PictureDecombCustom"].to_s when 2 commandString << " --decomb" when 3 commandString << " --decomb=fast" when 4 commandString << " --decomb=bob" end case hash["PictureDetelecine"] when 1 commandString << " --detelecine=" << hash["PictureDetelecineCustom"].to_s when 2 commandString << " --detelecine" end if hash["PictureDeblock"] != 0 commandString << " --deblock=" << hash["PictureDeblock"].to_s end end #Anamorphic if hash["PicturePAR"] == 1 commandString << " --strict-anamorphic" elsif hash["PicturePAR"] == 2 commandString << " --loose-anamorphic" elsif hash["PicturePAR"] == 3 commandString << " --custom-anamorphic" end #Modulus if hash["PictureModulus"] commandString << " --modulus " << hash["PictureModulus"].to_s end #Booleans if hash["ChapterMarkers"] == 1 then commandString << " -m" end if hash["VideoGrayScale"] == 1 then commandString << " -g" end if hash["VideoTwoPass"] == 1 then commandString << " -2" end if hash["VideoTurboTwoPass"] == 1 then commandString << " -T" end #Advanced Options if hash["x264Option"] != "" commandString << " -x " commandString << hash["x264Option"] end # That's it, print to screen now puts commandString #puts "*" * @columnWidth puts "\n" end def generateAPIcalls(hash) # Makes a C version of the preset ready for coding into the CLI commandString = "if (!strcmp(preset_name, \"" << hash["PresetName"] << "\"))\n{\n " #Filename suffix commandString << "if( !mux )\n " commandString << "{\n " case hash["FileFormat"] when /MP4/ commandString << " mux = " << "HB_MUX_MP4;\n " when /MKV/ commandString << " mux = " << "HB_MUX_MKV;\n " end commandString << "}\n " #iPod MP4 atom if hash["Mp4iPodCompatible"].to_i == 1 commandString << "job->ipod_atom = 1;\n " end # 64-bit files if hash["Mp4LargeFile"] == 1 commandString << "job->largeFileSize = 1;\n " end #MP4 Optimize for HTTP Streaming if hash["Mp4HttpOptimize"].to_i == 1 commandString << "job->mp4_optimize = 1;\n " end #Video encoder if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" commandString << "vcodec = " case hash["VideoEncoder"] when /x264/ commandString << "HB_VCODEC_X264;\n " when /Theora/ commandString << "HB_VCODEC_THEORA;\n " when /MPEG/ commandString << "HB_VCODEC_FFMPEG_MPEG2;\n " end end #VideoRateControl case hash["VideoQualityType"] when 0 commandString << "size = " << hash["VideoTargetSize"] << ";\n " when 1 commandString << "job->vbitrate = " << hash["VideoAvgBitrate"] << ";\n " when 2 commandString << "job->vquality = " << hash["VideoQualitySlider"].to_s << ";\n " end #FPS if hash["VideoFramerate"] != "Same as source" if hash["VideoFramerate"] == "23.976 (NTSC Film)" commandString << "job->vrate_base = " << "1126125;\n " elsif hash["VideoFramerate"] == "29.97 (NTSC Video)" commandString << "job->vrate_base = " << "900900;\n " elsif hash["VideoFramerate"] == "25 (PAL Film/Video)" commandString << "job->vrate_base = " << "1080000;\n " else commandString << "job->vrate_base = " << (27000000 / hash["VideoFramerate"].to_i).to_s << ";\n " end # not same as source: pfr, else default (cfr) if hash["VideoFramerateMode"] == "pfr" commandString << "job->cfr = 2;\n " else commandString << "job->cfr = 1;\n " end # same as source: cfr, else default (vfr) elsif hash["VideoFramerateMode"] == "cfr" commandString << "job->cfr = 1;\n " end #Audio tracks audioBitrates = "" audioEncoders = "" audioMixdowns = "" audioSamplerates = "" audioTracks = "" audioTrackDRCs = "" audioCount = hash["AudioList"].size hash["AudioList"].each do |audioTrack| audioCount = audioCount - 1 #Bitrates audioBitrates << audioTrack["AudioBitrate"] #Encoders case audioTrack["AudioEncoder"] when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ audioEncoders << "ffac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" when "AAC (ffmpeg)" audioEncoders << "ffaac" when /AAC/ audioEncoders << "faac" when /Vorbis/ audioEncoders << "vorbis" when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ audioEncoders << "lame" when /FLAC/ audioEncoders << "ffflac" when /Auto Pass/ audioEncoders << "copy" end #Mixdowns case audioTrack["AudioMixdown"] when /Mono/ audioMixdowns << "mono" when /Stereo/ audioMixdowns << "stereo" when /Dolby Surround/ audioMixdowns << "dpl1" when /Dolby Pro Logic II/ audioMixdowns << "dpl2" when /discrete/ audioMixdowns << "6ch" when /None/ audioMixdowns << "auto" end #Samplerates audioSamplerates << audioTrack["AudioSamplerate"] #Tracks audioTracks << audioTrack["AudioTrack"].to_s #DRC audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s if audioCount > 0 audioBitrates << "," audioEncoders << "," audioMixdowns << "," audioSamplerates << "," audioTracks << "," audioTrackDRCs << "," end end commandString << "if( !atracks )\n " commandString << "{\n " commandString << " atracks = strdup(\"" << audioTracks commandString << "\");\n " commandString << "}\n " commandString << "if( !acodecs )\n " commandString << "{\n " commandString << " acodecs = strdup(\"" << audioEncoders commandString << "\");\n " commandString << "}\n " commandString << "if( !abitrates )\n " commandString << "{\n " commandString << " abitrates = str_split(\"" << audioBitrates commandString << "\", ',');\n " commandString << "}\n " commandString << "if( !mixdowns )\n " commandString << "{\n " commandString << " mixdowns = strdup(\"" << audioMixdowns commandString << "\");\n " commandString << "}\n " commandString << "if( !arates )\n " commandString << "{\n " commandString << " arates = strdup(\"" << audioSamplerates commandString << "\");\n " commandString << "}\n " commandString << "if( !dynamic_range_compression )\n " commandString << "{\n " commandString << " dynamic_range_compression = strdup(\"" << audioTrackDRCs commandString << "\");\n " commandString << "}\n " #Auto Passthru Mask if hash["AudioAllowAACPass"] commandString << "if( allowed_audio_copy == -1 )\n " commandString << "{\n " commandString << " allowed_audio_copy = 0;\n " if hash["AudioAllowAACPass"].to_i == 1 commandString << " allowed_audio_copy |= HB_ACODEC_AAC_PASS;\n " end if hash["AudioAllowAC3Pass"].to_i == 1 commandString << " allowed_audio_copy |= HB_ACODEC_AC3_PASS;\n " end if hash["AudioAllowDTSHDPass"].to_i == 1 commandString << " allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;\n " end if hash["AudioAllowDTSPass"].to_i == 1 commandString << " allowed_audio_copy |= HB_ACODEC_DCA_PASS;\n " end if hash["AudioAllowMP3Pass"].to_i == 1 commandString << " allowed_audio_copy |= HB_ACODEC_MP3_PASS;\n " end commandString << " allowed_audio_copy &= HB_ACODEC_PASS_MASK;\n " commandString << "}\n " end #Auto Passthru Fallback audioEncoderFallback = "" case hash["AudioEncoderFallback"] when /AC3/ audioEncoderFallback << "HB_ACODEC_AC3" when "AAC (ffmpeg)" audioEncoderFallback << "HB_ACODEC_FFAAC" when /AAC/ audioEncoderFallback << "HB_ACODEC_FAAC" when /Vorbis/ audioEncoderFallback << "HB_ACODEC_VORBIS" when /MP3/ audioEncoderFallback << "HB_ACODEC_LAME" when /FLAC/ audioEncoderFallback << "HB_ACODEC_FFFLAC" end if audioEncoderFallback.size > 0 commandString << "if( !acodec_fallback )\n " commandString << "{\n " commandString << " acodec_fallback = " << audioEncoderFallback commandString << ";\n " commandString << "}\n " end #Cropping if hash["PictureAutoCrop"] == 0 commandString << "job->crop[0] = " << hash["PictureTopCrop"].to_s << ";\n " commandString << "job->crop[1] = " << hash["PictureBottomCrop"].to_s << ";\n " commandString << "job->crop[2] = " << hash["PictureLeftCrop"].to_s << ";\n " commandString << "job->crop[4] = " << hash["PictureRightCrop"].to_s << ";\n " end #Dimensions if hash["PictureWidth"] != 0 commandString << "maxWidth = " commandString << hash["PictureWidth"].to_s << ";\n " end if hash["PictureHeight"] != 0 commandString << "maxHeight = " commandString << hash["PictureHeight"].to_s << ";\n " end #Subtitles if hash["Subtitles"] != "None" if hash["Subtitles"] == "Autoselect" commandString << "subtitle_scan = 1;\n " else commandString << "job->subtitle = " commandString << ( hash["Subtitles"].to_i - 1).to_s << ";\n " end end #Advanced Options if hash["x264Option"] != "" commandString << "if( !advanced_opts )\n " commandString << "{\n " commandString << " advanced_opts = strdup(\"" commandString << hash["x264Option"] << "\");\n " commandString << "}\n " end #Video Filters if hash["UsesPictureFilters"] == 1 if hash["PictureDeinterlace"].to_i != 0 commandString << "deinterlace = 1;\n " end case hash["PictureDeinterlace"] when 1 commandString << "deinterlace_opt = \"" << hash["PictureDeinterlaceCustom"].to_s << "\";\n " when 2 commandString << "deinterlace_opt = \"0\";\n " when 3 commandString << "deinterlace_opt = \"1\";\n " when 4 commandString << "deinterlace_opt = \"3\";\n " when 5 commandString << "deinterlace_opt = \"15\";\n " end if hash["PictureDenoise"].to_i != 0 commandString << "denoise = 1;\n " end case hash["PictureDenoise"] when 1 commandString << "denoise_opt = \"" << hash["PictureDenoiseCustom"].to_s << "\";\n " when 2 commandString << "denoise_opt = \"2:1:2:3\";\n " when 3 commandString << "denoise_opt = \"3:2:2:3\";\n " when 4 commandString << "denoise_opt = \"7:7:5:5\";\n " end if hash["PictureDecomb"].to_i != 0 commandString << "decomb = 1;\n " end case hash["PictureDecomb"] when 1 commandString << "decomb_opt = \"" << hash["PictureDecombCustom"].to_s << "\";\n " when 3 commandString << "decomb_opt = \"7:2:6:9:1:80\";\n " when 4 commandString << "decomb_opt = \"455\";\n " end if hash["PictureDetelecine"].to_i != 0 commandString << "detelecine = 1;\n " end case hash["PictureDetelecine"] when 1 commandString << "detelecine_opt = \"" << hash["PictureDetelecineCustom"].to_s << "\";\n " end if hash["PictureDeblock"] != 0 commandString << "deblock = 1;\n " commandString << "deblock_opt = \"" << hash["PictureDeblock"].to_s << "\";\n " end end #Anamorphic if hash["PicturePAR"] != 0 commandString << "if( !anamorphic_mode )\n " commandString << "{\n " if hash["PicturePAR"] == 1 commandString << " anamorphic_mode = 1;\n " elsif hash["PicturePAR"] == 2 commandString << " anamorphic_mode = 2;\n " elsif hash["PicturePAR"] == 3 commandString << " anamorphic_mode = 3;\n " end commandString << "}\n " end #Modulus if hash["PictureModulus"] commandString << "modulus = " << hash["PictureModulus"].to_s << ";\n " end #Booleans if hash["ChapterMarkers"] == 1 then commandString << "job->chapter_markers = 1;\n " end if hash["VideoGrayScale"] == 1 then commandString << "job->grayscale = 1;\n " end if hash["VideoTwoPass"] == 1 then commandString << "twoPass = 1;\n " end if hash["VideoTurboTwoPass"] == 1 then commandString << "turbo_opts_enabled = 1;\n" end commandString << "\n" commandString << "}" # That's it, print to screen now puts commandString #puts "*" * @columnWidth puts "\n" end def generateAPIFolderList( hash, depth ) commandString = "" commandString << " printf(\"\\n" depth.times do commandString << " " end (depth+1).times do commandString << "<" end commandString << " " << hash["PresetName"] commandString << "\\n\");\n\n" puts commandString end def generateAPIFolderCloserList( depth ) commandString = "" commandString << " printf(\"\\n" depth.times do commandString << " " end (depth+1).times do commandString << ">" end commandString << "\\n\");\n\n" puts commandString end def generateAPIList(hash, depth) # Makes a list of the CLI options a built-in CLI preset uses, for wrappers to parse commandString = "" commandString << " printf(\"\\n" depth.times do commandString << " " end commandString << "+ " << hash["PresetName"] << ": " #Video encoder if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" commandString << " -e " case hash["VideoEncoder"] when /x264/ commandString << "x264 " when /Theora/ commandString << "theora " when /MPEG/ commandString << "ffmpeg2 " end end #VideoRateControl case hash["VideoQualityType"] when 0 commandString << " -S " << hash["VideoTargetSize"] when 1 commandString << " -b " << hash["VideoAvgBitrate"] when 2 commandString << " -q " << hash["VideoQualitySlider"].to_s end #FPS if hash["VideoFramerate"] != "Same as source" if hash["VideoFramerate"] == "23.976 (NTSC Film)" commandString << " -r " << "23.976" elsif hash["VideoFramerate"] == "29.97 (NTSC Video)" commandString << " -r " << "29.97" elsif hash["VideoFramerate"] == "25 (PAL Film/Video)" commandString << " -r " << "25" else commandString << " -r " << hash["VideoFramerate"] end # not same as source: pfr, else default (cfr) if hash["VideoFramerateMode"] == "pfr" commandString << " --pfr " end # same as source: cfr, else default (vfr) elsif hash["VideoFramerateMode"] == "cfr" commandString << " --cfr " end #Audio tracks audioBitrates = "" audioEncoders = "" audioMixdowns = "" audioSamplerates = "" audioTracks = "" audioTrackDRCs = "" audioCount = hash["AudioList"].size hash["AudioList"].each do |audioTrack| audioCount = audioCount - 1 #Bitrates audioBitrates << audioTrack["AudioBitrate"] #Encoders case audioTrack["AudioEncoder"] when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ audioEncoders << "ffac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" when "AAC (ffmpeg)" audioEncoders << "ffaac" when /AAC/ audioEncoders << "faac" when /Vorbis/ audioEncoders << "vorbis" when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ audioEncoders << "lame" when /FLAC/ audioEncoders << "ffflac" when /Auto Pass/ audioEncoders << "copy" end #Mixdowns case audioTrack["AudioMixdown"] when /Mono/ audioMixdowns << "mono" when /Stereo/ audioMixdowns << "stereo" when /Dolby Surround/ audioMixdowns << "dpl1" when /Dolby Pro Logic II/ audioMixdowns << "dpl2" when /discrete/ audioMixdowns << "6ch" when /None/ audioMixdowns << "auto" end #Samplerates audioSamplerates << audioTrack["AudioSamplerate"] #Tracks audioTracks << audioTrack["AudioTrack"].to_s #DRC audioTrackDRCs << audioTrack["AudioTrackDRCSlider"].to_s if audioCount > 0 audioBitrates << "," audioEncoders << "," audioMixdowns << "," audioSamplerates << "," audioTracks << "," audioTrackDRCs << "," end end commandString << " -a " << audioTracks commandString << " -E " << audioEncoders commandString << " -B " << audioBitrates commandString << " -6 " << audioMixdowns commandString << " -R " << audioSamplerates commandString << " -D " << audioTrackDRCs #Auto Passthru Mask audioCopyMask = "" if hash["AudioAllowAACPass"].to_i == 1 audioCopyMask << "aac" end if hash["AudioAllowAC3Pass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "ac3" end if hash["AudioAllowDTSHDPass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "dtshd" end if hash["AudioAllowDTSPass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "dts" end if hash["AudioAllowMP3Pass"].to_i == 1 if audioCopyMask.size > 0 audioCopyMask << "," end audioCopyMask << "mp3" end if audioCopyMask.size > 0 commandString << " --audio-copy-mask " << audioCopyMask end #Auto Passthru Fallback audioEncoderFallback = "" case hash["AudioEncoderFallback"] when /AC3/ audioEncoderFallback << "ffac3" when "AAC (ffmpeg)" audioEncoderFallback << "ffaac" when /AAC/ audioEncoderFallback << "faac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ audioEncoderFallback << "lame" when /FLAC/ audioEncoderFallback << "ffflac" end if audioEncoderFallback.size > 0 commandString << " --audio-fallback " << audioEncoderFallback end #Container commandString << " -f " case hash["FileFormat"] when /MP4/ commandString << "mp4" when /MKV/ commandString << "mkv" end #iPod MP4 atom if hash["Mp4iPodCompatible"].to_i == 1 commandString << " -I" end # 64-bit files if hash["Mp4LargeFile"] == 1 commandString << " -4" end #MP4 Optimize for HTTP Streaming if hash["Mp4HttpOptimize"].to_i == 1 commandString << " -O" end #Cropping if hash["PictureAutoCrop"] == 0 commandString << " --crop " commandString << hash["PictureTopCrop"].to_s commandString << ":" commandString << hash["PictureBottomCrop"].to_s commandString << ":" commandString << hash["PictureLeftCrop"].to_s commandString << ":" commandString << hash["PictureRightCrop"].to_s end #Dimensions if hash["PictureWidth"] != 0 commandString << " -X " commandString << hash["PictureWidth"].to_s end if hash["PictureHeight"] != 0 commandString << " -Y " commandString << hash["PictureHeight"].to_s end #Subtitles if hash["Subtitles"] && hash["Subtitles"] != "None" if hash["Subtitles"] == "Autoselect" commandString << " --subtitle-scan" else commandString << " -s " commandString << hash["Subtitles"] end end #Video Filters if hash["UsesPictureFilters"] == 1 case hash["PictureDeinterlace"] when 1 commandString << " --deinterlace=" << hash["PictureDeinterlaceCustom"].to_s when 2 commandString << " --deinterlace=fast" when 3 commandString << " --deinterlace=slow" when 4 commandString << " --deinterlace=slower" when 5 commandString << " --deinterlace=bob" end case hash["PictureDenoise"] when 1 commandString << " --denoise=" << hash["PictureDenoiseCustom"].to_s when 2 commandString << " --denoise=weak" when 3 commandString << " --denoise=medium" when 4 commandString << " --denoise=strong" end case hash["PictureDecomb"] when 1 commandString << " --decomb=" << hash["PictureDecombCustom"].to_s when 2 commandString << " --decomb" when 3 commandString << " --decomb=fast" when 4 commandString << " --decomb=bob" end case hash["PictureDetelecine"] when 1 commandString << " --detelecine=" << hash["PictureDetelecineCustom"].to_s when 2 commandString << " --detelecine" end if hash["PictureDeblock"] != 0 commandString << " --deblock=" << hash["PictureDeblock"].to_s end end #Anamorphic if hash["PicturePAR"] == 1 commandString << " --strict-anamorphic" elsif hash["PicturePAR"] == 2 commandString << " --loose-anamorphic" elsif hash["PicturePAR"] == 3 commandString << " --custom-anamorphic" end #Modulus if hash["PictureModulus"] commandString << " --modulus " << hash["PictureModulus"].to_s end #Booleans if hash["ChapterMarkers"] == 1 then commandString << " -m" end if hash["VideoGrayScale"] == 1 then commandString << " -g" end if hash["VideoTwoPass"] == 1 then commandString << " -2" end if hash["VideoTurboTwoPass"] == 1 then commandString << " -T" end #Advanced Options if hash["x264Option"] != "" commandString << " -x " commandString << hash["x264Option"] end commandString << "\\n\");" # That's it, print to screen now puts commandString puts "\n" end end # First grab the specified CLI options options = readOptions # Only run if one of the useful CLI flags have been passed if options.cliraw == true || options.cliparse == true || options.api == true || options.apilist == true # This line is the ignition -- generates hashes of # presets and then displays them to the screen # with the options the user selects on the CLI. Display.new( Presets.new.hashMasterList, options ) else # Direct the user to the help puts "\n\tUsage: manicure.rb [options]" puts "\tSee help with -h or --help" end