// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // The User Setting Service // // -------------------------------------------------------------------------------------------------------------------- namespace HandBrakeWPF.Services { using System; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Linq; using System.Reflection; using System.Xml.Serialization; using HandBrake.Interop.Model; using HandBrake.Interop.Utilities; using HandBrakeWPF.Collections; using HandBrakeWPF.Extensions; using HandBrakeWPF.Properties; using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.Utilities; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using GeneralApplicationException = Exceptions.GeneralApplicationException; using SettingChangedEventArgs = EventArgs.SettingChangedEventArgs; /// /// The User Setting Service /// public class UserSettingService : IUserSettingService { private readonly string settingsFile = Path.Combine(DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()), "settings.json"); private readonly string releaseSettingsFile = Path.Combine(DirectoryUtilities.GetUserStoragePath(false), "settings.json"); private readonly string nightlySettingsFile = Path.Combine(DirectoryUtilities.GetUserStoragePath(true), "settings.json"); private readonly JsonSerializerSettings settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; private Dictionary userSettings; /// /// Initializes a new instance of the class. /// public UserSettingService() { this.Load(); } /// /// The setting changed. /// public event SettingEventHandler SettingChanged; /// /// Set the specified user setting. /// /// /// Name of the property /// /// /// The value to store. /// public void SetUserSetting(string name, object value) { this.userSettings[name] = value; this.Save(); this.OnSettingChanged(new SettingChangedEventArgs { Key = name, Value = value }); } /// /// Get user setting for a given key. /// /// /// The name. /// /// /// The conversion Type. /// /// /// The Type of the setting /// /// /// The user setting /// public T GetUserSetting(string name, Type conversionType = null) { if (this.userSettings.ContainsKey(name)) { if (conversionType != null && typeof(int) == conversionType) { object storedValue = this.userSettings[name]; object converted = storedValue?.ToString().ToInt(); return (T)converted; } // Treat String Arrays as StringCollections. TODO refactor upstream code to more traditional string arrays. object settingValue = this.userSettings[name]; if (settingValue != null && settingValue.GetType() == typeof(JArray)) { string[] stringArr = ((JArray)settingValue).ToObject(); StringCollection stringCollection = new StringCollection(); foreach (var item in stringArr) { stringCollection.Add(item); } settingValue = stringCollection; } return (T)settingValue; } return default(T); } /// /// The on setting changed. /// /// /// The e. /// protected virtual void OnSettingChanged(SettingChangedEventArgs e) { SettingEventHandler handler = this.SettingChanged; if (handler != null) { handler(this, e); } } /// /// Save the User Settings /// private void Save() { try { string directory = Path.GetDirectoryName(this.settingsFile); if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { Directory.CreateDirectory(directory); } using (StreamWriter file = new StreamWriter(new FileStream(this.settingsFile, FileMode.Create, FileAccess.Write))) { string appSettings = JsonConvert.SerializeObject(this.userSettings, Formatting.Indented, this.settings); file.Write(appSettings); } } catch (Exception exc) { throw new GeneralApplicationException( Resources.UserSettings_AnErrorOccured, Resources.SettingService_SaveErrorReset, exc); } } /// /// Load the User Settings /// private void Load() { try { // Load up the users current settings file. if (File.Exists(this.settingsFile)) { using (StreamReader reader = new StreamReader(this.settingsFile)) { string appSettings = reader.ReadToEnd(); Dictionary deserialisedSettings = JsonConvert.DeserializeObject< Dictionary>(appSettings); this.userSettings = deserialisedSettings; } } else if (VersionHelper.IsNightly() && File.Exists(this.releaseSettingsFile)) { // Port the release versions config to the nightly. if (!Directory.Exists(DirectoryUtilities.GetUserStoragePath(true))) { Directory.CreateDirectory(DirectoryUtilities.GetUserStoragePath(true)); } File.Copy(this.releaseSettingsFile, this.nightlySettingsFile); using (StreamReader reader = new StreamReader(this.settingsFile)) { string appSettings = reader.ReadToEnd(); Dictionary deserialisedSettings = JsonConvert.DeserializeObject>(appSettings); this.userSettings = deserialisedSettings; } } else { this.userSettings = new Dictionary(); } // Add any missing / new settings SerializableDictionary defaults = this.GetDefaults(); foreach (var item in defaults.Where(item => !this.userSettings.Keys.Contains(item.Key))) { this.userSettings.Add(item.Key, item.Value); this.Save(); } // Legacy Settings forced Reset. this.userSettings[UserSettingConstants.ScalingMode] = VideoScaler.Lanczos; } catch (Exception exc) { try { this.userSettings = this.GetDefaults(); if (File.Exists(this.settingsFile)) { File.Delete(this.settingsFile); } this.Save(); throw new GeneralApplicationException(Resources.UserSettings_YourSettingsHaveBeenReset, Resources.UserSettings_YourSettingsAreCorrupt, exc); } catch (Exception) { throw new GeneralApplicationException(string.Format(Resources.UserSettings_UnableToLoad, this.settingsFile), Resources.UserSettings_UnableToLoadSolution, exc); } } } /// /// Load Default Settings /// /// /// The get defaults. /// private SerializableDictionary GetDefaults() { // TODO Convert this to JSON. try { Assembly assembly = Assembly.GetEntryAssembly(); Stream stream = assembly.GetManifestResourceStream("HandBrakeWPF.defaultsettings.xml"); if (stream != null) { XmlSerializer serializer = new XmlSerializer(typeof(Collections.SerializableDictionary)); return (SerializableDictionary)serializer.Deserialize(stream); } } catch (Exception) { return new SerializableDictionary(); } return new SerializableDictionary(); } } }