From cde2931a51b2ba8df48f1e6af3c86bee208b7254 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 25 Jan 2017 03:06:41 +0100 Subject: [PATCH 1/8] added ~mal command --- .../Searches/Commands/AnimeSearchCommands.cs | 116 +++++++++++++++++- .../Resources/CommandStrings.Designer.cs | 27 ++++ src/NadekoBot/Resources/CommandStrings.resx | 9 ++ 3 files changed, 151 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs index ed6c058b..2aeb3c5b 100644 --- a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs @@ -1,4 +1,7 @@ -ο»Ώusing Discord; +ο»Ώusing AngleSharp; +using AngleSharp.Dom.Html; +using AngleSharp.Extensions; +using Discord; using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; @@ -8,6 +11,7 @@ using Newtonsoft.Json.Linq; using NLog; using System; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -52,6 +56,116 @@ namespace NadekoBot.Modules.Searches }, null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(29)); } + [NadekoCommand, Usage, Description, Aliases] + [Priority(1)] + public async Task Mal([Remainder] string name) + { + if (string.IsNullOrWhiteSpace(name)) + return; + + var fullQueryLink = "https://myanimelist.net/profile/" + name; + + var config = Configuration.Default.WithDefaultLoader(); + var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); + + var imageElem = document.QuerySelector("body > div#myanimelist > div.wrapper > div#contentWrapper > div#content > div.content-container > div.container-left > div.user-profile > div.user-image > img"); + var imageUrl = ((IHtmlImageElement)imageElem)?.Source ?? "http://icecream.me/uploads/870b03f36b59cc16ebfe314ef2dde781.png"; + + var stats = document.QuerySelectorAll("body > div#myanimelist > div.wrapper > div#contentWrapper > div#content > div.content-container > div.container-right > div#statistics > div.user-statistics-stats > div.stats > div.clearfix > ul.stats-status > li > span").Select(x => x.InnerHtml).ToList(); + + var favorites = document.QuerySelectorAll("div.user-favorites > div.di-tc"); + + var favAnime = "No favorite anime yet"; + if (favorites[0].QuerySelector("p") == null) + favAnime = string.Join("\n", favorites[0].QuerySelectorAll("ul > li > div.di-tc.va-t > a") + .Shuffle() + .Take(3) + .Select(x => + { + var elem = (IHtmlAnchorElement)x; + return $"[{elem.InnerHtml}]({elem.Href})"; + })); + + //var favManga = "No favorite manga yet."; + //if (favorites[1].QuerySelector("p") == null) + // favManga = string.Join("\n", favorites[1].QuerySelectorAll("ul > li > div.di-tc.va-t > a") + // .Take(3) + // .Select(x => + // { + // var elem = (IHtmlAnchorElement)x; + // return $"[{elem.InnerHtml}]({elem.Href})"; + // })); + + var info = document.QuerySelectorAll("ul.user-status:nth-child(3) > li") + .Select(x => Tuple.Create(x.Children[0].InnerHtml, x.Children[1].InnerHtml)) + .ToList(); + + var daysAndMean = document.QuerySelectorAll("div.anime:nth-child(1) > div:nth-child(2) > div") + .Select(x => x.TextContent.Split(':').Select(y => y.Trim()).ToArray()) + .ToArray(); + + var embed = new EmbedBuilder() + .WithOkColor() + .WithTitle($"{name}'s MAL profile") + .AddField(efb => efb.WithName("πŸ’š Watching").WithValue(stats[0]).WithIsInline(true)) + .AddField(efb => efb.WithName("πŸ’™ Completed").WithValue(stats[1]).WithIsInline(true)); + if (info.Count < 3) + embed.AddField(efb => efb.WithName("πŸ’› On-Hold").WithValue(stats[2]).WithIsInline(true)); + embed + .AddField(efb => efb.WithName("πŸ’” Dropped").WithValue(stats[3]).WithIsInline(true)) + .AddField(efb => efb.WithName("βšͺ Plan to watch").WithValue(stats[4]).WithIsInline(true)) + .AddField(efb => efb.WithName("πŸ• " + daysAndMean[0][0]).WithValue(daysAndMean[0][1]).WithIsInline(true)) + .AddField(efb => efb.WithName("πŸ“Š " + daysAndMean[1][0]).WithValue(daysAndMean[1][1]).WithIsInline(true)) + .AddField(efb => efb.WithName(MalInfoToEmoji(info[0].Item1) + " " + info[0].Item1).WithValue(info[0].Item2.TrimTo(20)).WithIsInline(true)) + .AddField(efb => efb.WithName(MalInfoToEmoji(info[1].Item1) + " " + info[1].Item1).WithValue(info[1].Item2.TrimTo(20)).WithIsInline(true)); + if (info.Count > 2) + embed.AddField(efb => efb.WithName(MalInfoToEmoji(info[2].Item1) + " " + info[2].Item1).WithValue(info[2].Item2.TrimTo(20)).WithIsInline(true)); + //if(info.Count > 3) + // embed.AddField(efb => efb.WithName(MalInfoToEmoji(info[3].Item1) + " " + info[3].Item1).WithValue(info[3].Item2).WithIsInline(true)) + embed + .WithDescription($@" +** https://myanimelist.net/animelist/{ name } ** + +**Top 3 Favorite Anime:** +{favAnime}" + +//**[Manga List](https://myanimelist.net/mangalist/{name})** +//πŸ’š`Reading:` {stats[5]} +//πŸ’™`Completed:` {stats[6]} +//πŸ’”`Dropped:` {stats[8]} +//βšͺ`Plan to read:` {stats[9]} + +//**Top 3 Favorite Manga:** +//{favManga}" + +) + .WithUrl(fullQueryLink) + .WithImageUrl(imageUrl); + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + + private static string MalInfoToEmoji(string info) { + info = info.Trim().ToLowerInvariant(); + switch (info) + { + case "gender": + return "🚁"; + case "location": + return "πŸ—Ί"; + case "last online": + return "πŸ‘₯"; + case "birthday": + return "πŸ“†"; + default: + return "❔"; + } + } + + [NadekoCommand, Usage, Description, Aliases] + [Priority(0)] + public Task Mal(IUser usr) => Mal(usr.Username); + [NadekoCommand, Usage, Description, Aliases] public async Task Anime([Remainder] string query) { diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index f37738f5..ae2ff2c6 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -4406,6 +4406,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to mal. + /// + public static string mal_cmd { + get { + return ResourceManager.GetString("mal_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows basic info from myanimelist profile.. + /// + public static string mal_desc { + get { + return ResourceManager.GetString("mal_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}mal straysocks`. + /// + public static string mal_usage { + get { + return ResourceManager.GetString("mal_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to manga mang mq. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 95b16f7d..a31288b1 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3024,4 +3024,13 @@ `{0}waifuinfo @MyCrush` or `{0}waifuinfo` + + mal + + + Shows basic info from myanimelist profile. + + + `{0}mal straysocks` + \ No newline at end of file From a4c190c3126376a479c808704f3386b140def945 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 25 Jan 2017 03:19:43 +0100 Subject: [PATCH 2/8] Fixed ~img and ~rimg, closes #1001 --- src/NadekoBot/Modules/Searches/Searches.cs | 4 +++- src/NadekoBot/Services/Impl/GoogleApiService.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index ad160599..27840678 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -115,6 +115,8 @@ namespace NadekoBot.Modules.Searches if (string.IsNullOrWhiteSpace(terms)) return; + terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); + try { var res = await NadekoBot.Google.GetImageAsync(terms).ConfigureAwait(false); @@ -131,7 +133,6 @@ namespace NadekoBot.Modules.Searches catch { _log.Warn("Falling back to Imgur search."); - terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); var fullQueryLink = $"http://imgur.com/search?q={ terms }"; var config = Configuration.Default.WithDefaultLoader(); @@ -167,6 +168,7 @@ namespace NadekoBot.Modules.Searches terms = terms?.Trim(); if (string.IsNullOrWhiteSpace(terms)) return; + terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); try { var res = await NadekoBot.Google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false); diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index f2934ba6..187bf272 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -199,7 +199,7 @@ namespace NadekoBot.Services.Impl } } - public async Task GetImageAsync(string query, int start = 0) + public async Task GetImageAsync(string query, int start = 1) { if (string.IsNullOrWhiteSpace(query)) throw new ArgumentNullException(nameof(query)); From 15a3b99cbd1fdf4c4ef07c7baaf9ddf407cd3bb5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 07:57:52 +0100 Subject: [PATCH 3/8] Hangman fixed --- .../Modules/Games/Commands/Hangman/HangmanGame.cs | 14 +++++++------- .../Modules/Games/Commands/HangmanCommands.cs | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index 4dcb54e9..3d5f7ec6 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -189,13 +189,13 @@ namespace NadekoBot.Modules.Games.Commands.Hangman catch (Exception ex) { _log.Warn(ex); } } - public string GetHangman() => $@"\_\_\_\_\_\_\_\_\_ - | | - | | - {(Errors > 0 ? "😲" : " ")} | - {(Errors > 1 ? "/" : " ")} {(Errors > 2 ? "|" : " ")} {(Errors > 3 ? "\\" : " ")} | - {(Errors > 4 ? "/" : " ")} {(Errors > 5 ? "\\" : " ")} | - /-\"; + public string GetHangman() => $@". β”Œβ”€β”€β”€β”€β”€β” +.┃...............β”‹ +.┃...............β”‹ +.┃{(Errors > 0 ? ".............😲" : "")} +.┃{(Errors > 1 ? "............./" : "")} {(Errors > 2 ? "|" : "")} {(Errors > 3 ? "\\" : "")} +.┃{(Errors > 4 ? "............../" : "")} {(Errors > 5 ? "\\" : "")} +/-\"; public void Dispose() { diff --git a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs index 50596e4c..4d499301 100644 --- a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs @@ -61,7 +61,7 @@ namespace NadekoBot.Modules.Games return; } - await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman() + "\n" + hm.ScrambledWord); + await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman()); } } } From 5d5a67b4770db1ab0ef20908a9d724db2139a889 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 08:02:57 +0100 Subject: [PATCH 4/8] .whpl fix on many users --- src/NadekoBot/Modules/Utility/Utility.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index dc5e56cd..304b2782 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -116,15 +116,18 @@ namespace NadekoBot.Modules.Utility var arr = (await (Context.Channel as IGuildChannel).Guild.GetUsersAsync()) .Where(u => u.Game?.Name?.ToUpperInvariant() == game) .Select(u => u.Username) + .Shuffle() + .Take(60) .ToList(); int i = 0; if (!arr.Any()) await Context.Channel.SendErrorAsync("Nobody is playing that game.").ConfigureAwait(false); - else + else { await Context.Channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2) .Select(ig => string.Concat(ig.Select(el => $"β€’ {el,-27}")))) + "\n```") .ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] From f40dbc7bec33b9750f4dc8eaa7d4f383848b3c12 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 08:08:40 +0100 Subject: [PATCH 5/8] Users can no longer submit multiple sentences in acrophobia --- src/NadekoBot/Modules/Games/Commands/Acropobia.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index 2a7307bb..b379e473 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -69,6 +69,7 @@ namespace NadekoBot.Modules.Games private readonly ConcurrentDictionary submissions = new ConcurrentDictionary(); public IReadOnlyDictionary Submissions => submissions; + private readonly ConcurrentHashSet usersWhoSubmitted = new ConcurrentHashSet(); private readonly ConcurrentHashSet usersWhoVoted = new ConcurrentHashSet(); private int spamCount = 0; @@ -191,8 +192,7 @@ namespace NadekoBot.Modules.Games catch { } } //user didn't input something already - IGuildUser throwaway; - if (submissions.TryGetValue(input, out throwaway)) + if (!usersWhoSubmitted.Add(guildUser.Id)) return; var inputWords = input.Split(' '); //get all words From d09a5fd2e92ddd1eb7c1eeefbceaef11cb9090c9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 19:13:59 +0100 Subject: [PATCH 6/8] ~osu now links to new profile, closes #1005 --- src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs index f7f83361..a2760a1a 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs @@ -45,7 +45,7 @@ namespace NadekoBot.Modules.Searches MemoryStream ms = new MemoryStream(); res.CopyTo(ms); ms.Position = 0; - await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **Profile Link: **https://osu.ppy.sh/u/{Uri.EscapeDataString(usr)}\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false); + await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **Profile Link:** \n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false); } catch (Exception ex) { From 927031dd60e990469997086f176e25f5d97f0beb Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 19:19:57 +0100 Subject: [PATCH 7/8] Fixed accented 'a' in typing articles --- src/NadekoBot/data/typing_articles.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json index 1a4581fe..c4317df8 100644 --- a/src/NadekoBot/data/typing_articles.json +++ b/src/NadekoBot/data/typing_articles.json @@ -237,7 +237,7 @@ }, { "Title":"Careers in Psychology: Opportunities in a Changing World", - "Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelorҀ™s and graduate level." + "Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bacheloras and graduate level." }, { "Title":"Philosophy of Psychology", From 14b7aae0b026d3e1ad3d21dd5123b8a419d6391f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 20:15:59 +0100 Subject: [PATCH 8/8] $raffle prettified --- src/NadekoBot/Modules/Gambling/Gambling.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 53ad4389..8db03d30 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -42,7 +42,7 @@ namespace NadekoBot.Modules.Gambling var members = role.Members().Where(u => u.Status != UserStatus.Offline && u.Status != UserStatus.Unknown); var membersArray = members as IUser[] ?? members.ToArray(); var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)]; - await Context.Channel.SendConfirmAsync("🎟 Raffled user", $"**{usr.Username}#{usr.Discriminator}** ID: `{usr.Id}`").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync("🎟 Raffled user", $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases]