From f91daa70b55b50ad1195ea835509178e35555d11 Mon Sep 17 00:00:00 2001 From: sr55 Date: Sun, 21 Apr 2019 16:57:54 +0100 Subject: [PATCH] WinGui: Auto-name System will now always generate a unique filename. The Prefix is now a configurable Pre/Postfix in preferences. "(1)" will always be appended with an appropriate number where a collision occurs. --- .../Converters/EnumComboConverter.cs | 76 +++++++++---------- win/CS/HandBrakeWPF/HandBrakeWPF.csproj | 1 + win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs | 67 ++++++++++++---- .../Options/AutonameFileCollisionBehaviour.cs | 22 ++++++ .../Properties/Resources.Designer.cs | 36 +++++++++ win/CS/HandBrakeWPF/Properties/Resources.resx | 12 +++ win/CS/HandBrakeWPF/UserSettingConstants.cs | 6 +- .../ViewModels/OptionsViewModel.cs | 61 ++++++++++++++- win/CS/HandBrakeWPF/Views/OptionsView.xaml | 7 ++ win/CS/HandBrakeWPF/defaultsettings.xml | 18 ++++- 10 files changed, 244 insertions(+), 62 deletions(-) create mode 100644 win/CS/HandBrakeWPF/Model/Options/AutonameFileCollisionBehaviour.cs diff --git a/win/CS/HandBrakeWPF/Converters/EnumComboConverter.cs b/win/CS/HandBrakeWPF/Converters/EnumComboConverter.cs index 8d52ec954..d9dec3ae8 100644 --- a/win/CS/HandBrakeWPF/Converters/EnumComboConverter.cs +++ b/win/CS/HandBrakeWPF/Converters/EnumComboConverter.cs @@ -27,24 +27,6 @@ namespace HandBrakeWPF.Converters /// public sealed class EnumComboConverter : IValueConverter { - /// - /// Convert an Enum to it's display value (attribute) - /// - /// - /// The value. - /// - /// - /// The target type. - /// - /// - /// The parameter. (A boolean which inverts the output) - /// - /// - /// The culture. - /// - /// - /// Visibility property - /// public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) @@ -57,61 +39,78 @@ namespace HandBrakeWPF.Converters { return EnumHelper.GetEnumDisplayValues(typeof(VideoEncoder)); } + if (value is IEnumerable) { return EnumHelper.GetEnumDisplayValues(typeof(PresetPictureSettingsMode)); } + if (value is IEnumerable) { return EnumHelper.GetEnumDisplayValues(typeof(Detelecine)); } + if (value is IEnumerable) { return EnumHelper.GetEnumDisplayValues(typeof(Denoise)); } + if (value is IEnumerable) { return EnumHelper.GetEnumDisplayValues(typeof(VideoScaler)); } + if (value is IEnumerable) { return EnumHelper.GetEnumDisplayValues(typeof(OutputFormat)); } + if (value is IEnumerable) { return EnumHelper.GetEnumDisplayValues(typeof(DeinterlaceFilter)); } + if (value is IEnumerable) { return EnumHelper.GetEnumDisplayValues(typeof(CombDetect)); } + if (value is IEnumerable) { return EnumHelper.GetEnumDisplayValues(typeof(Sharpen)); } + if (value is IEnumerable) { return EnumHelper.GetEnumDisplayValues(typeof(FileOverwriteBehaviour)); } + if (value is IEnumerable) + { + return EnumHelper.GetEnumDisplayValues(typeof(AutonameFileCollisionBehaviour)); + } // Single Items if (targetType == typeof(VideoEncoder) || value.GetType() == typeof(VideoEncoder)) { return EnumHelper.GetDisplay((VideoEncoder)value); - } + } + if (targetType == typeof(PresetPictureSettingsMode) || value.GetType() == typeof(PresetPictureSettingsMode)) { return EnumHelper.GetDisplay((PresetPictureSettingsMode)value); } + if (targetType == typeof(Detelecine) || value.GetType() == typeof(Detelecine)) { return EnumHelper.GetDisplay((Detelecine)value); } + if (targetType == typeof(Denoise) || value.GetType() == typeof(Denoise)) { return EnumHelper.GetDisplay((Denoise)value); } + if (targetType == typeof(QueueItemStatus) || value.GetType() == typeof(QueueItemStatus)) { return EnumHelper.GetDisplay((QueueItemStatus)value); @@ -131,61 +130,57 @@ namespace HandBrakeWPF.Converters { return EnumHelper.GetDisplay((DeinterlaceFilter)value); } + if (targetType == typeof(CombDetect) || value.GetType() == typeof(CombDetect)) { return EnumHelper.GetDisplay((CombDetect)value); } + if (targetType == typeof(Sharpen) || value.GetType() == typeof(Sharpen)) { return EnumHelper.GetDisplay((Sharpen)value); } + if (targetType == typeof(FileOverwriteBehaviour) || value.GetType() == typeof(FileOverwriteBehaviour)) { return EnumHelper.GetDisplay((FileOverwriteBehaviour)value); } + if (targetType == typeof(AutonameFileCollisionBehaviour) || value.GetType() == typeof(AutonameFileCollisionBehaviour)) + { + return EnumHelper.GetDisplay((AutonameFileCollisionBehaviour)value); + } + return null; } - /// - /// Convert Back for the IValueConverter Interface. - /// - /// - /// The value. - /// - /// - /// The target type. - /// - /// - /// The parameter. - /// - /// - /// The culture. - /// - /// - /// Nothing - /// - /// - /// This method is not used! - /// public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { + if (value is null) + { + return null; + } + if (targetType == typeof(VideoEncoder) || value.GetType() == typeof(VideoEncoder)) { return EnumHelper.GetValue(value.ToString()); } + if (targetType == typeof(PresetPictureSettingsMode) || value.GetType() == typeof(PresetPictureSettingsMode)) { return EnumHelper.GetValue(value.ToString()); } + if (targetType == typeof(Denoise) || value.GetType() == typeof(Denoise)) { return EnumHelper.GetValue(value.ToString()); } + if (targetType == typeof(Detelecine) || value.GetType() == typeof(Detelecine)) { return EnumHelper.GetValue(value.ToString()); } + if (targetType == typeof(VideoScaler) || value.GetType() == typeof(VideoScaler)) { return EnumHelper.GetValue(value.ToString()); @@ -210,6 +205,7 @@ namespace HandBrakeWPF.Converters { return EnumHelper.GetValue(value.ToString()); } + return null; } } diff --git a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj index aa076610e..cbacffed8 100644 --- a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj +++ b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj @@ -165,6 +165,7 @@ + diff --git a/win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs b/win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs index 4a1e96b50..cf21aae0a 100644 --- a/win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs +++ b/win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs @@ -10,9 +10,11 @@ namespace HandBrakeWPF.Helpers { using System; + using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.CompilerServices; + using System.Threading.Tasks; using Caliburn.Micro; @@ -228,22 +230,9 @@ namespace HandBrakeWPF.Helpers autoNamePath = Path.Combine(Path.GetDirectoryName(task.Destination), destinationFilename); } - // Append out_ to files that already exist or is the source file - //FileOverwriteBehaviour behaviour = (FileOverwriteBehaviour)userSettingService.GetUserSetting(UserSettingConstants.FileOverwriteBehaviour, typeof(int)); - //if (behaviour == FileOverwriteBehaviour.Autoname) - //{ - if (autoNamePath?.ToLower() == task.Source?.ToLower()) - { - autoNamePath = Path.Combine(Path.GetDirectoryName(task.Source), "output_" + destinationFilename); + autoNamePath = CheckAndHandleFilenameCollisions(autoNamePath, destinationFilename, task, userSettingService); + - int counter = 1; - while (autoNamePath == task.Source) - { - autoNamePath = Path.Combine(Path.GetDirectoryName(task.Source), string.Format("output{0}_", counter) + destinationFilename); - counter = counter + 1; - } - } - //} } return autoNamePath; @@ -268,6 +257,52 @@ namespace HandBrakeWPF.Helpers return userSettingService.GetUserSetting(UserSettingConstants.AutoNamePath).Trim().StartsWith(Constants.SourcePath) || (userSettingService.GetUserSetting(UserSettingConstants.AutoNamePath).Contains(Constants.SourceFolderName) || Directory.Exists(userSettingService.GetUserSetting(UserSettingConstants.AutoNamePath).Trim())); - } + } + + private static string CheckAndHandleFilenameCollisions(string autoNamePath, string destinationFilename, EncodeTask task, IUserSettingService userSettingService) + { + AutonameFileCollisionBehaviour behaviour = (AutonameFileCollisionBehaviour)userSettingService.GetUserSetting(UserSettingConstants.AutonameFileCollisionBehaviour, typeof(int)); + string prefix = string.Empty, postfix = string.Empty; + switch (behaviour) + { + case AutonameFileCollisionBehaviour.Postfix: + postfix = userSettingService.GetUserSetting(UserSettingConstants.AutonameFilePrePostString); + break; + case AutonameFileCollisionBehaviour.Prefix: + prefix = userSettingService.GetUserSetting(UserSettingConstants.AutonameFilePrePostString); + break; + } + + string extension = Path.GetExtension(destinationFilename); + string filenameWithoutExt = Path.GetFileNameWithoutExtension(destinationFilename); + + if (behaviour != AutonameFileCollisionBehaviour.AppendNumber) + { + if (autoNamePath?.ToLower() == task.Source?.ToLower()) + { + autoNamePath = Path.Combine(Path.GetDirectoryName(task.Source), prefix + filenameWithoutExt + postfix + extension); + + int counter = 0; + while (File.Exists(autoNamePath)) + { + counter = counter + 1; + string appendedNumber = string.Format("({0})", counter); + autoNamePath = Path.Combine(Path.GetDirectoryName(task.Source), prefix + filenameWithoutExt + postfix + appendedNumber + extension); + } + } + } + else + { + int counter = 0; + while (File.Exists(autoNamePath)) + { + counter = counter + 1; + string appendedNumber = string.Format("({0})", counter); + autoNamePath = Path.Combine(Path.GetDirectoryName(task.Source), filenameWithoutExt + appendedNumber + extension); + } + } + + return autoNamePath; + } } } diff --git a/win/CS/HandBrakeWPF/Model/Options/AutonameFileCollisionBehaviour.cs b/win/CS/HandBrakeWPF/Model/Options/AutonameFileCollisionBehaviour.cs new file mode 100644 index 000000000..b1f7e784a --- /dev/null +++ b/win/CS/HandBrakeWPF/Model/Options/AutonameFileCollisionBehaviour.cs @@ -0,0 +1,22 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrakeWPF.Model.Options +{ + using HandBrake.Interop.Attributes; + + using HandBrakeWPF.Properties; + + public enum AutonameFileCollisionBehaviour + { + [DisplayName(typeof(Resources), "CollisionBehaviour_AppendNumber")] + AppendNumber = 0, + [DisplayName(typeof(Resources), "CollisionBehaviour_Pre")] + Prefix = 1, + [DisplayName(typeof(Resources), "CollisionBehaviour_Post")] + Postfix = 2, + } +} diff --git a/win/CS/HandBrakeWPF/Properties/Resources.Designer.cs b/win/CS/HandBrakeWPF/Properties/Resources.Designer.cs index db9d95bdc..733a31c72 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.Designer.cs +++ b/win/CS/HandBrakeWPF/Properties/Resources.Designer.cs @@ -690,6 +690,33 @@ namespace HandBrakeWPF.Properties { } } + /// + /// Looks up a localized string similar to Append Number. + /// + public static string CollisionBehaviour_AppendNumber { + get { + return ResourceManager.GetString("CollisionBehaviour_AppendNumber", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Postfix. + /// + public static string CollisionBehaviour_Post { + get { + return ResourceManager.GetString("CollisionBehaviour_Post", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefix. + /// + public static string CollisionBehaviour_Pre { + get { + return ResourceManager.GetString("CollisionBehaviour_Pre", resourceCulture); + } + } + /// /// Looks up a localized string similar to Confirm. /// @@ -3093,6 +3120,15 @@ namespace HandBrakeWPF.Properties { } } + /// + /// Looks up a localized string similar to Filename collision behaviour:. + /// + public static string OptionsView_FileCollisionBehaviour { + get { + return ResourceManager.GetString("OptionsView_FileCollisionBehaviour", resourceCulture); + } + } + /// /// Looks up a localized string similar to File overwrite behaviour:. /// diff --git a/win/CS/HandBrakeWPF/Properties/Resources.resx b/win/CS/HandBrakeWPF/Properties/Resources.resx index 2e4627542..d389ea639 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.resx +++ b/win/CS/HandBrakeWPF/Properties/Resources.resx @@ -1966,4 +1966,16 @@ Non-Live Options: {date} {time} {creation-date} {creation-time} {quality} {bitra When Done: + + Filename collision behaviour: + + + Postfix + + + Prefix + + + Append Number + \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/UserSettingConstants.cs b/win/CS/HandBrakeWPF/UserSettingConstants.cs index 28136a341..07019e567 100644 --- a/win/CS/HandBrakeWPF/UserSettingConstants.cs +++ b/win/CS/HandBrakeWPF/UserSettingConstants.cs @@ -14,8 +14,6 @@ namespace HandBrakeWPF /// public class UserSettingConstants { - #region Constants and Fields - public const string AutoNameFormat = "autoNameFormat"; public const string AutoNamePath = "autoNamePath"; public const string AutoNameRemoveUnderscore = "AutoNameRemoveUnderscore"; @@ -71,7 +69,7 @@ namespace HandBrakeWPF public const string ShowAddAllToQueue = "ShowAddAllToQueue"; public const string ShowAddSelectionToQueue = "ShowAddSelectionToQueue"; public const string FileOverwriteBehaviour = "FileOverwriteBehaviour"; - - #endregion + public const string AutonameFileCollisionBehaviour = "AutonameFileCollisionBehaviour"; + public const string AutonameFilePrePostString = "AutonameFilePrePostString"; } } \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs index f04ecbff9..3090a8144 100644 --- a/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs @@ -106,6 +106,11 @@ namespace HandBrakeWPF.ViewModels private bool showAddSelectionToQueue; private bool showAddAllToQueue; private int selectedOverwriteBehaviour; + private int selectedCollisionBehaviour; + + private string prePostFilenameText; + + private bool showPrePostFilenameBox; #endregion @@ -661,6 +666,49 @@ namespace HandBrakeWPF.ViewModels } } + public BindingList AutonameFileCollisionBehaviours { get; set; } + + public int SelectedCollisionBehaviour + { + get => this.selectedCollisionBehaviour; + set + { + if (value == this.selectedCollisionBehaviour) return; + this.selectedCollisionBehaviour = value; + + this.ShowPrePostFilenameBox = this.selectedCollisionBehaviour >= 1; + + this.NotifyOfPropertyChange(() => this.SelectedCollisionBehaviour); + } + } + + public string PrePostFilenameText + { + get => this.prePostFilenameText; + set + { + if (value == this.prePostFilenameText) return; + + if (this.IsValidAutonameFormat(value, false)) + { + this.prePostFilenameText = value; + } + + this.NotifyOfPropertyChange(() => this.PrePostFilenameText); + } + } + + public bool ShowPrePostFilenameBox + { + get => this.showPrePostFilenameBox; + set + { + if (value == this.showPrePostFilenameBox) return; + this.showPrePostFilenameBox = value; + this.NotifyOfPropertyChange(() => this.ShowPrePostFilenameBox); + } + } + #endregion #region Preview @@ -1445,9 +1493,13 @@ namespace HandBrakeWPF.ViewModels this.FileOverwriteBehaviourList = new BindingList(); this.FileOverwriteBehaviourList.Add(FileOverwriteBehaviour.Ask); this.FileOverwriteBehaviourList.Add(FileOverwriteBehaviour.ForceOverwrite); - // this.FileOverwriteBehaviourList.Add(FileOverwriteBehaviour.Autoname); this.SelectedOverwriteBehaviour = this.userSettingService.GetUserSetting(UserSettingConstants.FileOverwriteBehaviour, typeof(int)); + // Collision behaviour + this.AutonameFileCollisionBehaviours = new BindingList() { AutonameFileCollisionBehaviour.AppendNumber, AutonameFileCollisionBehaviour.Prefix, AutonameFileCollisionBehaviour.Postfix }; + this.SelectedCollisionBehaviour = this.userSettingService.GetUserSetting(UserSettingConstants.AutonameFileCollisionBehaviour, typeof(int)); + this.PrePostFilenameText = this.userSettingService.GetUserSetting(UserSettingConstants.AutonameFilePrePostString); + // ############################# // Picture Tab // ############################# @@ -1598,6 +1650,8 @@ namespace HandBrakeWPF.ViewModels this.userSettingService.SetUserSetting(UserSettingConstants.AutoNameTitleCase, this.ChangeToTitleCase); this.userSettingService.SetUserSetting(UserSettingConstants.RemovePunctuation, this.RemovePunctuation); this.userSettingService.SetUserSetting(UserSettingConstants.FileOverwriteBehaviour, this.SelectedOverwriteBehaviour); + this.userSettingService.SetUserSetting(UserSettingConstants.AutonameFileCollisionBehaviour, this.SelectedCollisionBehaviour); + this.userSettingService.SetUserSetting(UserSettingConstants.AutonameFilePrePostString, this.PrePostFilenameText); /* Previews */ this.userSettingService.SetUserSetting(UserSettingConstants.VLCPath, this.VLCPath); @@ -1712,6 +1766,11 @@ namespace HandBrakeWPF.ViewModels /// True if valid private bool IsValidAutonameFormat(string input, bool isSilent) { + if (string.IsNullOrEmpty(input)) + { + return true; + } + char[] invalidchars = Path.GetInvalidFileNameChars(); Array.Sort(invalidchars); foreach (var characterToTest in input) diff --git a/win/CS/HandBrakeWPF/Views/OptionsView.xaml b/win/CS/HandBrakeWPF/Views/OptionsView.xaml index 7bccf0e1b..e7a3ed1ec 100644 --- a/win/CS/HandBrakeWPF/Views/OptionsView.xaml +++ b/win/CS/HandBrakeWPF/Views/OptionsView.xaml @@ -189,6 +189,13 @@ + + + + + + + diff --git a/win/CS/HandBrakeWPF/defaultsettings.xml b/win/CS/HandBrakeWPF/defaultsettings.xml index 53e077ea4..724dfd336 100644 --- a/win/CS/HandBrakeWPF/defaultsettings.xml +++ b/win/CS/HandBrakeWPF/defaultsettings.xml @@ -529,5 +529,21 @@ 0 - + + + AutonameFileCollisionBehaviour + + + 1 + + + + + AutonameFilePrePostString + + + output_ + + + \ No newline at end of file -- 2.40.0