From c9c572296ae342ca34b023f326b96f9111d5dcdc Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 28 Mar 2016 02:58:34 +0200 Subject: [PATCH 1/4] commandlist update --- NadekoBot/Commands/LoLCommands.cs | 144 +++++++++++++++++++---------- NadekoBot/Modules/Conversations.cs | 17 ++-- commandlist.md | 33 ++++--- 3 files changed, 125 insertions(+), 69 deletions(-) diff --git a/NadekoBot/Commands/LoLCommands.cs b/NadekoBot/Commands/LoLCommands.cs index 09a49e92..4b706745 100644 --- a/NadekoBot/Commands/LoLCommands.cs +++ b/NadekoBot/Commands/LoLCommands.cs @@ -1,19 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Discord.Commands; -using System.Drawing; +using Discord.Commands; using NadekoBot.Classes; using NadekoBot.Extensions; using NadekoBot.Modules; using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; -namespace NadekoBot.Commands { - internal class LoLCommands : DiscordCommand { +namespace NadekoBot.Commands +{ + internal class LoLCommands : DiscordCommand + { - private class CachedChampion { + private class CachedChampion + { public System.IO.Stream ImageStream { get; set; } public DateTime AddedAt { get; set; } public string Name { get; set; } @@ -24,16 +27,20 @@ namespace NadekoBot.Commands { private System.Timers.Timer clearTimer { get; } = new System.Timers.Timer(); - public LoLCommands(DiscordModule module) : base(module) { + public LoLCommands(DiscordModule module) : base(module) + { clearTimer.Interval = new TimeSpan(0, 10, 0).TotalMilliseconds; clearTimer.Start(); - clearTimer.Elapsed += (s, e) => { - try { + clearTimer.Elapsed += (s, e) => + { + try + { lock (cacheLock) CachedChampionImages = CachedChampionImages .Where(kvp => DateTime.Now - kvp.Value.AddedAt > new TimeSpan(1, 0, 0)) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); - } catch { } + } + catch { } }; } @@ -44,11 +51,13 @@ namespace NadekoBot.Commands { "If you consider playing teemo, do it. If you consider teemo, you deserve him.", "Doesn't matter what you ban really. Enemy will ban your main and you will lose." }; - public Func DoFunc() { + public Func DoFunc() + { throw new NotImplementedException(); } - private class MatchupModel { + private class MatchupModel + { public int Games { get; set; } public float WinRate { get; set; } [Newtonsoft.Json.JsonProperty("key")] @@ -56,48 +65,60 @@ namespace NadekoBot.Commands { public float StatScore { get; set; } } - internal override void Init(CommandGroupBuilder cgb) { + internal override void Init(CommandGroupBuilder cgb) + { cgb.CreateCommand(Module.Prefix + "lolchamp") .Description("Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role.\n**Usage**:~lolchamp Riven or ~lolchamp Annie sup") .Parameter("champ", ParameterType.Required) .Parameter("position", ParameterType.Unparsed) - .Do(async e => { - try { + .Do(async e => + { + try + { //get role var role = ResolvePos(e.GetArg("position")); var resolvedRole = role; var name = e.GetArg("champ").Replace(" ", "").ToLower(); CachedChampion champ = null; - lock (cacheLock) { + lock (cacheLock) + { CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ); } - if (champ != null) { + if (champ != null) + { champ.ImageStream.Position = 0; await e.Channel.SendFile("champ.png", champ.ImageStream); return; } var allData = JArray.Parse(await Classes.SearchHelper.GetResponseStringAsync($"http://api.champion.gg/champion/{name}?api_key={NadekoBot.Creds.LOLAPIKey}")); JToken data = null; - if (role != null) { - for (var i = 0; i < allData.Count; i++) { - if (allData[i]["role"].ToString().Equals(role)) { + if (role != null) + { + for (var i = 0; i < allData.Count; i++) + { + if (allData[i]["role"].ToString().Equals(role)) + { data = allData[i]; break; } } - if (data == null) { + if (data == null) + { await e.Channel.SendMessage("💢 Data for that role does not exist."); return; } - } else { + } + else { data = allData[0]; role = allData[0]["role"].ToString(); resolvedRole = ResolvePos(role); } - lock (cacheLock) { + lock (cacheLock) + { CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ); } - if (champ != null) { + if (champ != null) + { Console.WriteLine("Sending lol image from cache."); champ.ImageStream.Position = 0; await e.Channel.SendFile("champ.png", champ.ImageStream); @@ -106,7 +127,8 @@ namespace NadekoBot.Commands { //name = data["title"].ToString(); // get all possible roles, and "select" the shown one var roles = new string[allData.Count]; - for (var i = 0; i < allData.Count; i++) { + for (var i = 0; i < allData.Count; i++) + { roles[i] = allData[i]["role"].ToString(); if (roles[i] == role) roles[i] = ">" + roles[i] + "<"; @@ -114,14 +136,16 @@ namespace NadekoBot.Commands { var general = JArray.Parse(await SearchHelper.GetResponseStringAsync($"http://api.champion.gg/stats/" + $"champs/{name}?api_key={NadekoBot.Creds.LOLAPIKey}")) .FirstOrDefault(jt => jt["role"].ToString() == role)?["general"]; - if (general == null) { + if (general == null) + { Console.WriteLine("General is null."); return; } //get build data for this role var buildData = data["items"]["mostGames"]["items"]; var items = new string[6]; - for (var i = 0; i < 6; i++) { + for (var i = 0; i < 6; i++) + { items[i] = buildData[i]["id"].ToString(); } @@ -146,7 +170,8 @@ namespace NadekoBot.Commands { var orderArr = (data["skills"]["mostGames"]["order"] as JArray); var img = Image.FromFile("data/lol/bg.png"); - using (var g = Graphics.FromImage(img)) { + using (var g = Graphics.FromImage(img)) + { g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; //g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy; const int margin = 5; @@ -166,12 +191,14 @@ namespace NadekoBot.Commands { //draw skill order float orderFormula = 120 / orderArr.Count; const float orderVerticalSpacing = 10; - for (var i = 0; i < orderArr.Count; i++) { + for (var i = 0; i < orderArr.Count; i++) + { var orderX = margin + margin + imageSize + orderFormula * i + i; float orderY = margin + 35; var spellName = orderArr[i].ToString().ToLowerInvariant(); - switch (spellName) { + switch (spellName) + { case "w": orderY += orderVerticalSpacing; break; @@ -206,7 +233,8 @@ Assists: {general["assists"]} Ban: {general["banRate"]}% g.DrawString($"Best against", smallFont, Brushes.WhiteSmoke, margin, img.Height - imageSize + margin); var smallImgSize = 50; - for (var i = 0; i < counters.Length; i++) { + for (var i = 0; i < counters.Length; i++) + { g.DrawImage(GetImage(counters[i]), new Rectangle(i * (smallImgSize + margin) + margin, img.Height - smallImgSize - margin, smallImgSize, @@ -215,7 +243,8 @@ Assists: {general["assists"]} Ban: {general["banRate"]}% //draw countered by g.DrawString($"Worst against", smallFont, Brushes.WhiteSmoke, img.Width - 3 * (smallImgSize + margin), img.Height - imageSize + margin); - for (var i = 0; i < countered.Length; i++) { + for (var i = 0; i < countered.Length; i++) + { var j = countered.Length - i; g.DrawImage(GetImage(countered[i]), new Rectangle(img.Width - (j * (smallImgSize + margin) + margin), img.Height - smallImgSize - margin, @@ -225,7 +254,8 @@ Assists: {general["assists"]} Ban: {general["banRate"]}% //draw item build g.DrawString("Popular build", normalFont, Brushes.WhiteSmoke, img.Width - (3 * (smallImgSize + margin) + margin), 77); - for (var i = 0; i < 6; i++) { + for (var i = 0; i < 6; i++) + { var inverseI = 5 - i; var j = inverseI % 3 + 1; var k = inverseI / 3; @@ -238,18 +268,23 @@ Assists: {general["assists"]} Ban: {general["banRate"]}% var cachedChamp = new CachedChampion { AddedAt = DateTime.Now, ImageStream = img.ToStream(System.Drawing.Imaging.ImageFormat.Png), Name = name.ToLower() + "_" + resolvedRole }; CachedChampionImages.Add(cachedChamp.Name, cachedChamp); await e.Channel.SendFile(data["title"] + "_stats.png", cachedChamp.ImageStream); - } catch { + } + catch (Exception ex) + { + Console.WriteLine(ex); await e.Channel.SendMessage("💢 Failed retreiving data for that champion."); } }); cgb.CreateCommand(Module.Prefix + "lolban") .Description("Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time.") - .Do(async e => { + .Do(async e => + { var showCount = 6; //http://api.champion.gg/stats/champs/mostBanned?api_key=YOUR_API_TOKEN&page=1&limit=2 - try { + try + { var data = JObject.Parse( await Classes .SearchHelper @@ -260,7 +295,8 @@ Assists: {general["assists"]} Ban: {general["banRate"]}% var sb = new StringBuilder(); sb.AppendLine($"**Showing {showCount} top banned champions.**"); sb.AppendLine($"`{trashTalk[new Random().Next(0, trashTalk.Length)]}`"); - for (var i = 0; i < data.Count; i++) { + for (var i = 0; i < data.Count; i++) + { if (i % 2 == 0 && i != 0) sb.AppendLine(); sb.Append($"`{i + 1}.` **{data[i]["name"]}** "); @@ -268,34 +304,44 @@ Assists: {general["assists"]} Ban: {general["banRate"]}% } await e.Channel.SendMessage(sb.ToString()); - } catch (Exception ex) { + } + catch (Exception ex) + { await e.Channel.SendMessage($":anger: Fail: Champion.gg didsabled ban data until next patch. Sorry for the inconvenience."); } }); } - private enum GetImageType { + private enum GetImageType + { Champion, Item } - private static Image GetImage(string id, GetImageType imageType = GetImageType.Champion) { - try { - switch (imageType) { + private static Image GetImage(string id, GetImageType imageType = GetImageType.Champion) + { + try + { + switch (imageType) + { case GetImageType.Champion: return Image.FromFile($"data/lol/champions/{id}.png"); case GetImageType.Item: default: return Image.FromFile($"data/lol/items/{id}.png"); } - } catch (Exception) { + } + catch (Exception) + { return Image.FromFile("data/lol/_ERROR.png"); } } - private static string ResolvePos(string pos) { + private static string ResolvePos(string pos) + { if (string.IsNullOrWhiteSpace(pos)) return null; - switch (pos.ToLowerInvariant()) { + switch (pos.ToLowerInvariant()) + { case "m": case "mid": case "midorfeed": diff --git a/NadekoBot/Modules/Conversations.cs b/NadekoBot/Modules/Conversations.cs index a8ba0317..c3f8ecf1 100644 --- a/NadekoBot/Modules/Conversations.cs +++ b/NadekoBot/Modules/Conversations.cs @@ -1,18 +1,17 @@ using Discord; using Discord.Commands; using Discord.Modules; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Drawing.Imaging; using NadekoBot.Classes; +using NadekoBot.Commands; using NadekoBot.Extensions; using NadekoBot.Properties; -using NadekoBot.Commands; +using System; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Threading.Tasks; namespace NadekoBot.Modules { diff --git a/commandlist.md b/commandlist.md index 3fe3a9a1..681c48ba 100644 --- a/commandlist.md +++ b/commandlist.md @@ -2,7 +2,7 @@ ######You can donate on paypal: `nadekodiscordbot@gmail.com` or Bitcoin `17MZz1JAqME39akMLrVT4XBPffQJ2n1EPa` #NadekoBot List Of Commands -Version: `NadekoBot v0.9.5925.41065` +Version: `NadekoBot v0.9.5930.23184` ### Administration Command and aliases | Description | Usage ----------------|--------------|------- @@ -13,9 +13,9 @@ Command and aliases | Description | Usage `.byepm` | Toggles whether the good bye messages will be sent in a PM or in the text channel. `.greetpm` | Toggles whether the greet messages will be sent in a PM or in the text channel. `.spmom` | Toggles whether mentions of other offline users on your server will send a pm to them. -`.logserver` | Toggles logging in this channel. Logs every message sent/deleted/edited on the server. BOT OWNER ONLY. SERVER OWNER ONLY. -`.userpresence` | Starts logging to this channel when someone from the server goes online/offline/idle. BOT OWNER ONLY. SERVER OWNER ONLY. -`.voicepresence` | Toggles logging to this channel whenever someone joins or leaves a voice channel you are in right now. BOT OWNER ONLY. SERVER OWNER ONLY. +`.logserver` | Toggles logging in this channel. Logs every message sent/deleted/edited on the server. **Owner Only!** +`.userpresence` | Starts logging to this channel when someone from the server goes online/offline/idle. **Owner Only!** +`.voicepresence` | Toggles logging to this channel whenever someone joins or leaves a voice channel you are in right now. **Owner Only!** `.repeat` | Repeat a message every X minutes. If no parameters are specified, repeat is disabled. Requires manage messages. `.rotateplaying`, `.ropl` | Toggles rotation of playing status of the dynamic strings you specified earlier. `.addplaying`, `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %trivia% @@ -77,7 +77,7 @@ Command and aliases | Description | Usage Command and aliases | Description | Usage ----------------|--------------|------- `-h`, `-help`, `@BotName help`, `@BotName h`, `~h` | Either shows a help for a single command, or PMs you help link if no arguments are specified. | '-h !m q' or just '-h' -`-hgit` | OWNER ONLY commandlist.md file generation. +`-hgit` | Generates the commandlist.md file. **Owner Only!** `-readme`, `-guide` | Sends a readme and a guide links to the channel. `-donate`, `~donate` | Instructions for helping the project! `-modules`, `.modules` | List all bot modules. @@ -114,16 +114,19 @@ Command and aliases | Description | Usage `;arm`, `;allrolemodules` | Sets permissions for all modules at the role level. | ;arm [enable/disable] [role_name] `;arc`, `;allrolecommands` | Sets permissions for all commands from a certain module at the role level. | ;arc [module_name] [enable/disable] [role_name] `;ubl` | Blacklists a mentioned user. | ;ubl [user_mention] -`;uubl`, `;unblacklist` | Unblacklists a mentioned user. | ;uubl [user_mention] +`;uubl` | Unblacklists a mentioned user. | ;uubl [user_mention] `;cbl` | Blacklists a mentioned channel (#general for example). | ;ubl [channel_mention] +`;cubl` | Unblacklists a mentioned channel (#general for example). | ;cubl [channel_mention] `;sbl` | Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | ;usl [servername/serverid] ### Conversations Command and aliases | Description | Usage ----------------|--------------|------- `e` | You did it. +`comeatmebro` | Come at me bro (ง’̀-‘́)ง | comeatmebro {target} `\o\` | Nadeko replies with /o/ `/o/` | Nadeko replies with \o\ +`moveto` | Suggests moving the conversation. | moveto #spam `..` | Adds a new quote with the specified name (single word) and message (no limit). | .. abc My message `...` | Shows a random quote with a specified name. | .. abc `@BotName copyme`, `@BotName cm` | Nadeko starts copying everything you say. Disable with cs @@ -155,7 +158,7 @@ Command and aliases | Description | Usage `@BotName dump` | Dumps all of the invites it can to dump.txt.** Owner Only.** `@BotName ab` | Try to get 'abalabahaha' `@BotName av`, `@BotName avatar` | Shows a mentioned person's avatar. | ~av @X -`@BotName leet` | Convert your text to leetspeak. Level is a number 1-6. | @BotName leet [level] [Your text here] +`@BotName leet` | ### Gambling Command and aliases | Description | Usage @@ -167,6 +170,7 @@ Command and aliases | Description | Usage `$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15` `$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. `$$$` | Check how many NadekoFlowers you have. +`$give` | Give someone a certain amount of flowers ### Games Command and aliases | Description | Usage @@ -202,14 +206,14 @@ Command and aliases | Description | Usage `!m max` | Sets the music volume to 100% (real max is actually 150%). `!m half` | Sets the music volume to 50%. `!m sh` | Shuffles the current playlist. -`!m setgame` | Sets the game of the bot to the number of songs playing.**Owner only** +`!m setgame` | Sets the game of the bot to the number of songs playing. **Owner only** `!m pl` | Queues up to 25 songs from a youtube playlist specified by a link, or keywords. -`!m lopl` | Queues up to 50 songs from a directory. +`!m lopl` | Queues up to 50 songs from a directory. **Owner Only!** `!m radio`, `!m ra` | Queues a direct radio stream from a link. -`!m lo` | Queues a local file by specifying a full path. BOT OWNER ONLY. +`!m lo` | Queues a local file by specifying a full path. **Owner Only!** `!m mv` | Moves the bot to your voice channel. (works only if music is already playing) `!m rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. -`!m cleanup` | Cleans up hanging voice connections. BOT OWNER ONLY +`!m cleanup` | Cleans up hanging voice connections. **Owner Only!** ### Searches Command and aliases | Description | Usage @@ -223,6 +227,7 @@ Command and aliases | Description | Usage `~we` | Shows weather data for a specified city and a country BOTH ARE REQUIRED. Weather api is very random if you make a mistake. `~yt` | Searches youtubes and shows the first result `~ani`, `~anime`, `~aq` | Queries anilist for an anime and shows the first result. +`~imdb` | Queries imdb for movies or series, show first result. `~mang`, `~manga`, `~mq` | Queries anilist for a manga and shows the first result. `~randomcat` | Shows a random cat image. `~i` | Pulls the first image found using a search parameter. Use ~ir for different results. | ~i cute kitten @@ -234,6 +239,12 @@ Command and aliases | Description | Usage `~#` | Searches Tagdef.com for a hashtag. | ~# ff `~quote` | Shows a random quote. +### Translator +Command and aliases | Description | Usage +----------------|--------------|------- +`~trans` | Translates from>to text. From the given language to the destiation language. +`~translangs` | List the valid languages for translation. + ### NSFW Command and aliases | Description | Usage ----------------|--------------|------- From 5be9da55bcb48162df5225c89bb54e17d700d768 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 28 Mar 2016 03:40:52 +0200 Subject: [PATCH 2/4] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fd54c070..6421239a 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ In your bin/debug folder (or next to your exe if you are using release version), When you clone the project, make sure to run `git submodule init` and `git submodule update` to get the correct discord.net version +**Nothing was buffered music error?** make sure to follow the guide on google api key and ffmpeg [here](https://www.youtube.com/watch?v=x7v02MXNLeI) + **This is how the credentials.json should look like:** ```json { From 6ee896d6918b14da377af252e1451dd2c9665f01 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 28 Mar 2016 03:41:44 +0200 Subject: [PATCH 3/4] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6421239a..9ca36608 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,6 @@ In your bin/debug folder (or next to your exe if you are using release version), When you clone the project, make sure to run `git submodule init` and `git submodule update` to get the correct discord.net version -**Nothing was buffered music error?** make sure to follow the guide on google api key and ffmpeg [here](https://www.youtube.com/watch?v=x7v02MXNLeI) - **This is how the credentials.json should look like:** ```json { @@ -58,6 +56,8 @@ Next to your exe you must also have a data folder in which there is config.json - For Mashape Api Key you need to create an account on their api marketplace here https://market.mashape.com/. After that you need to go to market.mashape.com/YOURNAMEHERE/applications/default-application and press GET THE KEYS in the right top corner copy paste it into your credentials.json and you are ready to race! - If you want to have music, you need to download FFMPEG from this link http://ffmpeg.zeranoe.com/builds/ (static build version) and add ffmpeg/bin folder to your PATH environment variable. You do that by opening explorer -> right click 'This PC' -> properties -> advanced system settings -> In the top part, there is a PATH field, add `;` to the end and then your ffmpeg install location /bin (for example ;C:\ffmpeg-5.6.7\bin) and save. Open command prompt and type ffmpeg to see if you added it correctly. If it says "command not found" then you made a mistake somewhere. There are a lot of guides on the internet on how to add stuff to your PATH, check them out if you are stuck. - **IF YOU HAVE BEEN USING THIS BOT BEFORE AND YOU HAVE DATA FROM PARSE THAT YOU WANT TO KEEP** you should export your parse data and extract it inside /data/parsedata in your bot's folder. Next time you start the bot, type `.parsetosql` and the bot will fill your local sqlite db with data from those .json files. + +**Nothing was buffered music error?** make sure to follow the guide on google api key and ffmpeg [here](https://www.youtube.com/watch?v=x7v02MXNLeI) Enjoy From d72c809ae499a50ab4d9850cdcface8e4d91f64e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 28 Mar 2016 04:36:59 +0200 Subject: [PATCH 4/4] Currency name and sign should be external now! --- NadekoBot/Classes/FlowersHandler.cs | 2 +- NadekoBot/Classes/JSONModels/Configuration.cs | 31 +- NadekoBot/Commands/LogCommand.cs | 132 ++++-- NadekoBot/Modules/Administration.cs | 430 ++++++++++++------ NadekoBot/Modules/Gambling/GamblingModule.cs | 13 +- NadekoBot/Modules/Games.cs | 94 ++-- NadekoBot/Modules/Music.cs | 189 +++++--- NadekoBot/bin/Debug/data/config_example.json | 4 +- 8 files changed, 586 insertions(+), 309 deletions(-) diff --git a/NadekoBot/Classes/FlowersHandler.cs b/NadekoBot/Classes/FlowersHandler.cs index 3e9b7051..c40dd83e 100644 --- a/NadekoBot/Classes/FlowersHandler.cs +++ b/NadekoBot/Classes/FlowersHandler.cs @@ -20,7 +20,7 @@ namespace NadekoBot.Classes var flows = ""; for (var i = 0; i < amount; i++) { - flows += "🌸"; + flows += NadekoBot.Config.CurrencySign; } await u.SendMessage("👑Congratulations!👑\nYou received: " + flows); } diff --git a/NadekoBot/Classes/JSONModels/Configuration.cs b/NadekoBot/Classes/JSONModels/Configuration.cs index dcd8920f..296568b3 100644 --- a/NadekoBot/Classes/JSONModels/Configuration.cs +++ b/NadekoBot/Classes/JSONModels/Configuration.cs @@ -1,11 +1,12 @@ -using System; +using Discord; +using Newtonsoft.Json; using System.Collections.Generic; using System.IO; -using Discord; -using Newtonsoft.Json; -namespace NadekoBot.Classes.JSONModels { - public class Configuration { +namespace NadekoBot.Classes.JSONModels +{ + public class Configuration + { public bool DontJoinServers { get; set; } = false; public bool ForwardMessages { get; set; } = true; public bool IsRotatingStatus { get; set; } = false; @@ -49,7 +50,7 @@ namespace NadekoBot.Classes.JSONModels { "NO - It may cause disease contraction" }; - public string[] DisguiseResponses { get; set; } = { + public string[] DisguiseResponses { get; set; } = { "https://cdn.discordapp.com/attachments/140007341880901632/156721710458994690/Cc5mixjUYAADgBs.jpg", "https://cdn.discordapp.com/attachments/140007341880901632/156721715831898113/hqdefault.jpg", "https://cdn.discordapp.com/attachments/140007341880901632/156721724430352385/okawari_01_haruka_weird_mask.jpg", @@ -74,9 +75,13 @@ namespace NadekoBot.Classes.JSONModels { "http://gallery1.anivide.com/_full/65030_1382582341.gif", "https://49.media.tumblr.com/8e8a099c4eba22abd3ec0f70fd087cce/tumblr_nxovj9oY861ur1mffo1_500.gif ", }; + + public string CurrencySign { get; set; } = "🌸"; + public string CurrencyName { get; set; } = "NadekoFlower"; } - public class CommandPrefixesModel { + public class CommandPrefixesModel + { public string Administration { get; set; } = "."; public string Searches { get; set; } = "~"; public string NSFW { get; set; } = "~"; @@ -91,10 +96,13 @@ namespace NadekoBot.Classes.JSONModels { public string Programming { get; set; } = "%"; } - public static class ConfigHandler { + public static class ConfigHandler + { private static readonly object configLock = new object(); - public static void SaveConfig() { - lock (configLock) { + public static void SaveConfig() + { + lock (configLock) + { File.WriteAllText("data/config.json", JsonConvert.SerializeObject(NadekoBot.Config, Formatting.Indented)); } } @@ -110,7 +118,8 @@ namespace NadekoBot.Classes.JSONModels { public static bool IsUserBlacklisted(ulong id) => NadekoBot.Config.UserBlacklist.Contains(id); } - public class Quote { + public class Quote + { public string Author { get; set; } public string Text { get; set; } diff --git a/NadekoBot/Commands/LogCommand.cs b/NadekoBot/Commands/LogCommand.cs index d589f564..3b5783ea 100644 --- a/NadekoBot/Commands/LogCommand.cs +++ b/NadekoBot/Commands/LogCommand.cs @@ -1,23 +1,24 @@ -using System; -using System.Collections.Concurrent; -using System.Linq; -using System.Threading; -using System.Timers; -using System.Threading.Tasks; +using Discord; using Discord.Commands; -using Discord; using NadekoBot.Classes; using NadekoBot.Classes.Permissions; using NadekoBot.Modules; +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Threading.Tasks; -namespace NadekoBot.Commands { - internal class LogCommand : DiscordCommand { +namespace NadekoBot.Commands +{ + internal class LogCommand : DiscordCommand + { private readonly ConcurrentDictionary logs = new ConcurrentDictionary(); private readonly ConcurrentDictionary loggingPresences = new ConcurrentDictionary(); private readonly ConcurrentDictionary voiceChannelLog = new ConcurrentDictionary(); - public LogCommand(DiscordModule module) : base(module) { + public LogCommand(DiscordModule module) : base(module) + { NadekoBot.Client.MessageReceived += MsgRecivd; NadekoBot.Client.MessageDeleted += MsgDltd; NadekoBot.Client.MessageUpdated += MsgUpdtd; @@ -25,11 +26,13 @@ namespace NadekoBot.Commands { NadekoBot.Client.UserBanned += UsrBanned; - NadekoBot.Client.MessageReceived += async (s, e) => { + NadekoBot.Client.MessageReceived += async (s, e) => + { if (e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id) return; if (!SpecificConfigurations.Default.Of(e.Server.Id).SendPrivateMessageOnMention) return; - try { + try + { var usr = e.Message.MentionedUsers.FirstOrDefault(u => u != e.User); if (usr?.Status != UserStatus.Offline) return; @@ -38,22 +41,28 @@ namespace NadekoBot.Commands { $"User `{e.User.Name}` mentioned you on " + $"`{e.Server.Name}` server while you were offline.\n" + $"`Message:` {e.Message.Text}"); - } catch { } + } + catch { } }; } - private async void UsrBanned(object sender, UserEventArgs e) { - try { + private async void UsrBanned(object sender, UserEventArgs e) + { + try + { Channel ch; if (!logs.TryGetValue(e.Server, out ch)) return; await ch.SendMessage($"`User banned:` **{e.User.Name}** ({e.User.Id})"); - } catch { } + } + catch { } } - public Func DoFunc() => async e => { + public Func DoFunc() => async e => + { Channel ch; - if (!logs.TryRemove(e.Server, out ch)) { + if (!logs.TryRemove(e.Server, out ch)) + { logs.TryAdd(e.Server, e.Channel); await e.Channel.SendMessage($"**I WILL BEGIN LOGGING SERVER ACTIVITY IN THIS CHANNEL**"); return; @@ -62,57 +71,75 @@ namespace NadekoBot.Commands { await e.Channel.SendMessage($"**NO LONGER LOGGING IN {ch.Mention} CHANNEL**"); }; - private async void MsgRecivd(object sender, MessageEventArgs e) { - try { + private async void MsgRecivd(object sender, MessageEventArgs e) + { + try + { if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id) return; Channel ch; if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch) return; await ch.SendMessage($"`Type:` **Message received** `Time:` **{DateTime.Now}** `Channel:` **{e.Channel.Name}**\n`{e.User}:` {e.Message.Text}"); - } catch { } + } + catch { } } - private async void MsgDltd(object sender, MessageEventArgs e) { - try { + private async void MsgDltd(object sender, MessageEventArgs e) + { + try + { if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id) return; Channel ch; if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch) return; await ch.SendMessage($"`Type:` **Message deleted** `Time:` **{DateTime.Now}** `Channel:` **{e.Channel.Name}**\n`{e.User}:` {e.Message.Text}"); - } catch { } + } + catch { } } - private async void MsgUpdtd(object sender, MessageUpdatedEventArgs e) { - try { + private async void MsgUpdtd(object sender, MessageUpdatedEventArgs e) + { + try + { if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id) return; Channel ch; if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch) return; await ch.SendMessage($"`Type:` **Message updated** `Time:` **{DateTime.Now}** `Channel:` **{e.Channel.Name}**\n**BEFORE**: `{e.User}:` {e.Before.Text}\n---------------\n**AFTER**: `{e.User}:` {e.After.Text}"); - } catch { } + } + catch { } } - private async void UsrUpdtd(object sender, UserUpdatedEventArgs e) { - try { + private async void UsrUpdtd(object sender, UserUpdatedEventArgs e) + { + try + { Channel ch; if (loggingPresences.TryGetValue(e.Server, out ch)) - if (e.Before.Status != e.After.Status) { + if (e.Before.Status != e.After.Status) + { await ch.SendMessage($"**{e.Before.Name}** is now **{e.After.Status}**."); } - } catch { } + } + catch { } - try { - if (e.Before.VoiceChannel != null && voiceChannelLog.ContainsKey(e.Before.VoiceChannel)) { + try + { + if (e.Before.VoiceChannel != null && voiceChannelLog.ContainsKey(e.Before.VoiceChannel)) + { if (e.After.VoiceChannel != e.Before.VoiceChannel) await voiceChannelLog[e.Before.VoiceChannel].SendMessage($"🎼`{e.Before.Name} has left the` {e.Before.VoiceChannel.Mention} `voice channel.`"); } - if (e.After.VoiceChannel != null && voiceChannelLog.ContainsKey(e.After.VoiceChannel)) { + if (e.After.VoiceChannel != null && voiceChannelLog.ContainsKey(e.After.VoiceChannel)) + { if (e.After.VoiceChannel != e.Before.VoiceChannel) await voiceChannelLog[e.After.VoiceChannel].SendMessage($"🎼`{e.After.Name} has joined the`{e.After.VoiceChannel.Mention} `voice channel.`"); } - } catch { } + } + catch { } - try { + try + { Channel ch; if (!logs.TryGetValue(e.Server, out ch)) return; @@ -126,15 +153,18 @@ namespace NadekoBot.Commands { else return; await ch.SendMessage(str); - } catch { } + } + catch { } } - internal override void Init(CommandGroupBuilder cgb) { + internal override void Init(CommandGroupBuilder cgb) + { cgb.CreateCommand(Module.Prefix + "spmom") .Description("Toggles whether mentions of other offline users on your server will send a pm to them.") .AddCheck(SimpleCheckers.ManageServer()) - .Do(async e => { + .Do(async e => + { var specificConfig = SpecificConfigurations.Default.Of(e.Server.Id); specificConfig.SendPrivateMessageOnMention = !specificConfig.SendPrivateMessageOnMention; @@ -156,9 +186,11 @@ namespace NadekoBot.Commands { .Description("Starts logging to this channel when someone from the server goes online/offline/idle. **Owner Only!**") .AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.ManageServer()) - .Do(async e => { + .Do(async e => + { Channel ch; - if (!loggingPresences.TryRemove(e.Server, out ch)) { + if (!loggingPresences.TryRemove(e.Server, out ch)) + { loggingPresences.TryAdd(e.Server, e.Channel); await e.Channel.SendMessage($"**User presence notifications enabled.**"); return; @@ -172,25 +204,31 @@ namespace NadekoBot.Commands { .Parameter("all", ParameterType.Optional) .AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.ManageServer()) - .Do(async e => { + .Do(async e => + { - if (e.GetArg("all")?.ToLower() == "all") { - foreach (var voiceChannel in e.Server.VoiceChannels) { + if (e.GetArg("all")?.ToLower() == "all") + { + foreach (var voiceChannel in e.Server.VoiceChannels) + { voiceChannelLog.TryAdd(voiceChannel, e.Channel); } await e.Channel.SendMessage("Started logging user presence for **ALL** voice channels!"); return; } - if (e.User.VoiceChannel == null) { + if (e.User.VoiceChannel == null) + { await e.Channel.SendMessage("💢 You are not in a voice channel right now. If you are, please rejoin it."); return; } Channel throwaway; - if (!voiceChannelLog.TryRemove(e.User.VoiceChannel, out throwaway)) { + if (!voiceChannelLog.TryRemove(e.User.VoiceChannel, out throwaway)) + { voiceChannelLog.TryAdd(e.User.VoiceChannel, e.Channel); await e.Channel.SendMessage($"`Logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`"); - } else + } + else await e.Channel.SendMessage($"`Stopped logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`"); }); } diff --git a/NadekoBot/Modules/Administration.cs b/NadekoBot/Modules/Administration.cs index b2ca41c9..80b5c0d2 100644 --- a/NadekoBot/Modules/Administration.cs +++ b/NadekoBot/Modules/Administration.cs @@ -1,21 +1,23 @@ -using Discord.Modules; -using Discord.Commands; using Discord; -using System; -using System.Collections.Generic; -using System.Linq; -using NadekoBot.Extensions; -using System.Threading.Tasks; -using NadekoBot.Commands; -using System.IO; -using Newtonsoft.Json.Linq; +using Discord.Commands; +using Discord.Modules; using NadekoBot.Classes; -using NadekoBot.Classes.Permissions; using NadekoBot.Classes._DataModels; +using NadekoBot.Classes.Permissions; +using NadekoBot.Commands; +using NadekoBot.Extensions; +using Newtonsoft.Json.Linq; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; -namespace NadekoBot.Modules { - internal class Administration : DiscordModule { - public Administration() { +namespace NadekoBot.Modules +{ + internal class Administration : DiscordModule + { + public Administration() + { commands.Add(new ServerGreetCommand(this)); commands.Add(new LogCommand(this)); commands.Add(new MessageRepeater(this)); @@ -28,8 +30,10 @@ namespace NadekoBot.Modules { public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Administration; - public override void Install(ModuleManager manager) { - manager.CreateCommands("", cgb => { + public override void Install(ModuleManager manager) + { + manager.CreateCommands("", cgb => + { cgb.AddCheck(PermissionChecker.Instance); @@ -42,32 +46,39 @@ namespace NadekoBot.Modules { .Parameter("user_name", ParameterType.Required) .Parameter("role_name", ParameterType.Unparsed) .AddCheck(SimpleCheckers.CanManageRoles) - .Do(async e => { + .Do(async e => + { var userName = e.GetArg("user_name"); var roleName = e.GetArg("role_name"); if (string.IsNullOrWhiteSpace(roleName)) return; - if (!e.User.ServerPermissions.ManageRoles) { + if (!e.User.ServerPermissions.ManageRoles) + { await e.Channel.SendMessage("You have insufficient permissions."); } var usr = e.Server.FindUsers(userName).FirstOrDefault(); - if (usr == null) { + if (usr == null) + { await e.Channel.SendMessage("You failed to supply a valid username"); return; } var role = e.Server.FindRoles(roleName).FirstOrDefault(); - if (role == null) { + if (role == null) + { await e.Channel.SendMessage("You failed to supply a valid role"); return; } - try { + try + { await usr.AddRoles(role); await e.Channel.SendMessage($"Successfully added role **{role.Name}** to user **{usr.Name}**"); - } catch (Exception ex) { + } + catch (Exception ex) + { await e.Channel.SendMessage("Failed to add roles. Bot has insufficient permissions.\n"); Console.WriteLine(ex.ToString()); } @@ -78,28 +89,34 @@ namespace NadekoBot.Modules { .Parameter("user_name", ParameterType.Required) .Parameter("role_name", ParameterType.Unparsed) .AddCheck(SimpleCheckers.CanManageRoles) - .Do(async e => { + .Do(async e => + { var userName = e.GetArg("user_name"); var roleName = e.GetArg("role_name"); if (string.IsNullOrWhiteSpace(roleName)) return; var usr = e.Server.FindUsers(userName).FirstOrDefault(); - if (usr == null) { + if (usr == null) + { await e.Channel.SendMessage("You failed to supply a valid username"); return; } var role = e.Server.FindRoles(roleName).FirstOrDefault(); - if (role == null) { + if (role == null) + { await e.Channel.SendMessage("You failed to supply a valid role"); return; } - try { + try + { await usr.RemoveRoles(role); await e.Channel.SendMessage($"Successfully removed role **{role.Name}** from user **{usr.Name}**"); - } catch { + } + catch + { await e.Channel.SendMessage("Failed to remove roles. Most likely reason: Insufficient permissions."); } }); @@ -108,13 +125,17 @@ namespace NadekoBot.Modules { .Description("Creates a role with a given name.**Usage**: .r Awesome Role") .Parameter("role_name", ParameterType.Unparsed) .AddCheck(SimpleCheckers.CanManageRoles) - .Do(async e => { + .Do(async e => + { if (string.IsNullOrWhiteSpace(e.GetArg("role_name"))) return; - try { + try + { var r = await e.Server.CreateRole(e.GetArg("role_name")); await e.Channel.SendMessage($"Successfully created role **{r.Name}**."); - } catch (Exception) { + } + catch (Exception) + { await e.Channel.SendMessage(":warning: Unspecified error."); } }); @@ -125,26 +146,31 @@ namespace NadekoBot.Modules { .Parameter("g", ParameterType.Optional) .Parameter("b", ParameterType.Optional) .Description("Set a role's color to the hex or 0-255 rgb color value provided.\n**Usage**: .color Admin 255 200 100 or .color Admin ffba55") - .Do(async e => { - if (!e.User.ServerPermissions.ManageRoles) { + .Do(async e => + { + if (!e.User.ServerPermissions.ManageRoles) + { await e.Channel.SendMessage("You don't have permission to use this!"); return; } var args = e.Args.Where(s => s != string.Empty); - if (args.Count() != 2 && args.Count() != 4) { + if (args.Count() != 2 && args.Count() != 4) + { await e.Channel.SendMessage("The parameters are invalid."); return; } var role = e.Server.FindRoles(e.Args[0]).FirstOrDefault(); - if (role == null) { + if (role == null) + { await e.Channel.SendMessage("That role does not exist."); return; } - try { + try + { var rgb = args.Count() == 4; var red = Convert.ToByte(rgb ? int.Parse(e.Args[1]) : Convert.ToInt32(e.Args[1].Substring(0, 2), 16)); @@ -153,7 +179,9 @@ namespace NadekoBot.Modules { await role.Edit(color: new Color(red, green, blue)); await e.Channel.SendMessage($"Role {role.Name}'s color has been changed."); - } catch (Exception ex) { + } + catch (Exception ex) + { await e.Channel.SendMessage("Error occured, most likely invalid parameters or insufficient permissions."); } }); @@ -161,8 +189,10 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "roles") .Description("List all roles on this server or a single user if specified.") .Parameter("user", ParameterType.Unparsed) - .Do(async e => { - if (!string.IsNullOrWhiteSpace(e.GetArg("user"))) { + .Do(async e => + { + if (!string.IsNullOrWhiteSpace(e.GetArg("user"))) + { var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault(); if (usr == null) return; @@ -176,24 +206,31 @@ namespace NadekoBot.Modules { .Parameter("user", ParameterType.Required) .Parameter("msg", ParameterType.Optional) .Description("Bans a user by id or name with an optional message.\n**Usage**: .b \"@some Guy\" Your behaviour is toxic.") - .Do(async e => { + .Do(async e => + { var msg = e.GetArg("msg"); var user = e.GetArg("user"); - if (e.User.ServerPermissions.BanMembers) { + if (e.User.ServerPermissions.BanMembers) + { var usr = e.Server.FindUsers(user).FirstOrDefault(); - if (usr == null) { + if (usr == null) + { await e.Channel.SendMessage("User not found."); return; } - if (!string.IsNullOrWhiteSpace(msg)) { + if (!string.IsNullOrWhiteSpace(msg)) + { await usr.SendMessage($"**You have been BANNED from `{e.Server.Name}` server.**\n" + $"Reason: {msg}"); await Task.Delay(2000); // temp solution; give time for a message to be send, fu volt } - try { + try + { await e.Server.Ban(usr); await e.Channel.SendMessage("Banned user " + usr.Name + " Id: " + usr.Id); - } catch { + } + catch + { await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions."); } } @@ -203,24 +240,31 @@ namespace NadekoBot.Modules { .Parameter("user") .Parameter("msg", ParameterType.Unparsed) .Description("Kicks a mentioned user.") - .Do(async e => { + .Do(async e => + { var msg = e.GetArg("msg"); var user = e.GetArg("user"); - if (e.User.ServerPermissions.KickMembers) { + if (e.User.ServerPermissions.KickMembers) + { var usr = e.Server.FindUsers(user).FirstOrDefault(); - if (usr == null) { + if (usr == null) + { await e.Channel.SendMessage("User not found."); return; } - if (!string.IsNullOrWhiteSpace(msg)) { + if (!string.IsNullOrWhiteSpace(msg)) + { await usr.SendMessage($"**You have been KICKED from `{e.Server.Name}` server.**\n" + $"Reason: {msg}"); await Task.Delay(2000); // temp solution; give time for a message to be send, fu volt } - try { + try + { await usr.Kick(); await e.Channel.SendMessage("Kicked user " + usr.Name + " Id: " + usr.Id); - } catch { + } + catch + { await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions."); } } @@ -228,19 +272,25 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "mute") .Description("Mutes mentioned user or users.") .Parameter("throwaway", ParameterType.Unparsed) - .Do(async e => { - if (!e.User.ServerPermissions.MuteMembers) { + .Do(async e => + { + if (!e.User.ServerPermissions.MuteMembers) + { await e.Channel.SendMessage("You do not have permission to do that."); return; } if (!e.Message.MentionedUsers.Any()) return; - try { - foreach (var u in e.Message.MentionedUsers) { + try + { + foreach (var u in e.Message.MentionedUsers) + { await u.Edit(isMuted: true); } await e.Channel.SendMessage("Mute successful"); - } catch { + } + catch + { await e.Channel.SendMessage("I do not have permission to do that most likely."); } }); @@ -248,19 +298,25 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "unmute") .Description("Unmutes mentioned user or users.") .Parameter("throwaway", ParameterType.Unparsed) - .Do(async e => { - if (!e.User.ServerPermissions.MuteMembers) { + .Do(async e => + { + if (!e.User.ServerPermissions.MuteMembers) + { await e.Channel.SendMessage("You do not have permission to do that."); return; } if (!e.Message.MentionedUsers.Any()) return; - try { - foreach (var u in e.Message.MentionedUsers) { + try + { + foreach (var u in e.Message.MentionedUsers) + { await u.Edit(isMuted: false); } await e.Channel.SendMessage("Unmute successful"); - } catch { + } + catch + { await e.Channel.SendMessage("I do not have permission to do that most likely."); } }); @@ -269,19 +325,25 @@ namespace NadekoBot.Modules { .Alias(Prefix + "deaf") .Description("Deafens mentioned user or users") .Parameter("throwaway", ParameterType.Unparsed) - .Do(async e => { - if (!e.User.ServerPermissions.DeafenMembers) { + .Do(async e => + { + if (!e.User.ServerPermissions.DeafenMembers) + { await e.Channel.SendMessage("You do not have permission to do that."); return; } if (!e.Message.MentionedUsers.Any()) return; - try { - foreach (var u in e.Message.MentionedUsers) { + try + { + foreach (var u in e.Message.MentionedUsers) + { await u.Edit(isDeafened: true); } await e.Channel.SendMessage("Deafen successful"); - } catch { + } + catch + { await e.Channel.SendMessage("I do not have permission to do that most likely."); } }); @@ -290,19 +352,25 @@ namespace NadekoBot.Modules { .Alias(Prefix + "undeaf") .Description("Undeafens mentioned user or users") .Parameter("throwaway", ParameterType.Unparsed) - .Do(async e => { - if (!e.User.ServerPermissions.DeafenMembers) { + .Do(async e => + { + if (!e.User.ServerPermissions.DeafenMembers) + { await e.Channel.SendMessage("You do not have permission to do that."); return; } if (!e.Message.MentionedUsers.Any()) return; - try { - foreach (var u in e.Message.MentionedUsers) { + try + { + foreach (var u in e.Message.MentionedUsers) + { await u.Edit(isDeafened: false); } await e.Channel.SendMessage("Undeafen successful"); - } catch { + } + catch + { await e.Channel.SendMessage("I do not have permission to do that most likely."); } }); @@ -310,13 +378,18 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "rvch") .Description("Removes a voice channel with a given name.") .Parameter("channel_name", ParameterType.Required) - .Do(async e => { - try { - if (e.User.ServerPermissions.ManageChannels) { + .Do(async e => + { + try + { + if (e.User.ServerPermissions.ManageChannels) + { await e.Server.FindChannels(e.GetArg("channel_name"), ChannelType.Voice).FirstOrDefault()?.Delete(); await e.Channel.SendMessage($"Removed channel **{e.GetArg("channel_name")}**."); } - } catch { + } + catch + { await e.Channel.SendMessage("Insufficient permissions."); } }); @@ -324,13 +397,18 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "vch").Alias(Prefix + "cvch") .Description("Creates a new voice channel with a given name.") .Parameter("channel_name", ParameterType.Required) - .Do(async e => { - try { - if (e.User.ServerPermissions.ManageChannels) { + .Do(async e => + { + try + { + if (e.User.ServerPermissions.ManageChannels) + { await e.Server.CreateChannel(e.GetArg("channel_name"), ChannelType.Voice); await e.Channel.SendMessage($"Created voice channel **{e.GetArg("channel_name")}**."); } - } catch { + } + catch + { await e.Channel.SendMessage("Insufficient permissions."); } }); @@ -338,15 +416,20 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "rch").Alias(Prefix + "rtch") .Description("Removes a text channel with a given name.") .Parameter("channel_name", ParameterType.Required) - .Do(async e => { - try { - if (e.User.ServerPermissions.ManageChannels) { + .Do(async e => + { + try + { + if (e.User.ServerPermissions.ManageChannels) + { var channel = e.Server.FindChannels(e.GetArg("channel_name"), ChannelType.Text).FirstOrDefault(); if (channel == null) return; await channel.Delete(); await e.Channel.SendMessage($"Removed text channel **{e.GetArg("channel_name")}**."); } - } catch { + } + catch + { await e.Channel.SendMessage("Insufficient permissions."); } }); @@ -354,31 +437,40 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "ch").Alias(Prefix + "tch") .Description("Creates a new text channel with a given name.") .Parameter("channel_name", ParameterType.Required) - .Do(async e => { - try { - if (e.User.ServerPermissions.ManageChannels) { + .Do(async e => + { + try + { + if (e.User.ServerPermissions.ManageChannels) + { await e.Server.CreateChannel(e.GetArg("channel_name"), ChannelType.Text); await e.Channel.SendMessage($"Added text channel **{e.GetArg("channel_name")}**."); } - } catch { + } + catch + { await e.Channel.SendMessage("Insufficient permissions."); } }); cgb.CreateCommand(Prefix + "st").Alias(Prefix + "settopic") + .Alias(Prefix + "topic") .Description("Sets a topic on the current channel.") .Parameter("topic", ParameterType.Unparsed) - .Do(async e => { - try { - if (e.User.ServerPermissions.ManageChannels) - await e.Channel.Edit(topic: e.GetArg("topic")); - } catch { } + .Do(async e => + { + var topic = e.GetArg("topic"); + if (string.IsNullOrWhiteSpace(topic)) + return; + await e.Channel.Edit(topic: topic); + await e.Channel.SendMessage(":ok: **New channel topic set.**"); }); cgb.CreateCommand(Prefix + "uid").Alias(Prefix + "userid") .Description("Shows user ID.") .Parameter("user", ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { var usr = e.User; if (!string.IsNullOrWhiteSpace(e.GetArg("user"))) usr = e.Channel.FindUsers(e.GetArg("user")).FirstOrDefault(); if (usr == null) @@ -396,33 +488,38 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "stats") .Description("Shows some basic stats for Nadeko.") - .Do(async e => { + .Do(async e => + { await e.Channel.SendMessage(await NadekoStats.Instance.GetStats()); }); cgb.CreateCommand(Prefix + "dysyd") .Description("Shows some basic stats for Nadeko.") - .Do(async e => { + .Do(async e => + { await e.Channel.SendMessage((await NadekoStats.Instance.GetStats()).Matrix().TrimTo(1990)); }); cgb.CreateCommand(Prefix + "heap") .Description("Shows allocated memory - **Owner Only!**") .AddCheck(SimpleCheckers.OwnerOnly()) - .Do(async e => { + .Do(async e => + { var heap = await Task.Run(() => NadekoStats.Instance.Heap()); await e.Channel.SendMessage($"`Heap Size:` {heap}"); }); cgb.CreateCommand(Prefix + "prune") .Parameter("num", ParameterType.Required) .Description("Prunes a number of messages from the current channel.\n**Usage**: .prune 5") - .Do(async e => { + .Do(async e => + { if (!e.User.ServerPermissions.ManageMessages) return; int val; if (string.IsNullOrWhiteSpace(e.GetArg("num")) || !int.TryParse(e.GetArg("num"), out val) || val < 0) return; - foreach (var msg in await e.Channel.DownloadMessages(val)) { + foreach (var msg in await e.Channel.DownloadMessages(val)) + { await msg.Delete(); await Task.Delay(100); } @@ -431,8 +528,10 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "die") .Alias(Prefix + "graceful") .Description("Shuts the bot down and notifies users about the restart. **Owner Only!**") - .Do(async e => { - if (NadekoBot.IsOwner(e.User.Id)) { + .Do(async e => + { + if (NadekoBot.IsOwner(e.User.Id)) + { await e.Channel.SendMessage("`Shutting down.`"); await Task.Delay(2000); Environment.Exit(0); @@ -442,19 +541,25 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "clr") .Description("Clears some of Nadeko's messages from the current channel. If given a user, will clear the user's messages from the current channel (**Owner Only!**) \n**Usage**: .clr @X") .Parameter("user", ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { var usrId = NadekoBot.Client.CurrentUser.Id; - if (!string.IsNullOrWhiteSpace(e.GetArg("user")) && e.User.ServerPermissions.ManageMessages) { + if (!string.IsNullOrWhiteSpace(e.GetArg("user")) && e.User.ServerPermissions.ManageMessages) + { var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault(); if (usr != null) usrId = usr.Id; } - await Task.Run(async () => { + await Task.Run(async () => + { var msgs = (await e.Channel.DownloadMessages(100)).Where(m => m.User.Id == usrId); - foreach (var m in msgs) { - try { + foreach (var m in msgs) + { + try + { await m.Delete(); - } catch { } + } + catch { } await Task.Delay(200); } @@ -465,7 +570,8 @@ namespace NadekoBot.Modules { .Alias(Prefix + "setname") .Description("Give the bot a new name. **Owner Only!**") .Parameter("new_name", ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { if (!NadekoBot.IsOwner(e.User.Id) || e.GetArg("new_name") == null) return; await client.CurrentUser.Edit(NadekoBot.Creds.Password, e.GetArg("new_name")); @@ -475,7 +581,8 @@ namespace NadekoBot.Modules { .Alias(Prefix + "setavatar") .Description("Sets a new avatar image for the NadekoBot. **Owner Only!**") .Parameter("img", ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { if (!NadekoBot.IsOwner(e.User.Id) || string.IsNullOrWhiteSpace(e.GetArg("img"))) return; // Gather user provided URL. @@ -492,7 +599,8 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "setgame") .Description("Sets the bots game. **Owner Only!**") .Parameter("set_game", ParameterType.Unparsed) - .Do(e => { + .Do(e => + { if (!NadekoBot.IsOwner(e.User.Id) || e.GetArg("set_game") == null) return; client.SetGame(e.GetArg("set_game")); @@ -500,9 +608,11 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "checkmyperms") .Description("Checks your userspecific permissions on this channel.") - .Do(async e => { + .Do(async e => + { var output = "```\n"; - foreach (var p in e.User.ServerPermissions.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any())) { + foreach (var p in e.User.ServerPermissions.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any())) + { output += p.Name + ": " + p.GetValue(e.User.ServerPermissions, null).ToString() + "\n"; } output += "```"; @@ -516,20 +626,24 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "commsuser") .Description("Sets a user for through-bot communication. Only works if server is set. Resets commschannel. **Owner Only!**") .Parameter("name", ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { if (!NadekoBot.IsOwner(e.User.Id)) return; commsUser = commsServer?.FindUsers(e.GetArg("name")).FirstOrDefault(); - if (commsUser != null) { + if (commsUser != null) + { commsChannel = null; await e.Channel.SendMessage("User for comms set."); - } else + } + else await e.Channel.SendMessage("No server specified or user."); }); cgb.CreateCommand(Prefix + "commsserver") .Description("Sets a server for through-bot communication. **Owner Only!**") .Parameter("server", ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { if (!NadekoBot.IsOwner(e.User.Id)) return; commsServer = client.FindServers(e.GetArg("server")).FirstOrDefault(); if (commsServer != null) @@ -541,20 +655,24 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "commschannel") .Description("Sets a channel for through-bot communication. Only works if server is set. Resets commsuser. **Owner Only!**") .Parameter("ch", ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { if (!NadekoBot.IsOwner(e.User.Id)) return; commsChannel = commsServer?.FindChannels(e.GetArg("ch"), ChannelType.Text).FirstOrDefault(); - if (commsChannel != null) { + if (commsChannel != null) + { commsUser = null; await e.Channel.SendMessage("Server for comms set."); - } else + } + else await e.Channel.SendMessage("No server specified or channel is invalid."); }); cgb.CreateCommand(Prefix + "send") .Description("Send a message to someone on a different server through the bot. **Owner Only!**\n **Usage**: .send Message text multi word!") .Parameter("msg", ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { if (!NadekoBot.IsOwner(e.User.Id)) return; if (commsUser != null) await commsUser.SendMessage(e.GetArg("msg")); @@ -568,19 +686,23 @@ namespace NadekoBot.Modules { .Alias(Prefix + "mentionrole") .Description("Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission.") .Parameter("roles", ParameterType.Unparsed) - .Do(async e => { - await Task.Run(async () => { + .Do(async e => + { + await Task.Run(async () => + { if (!e.User.ServerPermissions.MentionEveryone) return; var arg = e.GetArg("roles").Split(',').Select(r => r.Trim()); string send = $"--{e.User.Mention} has invoked a mention on the following roles--"; - foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str))) { + foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str))) + { var role = e.Server.FindRoles(roleStr).FirstOrDefault(); if (role == null) continue; send += $"\n`{role.Name}`\n"; send += string.Join(", ", role.Members.Select(r => r.Mention)); } - while (send.Length > 2000) { + while (send.Length > 2000) + { var curstr = send.Substring(0, 2000); await e.Channel.Send(curstr.Substring(0, @@ -594,10 +716,12 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "parsetosql") .Description("Loads exported parsedata from /data/parsedata/ into sqlite database.") - .Do(async e => { + .Do(async e => + { if (!NadekoBot.IsOwner(e.User.Id)) return; - await Task.Run(() => { + await Task.Run(() => + { SaveParseToDb("data/parsedata/Announcements.json"); SaveParseToDb("data/parsedata/CommandsRan.json"); SaveParseToDb("data/parsedata/Requests.json"); @@ -609,14 +733,17 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "unstuck") .Description("Clears the message queue. **Owner Only!**") .AddCheck(SimpleCheckers.OwnerOnly()) - .Do(e => { + .Do(e => + { NadekoBot.Client.MessageQueue.Clear(); }); cgb.CreateCommand(Prefix + "donators") .Description("List of lovely people who donated to keep this project alive.") - .Do(async e => { - await Task.Run(async () => { + .Do(async e => + { + await Task.Run(async () => + { var rows = DbHandler.Instance.GetAllRows(); var donatorsOrdered = rows.OrderByDescending(d => d.Amount); string str = $"**Thanks to the people listed below for making this project happen!**\n"; @@ -632,64 +759,65 @@ namespace NadekoBot.Modules { .Parameter("donator") .Parameter("amount") .AddCheck(SimpleCheckers.OwnerOnly()) - .Do(async e => { - await Task.Run(() => { + .Do(async e => + { + await Task.Run(() => + { if (!NadekoBot.IsOwner(e.User.Id)) return; var donator = e.Server.FindUsers(e.GetArg("donator")).FirstOrDefault(); var amount = int.Parse(e.GetArg("amount")); if (donator == null) return; - try { - DbHandler.Instance.InsertData(new Donator { + try + { + DbHandler.Instance.InsertData(new Donator + { Amount = amount, UserName = donator.Name, UserId = (long)e.User.Id }); e.Channel.SendMessage("Successfuly added a new donator. 👑"); - } catch { } + } + catch { } }); }); - cgb.CreateCommand(Prefix + "topic") - .Description("Sets current channel's topic.") - .Parameter("topic", ParameterType.Unparsed) - .AddCheck(SimpleCheckers.ManageChannels()) - .Do(async e => { - var topic = e.GetArg("topic"); - if (string.IsNullOrWhiteSpace(topic)) - return; - await e.Channel.Edit(topic: topic); - await e.Channel.SendMessage(":ok: **New channel topic set.**"); - }); - cgb.CreateCommand(Prefix + "videocall") .Description("Creates a private appear.in video call link for you and other mentioned people. The link is sent to mentioned people via a private message.") .Parameter("arg", ParameterType.Unparsed) - .Do(async e => { - try { + .Do(async e => + { + try + { var allUsrs = e.Message.MentionedUsers.Union(new User[] { e.User }); var allUsrsArray = allUsrs as User[] ?? allUsrs.ToArray(); var str = allUsrsArray.Aggregate("http://appear.in/", (current, usr) => current + Uri.EscapeUriString(usr.Name[0].ToString())); str += new Random().Next(); - foreach (var usr in allUsrsArray) { + foreach (var usr in allUsrsArray) + { await usr.SendMessage(str); } - } catch (Exception ex) { + } + catch (Exception ex) + { Console.WriteLine(ex); } }); }); } - public void SaveParseToDb(string where) where T : IDataModel { - try { + public void SaveParseToDb(string where) where T : IDataModel + { + try + { var data = File.ReadAllText(where); var arr = JObject.Parse(data)["results"] as JArray; if (arr == null) return; var objects = arr.Select(x => x.ToObject()); DbHandler.Instance.InsertMany(objects); - } catch { } + } + catch { } } } } diff --git a/NadekoBot/Modules/Gambling/GamblingModule.cs b/NadekoBot/Modules/Gambling/GamblingModule.cs index 64a897e8..ee1661d3 100644 --- a/NadekoBot/Modules/Gambling/GamblingModule.cs +++ b/NadekoBot/Modules/Gambling/GamblingModule.cs @@ -34,15 +34,14 @@ namespace NadekoBot.Modules.Gambling .Parameter("role", ParameterType.Optional) .Do(RaffleFunc()); cgb.CreateCommand(Prefix + "$$") - .Description("Check how many NadekoFlowers you have.") + .Description(string.Format("Check how much {0}s you have.", NadekoBot.Config.CurrencyName)) .Do(NadekoFlowerCheckFunc()); cgb.CreateCommand(Prefix + "give") - .Description("Give someone a certain amount of flowers") + .Description(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName)) .Parameter("amount", ParameterType.Required) .Parameter("receiver", ParameterType.Unparsed) .Do(async e => { - var amountStr = e.GetArg("amount")?.Trim(); long amount; if (!long.TryParse(amountStr, out amount) || amount < 0) @@ -58,14 +57,14 @@ namespace NadekoBot.Modules.Gambling if (userFlowers < amount) { - await e.Channel.SendMessage($"{e.User.Mention} You don't have enough flowers. You have only {userFlowers}🌸."); + await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You have only {userFlowers}{NadekoBot.Config.CurrencySign}."); return; } await FlowersHandler.RemoveFlowersAsync(e.User, "Gift", (int)amount); await FlowersHandler.AddFlowersAsync(mentionedUser, "Gift", (int)amount); - await e.Channel.SendMessage($"{e.User.Mention} successfully sent {amount}🌸 to {mentionedUser.Mention}!"); + await e.Channel.SendMessage($"{e.User.Mention} successfully sent {amount} {NadekoBot.Config.CurrencyName}s to {mentionedUser.Mention}!"); }); }); @@ -76,10 +75,10 @@ namespace NadekoBot.Modules.Gambling return async e => { var pts = GetUserFlowers(e.User.Id); - var str = $"`You have {pts} NadekoFlowers".SnPl((int)pts) + "`\n"; + var str = $"`You have {pts} {NadekoBot.Config.CurrencyName}s".SnPl((int)pts) + "`\n"; for (var i = 0; i < pts; i++) { - str += "🌸"; + str += NadekoBot.Config.CurrencySign; } await e.Channel.SendMessage(str); }; diff --git a/NadekoBot/Modules/Games.cs b/NadekoBot/Modules/Games.cs index 3dd8d46f..32b6b4fd 100644 --- a/NadekoBot/Modules/Games.cs +++ b/NadekoBot/Modules/Games.cs @@ -1,17 +1,18 @@ -using System; -using System.Linq; +using Discord.Commands; using Discord.Modules; using NadekoBot.Commands; -using Newtonsoft.Json.Linq; -using System.IO; -using Discord.Commands; using NadekoBot.Extensions; +using System; +using System.Linq; -namespace NadekoBot.Modules { - internal class Games : DiscordModule { +namespace NadekoBot.Modules +{ + internal class Games : DiscordModule + { private readonly Random rng = new Random(); - public Games() { + public Games() + { commands.Add(new Trivia(this)); commands.Add(new SpeedTyping(this)); commands.Add(new PollCommand(this)); @@ -20,8 +21,10 @@ namespace NadekoBot.Modules { public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Games; - public override void Install(ModuleManager manager) { - manager.CreateCommands("", cgb => { + public override void Install(ModuleManager manager) + { + manager.CreateCommands("", cgb => + { cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance); @@ -30,7 +33,8 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "choose") .Description("Chooses a thing from a list of things\n**Usage**: >choose Get up;Sleep;Sleep more") .Parameter("list", Discord.Commands.ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { var arg = e.GetArg("list"); if (string.IsNullOrWhiteSpace(arg)) return; @@ -43,23 +47,28 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "8ball") .Description("Ask the 8ball a yes/no question.") .Parameter("question", Discord.Commands.ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { var question = e.GetArg("question"); if (string.IsNullOrWhiteSpace(question)) return; - try { + try + { await e.Channel.SendMessage( $":question: **Question**: `{question}` \n🎱 **8Ball Answers**: `{NadekoBot.Config._8BallResponses[rng.Next(0, NadekoBot.Config._8BallResponses.Length)]}`"); - } catch { } + } + catch { } }); cgb.CreateCommand(Prefix + "attack") .Description("Attack a person. Supported attacks: 'splash', 'strike', 'burn', 'surge'.\n**Usage**: >attack strike @User") .Parameter("attack_type", Discord.Commands.ParameterType.Required) .Parameter("target", Discord.Commands.ParameterType.Required) - .Do(async e => { + .Do(async e => + { var usr = e.Server.FindUsers(e.GetArg("target")).FirstOrDefault(); - if (usr == null) { + if (usr == null) + { await e.Channel.SendMessage("No such person."); return; } @@ -67,9 +76,12 @@ namespace NadekoBot.Modules { var response = ""; var dmg = GetDamage(usrType, e.GetArg("attack_type").ToLowerInvariant()); response = e.GetArg("attack_type") + (e.GetArg("attack_type") == "splash" ? "es " : "s ") + $"{usr.Mention}{GetImage(usrType)} for {dmg}\n"; - if (dmg >= 65) { + if (dmg >= 65) + { response += "It's super effective!"; - } else if (dmg <= 35) { + } + else if (dmg <= 35) + { response += "Ineffective!"; } await e.Channel.SendMessage($"{ e.User.Mention }{GetImage(GetType(e.User.Id))} {response}"); @@ -78,9 +90,11 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "poketype") .Parameter("target", Discord.Commands.ParameterType.Required) .Description("Gets the users element type. Use this to do more damage with strike!") - .Do(async e => { + .Do(async e => + { var usr = e.Server.FindUsers(e.GetArg("target")).FirstOrDefault(); - if (usr == null) { + if (usr == null) + { await e.Channel.SendMessage("No such person."); return; } @@ -90,10 +104,12 @@ namespace NadekoBot.Modules { cgb.CreateCommand(Prefix + "rps") .Description("Play a game of rocket paperclip scissors with nadkeo.\n**Usage**: >rps scissors") .Parameter("input", ParameterType.Required) - .Do(async e => { + .Do(async e => + { var input = e.GetArg("input").Trim(); int pick; - switch (input) { + switch (input) + { case "r": case "rock": case "rocket": @@ -129,7 +145,8 @@ namespace NadekoBot.Modules { .Description("Prints a customizable Linux interjection") .Parameter("gnu", ParameterType.Required) .Parameter("linux", ParameterType.Required) - .Do(async e => { + .Do(async e => + { var guhnoo = e.Args[0]; var loonix = e.Args[1]; @@ -157,8 +174,10 @@ There really is a {loonix}, and these people are using it, but it is just a part 🌟 or 💫 or ✨ Fairy */ - private string GetImage(PokeType t) { - switch (t) { + private string GetImage(PokeType t) + { + switch (t) + { case PokeType.WATER: return "💦"; case PokeType.GRASS: @@ -172,9 +191,11 @@ There really is a {loonix}, and these people are using it, but it is just a part } } - private int GetDamage(PokeType targetType, string v) { + private int GetDamage(PokeType targetType, string v) + { var rng = new Random(); - switch (v) { + switch (v) + { case "splash": //water if (targetType == PokeType.FIRE) return rng.Next(65, 100); @@ -210,27 +231,34 @@ There really is a {loonix}, and these people are using it, but it is just a part } } - private PokeType GetType(ulong id) { + private PokeType GetType(ulong id) + { if (id == 113760353979990024) return PokeType.FIRE; var remainder = id % 10; if (remainder < 3) return PokeType.WATER; - else if (remainder >= 3 && remainder < 5) { + else if (remainder >= 3 && remainder < 5) + { return PokeType.GRASS; - } else if (remainder >= 5 && remainder < 8) { + } + else if (remainder >= 5 && remainder < 8) + { return PokeType.FIRE; - } else { + } + else { return PokeType.ELECTRICAL; } } - private enum PokeType { + private enum PokeType + { WATER, GRASS, FIRE, ELECTRICAL } - private string GetRPSPick(int i) { + private string GetRPSPick(int i) + { if (i == 0) return "rocket"; else if (i == 1) diff --git a/NadekoBot/Modules/Music.cs b/NadekoBot/Modules/Music.cs index 6fa3806b..32c9f1c9 100644 --- a/NadekoBot/Modules/Music.cs +++ b/NadekoBot/Modules/Music.cs @@ -3,16 +3,18 @@ using Discord.Commands; using Discord.Modules; using NadekoBot.Classes; using NadekoBot.Classes.Music; +using NadekoBot.Classes.Permissions; using NadekoBot.Extensions; using System; using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; -using NadekoBot.Classes.Permissions; using Timer = System.Timers.Timer; -namespace NadekoBot.Modules { - internal class Music : DiscordModule { +namespace NadekoBot.Modules +{ + internal class Music : DiscordModule + { public static ConcurrentDictionary MusicPlayers = new ConcurrentDictionary(); public static ConcurrentDictionary DefaultMusicVolumes = new ConcurrentDictionary(); @@ -21,24 +23,46 @@ namespace NadekoBot.Modules { private bool setgameEnabled = false; - public Music() { + public Music() + { setgameTimer.Interval = 20000; - setgameTimer.Elapsed += (s, e) => { - try { + setgameTimer.Elapsed += (s, e) => + { + try + { var num = MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null); NadekoBot.Client.SetGame($"{num} songs".SnPl(num) + $", {MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count())} queued"); - } catch { } + } + catch { } }; + // ready for 1.0 + //NadekoBot.Client.UserUpdated += (s, e) => + //{ + // try + // { + // if (e.Before.VoiceChannel != e.After.VoiceChannel && + // e.Before.VoiceChannel.Members.Count() == 0) + // { + // MusicPlayer musicPlayer; + // if (!MusicPlayers.TryRemove(e.Server, out musicPlayer)) return; + // musicPlayer.Destroy(); + // } + // } + // catch { } + //}; + } public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Music; - public override void Install(ModuleManager manager) { + public override void Install(ModuleManager manager) + { var client = NadekoBot.Client; - manager.CreateCommands(Prefix, cgb => { + manager.CreateCommands(Prefix, cgb => + { cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance); @@ -47,7 +71,8 @@ namespace NadekoBot.Modules { cgb.CreateCommand("n") .Alias("next") .Description("Goes to the next song in the queue.") - .Do(e => { + .Do(e => + { MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; musicPlayer.Next(); @@ -56,8 +81,10 @@ namespace NadekoBot.Modules { cgb.CreateCommand("s") .Alias("stop") .Description("Stops the music and clears the playlist. Stays in the channel.") - .Do(async e => { - await Task.Run(() => { + .Do(async e => + { + await Task.Run(() => + { MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; musicPlayer.Stop(); @@ -67,8 +94,10 @@ namespace NadekoBot.Modules { cgb.CreateCommand("d") .Alias("destroy") .Description("Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour)") - .Do(async e => { - await Task.Run(() => { + .Do(async e => + { + await Task.Run(() => + { MusicPlayer musicPlayer; if (!MusicPlayers.TryRemove(e.Server, out musicPlayer)) return; musicPlayer.Destroy(); @@ -78,7 +107,8 @@ namespace NadekoBot.Modules { cgb.CreateCommand("p") .Alias("pause") .Description("Pauses or Unpauses the song.") - .Do(async e => { + .Do(async e => + { MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; musicPlayer.TogglePause(); @@ -92,16 +122,19 @@ namespace NadekoBot.Modules { .Alias("yq") .Description("Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**.\n**Usage**: `!m q Dream Of Venice`") .Parameter("query", ParameterType.Unparsed) - .Do(async e => { + .Do(async e => + { await QueueSong(e.Channel, e.User.VoiceChannel, e.GetArg("query")); }); cgb.CreateCommand("lq") .Alias("ls").Alias("lp") .Description("Lists up to 15 currently queued songs.") - .Do(async e => { + .Do(async e => + { MusicPlayer musicPlayer; - if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) { + if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) + { await e.Channel.SendMessage("🎵 No active music player."); return; } @@ -117,7 +150,8 @@ namespace NadekoBot.Modules { cgb.CreateCommand("np") .Alias("playing") .Description("Shows the song currently playing.") - .Do(async e => { + .Do(async e => + { MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; @@ -130,13 +164,15 @@ namespace NadekoBot.Modules { cgb.CreateCommand("vol") .Description("Sets the music volume 0-150%") .Parameter("val", ParameterType.Required) - .Do(async e => { + .Do(async e => + { MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; var arg = e.GetArg("val"); int volume; - if (!int.TryParse(arg, out volume)) { + if (!int.TryParse(arg, out volume)) + { await e.Channel.SendMessage("Volume number invalid."); return; } @@ -148,10 +184,12 @@ namespace NadekoBot.Modules { .Alias("defvol") .Description("Sets the default music volume when music playback is started (0-100). Does not persist through restarts.\n**Usage**: !m dv 80") .Parameter("val", ParameterType.Required) - .Do(async e => { + .Do(async e => + { var arg = e.GetArg("val"); float volume; - if (!float.TryParse(arg, out volume) || volume < 0 || volume > 100) { + if (!float.TryParse(arg, out volume) || volume < 0 || volume > 100) + { await e.Channel.SendMessage("Volume number invalid."); return; } @@ -161,7 +199,8 @@ namespace NadekoBot.Modules { cgb.CreateCommand("min").Alias("mute") .Description("Sets the music volume to 0%") - .Do(e => { + .Do(e => + { MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; @@ -170,7 +209,8 @@ namespace NadekoBot.Modules { cgb.CreateCommand("max") .Description("Sets the music volume to 100% (real max is actually 150%).") - .Do(e => { + .Do(e => + { MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; @@ -179,7 +219,8 @@ namespace NadekoBot.Modules { cgb.CreateCommand("half") .Description("Sets the music volume to 50%.") - .Do(e => { + .Do(e => + { MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; @@ -188,11 +229,13 @@ namespace NadekoBot.Modules { cgb.CreateCommand("sh") .Description("Shuffles the current playlist.") - .Do(async e => { + .Do(async e => + { MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; - if (musicPlayer.Playlist.Count < 2) { + if (musicPlayer.Playlist.Count < 2) + { await e.Channel.SendMessage("💢 Not enough songs in order to perform the shuffle."); return; } @@ -204,7 +247,8 @@ namespace NadekoBot.Modules { cgb.CreateCommand("setgame") .Description("Sets the game of the bot to the number of songs playing. **Owner only**") .AddCheck(SimpleCheckers.OwnerOnly()) - .Do(async e => { + .Do(async e => + { await e.Channel.SendMessage("❗This command is deprecated. " + "Use:\n `.ropl`\n `.adpl %playing% songs, %queued% queued.` instead.\n " + "It even persists through restarts."); @@ -213,8 +257,10 @@ namespace NadekoBot.Modules { cgb.CreateCommand("pl") .Description("Queues up to 25 songs from a youtube playlist specified by a link, or keywords.") .Parameter("playlist", ParameterType.Unparsed) - .Do(async e => { - if (e.User.VoiceChannel?.Server != e.Server) { + .Do(async e => + { + if (e.User.VoiceChannel?.Server != e.Server) + { await e.Channel.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it."); return; } @@ -224,10 +270,13 @@ namespace NadekoBot.Modules { var count = idArray.Count(); var msg = await e.Channel.SendMessage($"🎵 `Attempting to queue {count} songs".SnPl(count) + "...`"); - foreach (var id in idArray) { - try { + foreach (var id in idArray) + { + try + { await QueueSong(e.Channel, e.User.VoiceChannel, id, true); - } catch { } + } + catch { } } await msg.Edit("🎵 `Playlist queue complete.`"); }); @@ -236,24 +285,30 @@ namespace NadekoBot.Modules { .Description("Queues up to 50 songs from a directory. **Owner Only!**") .Parameter("directory", ParameterType.Unparsed) .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) - .Do(async e => { + .Do(async e => + { var arg = e.GetArg("directory"); if (string.IsNullOrWhiteSpace(e.GetArg("directory"))) return; - try { + try + { var fileEnum = System.IO.Directory.EnumerateFiles(e.GetArg("directory")).Take(50); - foreach (var file in fileEnum) { + foreach (var file in fileEnum) + { await QueueSong(e.Channel, e.User.VoiceChannel, file, true, MusicType.Local); } await e.Channel.SendMessage("🎵 `Directory queue complete.`"); - } catch { } + } + catch { } }); cgb.CreateCommand("radio").Alias("ra") .Description("Queues a direct radio stream from a link.") .Parameter("radio_link", ParameterType.Required) - .Do(async e => { - if (e.User.VoiceChannel?.Server != e.Server) { + .Do(async e => + { + if (e.User.VoiceChannel?.Server != e.Server) + { await e.Channel.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it."); return; } @@ -264,7 +319,8 @@ namespace NadekoBot.Modules { .Description("Queues a local file by specifying a full path. **Owner Only!**") .Parameter("path", ParameterType.Unparsed) .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) - .Do(async e => { + .Do(async e => + { var arg = e.GetArg("path"); if (string.IsNullOrWhiteSpace(arg)) return; @@ -273,7 +329,8 @@ namespace NadekoBot.Modules { cgb.CreateCommand("mv") .Description("Moves the bot to your voice channel. (works only if music is already playing)") - .Do(e => { + .Do(e => + { MusicPlayer musicPlayer; var voiceChannel = e.User.VoiceChannel; if (voiceChannel == null || voiceChannel.Server != e.Server || !MusicPlayers.TryGetValue(e.Server, out musicPlayer)) @@ -284,19 +341,23 @@ namespace NadekoBot.Modules { cgb.CreateCommand("rm") .Description("Remove a song by its # in the queue, or 'all' to remove whole queue.") .Parameter("num", ParameterType.Required) - .Do(async e => { + .Do(async e => + { var arg = e.GetArg("num"); MusicPlayer musicPlayer; - if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) { + if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) + { return; } - if (arg?.ToLower() == "all") { + if (arg?.ToLower() == "all") + { musicPlayer.ClearQueue(); await e.Channel.SendMessage($"🎵`Queue cleared!`"); return; } int num; - if (!int.TryParse(arg, out num)) { + if (!int.TryParse(arg, out num)) + { return; } if (num <= 0 || num > musicPlayer.Playlist.Count) @@ -309,11 +370,14 @@ namespace NadekoBot.Modules { cgb.CreateCommand("cleanup") .Description("Cleans up hanging voice connections. **Owner Only!**") .AddCheck(SimpleCheckers.OwnerOnly()) - .Do(e => { - foreach (var kvp in MusicPlayers) { + .Do(e => + { + foreach (var kvp in MusicPlayers) + { var songs = kvp.Value.Playlist; var currentSong = kvp.Value.CurrentSong; - if (songs.Count == 0 && currentSong == null) { + if (songs.Count == 0 && currentSong == null) + { MusicPlayer throwaway; MusicPlayers.TryRemove(kvp.Key, out throwaway); throwaway.Destroy(); @@ -331,8 +395,10 @@ namespace NadekoBot.Modules { }); } - private async Task QueueSong(Channel textCh, Channel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal) { - if (voiceCh == null || voiceCh.Server != textCh.Server) { + private async Task QueueSong(Channel textCh, Channel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal) + { + if (voiceCh == null || voiceCh.Server != textCh.Server) + { if (!silent) await textCh.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining."); throw new ArgumentNullException(nameof(voiceCh)); @@ -340,25 +406,32 @@ namespace NadekoBot.Modules { if (string.IsNullOrWhiteSpace(query) || query.Length < 3) throw new ArgumentException("💢 Invalid query for queue song.", nameof(query)); - var musicPlayer = MusicPlayers.GetOrAdd(textCh.Server, server => { + var musicPlayer = MusicPlayers.GetOrAdd(textCh.Server, server => + { float? vol = null; float throwAway; if (DefaultMusicVolumes.TryGetValue(server.Id, out throwAway)) vol = throwAway; var mp = new MusicPlayer(voiceCh, vol); - mp.OnCompleted += async (s, song) => { - try { + mp.OnCompleted += async (s, song) => + { + try + { await textCh.SendMessage($"🎵`Finished`{song.PrettyName}"); - } catch { } + } + catch { } }; - mp.OnStarted += async (s, song) => { + mp.OnStarted += async (s, song) => + { var sender = s as MusicPlayer; if (sender == null) return; - try { + try + { var msgTxt = $"🎵`Playing`{song.PrettyName} `Vol: {(int)(sender.Volume * 100)}%`"; await textCh.SendMessage(msgTxt); - } catch { } + } + catch { } }; return mp; }); diff --git a/NadekoBot/bin/Debug/data/config_example.json b/NadekoBot/bin/Debug/data/config_example.json index 13198eee..9b6bb69d 100644 --- a/NadekoBot/bin/Debug/data/config_example.json +++ b/NadekoBot/bin/Debug/data/config_example.json @@ -69,5 +69,7 @@ "https://media.giphy.com/media/12hvLuZ7uzvCvK/giphy.gif", "http://gallery1.anivide.com/_full/65030_1382582341.gif", "https://49.media.tumblr.com/8e8a099c4eba22abd3ec0f70fd087cce/tumblr_nxovj9oY861ur1mffo1_500.gif " - ] + ], + "CurrencySign": "🌸", + "CurrencyName": "NadekoFlower" } \ No newline at end of file