Add wikipedia api client, add wikipedia command, show errors in chat when debugging

This commit is contained in:
runebaas 2018-04-28 01:01:48 +02:00
parent f4ced55d15
commit 846c928f5f
No known key found for this signature in database
GPG key ID: 2677AF508D0300D6
18 changed files with 334 additions and 9 deletions

4
.gitignore vendored
View file

@ -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/

View file

@ -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

View file

@ -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();
}
}
}

View file

@ -15,6 +15,7 @@
<Version>1.0.2</Version>
</PackageReference>
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.29.1.991" />
<PackageReference Include="HtmlAgilityPack" Version="1.8.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" />
@ -22,7 +23,7 @@
<PackageReference Include="MyAnimeListSharp" Version="1.3.4" />
<PackageReference Include="Nancy" Version="2.0.0-clinteastwood" />
<PackageReference Include="Nancy.Hosting.Self" Version="2.0.0-clinteastwood" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="Overwatch.Net" Version="3.0.0" />
<PackageReference Include="PokeApi.NET" Version="1.1.0" />
<PackageReference Include="Serilog" Version="2.6.0" />
@ -76,4 +77,7 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WikipediaApi\WikipediaApi.csproj" />
</ItemGroup>
</Project>

View file

@ -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;

View file

@ -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<IGeekbotLogger>(logger);
@ -112,6 +110,7 @@ namespace Geekbot.net
services.AddSingleton<IMediaProvider>(mediaProvider);
services.AddSingleton<IMalClient>(malClient);
services.AddSingleton<IMtgManaConverter>(mtgManaConverter);
services.AddSingleton<IWikipediaClient>(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);

View file

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using WikipediaApi.Page;
namespace WikipediaApi
{
public interface IWikipediaClient
{
Task<PagePreview> GetPreview(string pageName);
}
}

View file

@ -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; }
}
}

View file

@ -0,0 +1,8 @@
namespace WikipediaApi.Page
{
public class PageContentUrlCollection
{
public PageContentUrls Desktop { get; set; }
public PageContentUrls Mobile { get; set; }
}
}

View file

@ -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; }
}
}

View file

@ -0,0 +1,8 @@
namespace WikipediaApi.Page
{
public class PageCoordinates
{
public float lat { get; set; }
public float lon { get; set; }
}
}

View file

@ -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; }
}
}

View file

@ -0,0 +1,8 @@
namespace WikipediaApi.Page
{
public class PageNamespace
{
public ulong Id { get; set; }
public string Text { get; set; }
}
}

View file

@ -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; }
}
}

View file

@ -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; }
}
}

View file

@ -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
}
}

View file

@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
</Project>

View file

@ -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<PagePreview> 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<PagePreview>(stringResponse);
}
}
}