diff --git a/docs/Commands List.md b/docs/Commands List.md index e45a428c..3465c139 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -14,11 +14,13 @@ Command and aliases | Description | Usage `.ban` `.b` | Bans a user by ID or name with an optional message. **Requires BanMembers server permission.** | `.b "@some Guy" Your behaviour is toxic.` `.softban` `.sb` | Bans and then unbans a user by ID or name with an optional message. **Requires BanMembers server permission.** | `.sb "@some Guy" Your behaviour is toxic.` `.kick` `.k` | Kicks a mentioned user. **Requires KickMembers server permission.** | `.k "@some Guy" Your behaviour is toxic.` -`.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. After specifying this role, restart commands which use mute as punishment. | `.setmuterole Silenced` -`.mute` | Mutes a mentioned user both fom speaking and chatting. **Requires MuteMembers server permission.** | `.mute @Someone` -`.textmute` | Prevents a mentioned user from chatting in text channels. **Requires MuteMembers server permission.** | `.textmute @Someone` +`.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. After specifying this role, restart commands which use mute as punishment. **Requires ManageRoles server permission.** | `.setmuterole Silenced` +`.mute` | Mutes a mentioned user both from speaking and chatting. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone` +`.unmute` | Unmutes a mentioned user previously muted with `.mute` command. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.unmute @Someone` +`.chatmute` | Prevents a mentioned user from chatting in text channels. **Requires ManageRoles server permission.** | `.chatmute @Someone` +`.chatunmute` | Removes a mute role previously set on a mentioned user with `.chatmute` which prevented him from chatting in text channels. **Requires ManageRoles server permission.** | `.chatunmute @Someone` `.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone` -`.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.unmute @Someguy` +`.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy` `.deafen` `.deaf` | Deafens mentioned user or users. **Requires DeafenMembers server permission.** | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"` `.undeafen` `.undef` | Undeafens mentioned user or users. **Requires DeafenMembers server permission.** | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"` `.delvoichanl` `.dvch` | Deletes a voice channel with a given name. **Requires ManageChannels server permission.** | `.dvch VoiceChannelName` @@ -28,10 +30,11 @@ Command and aliases | Description | Usage `.settopic` `.st` | Sets a topic on the current channel. **Requires ManageChannels server permission.** | `.st My new topic` `.setchanlname` `.schn` | Changes the name of the current channel. **Requires ManageChannels server permission.** | `.schn NewName` `.prune` `.clr` | `.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X` -`.die` | Shuts the bot down. **Bot owner only.** | `@NadekoBot die` +`.die` | Shuts the bot down. **Bot owner only.** | `.die` `.setname` `.newnm` | Gives the bot a new name. **Bot owner only.** | `.newnm BotName` `.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot owner only.** | `.setav http://i.imgur.com/xTG3a1I.jpg` -`.setgame` | Sets the bots game. **Bot owner only.** | `.setgame Playing with kwoth` +`.setgame` | Sets the bots game. **Bot owner only.** | `.setgame with snakes` +`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot owner only.** | `.setstream https://www.twitch.tv/masterkwoth Developing Nakedo` `.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. **Bot owner only.** | `.send serverid|c:channelid` or `.send serverid|u:userid` `.announce` | Sends a message to all servers' general channel bot is connected to. **Bot owner only.** | `.announce Useless spam` `.savechat` | Saves a number of messages to a text file and sends it to you. **Bot owner only.** | `.savechat 150` @@ -58,6 +61,7 @@ Command and aliases | Description | Usage `.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot owner only.** | `.lipl` `.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot owner only.** | `.rmpl` `.slowmode` | Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. **Requires ManageMessages server permission.** | `.slowmode 1 5` or `.slowmode` +`.adsarm` | Toggles the automatic deletion of confirmations for .iam and .iamn commands. **Requires ManageMessages server permission.** | `.adsarm` `.asar` | Adds a role to the list of self-assignable roles. **Requires ManageRoles server permission.** | `.asar Gamer` `.rsar` | Removes a specified role from the list of self-assignable roles. **Requires ManageRoles server permission.** | `.rsar` `.lsar` | Lists all self-assignable roles. | `.lsar` @@ -101,21 +105,21 @@ Command and aliases | Description | Usage Command and aliases | Description | Usage ----------------|--------------|------- `$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName` -`$cash` `$$$` | Check how much NadekoFlowers a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy` +`$cash` `$$$` | Check how much currency a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy` `$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"` -`$award` | Awards someone a certain amount of currency. **Bot owner only.** | `$award 100 @person` -`$take` | Takes a certain amount of flowers from someone. **Bot owner only.** | `$take 1 "@someguy"` -`$betroll` `$br` | Bets a certain amount of NadekoFlowers and rolls a dice. Rolling over 66 yields x2 flowers, over 90 - x3 and 100 x10. | `$br 5` +`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot owner only.** | `$award 100 @person` or `$award 5 Role Of Gamblers` +`$take` | Takes a certain amount of currency from someone. **Bot owner only.** | `$take 1 "@someguy"` +`$betroll` `$br` | Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x3 and 100 x10. | `$br 5` `$leaderboard` `$lb` | Displays bot currency leaderboard. | `$lb` `$race` | Starts a new animal race. | `$race` -`$joinrace` `$jr` | Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5` +`$joinrace` `$jr` | Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5` `$roll` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$roll` or `$roll 7` or `$roll 3d5` `$rolluo` | Rolls X normal dice (up to 30) unordered. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$rolluo` or `$rolluo 7` or `$rolluo 3d5` `$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15` `$draw` | Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. | `$draw` or `$draw 5` `$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh` `$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3` -`$betflip` `$bf` | Bet to guess will the result be heads or tails. Guessing awards you double flowers you've bet. | `$bf 5 heads` or `$bf 3 t` +`$betflip` `$bf` | Bet to guess will the result be heads or tails. Guessing awards you 1.8x the currency you've bet. | `$bf 5 heads` or `$bf 3 t` ### Games Command and aliases | Description | Usage @@ -125,15 +129,16 @@ Command and aliases | Description | Usage `>rps` | Play a game of rocket paperclip scissors with Nadeko. | `>rps scissors` `>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows` `>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello` -`>poll` | Creates a poll, only person who has manage server permission can do it. | `>poll Question?;Answer1;Answ 2;A_3` -`>pollend` | Stops active poll on this server and prints the results in this channel. | `>pollend` -`>pick` | Picks a flower planted in this channel. | `>pick` -`>plant` | Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost) | `>plant` -`>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn a NadekoFlower. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc` +`>poll` | Creates a poll which requires users to send the number of the voting option to the bot. **Requires ManageMessages server permission.** | `>poll Question?;Answer1;Answ 2;A_3` +`>publicpoll` `>ppoll` | Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. **Requires ManageMessages server permission.** | `>ppoll Question?;Answer1;Answ 2;A_3` +`>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend` +`>pick` | Picks the currency planted in this channel. | `>pick` +`>plant` | Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost) | `>plant` +`>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc` `>typestart` | Starts a typing contest. | `>typestart` `>typestop` | Stops a typing contest on the current channel. | `>typestop` `>typeadd` | Adds a new article to the typing contest. **Bot owner only.** | `>typeadd wordswords` -`>trivia` `>t` | Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `>t nohint` or `>t 5 nohint` +`>trivia` `>t` | Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `>t` or `>t 5 nohint` `>tl` | Shows a current trivia leaderboard. | `>tl` `>tq` | Quits current trivia after current question. | `>tq` @@ -168,7 +173,7 @@ Command and aliases | Description | Usage `!!local` `!!lo` | Queues a local file by specifying a full path. **Bot owner only.** | `!!lo C:/music/mysong.mp3` `!!move` `!!mv` | Moves the bot to your voice channel. (works only if music is already playing) | `!!mv` `!!remove` `!!rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!!rm 5` -`!!movesong` `!!ms` | Moves a song from one position to another. | `!! ms 5>3` +`!!movesong` `!!ms` | Moves a song from one position to another. | `!!ms 5>3` `!!setmaxqueue` `!!smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `!!smq 50` or `!!smq` `!!reptcursong` `!!rcs` | Toggles repeat of current song. | `!!rcs` `!!rpeatplaylst` `!!rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!!rpl` @@ -199,8 +204,8 @@ Command and aliases | Description | Usage `;verbose` `;v` | Sets whether to show when a command/module is blocked. | `;verbose true` `;permrole` `;pr` | Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. | `;pr role` `;listperms` `;lp` | Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. | `;lp` or `;lp 3` -`;removeperm` `;rp` | Removes a permission from a given position | `;rp 1` -`;moveperm` `;mp` | Moves permission from one position to another. | `;mp 2 4` +`;removeperm` `;rp` | Removes a permission from a given position in Permissions list. | `;rp 1` +`;moveperm` `;mp` | Moves permission from one position to another in Permissions list. | `;mp 2 4` `;srvrcmd` `;sc` | Sets a command's permission at the server level. | `;sc "command name" disable` `;srvrmdl` `;sm` | Sets a module's permission at the server level. | `;sm "module name" enable` `;usrcmd` `;uc` | Sets a command's permission at the user level. | `;uc "command name" enable SomeUsername` @@ -222,7 +227,7 @@ Command and aliases | Description | Usage `;chnlfilterinv` `;cfi` | Toggles automatic deleting of invites posted in the channel. Does not negate the ;srvrfilterinv enabled setting. Does not affect Bot Owner. | `;cfi` `;srvrfilterwords` `;sfw` | Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. | `;sfw` `;chnlfilterwords` `;cfw` | Toggles automatic deleting of messages containing banned words on the channel. Does not negate the ;srvrfilterwords enabled setting. Does not affect bot owner. | `;cfw` -`;fw` | Adds or removes (if it exists) a word from the list of filtered words. Use` ;sfw` or `;cfw` to toggle filtering. | `;fw poop` +`;fw` | Adds or removes (if it exists) a word from the list of filtered words. Use`;sfw` or `;cfw` to toggle filtering. | `;fw poop` `;lstfilterwords` `;lfw` | Shows a list of filtered words. | `;lfw` ### Searches @@ -263,6 +268,8 @@ Command and aliases | Description | Usage `~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko` `~osub` | Shows information about an osu beatmap. | `~osub https://osu.ppy.sh/s/127712` `~osu5` | Displays a user's top 5 plays. | `~osu5 Name` +`~placelist` | Shows the list of available tags for the `~place` command. | `~placelist` +`~place` | Shows a placeholder image of a given tag. Use `~placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. | `~place Cage` or `~place steven 500 400` `~pokemon` `~poke` | Searches for a pokemon. | `~poke Sylveon` `~pokemonability` `~pokeab` | Searches for a pokemon ability. | `~pokeab overgrow` `~hitbox` `~hb` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `~hitbox SomeStreamer` @@ -271,22 +278,24 @@ Command and aliases | Description | Usage `~liststreams` `~ls` | Lists all streams you are following on this server. | `~ls` `~removestream` `~rms` | Removes notifications of a certain streamer on this channel. **Requires ManageMessages server permission.** | `~rms SomeGuy` `~checkstream` `~cs` | Checks if a user is online on a certain streaming platform. | `~cs twitch MyFavStreamer` +`~xkcd` | Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. | `~xkcd` or `~xkcd 1400` or `~xkcd latest` ### Utility Command and aliases | Description | Usage ----------------|--------------|------- `.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch` `.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role` -`.checkmyperms` | Checks your userspecific permissions on this channel. | `.checkmyperms` +`.checkmyperms` | Checks your user-specific permissions on this channel. | `.checkmyperms` `.userid` `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"` `.channelid` `.cid` | Shows current channel ID. | `.cid` `.serverid` `.sid` | Shows current server ID. | `.sid` `.roles` | List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. | `.roles 2` or `.roles @Someone` `.channeltopic` `.ct` | Sends current channel's topic as a message. | `.ct` `.stats` | Shows some basic stats for Nadeko. | `.stats` -`.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIALemojis` +`.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis` `.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` `.calcops` | Shows all available operations in .calc command | `.calcops` +`.togethertube` `.totube` | Creates a new room on and shows the link in the chat. | `.totube` `.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server` `.channelinfo` `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | `.cinfo #some-channel` `.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser` diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 86522f30..28a68c1b 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -749,7 +749,7 @@ namespace NadekoBot.Modules.Administration game = game ?? ""; - await NadekoBot.Client.GetCurrentUser().ModifyStatusAsync(u => u.Game = new Game(game)).ConfigureAwait(false); + await NadekoBot.Client.SetGame(game).ConfigureAwait(false); await channel.SendMessageAsync("`New game set.`").ConfigureAwait(false); } @@ -763,7 +763,7 @@ namespace NadekoBot.Modules.Administration name = name ?? ""; - await NadekoBot.Client.GetCurrentUser().ModifyStatusAsync(u => u.Game = new Game(name, url, StreamType.Twitch)).ConfigureAwait(false); + await NadekoBot.Client.SetStream(name, url).ConfigureAwait(false); await channel.SendMessageAsync("`New stream set.`").ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs b/src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs index 1bc1e041..2550a94d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs @@ -101,23 +101,25 @@ namespace NadekoBot.Modules.Administration var t = Task.Run(async () => { - AntiSpamSetting spamSettings; - if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings)) - return; - - var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content), - (id, old) => { old.ApplyNextMessage(msg.Content); return old; }); - - if (stats.Count >= spamSettings.MessageThreshold) + try { - if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats)) - { - var log = await PunishUser((IGuildUser)msg.Author, spamSettings.Action, spamSettings.MuteRole, ProtectionType.Spamming) - .ConfigureAwait(false); - try { await channel.Guild.SendMessageToOwnerAsync(log).ConfigureAwait(false); } catch { } - } - } + AntiSpamSetting spamSettings; + if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings)) + return; + var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content), + (id, old) => { old.ApplyNextMessage(msg.Content); return old; }); + + if (stats.Count >= spamSettings.MessageThreshold) + { + if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats)) + { + var log = await PunishUser((IGuildUser)msg.Author, spamSettings.Action, spamSettings.MuteRole, ProtectionType.Spamming) + .ConfigureAwait(false); + await channel.Guild.SendMessageToOwnerAsync(log).ConfigureAwait(false); } + } + } + catch { } }); return Task.CompletedTask; }; diff --git a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs index 47abda51..4a159152 100644 --- a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs @@ -27,19 +27,23 @@ namespace NadekoBot.Modules.Administration { var t = Task.Run(async () => { - GuildConfig conf; - using (var uow = DbHandler.UnitOfWork()) + try { - conf = uow.GuildConfigs.For(user.Guild.Id); + GuildConfig conf; + using (var uow = DbHandler.UnitOfWork()) + { + conf = uow.GuildConfigs.For(user.Guild.Id); + } + + if (conf.AutoAssignRoleId == 0) + return; + + var role = user.Guild.Roles.FirstOrDefault(r => r.Id == conf.AutoAssignRoleId); + + if (role != null) + await user.AddRolesAsync(role); } - - if (conf.AutoAssignRoleId == 0) - return; - - var role = user.Guild.Roles.FirstOrDefault(r => r.Id == conf.AutoAssignRoleId); - - if (role != null) - try { await user.AddRolesAsync(role); } catch (Exception ex) { _log.Warn(ex); } + catch (Exception ex) { _log.Warn(ex); } }); return Task.CompletedTask; }; diff --git a/src/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs b/src/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs index b6f3a612..b691e86c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs +++ b/src/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs @@ -36,17 +36,17 @@ namespace NadekoBot.Modules.Administration Task.Run(async () => { - if (msg.Author.Id == NadekoBot.Client.GetCurrentUser().Id) return; - foreach (var subscriber in Subscribers) + if (msg.Author.Id == NadekoBot.Client.GetCurrentUser().Id) return; + foreach (var subscriber in Subscribers) + { + var set = subscriber.Value; + if (!set.Contains(msg.Channel)) + continue; + foreach (var chan in set.Except(new[] { channel })) { - var set = subscriber.Value; - if (!set.Contains(msg.Channel)) - continue; - foreach (var chan in set.Except(new[] { channel })) - { - try { await chan.SendMessageAsync(GetText(channel.Guild, channel, (IGuildUser)msg.Author, msg)).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } - } + try { await chan.SendMessageAsync(GetText(channel.Guild, channel, (IGuildUser)msg.Author, msg)).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } } + } }); return Task.CompletedTask; }; diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index a4fa6baa..e291522d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -90,29 +90,33 @@ namespace NadekoBot.Modules.Administration var task = Task.Run(async () => { - string str = $"🕔`{prettyCurrentTime}`"; - if (before.Username != after.Username) - str += $"**Name Changed**👤`{before.Username}#{before.Discriminator}`\n\t\t`New:`{after.ToString()}`"; - else if (before.Nickname != after.Nickname) - str += $"**Nickname Changed**👤`{before.Username}#{before.Discriminator}`\n\t\t`Old:` {before.Nickname}#{before.Discriminator}\n\t\t`New:` {after.Nickname}#{after.Discriminator}"; - else if (before.AvatarUrl != after.AvatarUrl) - str += $"**Avatar Changed**👤`{before.Username}#{before.Discriminator}`\n\t {await _google.ShortenUrl(before.AvatarUrl)} `=>` {await _google.ShortenUrl(after.AvatarUrl)}"; - else if (!before.Roles.SequenceEqual(after.Roles)) + try { - if (before.Roles.Count() < after.Roles.Count()) + string str = $"🕔`{prettyCurrentTime}`"; + if (before.Username != after.Username) + str += $"**Name Changed**👤`{before.Username}#{before.Discriminator}`\n\t\t`New:`{after.ToString()}`"; + else if (before.Nickname != after.Nickname) + str += $"**Nickname Changed**👤`{before.Username}#{before.Discriminator}`\n\t\t`Old:` {before.Nickname}#{before.Discriminator}\n\t\t`New:` {after.Nickname}#{after.Discriminator}"; + else if (before.AvatarUrl != after.AvatarUrl) + str += $"**Avatar Changed**👤`{before.Username}#{before.Discriminator}`\n\t {await _google.ShortenUrl(before.AvatarUrl)} `=>` {await _google.ShortenUrl(after.AvatarUrl)}"; + else if (!before.Roles.SequenceEqual(after.Roles)) { - var diffRoles = after.Roles.Where(r => !before.Roles.Contains(r)).Select(r => "`" + r.Name + "`"); - str += $"**User's Roles changed ⚔➕**👤`{before.ToString()}`\n\tNow has {string.Join(", ", diffRoles)} role."; - } - else if (before.Roles.Count() > after.Roles.Count()) - { - var diffRoles = before.Roles.Where(r => !after.Roles.Contains(r)).Select(r => "`" + r.Name + "`"); - str += $"**User's Roles changed ⚔➖**👤`{before.ToString()}`\n\tNo longer has {string.Join(", ", diffRoles)} role."; + if (before.Roles.Count() < after.Roles.Count()) + { + var diffRoles = after.Roles.Where(r => !before.Roles.Contains(r)).Select(r => "`" + r.Name + "`"); + str += $"**User's Roles changed ⚔➕**👤`{before.ToString()}`\n\tNow has {string.Join(", ", diffRoles)} role."; + } + else if (before.Roles.Count() > after.Roles.Count()) + { + var diffRoles = before.Roles.Where(r => !after.Roles.Contains(r)).Select(r => "`" + r.Name + "`"); + str += $"**User's Roles changed ⚔➖**👤`{before.ToString()}`\n\tNo longer has {string.Join(", ", diffRoles)} role."; + } } + else + return; + try { await logChannel.SendMessageAsync(str).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } } - else - return; - try { await logChannel.SendMessageAsync(str).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + catch { } }); return Task.CompletedTask; @@ -138,14 +142,18 @@ namespace NadekoBot.Modules.Administration var task = Task.Run(async () => { - if (before.Name != after.Name) - await logChannel.SendMessageAsync($@"`{prettyCurrentTime}` **Channel Name Changed** `#{after.Name}` ({after.Id}) + try + { + if (before.Name != after.Name) + await logChannel.SendMessageAsync($@"`{prettyCurrentTime}` **Channel Name Changed** `#{after.Name}` ({after.Id}) `Old:` {before.Name} `New:` {after.Name}").ConfigureAwait(false); - else if ((before as ITextChannel).Topic != (after as ITextChannel).Topic) - await logChannel.SendMessageAsync($@"`{prettyCurrentTime}` **Channel Topic Changed** `#{after.Name}` ({after.Id}) + else if ((before as ITextChannel).Topic != (after as ITextChannel).Topic) + await logChannel.SendMessageAsync($@"`{prettyCurrentTime}` **Channel Topic Changed** `#{after.Name}` ({after.Id}) `Old:` {((ITextChannel)before).Topic} `New:` {((ITextChannel)after).Topic}").ConfigureAwait(false); + } + catch { } }); return Task.CompletedTask; @@ -365,11 +373,15 @@ namespace NadekoBot.Modules.Administration var task = Task.Run(async () => { - var str = $@"🕔`{prettyCurrentTime}` **Message** 🚮 `#{channel.Name}` -👤`{msg.Author.Username}`: {msg.Resolve(userHandling:UserMentionHandling.NameAndDiscriminator)}"; - if (msg.Attachments.Any()) - str += $"{Environment.NewLine}`Attachements`: {string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))}"; - try { await logChannel.SendMessageAsync(str).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + try + { + var str = $@"🕔`{prettyCurrentTime}` **Message** 🚮 `#{channel.Name}` +👤`{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); + } + catch (Exception ex) { _log.Warn(ex); } }); return Task.CompletedTask; diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index bf6030bb..41d7201f 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -58,9 +58,7 @@ namespace NadekoBot.Modules.Administration if (string.IsNullOrWhiteSpace(status)) continue; PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value())); - await (await NadekoBot.Client.GetCurrentUserAsync()) - .ModifyStatusAsync(mpp => mpp.Game = new Game(status)) - .ConfigureAwait(false); + await NadekoBot.Client.SetGame(status); } } catch (Exception ex) diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index 71414d37..d74b7a9f 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -39,9 +39,10 @@ namespace NadekoBot.Modules.Administration return Task.CompletedTask; var task = Task.Run(async () => { - var botUserPerms = guild.GetCurrentUser().GuildPermissions; try { + var botUserPerms = guild.GetCurrentUser().GuildPermissions; + if (before.VoiceChannel == after.VoiceChannel) return; if (!voicePlusTextCache.Contains(guild.Id)) diff --git a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs index bf29c2bf..a849f702 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs @@ -186,6 +186,7 @@ namespace NadekoBot.Modules.Gambling await Task.Delay(2500); } } + catch { } finally { NadekoBot.Client.MessageReceived -= Client_MessageReceived; diff --git a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs index e3ca136c..73c650c0 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs @@ -35,10 +35,14 @@ namespace NadekoBot.Modules.Gambling var num2 = gen % 10; var imageStream = await Task.Run(() => { - var ms = new MemoryStream(); - new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms); - ms.Position = 0; - return ms; + try + { + var ms = new MemoryStream(); + new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms); + ms.Position = 0; + return ms; + } + catch { return new MemoryStream(); } }); await channel.SendFileAsync(imageStream, "dice.png", $"{umsg.Author.Mention} rolled " + Format.Code(gen.ToString())).ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index dbc56b74..a52b8122 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -42,7 +42,7 @@ namespace NadekoBot.Modules.Games.Trivia this.guild = guild; this.channel = channel; WinRequirement = winReq; - Task.Run(StartGame); + Task.Run(async () => { try { await StartGame().ConfigureAwait(false); } catch { } }); } private async Task StartGame() diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index 6c8a694c..9e83ff14 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -306,7 +306,7 @@ namespace NadekoBot.Modules.Music.Classes var link = (await NadekoBot.Google.GetVideosByKeywordsAsync(query).ConfigureAwait(false)).FirstOrDefault(); if (string.IsNullOrWhiteSpace(link)) throw new OperationCanceledException("Not a valid youtube query."); - var allVideos = await Task.Run(async () => await YouTube.Default.GetAllVideosAsync(link).ConfigureAwait(false)).ConfigureAwait(false); + var allVideos = await Task.Run(async () => { try { return await YouTube.Default.GetAllVideosAsync(link).ConfigureAwait(false); } catch { return Enumerable.Empty(); } }).ConfigureAwait(false); var videos = allVideos.Where(v => v.AdaptiveKind == AdaptiveKind.Audio); var video = videos .Where(v => v.AudioBitrate < 192) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 6b58d21b..70af561d 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -799,9 +799,10 @@ namespace NadekoBot.Modules.Music var queuedMessage = await textCh.SendMessageAsync($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false); var t = Task.Run(async () => { - await Task.Delay(10000).ConfigureAwait(false); try { + await Task.Delay(10000).ConfigureAwait(false); + await queuedMessage.DeleteAsync().ConfigureAwait(false); } catch { } diff --git a/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs index 6f5b2b4a..9cdd092b 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs @@ -112,8 +112,12 @@ namespace NadekoBot.Modules.Permissions }); var t = Task.Run(async () => { - await Task.Delay(cdRule.Seconds * 1000); - activeCdsForGuild.RemoveWhere(ac => ac.Command == cmd.Text.ToLowerInvariant() && ac.UserId == user.Id); + try + { + await Task.Delay(cdRule.Seconds * 1000); + activeCdsForGuild.RemoveWhere(ac => ac.Command == cmd.Text.ToLowerInvariant() && ac.UserId == user.Id); + } + catch { } }); } } diff --git a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs index 27320f0d..5b8d8f5d 100644 --- a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs @@ -72,7 +72,7 @@ namespace NadekoBot.Modules.Searches var smallObj = JArray.Parse(res)[0]; var aniData = await http.GetStringAsync("http://anilist.co/api/anime/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false); - return await Task.Run(() => JsonConvert.DeserializeObject(aniData)).ConfigureAwait(false); + return await Task.Run(() => { try { return JsonConvert.DeserializeObject(aniData); } catch { return null; } }).ConfigureAwait(false); } } catch (Exception ex) { @@ -118,7 +118,7 @@ namespace NadekoBot.Modules.Searches var smallObj = JArray.Parse(res)[0]; var aniData = await http.GetStringAsync("http://anilist.co/api/manga/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false); - return await Task.Run(() => JsonConvert.DeserializeObject(aniData)).ConfigureAwait(false); + return await Task.Run(() => { try { return JsonConvert.DeserializeObject(aniData); } catch { return null; } }).ConfigureAwait(false); } } catch (Exception ex) diff --git a/src/NadekoBot/ShardedDiscordClient.cs b/src/NadekoBot/ShardedDiscordClient.cs index b119df42..afe84ca2 100644 --- a/src/NadekoBot/ShardedDiscordClient.cs +++ b/src/NadekoBot/ShardedDiscordClient.cs @@ -9,6 +9,7 @@ using Discord.API; using Discord.Logging; using System.IO; using NLog; +using NadekoBot.Extensions; namespace NadekoBot { @@ -70,6 +71,9 @@ namespace NadekoBot public Task GetCurrentUserAsync() => Clients[0].GetCurrentUserAsync(); + public Task GetAllCurrentUsersAsync() => + Task.WhenAll(Clients.Select(c => c.GetCurrentUserAsync())); + public IReadOnlyCollection GetGuilds() => Clients.SelectMany(c => c.GetGuilds()).ToArray(); @@ -87,5 +91,18 @@ namespace NadekoBot internal Task DownloadAllUsersAsync() => Task.WhenAll(Clients.Select(async c => { await c.DownloadAllUsersAsync(); _log.Info($"Shard #{c.ShardId} downloaded {c.GetGuilds().Sum(g => g.GetUsers().Count)} users."); })); + + public async Task SetGame(string game) + { + await Task.WhenAll((await GetAllCurrentUsersAsync()) + .Select(u => u.ModifyStatusAsync(ms => ms.Game = new Discord.Game(game)))); + } + + public async Task SetStream(string name, string url) + { + await Task.WhenAll((await GetAllCurrentUsersAsync()) + .Select(u => u.ModifyStatusAsync(ms => ms.Game = new Discord.Game(name, url, StreamType.Twitch)))); + + } } }