Split Geekbot.net into src/Bot, src/Core, and src/Web

This commit is contained in:
runebaas 2020-08-08 22:24:01 +02:00
parent 7b6dd2d2f9
commit fc0af492ad
No known key found for this signature in database
GPG key ID: 2677AF508D0300D6
197 changed files with 542 additions and 498 deletions

View file

@ -0,0 +1,61 @@
using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Discord.Commands;
using Geekbot.Core;
using Geekbot.Core.ErrorHandling;
namespace Geekbot.Bot.Commands.Integrations.LolMmr
{
public class LolMmr : ModuleBase
{
private readonly IErrorHandler _errorHandler;
public LolMmr(IErrorHandler errorHandler)
{
_errorHandler = errorHandler;
}
[Command("mmr", RunMode = RunMode.Async)]
[Summary("Get the League of Legends MMR for a specified summoner")]
public async Task GetMmr([Remainder] [Summary("summoner")] string summonerName)
{
try
{
LolMmrDto data;
try
{
var name = HttpUtility.UrlEncode(summonerName.ToLower());
var httpClient = HttpAbstractions.CreateDefaultClient();
// setting the user agent in accordance with the whatismymmr.com api rules
httpClient.DefaultRequestHeaders.Remove("User-Agent");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Linux:rocks.pizzaandcoffee.geekbot:v0.0.0");
data = await HttpAbstractions.Get<LolMmrDto>(new Uri($"https://euw.whatismymmr.com/api/v1/summoner?name={name}"), httpClient);
}
catch (HttpRequestException e)
{
if (e.StatusCode != HttpStatusCode.NotFound) throw e;
await Context.Channel.SendMessageAsync("Player not found");
return;
}
var sb = new StringBuilder();
sb.AppendLine($"**MMR for {summonerName}**");
sb.AppendLine($"Normal: {data.Normal.Avg}");
sb.AppendLine($"Ranked: {data.Ranked.Avg}");
sb.AppendLine($"ARAM: {data.ARAM.Avg}");
await Context.Channel.SendMessageAsync(sb.ToString());
}
catch (Exception e)
{
await _errorHandler.HandleCommandException(e, Context);
}
}
}
}

View file

@ -0,0 +1,9 @@
namespace Geekbot.Bot.Commands.Integrations.LolMmr
{
public class LolMmrDto
{
public LolMrrInfoDto Ranked { get; set; }
public LolMrrInfoDto Normal { get; set; }
public LolMrrInfoDto ARAM { get; set; }
}
}

View file

@ -0,0 +1,10 @@
using Newtonsoft.Json;
namespace Geekbot.Bot.Commands.Integrations.LolMmr
{
public class LolMrrInfoDto
{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public decimal Avg { get; set; } = 0;
}
}

