From 00561c98b70ab9d48bb0f8ccc8e9a211dda44e63 Mon Sep 17 00:00:00 2001 From: Assistant Date: Tue, 5 May 2020 13:43:50 -0600 Subject: [PATCH] Refactored OneClick Install code --- .../Classes/External Interfaces/BeatSaver.cs | 171 +++++++++++++++ .../Classes/External Interfaces/ModelSaber.cs | 34 +++ .../Classes/External Interfaces/Utils.cs | 46 ++++ ModAssistant/Classes/OneClickInstaller.cs | 203 +----------------- ModAssistant/ModAssistant.csproj | 3 + 5 files changed, 256 insertions(+), 201 deletions(-) create mode 100644 ModAssistant/Classes/External Interfaces/BeatSaver.cs create mode 100644 ModAssistant/Classes/External Interfaces/ModelSaber.cs create mode 100644 ModAssistant/Classes/External Interfaces/Utils.cs diff --git a/ModAssistant/Classes/External Interfaces/BeatSaver.cs b/ModAssistant/Classes/External Interfaces/BeatSaver.cs new file mode 100644 index 0000000..4842a77 --- /dev/null +++ b/ModAssistant/Classes/External Interfaces/BeatSaver.cs @@ -0,0 +1,171 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Threading.Tasks; +using System.Windows; +using static ModAssistant.Http; + +namespace ModAssistant.API +{ + public class BeatSaver + { + private const string BeatSaverURLPrefix = "https://beatsaver.com"; + private static readonly string CustomSongsFolder = Path.Combine("Beat Saber_Data", "CustomLevels"); + private const bool BypassDownloadCounter = false; + + public static async Task GetFromKey(string Key) + { + BeatSaverApiResponse Map = await GetResponse(BeatSaverURLPrefix + "/api/maps/detail/" + Key); + await InstallMap(Map); + } + + public static async Task GetFromHash(string Hash) + { + BeatSaverApiResponse Map = await GetResponse(BeatSaverURLPrefix + "/api/maps/by-hash/" + Hash); + await InstallMap(Map); + } + + private static async Task GetResponse(string url) + { + try + { + var resp = await HttpClient.GetAsync(url); + var body = await resp.Content.ReadAsStringAsync(); + + return JsonSerializer.Deserialize(body); + } + catch (Exception e) + { + MessageBox.Show($"{Application.Current.FindResource("OneClick:MapDownloadFailed")}\n\n" + e); + return null; + } + } + + public static async Task InstallMap(BeatSaverApiResponse Map) + { + string zip = Path.Combine(Utils.BeatSaberPath, CustomSongsFolder, Map.hash) + ".zip"; + string mapName = string.Concat(($"{Map.key} ({Map.metadata.songName} - {Map.metadata.levelAuthorName})") + .Split(ModAssistant.Utils.Constants.IllegalCharacters)); + string directory = Path.Combine(Utils.BeatSaberPath, CustomSongsFolder, mapName); + + if (BypassDownloadCounter) + { + await Utils.DownloadAsset(BeatSaverURLPrefix + Map.directDownload, CustomSongsFolder, Map.hash + ".zip", mapName); + } + else + { + await Utils.DownloadAsset(BeatSaverURLPrefix + Map.downloadURL, CustomSongsFolder, Map.hash + ".zip", mapName); + } + + if (File.Exists(zip)) + { + using (FileStream stream = new FileStream(zip, FileMode.Open)) + using (ZipArchive archive = new ZipArchive(stream)) + { + foreach (ZipArchiveEntry file in archive.Entries) + { + string fileDirectory = Path.GetDirectoryName(Path.Combine(directory, file.FullName)); + if (!Directory.Exists(fileDirectory)) + { + Directory.CreateDirectory(fileDirectory); + } + + if (!string.IsNullOrEmpty(file.Name)) + { + file.ExtractToFile(Path.Combine(directory, file.FullName), true); + } + } + } + + File.Delete(zip); + } + else + { + string line1 = (string)Application.Current.FindResource("OneClick:SongDownload:Failed"); + string line2 = (string)Application.Current.FindResource("OneClick:SongDownload:NetworkIssues"); + string title = (string)Application.Current.FindResource("OneClick:SongDownload:FailedTitle"); + MessageBox.Show($"{line1}\n{line2}", title); + } + } + + public class BeatSaverApiResponse + { + public Metadata metadata { get; set; } + public Stats stats { get; set; } + public string description { get; set; } + public DateTime? deletedAt { get; set; } + public string _id { get; set; } + public string key { get; set; } + public string name { get; set; } + public Uploader uploader { get; set; } + public DateTime uploaded { get; set; } + public string hash { get; set; } + public string directDownload { get; set; } + public string downloadURL { get; set; } + public string coverURL { get; set; } + + public class Difficulties + { + public bool easy { get; set; } + public bool normal { get; set; } + public bool hard { get; set; } + public bool expert { get; set; } + public bool expertPlus { get; set; } + } + + public class Metadata + { + public Difficulties difficulties { get; set; } + public Characteristic[] characteristics { get; set; } + public double duration { get; set; } + public string songName { get; set; } + public string songSubName { get; set; } + public string songAuthorName { get; set; } + public string levelAuthorName { get; set; } + public double bpm { get; set; } + } + + public class Characteristic + { + public string name { get; set; } + public CharacteristicDifficulties difficulties { get; set; } + } + + public class CharacteristicDifficulties + { + public Difficulty easy { get; set; } + public Difficulty normal { get; set; } + public Difficulty hard { get; set; } + public Difficulty expert { get; set; } + public Difficulty expertPlus { get; set; } + } + + public class Difficulty + { + public double? duration { get; set; } + public double? length { get; set; } + public double bombs { get; set; } + public double notes { get; set; } + public double obstacles { get; set; } + public double njs { get; set; } + public double njsOffset { get; set; } + } + + public class Stats + { + public int downloads { get; set; } + public int plays { get; set; } + public int downVotes { get; set; } + public int upVotes { get; set; } + public double heat { get; set; } + public double rating { get; set; } + } + + public class Uploader + { + public string _id { get; set; } + public string username { get; set; } + } + } + } +} diff --git a/ModAssistant/Classes/External Interfaces/ModelSaber.cs b/ModAssistant/Classes/External Interfaces/ModelSaber.cs new file mode 100644 index 0000000..f3da082 --- /dev/null +++ b/ModAssistant/Classes/External Interfaces/ModelSaber.cs @@ -0,0 +1,34 @@ +using System; +using System.Threading.Tasks; + +namespace ModAssistant.API +{ + class ModelSaber + { + private const string ModelSaberURLPrefix = "https://modelsaber.com/files/"; + private const string CustomAvatarsFolder = "CustomAvatars"; + private const string CustomSabersFolder = "CustomSabers"; + private const string CustomPlatformsFolder = "CustomPlatforms"; + private const string CustomBloqsFolder = "CustomNotes"; + + public static async Task GetModel(Uri uri) + { + switch (uri.Host) + { + case "avatar": + await Utils.DownloadAsset(ModelSaberURLPrefix + uri.Host + uri.AbsolutePath, CustomAvatarsFolder); + break; + case "saber": + await Utils.DownloadAsset(ModelSaberURLPrefix + uri.Host + uri.AbsolutePath, CustomSabersFolder); + break; + case "platform": + await Utils.DownloadAsset(ModelSaberURLPrefix + uri.Host + uri.AbsolutePath, CustomPlatformsFolder); + break; + case "bloq": + await Utils.DownloadAsset(ModelSaberURLPrefix + uri.Host + uri.AbsolutePath, CustomBloqsFolder); + break; + } + } + + } +} diff --git a/ModAssistant/Classes/External Interfaces/Utils.cs b/ModAssistant/Classes/External Interfaces/Utils.cs new file mode 100644 index 0000000..282481b --- /dev/null +++ b/ModAssistant/Classes/External Interfaces/Utils.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using System.Windows; + +namespace ModAssistant.API +{ + public class Utils + { + public static readonly string BeatSaberPath = App.BeatSaberInstallDirectory; + + public static async Task DownloadAsset(string link, string folder, string fileName = null, string displayName = null) + { + if (string.IsNullOrEmpty(displayName)) + { + displayName = Path.GetFileNameWithoutExtension(fileName); + } + if (string.IsNullOrEmpty(BeatSaberPath)) + { + ModAssistant.Utils.SendNotify((string)Application.Current.FindResource("OneClick:InstallDirNotFound")); + } + try + { + Directory.CreateDirectory(Path.Combine(BeatSaberPath, folder)); + if (string.IsNullOrEmpty(fileName)) + { + fileName = WebUtility.UrlDecode(Path.Combine(BeatSaberPath, folder, new Uri(link).Segments.Last())); + } + else + { + fileName = WebUtility.UrlDecode(Path.Combine(BeatSaberPath, folder, fileName)); + } + + await ModAssistant.Utils.Download(link, fileName); + ModAssistant.Utils.SendNotify(string.Format((string)Application.Current.FindResource("OneClick:InstalledAsset"), displayName)); + } + catch + { + ModAssistant.Utils.SendNotify((string)Application.Current.FindResource("OneClick:AssetInstallFailed")); + } + } + + } +} diff --git a/ModAssistant/Classes/OneClickInstaller.cs b/ModAssistant/Classes/OneClickInstaller.cs index 89b3d4d..9c34a6b 100644 --- a/ModAssistant/Classes/OneClickInstaller.cs +++ b/ModAssistant/Classes/OneClickInstaller.cs @@ -1,31 +1,15 @@ using Microsoft.Win32; using System; -using System.IO; -using System.IO.Compression; using System.Linq; -using System.Net; using System.Threading.Tasks; using System.Windows; -using static ModAssistant.Http; namespace ModAssistant { class OneClickInstaller { - private const string ModelSaberURLPrefix = "https://modelsaber.com/files/"; - private const string BeatSaverURLPrefix = "https://beatsaver.com"; - - private static readonly string BeatSaberPath = App.BeatSaberInstallDirectory; - - private const string CustomAvatarsFolder = "CustomAvatars"; - private const string CustomSabersFolder = "CustomSabers"; - private const string CustomPlatformsFolder = "CustomPlatforms"; - private const string CustomBloqsFolder = "CustomNotes"; - private static readonly string CustomSongsFolder = Path.Combine("Beat Saber_Data", "CustomLevels"); - private static readonly string[] Protocols = new[] { "modelsaber", "beatsaver" }; - private const bool BypassDownloadCounter = false; public static async Task InstallAsset(string link) { Uri uri = new Uri(link); @@ -45,115 +29,12 @@ namespace ModAssistant private static async Task BeatSaver(Uri uri) { string Key = uri.Host; - BeatSaverApiResponse Response; - - try - { - var resp = await HttpClient.GetAsync(BeatSaverURLPrefix + "/api/maps/detail/" + Key); - var body = await resp.Content.ReadAsStringAsync(); - - Response = JsonSerializer.Deserialize(body); - } - catch (Exception e) - { - MessageBox.Show($"{Application.Current.FindResource("OneClick:MapDownloadFailed")}\n\n" + e); - return; - } - - string zip = Path.Combine(BeatSaberPath, CustomSongsFolder, Response.hash) + ".zip"; - string directory = Path.Combine( - BeatSaberPath, - CustomSongsFolder, - string.Concat( - (Response.key + " (" + Response.metadata.songName + " - " + Response.metadata.levelAuthorName + ")") - .Split(Utils.Constants.IllegalCharacters) - ) - ); - - if (BypassDownloadCounter) - { - await DownloadAsset(BeatSaverURLPrefix + Response.directDownload, CustomSongsFolder, Response.hash + ".zip"); - } - else - { - await DownloadAsset(BeatSaverURLPrefix + Response.downloadURL, CustomSongsFolder, Response.hash + ".zip"); - } - - if (File.Exists(zip)) - { - using (FileStream stream = new FileStream(zip, FileMode.Open)) - using (ZipArchive archive = new ZipArchive(stream)) - { - foreach (ZipArchiveEntry file in archive.Entries) - { - string fileDirectory = Path.GetDirectoryName(Path.Combine(directory, file.FullName)); - if (!Directory.Exists(fileDirectory)) - { - Directory.CreateDirectory(fileDirectory); - } - - if (!string.IsNullOrEmpty(file.Name)) - { - file.ExtractToFile(Path.Combine(directory, file.FullName), true); - } - } - } - - File.Delete(zip); - } - else - { - string line1 = (string)Application.Current.FindResource("OneClick:SongDownload:Failed"); - string line2 = (string)Application.Current.FindResource("OneClick:SongDownload:NetworkIssues"); - string title = (string)Application.Current.FindResource("OneClick:SongDownload:FailedTitle"); - MessageBox.Show($"{line1}\n{line2}", title); - } + await API.BeatSaver.GetFromKey(Key); } private static async Task ModelSaber(Uri uri) { - switch (uri.Host) - { - case "avatar": - await DownloadAsset(ModelSaberURLPrefix + uri.Host + uri.AbsolutePath, CustomAvatarsFolder); - break; - case "saber": - await DownloadAsset(ModelSaberURLPrefix + uri.Host + uri.AbsolutePath, CustomSabersFolder); - break; - case "platform": - await DownloadAsset(ModelSaberURLPrefix + uri.Host + uri.AbsolutePath, CustomPlatformsFolder); - break; - case "bloq": - await DownloadAsset(ModelSaberURLPrefix + uri.Host + uri.AbsolutePath, CustomBloqsFolder); - break; - } - } - - private static async Task DownloadAsset(string link, string folder, string fileName = null) - { - if (string.IsNullOrEmpty(BeatSaberPath)) - { - Utils.SendNotify((string)Application.Current.FindResource("OneClick:InstallDirNotFound")); - } - try - { - Directory.CreateDirectory(Path.Combine(BeatSaberPath, folder)); - if (string.IsNullOrEmpty(fileName)) - { - fileName = WebUtility.UrlDecode(Path.Combine(BeatSaberPath, folder, new Uri(link).Segments.Last())); - } - else - { - fileName = WebUtility.UrlDecode(Path.Combine(BeatSaberPath, folder, fileName)); - } - - await Utils.Download(link, fileName); - Utils.SendNotify(string.Format((string)Application.Current.FindResource("OneClick:InstalledAsset"), Path.GetFileNameWithoutExtension(fileName))); - } - catch - { - Utils.SendNotify((string)Application.Current.FindResource("OneClick:AssetInstallFailed")); - } + await API.ModelSaber.GetModel(uri); } public static void Register(string Protocol, bool Background = false) @@ -242,84 +123,4 @@ namespace ModAssistant return false; } } - -#pragma warning disable IDE1006 // Naming Styles - class BeatSaverApiResponse - { - public Metadata metadata { get; set; } - public Stats stats { get; set; } - public string description { get; set; } - public DateTime? deletedAt { get; set; } - public string _id { get; set; } - public string key { get; set; } - public string name { get; set; } - public Uploader uploader { get; set; } - public DateTime uploaded { get; set; } - public string hash { get; set; } - public string directDownload { get; set; } - public string downloadURL { get; set; } - public string coverURL { get; set; } - - public class Difficulties - { - public bool easy { get; set; } - public bool normal { get; set; } - public bool hard { get; set; } - public bool expert { get; set; } - public bool expertPlus { get; set; } - } - - public class Metadata - { - public Difficulties difficulties { get; set; } - public Characteristic[] characteristics { get; set; } - public string songName { get; set; } - public string songSubName { get; set; } - public string songAuthorName { get; set; } - public string levelAuthorName { get; set; } - public double bpm { get; set; } - } - - public class Characteristic - { - public string name { get; set; } - public CharacteristicDifficulties difficulties { get; set; } - } - - public class CharacteristicDifficulties - { - public Difficulty easy { get; set; } - public Difficulty normal { get; set; } - public Difficulty hard { get; set; } - public Difficulty expert { get; set; } - public Difficulty expertPlus { get; set; } - } - - public class Difficulty - { - public double? duration { get; set; } - public double? length { get; set; } - public double bombs { get; set; } - public double notes { get; set; } - public double obstacles { get; set; } - public double njs { get; set; } - } - - public class Stats - { - public int downloads { get; set; } - public int plays { get; set; } - public int downVotes { get; set; } - public int upVotes { get; set; } - public double heat { get; set; } - public double rating { get; set; } - } - - public class Uploader - { - public string _id { get; set; } - public string username { get; set; } - } - } } -#pragma warning restore IDE1006 // Naming Styles diff --git a/ModAssistant/ModAssistant.csproj b/ModAssistant/ModAssistant.csproj index 60c4b76..ec0f7cb 100644 --- a/ModAssistant/ModAssistant.csproj +++ b/ModAssistant/ModAssistant.csproj @@ -65,6 +65,9 @@ MSBuild:Compile Designer + + +