diff --git a/README.md b/README.md index 7bb0d57e..f1bef229 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true) -[![Discord](https://discordapp.com/api/servers/117523346618318850/widget.png)](https://discord.gg/0ehQwTK2RBjAxzEY) +[![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/0ehQwTK2RBjAxzEY) [![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/1.0/?badge=latest) # NadekoBot diff --git a/docs/Commands List.md b/docs/Commands List.md index 003da472..2088905f 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -1,17 +1,17 @@ For more information and how to setup your own NadekoBot, go to: You can support the project on patreon: or paypal: `nadekodiscordbot@gmail.com` ##Table Of Contents -- [Searches](#searches) +- [Help](#help) +- [Music](#music) +- [CustomReactions](#customreactions) +- [ClashOfClans](#clashofclans) +- [Gambling](#gambling) +- [Administration](#administration) - [Games](#games) +- [Searches](#searches) - [Permissions](#permissions) - [Utility](#utility) -- [Gambling](#gambling) -- [CustomReactions](#customreactions) -- [Music](#music) -- [ClashOfClans](#clashofclans) - [NSFW](#nsfw) -- [Administration](#administration) -- [Help](#help) ### Administration @@ -285,9 +285,6 @@ Command and aliases | Description | Usage `~color` `~clr` | Shows you what color corresponds to that hex. | `~clr 00ff00` `~videocall` | Creates a private video call link for you and other mentioned people. The link is sent to mentioned people via a private message. | `~videocall "@SomeGuy"` `~avatar` `~av` | Shows a mentioned person's avatar. | `~av "@SomeGuy"` -`~minecraftping` `~mcping` | Pings a minecraft server. | `~mcping 127.0.0.1:1337` -`~minecraftquery` `~mcquery` | Finds information about a minecraft server. | `~mcquery server:ip` -`~minecraftuser` `~mcuser` | Finds information about a minecraft user. | `~mcuser username or uuid` `~lolban` | Shows top banned champions ordered by ban rate. | `~lolban` `~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist` `~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"` diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 46176fcf..d7f72186 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -311,7 +311,8 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - [RequirePermission(GuildPermission.BanMembers)] + [RequirePermission(GuildPermission.KickMembers)] + [RequirePermission(GuildPermission.ManageMessages)] public async Task Softban(IUserMessage umsg, IGuildUser user, [Remainder] string msg = null) { var channel = (ITextChannel)umsg.Channel; diff --git a/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs b/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs index 9a872341..c755d34d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs @@ -80,7 +80,7 @@ namespace NadekoBot.Modules.Administration { var firstOwnerChannel = ownerChannels.First(); if (firstOwnerChannel.Recipient.Id != msg.Author.Id) - try { await firstOwnerChannel.SendMessageAsync(msg.Content).ConfigureAwait(false); } catch { } + try { await firstOwnerChannel.SendMessageAsync(toSend).ConfigureAwait(false); } catch { } } } } diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 40ac1a5d..23aa8e7c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -384,7 +384,7 @@ namespace NadekoBot.Modules.Administration πŸ‘€`{msg.Author.Username}`: {msg.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator)}"; if (msg.Attachments.Any()) str += $"{Environment.NewLine}`Attachements`: {string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))}"; - await logChannel.SendMessageAsync(str).ConfigureAwait(false); + await logChannel.SendMessageAsync(str.SanitizeMentions()).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } }); @@ -421,8 +421,8 @@ namespace NadekoBot.Modules.Administration { try { await logChannel.SendMessageAsync($@"πŸ•”`{prettyCurrentTime}` **Message** πŸ“ `#{channel.Name}` πŸ‘€`{before.Author.Username}` - `Old:` {before.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator)} - `New:` {after.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator)}").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + `Old:` {before.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator).SanitizeMentions()} + `New:` {after.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator).SanitizeMentions()}").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } }); return Task.CompletedTask; diff --git a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs index 713fb7a2..44459e8f 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs @@ -159,7 +159,7 @@ namespace NadekoBot.Modules.Administration return old; }); - await channel.SendMessageAsync($"Repeating \"{rep.Repeater.Message}\" every {rep.Repeater.Interval} minutes").ConfigureAwait(false); + await channel.SendMessageAsync($"Repeating \"{rep.Repeater.Message}\" every {rep.Repeater.Interval.Days} days, {rep.Repeater.Interval.Hours} hours and {rep.Repeater.Interval.Minutes} minutes.").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index cd9b4bc2..1e4ca219 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -114,7 +114,7 @@ namespace NadekoBot.Modules.Administration var channel = (ITextChannel)msg.Channel; var guild = channel.Guild; - var botUser = guild.GetCurrentUser(); + var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false); if (!botUser.GuildPermissions.ManageRoles || !botUser.GuildPermissions.ManageChannels) { await channel.SendMessageAsync(":anger: `I require atleast manage roles and manage channels permissions to enable this feature (preffered Administration permission).`"); @@ -166,7 +166,8 @@ namespace NadekoBot.Modules.Administration { var channel = (ITextChannel)msg.Channel; var guild = channel.Guild; - if (!guild.GetCurrentUser().GuildPermissions.Administrator) + var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false); + if (!botUser.GuildPermissions.Administrator) { await channel.SendMessageAsync("`I need Administrator permission to do that.`").ConfigureAwait(false); return; diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index d13b143a..2882eb11 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -19,6 +19,7 @@ namespace NadekoBot.Modules.CustomReactions { public static ConcurrentHashSet GlobalReactions { get; } = new ConcurrentHashSet(); public static ConcurrentDictionary> GuildReactions { get; } = new ConcurrentDictionary>(); + static CustomReactions() { using (var uow = DbHandler.UnitOfWork()) @@ -30,49 +31,43 @@ namespace NadekoBot.Modules.CustomReactions } public CustomReactions(ILocalization loc, CommandService cmds, ShardedDiscordClient client) : base(loc, cmds, client) { - client.MessageReceived += (imsg) => + } + + public static async Task TryExecuteCustomReaction(IUserMessage umsg) + { + var channel = umsg.Channel as ITextChannel; + if (channel == null) + return false; + + var content = umsg.Content.Trim().ToLowerInvariant(); + ConcurrentHashSet reactions; + GuildReactions.TryGetValue(channel.Guild.Id, out reactions); + if (reactions != null && reactions.Any()) { - var umsg = imsg as IUserMessage; - if (umsg == null || imsg.Author.IsBot) - return Task.CompletedTask; - - var channel = umsg.Channel as ITextChannel; - if (channel == null) - return Task.CompletedTask; - - var t = Task.Run(async () => + var reaction = reactions.Where(cr => { + var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%"); + var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant(); + return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); + }).Shuffle().FirstOrDefault(); + if (reaction != null) { - var content = umsg.Content.Trim().ToLowerInvariant(); - ConcurrentHashSet reactions; - GuildReactions.TryGetValue(channel.Guild.Id, out reactions); - if (reactions != null && reactions.Any()) - { - var reaction = reactions.Where(cr => { - var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%"); - var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant(); - return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); - }).Shuffle().FirstOrDefault(); - if (reaction != null) - { - try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } - return; - } - } - var greaction = GlobalReactions.Where(cr => - { - var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%"); - var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant(); - return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); - }).Shuffle().FirstOrDefault(); + try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } + return true; + } + } + var greaction = GlobalReactions.Where(cr => + { + var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%"); + var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant(); + return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); + }).Shuffle().FirstOrDefault(); - if (greaction != null) - { - try { await channel.SendMessageAsync(greaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } - return; - } - }); - return Task.CompletedTask; - }; + if (greaction != null) + { + try { await channel.SendMessageAsync(greaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } + return true; + } + return false; } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs index 466bc23a..801b4bab 100644 --- a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs @@ -218,6 +218,47 @@ namespace NadekoBot.Modules.Games await channel.SendMessageAsync("Added new article for typing game.").ConfigureAwait(false); } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task Typelist(IUserMessage imsg, int page = 1) + { + var channel = (ITextChannel)imsg.Channel; + + if (page < 1) + return; + + var articles = TypingArticles.Skip((page - 1) * 15).Take(15); + + if (!articles.Any()) + { + await channel.SendMessageAsync($"{imsg.Author.Mention} `No articles found on that page.`").ConfigureAwait(false); + return; + } + var i = (page - 1) * 15; + await channel.SendMessageAsync(String.Join("\n", articles.Select(a => $"`#{++i}` - {a.Text.TrimTo(50)}"))) + .ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task Typedel(IUserMessage imsg, int index) + { + var channel = (ITextChannel)imsg.Channel; + + index -= 1; + if (index < 0 || index >= TypingArticles.Count) + return; + + var removed = TypingArticles[index]; + TypingArticles.RemoveAt(index); + + File.WriteAllText(typingArticlesPath, JsonConvert.SerializeObject(TypingArticles)); + + await channel.SendMessageAsync($"`Removed typing article:` #{index + 1} - {removed.Text.TrimTo(50)}") + .ConfigureAwait(false); + } } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 70af561d..be775ab0 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -38,14 +38,23 @@ namespace NadekoBot.Modules.Music [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public Task Next(IUserMessage umsg) + public Task Next(IUserMessage umsg, int skipCount = 1) { var channel = (ITextChannel)umsg.Channel; + if (skipCount < 1) + return Task.CompletedTask; + MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer)) return Task.CompletedTask; if (musicPlayer.PlaybackVoiceChannel == ((IGuildUser)umsg.Author).VoiceChannel) + { + while (--skipCount > 0) + { + musicPlayer.RemoveSongAt(0); + } musicPlayer.Next(); + } return Task.CompletedTask; } diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 93834390..2ae6a96e 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -30,17 +30,71 @@ namespace NadekoBot.Modules.NSFW tag = tag?.Trim() ?? ""; - var links = await Task.WhenAll(GetGelbooruImageLink("rating%3Aexplicit+" + tag), GetDanbooruImageLink("rating%3Aexplicit+" + tag)).ConfigureAwait(false); + tag = "rating%3Aexplicit+" + tag; + + var rng = new NadekoRandom(); + Task provider = Task.FromResult(""); + switch (rng.Next(0,4)) + { + case 0: + provider = GetDanbooruImageLink(tag); + break; + case 1: + provider = GetGelbooruImageLink(tag); + break; + case 2: + provider = GetATFbooruImageLink(tag); + break; + case 3: + provider = GetKonachanImageLink(tag); + break; + default: + break; + } + var link = await provider.ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(link)) + await channel.SendMessageAsync("Search yielded no results ;(").ConfigureAwait(false); + else + await channel.SendMessageAsync(link).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task HentaiBomb(IUserMessage umsg, [Remainder] string tag = null) + { + var channel = (ITextChannel)umsg.Channel; + + tag = tag?.Trim() ?? ""; + tag = "rating%3Aexplicit+" + tag; + + var links = await Task.WhenAll(GetGelbooruImageLink(tag), + GetDanbooruImageLink(tag), + GetKonachanImageLink(tag), + GetATFbooruImageLink(tag)).ConfigureAwait(false); if (links.All(l => l == null)) { - await channel.SendMessageAsync("`No results.`"); + await channel.SendMessageAsync("`No results.`").ConfigureAwait(false); return; } await channel.SendMessageAsync(String.Join("\n\n", links)).ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task ATFbooru(IUserMessage umsg, [Remainder] string tag = null) + { + var channel = (ITextChannel)umsg.Channel; + + tag = tag?.Trim() ?? ""; + var link = await GetATFbooruImageLink(tag).ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(link)) + await channel.SendMessageAsync("Search yielded no results ;(").ConfigureAwait(false); + else + await channel.SendMessageAsync(link).ConfigureAwait(false); + } + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Danbooru(IUserMessage umsg, [Remainder] string tag = null) @@ -50,7 +104,7 @@ namespace NadekoBot.Modules.NSFW tag = tag?.Trim() ?? ""; var link = await GetDanbooruImageLink(tag).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(link)) - await channel.SendMessageAsync("Search yielded no results ;("); + await channel.SendMessageAsync("Search yielded no results ;(").ConfigureAwait(false); else await channel.SendMessageAsync(link).ConfigureAwait(false); } @@ -64,7 +118,7 @@ namespace NadekoBot.Modules.NSFW tag = tag?.Trim() ?? ""; var link = await GetKonachanImageLink(tag).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(link)) - await channel.SendMessageAsync("Search yielded no results ;("); + await channel.SendMessageAsync("Search yielded no results ;(").ConfigureAwait(false); else await channel.SendMessageAsync(link).ConfigureAwait(false); } @@ -78,7 +132,7 @@ namespace NadekoBot.Modules.NSFW tag = tag?.Trim() ?? ""; var link = await GetGelbooruImageLink(tag).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(link)) - await channel.SendMessageAsync("Search yielded no results ;("); + await channel.SendMessageAsync("Search yielded no results ;(").ConfigureAwait(false); else await channel.SendMessageAsync(link).ConfigureAwait(false); } @@ -92,7 +146,7 @@ namespace NadekoBot.Modules.NSFW tag = tag?.Trim() ?? ""; var link = await GetRule34ImageLink(tag).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(link)) - await channel.SendMessageAsync("Search yielded no results ;("); + await channel.SendMessageAsync("Search yielded no results ;(").ConfigureAwait(false); else await channel.SendMessageAsync(link).ConfigureAwait(false); } @@ -106,7 +160,7 @@ namespace NadekoBot.Modules.NSFW tag = tag?.Trim() ?? ""; var link = await GetE621ImageLink(tag).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(link)) - await channel.SendMessageAsync("Search yielded no results ;("); + await channel.SendMessageAsync("Search yielded no results ;(").ConfigureAwait(false); else await channel.SendMessageAsync(link).ConfigureAwait(false); } @@ -176,7 +230,7 @@ namespace NadekoBot.Modules.NSFW if (matches.Count == 0) return null; - return await NadekoBot.Google.ShortenUrl(matches[rng.Next(0, matches.Count)].Groups["ll"].Value).ConfigureAwait(false); + return matches[rng.Next(0, matches.Count)].Groups["ll"].Value; } } @@ -255,5 +309,25 @@ namespace NadekoBot.Modules.NSFW return "Error, do you have too many tags?"; } } + + public static async Task GetATFbooruImageLink(string tag) + { + var rng = new NadekoRandom(); + + var link = $"https://atfbooru.ninja/posts?" + + $"limit=100"; + if (!string.IsNullOrWhiteSpace(tag)) + link += $"&tags={tag.Replace(" ", "+")}"; + using (var http = new HttpClient()) + { + var webpage = await http.GetStringAsync(link).ConfigureAwait(false); + var matches = Regex.Matches(webpage, "data-file-url=\"(?.*?)\""); + + if (matches.Count == 0) + return null; + return $"https://atfbooru.ninja" + + $"{matches[rng.Next(0, matches.Count)].Groups["id"].Value}"; + } + } } } diff --git a/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs index e538e2a6..bbffabcf 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs @@ -80,7 +80,7 @@ namespace NadekoBot.Modules.Permissions } await uow.CompleteAsync().ConfigureAwait(false); } - if (action == AddRemove.Rem) + if (action == AddRemove.Add) { TriviaGame tg; switch (type) diff --git a/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs b/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs index 2108878f..c18eecdc 100644 --- a/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs @@ -58,7 +58,7 @@ namespace NadekoBot.Modules.Searches { if (i % 2 == 0 && i != 0) sb.AppendLine(); - sb.Append($"`{i + 1}.` **{dataList[i]["name"]}** "); + sb.Append($"`{i + 1}.` **{dataList[i]["name"]}** {dataList[i]["general"]["banRate"]}% "); //sb.AppendLine($" ({dataList[i]["general"]["banRate"]}%)"); } @@ -67,7 +67,7 @@ namespace NadekoBot.Modules.Searches } catch (Exception) { - await channel.SendMessageAsync($":anger: Fail: Champion.gg didsabled ban data until next patch. Sorry for the inconvenience.").ConfigureAwait(false); + await channel.SendMessageAsync($":anger: `Something went wrong.`").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index bf8c5203..2dc1c1b5 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Linq; +using System.Text; using System.Net.Http; using NadekoBot.Services; using System.Threading.Tasks; @@ -271,7 +272,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】 try { var items = JObject.Parse(res); - var sb = new System.Text.StringBuilder(); + var sb = new StringBuilder(); sb.AppendLine($"`Term:` {items["list"][0]["word"].ToString()}"); sb.AppendLine($"`Definition:` {items["list"][0]["definition"].ToString()}"); sb.Append($"`Link:` <{await _google.ShortenUrl(items["list"][0]["permalink"].ToString()).ConfigureAwait(false)}>"); @@ -463,6 +464,118 @@ $@"🌍 **Weather for** 【{obj["target"]}】 return matches[rng.Next(0, matches.Count)].Groups["url"].Value; } } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task Wikia(IUserMessage umsg, string targ, [Remainder] string query = null) + { + var channel = (ITextChannel)umsg.Channel; + var arg = query; + if (string.IsNullOrWhiteSpace(targ) || string.IsNullOrWhiteSpace(arg)) + { + await channel.SendMessageAsync("πŸ’’ Please enter `target query`.").ConfigureAwait(false); + return; + } + await umsg.Channel.TriggerTypingAsync().ConfigureAwait(false); + using (var http = new HttpClient()) + { + http.DefaultRequestHeaders.Clear(); + string target = targ; + string search = arg; + try + { + var res = await http.GetStringAsync($"http://www.{Uri.EscapeUriString(target)}.wikia.com/api/v1/Search/List?query={Uri.EscapeUriString(search)}&limit=25&minArticleQuality=10&batch=1&namespaces=0%2C14").ConfigureAwait(false); + var items = JObject.Parse(res); + var sb = new StringBuilder(); + sb.AppendLine($"`Found:` {items["items"][0]["title"].ToString()}"); + sb.AppendLine($"`Total Found:` {items["total"].ToString()}"); + sb.AppendLine($"`Batch:` {items["currentBatch"].ToString()}/{items["batches"].ToString()}"); + sb.Append($"`URL:` <{await _google.ShortenUrl(items["items"][0]["url"].ToString()).ConfigureAwait(false)}> / `Quality`: {items["items"][0]["quality"].ToString()}"); + await channel.SendMessageAsync(sb.ToString()); + } + catch + { + await channel.SendMessageAsync($"πŸ’’ Failed finding `{arg}`.").ConfigureAwait(false); + } + } + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task MCPing(IUserMessage umsg, [Remainder] string query = null) + { + var channel = (ITextChannel)umsg.Channel; + var arg = query; + if (string.IsNullOrWhiteSpace(arg)) + { + await channel.SendMessageAsync("πŸ’’ Please enter a `ip:port`.").ConfigureAwait(false); + return; + } + await umsg.Channel.TriggerTypingAsync().ConfigureAwait(false); + using (var http = new HttpClient()) + { + http.DefaultRequestHeaders.Clear(); + string ip = arg.Split(':')[0]; + string port = arg.Split(':')[1]; + var res = await http.GetStringAsync($"https://api.minetools.eu/ping/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false); + try + { + var items = JObject.Parse(res); + var sb = new StringBuilder(); + int ping = (int)Math.Ceiling(Double.Parse(items["latency"].ToString())); + sb.AppendLine($"`Server:` {arg}"); + sb.AppendLine($"`Version:` {items["version"]["name"].ToString()} / Protocol {items["version"]["protocol"].ToString()}"); + sb.AppendLine($"`Description:` {items["description"].ToString()}"); + sb.AppendLine($"`Online Players:` {items["players"]["online"].ToString()}/{items["players"]["max"].ToString()}"); + sb.Append($"`Latency:` {ping}"); + await channel.SendMessageAsync(sb.ToString()); + } + catch + { + await channel.SendMessageAsync($"πŸ’’ Failed finding `{arg}`.").ConfigureAwait(false); + } + } + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task MCQ(IUserMessage umsg, [Remainder] string query = null) + { + var channel = (ITextChannel)umsg.Channel; + var arg = query; + if (string.IsNullOrWhiteSpace(arg)) + { + await channel.SendMessageAsync("πŸ’’ Please enter a `ip:port`.").ConfigureAwait(false); + return; + } + await umsg.Channel.TriggerTypingAsync().ConfigureAwait(false); + using (var http = new HttpClient()) + { + http.DefaultRequestHeaders.Clear(); + try + { + string ip = arg.Split(':')[0]; + string port = arg.Split(':')[1]; + var res = await http.GetStringAsync($"https://api.minetools.eu/query/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false); + var items = JObject.Parse(res); + var sb = new StringBuilder(); + sb.AppendLine($"`Server:` {arg.ToString()} γ€˜Status: {items["status"]}γ€™"); + sb.AppendLine($"`Player List (First 5):`"); + foreach (var item in items["Playerlist"].Take(5)) + { + sb.AppendLine($"γ€”:rosette: {item}〕"); + } + sb.AppendLine($"`Online Players:` {items["Players"]} / {items["MaxPlayers"]}"); + sb.AppendLine($"`Plugins:` {items["Plugins"]}"); + sb.Append($"`Version:` {items["Version"]}"); + await channel.SendMessageAsync(sb.ToString()); + } + catch + { + await channel.SendMessageAsync($"πŸ’’ Failed finding server `{arg}`.").ConfigureAwait(false); + } + } + } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 8634c721..fb4a95a9 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -169,14 +169,35 @@ namespace NadekoBot.Modules.Utility { var matches = emojiFinder.Matches(emojis); - - var result = string.Join("\n", matches.Cast() .Select(m => $"`Name:` {m.Groups["name"]} `Link:` http://discordapp.com/api/emojis/{m.Groups["id"]}.png")); await msg.Channel.SendMessageAsync(result).ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task ListServers(IUserMessage imsg, int page = 1) + { + var channel = (ITextChannel)imsg.Channel; + + page -= 1; + + if (page < 0) + return; + + var guilds = NadekoBot.Client.GetGuilds().OrderBy(g => g.Name).Skip((page - 1) * 15).Take(15); + + if (!guilds.Any()) + { + await channel.SendMessageAsync("`No servers found on that page.`").ConfigureAwait(false); + return; + } + + await channel.SendMessageAsync(String.Join("\n", guilds.Select(g => $"`Name:` {g.Name} `Id:` {g.Id} `Members:` {g.GetUsers().Count} `OwnerId:`{g.OwnerId}"))).ConfigureAwait(false); + } + //[NadekoCommand, Usage, Description, Aliases] //[RequireContext(ContextType.Guild)] //public async Task TextToImage(IUserMessage msg, [Remainder] string arg) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index a41c6a07..6fe768c9 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -464,6 +464,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to atfbooru atf. + /// + public static string atfbooru_cmd { + get { + return ResourceManager.GetString("atfbooru_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows a random hentai image from atfbooru with a given tag. Tag is optional but preferred.. + /// + public static string atfbooru_desc { + get { + return ResourceManager.GetString("atfbooru_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}atfbooru yuri+kissing`. + /// + public static string atfbooru_usage { + get { + return ResourceManager.GetString("atfbooru_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to autoassignrole aar. /// @@ -2823,7 +2850,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows a 2 random images (from gelbooru and danbooru) with a given tag. Tag is optional but preferred. Only 1 tag allowed.. + /// Looks up a localized string similar to Shows a hentai image from a random website (gelbooru or danbooru or konachan or atfbooru) with a given tag. Tag is optional but preferred. Only 1 tag allowed.. /// public static string hentai_desc { get { @@ -2840,6 +2867,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to hentaibomb. + /// + public static string hentaibomb_cmd { + get { + return ResourceManager.GetString("hentaibomb_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows a total 4 images (from gelbooru, danbooru, konachan and atfbooru). Tag is optional but preferred.. + /// + public static string hentaibomb_desc { + get { + return ResourceManager.GetString("hentaibomb_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}hentaibomb yuri`. + /// + public static string hentaibomb_usage { + get { + return ResourceManager.GetString("hentaibomb_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to hgit. /// @@ -3147,7 +3201,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. (multiple tags are appended with +). + /// Looks up a localized string similar to Shows a random hentai image from konachan with a given tag. Tag is optional but preferred.. /// public static string konachan_desc { get { @@ -3434,6 +3488,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to listservers. + /// + public static string listservers_cmd { + get { + return ResourceManager.GetString("listservers_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lists servers the bot is on with some basic info. 15 per page.. + /// + public static string listservers_desc { + get { + return ResourceManager.GetString("listservers_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}listservers 3`. + /// + public static string listservers_usage { + get { + return ResourceManager.GetString("listservers_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to liststreams ls. /// @@ -3856,6 +3937,60 @@ namespace NadekoBot.Resources { return ResourceManager.GetString("memegen_desc", resourceCulture); } } + + /// + /// Looks up a localized string similar to minecraftping mcping. + /// + public static string mcping_cmd { + get { + return ResourceManager.GetString("mcping_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pings a minecraft server.. + /// + public static string mcping_desc { + get { + return ResourceManager.GetString("mcping_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}mcping 127.0.0.1:1337`. + /// + public static string mcping_usage { + get { + return ResourceManager.GetString("mcping_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to minecraftquery mcq. + /// + public static string mcq_cmd { + get { + return ResourceManager.GetString("mcq_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Finds information about a minecraft server.. + /// + public static string mcq_desc { + get { + return ResourceManager.GetString("mcq_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}mcq server:ip`. + /// + public static string mcq_usage { + get { + return ResourceManager.GetString("mcq_usage", resourceCulture); + } + } /// /// Looks up a localized string similar to `{0}memegen biw "gets iced coffee" "in the winter"`. @@ -4092,7 +4227,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Goes to the next song in the queue. You have to be in the same voice channel as the bot.. + /// Looks up a localized string similar to Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if {0}rcs or {0}rpl is enabled.. /// public static string next_desc { get { @@ -4101,7 +4236,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}n`. + /// Looks up a localized string similar to `{0}n` or `{0}n 5`. /// public static string next_usage { get { @@ -6701,6 +6836,60 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to typedel. + /// + public static string typedel_cmd { + get { + return ResourceManager.GetString("typedel_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Deletes a typing article given the ID.. + /// + public static string typedel_desc { + get { + return ResourceManager.GetString("typedel_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}typedel 3`. + /// + public static string typedel_usage { + get { + return ResourceManager.GetString("typedel_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to typelist. + /// + public static string typelist_cmd { + get { + return ResourceManager.GetString("typelist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lists added typing articles with their IDs. 15 per page.. + /// + public static string typelist_desc { + get { + return ResourceManager.GetString("typelist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}typelist` or `{0}typelist 3`. + /// + public static string typelist_usage { + get { + return ResourceManager.GetString("typelist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to typestart. /// @@ -7321,6 +7510,33 @@ namespace NadekoBot.Resources { return ResourceManager.GetString("wiki_usage", resourceCulture); } } + + /// + /// Looks up a localized string similar to wikia. + /// + public static string wikia_cmd { + get { + return ResourceManager.GetString("wikia_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gives you back a wikia link. + /// + public static string wikia_desc { + get { + return ResourceManager.GetString("wikia_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}wikia target query`. + /// + public static string wikia_usage { + get { + return ResourceManager.GetString("wikia_usage", resourceCulture); + } + } /// /// Looks up a localized string similar to wowjoke. diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index a89a5669..98faafae 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1426,10 +1426,10 @@ next n - Goes to the next song in the queue. You have to be in the same voice channel as the bot. + Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if {0}rcs or {0}rpl is enabled. - `{0}n` + `{0}n` or `{0}n 5` stop s @@ -2101,7 +2101,7 @@ hentai - Shows a 2 random images (from gelbooru and danbooru) with a given tag. Tag is optional but preferred. Only 1 tag allowed. + Shows a hentai image from a random website (gelbooru or danbooru or konachan or atfbooru) with a given tag. Tag is optional but preferred. Only 1 tag allowed. `{0}hentai yuri` @@ -2115,6 +2115,15 @@ `{0}danbooru yuri+kissing` + + atfbooru atf + + + Shows a random hentai image from atfbooru with a given tag. Tag is optional but preferred. + + + `{0}atfbooru yuri+kissing` + gelbooru @@ -2452,7 +2461,7 @@ konachan - Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. `{0}konachan yuri` @@ -2574,31 +2583,67 @@ Lists all quotes on the server ordered alphabetically. 15 Per page. + + typedel + + + Deletes a typing article given the ID. + + + `{0}typedel 3` + + + typelist + + + Lists added typing articles with their IDs. 15 per page. + + + `{0}typelist` or `{0}typelist 3` + + + listservers + + + Lists servers the bot is on with some basic info. 15 per page. + + + `{0}listservers 3` + + + hentaibomb + + + Shows a total 4 images (from gelbooru, danbooru, konachan and atfbooru). Tag is optional but preferred. + + + `{0}hentaibomb yuri` + - minecraftping mcping - + minecraftping mcping + - Pings a minecraft server. + Pings a minecraft server. - `{0}mcping 127.0.0.1:1337` + `{0}mcping 127.0.0.1:25565` - - minecraftuser mcuser + + minecraftquery mcq - - Finds information about a minecraft user. + + Finds information about a minecraft server. - - `{0}mcuser username or uuid` + + `{0}mcq server:ip` - - minecraftquery mcquery + + wikia - - Finds information about a minecraft server. + + Gives you back a wikia link - - `{0}mcquery server:ip` + + `{0}wikia target query` \ No newline at end of file diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index a70eabe4..52d4ba4f 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -18,6 +18,7 @@ using static NadekoBot.Modules.Permissions.Permissions; using System.Collections.Concurrent; using NadekoBot.Modules.Help; using static NadekoBot.Modules.Administration.Administration; +using NadekoBot.Modules.CustomReactions; namespace NadekoBot.Services { @@ -110,16 +111,28 @@ namespace NadekoBot.Services _log.Warn("I do not have permission to filter words in channel with id " + usrMsg.Channel.Id, ex); } } - - BlacklistItem blacklistedItem; - if ((blacklistedItem = Permissions.BlacklistCommands.BlacklistedItems.FirstOrDefault(bi => - (bi.Type == BlacklistItem.BlacklistType.Server && bi.ItemId == guild?.Id) || - (bi.Type == BlacklistItem.BlacklistType.Channel && bi.ItemId == msg.Channel.Id) || - (bi.Type == BlacklistItem.BlacklistType.User && bi.ItemId == usrMsg.Author.Id))) != null) - { - return; - } } + + BlacklistItem blacklistedItem; + if ((blacklistedItem = Permissions.BlacklistCommands.BlacklistedItems.FirstOrDefault(bi => + (bi.Type == BlacklistItem.BlacklistType.Server && bi.ItemId == guild?.Id) || + (bi.Type == BlacklistItem.BlacklistType.Channel && bi.ItemId == msg.Channel.Id) || + (bi.Type == BlacklistItem.BlacklistType.User && bi.ItemId == usrMsg.Author.Id))) != null) + { + return; + } + + try + { + // maybe this message is a custom reaction + var crExecuted = await CustomReactions.TryExecuteCustomReaction(usrMsg).ConfigureAwait(false); + + //if it was, don't execute the command + if (crExecuted) + return; + } + catch { } + var throwaway = Task.Run(async () => { var sw = new Stopwatch(); diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index 5d578dc1..860a379c 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -91,6 +91,10 @@ namespace NadekoBot.Services.Impl { if (string.IsNullOrWhiteSpace(url)) throw new ArgumentNullException(nameof(url)); + + if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.GoogleApiKey)) + return url; + try { var response = await sh.Url.Insert(new Url { LongUrl = url }).ExecuteAsync(); diff --git a/src/NadekoBot/project.json b/src/NadekoBot/project.json index 5d021051..9ed621ff 100644 --- a/src/NadekoBot/project.json +++ b/src/NadekoBot/project.json @@ -7,7 +7,7 @@ "emitEntryPoint": true, "allowUnsafe": true, "compile": { - "exclude": [ "data" ] + "exclude": [ "data", "credentials.json", "credentials_example.json" ] }, "copyToOutput": { "include": [ "data" ],