From 846c928f5f5dd551963b61e5a4490fd42d3e2353 Mon Sep 17 00:00:00 2001 From: runebaas Date: Sat, 28 Apr 2018 01:01:48 +0200 Subject: [PATCH] Add wikipedia api client, add wikipedia command, show errors in chat when debugging --- .gitignore | 4 + Geekbot.net.sln | 6 ++ Geekbot.net/Commands/Wikipedia.cs | 94 +++++++++++++++++++ Geekbot.net/Geekbot.net.csproj | 6 +- Geekbot.net/Lib/ErrorHandler.cs | 18 +++- Geekbot.net/Program.cs | 9 +- WikipediaApi/IWikipediaClient.cs | 10 ++ WikipediaApi/Page/PageApiUrls.cs | 14 +++ WikipediaApi/Page/PageContentUrlCollection.cs | 8 ++ WikipediaApi/Page/PageContentUrls.cs | 12 +++ WikipediaApi/Page/PageCoordinates.cs | 8 ++ WikipediaApi/Page/PageImage.cs | 12 +++ WikipediaApi/Page/PageNamespace.cs | 8 ++ WikipediaApi/Page/PagePreview.cs | 68 ++++++++++++++ WikipediaApi/Page/PageTitles.cs | 10 ++ WikipediaApi/Page/PageTypes.cs | 19 ++++ WikipediaApi/WikipediaApi.csproj | 8 ++ WikipediaApi/WikipediaClient.cs | 29 ++++++ 18 files changed, 334 insertions(+), 9 deletions(-) create mode 100644 Geekbot.net/Commands/Wikipedia.cs create mode 100644 WikipediaApi/IWikipediaClient.cs create mode 100644 WikipediaApi/Page/PageApiUrls.cs create mode 100644 WikipediaApi/Page/PageContentUrlCollection.cs create mode 100644 WikipediaApi/Page/PageContentUrls.cs create mode 100644 WikipediaApi/Page/PageCoordinates.cs create mode 100644 WikipediaApi/Page/PageImage.cs create mode 100644 WikipediaApi/Page/PageNamespace.cs create mode 100644 WikipediaApi/Page/PagePreview.cs create mode 100644 WikipediaApi/Page/PageTitles.cs create mode 100644 WikipediaApi/Page/PageTypes.cs create mode 100644 WikipediaApi/WikipediaApi.csproj create mode 100644 WikipediaApi/WikipediaClient.cs diff --git a/.gitignore b/.gitignore index c99d9e6..fe7e3d4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,7 @@ UpgradeLog.htm .vscode Geekbot.net/Logs/* !/Geekbot.net/Logs/.keep +Geekbot.net.sln.DotSettings.user +Geekbot.net/temp/ +WikipediaApi/bin/ +WikipediaApi/obj/ diff --git a/Geekbot.net.sln b/Geekbot.net.sln index 5011ad4..b542f25 100644 --- a/Geekbot.net.sln +++ b/Geekbot.net.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geekbot.net", "Geekbot.net/ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WikipediaApi", "WikipediaApi\WikipediaApi.csproj", "{1084D499-EF94-4834-9E6A-B2AD81B60078}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Debug|Any CPU.Build.0 = Debug|Any CPU {4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Release|Any CPU.ActiveCfg = Release|Any CPU {4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Release|Any CPU.Build.0 = Release|Any CPU + {1084D499-EF94-4834-9E6A-B2AD81B60078}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1084D499-EF94-4834-9E6A-B2AD81B60078}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1084D499-EF94-4834-9E6A-B2AD81B60078}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1084D499-EF94-4834-9E6A-B2AD81B60078}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Geekbot.net/Commands/Wikipedia.cs b/Geekbot.net/Commands/Wikipedia.cs new file mode 100644 index 0000000..d0ea945 --- /dev/null +++ b/Geekbot.net/Commands/Wikipedia.cs @@ -0,0 +1,94 @@ +using System; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Discord.Net; +using Geekbot.net.Lib; +using HtmlAgilityPack; +using WikipediaApi; +using WikipediaApi.Page; + +namespace Geekbot.net.Commands +{ + public class Wikipedia : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IWikipediaClient _wikipediaClient; + + public Wikipedia(IErrorHandler errorHandler, IWikipediaClient wikipediaClient) + { + _errorHandler = errorHandler; + _wikipediaClient = wikipediaClient; + } + + [Command("wiki", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Get an article from wikipedia.")] + public async Task GetPreview([Remainder] [Summary("Article")] string articleName) + { + try + { + var article = await _wikipediaClient.GetPreview(articleName.Replace(" ", "_")); + + if (article.Type != PageTypes.Standard) + { + switch (article.Type) + { + case PageTypes.Disambiguation: + await ReplyAsync($"**__Disambiguation__**\r\n{DisambiguationExtractor(article.ExtractHtml)}"); + break; + case PageTypes.MainPage: + await ReplyAsync("The main page is not supported"); + break; + case PageTypes.NoExtract: + await ReplyAsync($"This page has no summary, here is the link: {article.ContentUrls.Desktop.Page}"); + break; + case PageTypes.Standard: + break; + default: + await ReplyAsync($"This page type is currently not supported, here is the link: {article.ContentUrls.Desktop.Page}"); + break; + } + return; + } + + var eb = new EmbedBuilder + { + Title = article.Title, + Description = article.Extract, + ImageUrl = article.Thumbnail.Source.ToString(), + Url = article.ContentUrls.Desktop.Page.ToString() + }; + await ReplyAsync("", false, eb.Build()); + } + catch (HttpRequestException e) + { + await ReplyAsync("I couldn't find that article"); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + private string DisambiguationExtractor(string extractHtml) + { + var doc = new HtmlDocument(); + doc.LoadHtml(extractHtml); + var nodes = doc.DocumentNode.SelectNodes("//li"); + var sb = new StringBuilder(); + foreach (var node in nodes) + { + var split = node.InnerText.Split(','); + var title = split.First(); + var desc = string.Join(",", split.Skip(1)); + sb.AppendLine($"**{title}** - {desc}"); + } + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Geekbot.net.csproj b/Geekbot.net/Geekbot.net.csproj index 1a11cd9..6fb13f9 100755 --- a/Geekbot.net/Geekbot.net.csproj +++ b/Geekbot.net/Geekbot.net.csproj @@ -15,6 +15,7 @@ 1.0.2 + @@ -22,7 +23,7 @@ - + @@ -76,4 +77,7 @@ PreserveNewest + + + \ No newline at end of file diff --git a/Geekbot.net/Lib/ErrorHandler.cs b/Geekbot.net/Lib/ErrorHandler.cs index 3410e91..c0c3d95 100644 --- a/Geekbot.net/Lib/ErrorHandler.cs +++ b/Geekbot.net/Lib/ErrorHandler.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Diagnostics; using System.Net; using Discord.Commands; using Discord.Net; @@ -12,12 +14,14 @@ namespace Geekbot.net.Lib private readonly IGeekbotLogger _logger; private readonly ITranslationHandler _translation; private readonly IRavenClient _raven; + private readonly bool _errorsInChat; - public ErrorHandler(IGeekbotLogger logger, ITranslationHandler translation) + public ErrorHandler(IGeekbotLogger logger, ITranslationHandler translation, bool errorsInChat) { _logger = logger; _translation = translation; - + _errorsInChat = errorsInChat; + var sentryDsn = Environment.GetEnvironmentVariable("SENTRY"); if (!string.IsNullOrEmpty(sentryDsn)) { @@ -41,7 +45,15 @@ namespace Geekbot.net.Lib _logger.Error("Geekbot", "An error ocured", e, errorObj); if (!string.IsNullOrEmpty(errorMessage)) { - Context.Channel.SendMessageAsync(errorString); + if (_errorsInChat) + { + Context.Channel.SendMessageAsync($"{e.Message}\r\n```\r\n{e.InnerException}\r\n```"); + } + else + { + Context.Channel.SendMessageAsync(errorString); + } + } if (_raven == null) return; diff --git a/Geekbot.net/Program.cs b/Geekbot.net/Program.cs index 3f31945..b805e5f 100755 --- a/Geekbot.net/Program.cs +++ b/Geekbot.net/Program.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.IO; using System.Linq; using System.Net; using System.Reflection; -using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Discord; @@ -14,8 +11,8 @@ using Geekbot.net.Lib; using Geekbot.net.Lib.Media; using Microsoft.Extensions.DependencyInjection; using Nancy.Hosting.Self; -using Serilog; using StackExchange.Redis; +using WikipediaApi; namespace Geekbot.net { @@ -101,6 +98,7 @@ namespace Geekbot.net var emojiConverter = new EmojiConverter(); var audioUtils = new AudioUtils(); var mtgManaConverter = new MtgManaConverter(); + var wikipediaClient = new WikipediaClient(); services.AddSingleton(redis); services.AddSingleton(logger); @@ -112,6 +110,7 @@ namespace Geekbot.net services.AddSingleton(mediaProvider); services.AddSingleton(malClient); services.AddSingleton(mtgManaConverter); + services.AddSingleton(wikipediaClient); logger.Information("Geekbot", "Connecting to Discord"); @@ -134,7 +133,7 @@ namespace Geekbot.net logger.Information("Geekbot", "Registering Stuff"); var translationHandler = new TranslationHandler(client.Guilds, redis, logger); - var errorHandler = new ErrorHandler(logger, translationHandler); + var errorHandler = new ErrorHandler(logger, translationHandler, args.Contains("--expose-errors")); var reactionListener = new ReactionListener(redis); await commands.AddModulesAsync(Assembly.GetEntryAssembly()); services.AddSingleton(commands); diff --git a/WikipediaApi/IWikipediaClient.cs b/WikipediaApi/IWikipediaClient.cs new file mode 100644 index 0000000..3fad554 --- /dev/null +++ b/WikipediaApi/IWikipediaClient.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using WikipediaApi.Page; + +namespace WikipediaApi +{ + public interface IWikipediaClient + { + Task GetPreview(string pageName); + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageApiUrls.cs b/WikipediaApi/Page/PageApiUrls.cs new file mode 100644 index 0000000..8a121be --- /dev/null +++ b/WikipediaApi/Page/PageApiUrls.cs @@ -0,0 +1,14 @@ +using System; + +namespace WikipediaApi.Page +{ + public class PageApiUrls + { + public Uri Summary { get; set; } + public Uri Metadata { get; set; } + public Uri References { get; set; } + public Uri Media { get; set; } + public Uri EditHtml { get; set; } + public Uri TalkPageHtml { get; set; } + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageContentUrlCollection.cs b/WikipediaApi/Page/PageContentUrlCollection.cs new file mode 100644 index 0000000..f6c680b --- /dev/null +++ b/WikipediaApi/Page/PageContentUrlCollection.cs @@ -0,0 +1,8 @@ +namespace WikipediaApi.Page +{ + public class PageContentUrlCollection + { + public PageContentUrls Desktop { get; set; } + public PageContentUrls Mobile { get; set; } + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageContentUrls.cs b/WikipediaApi/Page/PageContentUrls.cs new file mode 100644 index 0000000..64a80dc --- /dev/null +++ b/WikipediaApi/Page/PageContentUrls.cs @@ -0,0 +1,12 @@ +using System; + +namespace WikipediaApi.Page +{ + public class PageContentUrls + { + public Uri Page { get; set; } + public Uri Revisions { get; set; } + public Uri Edit { get; set; } + public Uri Talk { get; set; } + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageCoordinates.cs b/WikipediaApi/Page/PageCoordinates.cs new file mode 100644 index 0000000..f86bb09 --- /dev/null +++ b/WikipediaApi/Page/PageCoordinates.cs @@ -0,0 +1,8 @@ +namespace WikipediaApi.Page +{ + public class PageCoordinates + { + public float lat { get; set; } + public float lon { get; set; } + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageImage.cs b/WikipediaApi/Page/PageImage.cs new file mode 100644 index 0000000..4a8b28d --- /dev/null +++ b/WikipediaApi/Page/PageImage.cs @@ -0,0 +1,12 @@ +using System; + +namespace WikipediaApi.Page +{ + public class PageImage + { + public Uri Source { get; set; } + public int Width { get; set; } + public int Height { get; set; } + + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageNamespace.cs b/WikipediaApi/Page/PageNamespace.cs new file mode 100644 index 0000000..66600b6 --- /dev/null +++ b/WikipediaApi/Page/PageNamespace.cs @@ -0,0 +1,8 @@ +namespace WikipediaApi.Page +{ + public class PageNamespace + { + public ulong Id { get; set; } + public string Text { get; set; } + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PagePreview.cs b/WikipediaApi/Page/PagePreview.cs new file mode 100644 index 0000000..41ab6f3 --- /dev/null +++ b/WikipediaApi/Page/PagePreview.cs @@ -0,0 +1,68 @@ +using System; +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace WikipediaApi.Page +{ + public class PagePreview + { + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public PageTypes Type { get; set; } = PageTypes.NoExtract; + + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("displaytitle")] + public string Displaytitle { get; set; } + + [JsonProperty("namespace")] + public PageNamespace @Namespace { get; set; } + + [JsonProperty("titles")] + public PageTitles Titles { get; set; } + + [JsonProperty("pageid")] + public ulong Pageid { get; set; } + + [JsonProperty("thumbnail")] + public PageImage Thumbnail { get; set; } + + [JsonProperty("originalimage")] + public PageImage Originalimage { get; set; } + + [JsonProperty("lang")] + public string Lang { get; set; } + + [JsonProperty("dir")] + public string Dir { get; set; } + + [JsonProperty("revision")] + public ulong Revision { get; set; } + + [JsonProperty("tid")] + public string Tid { get; set; } + + [JsonProperty("timestamp")] + public DateTimeOffset Timestamp { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("coordinates")] + public PageCoordinates Coordinates { get; set; } + + [JsonProperty("content_urls")] + public PageContentUrlCollection ContentUrls { get; set; } + + [JsonProperty("api_urls")] + public PageApiUrls ApiUrls { get; set; } + + [JsonProperty("extract")] + public string Extract { get; set; } + + [JsonProperty("extract_html")] + public string ExtractHtml { get; set; } + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageTitles.cs b/WikipediaApi/Page/PageTitles.cs new file mode 100644 index 0000000..31a55b9 --- /dev/null +++ b/WikipediaApi/Page/PageTitles.cs @@ -0,0 +1,10 @@ +namespace WikipediaApi.Page +{ + public class PageTitles + { + public string Canonical { get; set; } + public string Normalized { get; set; } + public string Display { get; set; } + + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageTypes.cs b/WikipediaApi/Page/PageTypes.cs new file mode 100644 index 0000000..a415d75 --- /dev/null +++ b/WikipediaApi/Page/PageTypes.cs @@ -0,0 +1,19 @@ +using System.Runtime.Serialization; + +namespace WikipediaApi.Page +{ + public enum PageTypes + { + [EnumMember(Value = "standard")] + Standard, + + [EnumMember(Value = "disambiguation")] + Disambiguation, + + [EnumMember(Value = "mainpage")] + MainPage, + + [EnumMember(Value = "no-extract")] + NoExtract + } +} \ No newline at end of file diff --git a/WikipediaApi/WikipediaApi.csproj b/WikipediaApi/WikipediaApi.csproj new file mode 100644 index 0000000..f182d90 --- /dev/null +++ b/WikipediaApi/WikipediaApi.csproj @@ -0,0 +1,8 @@ + + + netcoreapp2.0 + + + + + \ No newline at end of file diff --git a/WikipediaApi/WikipediaClient.cs b/WikipediaApi/WikipediaClient.cs new file mode 100644 index 0000000..9bd3059 --- /dev/null +++ b/WikipediaApi/WikipediaClient.cs @@ -0,0 +1,29 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Newtonsoft.Json; +using WikipediaApi.Page; + +namespace WikipediaApi +{ + public class WikipediaClient : IWikipediaClient + { + private readonly HttpClient _httpClient; + public WikipediaClient() + { + _httpClient = new HttpClient + { + BaseAddress = new Uri("https://en.wikipedia.org") + }; + } + + public async Task GetPreview(string pageName) + { + var response = await _httpClient.GetAsync($"/api/rest_v1/page/summary/{pageName}"); + response.EnsureSuccessStatusCode(); + + var stringResponse = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(stringResponse); + } + } +} \ No newline at end of file