View file

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Geekbot.Core.Converters;
using Geekbot.Core.ErrorHandling;
using Geekbot.Core.Extensions;
using MtgApiManager.Lib.Service;
namespace Geekbot.Bot.Commands.Integrations
{
public class MagicTheGathering : ModuleBase
{
private readonly IErrorHandler _errorHandler;
private readonly IMtgManaConverter _manaConverter;
public MagicTheGathering(IErrorHandler errorHandler, IMtgManaConverter manaConverter)
{
_errorHandler = errorHandler;
_manaConverter = manaConverter;
}
[Command("mtg", RunMode = RunMode.Async)]
[Summary("Find a Magic The Gathering Card.")]
public async Task GetCard([Remainder] [Summary("card-name")] string cardName)
{
try
{
var message = await Context.Channel.SendMessageAsync($":mag: Looking up\"{cardName}\", please wait...");
var service = new CardService();
var result = service
.Where(x => x.Name, cardName)
// fewer cards less risk of deserialization problems, don't need more than one anyways...
.Where(x => x.PageSize, 1);
var card = result.All().Value.FirstOrDefault();
if (card == null)
{
await message.ModifyAsync(properties => properties.Content = ":red_circle: I couldn't find a card with that name...");
return;
}
var eb = new EmbedBuilder
{
Title = card.Name,
Description = card.Type
};
if (card.Colors != null) eb.WithColor(GetColor(card.Colors));
if (card.ImageUrl != null) eb.ImageUrl = card.ImageUrl.ToString();
if (!string.IsNullOrEmpty(card.Text)) eb.AddField("Text", _manaConverter.ConvertMana(card.Text));
if (!string.IsNullOrEmpty(card.Flavor)) eb.AddField("Flavor", card.Flavor);
if (!string.IsNullOrEmpty(card.SetName)) eb.AddInlineField("Set", card.SetName);
if (!string.IsNullOrEmpty(card.Power)) eb.AddInlineField("Power", card.Power);
if (!string.IsNullOrEmpty(card.Loyalty)) eb.AddInlineField("Loyality", card.Loyalty);
if (!string.IsNullOrEmpty(card.Toughness)) eb.AddInlineField("Thoughness", card.Toughness);
if (!string.IsNullOrEmpty(card.ManaCost)) eb.AddInlineField("Cost", _manaConverter.ConvertMana(card.ManaCost));
if (!string.IsNullOrEmpty(card.Rarity)) eb.AddInlineField("Rarity", card.Rarity);
if (card.Legalities != null && card.Legalities.Count > 0)
eb.AddField("Legality", string.Join(", ", card.Legalities.Select(e => e.Format)));
await message.ModifyAsync(properties =>
{
properties.Content = string.Empty;
properties.Embed = eb.Build();
});
}
catch (Exception e)
{
await _errorHandler.HandleCommandException(e, Context);
}
}
private Color GetColor(IEnumerable<string> colors)
{
var color = colors.FirstOrDefault();
return color switch
{
"Black" => new Color(203, 194, 191),
"White" => new Color(255, 251, 213),
"Blue" => new Color(170, 224, 250),
"Red" => new Color(250, 170, 143),
"Green" => new Color(155, 211, 174),
_ => new Color(204, 194, 212)
};
}
}
}

View file

@ -0,0 +1,128 @@
using System;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using Discord;
using Discord.Commands;
using Geekbot.Core.ErrorHandling;
using Geekbot.Core.Extensions;
using Geekbot.Core.MalClient;
namespace Geekbot.Bot.Commands.Integrations
{
public class Mal : ModuleBase
{
private readonly IErrorHandler _errorHandler;
private readonly IMalClient _malClient;
public Mal(IMalClient malClient, IErrorHandler errorHandler)
{
_malClient = malClient;
_errorHandler = errorHandler;
}
[Command("anime", RunMode = RunMode.Async)]
[Summary("Show Info about an Anime.")]
public async Task SearchAnime([Remainder] [Summary("anime-name")] string animeName)
{
try
{
if (_malClient.IsLoggedIn())
{
var anime = await _malClient.GetAnime(animeName);
if (anime != null)
{
var eb = new EmbedBuilder();
var description = HttpUtility.HtmlDecode(anime.Synopsis)
.Replace("<br />", "")
.Replace("[i]", "*")
.Replace("[/i]", "*");
eb.Title = anime.Title;
eb.Description = description;
eb.ImageUrl = anime.Image;
eb.AddInlineField("Premiered", $"{anime.StartDate}");
eb.AddInlineField("Ended", anime.EndDate == "0000-00-00" ? "???" : anime.EndDate);
eb.AddInlineField("Status", anime.Status);
eb.AddInlineField("Episodes", anime.Episodes);
eb.AddInlineField("MAL Score", anime.Score);
eb.AddInlineField("Type", anime.Type);
eb.AddField("MAL Link", $"https://myanimelist.net/anime/{anime.Id}");
await ReplyAsync("", false, eb.Build());
}
else
{
await ReplyAsync("No anime found with that name...");
}
}
else
{
await ReplyAsync(
"Unfortunally i'm not connected to MyAnimeList.net, please tell my senpai to connect me");
}
}
catch (XmlException e)
{
await _errorHandler.HandleCommandException(e, Context, "The MyAnimeList.net API refused to answer");
}
catch (Exception e)
{
await _errorHandler.HandleCommandException(e, Context);
}
}
[Command("manga", RunMode = RunMode.Async)]
[Summary("Show Info about a Manga.")]
public async Task SearchManga([Remainder] [Summary("manga-name")] string mangaName)
{
try
{
if (_malClient.IsLoggedIn())
{
var manga = await _malClient.GetManga(mangaName);
if (manga != null)
{
var eb = new EmbedBuilder();
var description = HttpUtility.HtmlDecode(manga.Synopsis)
.Replace("<br />", "")
.Replace("[i]", "*")
.Replace("[/i]", "*");
eb.Title = manga.Title;
eb.Description = description;
eb.ImageUrl = manga.Image;
eb.AddInlineField("Premiered", $"{manga.StartDate}");
eb.AddInlineField("Ended", manga.EndDate == "0000-00-00" ? "???" : manga.EndDate);
eb.AddInlineField("Status", manga.Status);
eb.AddInlineField("Volumes", manga.Volumes);
eb.AddInlineField("Chapters", manga.Chapters);
eb.AddInlineField("MAL Score", manga.Score);
eb.AddField("MAL Link", $"https://myanimelist.net/manga/{manga.Id}");
await ReplyAsync("", false, eb.Build());
}
else
{
await ReplyAsync("No manga found with that name...");
}
}
else
{
await ReplyAsync(
"Unfortunally i'm not connected to MyAnimeList.net, please tell my senpai to connect me");
}
}
catch (XmlException e)
{
await _errorHandler.HandleCommandException(e, Context, "The MyAnimeList.net API refused to answer");
}
catch (Exception e)
{
await _errorHandler.HandleCommandException(e, Context);
}
}
}
}

