SongBrowserSettings.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. using SongBrowserPlugin.UI;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Text;
  6. using System.Xml;
  7. using System.Xml.Serialization;
  8. using SongBrowserPlugin.Logging;
  9. using Logger = SongBrowserPlugin.Logging.Logger;
  10. namespace SongBrowserPlugin.DataAccess
  11. {
  12. [Serializable]
  13. public enum SongSortMode
  14. {
  15. Default,
  16. Author,
  17. Original,
  18. Newest,
  19. PlayCount,
  20. Difficulty,
  21. Random,
  22. PP,
  23. // Deprecated
  24. Favorites,
  25. Playlist,
  26. Search
  27. }
  28. [Serializable]
  29. public enum SongFilterMode
  30. {
  31. None,
  32. Favorites,
  33. Playlist,
  34. Search
  35. }
  36. [Serializable]
  37. public class SongBrowserSettings
  38. {
  39. public static readonly Encoding Utf8Encoding = Encoding.UTF8;
  40. public static readonly XmlSerializer SettingsSerializer = new XmlSerializer(typeof(SongBrowserSettings));
  41. public static readonly String DefaultConvertedFavoritesPlaylistName = "SongBrowserPluginFavorites.json";
  42. public SongSortMode sortMode = default(SongSortMode);
  43. public SongFilterMode filterMode = default(SongFilterMode);
  44. private HashSet<String> _favorites = default(HashSet<String>);
  45. public List<String> searchTerms = default(List<String>);
  46. public String currentLevelId = default(String);
  47. public String currentDirectory = default(String);
  48. public String currentPlaylistFile = default(String);
  49. public String currentEditingPlaylistFile = default(String);
  50. public bool folderSupportEnabled = false;
  51. public bool randomInstantQueue = false;
  52. public bool deleteNumberedSongFolder = true;
  53. public int randomSongSeed;
  54. public bool invertSortResults = false;
  55. [XmlIgnore]
  56. [NonSerialized]
  57. public bool DisableSavingSettings = false;
  58. [XmlArray(@"favorites")]
  59. public HashSet<String> Favorites
  60. {
  61. get
  62. {
  63. return _favorites;
  64. }
  65. }
  66. /// <summary>
  67. /// Constructor.
  68. /// </summary>
  69. public SongBrowserSettings()
  70. {
  71. searchTerms = new List<string>();
  72. _favorites = new HashSet<String>();
  73. }
  74. /// <summary>
  75. /// Helper to acquire settings path at runtime.
  76. /// </summary>
  77. /// <returns></returns>
  78. public static String SettingsPath()
  79. {
  80. return Path.Combine(Environment.CurrentDirectory, "song_browser_settings.xml");
  81. }
  82. /// <summary>
  83. /// Backup settings file location.
  84. /// </summary>
  85. /// <returns></returns>
  86. public static String SettingsBackupPath()
  87. {
  88. return Path.Combine(Environment.CurrentDirectory, "song_browser_settings.xml.bak");
  89. }
  90. /// <summary>
  91. /// Path to the common favorites file location.
  92. /// </summary>
  93. /// <returns></returns>
  94. public static String DownloaderFavoritesFilePath()
  95. {
  96. return Path.Combine(Environment.CurrentDirectory, "favoriteSongs.cfg");
  97. }
  98. /// <summary>
  99. /// Load the settings file for this plugin.
  100. /// If we fail to load return Default settings.
  101. /// </summary>
  102. /// <returns>SongBrowserSettings</returns>
  103. public static SongBrowserSettings Load()
  104. {
  105. Logger.Trace("Load()");
  106. SongBrowserSettings retVal = null;
  107. // No Settings file.
  108. String settingsFilePath = SongBrowserSettings.SettingsPath();
  109. if (File.Exists(settingsFilePath))
  110. {
  111. // Deserialization from JSON
  112. FileStream fs = null;
  113. try
  114. {
  115. fs = File.OpenRead(settingsFilePath);
  116. XmlSerializer serializer = new XmlSerializer(typeof(SongBrowserSettings));
  117. retVal = (SongBrowserSettings)serializer.Deserialize(fs);
  118. // Success loading, sane time to make a backup
  119. retVal.SaveBackup();
  120. }
  121. catch (Exception e)
  122. {
  123. Logger.Exception("Unable to deserialize song browser settings file, using default settings: ", e);
  124. retVal = new SongBrowserSettings
  125. {
  126. DisableSavingSettings = true
  127. };
  128. }
  129. finally
  130. {
  131. if (fs != null) { fs.Close(); }
  132. }
  133. }
  134. else
  135. {
  136. Logger.Debug("Settings file does not exist, returning defaults: " + settingsFilePath);
  137. retVal = new SongBrowserSettings();
  138. }
  139. // check if the playlist directory exists, make it otherwise.
  140. String playlistDirPath = Path.Combine(Environment.CurrentDirectory, "Playlists");
  141. if (!Directory.Exists(playlistDirPath))
  142. {
  143. Directory.CreateDirectory(playlistDirPath);
  144. }
  145. // Load Downloader favorites but only once, we'll convert them once, empty the song_browser_setting.xml favorites and never load it again.
  146. String playlistPath = Path.Combine(Environment.CurrentDirectory, "Playlists", DefaultConvertedFavoritesPlaylistName);
  147. if (!File.Exists(playlistPath))
  148. {
  149. if (File.Exists(SongBrowserSettings.DownloaderFavoritesFilePath()))
  150. {
  151. String[] downloaderFavorites = File.ReadAllLines(SongBrowserSettings.DownloaderFavoritesFilePath());
  152. retVal.Favorites.UnionWith(downloaderFavorites);
  153. }
  154. }
  155. if (String.IsNullOrEmpty(retVal.currentEditingPlaylistFile))
  156. {
  157. retVal.currentEditingPlaylistFile = playlistPath;
  158. }
  159. return retVal;
  160. }
  161. /// <summary>
  162. /// Favorites used to exist as part of the song_browser_settings.xml
  163. /// This makes little sense now. This is the upgrade path.
  164. /// Convert all existing favorites to the best of our effort into a playlist.
  165. /// </summary>
  166. /// <param name="levelIdToCustomLevel"></param>
  167. /// <param name="levelIdToSongVersion"></param>
  168. public void ConvertFavoritesToPlaylist(Dictionary<String, SongLoaderPlugin.OverrideClasses.CustomLevel> levelIdToCustomLevel,
  169. Dictionary<string, string> levelIdToSongVersion)
  170. {
  171. // Check if we have favorites to convert to the playlist
  172. if (this.Favorites.Count <= 0)
  173. {
  174. return;
  175. }
  176. // check if the playlist exists
  177. String playlistPath = Path.Combine(Environment.CurrentDirectory, "Playlists", DefaultConvertedFavoritesPlaylistName);
  178. bool playlistExists = false;
  179. if (File.Exists(playlistPath))
  180. {
  181. playlistExists = true;
  182. }
  183. // abort here if playlist already exits.
  184. if (playlistExists)
  185. {
  186. Logger.Info("Not converting song_browser_setting.xml favorites because {0} already exists...", playlistPath);
  187. return;
  188. }
  189. Logger.Info("Converting {0} Favorites in song_browser_settings.xml to {1}...", this.Favorites.Count, playlistPath);
  190. // written like this in case we ever want to support adding to this playlist
  191. Playlist p = null;
  192. if (playlistExists)
  193. {
  194. p = PlaylistsReader.ParsePlaylist(playlistPath);
  195. }
  196. else
  197. {
  198. p = new Playlist
  199. {
  200. Title = "Song Browser Favorites",
  201. Author = "SongBrowserPlugin",
  202. Path = "",
  203. Image = Base64Sprites.PlaylistIconB64,
  204. Songs = new List<PlaylistSong>(),
  205. };
  206. }
  207. List<String> successfullyRemoved = new List<string>();
  208. this.Favorites.RemoveWhere(levelId =>
  209. {
  210. PlaylistSong playlistSong = new PlaylistSong
  211. {
  212. LevelId = levelId
  213. };
  214. if (levelIdToCustomLevel.ContainsKey(levelId) && levelIdToSongVersion.ContainsKey(levelId))
  215. {
  216. playlistSong.SongName = levelIdToCustomLevel[levelId].songName;
  217. playlistSong.Key = levelIdToSongVersion[levelId];
  218. }
  219. else
  220. {
  221. // No easy way to look up original songs... They will still work but have wrong song name in playlist.
  222. playlistSong.SongName = levelId;
  223. playlistSong.Key = "";
  224. }
  225. p.Songs.Add(playlistSong);
  226. return true;
  227. });
  228. PlaylistWriter.WritePlaylist(p, playlistPath);
  229. if (String.IsNullOrEmpty(this.currentEditingPlaylistFile))
  230. {
  231. this.currentEditingPlaylistFile = playlistPath;
  232. }
  233. this.Save();
  234. }
  235. /// <summary>
  236. /// Save this Settings insance to file.
  237. /// </summary>
  238. public void Save()
  239. {
  240. this._Save(SongBrowserSettings.SettingsPath());
  241. }
  242. /// <summary>
  243. /// Save a backup.
  244. /// </summary>
  245. public void SaveBackup()
  246. {
  247. this._Save(SongBrowserSettings.SettingsBackupPath());
  248. }
  249. /// <summary>
  250. /// Save helper.
  251. /// </summary>
  252. private void _Save(String path)
  253. {
  254. if (this.DisableSavingSettings)
  255. {
  256. Logger.Info("Saving settings has been disabled...");
  257. return;
  258. }
  259. // TODO - not here
  260. if (searchTerms.Count > 10)
  261. {
  262. searchTerms.RemoveRange(10, searchTerms.Count - 10);
  263. }
  264. var settings = new XmlWriterSettings
  265. {
  266. OmitXmlDeclaration = false,
  267. Indent = true,
  268. NewLineOnAttributes = true,
  269. NewLineHandling = System.Xml.NewLineHandling.Entitize
  270. };
  271. using (var stream = new StreamWriter(path, false, Utf8Encoding))
  272. {
  273. using (var writer = XmlWriter.Create(stream, settings))
  274. {
  275. SettingsSerializer.Serialize(writer, this);
  276. }
  277. }
  278. }
  279. }
  280. }