diff --git a/.gitignore b/.gitignore index 0950c7f2..4042b16d 100644 --- a/.gitignore +++ b/.gitignore @@ -353,4 +353,5 @@ healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ -# End of https://www.gitignore.io/api/visualstudio \ No newline at end of file +# End of https://www.gitignore.io/api/visualstudio +src/FlawBOT.Core/config.json diff --git a/src/FlawBOT/Common/HelpFormatter.cs b/src/FlawBOT.Core/Common/HelpFormatter.cs similarity index 98% rename from src/FlawBOT/Common/HelpFormatter.cs rename to src/FlawBOT.Core/Common/HelpFormatter.cs index 81718cdb..6fa7044d 100644 --- a/src/FlawBOT/Common/HelpFormatter.cs +++ b/src/FlawBOT.Core/Common/HelpFormatter.cs @@ -1,11 +1,11 @@ -using DSharpPlus; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using DSharpPlus; using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Converters; using DSharpPlus.CommandsNext.Entities; using DSharpPlus.Entities; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace FlawBOT.Common { diff --git a/src/FlawBOT/Common/SharedData.cs b/src/FlawBOT.Core/Common/SharedData.cs similarity index 50% rename from src/FlawBOT/Common/SharedData.cs rename to src/FlawBOT.Core/Common/SharedData.cs index ccce1cdd..8eb4540f 100644 --- a/src/FlawBOT/Common/SharedData.cs +++ b/src/FlawBOT.Core/Common/SharedData.cs @@ -1,23 +1,16 @@ -using DSharpPlus.Entities; -using FlawBOT.Models; -using Steam.Models.TF2; -using System; -using System.Collections.Generic; +using System; using System.Reflection; +using DSharpPlus.Entities; namespace FlawBOT.Common { public class SharedData { - public static string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name; + public static string Name { get; } = "FlawBOT"; public static string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString(); public static string GitHubLink { get; set; } = "https://github.com/CriticalFlaw/FlawBOT/"; public static string InviteLink { get; } = "https://discordapp.com/oauth2/authorize?client_id=339833029013012483&scope=bot&permissions=66186303"; public static DiscordColor DefaultColor { get; set; } = new DiscordColor("#00FF7F"); public static DateTime ProcessStarted { get; set; } - public static Dictionary SteamAppList { get; set; } = new Dictionary(); - public static Dictionary TF2ItemSchema { get; set; } = new Dictionary(); - public static List PokemonList { get; set; } = new List(); - public static TokenData Tokens { get; set; } = new TokenData(); } } \ No newline at end of file diff --git a/src/FlawBOT.Core/Dockerfile b/src/FlawBOT.Core/Dockerfile new file mode 100644 index 00000000..18cb0962 --- /dev/null +++ b/src/FlawBOT.Core/Dockerfile @@ -0,0 +1,20 @@ +FROM mcr.microsoft.com/dotnet/core/runtime:2.2-stretch-slim AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build +WORKDIR /src +COPY ["FlawBOT.Core/FlawBOT.Core.csproj", "FlawBOT.Core/"] +COPY ["FlawBOT.Core/NuGet.Config", "FlawBOT.Core/"] +COPY ["FlawBOT.Framework/FlawBOT.Framework.csproj", "FlawBOT.Framework/"] +RUN dotnet restore "FlawBOT.Core/FlawBOT.Core.csproj" +COPY . . +WORKDIR "/src/FlawBOT.Core" +RUN dotnet build "FlawBOT.Core.csproj" -c Release -o /app + +FROM build AS publish +RUN dotnet publish "FlawBOT.Core.csproj" -c Release -o /app + +FROM base AS final +WORKDIR /app +COPY --from=publish /app . +ENTRYPOINT ["dotnet", "FlawBOT.Core.dll"] \ No newline at end of file diff --git a/src/FlawBOT.Core/FlawBOT.Core.csproj b/src/FlawBOT.Core/FlawBOT.Core.csproj new file mode 100644 index 00000000..dffd93d1 --- /dev/null +++ b/src/FlawBOT.Core/FlawBOT.Core.csproj @@ -0,0 +1,50 @@ + + + + Exe + netcoreapp2.2 + icon.ico + FlawBOT.Program + true + 2.2.0 + + 7.2 + 2.2.0 + 2.2.0 + Linux + FlawBOT.Core + FlawBOT.Core + + + + false + AnyCPU + + + + + + + + + PreserveNewest + + + + + + + + + + + + + + + + ..\FlawBOT.Framework\Resources\PokemonTcgSdk.dll + + + + diff --git a/src/FlawBOT/Modules/Bot/BotModule.cs b/src/FlawBOT.Core/Modules/Bot/BotModule.cs similarity index 84% rename from src/FlawBOT/Modules/Bot/BotModule.cs rename to src/FlawBOT.Core/Modules/Bot/BotModule.cs index 30a3cf77..d2ddc81d 100644 --- a/src/FlawBOT/Modules/Bot/BotModule.cs +++ b/src/FlawBOT.Core/Modules/Bot/BotModule.cs @@ -1,15 +1,15 @@ -using DSharpPlus; +using System; +using System.Threading.Tasks; +using DSharpPlus; using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; using DSharpPlus.Interactivity; using FlawBOT.Common; -using FlawBOT.Models; -using FlawBOT.Services; -using System; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Bot +namespace FlawBOT.Modules { [Group("bot")] [Description("Basic commands for interacting with FlawBOT")] @@ -29,9 +29,9 @@ public async Task BotInfo(CommandContext ctx) .WithDescription("A multipurpose Discord bot written in C# with [DSharpPlus](https://github.com/DSharpPlus/DSharpPlus/).") .AddField(":clock1: Uptime", $"{(int)uptime.TotalDays:00} days {uptime.Hours:00}:{uptime.Minutes:00}:{uptime.Seconds:00}", true) .AddField(":link: Links", $"[Commands]({SharedData.GitHubLink}wiki) **|** [Invite]({SharedData.InviteLink}) **|** [GitHub]({SharedData.GitHubLink})", true) - .WithFooter($"Thank you for using {SharedData.Name} (v{SharedData.Version})") + .WithFooter("Thank you for using " + SharedData.Name + $" (v{SharedData.Version})") .WithUrl(SharedData.GitHubLink) - .WithColor(DiscordColor.Aquamarine); + .WithColor(SharedData.DefaultColor); await ctx.RespondAsync(embed: output.Build()); } @@ -45,7 +45,7 @@ public async Task BotInfo(CommandContext ctx) public async Task LeaveAsync(CommandContext ctx) { await BotServices.SendEmbedAsync(ctx, $"Are you sure you want {SharedData.Name} to leave this server?\nRespond with **yes** to proceed or wait 10 seconds to cancel this operation."); - var interactivity = await ctx.Client.GetInteractivity().WaitForMessageAsync(m => m.Channel.Id == ctx.Channel.Id && m.Content.ToLowerInvariant() == "yes", TimeSpan.FromSeconds(10)); + var interactivity = await ctx.Client.GetInteractivity().WaitForMessageAsync(m => m.Channel.Id == ctx.Channel.Id && m.Author.Id == ctx.User.Id && m.Content.ToLowerInvariant() == "yes", TimeSpan.FromSeconds(10)); if (interactivity.Result == null) await BotServices.SendEmbedAsync(ctx, "Request timed out..."); else @@ -81,7 +81,7 @@ public async Task ReportIssue(CommandContext ctx, await ctx.RespondAsync("Please provide more information on the issue (50 characters minimum)."); else { - await ctx.RespondAsync("The following information will be sent to the developer for investigation: User ID, Server ID, Server Name and Server Owner Name.\nRespond with **yes** in the next 10 seconds to proceed, otherwise the operation will be cancelled."); + await BotServices.SendEmbedAsync(ctx, "The following information will be sent to the developer for investigation: User ID, Server ID, Server Name and Server Owner Name.\nRespond with **yes** in the next 10 seconds to proceed, otherwise the operation will be cancelled."); var interactivity = await ctx.Client.GetInteractivity().WaitForMessageAsync(m => m.Channel.Id == ctx.Channel.Id && m.Author.Id == ctx.User.Id && m.Content.ToLowerInvariant() == "yes", TimeSpan.FromSeconds(10)); if (interactivity.Result == null) await BotServices.SendEmbedAsync(ctx, "Request timed out..."); @@ -95,7 +95,7 @@ public async Task ReportIssue(CommandContext ctx, .AddField("Server", ctx.Guild.Name + $" (ID: {ctx.Guild.Id})") .AddField("Owner", ctx.Guild.Owner.Username + "#" + ctx.Guild.Owner.Discriminator) .AddField("Confirm", $"[Click here to add this issue to GitHub]({SharedData.GitHubLink}/issues/new)") - .WithColor(DiscordColor.Turquoise); + .WithColor(SharedData.DefaultColor); await dm.SendMessageAsync(embed: output.Build()); await BotServices.SendEmbedAsync(ctx, "Thank You! Your report has been submitted.", EmbedType.Good); } @@ -112,8 +112,7 @@ public async Task ReportIssue(CommandContext ctx, public Task Say(CommandContext ctx, [Description("Message for the bot to repeat")] [RemainingText] string message) { - message = (string.IsNullOrWhiteSpace(message)) ? ":thinking:" : message; - return ctx.RespondAsync(message); + return ctx.RespondAsync((string.IsNullOrWhiteSpace(message)) ? ":thinking:" : message); } #endregion COMMAND_SAY @@ -125,7 +124,8 @@ public Task Say(CommandContext ctx, public async Task Uptime(CommandContext ctx) { var uptime = DateTime.Now - SharedData.ProcessStarted; - await BotServices.SendEmbedAsync(ctx, ":clock1: " + SharedData.Name + $" has been online for {(int)uptime.TotalDays:00} days ({uptime.Hours:00}:{uptime.Minutes:00}:{uptime.Seconds:00})"); + var days = (uptime.Days > 0) ? $"({uptime.Days:00} days)" : null; + await BotServices.SendEmbedAsync(ctx, ":clock1: " + SharedData.Name + $" has been online for {uptime.Hours:00}:{uptime.Minutes:00} {days}"); } #endregion COMMAND_UPTIME diff --git a/src/FlawBOT/Modules/Bot/OwnerModule.cs b/src/FlawBOT.Core/Modules/Bot/OwnerModule.cs similarity index 77% rename from src/FlawBOT/Modules/Bot/OwnerModule.cs rename to src/FlawBOT.Core/Modules/Bot/OwnerModule.cs index 29f86348..2a4d89ee 100644 --- a/src/FlawBOT/Modules/Bot/OwnerModule.cs +++ b/src/FlawBOT.Core/Modules/Bot/OwnerModule.cs @@ -1,15 +1,13 @@ -using DSharpPlus; +using System.Threading.Tasks; +using DSharpPlus; using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; using FlawBOT.Common; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Games; -using FlawBOT.Services.Search; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Bot +namespace FlawBOT.Modules { [Group("sudo"), Hidden] [Description("Owner commands for controlling FlawBOT")] @@ -32,6 +30,7 @@ public async Task SetBotActivity(CommandContext ctx, } else { + // TODO: Set the activity type var game = new DiscordActivity(activity); await ctx.Client.UpdateStatusAsync(activity: game); await BotServices.SendEmbedAsync(ctx, SharedData.Name + " activity has been changed to " + Formatter.Bold("Playing " + game.Name), EmbedType.Good); @@ -110,11 +109,35 @@ public async Task Update(CommandContext ctx) { var message = await ctx.RespondAsync("Starting update..."); await SteamService.UpdateSteamListAsync().ConfigureAwait(false); - await TeamFortressService.UpdateTF2SchemaAsync().ConfigureAwait(false); + await TeamFortressService.LoadTF2SchemaAsync().ConfigureAwait(false); await PokemonService.UpdatePokemonListAsync().ConfigureAwait(false); await message.ModifyAsync("Starting update...done!"); } #endregion COMMAND_UPDATE + + #region COMMAND_USERNAME + + [RequireOwner] + [Command("username"), Hidden] + [Aliases("setusername", "name", "setname", "nickname")] + [Description("Set FlawBOT's username")] + public async Task SetBotUsername(CommandContext ctx, + [Description("New bot username")] [RemainingText] string name) + { + var oldUsername = ctx.Client.CurrentUser.Username; + if (string.IsNullOrWhiteSpace(name)) + { + await ctx.Client.UpdateCurrentUserAsync(username: SharedData.Name); + await BotServices.SendEmbedAsync(ctx, oldUsername + " username has been changed to " + SharedData.Name); + } + else + { + await ctx.Client.UpdateCurrentUserAsync(username: name); + await BotServices.SendEmbedAsync(ctx, oldUsername + " username has been changed to " + ctx.Client.CurrentUser.Username, EmbedType.Good); + } + } + + #endregion COMMAND_USERNAME } } \ No newline at end of file diff --git a/src/FlawBOT/Modules/Games/PokemonModule.cs b/src/FlawBOT.Core/Modules/Games/PokemonModule.cs similarity index 80% rename from src/FlawBOT/Modules/Games/PokemonModule.cs rename to src/FlawBOT.Core/Modules/Games/PokemonModule.cs index 4ad9ac9a..915089fe 100644 --- a/src/FlawBOT/Modules/Games/PokemonModule.cs +++ b/src/FlawBOT.Core/Modules/Games/PokemonModule.cs @@ -1,16 +1,14 @@ -using DSharpPlus.CommandsNext; +using System; +using System.Text; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; using DSharpPlus.Interactivity; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Games; -using PokemonTcgSdk; -using System; -using System.Text; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Games +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class PokemonModule : BaseCommandModule @@ -30,22 +28,22 @@ public async Task Pokemon(CommandContext ctx, { foreach (var value in results.Cards) { - var card = PokemonTcgSdk.Card.Find(value.ID).Card; + var card = PokemonService.GetExactPokemonAsync(value.ID); var output = new DiscordEmbedBuilder() .WithTitle(card.Name + $" (PokeDex ID: {card.NationalPokedexNumber})") + .AddField("Subtype", card.SubType ?? "Unknown", true) .AddField("Health Points", card.Hp ?? "Unknown", true) .AddField("Artist", card.Artist ?? "Unknown", true) .AddField("Rarity", card.Rarity ?? "Unknown", true) .AddField("Series", card.Series ?? "Unknown", true) - .WithImageUrl((!string.IsNullOrWhiteSpace(card.ImageUrlHiRes)) ? card.ImageUrlHiRes : card.ImageUrl) + .WithImageUrl(card.ImageUrlHiRes ?? card.ImageUrl) .WithColor(DiscordColor.Gold) .WithFooter("Type next in the next 10 seconds for the next card"); var types = new StringBuilder(); foreach (var type in card.Types) types.Append(type); - if (types.Length != 0) - output.AddField("Type(s)", types.ToString(), true); + output.AddField("Type(s)", types.ToString() ?? "Unknown", true); await ctx.RespondAsync(embed: output.Build()); var interactivity = await ctx.Client.GetInteractivity().WaitForMessageAsync(m => m.Channel.Id == ctx.Channel.Id && m.Content.ToLowerInvariant() == "next", TimeSpan.FromSeconds(10)); diff --git a/src/FlawBOT/Modules/Games/SmashModule.cs b/src/FlawBOT.Core/Modules/Games/SmashModule.cs similarity index 55% rename from src/FlawBOT/Modules/Games/SmashModule.cs rename to src/FlawBOT.Core/Modules/Games/SmashModule.cs index 94c75b8f..12d8de96 100644 --- a/src/FlawBOT/Modules/Games/SmashModule.cs +++ b/src/FlawBOT.Core/Modules/Games/SmashModule.cs @@ -1,12 +1,13 @@ -using DSharpPlus.CommandsNext; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Games; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Games +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class SmashModule : BaseCommandModule @@ -14,8 +15,8 @@ public class SmashModule : BaseCommandModule #region COMMAND_SMASH [Command("smash")] - [Aliases("smashbros")] - [Description("Retrieve Smash Ultimate character information")] + [Aliases("smashbros", "sb", "sbu")] + [Description("Retrieve Smash Bros. Ultimate character information")] public async Task GetCharacter(CommandContext ctx, [Description("Name of the Smash character")] [RemainingText] string query) { @@ -27,10 +28,21 @@ public async Task GetCharacter(CommandContext ctx, { var output = new DiscordEmbedBuilder() .WithTitle(results.DisplayName) - .WithDescription($"[Attributes]({results.Related.Ultimate.Attributes}) **|** [Movements]({results.Related.Ultimate.Movements}) **|** [Moves]({results.Related.Ultimate.Moves})") .WithThumbnailUrl(results.ThumbnailUrl) .WithColor(new DiscordColor(results.ColorTheme)) .WithUrl(results.FullUrl); + + var attributes = await SmashService.GetCharacterAttributesAsync(results.OwnerId); + var attributesProcessed = new List(); + foreach (var attribute in attributes) + { + if (attributesProcessed.Contains(attribute.Name)) continue; + var values = new StringBuilder(); + foreach (var value in attribute.Attributes) + values.Append(value.Name + ": " + value.Value + "\n"); + output.AddField(attribute.Name, values.ToString() ?? "Unknown", true); + attributesProcessed.Add(attribute.Name); + } await ctx.RespondAsync(embed: output.Build()); } } diff --git a/src/FlawBOT.Core/Modules/Games/SpeedrunModule.cs b/src/FlawBOT.Core/Modules/Games/SpeedrunModule.cs new file mode 100644 index 00000000..cf9a2c1e --- /dev/null +++ b/src/FlawBOT.Core/Modules/Games/SpeedrunModule.cs @@ -0,0 +1,45 @@ +using System.Linq; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; +using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus.Entities; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; + +namespace FlawBOT.Modules +{ + [Cooldown(3, 5, CooldownBucketType.Channel)] + public class SpeedrunModule : BaseCommandModule + { + #region COMMAND_SPEEDRUN + + [Command("speedrun")] + [Description("Search Speedrun.com for a given game")] + public async Task Speedrun(CommandContext ctx, + [Description("Game to search on Speedrun.com")] [RemainingText] string query) + { + if (!BotServices.CheckUserInput(query)) return; + var results = SpeedrunService.GetSpeedrunGameAsync(query).Result.Data.FirstOrDefault(); + if (results == null) + await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); + else + { + var output = new DiscordEmbedBuilder() + .WithTitle(results.Names.International) + .AddField("Release Date", results.ReleaseDate.ToString() ?? "Unknown", true) + .AddField("Emulators Allowed?", (results.RuleSet.EmulatorsAllowed) ? "Yes" : "No", true) + .AddField("Developers", (results.Developers.Count > 0) ? SpeedrunService.GetSpeedrunExtraAsync(results.Developers.Take(3).ToList(), SpeedrunExtras.Developers).Result : "Unknown", true) + .AddField("Publishers", (results.Publishers.Count > 0) ? SpeedrunService.GetSpeedrunExtraAsync(results.Publishers.Take(3).ToList(), SpeedrunExtras.Publishers).Result : "Unknown", true) + .AddField("Genres", (results.Genres.Count > 0) ? SpeedrunService.GetSpeedrunExtraAsync(results.Genres.Take(3).ToList(), SpeedrunExtras.Genres).Result : "Unknown", true) + .AddField("Platforms", (results.Platforms.Count > 0) ? SpeedrunService.GetSpeedrunExtraAsync(results.Platforms.Take(3).ToList(), SpeedrunExtras.Platforms).Result : "Unknown", true) + .WithFooter($"ID: {results.ID} - Abbreviation: {results.Abbreviation}") + .WithThumbnailUrl(results.Assets.CoverLarge.URL ?? results.Assets.Icon.URL) + .WithUrl(results.WebLink) + .WithColor(new DiscordColor("#0F7A4D")); + await ctx.RespondAsync(embed: output.Build()); + } + } + + #endregion COMMAND_SPEEDRUN + } +} \ No newline at end of file diff --git a/src/FlawBOT/Modules/Search/SteamModule.cs b/src/FlawBOT.Core/Modules/Games/SteamModule.cs similarity index 72% rename from src/FlawBOT/Modules/Search/SteamModule.cs rename to src/FlawBOT.Core/Modules/Games/SteamModule.cs index 7ebfb174..cbbedd99 100644 --- a/src/FlawBOT/Modules/Search/SteamModule.cs +++ b/src/FlawBOT.Core/Modules/Games/SteamModule.cs @@ -1,17 +1,15 @@ -using DSharpPlus.CommandsNext; +using System.Globalization; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Search; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; using Steam.Models.SteamCommunity; -using SteamWebAPI2.Interfaces; -using System.Globalization; -using System.Text.RegularExpressions; -using System.Threading.Tasks; using UserStatus = Steam.Models.SteamCommunity.UserStatus; -namespace FlawBOT.Modules.Search +namespace FlawBOT.Modules { [Group("steam")] [Description("Commands finding Steam games and users")] @@ -29,25 +27,18 @@ public async Task SteamGame(CommandContext ctx, while (check == false) try { - var store = new SteamStore(); - var appId = SteamService.GetSteamAppAsync(query); - var app = await store.GetStoreAppDetailsAsync(appId); + var app = SteamService.GetSteamAppAsync(query).Result; var output = new DiscordEmbedBuilder() .WithTitle(app.Name) + .WithDescription((Regex.Replace(app.DetailedDescription.Length <= 500 ? app.DetailedDescription : app.DetailedDescription.Substring(0, 500) + "...", "<[^>]*>", "")) ?? "Unknown") + .AddField("Developers", app.Developers[0] ?? "Unknown", true) + .AddField("Publisher", app.Publishers[0] ?? "Unknown", true) + .AddField("Release Date", app.ReleaseDate.Date ?? "Unknown", true) + .AddField("Metacritic", app.Metacritic.Score.ToString() ?? "Unknown", true) .WithThumbnailUrl(app.HeaderImage) .WithUrl("http://store.steampowered.com/app/" + app.SteamAppId.ToString()) .WithFooter("App ID: " + app.SteamAppId.ToString()) .WithColor(new DiscordColor("#1B2838")); - if (!string.IsNullOrWhiteSpace(app.DetailedDescription)) - output.WithDescription(Regex.Replace(app.DetailedDescription.Length <= 500 ? app.DetailedDescription : app.DetailedDescription.Substring(0, 500) + "...", "<[^>]*>", "")); - if (!string.IsNullOrWhiteSpace(app.Developers[0])) - output.AddField("Developers", app.Developers[0], true); - if (!string.IsNullOrWhiteSpace(app.Publishers[0])) - output.AddField("Publisher", app.Publishers[0], true); - if (!string.IsNullOrWhiteSpace(app.ReleaseDate.Date)) - output.AddField("Release Date", app.ReleaseDate.Date, true); - if (app.Metacritic != null) - output.AddField("Metacritic", app.Metacritic.Score.ToString(), true); await ctx.RespondAsync(embed: output.Build()); check = true; } @@ -103,5 +94,21 @@ public async Task SteamUser(CommandContext ctx, } #endregion COMMAND_USER + + #region COMMAND_CONNECT + + [Command("connect")] + [Description("Format a game connection string into a clickable link")] + public async Task SteamServerLink(CommandContext ctx, + [Description("Connection string")] [RemainingText] string link) + { + var regex = new Regex(@"\s*(?'ip'\S+)\s*", RegexOptions.Compiled).Match(link); + if (regex.Success) + await ctx.RespondAsync(string.Format($"steam://connect/{regex.Groups["ip"].Value}/{regex.Groups["pw"].Value}")); + else + await BotServices.SendEmbedAsync(ctx, "Invalid connection info, follow the format: 123.345.56.789:000; password hello", EmbedType.Warning); + } + + #endregion COMMAND_CONNECT } } \ No newline at end of file diff --git a/src/FlawBOT/Modules/Games/TeamFortressModule.cs b/src/FlawBOT.Core/Modules/Games/TeamFortressModule.cs similarity index 57% rename from src/FlawBOT/Modules/Games/TeamFortressModule.cs rename to src/FlawBOT.Core/Modules/Games/TeamFortressModule.cs index f2e9aa1d..ef699d2c 100644 --- a/src/FlawBOT/Modules/Games/TeamFortressModule.cs +++ b/src/FlawBOT.Core/Modules/Games/TeamFortressModule.cs @@ -1,18 +1,17 @@ -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using DSharpPlus.Interactivity; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Games; -using System; +using System; using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using DSharpPlus.CommandsNext; +using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus.Entities; +using DSharpPlus.Interactivity; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Games +namespace FlawBOT.Modules { [Group("tf2")] [Description("Commands related to Team Fortress 2")] @@ -21,7 +20,8 @@ public class TeamFortressModule : BaseCommandModule { #region COMMAND_SCHEMA - [Command("item"), Hidden] + [Command("item")] + [Aliases("schema")] [Description("Retrieve an item from the latest TF2 item schema")] public async Task TF2Item(CommandContext ctx, [Description("Item to find in the TF2 schema")] [RemainingText] string query = "The Scattergun") @@ -34,35 +34,25 @@ public async Task TF2Item(CommandContext ctx, var textInfo = new CultureInfo("en-US", false).TextInfo; var output = new DiscordEmbedBuilder() .WithTitle(item.ItemName) - .WithThumbnailUrl(item.ImageUrl) + .WithDescription((!string.IsNullOrWhiteSpace(item.Description)) ? item.Description : "") + .AddField("Giftable", (item.Capabilities.Giftable) ? "Yes" : "No", true) + .AddField("Nameable", (item.Capabilities.Renamable) ? "Yes" : "No", true) + .AddField("Item Slot:", (!string.IsNullOrWhiteSpace(item.ItemSlot)) ? textInfo.ToTitleCase(item.ItemSlot) : "Unknown", true) + .WithThumbnailUrl(item.ImageURL) .WithUrl("https://wiki.teamfortress.com/wiki/" + item.ItemName.Replace(' ', '_')) + .WithFooter("ID: " + item.DefIndex) .WithColor(new DiscordColor("#E7B53B")); - if (!string.IsNullOrWhiteSpace(item.ItemDescription)) - output.WithDescription(item.ItemDescription); - if (!string.IsNullOrWhiteSpace(item.ItemSlot)) - output.AddField("Item Slot:", textInfo.ToTitleCase(item.ItemSlot), true); - if (!string.IsNullOrWhiteSpace(item.ModelPlayer)) - await ctx.RespondAsync(embed: output.Build()); - } - } - - #endregion COMMAND_SCHEMA - #region COMMAND_CONNECT + var userClasses = new StringBuilder(); + foreach (var className in item.UsedByClasses) + userClasses.Append(className + "\n"); + output.AddField("Classes:", userClasses.ToString() ?? "Unknown", true); - [Command("connect")] - [Description("Format TF2 connection information into a clickable link")] - public async Task SteamServerLink(CommandContext ctx, - [Description("Connection string")] [RemainingText] string link) - { - var regex = new Regex(@"\s*(?'ip'\S+)\s*", RegexOptions.Compiled).Match(link); - if (regex.Success) - await ctx.RespondAsync(string.Format($"steam://connect/{regex.Groups["ip"].Value}/{regex.Groups["pw"].Value}")); - else - await BotServices.SendEmbedAsync(ctx, "Invalid connection info, follow the format: 123.345.56.789:000; password hello", EmbedType.Warning); + await ctx.RespondAsync(embed: output.Build()); + } } - #endregion COMMAND_CONNECT + #endregion COMMAND_SCHEMA #region COMMAND_MAP @@ -78,7 +68,7 @@ public async Task TF2Map(CommandContext ctx, await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); else { - Double.TryParse(results.AvgPlayers, out var avg_players); + double.TryParse(results.AvgPlayers, out var avg_players); var output = new DiscordEmbedBuilder() .WithTitle(results.MapName) .AddField("Official", results.OfficialMap ? "YES" : "NO", true) @@ -89,13 +79,12 @@ public async Task TF2Map(CommandContext ctx, .WithImageUrl(results.Thumbnail) .WithUrl("https://wiki.teamfortress.com/wiki/" + results.MapName) .WithColor(new DiscordColor("#E7B53B")); - if (results.RelatedMaps.Count > 0) output.AddField("Related Map", results.RelatedMaps[0]); var related_maps = new StringBuilder(); foreach (var map in results.RelatedMaps.Take(5)) related_maps.Append(map + "\n"); if (related_maps.Length > 0) - output.AddField("Related map(s)", related_maps.ToString(), true); + output.AddField("Related Map(s)", related_maps.ToString(), true); await ctx.RespondAsync(embed: output.Build()); } @@ -151,10 +140,10 @@ public async Task TF2Servers(CommandContext ctx, .AddField("Current Map", server.MapName ?? "Unknown", true) .AddField("Next Map", server.NextMap ?? "Unknown", true) .AddField("Provider", server.Provider ?? "Unknown", true) - .AddField("Roll the Dice", server.HasRTD ? "YES" : "NO", true) - //.AddField("Random Crits", server.has_randomcrits.ToString() ?? "Unknown", true) - .AddField("Respawn Timer", server.HasNoSpawnTimer ? "YES" : "NO", true) - .AddField("All Talk", server.HasAllTalk ? "YES" : "NO", true) + .AddField("Roll the Dice>", server.HasRTD ? "Yes" : "No", true) + .AddField("Random Crits", server.HasRandomCrits == true ? "Yes" : "No", true) + .AddField("Respawn Timer", server.HasNoSpawnTimer ? "Yes" : "No", true) + .AddField("All Talk", server.HasAllTalk ? "Yes" : "No", true) .WithThumbnailUrl("https://teamwork.tf" + server.MapThumbnail) .WithFooter("Type next in the next 10 seconds for the next server") .WithColor(new DiscordColor("#E7B53B")); @@ -170,123 +159,51 @@ public async Task TF2Servers(CommandContext ctx, #endregion COMMAND_SERVERS - #region BACKPACK.TF - - [Command("price_history"), Hidden] - [Description("Retrieve price history for the specified item")] - public async Task BackpackPriceHistory(CommandContext ctx, - [RemainingText] string itemName) - { - var results = TeamFortressService.GetPriceHistory(itemName).Response; - if (results.Success > 0) - await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); - else - { - var output = new DiscordEmbedBuilder() - .WithTitle(itemName) - .WithColor(DiscordColor.Chartreuse); - - var histories = new StringBuilder(); - foreach (var history in results.History.Take(5)) - histories.Append(history + "\n"); - if (histories.Length > 0) - output.AddField("History", histories.ToString(), true); - - await ctx.RespondAsync(embed: output.Build()); - } - } - - [Command("item_prices"), Hidden] - [Description("Retrieve item prices for the specified API key. A request may be sent once every 60 seconds")] - public async Task BackpackItemPrices(CommandContext ctx) - { - var results = TeamFortressService.GetItemPrices().Response; - if (results.Success > 0) - await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); - else - { - // Return results - } - } - - [Command("special_items"), Hidden] - [Description("Retrieve special items for the specified API key")] - public async Task BackpackSpecialItems(CommandContext ctx) - { - var results = TeamFortressService.GetSpecialItems().Response; - if (results.Success > 0) - await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); - else - { - // Return results - } - } + #region COMMAND_CLASSIFIEDS [Command("classifieds_all"), Hidden] [Description("Retrieve all currently open classifieds that are on backpack.tf")] public async Task BackpackClassifieds(CommandContext ctx) { var results = TeamFortressService.GetClassifieds(); - if (results == null) + if (results.Total > 0) await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); else { - // Return results + var output = new DiscordEmbedBuilder() + .WithFooter("These are the classifieds retrieved from Backpack.TF") + .WithColor(new DiscordColor("#E7B53B")); + if (results.Sell.Total > 0) + foreach (var result in results.Sell.Listings.Take(5)) + output.AddField(result.Intent.ToString(), result.Item.Name); + if (results.Buy.Total > 0) + foreach (var result in results.Buy.Listings.Take(5)) + output.AddField(result.Intent.ToString(), result.Item.Name); + await ctx.RespondAsync(embed: output.Build()); } } [Command("classifieds_my"), Hidden] [Description("Retrieve the currently opened user's classifieds from backpack.tf")] - public async Task BackpackOwnClassifieds(CommandContext ctx) - { - var results = TeamFortressService.GetOwnClassifieds(); - if (results == null) - await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); - else - { - // Return results - } - } - - [Command("inventory_user"), Hidden] - [Description("Retrieve the currently opened user's classifieds from backpack.tf")] - public async Task BackpackUserInventory(CommandContext ctx, string steamID) + public async Task BackpackOwnClassifieds(CommandContext ctx, + [Description("User whose classifieds to find on Backpack.TF")] [RemainingText] string query) { - var results = TeamFortressService.GetUserInventory(steamID); - if (results.Success > 0) - await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); - else - { - // Return results - } - } - - [Command("inventory_my"), Hidden] - [Description("Retrieve the currently opened user's classifieds from backpack.tf")] - public async Task BackpackOwnInventory(CommandContext ctx) - { - var results = TeamFortressService.GetOwnInventory(); - if (results.Success > 0) - await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); - else - { - // Return results - } - } - - [Command("inventory_item"), Hidden] - [Description("Retrieve an item in the user's inventory and returns its Asset and Description models")] - public async Task BackpackItemFromInventory(CommandContext ctx, string itemName) - { - var results = TeamFortressService.GetItemFromInventory(itemName); - if (results == null) + if (!BotServices.CheckUserInput(query)) return; + var steamId = SteamService.GetSteamUserProfileAsync(query).Result.SteamID.ToString(); + var results = TeamFortressService.GetOwnClassifieds(steamId); + if (results.Items.Count == 0) await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); else { - // Return results + var output = new DiscordEmbedBuilder() + .WithFooter($"These are the classifieds by {query} retrieved from Backpack.TF") + .WithColor(new DiscordColor("#E7B53B")); + foreach (var result in results.Items.Take(5)) + output.AddField(result.Name, result.MarketplacePrice.ToString()); + await ctx.RespondAsync(embed: output.Build()); } } - #endregion BACKPACK.TF + #endregion COMMAND_CLASSIFIEDS } } \ No newline at end of file diff --git a/src/FlawBOT/Modules/Misc/MathModule.cs b/src/FlawBOT.Core/Modules/Misc/MathModule.cs similarity index 94% rename from src/FlawBOT/Modules/Misc/MathModule.cs rename to src/FlawBOT.Core/Modules/Misc/MathModule.cs index c6948752..ee0221df 100644 --- a/src/FlawBOT/Modules/Misc/MathModule.cs +++ b/src/FlawBOT.Core/Modules/Misc/MathModule.cs @@ -1,12 +1,12 @@ -using DSharpPlus.CommandsNext; +using System.Linq; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using FlawBOT.Models; -using FlawBOT.Services; -using System.Linq; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Misc +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class MathModule : BaseCommandModule diff --git a/src/FlawBOT/Modules/Misc/MiscModule.cs b/src/FlawBOT.Core/Modules/Misc/MiscModule.cs similarity index 95% rename from src/FlawBOT/Modules/Misc/MiscModule.cs rename to src/FlawBOT.Core/Modules/Misc/MiscModule.cs index 35506714..1a4b0fe2 100644 --- a/src/FlawBOT/Modules/Misc/MiscModule.cs +++ b/src/FlawBOT.Core/Modules/Misc/MiscModule.cs @@ -1,15 +1,16 @@ -using DSharpPlus; +using System; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using DSharpPlus; using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using FlawBOT.Models; -using FlawBOT.Services; +using FlawBOT.Common; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; using Newtonsoft.Json.Linq; -using System; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -namespace FlawBOT.Modules.Misc +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class MiscModule : BaseCommandModule @@ -58,7 +59,6 @@ public async Task CatPic(CommandContext ctx) var results = CatService.GetCatPhotoAsync().Result; if (string.IsNullOrWhiteSpace(results)) await BotServices.SendEmbedAsync(ctx, "Connection to random.cat failed!", EmbedType.Warning); - var output = new DiscordEmbedBuilder() .WithTitle(":cat: Meow!") .WithImageUrl(results) @@ -78,7 +78,7 @@ public Task CoinFlip(CommandContext ctx) var random = new Random(); var output = new DiscordEmbedBuilder() .WithDescription(ctx.User.Mention + " flipped " + Formatter.Bold(Convert.ToBoolean(random.Next(0, 2)) ? "Heads" : "Tails")) - .WithColor(DiscordColor.Black); + .WithColor(SharedData.DefaultColor); return ctx.RespondAsync(embed: output.Build()); } @@ -93,7 +93,9 @@ public async Task GetColor(CommandContext ctx, [Description("HEX color code to process")] DiscordColor color) { var regex = new Regex(@"^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", RegexOptions.Compiled).Match(color.ToString()); - if (regex.Success) + if (!regex.Success) + await BotServices.SendEmbedAsync(ctx, "Invalid color code. Please enter a HEX color code like #E7B53B", EmbedType.Warning); + else { var output = new DiscordEmbedBuilder() .AddField("HEX:", $"{color.Value:X}", true) @@ -102,8 +104,6 @@ public async Task GetColor(CommandContext ctx, .WithColor(color); await ctx.RespondAsync(embed: output.Build()); } - else - await BotServices.SendEmbedAsync(ctx, "Invalid color code. Please enter a HEX color code like #E7B53B", EmbedType.Warning); } #endregion COMMAND_COLOR @@ -118,7 +118,7 @@ public Task RollDice(CommandContext ctx) var random = new Random(); var output = new DiscordEmbedBuilder() .WithDescription(ctx.User.Mention + " rolled a " + Formatter.Bold(random.Next(1, 7).ToString())) - .WithColor(DiscordColor.Black); + .WithColor(SharedData.DefaultColor); return ctx.RespondAsync(embed: output.Build()); } diff --git a/src/FlawBOT/Modules/Misc/PollModule.cs b/src/FlawBOT.Core/Modules/Misc/PollModule.cs similarity index 93% rename from src/FlawBOT/Modules/Misc/PollModule.cs rename to src/FlawBOT.Core/Modules/Misc/PollModule.cs index 248ddc55..f6e5d220 100644 --- a/src/FlawBOT/Modules/Misc/PollModule.cs +++ b/src/FlawBOT.Core/Modules/Misc/PollModule.cs @@ -1,15 +1,15 @@ -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using DSharpPlus.Interactivity; -using FlawBOT.Models; -using FlawBOT.Services; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using DSharpPlus.CommandsNext; +using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus.Entities; +using DSharpPlus.Interactivity; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Misc +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class PollModule : BaseCommandModule diff --git a/src/FlawBOT.Core/Modules/Search/AmiiboModule.cs b/src/FlawBOT.Core/Modules/Search/AmiiboModule.cs new file mode 100644 index 00000000..6db43914 --- /dev/null +++ b/src/FlawBOT.Core/Modules/Search/AmiiboModule.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; +using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus.Entities; +using DSharpPlus.Interactivity; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; + +namespace FlawBOT.Modules +{ + [Cooldown(3, 5, CooldownBucketType.Channel)] + public class AmiiboModule : BaseCommandModule + { + #region COMMAND_AMIIBO + + [Command("amiibo")] + [Aliases("amib")] + [Description("Retrieve Amiibo figurine information")] + public async Task GetAmiibo(CommandContext ctx, + [Description("Name of the Amiibo figurine")] [RemainingText] string query) + { + if (!BotServices.CheckUserInput(query)) return; + var results = await AmiiboService.GetAmiiboFigurineAsync(query); + if (results == null) + await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); + else + { + foreach (var amiibo in results.Amiibo) + { + var output = new DiscordEmbedBuilder() + .WithTitle(amiibo.Name) + .AddField("Amiibo Series", amiibo.AmiiboSeries, true) + .AddField("Game Series", amiibo.GameSeries, true) + .AddField(":flag_us: Release:", amiibo.ReleaseDate.American, true) + .AddField(":flag_jp: Release:", amiibo.ReleaseDate.Japanese, true) + .AddField(":flag_eu: Release:", amiibo.ReleaseDate.European, true) + .AddField(":flag_au: Release:", amiibo.ReleaseDate.Australian, true) + .WithImageUrl(amiibo.Image) + .WithFooter("Type next in the next 10 seconds the next amiibo") + .WithColor(new DiscordColor("#E70009")); + var message = await ctx.RespondAsync(embed: output.Build()); + + var interactivity = await ctx.Client.GetInteractivity().WaitForMessageAsync(m => m.Channel.Id == ctx.Channel.Id && m.Content.ToLowerInvariant() == "next", TimeSpan.FromSeconds(10)); + if (interactivity.Result == null) break; + await BotServices.RemoveMessage(interactivity.Result); + await BotServices.RemoveMessage(message); + } + } + } + + #endregion COMMAND_AMIIBO + } +} \ No newline at end of file diff --git a/src/FlawBOT/Modules/Search/DictionaryModule.cs b/src/FlawBOT.Core/Modules/Search/DictionaryModule.cs similarity index 82% rename from src/FlawBOT/Modules/Search/DictionaryModule.cs rename to src/FlawBOT.Core/Modules/Search/DictionaryModule.cs index 68c1ebb4..9df66771 100644 --- a/src/FlawBOT/Modules/Search/DictionaryModule.cs +++ b/src/FlawBOT.Core/Modules/Search/DictionaryModule.cs @@ -1,16 +1,15 @@ -using DSharpPlus; +using System; +using System.Linq; +using System.Threading.Tasks; +using DSharpPlus; using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; using DSharpPlus.Interactivity; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Search; -using System; -using System.Linq; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Search +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class DictionaryModule : BaseCommandModule @@ -34,13 +33,12 @@ public async Task UrbanDictionary(CommandContext ctx, var output = new DiscordEmbedBuilder() .WithTitle("Urban Dictionary definition for " + Formatter.Bold(query) + (!string.IsNullOrWhiteSpace(definition.Author) ? $" by {definition.Author}" : "")) .WithDescription(definition.Definition.Length < 500 ? definition.Definition : definition.Definition.Take(500) + "...") + .AddField("Example", definition.Example ?? "None") + .AddField(":thumbsup:", definition.ThumbsUp.ToString(), true) + .AddField(":thumbsdown:", definition.ThumbsDown.ToString(), true) .WithUrl(definition.Permalink) .WithFooter("Type next in the next 10 seconds the next definition") .WithColor(new DiscordColor("#1F2439")); - if (!string.IsNullOrWhiteSpace(definition.Example)) - output.AddField("Example", definition.Example); - output.AddField(":thumbsup:", definition.ThumbsUp.ToString(), true); - output.AddField(":thumbsdown:", definition.ThumbsDown.ToString(), true); var message = await ctx.RespondAsync(embed: output.Build()); var interactivity = await ctx.Client.GetInteractivity().WaitForMessageAsync(m => m.Channel.Id == ctx.Channel.Id && m.Content.ToLowerInvariant() == "next", TimeSpan.FromSeconds(10)); diff --git a/src/FlawBOT/Modules/Search/GoogleModule.cs b/src/FlawBOT.Core/Modules/Search/GoogleModule.cs similarity index 91% rename from src/FlawBOT/Modules/Search/GoogleModule.cs rename to src/FlawBOT.Core/Modules/Search/GoogleModule.cs index 495fb452..b4d0cd6b 100644 --- a/src/FlawBOT/Modules/Search/GoogleModule.cs +++ b/src/FlawBOT.Core/Modules/Search/GoogleModule.cs @@ -1,15 +1,15 @@ -using DSharpPlus; +using System; +using System.Linq; +using System.Threading.Tasks; +using DSharpPlus; using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Search; -using System; -using System.Linq; -using System.Threading.Tasks; +using FlawBOT.Common; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Search +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class GoogleModule : BaseCommandModule @@ -31,7 +31,7 @@ public async Task GetTime(CommandContext ctx, var output = new DiscordEmbedBuilder() .WithTitle(":clock1: Time in " + results.Results[0].FormattedAddress) .WithDescription(Formatter.Bold(results.Time.ToShortTimeString()) + " " + results.Timezone.timeZoneName) - .WithColor(DiscordColor.Cyan); + .WithColor(SharedData.DefaultColor); await ctx.RespondAsync(embed: output.Build()); } } @@ -59,7 +59,7 @@ public async Task Weather(CommandContext ctx, .AddField("Humidity", $"{results.Main.Humidity}%", true) .AddField("Wind Speed", $"{results.Wind.Speed}m/s", true) .WithUrl("https://openweathermap.org/city/" + results.ID) - .WithColor(DiscordColor.Cyan); + .WithColor(SharedData.DefaultColor); await ctx.RespondAsync(embed: output.Build()); } } diff --git a/src/FlawBOT/Modules/Search/ImgurModule.cs b/src/FlawBOT.Core/Modules/Search/ImgurModule.cs similarity index 86% rename from src/FlawBOT/Modules/Search/ImgurModule.cs rename to src/FlawBOT.Core/Modules/Search/ImgurModule.cs index 4d8d216e..6174f745 100644 --- a/src/FlawBOT/Modules/Search/ImgurModule.cs +++ b/src/FlawBOT.Core/Modules/Search/ImgurModule.cs @@ -1,11 +1,10 @@ -using DSharpPlus.CommandsNext; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using FlawBOT.Services.Search; +using FlawBOT.Framework.Services; using Imgur.API.Models.Impl; -using System.Threading.Tasks; -namespace FlawBOT.Modules.Search +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class ImgurModule : BaseCommandModule diff --git a/src/FlawBOT.Core/Modules/Search/NASAModule.cs b/src/FlawBOT.Core/Modules/Search/NASAModule.cs new file mode 100644 index 00000000..e644fa50 --- /dev/null +++ b/src/FlawBOT.Core/Modules/Search/NASAModule.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; +using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus.Entities; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; + +namespace FlawBOT.Modules +{ + [Cooldown(3, 5, CooldownBucketType.Channel)] + public class NASAModule : BaseCommandModule + { + #region COMMAND_NASA + + [Command("nasa")] + [Aliases("apod")] + [Description("Retrieve NASA's Astronomy Picture of the Day")] + public async Task NASA(CommandContext ctx) + { + var results = await NASAService.GetNASAImage(); + if (results == null) + await BotServices.SendEmbedAsync(ctx, "Unable to reach NASA API", EmbedType.Missing); + else + { + var output = new DiscordEmbedBuilder() + .WithTitle(results.Title) + .WithDescription(results.Description) + .WithImageUrl(results.ImageHD ?? results.ImageSD) + .WithFooter(results.Copyright + " - " + results.Date) + .WithColor(new DiscordColor("#0B3D91")); + await ctx.RespondAsync(embed: output.Build()); + } + } + + #endregion COMMAND_NASA + } +} \ No newline at end of file diff --git a/src/FlawBOT/Modules/Search/IMDBModule.cs b/src/FlawBOT.Core/Modules/Search/OMDBModule.cs similarity index 76% rename from src/FlawBOT/Modules/Search/IMDBModule.cs rename to src/FlawBOT.Core/Modules/Search/OMDBModule.cs index e6ef70bf..6f3cb1db 100644 --- a/src/FlawBOT/Modules/Search/IMDBModule.cs +++ b/src/FlawBOT.Core/Modules/Search/OMDBModule.cs @@ -1,27 +1,26 @@ -using DSharpPlus.CommandsNext; +using System.Linq; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Search; -using System.Linq; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Search +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] - public class IMDBModule : BaseCommandModule + public class OMDBModule : BaseCommandModule { - #region COMMAND_IMDB + #region COMMAND_OMDB - [Command("imdb")] - [Aliases("omdb", "movie")] - [Description("Retrieve a movie or TV show from IMDB")] + [Command("omdb")] + [Aliases("imdb", "movie")] + [Description("Retrieve a movie or TV show from OMDB")] public async Task OMDB(CommandContext ctx, - [Description("Movie or TV show to find on IMDB")] [RemainingText] string query) + [Description("Movie or TV show to find on OMDB")] [RemainingText] string query) { if (!BotServices.CheckUserInput(query)) return; - var results = IMDBService.GetMovieDataAsync(query.Replace(" ", "+")).Result; + var results = OMDBService.GetMovieDataAsync(query.Replace(" ", "+")).Result; if (results.Response == "False") await BotServices.SendEmbedAsync(ctx, "No results found!", EmbedType.Missing); else @@ -46,6 +45,6 @@ public async Task OMDB(CommandContext ctx, } } - #endregion COMMAND_IMDB + #endregion COMMAND_OMDB } } \ No newline at end of file diff --git a/src/FlawBOT/Modules/Search/RedditModule.cs b/src/FlawBOT.Core/Modules/Search/RedditModule.cs similarity index 89% rename from src/FlawBOT/Modules/Search/RedditModule.cs rename to src/FlawBOT.Core/Modules/Search/RedditModule.cs index c68ddce0..0b341730 100644 --- a/src/FlawBOT/Modules/Search/RedditModule.cs +++ b/src/FlawBOT.Core/Modules/Search/RedditModule.cs @@ -1,13 +1,12 @@ -using DSharpPlus.CommandsNext; +using System.Linq; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Search; -using System.Linq; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Search +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class RedditModule : BaseCommandModule diff --git a/src/FlawBOT/Modules/Search/SimpsonsModule.cs b/src/FlawBOT.Core/Modules/Search/SimpsonsModule.cs similarity index 89% rename from src/FlawBOT/Modules/Search/SimpsonsModule.cs rename to src/FlawBOT.Core/Modules/Search/SimpsonsModule.cs index 80251910..fb1a5c10 100644 --- a/src/FlawBOT/Modules/Search/SimpsonsModule.cs +++ b/src/FlawBOT.Core/Modules/Search/SimpsonsModule.cs @@ -1,18 +1,14 @@ -using DSharpPlus.CommandsNext; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using FlawBOT.Services.Search; -using System.Threading.Tasks; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Search +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class SimpsonsModule : BaseCommandModule { - private readonly string simpsons_site = "frinkiac"; - private readonly string futurama_site = "morbotron"; - private readonly string rickmorty_site = "masterofallscience"; - #region COMMAND_SIMPSONS [Command("simpsons")] @@ -20,7 +16,7 @@ public class SimpsonsModule : BaseCommandModule [Description("Retrieve a random Simpsons screenshot and episode")] public async Task Simpsons(CommandContext ctx) { - var results = await SimpsonsService.GetSimpsonsDataAsync(simpsons_site); + var results = await SimpsonsService.GetSimpsonsDataAsync(SimpsonsService.SiteRoot.Frinkiac); await ctx.RespondAsync(embed: results.Build()); } @@ -34,12 +30,12 @@ public async Task Simpsons(CommandContext ctx) public async Task SimpsonsGIF(CommandContext ctx, [Description("Inputting anything will add episode information")] [RemainingText] string input) { - var output = await SimpsonsService.GetSimpsonsGifAsync(simpsons_site); + var output = await SimpsonsService.GetSimpsonsGifAsync(SimpsonsService.SiteRoot.Frinkiac); if (string.IsNullOrWhiteSpace(input)) await ctx.RespondAsync(output); else // Include episode information if any kind of parameter is inputted { - var results = await SimpsonsService.GetSimpsonsDataAsync(simpsons_site); + var results = await SimpsonsService.GetSimpsonsDataAsync(SimpsonsService.SiteRoot.Frinkiac); results.WithFooter("Note: First time gifs take a few minutes to properly generate"); await ctx.RespondAsync(output, embed: results.Build()); } @@ -54,7 +50,7 @@ public async Task SimpsonsGIF(CommandContext ctx, [Description("Retrieve a random Futurama screenshot and episode")] public async Task Futurama(CommandContext ctx) { - var results = await SimpsonsService.GetSimpsonsDataAsync(futurama_site); + var results = await SimpsonsService.GetSimpsonsDataAsync(SimpsonsService.SiteRoot.Morbotron); results.WithColor(new DiscordColor("#69E398")); await ctx.RespondAsync(embed: results.Build()); } @@ -69,12 +65,12 @@ public async Task Futurama(CommandContext ctx) public async Task FuturamaGIF(CommandContext ctx, [Description("Inputting anything will add episode information")] [RemainingText] string input) { - var output = await SimpsonsService.GetSimpsonsGifAsync(futurama_site); + var output = await SimpsonsService.GetSimpsonsGifAsync(SimpsonsService.SiteRoot.Morbotron); if (string.IsNullOrWhiteSpace(input)) await ctx.RespondAsync(output); else // Include episode information if any kind of parameter is inputted { - var results = await SimpsonsService.GetSimpsonsDataAsync(futurama_site); + var results = await SimpsonsService.GetSimpsonsDataAsync(SimpsonsService.SiteRoot.Morbotron); results.WithFooter("Note: First time gifs take a few minutes to properly generate"); results.WithColor(new DiscordColor("#69E398")); await ctx.RespondAsync(output, embed: results.Build()); @@ -90,7 +86,7 @@ public async Task FuturamaGIF(CommandContext ctx, [Description("Retrieve a random Rick and Morty screenshot and episode")] public async Task RickMorty(CommandContext ctx) { - var results = await SimpsonsService.GetSimpsonsDataAsync(rickmorty_site); + var results = await SimpsonsService.GetSimpsonsDataAsync(SimpsonsService.SiteRoot.MasterOfAllScience); results.WithColor(new DiscordColor("#ABD5EC")); await ctx.RespondAsync(embed: results.Build()); } @@ -105,12 +101,12 @@ public async Task RickMorty(CommandContext ctx) public async Task RickMortyGif(CommandContext ctx, [Description("Inputting anything will add episode information")] [RemainingText] string input) { - var output = await SimpsonsService.GetSimpsonsGifAsync(rickmorty_site); + var output = await SimpsonsService.GetSimpsonsGifAsync(SimpsonsService.SiteRoot.MasterOfAllScience); if (string.IsNullOrWhiteSpace(input)) await ctx.RespondAsync(output); else // Include episode information if any kind of parameter is inputted { - var results = await SimpsonsService.GetSimpsonsDataAsync(rickmorty_site); + var results = await SimpsonsService.GetSimpsonsDataAsync(SimpsonsService.SiteRoot.MasterOfAllScience); results.WithFooter("Note: First time gifs take a few minutes to properly generate"); results.WithColor(new DiscordColor("#ABD5EC")); await ctx.RespondAsync(output, embed: results.Build()); diff --git a/src/FlawBOT/Modules/Search/TwitchModule.cs b/src/FlawBOT.Core/Modules/Search/TwitchModule.cs similarity index 81% rename from src/FlawBOT/Modules/Search/TwitchModule.cs rename to src/FlawBOT.Core/Modules/Search/TwitchModule.cs index 4698dfa6..475fa0ee 100644 --- a/src/FlawBOT/Modules/Search/TwitchModule.cs +++ b/src/FlawBOT.Core/Modules/Search/TwitchModule.cs @@ -1,12 +1,11 @@ -using DSharpPlus.CommandsNext; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Search; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Search +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class TwitchModule : BaseCommandModule @@ -26,11 +25,10 @@ public async Task Twitch(CommandContext ctx, else { var stream = results.Stream; - stream.Game = (string.IsNullOrWhiteSpace(stream.Game)) ? "Nothing" : stream.Game; var output = new DiscordEmbedBuilder() .WithTitle(stream.Channel.Name + " is now live on Twitch!") .WithDescription(stream.Channel.Status) - .AddField("Now Playing", stream.Game) + .AddField("Now Playing", (stream.Game) ?? "Nothing") .AddField("Start Time", stream.CreatedAt.ToString(), true) .AddField("Viewers", $"{stream.Viewers:#,##0}", true) .WithThumbnailUrl(stream.Channel.Logo) diff --git a/src/FlawBOT/Modules/Search/WikipediaModule.cs b/src/FlawBOT.Core/Modules/Search/WikipediaModule.cs similarity index 83% rename from src/FlawBOT/Modules/Search/WikipediaModule.cs rename to src/FlawBOT.Core/Modules/Search/WikipediaModule.cs index ba19ff2b..48f4c19e 100644 --- a/src/FlawBOT/Modules/Search/WikipediaModule.cs +++ b/src/FlawBOT.Core/Modules/Search/WikipediaModule.cs @@ -1,11 +1,10 @@ -using DSharpPlus.CommandsNext; +using System.Threading.Tasks; +using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; -using FlawBOT.Models; -using FlawBOT.Services; -using FlawBOT.Services.Search; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Search +namespace FlawBOT.Modules { [Cooldown(3, 5, CooldownBucketType.Channel)] public class WikipediaModule : BaseCommandModule diff --git a/src/FlawBOT/Modules/Search/YoutubeModule.cs b/src/FlawBOT.Core/Modules/Search/YoutubeModule.cs similarity index 95% rename from src/FlawBOT/Modules/Search/YoutubeModule.cs rename to src/FlawBOT.Core/Modules/Search/YoutubeModule.cs index e109e897..d74401ec 100644 --- a/src/FlawBOT/Modules/Search/YoutubeModule.cs +++ b/src/FlawBOT.Core/Modules/Search/YoutubeModule.cs @@ -1,11 +1,10 @@ -using DSharpPlus; +using System.Threading.Tasks; +using DSharpPlus; using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; -using FlawBOT.Services; -using FlawBOT.Services.Search; -using System.Threading.Tasks; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Search +namespace FlawBOT.Modules { [Group("youtube")] [Aliases("yt")] diff --git a/src/FlawBOT/Modules/Server/ChannelModule.cs b/src/FlawBOT.Core/Modules/Server/ChannelModule.cs similarity index 98% rename from src/FlawBOT/Modules/Server/ChannelModule.cs rename to src/FlawBOT.Core/Modules/Server/ChannelModule.cs index 478c0956..aba1fec8 100644 --- a/src/FlawBOT/Modules/Server/ChannelModule.cs +++ b/src/FlawBOT.Core/Modules/Server/ChannelModule.cs @@ -1,19 +1,20 @@ -using DSharpPlus; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using DSharpPlus.Interactivity; -using DSharpPlus.Net.Models; -using FlawBOT.Models; -using FlawBOT.Services; -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; +using DSharpPlus; +using DSharpPlus.CommandsNext; +using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus.Entities; +using DSharpPlus.Interactivity; +using DSharpPlus.Net.Models; +using FlawBOT.Common; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Server +namespace FlawBOT.Modules { [Group("channel")] [Aliases("chn", "ch", "c")] @@ -108,7 +109,7 @@ public Task GetChannel(CommandContext ctx, .AddField("NSFW", channel.IsNSFW ? "YES" : "NO", true) .WithThumbnailUrl(ctx.Guild.IconUrl) .WithFooter("Created on " + channel.CreationTimestamp.DateTime.ToString(CultureInfo.InvariantCulture)) - .WithColor(DiscordColor.Aquamarine); + .WithColor(SharedData.DefaultColor); if (channel.Type == ChannelType.Voice) { output.AddField("Bitrate", channel.Bitrate.ToString(), true); diff --git a/src/FlawBOT/Modules/Server/RoleModule.cs b/src/FlawBOT.Core/Modules/Server/RoleModule.cs similarity index 98% rename from src/FlawBOT/Modules/Server/RoleModule.cs rename to src/FlawBOT.Core/Modules/Server/RoleModule.cs index 8bca295f..36e2fab8 100644 --- a/src/FlawBOT/Modules/Server/RoleModule.cs +++ b/src/FlawBOT.Core/Modules/Server/RoleModule.cs @@ -1,17 +1,17 @@ -using DSharpPlus; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using FlawBOT.Models; -using FlawBOT.Services; -using System; +using System; using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using DSharpPlus; +using DSharpPlus.CommandsNext; +using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus.Entities; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Server +namespace FlawBOT.Modules { [Group("roles")] [Aliases("role", "rl")] diff --git a/src/FlawBOT/Modules/Server/ServerModule.cs b/src/FlawBOT.Core/Modules/Server/ServerModule.cs similarity index 98% rename from src/FlawBOT/Modules/Server/ServerModule.cs rename to src/FlawBOT.Core/Modules/Server/ServerModule.cs index b5ad2e65..86c00435 100644 --- a/src/FlawBOT/Modules/Server/ServerModule.cs +++ b/src/FlawBOT.Core/Modules/Server/ServerModule.cs @@ -1,16 +1,16 @@ -using DSharpPlus; +using System; +using System.Globalization; +using System.Text; +using System.Threading.Tasks; +using DSharpPlus; using DSharpPlus.CommandsNext; using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; using DSharpPlus.Interactivity; -using FlawBOT.Models; -using FlawBOT.Services; -using System; -using System.Globalization; -using System.Text; -using System.Threading.Tasks; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Server +namespace FlawBOT.Modules { [Group("server")] [Aliases("guild")] diff --git a/src/FlawBOT/Modules/Server/UserModule.cs b/src/FlawBOT.Core/Modules/Server/UserModule.cs similarity index 98% rename from src/FlawBOT/Modules/Server/UserModule.cs rename to src/FlawBOT.Core/Modules/Server/UserModule.cs index 0423c243..23d2104a 100644 --- a/src/FlawBOT/Modules/Server/UserModule.cs +++ b/src/FlawBOT.Core/Modules/Server/UserModule.cs @@ -1,15 +1,15 @@ -using DSharpPlus; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using FlawBOT.Models; -using FlawBOT.Services; -using System; +using System; using System.Globalization; using System.Text; using System.Threading.Tasks; +using DSharpPlus; +using DSharpPlus.CommandsNext; +using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus.Entities; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; -namespace FlawBOT.Modules.Server +namespace FlawBOT.Modules { [Group("user")] [Aliases("users", "u", "usr")] diff --git a/src/FlawBOT/NuGet.Config b/src/FlawBOT.Core/NuGet.Config similarity index 100% rename from src/FlawBOT/NuGet.Config rename to src/FlawBOT.Core/NuGet.Config diff --git a/src/FlawBOT/Program.cs b/src/FlawBOT.Core/Program.cs similarity index 73% rename from src/FlawBOT/Program.cs rename to src/FlawBOT.Core/Program.cs index 626c7de2..14216faa 100644 --- a/src/FlawBOT/Program.cs +++ b/src/FlawBOT.Core/Program.cs @@ -1,25 +1,22 @@ -using DSharpPlus; +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using DSharpPlus; using DSharpPlus.CommandsNext; +using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.CommandsNext.Exceptions; using DSharpPlus.Entities; using DSharpPlus.EventArgs; using DSharpPlus.Interactivity; using DSharpPlus.Interactivity.Enums; using FlawBOT.Common; -using FlawBOT.Models; -using FlawBOT.Modules.Bot; -using FlawBOT.Modules.Games; -using FlawBOT.Modules.Misc; -using FlawBOT.Modules.Search; -using FlawBOT.Modules.Server; -using FlawBOT.Services; -using FlawBOT.Services.Games; -using FlawBOT.Services.Search; -using System; -using System.IO; -using System.Net; -using System.Threading; -using System.Threading.Tasks; +using FlawBOT.Framework.Common; +using FlawBOT.Framework.Models; +using FlawBOT.Framework.Services; +using FlawBOT.Modules; namespace FlawBOT { @@ -51,11 +48,11 @@ public static async Task Main(string[] args) public async Task RunBotAsync() { var service = new BotServices(); - service.UpdateTokenList(); + service.LoadBotConfiguration(); Client = new DiscordClient(new DiscordConfiguration { - Token = SharedData.Tokens.DiscordToken, + Token = TokenHandler.Tokens.DiscordToken, TokenType = TokenType.Bot, AutoReconnect = true, LogLevel = LogLevel.Info, @@ -76,28 +73,27 @@ public async Task RunBotAsync() { PrefixResolver = PrefixResolverAsync, // Set the command prefix that will be used by the bot EnableDms = false, // Set the boolean for responding to direct messages - //EnableDefaultHelp = false, EnableMentionPrefix = true, // Set the boolean for mentioning the bot as a command prefix CaseSensitive = false, - //DefaultHelpChecks = new List() }); Commands.CommandExecuted += Commands_CommandExecuted; Commands.CommandErrored += Commands_CommandErrored; - Commands.SetHelpFormatter(); Commands.RegisterCommands(); Commands.RegisterCommands(); Commands.RegisterCommands(); - Commands.RegisterCommands(); Commands.RegisterCommands(); + Commands.RegisterCommands(); Commands.RegisterCommands(); Commands.RegisterCommands(); Commands.RegisterCommands(); Commands.RegisterCommands(); + Commands.RegisterCommands(); Commands.RegisterCommands(); Commands.RegisterCommands(); - Commands.RegisterCommands(); Commands.RegisterCommands(); + Commands.RegisterCommands(); + Commands.RegisterCommands(); Commands.RegisterCommands(); Commands.RegisterCommands(); Commands.RegisterCommands(); @@ -112,22 +108,22 @@ public async Task RunBotAsync() // Start the uptime counter Console.Title = SharedData.Name + " (" + SharedData.Version + ")"; SharedData.ProcessStarted = DateTime.Now; - await SteamService.UpdateSteamListAsync().ConfigureAwait(false); // Update the Steam App list - await TeamFortressService.UpdateTF2SchemaAsync().ConfigureAwait(false); // Update the Pokemon list - await PokemonService.UpdatePokemonListAsync().ConfigureAwait(false); // Update the Pokemon list + await SteamService.UpdateSteamListAsync().ConfigureAwait(false); + await TeamFortressService.LoadTF2SchemaAsync().ConfigureAwait(false); + await PokemonService.UpdatePokemonListAsync().ConfigureAwait(false); await Client.ConnectAsync(); // Connect and log into Discord await Task.Delay(-1).ConfigureAwait(false); // Prevent the console window from closing } private static Task Client_Ready(ReadyEventArgs e) { - e.Client.DebugLogger.LogMessage(LogLevel.Info, SharedData.Name, SharedData.Name + $", version: " + SharedData.Version, DateTime.Now); + e.Client.DebugLogger.LogMessage(LogLevel.Info, SharedData.Name, SharedData.Name + ", version: " + SharedData.Version, DateTime.Now); return Task.CompletedTask; } private static Task Client_ClientError(ClientErrorEventArgs e) { - e.Client.DebugLogger.LogMessage(LogLevel.Error, SharedData.Name, $"Exception occured: " + e.Exception.GetType() + ": " + e.Exception.Message, DateTime.Now); + e.Client.DebugLogger.LogMessage(LogLevel.Error, SharedData.Name, "Exception occured: " + e.Exception.GetType() + ": " + e.Exception.Message, DateTime.Now); return Task.CompletedTask; } @@ -141,6 +137,47 @@ private static async Task Commands_CommandErrored(CommandErrorEventArgs e) { switch (e.Exception) { + case ChecksFailedException cfe: + switch (cfe.FailedChecks.First()) + { + case CooldownAttribute _: + return; + + default: + await BotServices.SendEmbedAsync(e.Context, $"Command **{e.Command.QualifiedName}** could not be executed.", EmbedType.Error); + foreach (var check in cfe.FailedChecks) + { + switch (check) + { + case RequirePermissionsAttribute perms: + await BotServices.SendEmbedAsync(e.Context, $"- One of us does not have the required permissions ({perms.Permissions.ToPermissionString()})!", EmbedType.Error); + break; + + case RequireUserPermissionsAttribute uperms: + await BotServices.SendEmbedAsync(e.Context, $"- You do not have sufficient permissions ({uperms.Permissions.ToPermissionString()})!", EmbedType.Error); + break; + + case RequireBotPermissionsAttribute bperms: + await BotServices.SendEmbedAsync(e.Context, $"- I do not have sufficient permissions ({bperms.Permissions.ToPermissionString()})!", EmbedType.Error); + break; + + case RequireOwnerAttribute _: + await BotServices.SendEmbedAsync(e.Context, $"- This command is reserved only for the bot owner.", EmbedType.Error); + break; + + case RequirePrefixesAttribute pa: + await BotServices.SendEmbedAsync(e.Context, $"- This command can only be invoked with the following prefixes: {string.Join(" ", pa.Prefixes)}.", EmbedType.Error); + break; + + default: + await BotServices.SendEmbedAsync(e.Context, "Unknown check triggered. Please notify the developer using the command *.bot report*", EmbedType.Error); + break; + } + } + break; + } + break; + case CommandNotFoundException _: //await BotServices.SendEmbedAsync(e.Context, "This command does not exist!", EmbedType.Error); break; @@ -176,7 +213,7 @@ private static async Task Commands_CommandErrored(CommandErrorEventArgs e) private static Task PrefixResolverAsync(DiscordMessage m) { - return Task.FromResult(m.GetStringPrefixLength(SharedData.Tokens.CommandPrefix)); + return Task.FromResult(m.GetStringPrefixLength(TokenHandler.Tokens.CommandPrefix)); } private static void Client_LogMessageHandler(object sender, DebugLogMessageEventArgs ea) diff --git a/src/FlawBOT.Core/Properties/launchSettings.json b/src/FlawBOT.Core/Properties/launchSettings.json new file mode 100644 index 00000000..7276b364 --- /dev/null +++ b/src/FlawBOT.Core/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "FlawBOT.Core": { + "commandName": "Project" + }, + "Docker": { + "commandName": "Docker" + } + } +} \ No newline at end of file diff --git a/src/FlawBOT.Core/config.json b/src/FlawBOT.Core/config.json new file mode 100644 index 00000000..d8a92c91 --- /dev/null +++ b/src/FlawBOT.Core/config.json @@ -0,0 +1,18 @@ +{ + "prefix": ".", + "discord": null, + "google": null, + "steam": null, + "steam64": null, + "imgur": null, + "omdb": null, + "twitch": null, + "nasa": null, + "teamworktf": null, + "backpacktf": null, + "backpacktf_secret": null, + "backpacktf_schema": null, + "reddit_appid": null, + "reddit_access": null, + "reddit_refresh": null +} \ No newline at end of file diff --git a/src/FlawBOT/icon.ico b/src/FlawBOT.Core/icon.ico similarity index 100% rename from src/FlawBOT/icon.ico rename to src/FlawBOT.Core/icon.ico diff --git a/src/FlawBOT/Common/HttpHandler.cs b/src/FlawBOT.Framework/Common/HttpHandler.cs similarity index 88% rename from src/FlawBOT/Common/HttpHandler.cs rename to src/FlawBOT.Framework/Common/HttpHandler.cs index 41469330..37322d61 100644 --- a/src/FlawBOT/Common/HttpHandler.cs +++ b/src/FlawBOT.Framework/Common/HttpHandler.cs @@ -1,6 +1,6 @@ using System.Net.Http; -namespace FlawBOT.Common +namespace FlawBOT.Framework.Common { public abstract class HttpHandler { diff --git a/src/FlawBOT.Framework/Common/TokenHandler.cs b/src/FlawBOT.Framework/Common/TokenHandler.cs new file mode 100644 index 00000000..b03956b6 --- /dev/null +++ b/src/FlawBOT.Framework/Common/TokenHandler.cs @@ -0,0 +1,9 @@ +using FlawBOT.Framework.Models; + +namespace FlawBOT.Framework.Common +{ + public class TokenHandler + { + public static TokenData Tokens { get; set; } = new TokenData(); + } +} \ No newline at end of file diff --git a/src/FlawBOT.Framework/FlawBOT.Framework.csproj b/src/FlawBOT.Framework/FlawBOT.Framework.csproj new file mode 100644 index 00000000..a62176cb --- /dev/null +++ b/src/FlawBOT.Framework/FlawBOT.Framework.csproj @@ -0,0 +1,39 @@ + + + + netcoreapp2.2 + 2.2.0.0 + 2.2.0 + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/src/FlawBOT/Models/Bot/BotData.cs b/src/FlawBOT.Framework/Models/Bot/BotData.cs similarity index 86% rename from src/FlawBOT/Models/Bot/BotData.cs rename to src/FlawBOT.Framework/Models/Bot/BotData.cs index dcc7a4c8..48a8fb8c 100644 --- a/src/FlawBOT/Models/Bot/BotData.cs +++ b/src/FlawBOT.Framework/Models/Bot/BotData.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace FlawBOT.Models +namespace FlawBOT.Framework.Models { public class TokenData { @@ -28,6 +28,9 @@ public class TokenData [JsonProperty("twitch")] public string TwitchToken { get; private set; } + [JsonProperty("nasa")] + public string NASAToken { get; private set; } + [JsonProperty("teamworktf")] public string TeamworkToken { get; private set; } @@ -37,6 +40,9 @@ public class TokenData [JsonProperty("backpacktf_secret")] public string BackpackAccess { get; private set; } + [JsonProperty("backpacktf_schema")] + public string BackpackSchema { get; private set; } + [JsonProperty("reddit_appid")] public string RedditAppToken { get; private set; } diff --git a/src/FlawBOT.Framework/Models/Games/AmiiboData.cs b/src/FlawBOT.Framework/Models/Games/AmiiboData.cs new file mode 100644 index 00000000..e79a06a6 --- /dev/null +++ b/src/FlawBOT.Framework/Models/Games/AmiiboData.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace FlawBOT.Framework.Models +{ + public class AmiiboData + { + [JsonProperty("amiibo")] + public List Amiibo { get; set; } + } + + public class Amiibo + { + [JsonProperty("amiiboSeries")] + public string AmiiboSeries { get; set; } + + [JsonProperty("character")] + public string Character { get; set; } + + [JsonProperty("gameSeries")] + public string GameSeries { get; set; } + + [JsonProperty("head")] + public string Head { get; set; } + + [JsonProperty("image")] + public string Image { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("release")] + public Release ReleaseDate { get; set; } + + [JsonProperty("tail")] + public string Tail { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + } + + public class Release + { + [JsonProperty("au")] + public string Australian { get; set; } + + [JsonProperty("eu")] + public string European { get; set; } + + [JsonProperty("jp")] + public string Japanese { get; set; } + + [JsonProperty("na")] + public string American { get; set; } + } +} \ No newline at end of file diff --git a/src/FlawBOT/Models/Games/PokemonData.cs b/src/FlawBOT.Framework/Models/Games/PokemonData.cs similarity index 85% rename from src/FlawBOT/Models/Games/PokemonData.cs rename to src/FlawBOT.Framework/Models/Games/PokemonData.cs index 5269d747..569a20c3 100644 --- a/src/FlawBOT/Models/Games/PokemonData.cs +++ b/src/FlawBOT.Framework/Models/Games/PokemonData.cs @@ -1,7 +1,7 @@ -using Newtonsoft.Json; -using System.Collections.Generic; +using System.Collections.Generic; +using Newtonsoft.Json; -namespace FlawBOT.Models +namespace FlawBOT.Framework.Models { public class PokemonCards { diff --git a/src/FlawBOT/Models/Games/SmashData.cs b/src/FlawBOT.Framework/Models/Games/SmashData.cs similarity index 51% rename from src/FlawBOT/Models/Games/SmashData.cs rename to src/FlawBOT.Framework/Models/Games/SmashData.cs index 395f6339..99ef3782 100644 --- a/src/FlawBOT/Models/Games/SmashData.cs +++ b/src/FlawBOT.Framework/Models/Games/SmashData.cs @@ -1,6 +1,7 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using Newtonsoft.Json; -namespace FlawBOT.Models +namespace FlawBOT.Framework.Models { public class SmashCharacter { @@ -30,29 +31,35 @@ public class SmashCharacter [JsonProperty("Game")] public string Game { get; set; } - - [JsonProperty("Related")] - public Related Related { get; set; } } - public class Related + public class SmashCharacterAttributes { - [JsonProperty("Ultimate")] - public Ultimate Ultimate { get; set; } + [JsonProperty("Name")] + public string Name { get; set; } + + [JsonProperty("OwnerId")] + public int OwnerId { get; set; } + + [JsonProperty("Owner")] + public string Owner { get; set; } + + [JsonProperty("Values")] + public List Attributes { get; set; } } - public class Ultimate + public class Attribute { - [JsonProperty("Self")] - public string Self { get; set; } + [JsonProperty("Name")] + public string Name { get; set; } - [JsonProperty("Moves")] - public string Moves { get; set; } + [JsonProperty("Value")] + public string Value { get; set; } - [JsonProperty("Movements")] - public string Movements { get; set; } + [JsonProperty("Owner")] + public string Owner { get; set; } - [JsonProperty("Attributes")] - public string Attributes { get; set; } + [JsonProperty("OwnerId")] + public int OwnerId { get; set; } } } \ No newline at end of file diff --git a/src/FlawBOT/Models/Games/SpeedrunData.cs b/src/FlawBOT.Framework/Models/Games/SpeedrunData.cs similarity index 92% rename from src/FlawBOT/Models/Games/SpeedrunData.cs rename to src/FlawBOT.Framework/Models/Games/SpeedrunData.cs index 0ea79358..77845c58 100644 --- a/src/FlawBOT/Models/Games/SpeedrunData.cs +++ b/src/FlawBOT.Framework/Models/Games/SpeedrunData.cs @@ -1,8 +1,8 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; +using Newtonsoft.Json; -namespace FlawBOT.Models.Games +namespace FlawBOT.Framework.Models { #region MODEL_GAME @@ -11,8 +11,8 @@ public class SpeedrunGame [JsonProperty("data")] public List Data { get; set; } - [JsonProperty("pagination")] [JsonIgnore] + [JsonProperty("pagination")] public Pagination Pagination { get; set; } } @@ -21,8 +21,8 @@ public class Names [JsonProperty("international")] public string International { get; set; } - [JsonProperty("japanese")] [JsonIgnore] + [JsonProperty("japanese")] public string Japanese { get; set; } [JsonProperty("twitch")] @@ -40,22 +40,18 @@ public class Ruleset [JsonProperty("require-video")] public bool RequiresVideo { get; set; } - [JsonProperty("run-times")] [JsonIgnore] + [JsonProperty("run-times")] public List RunTimes { get; set; } - [JsonProperty("default-time")] [JsonIgnore] + [JsonProperty("default-time")] public string DefaultTime { get; set; } [JsonProperty("emulators-allowed")] public bool EmulatorsAllowed { get; set; } } - public class Moderators - { - } - public class Logo { [JsonProperty("uri")] @@ -196,22 +192,18 @@ public class Assets [JsonProperty("icon")] public Icon Icon { get; set; } - [JsonProperty("trophy-1st")] [JsonIgnore] + [JsonProperty("trophy-1st")] public Trophy1st Trophy1st { get; set; } - [JsonProperty("trophy-2nd")] [JsonIgnore] + [JsonProperty("trophy-2nd")] public Trophy2nd Trophy2nd { get; set; } - [JsonProperty("trophy-3rd")] [JsonIgnore] + [JsonProperty("trophy-3rd")] public Trophy3rd Trophy3rd { get; set; } - [JsonProperty("trophy-4th")] - [JsonIgnore] - public object Trophy4th { get; set; } - [JsonProperty("background")] public Background Background { get; set; } @@ -249,7 +241,7 @@ public class Datum public List GameTypes { get; set; } [JsonProperty("platforms")] - public List Platforms { get; set; } + public List Platforms { get; set; } [JsonProperty("regions")] public List Regions { get; set; } @@ -266,12 +258,8 @@ public class Datum [JsonProperty("publishers")] public List Publishers { get; set; } - [JsonProperty("moderators")] - [JsonIgnore] - public Moderators Moderators { get; set; } - [JsonProperty("created")] - public DateTime Created { get; set; } + public DateTime? Created { get; set; } [JsonProperty("assets")] public Assets Assets { get; set; } @@ -300,26 +288,26 @@ public class Link2 public class Pagination { - [JsonProperty("offset")] [JsonIgnore] + [JsonProperty("offset")] public int Offset { get; set; } - [JsonProperty("max")] [JsonIgnore] + [JsonProperty("max")] public int Max { get; set; } - [JsonProperty("size")] [JsonIgnore] + [JsonProperty("size")] public int Size { get; set; } - [JsonProperty("links")] [JsonIgnore] + [JsonProperty("links")] public List Links { get; set; } } #endregion MODEL_GAME - #region MODEL_PLATFORM + #region MODEL_OTHER public class PlatformLinks { @@ -330,7 +318,7 @@ public class PlatformLinks public string URL { get; set; } } - public class PlatformData + public class Data { [JsonProperty("id")] public string ID { get; set; } @@ -339,17 +327,25 @@ public class PlatformData public string Name { get; set; } [JsonProperty("released")] - public int Released { get; set; } + public int? Released { get; set; } [JsonProperty("links")] public List Links { get; set; } } - public class SpeedrunPlatform + public class SpeedrunExtra { [JsonProperty("data")] - public PlatformData Data { get; set; } + public Data Data { get; set; } } - #endregion MODEL_PLATFORM + #endregion MODEL_OTHER + + public enum SpeedrunExtras + { + Platforms, + Genres, + Developers, + Publishers + } } \ No newline at end of file diff --git a/src/FlawBOT/Models/Games/TeamFortressData.cs b/src/FlawBOT.Framework/Models/Games/TeamFortressData.cs similarity index 50% rename from src/FlawBOT/Models/Games/TeamFortressData.cs rename to src/FlawBOT.Framework/Models/Games/TeamFortressData.cs index 8d4c4c34..4d06f116 100644 --- a/src/FlawBOT/Models/Games/TeamFortressData.cs +++ b/src/FlawBOT.Framework/Models/Games/TeamFortressData.cs @@ -1,7 +1,7 @@ -using Newtonsoft.Json; -using System.Collections.Generic; +using System.Collections.Generic; +using Newtonsoft.Json; -namespace FlawBOT.Models +namespace FlawBOT.Framework.Models { #region TEAMWORK_NEWS @@ -132,229 +132,305 @@ public class TeamworkMap #endregion TEAMWORK_MAPS - #region ITEM_SCHEMA + #region SCHEMA - public class Capabilities + public class TFItemSchema { - [JsonProperty("nameable")] - public bool Nameable { get; set; } + [JsonProperty("result")] + public Result Results { get; set; } + } - [JsonProperty("can_gift_wrap")] - public bool CanGiftWrap { get; set; } + public class Result + { + [JsonProperty("originNames")] + public List OriginNames { get; set; } - [JsonProperty("can_craft_mark")] - public bool CanCraft { get; set; } + [JsonProperty("attribute_controlled_attached_particles")] + public List UnusualEffect { get; set; } - [JsonProperty("can_be_restored")] - public bool CanBeRestored { get; set; } + [JsonProperty("qualities")] + public QualityId QualityId { get; set; } - [JsonProperty("strange_parts")] - public bool StrangeParts { get; set; } + [JsonProperty("qualityNames")] + public QualityName QualityName { get; set; } - [JsonProperty("can_card_upgrade")] - public bool CanCardUpgrade { get; set; } + [JsonProperty("attributes")] + public List Attributes { get; set; } - [JsonProperty("can_strangify")] - public bool CanStrangify { get; set; } + [JsonProperty("items")] + public List Items { get; set; } + } - [JsonProperty("can_killstreakify")] - public bool CanKillstreakify { get; set; } + public class ItemOrigin + { + [JsonProperty("origin")] + public int Id { get; set; } - [JsonProperty("can_consume")] - public bool CanConsume { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + } - [JsonProperty("can_collect")] - public bool? CanCollect { get; set; } + public class UnusualEffect + { + [JsonProperty("id")] + public int Id { get; set; } - [JsonProperty("paintable")] - public bool? Paintable { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + } - [JsonProperty("can_craft_if_purchased")] - public bool? CanCraftIfPurchased { get; set; } + public class QualityId + { + [JsonProperty("Unique")] + public string Unique { get; set; } - [JsonProperty("can_craft_count")] - public bool? CanCraftCount { get; set; } + [JsonProperty("selfmade")] + public string SelfMade { get; set; } - [JsonProperty("can_unusualify")] - public bool? CanUnusualify { get; set; } + [JsonProperty("collectors")] + public string Collectors { get; set; } - [JsonProperty("usable_gc")] - public bool? UsableGC { get; set; } + [JsonProperty("Normal")] + public string Normal { get; set; } - [JsonProperty("usable")] - public bool? Usable { get; set; } + [JsonProperty("vintage")] + public string Vintage { get; set; } - [JsonProperty("can_customize_texture")] - public bool? CanCustomizeTexture { get; set; } + [JsonProperty("completed")] + public string Completed { get; set; } - [JsonProperty("usable_out_of_game")] - public bool? UsableOutOfGame { get; set; } + [JsonProperty("customized")] + public string Customized { get; set; } - [JsonProperty("can_spell_page")] - public bool? CanSpellPage { get; set; } + [JsonProperty("rarity1")] + public string Rarity1 { get; set; } - [JsonProperty("duck_upgradable")] - public bool? DuckUpgradable { get; set; } - } + [JsonProperty("rarity2")] + public string Rarity2 { get; set; } - public class AdditionalHiddenBodygroups - { - [JsonProperty("hat")] - public int Hat { get; set; } + [JsonProperty("rarity3")] + public string Rarity3 { get; set; } - [JsonProperty("headphones")] - public int Headphones { get; set; } + [JsonProperty("rarity4")] + public string Rarity4 { get; set; } - [JsonProperty("head")] - public int? Head { get; set; } - } + [JsonProperty("paintkitweapon")] + public string PaintKit { get; set; } - public class Style - { - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("strange")] + public string Strange { get; set; } + + [JsonProperty("haunted")] + public string Haunted { get; set; } + + [JsonProperty("community")] + public string Community { get; set; } - [JsonProperty("additional_hidden_bodygroups")] - public AdditionalHiddenBodygroups HiddenBodyGroups { get; set; } + [JsonProperty("developer")] + public string Developer { get; set; } } - public class Attribute + public class QualityName { - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("Unique")] + public string Unique { get; set; } - [JsonProperty("@class")] - public string Class { get; set; } + [JsonProperty("selfmade")] + public string SelfMade { get; set; } - [JsonProperty("value")] - public double Value { get; set; } - } + [JsonProperty("collectors")] + public string Collectors { get; set; } - public class PerClassLoadoutSlots - { - [JsonProperty("Soldier")] - public string Soldier { get; set; } + [JsonProperty("Normal")] + public string Normal { get; set; } - [JsonProperty("Heavy")] - public string Heavy { get; set; } + [JsonProperty("vintage")] + public string Vintage { get; set; } - [JsonProperty("Pyro")] - public string Pyro { get; set; } + [JsonProperty("completed")] + public string Completed { get; set; } - [JsonProperty("Engineer")] - public string Engineer { get; set; } + [JsonProperty("customized")] + public string Customized { get; set; } - [JsonProperty("Demoman")] - public string Demoman { get; set; } - } + [JsonProperty("rarity1")] + public string Rarity1 { get; set; } - public class Tool - { - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("rarity2")] + public string Rarity2 { get; set; } + + [JsonProperty("rarity3")] + public string Rarity3 { get; set; } + + [JsonProperty("rarity4")] + public string Rarity4 { get; set; } + + [JsonProperty("paintkitweapon")] + public string PaintKit { get; set; } + + [JsonProperty("strange")] + public string Strange { get; set; } + + [JsonProperty("haunted")] + public string Haunted { get; set; } + + [JsonProperty("community")] + public string Community { get; set; } + + [JsonProperty("developer")] + public string Developer { get; set; } } - public class SchemaItem + public class Attributes { + [JsonProperty("defindex")] + public int Id { get; set; } + [JsonProperty("name")] public string Name { get; set; } - [JsonProperty("defindex")] - public int DefIndex { get; set; } + [JsonProperty("description_string")] + public string Description { get; set; } - [JsonProperty("item_class")] - public string ItemClass { get; set; } + [JsonProperty("effect_type")] + public string EffectType { get; set; } - [JsonProperty("item_type_name")] - public string ItemTypeName { get; set; } + [JsonProperty("hidden")] + public bool Hidden { get; set; } + } - [JsonProperty("item_name")] - public string ItemName { get; set; } + public class Level + { + [JsonProperty("level")] + public int Id { get; set; } - [JsonProperty("proper_name")] - public bool ProperName { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("item_slot")] - public string ItemSlot { get; set; } + [JsonProperty("required_score")] + public int ReqScore { get; set; } + } - [JsonProperty("model_player")] - public string ModelPlayer { get; set; } + #endregion SCHEMA - [JsonProperty("item_quality")] - public int ItemQuality { get; set; } + #region ITEM - [JsonProperty("image_inventory")] - public string ImageInventory { get; set; } + public class SchemaItem + { + [JsonProperty("defindex")] + public int DefIndex { get; set; } - [JsonProperty("min_ilevel")] - public int MinILevel { get; set; } + [JsonProperty("used_by_classes")] + public List UsedByClasses { get; set; } - [JsonProperty("max_ilevel")] - public int MaxILevel { get; set; } + [JsonProperty("item_name")] + public string ItemName { get; set; } - [JsonProperty("image_url")] - public string ImageUrl { get; set; } + [JsonProperty("name")] + public string ItemName2 { get; set; } - [JsonProperty("image_url_large")] - public string ImageUrlLarge { get; set; } + [JsonProperty("item_description")] + public string Description { get; set; } - [JsonProperty("craft_class")] - public string CraftClass { get; set; } + [JsonProperty("image_inventory")] + public string ItemImagePath { get; set; } + + [JsonProperty("item_type_name")] + public string ItemType { get; set; } - [JsonProperty("craft_material_type")] - public string CraftMaterialType { get; set; } + [JsonProperty("item_slot")] + public string ItemSlot { get; set; } [JsonProperty("capabilities")] public Capabilities Capabilities { get; set; } - [JsonProperty("used_by_classes")] - public List UsedByClasses { get; set; } + [JsonProperty("image_url")] + public string ImageURL { get; set; } - [JsonProperty("item_description")] - public string ItemDescription { get; set; } + [JsonProperty("image_url_large")] + public string ImageURL_Large { get; set; } + + [JsonProperty("item_quality")] + public int QualityId { get; set; } [JsonProperty("styles")] public List