View file

@ -0,0 +1,12 @@
namespace Geekbot.Bot.Commands.Integrations.UbranDictionary
{
internal class UrbanListItemDto
{
public string Definition { get; set; }
public string Permalink { get; set; }
public string ThumbsUp { get; set; }
public string Word { get; set; }
public string Example { get; set; }
public string ThumbsDown { get; set; }
}
}

View file

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Geekbot.Bot.Commands.Integrations.UbranDictionary
{
internal class UrbanResponseDto
{
public string[] Tags { get; set; }
public List<UrbanListItemDto> List { get; set; }
}
}

View file

@ -0,0 +1,63 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Geekbot.Core;
using Geekbot.Core.ErrorHandling;
using Geekbot.Core.Extensions;
namespace Geekbot.Bot.Commands.Integrations.UbranDictionary
{
public class UrbanDictionary : ModuleBase
{
private readonly IErrorHandler _errorHandler;
public UrbanDictionary(IErrorHandler errorHandler)
{
_errorHandler = errorHandler;
}
[Command("urban", RunMode = RunMode.Async)]
[Summary("Lookup something on urban dictionary")]
public async Task UrbanDefine([Remainder] [Summary("word")] string word)
{
try
{
var definitions = await HttpAbstractions.Get<UrbanResponseDto>(new Uri($"https://api.urbandictionary.com/v0/define?term={word}"));
if (definitions.List.Count == 0)
{
await ReplyAsync("That word hasn't been defined...");
return;
}
var definition = definitions.List.First(e => !string.IsNullOrWhiteSpace(e.Example));
var description = definition.Definition;
if (description.Length > 1801)
{
description = description.Substring(0, 1800) + " [...]";
}
var eb = new EmbedBuilder();
eb.WithAuthor(new EmbedAuthorBuilder
{
Name = definition.Word,
Url = definition.Permalink
});
eb.WithColor(new Color(239, 255, 0));
if (!string.IsNullOrEmpty(definition.Definition)) eb.Description = description;
if (!string.IsNullOrEmpty(definition.Example)) eb.AddField("Example", definition.Example ?? "(no example given...)");
if (!string.IsNullOrEmpty(definition.ThumbsUp)) eb.AddInlineField("Upvotes", definition.ThumbsUp);
if (!string.IsNullOrEmpty(definition.ThumbsDown)) eb.AddInlineField("Downvotes", definition.ThumbsDown);
if (definitions.Tags?.Length > 0) eb.AddField("Tags", string.Join(", ", definitions.Tags));
await ReplyAsync("", false, eb.Build());
}
catch (Exception e)
{
await _errorHandler.HandleCommandException(e, Context);
}
}
}
}

