diff --git a/src/NadekoBot/Modules/Searches/OsuCommands.cs b/src/NadekoBot/Modules/Searches/OsuCommands.cs index 90c075b15..91555a544 100644 --- a/src/NadekoBot/Modules/Searches/OsuCommands.cs +++ b/src/NadekoBot/Modules/Searches/OsuCommands.cs @@ -109,136 +109,16 @@ public partial class Searches await Response().Error("Please provide a username.").SendAsync(); return; } - - using var http = _httpFactory.CreateClient(); - var m = 0; - if (!string.IsNullOrWhiteSpace(mode)) - m = OsuService.ResolveGameMode(mode); - - var reqString = "https://osu.ppy.sh/api/get_user_best" - + $"?k={_creds.OsuApiKey}" - + $"&u={Uri.EscapeDataString(user)}" - + "&type=string" - + "&limit=5" - + $"&m={m}"; - - var resString = await http.GetStringAsync(reqString); - var obj = JsonConvert.DeserializeObject>(resString); - - var mapTasks = obj.Select(async item => - { - var mapReqString = "https://osu.ppy.sh/api/get_beatmaps" - + $"?k={_creds.OsuApiKey}" - + $"&b={item.BeatmapId}"; - - var mapResString = await http.GetStringAsync(mapReqString); - var map = JsonConvert.DeserializeObject>(mapResString).FirstOrDefault(); - if (map is null) - return default; - var pp = Math.Round(item.Pp, 2); - var acc = CalculateAcc(item, m); - var mods = ResolveMods(item.EnabledMods); - - var title = $"{map.Artist}-{map.Title} ({map.Version})"; - var desc = $@"[/b/{item.BeatmapId}](https://osu.ppy.sh/b/{item.BeatmapId}) -{pp + "pp",-7} | {acc + "%",-7} -"; - if (mods != "+") - desc += Format.Bold(mods); - - return (title, desc); - }); + + var plays = await _service.GetOsuPlay(user, mode); + var eb = _sender.CreateEmbed().WithOkColor().WithTitle($"Top 5 plays for {user}"); - var mapData = await mapTasks.WhenAll(); - foreach (var (title, desc) in mapData.Where(x => x != default)) + foreach(var (title, desc) in plays) eb.AddField(title, desc); await Response().Embed(eb).SendAsync(); } - - //https://osu.ppy.sh/wiki/Accuracy - private static double CalculateAcc(OsuUserBests play, int mode) - { - double hitPoints; - double totalHits; - if (mode == 0) - { - hitPoints = (play.Count50 * 50) + (play.Count100 * 100) + (play.Count300 * 300); - totalHits = play.Count50 + play.Count100 + play.Count300 + play.Countmiss; - totalHits *= 300; - } - else if (mode == 1) - { - hitPoints = (play.Countmiss * 0) + (play.Count100 * 0.5) + play.Count300; - totalHits = (play.Countmiss + play.Count100 + play.Count300) * 300; - hitPoints *= 300; - } - else if (mode == 2) - { - hitPoints = play.Count50 + play.Count100 + play.Count300; - totalHits = play.Countmiss + play.Count50 + play.Count100 + play.Count300 + play.Countkatu; - } - else - { - hitPoints = (play.Count50 * 50) - + (play.Count100 * 100) - + (play.Countkatu * 200) - + ((play.Count300 + play.Countgeki) * 300); - - totalHits = (play.Countmiss - + play.Count50 - + play.Count100 - + play.Countkatu - + play.Count300 - + play.Countgeki) - * 300; - } - - - return Math.Round(hitPoints / totalHits * 100, 2); - } - - - //https://github.com/ppy/osu-api/wiki#mods - private static string ResolveMods(int mods) - { - var modString = "+"; - - if (IsBitSet(mods, 0)) - modString += "NF"; - if (IsBitSet(mods, 1)) - modString += "EZ"; - if (IsBitSet(mods, 8)) - modString += "HT"; - - if (IsBitSet(mods, 3)) - modString += "HD"; - if (IsBitSet(mods, 4)) - modString += "HR"; - if (IsBitSet(mods, 6) && !IsBitSet(mods, 9)) - modString += "DT"; - if (IsBitSet(mods, 9)) - modString += "NC"; - if (IsBitSet(mods, 10)) - modString += "FL"; - - if (IsBitSet(mods, 5)) - modString += "SD"; - if (IsBitSet(mods, 14)) - modString += "PF"; - - if (IsBitSet(mods, 7)) - modString += "RX"; - if (IsBitSet(mods, 11)) - modString += "AT"; - if (IsBitSet(mods, 12)) - modString += "SO"; - return modString; - } - - private static bool IsBitSet(int mods, int pos) - => (mods & (1 << pos)) != 0; } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Searches/OsuService.cs b/src/NadekoBot/Modules/Searches/OsuService.cs index 415b63b09..5f1b8bc6a 100644 --- a/src/NadekoBot/Modules/Searches/OsuService.cs +++ b/src/NadekoBot/Modules/Searches/OsuService.cs @@ -40,7 +40,7 @@ public sealed class OsuService : INService public static int ResolveGameMode(string mode) { - switch (mode.ToUpperInvariant()) + switch (mode?.ToUpperInvariant()) { case "STD": case "STANDARD": @@ -97,4 +97,131 @@ public sealed class OsuService : INService return (userData, userStats); } + + public async Task<(string title, string desc)[]> GetOsuPlay(string user, string mode) + { + using var http = _httpFactory.CreateClient(); + var m = 0; + if (!string.IsNullOrWhiteSpace(mode)) + m = OsuService.ResolveGameMode(mode); + + var reqString = "https://osu.ppy.sh/api/get_user_best" + + $"?k={_creds.OsuApiKey}" + + $"&u={Uri.EscapeDataString(user)}" + + "&type=string" + + "&limit=5" + + $"&m={m}"; + + var resString = await http.GetStringAsync(reqString); + var obj = JsonConvert.DeserializeObject>(resString); + + var mapTasks = obj.Select(async item => + { + var mapReqString = "https://osu.ppy.sh/api/get_beatmaps" + + $"?k={_creds.OsuApiKey}" + + $"&b={item.BeatmapId}"; + + var mapResString = await http.GetStringAsync(mapReqString); + var map = JsonConvert.DeserializeObject>(mapResString).FirstOrDefault(); + if (map is null) + return default; + var pp = Math.Round(item.Pp, 2); + var acc = CalculateAcc(item, m); + var mods = ResolveMods(item.EnabledMods); + + var title = $"{map.Artist}-{map.Title} ({map.Version})"; + var desc = $@"[/b/{item.BeatmapId}](https://osu.ppy.sh/b/{item.BeatmapId}) + {pp + "pp",-7} | {acc + "%",-7} + "; + if (mods != "+") + desc += Format.Bold(mods); + + return (title, desc); + }); + + return await Task.WhenAll(mapTasks); + } + + //https://osu.ppy.sh/wiki/Accuracy + private static double CalculateAcc(OsuUserBests play, int mode) + { + double hitPoints; + double totalHits; + if (mode == 0) + { + hitPoints = (play.Count50 * 50) + (play.Count100 * 100) + (play.Count300 * 300); + totalHits = play.Count50 + play.Count100 + play.Count300 + play.Countmiss; + totalHits *= 300; + } + else if (mode == 1) + { + hitPoints = (play.Countmiss * 0) + (play.Count100 * 0.5) + play.Count300; + totalHits = (play.Countmiss + play.Count100 + play.Count300) * 300; + hitPoints *= 300; + } + else if (mode == 2) + { + hitPoints = play.Count50 + play.Count100 + play.Count300; + totalHits = play.Countmiss + play.Count50 + play.Count100 + play.Count300 + play.Countkatu; + } + else + { + hitPoints = (play.Count50 * 50) + + (play.Count100 * 100) + + (play.Countkatu * 200) + + ((play.Count300 + play.Countgeki) * 300); + + totalHits = (play.Countmiss + + play.Count50 + + play.Count100 + + play.Countkatu + + play.Count300 + + play.Countgeki) + * 300; + } + + + return Math.Round(hitPoints / totalHits * 100, 2); + } + + + //https://github.com/ppy/osu-api/wiki#mods + private static string ResolveMods(int mods) + { + var modString = "+"; + + if (IsBitSet(mods, 0)) + modString += "NF"; + if (IsBitSet(mods, 1)) + modString += "EZ"; + if (IsBitSet(mods, 8)) + modString += "HT"; + + if (IsBitSet(mods, 3)) + modString += "HD"; + if (IsBitSet(mods, 4)) + modString += "HR"; + if (IsBitSet(mods, 6) && !IsBitSet(mods, 9)) + modString += "DT"; + if (IsBitSet(mods, 9)) + modString += "NC"; + if (IsBitSet(mods, 10)) + modString += "FL"; + + if (IsBitSet(mods, 5)) + modString += "SD"; + if (IsBitSet(mods, 14)) + modString += "PF"; + + if (IsBitSet(mods, 7)) + modString += "RX"; + if (IsBitSet(mods, 11)) + modString += "AT"; + if (IsBitSet(mods, 12)) + modString += "SO"; + return modString; + } + + private static bool IsBitSet(int mods, int pos) + => (mods & (1 << pos)) != 0; } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Searches/_common/GatariUserStatsResponse.cs b/src/NadekoBot/Modules/Searches/_common/GatariUserStatsResponse.cs index 3a8dd0651..b3d7b2f41 100644 --- a/src/NadekoBot/Modules/Searches/_common/GatariUserStatsResponse.cs +++ b/src/NadekoBot/Modules/Searches/_common/GatariUserStatsResponse.cs @@ -39,7 +39,7 @@ public class GatariUserStats public int Pp { get; set; } [JsonProperty("rank")] - public int Rank { get; set; } + public int? Rank { get; set; } [JsonProperty("ranked_score")] public int RankedScore { get; set; }