summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--macosx/English.lproj/PictureSettings.xib50
-rw-r--r--macosx/HBAddPresetController.m3
-rw-r--r--macosx/HBAppDelegate.m16
-rw-r--r--macosx/HBAudioDefaults.m97
-rw-r--r--macosx/HBAudioTrackPreset.h2
-rw-r--r--macosx/HBAudioTrackPreset.m4
-rw-r--r--macosx/HBController.m94
-rw-r--r--macosx/HBFilters+UIAdditions.h17
-rw-r--r--macosx/HBFilters+UIAdditions.m202
-rw-r--r--macosx/HBFilters.h6
-rw-r--r--macosx/HBFilters.m201
-rw-r--r--macosx/HBJob+HBJobConversion.m22
-rw-r--r--macosx/HBJob.m11
-rw-r--r--macosx/HBPicture.h2
-rw-r--r--macosx/HBPicture.m52
-rw-r--r--macosx/HBPreset.h65
-rw-r--r--macosx/HBPreset.m187
-rw-r--r--macosx/HBPresetsManager.h14
-rw-r--r--macosx/HBPresetsManager.m296
-rw-r--r--macosx/HBPresetsViewController.m6
-rw-r--r--macosx/HBTreeNode.h22
-rw-r--r--macosx/HBTreeNode.m59
-rw-r--r--macosx/HBVideo.m79
-rw-r--r--macosx/HandBrake.xcodeproj/project.pbxproj8
24 files changed, 896 insertions, 619 deletions
diff --git a/macosx/English.lproj/PictureSettings.xib b/macosx/English.lproj/PictureSettings.xib
index 39946b7ce..81b957b64 100644
--- a/macosx/English.lproj/PictureSettings.xib
+++ b/macosx/English.lproj/PictureSettings.xib
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7702" systemVersion="14E11f" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7702" systemVersion="14E17e" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment version="1060" identifier="macosx"/>
<development version="5100" identifier="xcode"/>
@@ -204,7 +204,7 @@
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" id="44">
<rect key="frame" x="143" y="103" width="15" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
- <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="64" id="169">
+ <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="59" id="169">
<font key="font" metaFont="smallSystem"/>
</stepperCell>
<connections>
@@ -254,7 +254,7 @@
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" id="46">
<rect key="frame" x="143" y="78" width="15" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
- <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="59" id="171">
+ <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="64" id="171">
<font key="font" metaFont="smallSystem"/>
</stepperCell>
<connections>
@@ -589,9 +589,9 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
- <binding destination="-2" name="hidden" keyPath="self.filters.detelecine" id="GeL-Hh-N04">
+ <binding destination="-2" name="hidden" keyPath="self.filters.customDetelecineSelected" id="xn5-rR-hyv">
<dictionary key="options">
- <string key="NSValueTransformerName">HBCustomFilterTransformer</string>
+ <string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
</connections>
@@ -605,8 +605,12 @@
<menu key="menu" title="OtherViews" id="349"/>
</popUpButtonCell>
<connections>
- <binding destination="-2" name="selectedIndex" keyPath="self.filters.detelecine" previousBinding="pGd-yk-F9V" id="nJ6-iy-GiP"/>
- <binding destination="-2" name="content" keyPath="self.filters.detelecineSettings" id="pGd-yk-F9V"/>
+ <binding destination="-2" name="selectedValue" keyPath="self.filters.detelecine" previousBinding="rmK-X3-zA9" id="x5y-hX-luP">
+ <dictionary key="options">
+ <string key="NSValueTransformerName">HBDetelecineTransformer</string>
+ </dictionary>
+ </binding>
+ <binding destination="-2" name="contentValues" keyPath="self.filters.detelecineSettings" id="rmK-X3-zA9"/>
</connections>
</popUpButton>
<textField verticalHuggingPriority="750" id="343">
@@ -618,9 +622,9 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
- <binding destination="-2" name="hidden" keyPath="self.filters.detelecine" id="BLn-QV-lw8">
+ <binding destination="-2" name="hidden" keyPath="self.filters.customDetelecineSelected" id="fF2-eT-6RN">
<dictionary key="options">
- <string key="NSValueTransformerName">HBCustomFilterTransformer</string>
+ <string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
<binding destination="-2" name="value" keyPath="self.filters.detelecineCustomString" id="gSO-TA-w8P">
@@ -693,9 +697,9 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
- <binding destination="-2" name="hidden" keyPath="self.filters.decomb" id="SgL-u6-Y9a">
+ <binding destination="-2" name="hidden" keyPath="self.filters.customDecombSelected" id="pks-wo-Nne">
<dictionary key="options">
- <string key="NSValueTransformerName">HBCustomFilterTransformer</string>
+ <string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
</connections>
@@ -709,7 +713,11 @@
<menu key="menu" title="OtherViews" id="322"/>
</popUpButtonCell>
<connections>
- <binding destination="-2" name="selectedIndex" keyPath="self.filters.decomb" previousBinding="Rky-63-XUy" id="0LF-hS-iFS"/>
+ <binding destination="-2" name="selectedValue" keyPath="self.filters.decomb" previousBinding="Rky-63-XUy" id="TQt-JS-VHx">
+ <dictionary key="options">
+ <string key="NSValueTransformerName">HBDecombTransformer</string>
+ </dictionary>
+ </binding>
<binding destination="-2" name="contentValues" keyPath="self.filters.decombSettings" id="Rky-63-XUy"/>
</connections>
</popUpButton>
@@ -722,9 +730,9 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
- <binding destination="-2" name="hidden" keyPath="self.filters.decomb" id="akE-8W-aND">
+ <binding destination="-2" name="hidden" keyPath="self.filters.customDecombSelected" id="nJx-xP-xY9">
<dictionary key="options">
- <string key="NSValueTransformerName">HBCustomFilterTransformer</string>
+ <string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
<binding destination="-2" name="value" keyPath="self.filters.decombCustomString" id="y3W-Df-Jgn">
@@ -764,9 +772,9 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
- <binding destination="-2" name="hidden" keyPath="self.filters.deinterlace" id="rIM-KR-bUf">
+ <binding destination="-2" name="hidden" keyPath="self.filters.customDeinterlaceSelected" id="Nh0-4S-cCl">
<dictionary key="options">
- <string key="NSValueTransformerName">HBCustomFilterTransformer</string>
+ <string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
</connections>
@@ -780,7 +788,11 @@
<menu key="menu" title="OtherViews" id="336"/>
</popUpButtonCell>
<connections>
- <binding destination="-2" name="selectedIndex" keyPath="self.filters.deinterlace" previousBinding="hol-Lh-FVF" id="5jK-2w-2Fq"/>
+ <binding destination="-2" name="selectedValue" keyPath="self.filters.deinterlace" previousBinding="hol-Lh-FVF" id="xvF-2Y-wvz">
+ <dictionary key="options">
+ <string key="NSValueTransformerName">HBDeinterlaceTransformer</string>
+ </dictionary>
+ </binding>
<binding destination="-2" name="contentValues" keyPath="self.filters.deinterlaceSettings" id="hol-Lh-FVF"/>
</connections>
</popUpButton>
@@ -793,9 +805,9 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
- <binding destination="-2" name="hidden" keyPath="self.filters.deinterlace" id="7f6-Fd-pfo">
+ <binding destination="-2" name="hidden" keyPath="self.filters.customDeinterlaceSelected" id="CFf-Mz-6Hc">
<dictionary key="options">
- <string key="NSValueTransformerName">HBCustomFilterTransformer</string>
+ <string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
<binding destination="-2" name="value" keyPath="self.filters.deinterlaceCustomString" id="aSX-hF-LBO">
diff --git a/macosx/HBAddPresetController.m b/macosx/HBAddPresetController.m
index cdc0caf14..ac3ea4829 100644
--- a/macosx/HBAddPresetController.m
+++ b/macosx/HBAddPresetController.m
@@ -8,6 +8,7 @@
#import "HBAddPresetController.h"
#import "HBPreset.h"
+
#include "hb.h"
@interface HBAddPresetController ()
@@ -121,6 +122,8 @@
self.preset.content = [dict copy];
+ [self.preset cleanUp];
+
[[self window] orderOut:nil];
[NSApp endSheet:[self window] returnCode:NSModalResponseContinue];
}
diff --git a/macosx/HBAppDelegate.m b/macosx/HBAppDelegate.m
index 03e10a921..39f6671ea 100644
--- a/macosx/HBAppDelegate.m
+++ b/macosx/HBAppDelegate.m
@@ -16,7 +16,7 @@
#import "HBCore.h"
#import "HBController.h"
-#define PRESET_FILE @"UserPresets.plist"
+#define PRESET_FILE @"UserPresets.json"
@interface HBAppDelegate ()
@@ -77,8 +77,6 @@
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
- // Updates built-ins presets if needed
- [self checkBuiltInsForUpdates];
[self buildPresetsMenu];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(buildPresetsMenu) name:HBPresetsChangedNotification object:nil];
@@ -286,9 +284,9 @@
- (void)checkBuiltInsForUpdates
{
// if we have built in presets to update, then do so AlertBuiltInPresetUpdate
- if ([self.presetsManager checkBuiltInsForUpdates])
- {
- if( [[NSUserDefaults standardUserDefaults] boolForKey:@"AlertBuiltInPresetUpdate"] == YES)
+ //if ([self.presetsManager checkBuiltInsForUpdates])
+ //{
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"AlertBuiltInPresetUpdate"] == YES)
{
// Show an alert window that built in presets will be updated
[NSApp requestUserAttention:NSCriticalRequest];
@@ -297,9 +295,7 @@
[alert setInformativeText:@"HandBrake will now update your built-in presets."];
[alert runModal];
}
- // when alert is dismissed, go ahead and update the built in presets
- [self.presetsManager generateBuiltInPresets];
- }
+ //}
}
/**
@@ -336,7 +332,7 @@
item.representedObject = obj;
}
// Make the default preset font bold.
- if ([obj isDefault])
+ if ([obj isEqualTo:self.presetsManager.defaultPreset])
{
NSAttributedString *newTitle = [[NSAttributedString alloc] initWithString:[obj name]
attributes:@{NSFontAttributeName: [NSFont boldSystemFontOfSize:14]}];
diff --git a/macosx/HBAudioDefaults.m b/macosx/HBAudioDefaults.m
index a5c6f100a..727910aa9 100644
--- a/macosx/HBAudioDefaults.m
+++ b/macosx/HBAudioDefaults.m
@@ -117,14 +117,41 @@
}
// Passthru settings
- self.allowAACPassthru = [preset[@"AudioAllowAACPass"] boolValue];
- self.allowAC3Passthru = [preset[@"AudioAllowAC3Pass"] boolValue];
- self.allowEAC3Passthru = [preset[@"AudioAllowEAC3Pass"] boolValue];
- self.allowDTSHDPassthru = [preset[@"AudioAllowDTSHDPass"] boolValue];
- self.allowDTSPassthru= [preset[@"AudioAllowDTSPass"] boolValue];
- self.allowMP3Passthru = [preset[@"AudioAllowMP3Pass"] boolValue];
- self.allowTrueHDPassthru = [preset[@"AudioAllowTrueHDPass"] boolValue];
- self.allowFLACPassthru = [preset[@"AudioAllowFlacPass"] boolValue];
+ for (NSString *copyMask in preset[@"AudioCopyMask"])
+ {
+ if ([copyMask isEqualToString:@"copy:aac"])
+ {
+ self.allowAACPassthru = YES;
+ }
+ else if ([copyMask isEqualToString:@"copy:ac3"])
+ {
+ self.allowAC3Passthru = YES;
+ }
+ else if ([copyMask isEqualToString:@"copy:eac3"])
+ {
+ self.allowEAC3Passthru = YES;
+ }
+ else if ([copyMask isEqualToString:@"copy:dtshd"])
+ {
+ self.allowDTSHDPassthru = YES;
+ }
+ else if ([copyMask isEqualToString:@"copy:dts"])
+ {
+ self.allowDTSPassthru = YES;
+ }
+ else if ([copyMask isEqualToString:@"copy:mp3"])
+ {
+ self.allowMP3Passthru = YES;
+ }
+ else if ([copyMask isEqualToString:@"copy:truehd"])
+ {
+ self.allowTrueHDPassthru = YES;
+ }
+ else if ([copyMask isEqualToString:@"copy:flac"])
+ {
+ self.allowFLACPassthru = YES;
+ }
+ }
self.secondaryEncoderMode = [preset[@"AudioSecondaryEncoderMode"] boolValue];
@@ -160,8 +187,8 @@
}
newTrack.bitRate = [track[@"AudioBitrate"] intValue];
- newTrack.drc = [track[@"AudioTrackDRCSlider"] floatValue];
- newTrack.gain = [track[@"AudioTrackGainSlider"] intValue];
+ newTrack.drc = [track[@"AudioTrackDRCSlider"] doubleValue];
+ newTrack.gain = [track[@"AudioTrackGainSlider"] doubleValue];
[self.tracksArray addObject:newTrack];
}
}
@@ -184,16 +211,42 @@
preset[@"AudioLanguageList"] = [self.trackSelectionLanguages copy];
// Passthru settings
- preset[@"AudioAllowAACPass"] = @(self.allowAACPassthru);
- preset[@"AudioAllowAC3Pass"] = @(self.allowAC3Passthru);
- preset[@"AudioAllowEAC3Pass"] = @(self.allowEAC3Passthru);
- preset[@"AudioAllowDTSHDPass"] = @(self.allowDTSHDPassthru);
- preset[@"AudioAllowDTSPass"] = @(self.allowDTSPassthru);
- preset[@"AudioAllowMP3Pass"] = @(self.allowMP3Passthru);
- preset[@"AudioAllowTrueHDPass"] = @(self.allowTrueHDPassthru);
- preset[@"AudioAllowFlacPass"] = @(self.allowFLACPassthru);
+ NSMutableArray *copyMask = [NSMutableArray array];
+ if (self.allowAACPassthru)
+ {
+ [copyMask addObject:@"copy:aac"];
+ }
+ if (self.allowAC3Passthru)
+ {
+ [copyMask addObject:@"copy:ac3"];
+ }
+ if (self.allowEAC3Passthru)
+ {
+ [copyMask addObject:@"copy:eac3"];
+ }
+ if (self.allowDTSHDPassthru)
+ {
+ [copyMask addObject:@"copy:dtshd"];
+ }
+ if (self.allowDTSPassthru)
+ {
+ [copyMask addObject:@"copy:dts"];
+ }
+ if (self.allowMP3Passthru)
+ {
+ [copyMask addObject:@"copy:mp3"];
+ }
+ if (self.allowTrueHDPassthru)
+ {
+ [copyMask addObject:@"copy:truehd"];
+ }
+ if (self.allowFLACPassthru)
+ {
+ [copyMask addObject:@"copy:flac"];
+ }
+ preset[@"AudioCopyMask"] = [copyMask copy];
- preset[@"AudioEncoderFallback"] = @(hb_audio_encoder_get_name(self.encoderFallback));
+ preset[@"AudioEncoderFallback"] = @(hb_audio_encoder_get_short_name(self.encoderFallback));
preset[@"AudioSecondaryEncoderMode"] = @(self.secondaryEncoderMode);
@@ -201,13 +254,13 @@
for (HBAudioTrackPreset *track in self.tracksArray)
{
- NSString *sampleRate = @"Auto";
+ NSString *sampleRate = @"auto";
if (hb_audio_samplerate_get_name(track.sampleRate))
{
sampleRate = @(hb_audio_samplerate_get_name(track.sampleRate));
}
- NSDictionary *newTrack = @{@"AudioEncoder": @(hb_audio_encoder_get_name(track.encoder)),
- @"AudioMixdown": @(hb_mixdown_get_name(track.mixdown)),
+ NSDictionary *newTrack = @{@"AudioEncoder": @(hb_audio_encoder_get_short_name(track.encoder)),
+ @"AudioMixdown": @(hb_mixdown_get_short_name(track.mixdown)),
@"AudioSamplerate": sampleRate,
@"AudioBitrate": @(track.bitRate),
@"AudioTrackDRCSlider": @(track.drc),
diff --git a/macosx/HBAudioTrackPreset.h b/macosx/HBAudioTrackPreset.h
index 3ca97d97e..a7d849757 100644
--- a/macosx/HBAudioTrackPreset.h
+++ b/macosx/HBAudioTrackPreset.h
@@ -24,7 +24,7 @@
@property (nonatomic, readwrite) int sampleRate;
@property (nonatomic, readwrite) int bitRate;
-@property (nonatomic, readwrite) int gain;
+@property (nonatomic, readwrite) double gain;
@property (nonatomic, readwrite) double drc;
/**
diff --git a/macosx/HBAudioTrackPreset.m b/macosx/HBAudioTrackPreset.m
index 2e479f4fc..f3f40d813 100644
--- a/macosx/HBAudioTrackPreset.m
+++ b/macosx/HBAudioTrackPreset.m
@@ -276,7 +276,7 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex;
encodeInt(_sampleRate);
encodeInt(_bitRate);
- encodeInt(_gain);
+ encodeDouble(_gain);
encodeDouble(_drc);
encodeInt(_container);
@@ -291,7 +291,7 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex;
decodeInt(_sampleRate);
decodeInt(_bitRate);
- decodeInt(_gain);
+ decodeDouble(_gain);
decodeDouble(_drc);
decodeInt(_container);
diff --git a/macosx/HBController.m b/macosx/HBController.m
index 07086cd2d..c169e0fdc 100644
--- a/macosx/HBController.m
+++ b/macosx/HBController.m
@@ -51,7 +51,7 @@
@property (nonatomic, strong) HBJob *jobFromQueue;
/// The current selected preset.
-@property (nonatomic, strong) HBPreset *selectedPreset;
+@property (nonatomic, strong) HBPreset *currentPreset;
@property (nonatomic) BOOL customPreset;
/// The HBCore used for scanning.
@@ -82,7 +82,6 @@
fQueueController.controller = self;
presetManager = manager;
- _selectedPreset = presetManager.defaultPreset;
}
return self;
@@ -397,7 +396,7 @@
}
if (action == @selector(selectPresetFromMenu:))
{
- if ([menuItem.representedObject isEqualTo:self.selectedPreset])
+ if ([menuItem.representedObject isEqualTo:self.currentPreset])
{
menuItem.state = NSOnState;
}
@@ -625,7 +624,7 @@
// Save the current settings
if (self.job)
{
- self.selectedPreset = [self createPresetFromCurrentSettings];
+ self.currentPreset = [self createPresetFromCurrentSettings];
}
self.job = nil;
@@ -833,7 +832,11 @@
// If there is already a title load, save the current settings to a preset
if (self.job)
{
- self.selectedPreset = [self createPresetFromCurrentSettings];
+ self.currentPreset = [self createPresetFromCurrentSettings];
+ }
+ else
+ {
+ self.currentPreset = fPresetsView.selectedPreset;
}
HBTitle *title = self.core.titles[fSrcTitlePopUp.indexOfSelectedItem];
@@ -846,7 +849,7 @@
}
else
{
- self.job = [[HBJob alloc] initWithTitle:title andPreset:self.selectedPreset];
+ self.job = [[HBJob alloc] initWithTitle:title andPreset:self.currentPreset];
self.job.destURL = [self destURLForJob:self.job];
}
@@ -1271,7 +1274,7 @@
{
if (preset != nil && self.job)
{
- self.selectedPreset = preset;
+ self.currentPreset = preset;
// Remove the job observer so we don't update the file name
// too many times while the preset is being applied
@@ -1309,7 +1312,7 @@
- (HBPreset *)createPresetFromCurrentSettings
{
NSMutableDictionary *preset = [NSMutableDictionary dictionary];
- NSDictionary *currentPreset = self.selectedPreset.content;
+ NSDictionary *currentPreset = self.currentPreset.content;
preset[@"PresetBuildNumber"] = [NSString stringWithFormat: @"%d", [[[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"] intValue]];
preset[@"PresetName"] = self.job.presetName;
@@ -1317,7 +1320,7 @@
// Set whether or not this is a user preset or factory 0 is factory, 1 is user
preset[@"Type"] = @1;
- preset[@"Default"] = @0;
+ preset[@"Default"] = @NO;
// Get the whether or not to apply pic Size and Cropping (includes Anamorphic)
preset[@"UsesPictureSettings"] = currentPreset[@"UsesPictureSettings"];
@@ -1337,38 +1340,23 @@
#pragma mark -
#pragma mark Import Export Preset(s)
-- (IBAction) browseExportPresetFile: (id) sender
+- (IBAction)browseExportPresetFile:(id)sender
{
// Open a panel to let the user choose where and how to save the export file
NSSavePanel *panel = [NSSavePanel savePanel];
// We get the current file name and path from the destination field here
NSURL *defaultExportDirectory = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"];
- [panel setDirectoryURL:defaultExportDirectory];
- [panel setNameFieldStringValue:@"HB_Export.plist"];
- [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
- if( result == NSOKButton )
+ panel.directoryURL = defaultExportDirectory;
+ panel.nameFieldStringValue = [NSString stringWithFormat:@"%@.json", fPresetsView.selectedPreset.name];
+
+ [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result)
+ {
+ if (result == NSOKButton)
{
- NSURL *exportPresetsFile = [panel URL];
- NSURL *presetExportDirectory = [exportPresetsFile URLByDeletingLastPathComponent];
+ NSURL *presetExportDirectory = [panel.URL URLByDeletingLastPathComponent];
[[NSUserDefaults standardUserDefaults] setURL:presetExportDirectory forKey:@"LastPresetExportDirectoryURL"];
- // We check for the presets.plist
- if ([[NSFileManager defaultManager] fileExistsAtPath:[exportPresetsFile path]] == 0)
- {
- [[NSFileManager defaultManager] createFileAtPath:[exportPresetsFile path] contents:nil attributes:nil];
- }
-
- NSMutableArray *presetsToExport = [[NSMutableArray alloc] initWithContentsOfURL:exportPresetsFile];
- if (presetsToExport == nil)
- {
- presetsToExport = [[NSMutableArray alloc] init];
- // now get and add selected presets to export
- }
- if (fPresetsView.selectedPreset != nil)
- {
- [presetsToExport addObject:[fPresetsView.selectedPreset content]];
- [presetsToExport writeToURL:exportPresetsFile atomically:YES];
- }
+ [fPresetsView.selectedPreset writeToURL:panel.URL atomically:YES format:HBPresetFormatJson removeRoot:NO];
}
}];
}
@@ -1376,43 +1364,31 @@
- (IBAction)browseImportPresetFile:(id)sender
{
NSOpenPanel *panel = [NSOpenPanel openPanel];
- [panel setAllowsMultipleSelection:NO];
- [panel setCanChooseFiles:YES];
- [panel setCanChooseDirectories:NO];
- [panel setAllowedFileTypes:@[@"plist", @"xml"]];
+ panel.allowsMultipleSelection = YES;
+ panel.canChooseFiles = YES;
+ panel.canChooseDirectories = NO;
+ panel.allowedFileTypes = @[@"plist", @"xml", @"json"];
- NSURL *sourceDirectory;
if ([[NSUserDefaults standardUserDefaults] URLForKey:@"LastPresetImportDirectoryURL"])
{
- sourceDirectory = [[NSUserDefaults standardUserDefaults] URLForKey:@"LastPresetImportDirectoryURL"];
+ panel.directoryURL = [[NSUserDefaults standardUserDefaults] URLForKey:@"LastPresetImportDirectoryURL"];
}
else
{
- sourceDirectory = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"];
+ panel.directoryURL = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"];
}
- // set this for allowed file types, not sure if we should allow xml or not.
- [panel setDirectoryURL:sourceDirectory];
[panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result)
{
- NSURL *importPresetsFile = [panel URL];
- NSURL *importPresetsDirectory = [importPresetsFile URLByDeletingLastPathComponent];
- [[NSUserDefaults standardUserDefaults] setURL:importPresetsDirectory forKey:@"LastPresetImportDirectoryURL"];
+ [[NSUserDefaults standardUserDefaults] setURL:panel.directoryURL forKey:@"LastPresetImportDirectoryURL"];
- // NOTE: here we need to do some sanity checking to verify we do not hose up our presets file
- NSMutableArray *presetsToImport = [[NSMutableArray alloc] initWithContentsOfURL:importPresetsFile];
- // iterate though the new array of presets to import and add them to our presets array
- for (NSMutableDictionary *dict in presetsToImport)
+ for (NSURL *url in panel.URLs)
{
- // make any changes to the incoming preset we see fit
- // make sure the incoming preset is not tagged as default
- dict[@"Default"] = @0;
- // prepend "(imported) to the name of the incoming preset for clarification since it can be changed
- NSString *prependedName = [@"(import) " stringByAppendingString:dict[@"PresetName"]] ;
- dict[@"PresetName"] = prependedName;
-
- // actually add the new preset to our presets array
- [presetManager addPresetFromDictionary:dict];
+ HBPreset *import = [[HBPreset alloc] initWithContentsOfURL:url];
+ if (import)
+ {
+ [presetManager addPreset:import];
+ }
}
}];
}
@@ -1423,7 +1399,7 @@
- (IBAction)selectDefaultPreset:(id)sender
{
[self applyPreset:presetManager.defaultPreset];
- [fPresetsView setSelection:_selectedPreset];
+ [fPresetsView setSelection:_currentPreset];
}
- (IBAction)insertFolder:(id)sender
diff --git a/macosx/HBFilters+UIAdditions.h b/macosx/HBFilters+UIAdditions.h
index c4dbaeaa7..9a3f0c428 100644
--- a/macosx/HBFilters+UIAdditions.h
+++ b/macosx/HBFilters+UIAdditions.h
@@ -12,10 +12,18 @@
/**
* Getters to get the possible values for the filters.
*/
++ (NSDictionary *)detelecinePresetsDict;
++ (NSDictionary *)decombPresetsDict;
++ (NSDictionary *)deinterlacePresetsDict;
+
+ (NSDictionary *)denoisePresetDict;
+ (NSDictionary *)nlmeansTunesDict;
+ (NSDictionary *)denoiseTypesDict;
+- (BOOL)customDetelecineSelected;
+- (BOOL)customDecombSelected;
+- (BOOL)customDeinterlaceSelected;
+
@property (nonatomic, readonly) NSArray *detelecineSettings;
@property (nonatomic, readonly) NSArray *deinterlaceSettings;
@property (nonatomic, readonly) NSArray *decombSettings;
@@ -40,6 +48,15 @@
@property (nonatomic, strong) NSDictionary *dict;
@end
+@interface HBDetelecineTransformer : HBGenericDictionaryTransformer
+@end
+
+@interface HBDecombTransformer : HBGenericDictionaryTransformer
+@end
+
+@interface HBDeinterlaceTransformer : HBGenericDictionaryTransformer
+@end
+
@interface HBDenoisePresetTransformer : HBGenericDictionaryTransformer
@end
diff --git a/macosx/HBFilters+UIAdditions.m b/macosx/HBFilters+UIAdditions.m
index dc867fbe5..6d2c255fe 100644
--- a/macosx/HBFilters+UIAdditions.m
+++ b/macosx/HBFilters+UIAdditions.m
@@ -67,6 +67,42 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int
@end
+@implementation HBDetelecineTransformer
+
+- (instancetype)init
+{
+ if (self = [super init])
+ self.dict = [HBFilters detelecinePresetsDict];
+
+ return self;
+}
+
+@end
+
+@implementation HBDecombTransformer
+
+- (instancetype)init
+{
+ if (self = [super init])
+ self.dict = [HBFilters decombPresetsDict];
+
+ return self;
+}
+
+@end
+
+@implementation HBDeinterlaceTransformer
+
+- (instancetype)init
+{
+ if (self = [super init])
+ self.dict = [HBFilters deinterlacePresetsDict];
+
+ return self;
+}
+
+@end
+
@implementation HBDenoisePresetTransformer
- (instancetype)init
@@ -125,25 +161,72 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int
@end
+static NSDictionary *detelecinePresetsDict = nil;
+static NSDictionary *decombPresetsDict = nil;
+static NSDictionary *deinterlacePresetsDict = nil;
+
+static NSDictionary *denoisePresetDict = nil;
+static NSDictionary *nlmeansTunesDict = nil;
+static NSDictionary *denoiseTypesDict = nil;
+
@implementation HBFilters (UIAdditions)
#pragma mark - Valid values
++ (NSDictionary *)detelecinePresetsDict
+{
+ if (!detelecinePresetsDict)
+ {
+ detelecinePresetsDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_DETELECINE);
+ }
+ return detelecinePresetsDict;
+}
+
++ (NSDictionary *)decombPresetsDict
+{
+ if (!decombPresetsDict)
+ {
+ decombPresetsDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_DECOMB);
+ }
+ return decombPresetsDict;
+}
+
++ (NSDictionary *)deinterlacePresetsDict
+{
+ if (!deinterlacePresetsDict)
+ {
+ deinterlacePresetsDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_DEINTERLACE);
+ }
+ return deinterlacePresetsDict;
+}
+
+ (NSDictionary *)denoisePresetDict
{
- return filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_NLMEANS);
+ if (!denoisePresetDict)
+ {
+ denoisePresetDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_NLMEANS);
+ }
+ return denoisePresetDict;
}
+ (NSDictionary *)nlmeansTunesDict
{
- return filterParamsToNamesDict(hb_filter_param_get_tunes, HB_FILTER_NLMEANS);
+ if (!nlmeansTunesDict)
+ {
+ nlmeansTunesDict = filterParamsToNamesDict(hb_filter_param_get_tunes, HB_FILTER_NLMEANS);
+ }
+ return nlmeansTunesDict;
}
+ (NSDictionary *)denoiseTypesDict
{
- return @{NSLocalizedString(@"Off", nil): @"off",
- NSLocalizedString(@"NLMeans", nil): @"nlmeans",
- NSLocalizedString(@"HQDN3D", nil): @"hqdn3d"};;
+ if (!denoiseTypesDict)
+ {
+ denoiseTypesDict = @{NSLocalizedString(@"Off", nil): @"off",
+ NSLocalizedString(@"NLMeans", nil): @"nlmeans",
+ NSLocalizedString(@"HQDN3D", nil): @"hqdn3d"};;
+ }
+ return denoiseTypesDict;
}
- (NSArray *)detelecineSettings
@@ -176,97 +259,80 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int
return filterParamsToNamesArray(hb_filter_param_get_tunes, HB_FILTER_NLMEANS);
}
+- (BOOL)customDetelecineSelected
+{
+ return [self.detelecine isEqualToString:@"custom"] ? YES : NO;
+}
+
+- (BOOL)customDecombSelected
+{
+ return [self.decomb isEqualToString:@"custom"] ? YES : NO;
+}
+
+- (BOOL)customDeinterlaceSelected
+{
+ return [self.deinterlace isEqualToString:@"custom"] ? YES : NO;
+}
+
- (NSString *)summary
{
NSMutableString *summary = [NSMutableString string];
- /* Detelecine */
- switch (self.detelecine)
+ // Detelecine
+ if (![self.detelecine isEqualToString:@"off"])
{
- case 1:
+ if ([self.detelecine isEqualToString:@"custom"])
+ {
[summary appendFormat:@" - Detelecine (%@)", self.detelecineCustomString];
- break;
-
- case 2:
- [summary appendString:@" - Detelecine (Default)"];
- break;
-
- default:
- break;
+ }
+ else
+ {
+ [summary appendFormat:@" - Detelecine (%@)", [[[HBFilters detelecinePresetsDict] allKeysForObject:self.detelecine] firstObject]];
+ }
}
- if (self.useDecomb)
+ if (self.useDecomb && ![self.decomb isEqualToString:@"off"])
{
- /* Decomb */
- switch (self.decomb)
+ // Decomb
+ if ([self.decomb isEqualToString:@"custom"])
{
- case 1:
- [summary appendFormat:@" - Decomb (%@)", self.decombCustomString];
- break;
-
- case 2:
- [summary appendString:@" - Decomb (Default)"];
- break;
-
- case 3:
- [summary appendString:@" - Decomb (Fast)"];
- break;
-
- case 4:
- [summary appendString:@" - Decomb (Bob)"];
- break;
-
- default:
- break;
+ [summary appendFormat:@" - Decomb (%@)", self.decombCustomString];
+ }
+ else
+ {
+ [summary appendFormat:@" - Decomb (%@)", [[[HBFilters decombPresetsDict] allKeysForObject:self.decomb] firstObject]];
}
}
- else
+ else if (![self.deinterlace isEqualToString:@"off"])
{
- /* Deinterlace */
- switch (self.deinterlace)
+ // Deinterlace
+ if ([self.deinterlace isEqualToString:@"custom"])
{
- case 1:
- [summary appendFormat:@" - Deinterlace (%@)", self.deinterlaceCustomString];
- break;
-
- case 2:
- [summary appendString:@" - Deinterlace (Fast)"];
- break;
-
- case 3:
- [summary appendString:@" - Deinterlace (Slow)"];
- break;
-
- case 4:
- [summary appendString:@" - Deinterlace (Slower)"];
- break;
-
- case 5:
- [summary appendString:@" - Deinterlace (Bob)"];
- break;
-
- default:
- break;
+ [summary appendFormat:@" - Deinterlace (%@)", self.deinterlaceCustomString];
+ }
+ else
+ {
+ [summary appendFormat:@" - Deinterlace (%@)", [[[HBFilters deinterlacePresetsDict] allKeysForObject:self.deinterlace] firstObject]];
}
}
- /* Deblock */
+ // Deblock
if (self.deblock > 0)
{
[summary appendFormat:@" - Deblock (%ld)", self.deblock];
}
- /* Denoise */
+ // Denoise
if (![self.denoise isEqualToString:@"off"])
{
- [summary appendFormat:@" - Denoise (%@", self.denoise];
+ [summary appendFormat:@" - Denoise (%@", [[[HBFilters denoiseTypesDict] allKeysForObject:self.denoise] firstObject]];
if (![self.denoisePreset isEqualToString:@"custom"])
{
- [summary appendFormat:@", %@", self.denoisePreset];
+ [summary appendFormat:@", %@", [[[HBFilters denoisePresetDict] allKeysForObject:self.denoisePreset] firstObject]];
if ([self.denoise isEqualToString:@"nlmeans"])
{
- [summary appendFormat:@", %@", self.denoiseTune];
+ [summary appendFormat:@", %@", [[[HBFilters nlmeansTunesDict] allKeysForObject:self.denoiseTune] firstObject]];
}
}
else
@@ -278,7 +344,7 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int
}
- /* Grayscale */
+ // Grayscale
if (self.grayscale)
{
[summary appendString:@" - Grayscale"];
diff --git a/macosx/HBFilters.h b/macosx/HBFilters.h
index 90876877d..9d13a018b 100644
--- a/macosx/HBFilters.h
+++ b/macosx/HBFilters.h
@@ -14,15 +14,15 @@ extern NSString * const HBFiltersChangedNotification;
*/
@interface HBFilters : NSObject <NSSecureCoding, NSCopying, HBPresetCoding>
-@property (nonatomic, readwrite) NSInteger detelecine;
+@property (nonatomic, readwrite, copy) NSString *detelecine;
@property (nonatomic, readwrite, copy) NSString *detelecineCustomString;
@property (nonatomic, readwrite) BOOL useDecomb;
-@property (nonatomic, readwrite) NSInteger deinterlace;
+@property (nonatomic, readwrite, copy) NSString *deinterlace;
@property (nonatomic, readwrite, copy) NSString *deinterlaceCustomString;
-@property (nonatomic, readwrite) NSInteger decomb;
+@property (nonatomic, readwrite, copy) NSString *decomb;
@property (nonatomic, readwrite, copy) NSString *decombCustomString;
@property (nonatomic, readwrite, copy) NSString *denoise;
diff --git a/macosx/HBFilters.m b/macosx/HBFilters.m
index 77d11defc..90a031c6d 100644
--- a/macosx/HBFilters.m
+++ b/macosx/HBFilters.m
@@ -23,8 +23,11 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
self = [super init];
if (self)
{
+ _detelecine = @"off";
_detelecineCustomString = @"";
+ _deinterlace = @"off";
_deinterlaceCustomString = @"";
+ _decomb = @"off";
_decombCustomString = @"";
_denoise = @"off";
_denoiseCustomString = @"";
@@ -48,9 +51,16 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
#pragma mark - Setters
-- (void)setDetelecine:(NSInteger)detelecine
+- (void)setDetelecine:(NSString *)detelecine
{
- _detelecine = detelecine;
+ if (detelecine)
+ {
+ _detelecine = [detelecine copy];
+ }
+ else
+ {
+ _detelecine = @"off";
+ }
[self postChangedNotification];
}
@@ -69,9 +79,16 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
[self postChangedNotification];
}
-- (void)setDeinterlace:(NSInteger)deinterlace
+- (void)setDeinterlace:(NSString *)deinterlace
{
- _deinterlace = deinterlace;
+ if (deinterlace)
+ {
+ _deinterlace = [deinterlace copy];
+ }
+ else
+ {
+ _deinterlace = @"off";
+ }
[self postChangedNotification];
}
@@ -89,9 +106,16 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
[self postChangedNotification];
}
-- (void)setDecomb:(NSInteger)decomb
+- (void)setDecomb:(NSString *)decomb
{
- _decomb = decomb;
+ if (decomb)
+ {
+ _decomb = [decomb copy];
+ }
+ else
+ {
+ _decomb = @"off";
+ }
[self postChangedNotification];
}
@@ -191,6 +215,12 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
{
retval = [NSSet setWithObjects:@"detelecine", @"detelecineCustomString", @"useDecomb", @"deinterlace", @"deinterlaceCustomString", @"decomb", @"decombCustomString", @"denoise", @"denoisePreset", @"denoiseTune", @"denoiseCustomString", @"deblock", @"grayscale", nil];
}
+ if ([key isEqualToString:@"customDetelecineSelected"] ||
+ [key isEqualToString:@"customDecombSelected"] ||
+ [key isEqualToString:@"customDeinterlaceSelected"])
+ {
+ retval = [NSSet setWithObjects:@"detelecine", @"decomb", @"deinterlace", @"useDecomb", nil];
+ }
return retval;
}
@@ -204,13 +234,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
if (copy)
{
- copy->_detelecine = _detelecine;
+ copy->_detelecine = [_detelecine copy];
copy->_detelecineCustomString = [_detelecineCustomString copy];
- copy->_deinterlace = _deinterlace;
+ copy->_deinterlace = [_deinterlace copy];
copy->_deinterlaceCustomString = [_deinterlaceCustomString copy];
- copy->_decomb = _decomb;
+ copy->_decomb = [_decomb copy];
copy->_decombCustomString = [_decombCustomString copy];
copy->_denoise = [_denoise copy];
@@ -223,7 +253,7 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
copy->_useDecomb = _useDecomb;
}
-
+
return copy;
}
@@ -238,13 +268,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
{
[coder encodeInt:1 forKey:@"HBFiltersVersion"];
- encodeInteger(_detelecine);
+ encodeObject(_detelecine);
encodeObject(_detelecineCustomString);
- encodeInteger(_deinterlace);
+ encodeObject(_deinterlace);
encodeObject(_deinterlaceCustomString);
- encodeInteger(_decomb);
+ encodeObject(_decomb);
encodeObject(_decombCustomString);
encodeObject(_denoise);
@@ -262,13 +292,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
{
self = [super init];
- decodeInteger(_detelecine);
+ decodeObject(_detelecine, NSString);
decodeObject(_detelecineCustomString, NSString);
- decodeInteger(_deinterlace);
+ decodeObject(_deinterlace, NSString);
decodeObject(_deinterlaceCustomString, NSString);
- decodeInteger(_decomb);
+ decodeObject(_decomb, NSString);
decodeObject(_decombCustomString, NSString);
decodeObject(_denoise, NSString);
@@ -292,13 +322,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
{
preset[@"PictureDecombDeinterlace"] = @(self.useDecomb);
- preset[@"PictureDeinterlace"] = @(self.deinterlace);
+ preset[@"PictureDeinterlace"] = self.deinterlace;
preset[@"PictureDeinterlaceCustom"] = self.deinterlaceCustomString;
- preset[@"PictureDecomb"] = @(self.decomb);
+ preset[@"PictureDecomb"] = self.decomb;
preset[@"PictureDecombCustom"] = self.decombCustomString;
- preset[@"PictureDetelecine"] = @(self.detelecine);
+ preset[@"PictureDetelecine"] = self.detelecine;
preset[@"PictureDetelecineCustom"] = self.detelecineCustomString;
preset[@"PictureDenoiseFilter"] = self.denoise;
@@ -314,127 +344,38 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification";
{
self.notificationsEnabled = NO;
- /* If the preset has an objectForKey:@"UsesPictureFilters", and handle the filters here */
- if (preset[@"UsesPictureFilters"] && [preset[@"UsesPictureFilters"] intValue] > 0)
+ // If the preset has an objectForKey:@"UsesPictureFilters", and handle the filters here
+ if ([preset[@"UsesPictureFilters"] boolValue])
{
- /* We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key. */
- self.useDecomb = 1;
- self.decomb = 0;
- self.deinterlace = 0;
- if ([preset[@"PictureDecombDeinterlace"] intValue] == 1)
- {
- /* we are using decomb */
- /* Decomb */
- if ([preset[@"PictureDecomb"] intValue] > 0)
- {
- self.decomb = [preset[@"PictureDecomb"] intValue];
-
- /* if we are using "Custom" in the decomb setting, also set the custom string*/
- if ([preset[@"PictureDecomb"] intValue] == 1)
- {
- self.decombCustomString = preset[@"PictureDecombCustom"];
- }
- }
- }
- else
- {
- /* We are using Deinterlace */
- /* Deinterlace */
- if ([preset[@"PictureDeinterlace"] intValue] > 0)
- {
- self.useDecomb = 0;
- self.deinterlace = [preset[@"PictureDeinterlace"] intValue];
- /* if we are using "Custom" in the deinterlace setting, also set the custom string*/
- if ([preset[@"PictureDeinterlace"] intValue] == 1)
- {
- self.deinterlaceCustomString = preset[@"PictureDeinterlaceCustom"];
- }
- }
- }
+ // We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key.
+ self.useDecomb = [preset[@"PictureDecombDeinterlace"] boolValue];
- /* Detelecine */
- if ([preset[@"PictureDetelecine"] intValue] > 0)
- {
- self.detelecine = [preset[@"PictureDetelecine"] intValue];
- /* if we are using "Custom" in the detelecine setting, also set the custom string*/
- if ([preset[@"PictureDetelecine"] intValue] == 1)
- {
- self.detelecineCustomString = preset[@"PictureDetelecineCustom"];
- }
- }
- else
- {
- self.detelecine = 0;
- }
+ self.decomb = preset[@"PictureDecomb"];
+ self.decombCustomString = preset[@"PictureDecombCustom"];
- /* Denoise */
- if (preset[@"PictureDenoise"])
- {
- // Old preset denoise format, try to map it to the new one
- if ([preset[@"PictureDenoise"] intValue] > 0)
- {
- self.denoise = @"hqdn3d";
- /* if we are using "Custom" in the denoise setting, also set the custom string*/
- if ([preset[@"PictureDenoise"] intValue] == 1)
- {
- self.denoisePreset = @"custom";
- self.denoiseCustomString = preset[@"PictureDenoiseCustom"];
- }
- switch ([preset[@"PictureDenoise"] intValue]) {
- case 2:
- self.denoisePreset = @"light";
- break;
- case 3:
- self.denoisePreset = @"medium";
- break;
- case 4:
- self.denoisePreset = @"strong";
- break;
- default:
- self.denoisePreset = @"medium";
- break;
- }
- }
- else
- {
- self.denoise = @"off";
- }
- }
- else
- {
- // New format, read the values directly
- if ([@[@"off", @"nlmeans", @"hqdn3d"] containsObject:preset[@"PictureDenoiseFilter"]])
- {
- self.denoise = preset[@"PictureDenoiseFilter"];
- }
- else
- {
- self.denoise = @"off";
- }
-
- if (hb_validate_filter_preset(HB_FILTER_DENOISE, [preset[@"PictureDenoisePreset"] UTF8String], [preset[@"PictureDenoiseTune"] UTF8String]))
- {
- self.denoisePreset = preset[@"PictureDenoisePreset"];
- self.denoiseTune = preset[@"PictureDenoiseTune"];
- }
- else
- {
- self.denoisePreset = @"medium";
- self.denoiseTune = @"none";
- }
-
- self.denoiseCustomString = preset[@"PictureDenoiseCustom"];
- }
+ self.deinterlace = preset[@"PictureDeinterlace"];
+ self.deinterlaceCustomString = preset[@"PictureDeinterlaceCustom"];
+
+ //Detelecine
+ self.detelecine = preset[@"PictureDetelecine"];
+ self.detelecineCustomString = preset[@"PictureDetelecineCustom"];
+
+ // Denoise
+ self.denoise = preset[@"PictureDenoiseFilter"];
+ self.denoisePreset = preset[@"PictureDenoisePreset"];
+ self.denoiseTune = preset[@"PictureDenoiseTune"];
+
+ self.denoiseCustomString = preset[@"PictureDenoiseCustom"];
- /* Deblock */
+ // Deblock
if ([preset[@"PictureDeblock"] intValue] == 1)
{
- /* if its a one, then its the old on/off deblock, set on to 5*/
+ // if its a one, then its the old on/off deblock, set on to 5
self.deblock = 5;
}
else
{
- /* use the settings intValue */
+ // use the settings intValue
self.deblock = [preset[@"PictureDeblock"] intValue];
}
diff --git a/macosx/HBJob+HBJobConversion.m b/macosx/HBJob+HBJobConversion.m
index 4778316f2..811602062 100644
--- a/macosx/HBJob+HBJobConversion.m
+++ b/macosx/HBJob+HBJobConversion.m
@@ -417,30 +417,30 @@
if (self.filters.detelecine)
{
int filter_id = HB_FILTER_DETELECINE;
- const char *filter_str = hb_generate_filter_settings_by_index(filter_id,
- (int)self.filters.detelecine,
- self.filters.detelecineCustomString.UTF8String);
+ const char *filter_str = hb_generate_filter_settings(filter_id,
+ self.filters.detelecine.UTF8String,
+ self.filters.detelecineCustomString.UTF8String);
filter = hb_filter_init(filter_id);
hb_add_filter(job, filter, filter_str);
}
- if (self.filters.useDecomb && self.filters.decomb)
+ if (self.filters.useDecomb && ![self.filters.decomb isEqualToString:@"off"])
{
// Decomb
int filter_id = HB_FILTER_DECOMB;
- const char *filter_str = hb_generate_filter_settings_by_index(filter_id,
- (int)self.filters.decomb,
- self.filters.decombCustomString.UTF8String);
+ const char *filter_str = hb_generate_filter_settings(filter_id,
+ self.filters.decomb.UTF8String,
+ self.filters.decombCustomString.UTF8String);
filter = hb_filter_init(filter_id);
hb_add_filter(job, filter, filter_str);
}
- else if (!self.filters.useDecomb && self.filters.deinterlace)
+ else if (!self.filters.useDecomb && [self.filters.deinterlace isEqualToString:@"off"])
{
// Deinterlace
int filter_id = HB_FILTER_DEINTERLACE;
- const char *filter_str = hb_generate_filter_settings_by_index(filter_id,
- (int)self.filters.deinterlace,
- self.filters.deinterlaceCustomString.UTF8String);
+ const char *filter_str = hb_generate_filter_settings(filter_id,
+ self.filters.deinterlace.UTF8String,
+ self.filters.deinterlaceCustomString.UTF8String);
filter = hb_filter_init(filter_id);
hb_add_filter(job, filter, filter_str);
}
diff --git a/macosx/HBJob.m b/macosx/HBJob.m
index 6578c9710..921eb4304 100644
--- a/macosx/HBJob.m
+++ b/macosx/HBJob.m
@@ -61,14 +61,7 @@ NSString *HBChaptersChangedNotification = @"HBChaptersChangedNotification";
- (void)applyPreset:(HBPreset *)preset
{
- if (preset.isDefault)
- {
- self.presetName = [NSString stringWithFormat:@"%@ (Default)", preset.name];
- }
- else
- {
- self.presetName = preset.name;
- }
+ self.presetName = preset.name;
NSDictionary *content = preset.content;
@@ -87,7 +80,7 @@ NSString *HBChaptersChangedNotification = @"HBChaptersChangedNotification";
- (void)applyCurrentSettingsToPreset:(NSMutableDictionary *)dict
{
- dict[@"FileFormat"] = @(hb_container_get_name(self.container));
+ dict[@"FileFormat"] = @(hb_container_get_short_name(self.container));
dict[@"ChapterMarkers"] = @(self.chaptersEnabled);
// MP4 specifics options.
dict[@"Mp4HttpOptimize"] = @(self.mp4HttpOptimize);
diff --git a/macosx/HBPicture.h b/macosx/HBPicture.h
index 9cace8fd9..cc0f3dfd8 100644
--- a/macosx/HBPicture.h
+++ b/macosx/HBPicture.h
@@ -21,7 +21,7 @@ extern NSString * const HBPictureChangedNotification;
@property (nonatomic, readwrite) int width;
@property (nonatomic, readwrite) int height;
-@property (nonatomic, readwrite) int keepDisplayAspect;
+@property (nonatomic, readwrite) BOOL keepDisplayAspect;
@property (nonatomic, readwrite) int anamorphicMode;
@property (nonatomic, readwrite) int modulus;
diff --git a/macosx/HBPicture.m b/macosx/HBPicture.m
index 8ebfb8477..9a0b7f931 100644
--- a/macosx/HBPicture.m
+++ b/macosx/HBPicture.m
@@ -305,7 +305,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification";
}
}
-- (void)setKeepDisplayAspect:(int)keepDisplayAspect
+- (void)setKeepDisplayAspect:(BOOL)keepDisplayAspect
{
_keepDisplayAspect = keepDisplayAspect;
if (!self.isValidating)
@@ -564,7 +564,25 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification";
- (void)writeToPreset:(NSMutableDictionary *)preset
{
preset[@"PictureKeepRatio"] = @(self.keepDisplayAspect);
- preset[@"PicturePAR"] = @(self.anamorphicMode);
+
+ switch (self.anamorphicMode) {
+ case HB_ANAMORPHIC_NONE:
+ preset[@"PicturePAR"] = @"none";
+ break;
+ case HB_ANAMORPHIC_LOOSE:
+ preset[@"PicturePAR"] = @"loose";
+ break;
+ case HB_ANAMORPHIC_STRICT:
+ preset[@"PicturePAR"] = @"strict";
+ break;
+ case HB_ANAMORPHIC_CUSTOM:
+ preset[@"PicturePAR"] = @"custom";
+ break;
+ default:
+ preset[@"PicturePAR"] = @"loose";
+ break;
+ }
+
preset[@"PictureModulus"] = @(self.modulus);
// Set crop settings
@@ -597,7 +615,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification";
{
// If Cropping is set to custom, then recall all four crop values from
// when the preset was created and apply them
- if ([preset[@"PictureAutoCrop"] intValue] == 0)
+ if ([preset[@"PictureAutoCrop"] intValue] == 0)
{
self.autocrop = NO;
@@ -632,17 +650,33 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification";
}
// Assume max picture settings initially.
- self.keepDisplayAspect = [preset[@"PictureKeepRatio"] intValue];
- self.anamorphicMode = [preset[@"PicturePAR"] intValue];
+ self.keepDisplayAspect = [preset[@"PictureKeepRatio"] boolValue];
+
+ if ([preset[@"PicturePAR"] isEqualToString:@"none"])
+ {
+ self.anamorphicMode = HB_ANAMORPHIC_NONE;
+ }
+ else if ([preset[@"PicturePAR"] isEqualToString:@"strict"])
+ {
+ self.anamorphicMode = HB_ANAMORPHIC_STRICT;
+ }
+ else if ([preset[@"PicturePAR"] isEqualToString:@"custom"])
+ {
+ self.anamorphicMode = HB_ANAMORPHIC_CUSTOM;
+ }
+ else
+ {
+ self.anamorphicMode = HB_ANAMORPHIC_LOOSE;
+ }
+
self.width = self.sourceWidth - self.cropLeft - self.cropRight;
self.height = self.sourceHeight - self.cropTop - self.cropBottom;
- // Check to see if the objectForKey:@"UsesPictureSettings" is 2,
+ // Check to see if the "UsesPictureSettings" is 2,
// which means "Use max. picture size for source"
// If not 2 it must be 1 here which means "Use the picture
// size specified in the preset"
- if ([preset[@"UsesPictureSettings"] intValue] != 2 &&
- [preset[@"UsesMaxPictureSettings"] intValue] != 1)
+ if ([preset[@"UsesPictureSettings"] intValue] != 2)
{
// if the preset specifies neither max. width nor height
// (both are 0), use the max. picture size
@@ -653,7 +687,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification";
{
jobMaxWidth = [preset[@"PictureWidth"] intValue];
}
- if ([preset[@"PictureHeight"] intValue] > 0)
+ if ([preset[@"PictureHeight"] intValue] > 0)
{
jobMaxHeight = [preset[@"PictureHeight"] intValue];
}
diff --git a/macosx/HBPreset.h b/macosx/HBPreset.h
index a0a10e7f6..1b74bcd3a 100644
--- a/macosx/HBPreset.h
+++ b/macosx/HBPreset.h
@@ -4,9 +4,13 @@
Homepage: <http://handbrake.fr/>.
It may be used under the terms of the GNU General Public License. */
-#import <Cocoa/Cocoa.h>
+#import <Foundation/Foundation.h>
#import "HBTreeNode.h"
+typedef NS_ENUM(NSUInteger, HBPresetFormat) {
+ HBPresetFormatPlist,
+ HBPresetFormatJson,
+};
/**
* HBPreset
* Stores a preset dictionary.
@@ -15,14 +19,67 @@
*/
@interface HBPreset : HBTreeNode <NSCopying>
-- (instancetype)initWithName:(NSString *)title content:(NSDictionary *)content builtIn:(BOOL)builtIn;
- (instancetype)initWithFolderName:(NSString *)title builtIn:(BOOL)builtIn;
+- (instancetype)initWithName:(NSString *)title content:(NSDictionary *)content builtIn:(BOOL)builtIn;
+
+- (instancetype)initWithDictionary:(NSDictionary *)dict;
+
+/**
+ * Initializes a newly allocated preset object initialized with the data found at a given URL.
+ *
+ * @param url An URL that identifies a resource containing a string representation of a property list or json in the HandBrake preset format.
+ *
+ * @return An initialized preset—which might be different than the original receiver—that contains the preset at URL,
+ * or nil if there is an error or if the contents of the resource are not and HandBrake preset.
+ */
+- (instancetype)initWithContentsOfURL:(NSURL *)url;
+
+/**
+ * Writes a property list or json representation of the contents of the preset to a given URL.
+ *
+ * @param url The URL to which to write the preset.
+ * @param atomically A flag that specifies whether the output should be written atomically.
+ * @param format the format of the file to write.
+ * @param removeRoot whether the root preset should be written or not.
+ *
+ * @return YES if the location is written successfully, otherwise NO.
+ */
+- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)atomically format:(HBPresetFormat)format removeRoot:(BOOL)removeRoot;
+
+/**
+ * Removes unknown keys and normalizes values.
+ */
+- (void)cleanUp;
+
+/**
+ * The name of the preset.
+ */
@property (nonatomic, copy) NSString *name;
+
+/**
+ * A long textual description of the preset.
+ */
@property (nonatomic, copy) NSString *presetDescription;
-@property (nonatomic, strong) NSDictionary *content;
-@property (nonatomic) BOOL isDefault;
+/**
+ * Whether the preset is one of the HandBrake built-in ones or not.
+ */
@property (nonatomic, readonly) BOOL isBuiltIn;
+/**
+ * Whether the preset is the default one or not. Only one preset can be the default.
+ */
+@property (nonatomic) BOOL isDefault;
+
+/**
+ * The actual content of the preset.
+ */
+@property (nonatomic, strong) NSDictionary *content;
+
+/**
+ * A dictionary representation of the preset.
+ */
+@property (readonly, copy) NSDictionary *dictionary;
+
@end
diff --git a/macosx/HBPreset.m b/macosx/HBPreset.m
index 0ad0a8c86..314704205 100644
--- a/macosx/HBPreset.m
+++ b/macosx/HBPreset.m
@@ -5,9 +5,22 @@
It may be used under the terms of the GNU General Public License. */
#import "HBPreset.h"
+#include "preset.h"
@implementation HBPreset
+- (instancetype)init
+{
+ self = [super init];
+ if (self)
+ {
+ _name = @"New Preset";
+ _presetDescription = @"";
+ self.isLeaf = YES;
+ }
+ return self;
+}
+
- (instancetype)initWithName:(NSString *)title content:(NSDictionary *)content builtIn:(BOOL)builtIn;
{
self = [self init];
@@ -15,7 +28,7 @@
{
_name = [title copy];
_isBuiltIn = builtIn;
- _content = content;
+ _content = [content copy];
_presetDescription = [content[@"PresetDescription"] copy];
}
return self;
@@ -33,24 +46,157 @@
return self;
}
-- (instancetype)init
+- (instancetype)initWithDictionary:(NSDictionary *)dict
{
- self = [super init];
- if (self)
+ NSParameterAssert(dict);
+
+ if ([dict[@"Folder"] boolValue])
{
- _name = @"New Preset";
- _presetDescription = @"";
- self.isLeaf = YES;
+ self = [self initWithFolderName:dict[@"PresetName"] builtIn:![dict[@"Type"] boolValue]];
+
+ for (NSDictionary *childDict in [dict[@"ChildrenArray"] reverseObjectEnumerator])
+ {
+ HBPreset *childPreset = [[HBPreset alloc] initWithDictionary:childDict];
+ [self insertObject:childPreset inChildrenAtIndex:0];
+ }
}
+ else
+ {
+ self = [self initWithName:dict[@"PresetName"]
+ content:dict
+ builtIn:![dict[@"Type"] boolValue]];
+ self.isDefault = [dict[@"Default"] boolValue];
+ }
+
return self;
}
+- (instancetype)initWithContentsOfURL:(NSURL *)url
+{
+ NSArray *presetsArray;
+ NSString *presetsJson;
+
+ if ([url.pathExtension isEqualToString:@"json"])
+ {
+ NSData *data = [[NSData alloc] initWithContentsOfURL:url];
+ presetsJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+ }
+ else
+ {
+ NSArray *array = [[NSArray alloc] initWithContentsOfURL:url];
+ if ([NSJSONSerialization isValidJSONObject:array])
+ {
+ NSData *data = [NSJSONSerialization dataWithJSONObject:array options:0 error:NULL];
+ presetsJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+ }
+ }
+
+ // Run the json through the libhb import function
+ // to avoid importing unknowns keys.
+ if (presetsJson.length) {
+ char *importedJson = hb_presets_import_json(presetsJson.UTF8String);
+
+ if (importedJson)
+ {
+ NSData *modernizedData = [NSData dataWithBytes:importedJson length:strlen(importedJson)];
+ id importedPresets = [NSJSONSerialization JSONObjectWithData:modernizedData options:0 error:NULL];
+
+ if ([importedPresets isKindOfClass:[NSDictionary class]])
+ {
+ presetsArray = importedPresets[@"PresetList"];
+ }
+ else if ([importedPresets isKindOfClass:[NSArray class]])
+ {
+ presetsArray = importedPresets;
+ }
+ }
+ }
+
+ if (presetsArray.count)
+ {
+ self = [self initWithFolderName:@"Imported Presets" builtIn:NO];
+
+ if (self)
+ {
+ for (NSDictionary *dict in presetsArray)
+ {
+ HBPreset *preset = [[HBPreset alloc] initWithDictionary:dict];
+ [self.children addObject:preset];
+ }
+ }
+ return self;
+ }
+
+ return nil;
+}
+
+- (NSDictionary *)dictionary
+{
+ NSMutableDictionary *output = [[NSMutableDictionary alloc] init];
+ [output addEntriesFromDictionary:self.content];
+
+ output[@"PresetName"] = self.name;
+ output[@"PresetDescription"] = self.presetDescription;
+ output[@"Folder"] = [NSNumber numberWithBool:!self.isLeaf];
+ output[@"Type"] = @(!self.isBuiltIn);
+ output[@"Default"] = @(self.isDefault);
+
+ if (!self.isLeaf)
+ {
+ NSMutableArray *childArray = [[NSMutableArray alloc] init];
+ for (HBPreset *child in self.children)
+ {
+ [childArray addObject:[child dictionary]];
+ }
+
+ output[@"ChildrenArray"] = childArray;
+ }
+
+ return output;
+}
+
+- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)atomically format:(HBPresetFormat)format removeRoot:(BOOL)removeRoot;
+{
+ BOOL success = NO;
+ NSArray *presetList;
+
+ if (removeRoot)
+ {
+ presetList = self.dictionary[@"ChildrenArray"];
+ }
+ else
+ {
+ presetList = @[self.dictionary];
+ }
+
+ int major, minor, micro;
+ hb_presets_current_version(&major, &minor, &micro);
+
+ NSDictionary *dict = @{ @"PresetList": presetList,
+ @"VersionMajor": @(major),
+ @"VersionMicro": @(minor),
+ @"VersionMinor": @(micro) };
+
+ if (format == HBPresetFormatPlist)
+ {
+ success = [dict writeToURL:url atomically:atomically];
+ }
+ else
+ {
+ NSData *jsonPreset = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:NULL];
+ success = [jsonPreset writeToURL:url atomically:atomically];
+ }
+
+ return success;
+}
+
- (id)copyWithZone:(NSZone *)zone
{
HBPreset *node = [[self class] allocWithZone:zone];
node->_name = [self.name copy];
node->_content = [self.content copy];
node->_presetDescription = [self.presetDescription copy];
+
for (HBPreset *children in self.children)
{
[node.children addObject:[children copy]];
@@ -64,11 +210,36 @@
return self.name.hash + self.isBuiltIn + self.isLeaf;
}
+- (void)cleanUp
+{
+ // Run the libhb clean function
+ NSData *presetData = [NSJSONSerialization dataWithJSONObject:self.dictionary options:0 error:NULL];
+ NSString *presetJson = [[NSString alloc] initWithData:presetData encoding:NSUTF8StringEncoding];
+
+ if (presetJson.length)
+ {
+ char *cleanedJson = hb_presets_clean_json(presetJson.UTF8String);
+
+ NSData *cleanedData = [NSData dataWithBytes:cleanedJson length:strlen(cleanedJson)];
+ NSDictionary *cleanedDict = [NSJSONSerialization JSONObjectWithData:cleanedData options:0 error:NULL];
+
+ if ([cleanedDict isKindOfClass:[NSDictionary class]])
+ {
+ self.content = cleanedDict;
+ }
+ }
+}
+
- (void)setName:(NSString *)name
{
_name = [name copy];
+ [self.delegate nodeDidChange:self];
+}
- [self.delegate nodeDidChange];
+- (void)setIsDefault:(BOOL)isDefault
+{
+ _isDefault = isDefault;
+ [self.delegate nodeDidChange:self];
}
#pragma mark - KVC
diff --git a/macosx/HBPresetsManager.h b/macosx/HBPresetsManager.h
index 453475152..4921768e9 100644
--- a/macosx/HBPresetsManager.h
+++ b/macosx/HBPresetsManager.h
@@ -39,13 +39,6 @@ extern NSString *HBPresetsChangedNotification;
- (instancetype)initWithURL:(NSURL *)url;
/**
- * Checks the version number of the builtin presets.
- *
- * @return YES if the builtin presets are out of date.
- */
-- (BOOL)checkBuiltInsForUpdates;
-
-/**
* Saves the presets to disk.
*/
- (BOOL)savePresets;
@@ -55,13 +48,6 @@ extern NSString *HBPresetsChangedNotification;
*
* @param preset the preset dict.
*/
-- (void)addPresetFromDictionary:(NSDictionary *)preset;
-
-/**
- * Adds a given preset to the manager.
- *
- * @param preset the preset dict.
- */
- (void)addPreset:(HBPreset *)preset;
/**
diff --git a/macosx/HBPresetsManager.m b/macosx/HBPresetsManager.m
index 2420e5acb..29205e371 100644
--- a/macosx/HBPresetsManager.m
+++ b/macosx/HBPresetsManager.m
@@ -9,6 +9,8 @@
#import "HBUtilities.h"
+#include "preset.h"
+
NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification";
@interface HBPresetsManager () <HBTreeNodeDelegate>
@@ -42,183 +44,130 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification";
return self;
}
-- (NSIndexPath *)indexPathOfPreset:(HBPreset *)preset
-{
- __block NSIndexPath *retValue = nil;
-
- // Visit the whole tree to find the index path.
- [self.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop)
- {
- if ([obj isEqualTo:preset])
- {
- retValue = idx;
- *stop = YES;
- }
- }];
-
- return retValue;
-}
-
#pragma mark - HBTreeNode delegate
-- (void)nodeDidChange
+- (void)nodeDidChange:(id)node
{
[[NSNotificationCenter defaultCenter] postNotificationName:HBPresetsChangedNotification object:nil];
}
-#pragma mark - Load/Save
-
-- (BOOL)loadPresetsFromURL:(NSURL *)url
+- (void)treeDidRemoveNode:(id)node
{
- NSArray *presetsArray = [[NSArray alloc] initWithContentsOfURL:url];
-
- for (NSDictionary *child in presetsArray)
+ if (node == self.defaultPreset)
{
- [self.root.children addObject:[self loadFromDict:child]];
+ // Select a new default preset
+ [self selectNewDefault];
}
+}
- // If the preset list contains no leaf,
- // add back the built in presets.
- __block BOOL leafFound = NO;
- [self.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) {
- if ([obj isLeaf])
- {
- leafFound = YES;
- *stop = YES;
- }
- }];
+#pragma mark - Load/Save
- if (!leafFound)
- {
- [self generateBuiltInPresets];
- }
+/**
+ * Loads the old presets format (0.10 and earlier) plist
+ *
+ * @param url the url of the plist
+ */
+- (void)loadOldPresetsFromURL:(NSURL *)url
+{
+ HBPreset *oldPresets = [[HBPreset alloc] initWithContentsOfURL:url];
- if (self.defaultPreset == nil)
+ for (HBPreset *preset in oldPresets.children)
{
- [self selectNewDefault];
+ [self.root.children addObject:preset];
}
-
- return YES;
}
-- (BOOL)savePresetsToURL:(NSURL *)url
+- (BOOL)checkIfOutOfDate:(NSDictionary *)dict
{
- NSMutableArray *presetsArray = [[NSMutableArray alloc] init];
+ int major, minor, micro;
+ hb_presets_current_version(&major, &minor, &micro);
- for (HBPreset *node in self.root.children)
+ if (major != [dict[@"VersionMajor"] intValue] ||
+ minor != [dict[@"VersionMinor"] intValue] ||
+ micro != [dict[@"VersionMicro"] intValue])
{
- [presetsArray addObject:[self convertToDict:node]];
+ return YES;
}
-
- return [presetsArray writeToURL:url atomically:YES];
-
- return YES;
+ return NO;
}
-- (BOOL)savePresets
+- (BOOL)loadPresetsFromURL:(NSURL *)url
{
- return [self savePresetsToURL:self.fileURL];
-}
+ NSData *presetData = [[NSData alloc] initWithContentsOfURL:url];
-#pragma mark - NSDictionary conversions
-
-/**
- * Converts the NSDictionary to a HBPreset object,
- */
-- (HBPreset *)loadFromDict:(NSDictionary *)dict
-{
- HBPreset *node = nil;
- if ([dict[@"Folder"] boolValue])
+ // Try to load to load the old presets file
+ // if the new one is empty
+ if (presetData == nil)
{
- node = [[HBPreset alloc] initWithFolderName:dict[@"PresetName"]
- builtIn:![dict[@"Type"] boolValue]];
-
- for (NSDictionary *child in dict[@"ChildrenArray"])
- {
- [node.children addObject:[self loadFromDict:child]];
- }
+ [self loadOldPresetsFromURL:[url.URLByDeletingPathExtension URLByAppendingPathExtension:@"plist"]];
+ [self generateBuiltInPresets];
}
else
{
- node = [[HBPreset alloc] initWithName:dict[@"PresetName"]
- content:dict
- builtIn:![dict[@"Type"] boolValue]];
- node.isDefault = [dict[@"Default"] boolValue];
+ const char *json = [[NSString alloc] initWithData:presetData encoding:NSUTF8StringEncoding].UTF8String;
+ const char *cleanedJson = hb_presets_clean_json(json);
+
+ NSData *cleanedData = [NSData dataWithBytes:cleanedJson length:strlen(cleanedJson)];
+ NSDictionary *presetsDict = [NSJSONSerialization JSONObjectWithData:cleanedData options:0 error:NULL];
- if ([dict[@"Default"] boolValue])
+ if ([self checkIfOutOfDate:presetsDict])
{
- self.defaultPreset = node;
+ const char *updatedJson = hb_presets_import_json(cleanedJson);
+ NSData *updatedData = [NSData dataWithBytes:updatedJson length:strlen(cleanedJson)];
+ presetsDict = [NSJSONSerialization JSONObjectWithData:updatedData options:0 error:NULL];
}
- }
-
- node.delegate = self;
-
- return node;
-}
-/**
- * Converts the HBPreset and its childrens to a NSDictionary.
- */
-- (NSDictionary *)convertToDict:(HBPreset *)node
-{
- NSMutableDictionary *output = [[NSMutableDictionary alloc] init];
- [output addEntriesFromDictionary:node.content];
-
- output[@"PresetName"] = node.name;
- output[@"Folder"] = @(!node.isLeaf);
- output[@"Type"] = @(!node.isBuiltIn);
- output[@"Default"] = @(node.isDefault);
-
- if (!node.isLeaf)
- {
- NSMutableArray *childArray = [[NSMutableArray alloc] init];
- for (HBPreset *child in node.children)
+ for (NSDictionary *child in presetsDict[@"PresetList"])
{
- [childArray addObject:[self convertToDict:child]];
+ [self.root.children addObject:[[HBPreset alloc] initWithDictionary:child]];
}
- output[@"ChildrenArray"] = childArray;
+ if ([self checkIfOutOfDate:presetsDict])
+ {
+ [self generateBuiltInPresets];
+ }
}
- return output;
-}
-
-#pragma mark - Presets Management
-
-- (BOOL)checkBuiltInsForUpdates
-{
- __block BOOL retValue = NO;
-
+ // If the preset list contains no leaf,
+ // add back the built in presets.
+ __block BOOL leafFound = NO;
[self.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) {
- NSDictionary *dict = [obj content];
-
- if ([obj isBuiltIn] && [obj isLeaf])
+ if ([obj isLeaf])
{
- if (!dict[@"PresetBuildNumber"] ||
- [dict[@"PresetBuildNumber"] intValue] < [[[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"] intValue])
- {
- retValue = YES;
- *stop = YES;
- }
+ leafFound = YES;
+ *stop = YES;
}
}];
- return retValue;
+ if (!leafFound)
+ {
+ [self generateBuiltInPresets];
+ }
+
+ [self selectNewDefault];
+
+ return YES;
}
-- (void)addPresetFromDictionary:(NSDictionary *)preset
+- (BOOL)savePresetsToURL:(NSURL *)url
{
- HBPreset *presetNode = [[HBPreset alloc] initWithName:preset[@"PresetName"]
- content:preset
- builtIn:NO];
-
- [self.root insertObject:presetNode inChildrenAtIndex:[self.root countOfChildren]];
+ return [self.root writeToURL:url atomically:YES format:HBPresetFormatJson removeRoot:YES];
+}
- [self savePresets];
+- (BOOL)savePresets
+{
+ return [self savePresetsToURL:self.fileURL];
}
+#pragma mark - Presets Management
+
- (void)addPreset:(HBPreset *)preset
{
+ // Make sure no preset has the default flag enabled.
+ [preset enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) {
+ [obj setIsDefault:NO];
+ }];
+
[self.root insertObject:preset inChildrenAtIndex:[self.root countOfChildren]];
[self savePresets];
@@ -226,39 +175,16 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification";
- (void)deletePresetAtIndexPath:(NSIndexPath *)idx
{
- HBPreset *parentNode = self.root;
-
- // Find the preset parent array
- // and delete it.
- NSUInteger currIdx = 0;
- NSUInteger i = 0;
- for (i = 0; i < idx.length - 1; i++)
- {
- currIdx = [idx indexAtPosition:i];
-
- if (parentNode.children.count > currIdx)
- {
- parentNode = (parentNode.children)[currIdx];
- }
- }
-
- currIdx = [idx indexAtPosition:i];
+ [self.root removeObjectAtIndexPath:idx];
+}
- if (parentNode.children.count > currIdx)
- {
- if ([(parentNode.children)[currIdx] isDefault])
- {
- [parentNode removeObjectFromChildrenAtIndex:currIdx];
- // Try to select a new default preset
- [self selectNewDefault];
- }
- else
- {
- [parentNode removeObjectFromChildrenAtIndex:currIdx];
- }
- }
+- (NSIndexPath *)indexPathOfPreset:(HBPreset *)preset
+{
+ return [self.root indexPathOfObject:preset];
}
+#pragma mark - Default preset
+
/**
* Private method to select a new default after the default preset is deleted
* or when the built-in presets are regenerated.
@@ -290,12 +216,15 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification";
*stop = YES;
}
- if ([obj isDefault]) {
+ if ([obj isDefault])
+ {
+ self.defaultPreset = obj;
defaultAlreadySetted = YES;
}
}];
- if (defaultAlreadySetted) {
+ if (defaultAlreadySetted)
+ {
return;
}
else if (normalPreset)
@@ -308,7 +237,8 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification";
self.defaultPreset = firstUserPreset;
firstUserPreset.isDefault = YES;
}
- else if (firstBuiltInPreset) {
+ else if (firstBuiltInPreset)
+ {
self.defaultPreset = firstBuiltInPreset;
firstBuiltInPreset.isDefault = YES;
}
@@ -324,8 +254,6 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification";
}
defaultPreset.isDefault = YES;
_defaultPreset = defaultPreset;
-
- [self nodeDidChange];
}
}
@@ -333,39 +261,43 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification";
/**
* Built-in preset folders at the root of the hierarchy
-*
+ *
* Note: the built-in presets will *not* sort themselves alphabetically,
* so they will appear in the order you create them.
*/
- (void)generateBuiltInPresets
{
- [self deleteBuiltInPresets];
+ // Load the built-in presets from libhb.
+ const char *presets = hb_presets_builtin_get_json();
+ NSData *presetsData = [NSData dataWithBytes:presets length:strlen(presets)];
- // Load the built-in presets from the app bundle Resources folder.
- NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"presets" withExtension:@"plist"];
- NSArray *presetsArray = [[NSArray alloc] initWithContentsOfURL:fileURL];
+ NSError *error = nil;
+ NSArray *presetsArray = [NSJSONSerialization JSONObjectWithData:presetsData options:NSJSONReadingAllowFragments error:&error];
- for (NSDictionary *child in presetsArray.reverseObjectEnumerator)
+ if (presetsArray.count == 0)
{
- HBPreset *preset = [self loadFromDict:child];
+ [HBUtilities writeToActivityLog:"failed to update built-in presets"];
- [preset enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop)
+ if (error)
{
- NSMutableDictionary *presetDict = [[obj content] mutableCopy];
-
- // Set the current version in the built-in presets, to they won't be reupdated
- // each time the app checks the version.
- presetDict[@"PresetBuildNumber"] = [[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"];
- [obj setContent:presetDict];
- }];
-
- [self.root insertObject:preset inChildrenAtIndex:0];
+ [HBUtilities writeToActivityLog:"Error raised:\n%s", error.localizedFailureReason];
+ }
}
+ else
+ {
+ [self deleteBuiltInPresets];
- // set a new Default preset
- [self selectNewDefault];
+ for (NSDictionary *child in presetsArray.reverseObjectEnumerator)
+ {
+ HBPreset *preset = [[HBPreset alloc] initWithDictionary:child];
+ [self.root insertObject:preset inChildrenAtIndex:0];
+ }
+
+ // set a new Default preset
+ [self selectNewDefault];
- [HBUtilities writeToActivityLog: "built in presets updated to build number: %d", [[[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"] intValue]];
+ [HBUtilities writeToActivityLog: "built-in presets updated"];
+ }
}
- (void)deleteBuiltInPresets
diff --git a/macosx/HBPresetsViewController.m b/macosx/HBPresetsViewController.m
index aab6e29f5..509ae9892 100644
--- a/macosx/HBPresetsViewController.m
+++ b/macosx/HBPresetsViewController.m
@@ -244,9 +244,9 @@
/**
* draggingSourceOperationMaskForLocal <NSDraggingSource override>
*/
-- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
+- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
{
- return NSDragOperationMove;
+ return NSDragOperationMove;
}
/**
@@ -330,7 +330,7 @@
// the KVC accessors method for the root node.
if (indexPath.length == 1)
{
- [self.presets performSelector:@selector(nodeDidChange)];
+ [self.presets performSelector:@selector(nodeDidChange:) withObject:nil];
}
}
diff --git a/macosx/HBTreeNode.h b/macosx/HBTreeNode.h
index 0a8ade45b..52fa0aa37 100644
--- a/macosx/HBTreeNode.h
+++ b/macosx/HBTreeNode.h
@@ -13,7 +13,10 @@
*/
@protocol HBTreeNodeDelegate <NSObject>
-- (void)nodeDidChange;
+- (void)nodeDidChange:(id)node;
+
+@optional
+- (void)treeDidRemoveNode:(id)node;
@end
@@ -35,7 +38,24 @@
*/
- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSIndexPath *idx, BOOL *stop))block;
+/**
+ * Returns the index path of an object in the tree.
+ *
+ * @param obj the object of the wanted NSIndexPath
+ *
+ * @return The index path whose corresponding value is equal to the preset. Returns nil if not found.
+ */
+- (NSIndexPath *)indexPathOfObject:(id)obj;
+
+/**
+ * Removes the object at the specified index path.
+ *
+ * @param idx the NSIndexPath of the object to delete.
+ */
+- (void)removeObjectAtIndexPath:(NSIndexPath *)idx;
+
// KVC Accessor Methods
+
@property (nonatomic, readonly) NSUInteger countOfChildren;
- (id)objectInChildrenAtIndex:(NSUInteger)index;
- (void)insertObject:(HBTreeNode *)presetObject inChildrenAtIndex:(NSUInteger)index;
diff --git a/macosx/HBTreeNode.m b/macosx/HBTreeNode.m
index 7b4a3bd76..786e9500b 100644
--- a/macosx/HBTreeNode.m
+++ b/macosx/HBTreeNode.m
@@ -33,13 +33,18 @@
[self.children insertObject:presetObject atIndex:index];
[presetObject setDelegate:self.delegate];
- [self.delegate nodeDidChange];
+ for (HBTreeNode *node in self.children)
+ {
+ node.delegate = self.delegate;
+ }
+
+ [self.delegate nodeDidChange:self];
}
- (void)removeObjectFromChildrenAtIndex:(NSUInteger)index
{
[self.children removeObjectAtIndex:index];
- [self.delegate nodeDidChange];
+ [self.delegate nodeDidChange:self];
}
#pragma mark - Enumeration
@@ -83,4 +88,54 @@
}
}
+- (NSIndexPath *)indexPathOfObject:(id)obj
+{
+ __block NSIndexPath *retValue = nil;
+
+ // Visit the whole tree to find the index path.
+ [self enumerateObjectsUsingBlock:^(id obj2, NSIndexPath *idx, BOOL *stop)
+ {
+ if ([obj2 isEqualTo:obj])
+ {
+ retValue = idx;
+ *stop = YES;
+ }
+ }];
+
+ return retValue;
+}
+
+- (void)removeObjectAtIndexPath:(NSIndexPath *)idx
+{
+ HBTreeNode *parentNode = self;
+
+ // Find the object parent array
+ // and delete it.
+ NSUInteger currIdx = 0;
+ NSUInteger i = 0;
+ for (i = 0; i < idx.length - 1; i++)
+ {
+ currIdx = [idx indexAtPosition:i];
+
+ if (parentNode.children.count > currIdx)
+ {
+ parentNode = (parentNode.children)[currIdx];
+ }
+ }
+
+ currIdx = [idx indexAtPosition:i];
+
+ if (parentNode.children.count > currIdx)
+ {
+ id removedNode = parentNode.children[currIdx];
+
+ [parentNode removeObjectFromChildrenAtIndex:currIdx];
+
+ if ([self.delegate respondsToSelector:@selector(treeDidRemoveNode:)])
+ {
+ [self.delegate treeDidRemoveNode:removedNode];
+ }
+ }
+}
+
@end
diff --git a/macosx/HBVideo.m b/macosx/HBVideo.m
index 48cd9f4a3..490bb29be 100644
--- a/macosx/HBVideo.m
+++ b/macosx/HBVideo.m
@@ -509,9 +509,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification";
if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265)
{
- if (self.encoder == HB_VCODEC_X264 &&
- (!preset[@"x264UseAdvancedOptions"] ||
- [preset[@"x264UseAdvancedOptions"] intValue]))
+ if (self.encoder == HB_VCODEC_X264 && [preset[@"x264UseAdvancedOptions"] boolValue])
{
// preset does not use the x264 preset system, reset the widgets.
self.preset = @"medium";
@@ -520,18 +518,8 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification";
self.level = @"auto";
self.fastDecode = NO;
- // x264UseAdvancedOptions is not set (legacy preset)
- // or set to 1 (enabled), so we use the old advanced panel.
- if (preset[@"x264Option"])
- {
- // we set the advanced options string here if applicable.
- self.videoOptionExtra = preset[@"x264Option"];
- self.advancedOptions = YES;
- }
- else
- {
- self.videoOptionExtra = nil;
- }
+ self.videoOptionExtra = preset[@"VideoOptionExtra"];
+ self.advancedOptions = YES;
}
else
{
@@ -540,24 +528,11 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification";
// disable the advanced panel
self.advancedOptions = NO;
- if (preset[@"x264Preset"])
- {
- // Read the old x264 preset keys
- self.preset = preset[@"x264Preset"];
- self.tune = preset[@"x264Tune"];
- self.videoOptionExtra = preset[@"x264OptionExtra"];
- self.profile = preset[@"h264Profile"];
- self.level = preset[@"h264Level"];
- }
- else
- {
- // Read the new preset keys (0.10)
- self.preset = preset[@"VideoPreset"];
- self.tune = preset[@"VideoTune"];
- self.videoOptionExtra = preset[@"VideoOptionExtra"];
- self.profile = preset[@"VideoProfile"];
- self.level = preset[@"VideoLevel"];
- }
+ self.preset = preset[@"VideoPreset"];
+ self.tune = preset[@"VideoTune"];
+ self.videoOptionExtra = preset[@"VideoOptionExtra"];
+ self.profile = preset[@"VideoProfile"];
+ self.level = preset[@"VideoLevel"];
if ([self.tune rangeOfString:@"fastdecode"].location != NSNotFound)
{
@@ -573,15 +548,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification";
}
else
{
- if (preset[@"lavcOption"])
- {
- // Load the old format
- self.videoOptionExtra = preset[@"lavcOption"];
- }
- else
- {
- self.videoOptionExtra = preset[@"VideoOptionExtra"];
- }
+ self.videoOptionExtra = preset[@"VideoOptionExtra"];
}
int qualityType = [preset[@"VideoQualityType"] intValue] - 1;
@@ -600,7 +567,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification";
self.quality = [preset[@"VideoQualitySlider"] floatValue];
// Video framerate
- if ([preset[@"VideoFramerate"] isEqualToString:@"Same as source"])
+ if ([preset[@"VideoFramerate"] isEqualToString:@"auto"])
{
// Now set the Video Frame Rate Mode to either vfr or cfr according to the preset.
if (!preset[@"VideoFramerateMode"] ||
@@ -645,24 +612,26 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification";
- (void)writeToPreset:(NSMutableDictionary *)preset
{
- preset[@"VideoEncoder"] = @(hb_video_encoder_get_name(self.encoder));
+ preset[@"VideoEncoder"] = @(hb_video_encoder_get_short_name(self.encoder));
- // x264 Options, this will either be advanced panel or the video tabs x264 presets panel with modded option string
- if (self.advancedOptions)
- {
- // use the old advanced panel.
- preset[@"x264UseAdvancedOptions"] = @1;
- preset[@"x264Option"] = self.videoOptionExtra;
- }
- else if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265)
+ if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265)
{
- // use the new preset system.
- preset[@"x264UseAdvancedOptions"] = @0;
preset[@"VideoPreset"] = self.preset;
preset[@"VideoTune"] = [self completeTune];
preset[@"VideoOptionExtra"] = self.videoOptionExtra;
preset[@"VideoProfile"] = self.profile;
preset[@"VideoLevel"] = self.level;
+
+ // x264 Options, this will either be advanced panel or the video tabs x264 presets panel with modded option string
+ if (self.advancedOptions)
+ {
+ // use the old advanced panel.
+ preset[@"x264UseAdvancedOptions"] = @YES;
+ }
+ else
+ {
+ preset[@"x264UseAdvancedOptions"] = @NO;
+ }
}
else
{
@@ -684,7 +653,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification";
}
if (self.frameRate == 0) // Same as source is selected
{
- preset[@"VideoFramerate"] = @"Same as source";
+ preset[@"VideoFramerate"] = @"auto";
if (self.frameRateMode == 0)
{
diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj
index e595f4c30..19e786608 100644
--- a/macosx/HandBrake.xcodeproj/project.pbxproj
+++ b/macosx/HandBrake.xcodeproj/project.pbxproj
@@ -157,7 +157,6 @@
A9706CBA1AC1452800BAEAA8 /* ExceptionAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9706CB81AC1452800BAEAA8 /* ExceptionAlert.xib */; };
A971281F1A2C75180088C076 /* HBTitle.m in Sources */ = {isa = PBXBuildFile; fileRef = A971281E1A2C75180088C076 /* HBTitle.m */; };
A975C08E1AE8C5270061870D /* HBStateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = A975C08D1AE8C5270061870D /* HBStateFormatter.m */; };
- A983494F1A9A64B80059CB94 /* presets.plist in Resources */ = {isa = PBXBuildFile; fileRef = A983494E1A9A64B80059CB94 /* presets.plist */; };
A98C29C41977B10600AF5DED /* HBLanguagesSelection.m in Sources */ = {isa = PBXBuildFile; fileRef = A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */; };
A9906B2C1A710920001D82D5 /* HBQueueController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9906B2B1A710920001D82D5 /* HBQueueController.m */; };
A990D9071A64562200139032 /* HBJob+HBJobConversion.m in Sources */ = {isa = PBXBuildFile; fileRef = A990D9061A64562200139032 /* HBJob+HBJobConversion.m */; };
@@ -434,7 +433,6 @@
A971281E1A2C75180088C076 /* HBTitle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBTitle.m; sourceTree = "<group>"; };
A975C08C1AE8C5270061870D /* HBStateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBStateFormatter.h; sourceTree = "<group>"; };
A975C08D1AE8C5270061870D /* HBStateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBStateFormatter.m; sourceTree = "<group>"; };
- A983494E1A9A64B80059CB94 /* presets.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = presets.plist; sourceTree = "<group>"; };
A98C29C21977B10600AF5DED /* HBLanguagesSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBLanguagesSelection.h; sourceTree = "<group>"; };
A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBLanguagesSelection.m; sourceTree = "<group>"; };
A9906B2B1A710920001D82D5 /* HBQueueController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBQueueController.m; sourceTree = "<group>"; };
@@ -733,7 +731,6 @@
273F20CD14ADC8E60021BE6D /* Resources */ = {
isa = PBXGroup;
children = (
- A983494E1A9A64B80059CB94 /* presets.plist */,
3490BCB31614CF8D002A5AD7 /* HandBrake.icns */,
273F217914ADDDA10021BE6D /* English.lproj */,
273F212014ADCBF70021BE6D /* icons */,
@@ -1262,7 +1259,6 @@
D2BCB12816F5154E0084604C /* stopencode.png in Resources */,
A9252C041A17343500B8B7F8 /* [email protected] in Resources */,
D2BCB12916F5154E0084604C /* [email protected] in Resources */,
- A983494F1A9A64B80059CB94 /* presets.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1667,7 +1663,7 @@
"\"$(EXTERNAL_BUILD)/libhb\"",
"\"$(EXTERNAL_BUILD)/contrib/lib\"",
);
- MACOSX_DEPLOYMENT_TARGET = 10.6;
+ MACOSX_DEPLOYMENT_TARGET = 10.7;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -1692,7 +1688,7 @@
"\"$(EXTERNAL_BUILD)/libhb\"",
"\"$(EXTERNAL_BUILD)/contrib/lib\"",
);
- MACOSX_DEPLOYMENT_TARGET = 10.6;
+ MACOSX_DEPLOYMENT_TARGET = 10.7;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};