View file

@ -0,0 +1,112 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Geekbot.Core.Database;
using Geekbot.Core.ErrorHandling;
using Geekbot.Core.Extensions;
using Geekbot.Core.WikipediaClient;
using Geekbot.Core.WikipediaClient.Page;
using HtmlAgilityPack;
namespace Geekbot.Bot.Commands.Integrations
{
public class Wikipedia : ModuleBase
{
private readonly IErrorHandler _errorHandler;
private readonly IWikipediaClient _wikipediaClient;
private readonly DatabaseContext _database;
public Wikipedia(IErrorHandler errorHandler, IWikipediaClient wikipediaClient, DatabaseContext database)
{
_errorHandler = errorHandler;
_wikipediaClient = wikipediaClient;
_database = database;
}
[Command("wiki", RunMode = RunMode.Async)]
[Summary("Get an article from wikipedia.")]
public async Task GetPreview([Remainder] [Summary("article")] string articleName)
{
try
{
var wikiLang = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(Context.Guild.Id.AsLong()))?.WikiLang;
if (string.IsNullOrEmpty(wikiLang))
{
wikiLang = "en";
}
var article = await _wikipediaClient.GetPreview(articleName.Replace(" ", "_"), wikiLang);
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.Description,
ImageUrl = article.Thumbnail?.Source.ToString(),
Url = article.ContentUrls.Desktop.Page.ToString(),
Color = new Color(246,246,246),
Timestamp = article.Timestamp,
Footer = new EmbedFooterBuilder
{
Text = "Last Edit",
IconUrl = "http://icons.iconarchive.com/icons/sykonist/popular-sites/256/Wikipedia-icon.png"
}
};
eb.AddField("Description", article.Extract);
if (article.Coordinates != null) eb.AddField("Coordinates", $"{article.Coordinates.Lat} Lat {article.Coordinates.Lon} Lon");
await ReplyAsync("", false, eb.Build());
}
catch (HttpRequestException)
{
await ReplyAsync("I couldn't find that article");
}
catch (Exception e)
{
await _errorHandler.HandleCommandException(e, Context);
}
}
private string DisambiguationExtractor(string extractHtml)
{
var doc = new HtmlDocument();
doc.LoadHtml(extractHtml);
var nodes = doc.DocumentNode.SelectNodes("//li");
if (nodes == null) return "(List is to long to show)";
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

@ -0,0 +1,58 @@
using System;
using System.Threading.Tasks;
using Discord.Commands;
using Geekbot.Core.ErrorHandling;
using Geekbot.Core.GlobalSettings;
using Google.Apis.Services;
using Google.Apis.YouTube.v3;
namespace Geekbot.Bot.Commands.Integrations
{
public class Youtube : ModuleBase
{
private readonly IGlobalSettings _globalSettings;
private readonly IErrorHandler _errorHandler;
public Youtube(IGlobalSettings globalSettings, IErrorHandler errorHandler)
{
_globalSettings = globalSettings;
_errorHandler = errorHandler;
}
[Command("yt", RunMode = RunMode.Async)]
[Summary("Search for something on youtube.")]
public async Task Yt([Remainder] [Summary("title")] string searchQuery)
{
var key = _globalSettings.GetKey("YoutubeKey");
if (string.IsNullOrEmpty(key))
{
await ReplyAsync("No youtube key set, please tell my senpai to set one");
return;
}
try
{
var youtubeService = new YouTubeService(new BaseClientService.Initializer
{
ApiKey = key,
ApplicationName = GetType().ToString()
});
var searchListRequest = youtubeService.Search.List("snippet");
searchListRequest.Q = searchQuery;
searchListRequest.MaxResults = 2;
var searchListResponse = await searchListRequest.ExecuteAsync();
var result = searchListResponse.Items[0];
await ReplyAsync(
$"\"{result.Snippet.Title}\" from \"{result.Snippet.ChannelTitle}\" https://youtu.be/{result.Id.VideoId}");
}
catch (Exception e)
{
await _errorHandler.HandleCommandException(e, Context);
}
}
}
}