@@ -15,7 +15,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
    public partial class Games
 | 
			
		||||
    {
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class CleverBotCommands
 | 
			
		||||
        public class CleverBotCommands : ModuleBase
 | 
			
		||||
        {
 | 
			
		||||
            private static Logger _log { get; }
 | 
			
		||||
 | 
			
		||||
@@ -41,8 +41,8 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public static async Task<bool> TryAsk() {
 | 
			
		||||
                var channel = Context.Channel as ITextChannel;
 | 
			
		||||
            public static async Task<bool> TryAsk(IUserMessage msg) {
 | 
			
		||||
                var channel = msg.Channel as ITextChannel;
 | 
			
		||||
 | 
			
		||||
                if (channel == null)
 | 
			
		||||
                    return false;
 | 
			
		||||
@@ -68,16 +68,16 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
 | 
			
		||||
                await msg.Channel.TriggerTypingAsync().ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                var response = await cleverbot.Think(message).ConfigureAwait(false);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await Context.Channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false);
 | 
			
		||||
                    await msg.Channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    await Context.Channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); // try twice :\
 | 
			
		||||
                    await msg.Channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); // try twice :\
 | 
			
		||||
                }
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
@@ -87,32 +87,30 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            [RequireUserPermission(ChannelPermission.ManageMessages)]
 | 
			
		||||
            public async Task Cleverbot()
 | 
			
		||||
            {
 | 
			
		||||
                var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
                ChatterBotSession throwaway;
 | 
			
		||||
                if (CleverbotGuilds.TryRemove(channel.Guild.Id, out throwaway))
 | 
			
		||||
                if (CleverbotGuilds.TryRemove(Context.Guild.Id, out throwaway))
 | 
			
		||||
                {
 | 
			
		||||
                    using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                    {
 | 
			
		||||
                        uow.GuildConfigs.SetCleverbotEnabled(channel.Guild.Id, false);
 | 
			
		||||
                        uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, false);
 | 
			
		||||
                        await uow.CompleteAsync().ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    await channel.SendConfirmAsync($"{Context.User.Mention} Disabled cleverbot on this server.").ConfigureAwait(false);
 | 
			
		||||
                    await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Disabled cleverbot on this server.").ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var cleverbot = ChatterBotFactory.Create(ChatterBotType.CLEVERBOT);
 | 
			
		||||
                var session = cleverbot.CreateSession();
 | 
			
		||||
 | 
			
		||||
                CleverbotGuilds.TryAdd(channel.Guild.Id, session);
 | 
			
		||||
                CleverbotGuilds.TryAdd(Context.Guild.Id, session);
 | 
			
		||||
 | 
			
		||||
                using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                {
 | 
			
		||||
                    uow.GuildConfigs.SetCleverbotEnabled(channel.Guild.Id, true);
 | 
			
		||||
                    uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, true);
 | 
			
		||||
                    await uow.CompleteAsync().ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await channel.SendConfirmAsync($"{Context.User.Mention} Enabled cleverbot on this server.").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Enabled cleverbot on this server.").ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,8 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
{
 | 
			
		||||
    public partial class Games
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class HangmanCommands
 | 
			
		||||
        public class HangmanCommands : ModuleBase
 | 
			
		||||
        {
 | 
			
		||||
            private static Logger _log { get; }
 | 
			
		||||
 | 
			
		||||
@@ -42,7 +41,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            public async Task Hangman(IUserMessage imsg, HangmanTermPool.HangmanTermType type = HangmanTermPool.HangmanTermType.All)
 | 
			
		||||
            public async Task Hangman(HangmanTermPool.HangmanTermType type = HangmanTermPool.HangmanTermType.All)
 | 
			
		||||
            {
 | 
			
		||||
                var hm = new HangmanGame(Context.Channel, type);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
        /// https://discord.gg/0TYNJfCU4De7YIk8
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class PlantPickCommands
 | 
			
		||||
        public class PlantPickCommands : ModuleBase
 | 
			
		||||
        {
 | 
			
		||||
            private static ConcurrentHashSet<ulong> generationChannels { get; } = new ConcurrentHashSet<ulong>();
 | 
			
		||||
            //channelid/message
 | 
			
		||||
@@ -60,10 +60,10 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            private static Task PotentialFlowerGeneration(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var msg = imsg as IUserMessage;
 | 
			
		||||
                if (msg == null || msg.IsAuthor() || Context.User.IsBot)
 | 
			
		||||
                if (msg == null || msg.IsAuthor() || imsg.Author.IsBot)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var channel = Context.Channel as ITextChannel;
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                if (channel == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
@@ -111,7 +111,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
 | 
			
		||||
                List<IUserMessage> msgs;
 | 
			
		||||
 | 
			
		||||
                try { await imsg.DeleteAsync().ConfigureAwait(false); } catch { }
 | 
			
		||||
                try { await Context.Message.DeleteAsync().ConfigureAwait(false); } catch { }
 | 
			
		||||
                if (!plantedFlowers.TryRemove(channel.Id, out msgs))
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
@@ -130,12 +130,10 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Plant()
 | 
			
		||||
            {
 | 
			
		||||
                var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
                var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, "Planted a flower.", 1, false).ConfigureAwait(false);
 | 
			
		||||
                if (!removed)
 | 
			
		||||
                {
 | 
			
		||||
                    await channel.SendErrorAsync($"You don't have any {Gambling.Gambling.CurrencyPluralName}.").ConfigureAwait(false);
 | 
			
		||||
                    await Context.Channel.SendErrorAsync($"You don't have any {Gambling.Gambling.CurrencyPluralName}.").ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -146,13 +144,13 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
                var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(vowelFirst ? "an" : "a")} {Gambling.Gambling.CurrencyName}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick";
 | 
			
		||||
                if (file == null)
 | 
			
		||||
                {
 | 
			
		||||
                    msg = await channel.SendConfirmAsync(Gambling.Gambling.CurrencySign).ConfigureAwait(false);
 | 
			
		||||
                    msg = await Context.Channel.SendConfirmAsync(Gambling.Gambling.CurrencySign).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    msg = await channel.SendFileAsync(file, msgToSend).ConfigureAwait(false);
 | 
			
		||||
                    msg = await Context.Channel.SendFileAsync(file, msgToSend).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                plantedFlowers.AddOrUpdate(channel.Id, new List<IUserMessage>() { msg }, (id, old) => { old.Add(msg); return old; });
 | 
			
		||||
                plantedFlowers.AddOrUpdate(Context.Channel.Id, new List<IUserMessage>() { msg }, (id, old) => { old.Add(msg); return old; });
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
 
 | 
			
		||||
@@ -13,173 +13,177 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
{
 | 
			
		||||
    public partial class Games
 | 
			
		||||
    {
 | 
			
		||||
        public static ConcurrentDictionary<IGuild, Poll> ActivePolls = new ConcurrentDictionary<IGuild, Poll>();
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireUserPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public Task Poll(IUserMessage umsg, [Remainder] string arg = null)
 | 
			
		||||
            => InternalStartPoll(umsg, arg, isPublic: false);
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireUserPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public Task PublicPoll(IUserMessage umsg, [Remainder] string arg = null)
 | 
			
		||||
            => InternalStartPoll(umsg, arg, isPublic: true);
 | 
			
		||||
 | 
			
		||||
        private async Task InternalStartPoll(IUserMessage umsg, string arg, bool isPublic = false)
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class PollCommands : ModuleBase
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            public static ConcurrentDictionary<IGuild, Poll> ActivePolls = new ConcurrentDictionary<IGuild, Poll>();
 | 
			
		||||
 | 
			
		||||
            if (!(Context.User as IGuildUser).GuildPermissions.ManageChannels)
 | 
			
		||||
                return;
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";"))
 | 
			
		||||
                return;
 | 
			
		||||
            var data = arg.Split(';');
 | 
			
		||||
            if (data.Length < 3)
 | 
			
		||||
                return;
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireUserPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public Task Poll([Remainder] string arg = null)
 | 
			
		||||
                => InternalStartPoll(arg, isPublic: false);
 | 
			
		||||
 | 
			
		||||
            var poll = new Poll(umsg, data[0], data.Skip(1), isPublic: isPublic);
 | 
			
		||||
            if (ActivePolls.TryAdd(channel.Guild, poll))
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireUserPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public Task PublicPoll(IUserMessage umsg, [Remainder] string arg = null)
 | 
			
		||||
                => InternalStartPoll(arg, isPublic: true);
 | 
			
		||||
 | 
			
		||||
            private async Task InternalStartPoll(string arg, bool isPublic = false)
 | 
			
		||||
            {
 | 
			
		||||
                await poll.StartPoll().ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                await channel.SendErrorAsync("Poll is already running on this server.").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
                var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireUserPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Pollend()
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            Poll poll;
 | 
			
		||||
            ActivePolls.TryRemove(channel.Guild, out poll);
 | 
			
		||||
            await poll.StopPoll().ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class Poll
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IUserMessage originalMessage;
 | 
			
		||||
        private readonly IGuild guild;
 | 
			
		||||
        private readonly string[] answers;
 | 
			
		||||
        private ConcurrentDictionary<ulong, int> participants = new ConcurrentDictionary<ulong, int>();
 | 
			
		||||
        private readonly string question;
 | 
			
		||||
        private DateTime started;
 | 
			
		||||
        private CancellationTokenSource pollCancellationSource = new CancellationTokenSource();
 | 
			
		||||
        private readonly bool isPublic;
 | 
			
		||||
 | 
			
		||||
        public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
 | 
			
		||||
        {
 | 
			
		||||
            this.originalMessage = umsg;
 | 
			
		||||
            this.guild = ((ITextChannel)Context.Channel).Guild;
 | 
			
		||||
            this.question = question;
 | 
			
		||||
            this.answers = enumerable as string[] ?? enumerable.ToArray();
 | 
			
		||||
            this.isPublic = isPublic;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task StartPoll()
 | 
			
		||||
        {
 | 
			
		||||
            started = DateTime.Now;
 | 
			
		||||
            NadekoBot.Client.MessageReceived += Vote;
 | 
			
		||||
            var msgToSend = $"📃**{originalMessage.Author.Username}** has created a poll which requires your attention:\n\n**{question}**\n";
 | 
			
		||||
            var num = 1;
 | 
			
		||||
            msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
 | 
			
		||||
            if (!isPublic)
 | 
			
		||||
                msgToSend += "\n**Private Message me with the corresponding number of the answer.**";
 | 
			
		||||
            else
 | 
			
		||||
                msgToSend += "\n**Send a Message here with the corresponding number of the answer.**";
 | 
			
		||||
            await originalMessage.Channel.SendConfirmAsync(msgToSend).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task StopPoll()
 | 
			
		||||
        {
 | 
			
		||||
            NadekoBot.Client.MessageReceived -= Vote;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var results = participants.GroupBy(kvp => kvp.Value)
 | 
			
		||||
                                .ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
 | 
			
		||||
                                .OrderByDescending(kvp => kvp.Value);
 | 
			
		||||
 | 
			
		||||
                var totalVotesCast = results.Sum(kvp => kvp.Value);
 | 
			
		||||
                if (totalVotesCast == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    await originalMessage.Channel.SendMessageAsync("📄 **No votes have been cast.**").ConfigureAwait(false);
 | 
			
		||||
                if (!(Context.User as IGuildUser).GuildPermissions.ManageChannels)
 | 
			
		||||
                    return;
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";"))
 | 
			
		||||
                    return;
 | 
			
		||||
                var data = arg.Split(';');
 | 
			
		||||
                if (data.Length < 3)
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var closeMessage = $"--------------**POLL CLOSED**--------------\n" +
 | 
			
		||||
                                   $"📄 , here are the results:\n";
 | 
			
		||||
                closeMessage = results.Aggregate(closeMessage, (current, kvp) => current + $"`{kvp.Key}.` **[{answers[kvp.Key - 1]}]**" +
 | 
			
		||||
                                                                                 $" has {kvp.Value} votes." +
 | 
			
		||||
                                                                                 $"({kvp.Value * 1.0f / totalVotesCast * 100}%)\n");
 | 
			
		||||
 | 
			
		||||
                await originalMessage.Channel.SendConfirmAsync($"📄 **Total votes cast**: {totalVotesCast}\n{closeMessage}").ConfigureAwait(false);
 | 
			
		||||
                var poll = new Poll(umsg, data[0], data.Skip(1), isPublic: isPublic);
 | 
			
		||||
                if (ActivePolls.TryAdd(channel.Guild, poll))
 | 
			
		||||
                {
 | 
			
		||||
                    await poll.StartPoll().ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                    await channel.SendErrorAsync("Poll is already running on this server.").ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireUserPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Pollend()
 | 
			
		||||
            {
 | 
			
		||||
                Console.WriteLine($"Error in poll game {ex}");
 | 
			
		||||
                var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
                Poll poll;
 | 
			
		||||
                ActivePolls.TryRemove(channel.Guild, out poll);
 | 
			
		||||
                await poll.StopPoll().ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Vote(IMessage imsg)
 | 
			
		||||
        public class Poll
 | 
			
		||||
        {
 | 
			
		||||
            // has to be a user message
 | 
			
		||||
            var msg = imsg as IUserMessage;
 | 
			
		||||
            if (msg == null || Context.User.IsBot)
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            private readonly IUserMessage originalMessage;
 | 
			
		||||
            private readonly IGuild guild;
 | 
			
		||||
            private readonly string[] answers;
 | 
			
		||||
            private ConcurrentDictionary<ulong, int> participants = new ConcurrentDictionary<ulong, int>();
 | 
			
		||||
            private readonly string question;
 | 
			
		||||
            private DateTime started;
 | 
			
		||||
            private CancellationTokenSource pollCancellationSource = new CancellationTokenSource();
 | 
			
		||||
            private readonly bool isPublic;
 | 
			
		||||
 | 
			
		||||
            // has to be an integer
 | 
			
		||||
            int vote;
 | 
			
		||||
            if (!int.TryParse(imsg.Content, out vote))
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            if (vote < 1 || vote > answers.Length)
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
            var t = Task.Run(async () =>
 | 
			
		||||
            public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
 | 
			
		||||
            {
 | 
			
		||||
                this.originalMessage = umsg;
 | 
			
		||||
                this.guild = ((ITextChannel)umsg.Channel).Guild;
 | 
			
		||||
                this.question = question;
 | 
			
		||||
                this.answers = enumerable as string[] ?? enumerable.ToArray();
 | 
			
		||||
                this.isPublic = isPublic;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public async Task StartPoll()
 | 
			
		||||
            {
 | 
			
		||||
                started = DateTime.Now;
 | 
			
		||||
                NadekoBot.Client.MessageReceived += Vote;
 | 
			
		||||
                var msgToSend = $"📃**{originalMessage.Author.Username}** has created a poll which requires your attention:\n\n**{question}**\n";
 | 
			
		||||
                var num = 1;
 | 
			
		||||
                msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
 | 
			
		||||
                if (!isPublic)
 | 
			
		||||
                    msgToSend += "\n**Private Message me with the corresponding number of the answer.**";
 | 
			
		||||
                else
 | 
			
		||||
                    msgToSend += "\n**Send a Message here with the corresponding number of the answer.**";
 | 
			
		||||
                await originalMessage.Channel.SendConfirmAsync(msgToSend).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public async Task StopPoll()
 | 
			
		||||
            {
 | 
			
		||||
                NadekoBot.Client.MessageReceived -= Vote;
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    IMessageChannel ch;
 | 
			
		||||
                    if (isPublic)
 | 
			
		||||
                    {
 | 
			
		||||
                        //if public, channel must be the same the poll started in
 | 
			
		||||
                        if (originalMessage.Channel.Id != Context.Channel.Id)
 | 
			
		||||
                            return;
 | 
			
		||||
                        ch = Context.Channel;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //if private, channel must be dm channel
 | 
			
		||||
                        if ((ch = Context.Channel as IDMChannel) == null)
 | 
			
		||||
                            return;
 | 
			
		||||
                    var results = participants.GroupBy(kvp => kvp.Value)
 | 
			
		||||
                                    .ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
 | 
			
		||||
                                    .OrderByDescending(kvp => kvp.Value);
 | 
			
		||||
 | 
			
		||||
                        // user must be a member of the guild this poll is in
 | 
			
		||||
                        var guildUsers = await guild.GetUsersAsync().ConfigureAwait(false);
 | 
			
		||||
                        if (!guildUsers.Any(u => u.Id == Context.User.Id))
 | 
			
		||||
                            return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    //user can vote only once
 | 
			
		||||
                    if (participants.TryAdd(Context.User.Id, vote))
 | 
			
		||||
                    var totalVotesCast = results.Sum(kvp => kvp.Value);
 | 
			
		||||
                    if (totalVotesCast == 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!isPublic)
 | 
			
		||||
                        await originalMessage.Channel.SendMessageAsync("📄 **No votes have been cast.**").ConfigureAwait(false);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    var closeMessage = $"--------------**POLL CLOSED**--------------\n" +
 | 
			
		||||
                                       $"📄 , here are the results:\n";
 | 
			
		||||
                    closeMessage = results.Aggregate(closeMessage, (current, kvp) => current + $"`{kvp.Key}.` **[{answers[kvp.Key - 1]}]**" +
 | 
			
		||||
                                                                                     $" has {kvp.Value} votes." +
 | 
			
		||||
                                                                                     $"({kvp.Value * 1.0f / totalVotesCast * 100}%)\n");
 | 
			
		||||
 | 
			
		||||
                    await originalMessage.Channel.SendConfirmAsync($"📄 **Total votes cast**: {totalVotesCast}\n{closeMessage}").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    Console.WriteLine($"Error in poll game {ex}");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task Vote(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                // has to be a user message
 | 
			
		||||
                var msg = imsg as IUserMessage;
 | 
			
		||||
                if (msg == null || imsg.Author.IsBot)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                // has to be an integer
 | 
			
		||||
                int vote;
 | 
			
		||||
                if (!int.TryParse(imsg.Content, out vote))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                if (vote < 1 || vote > answers.Length)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var t = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        IMessageChannel ch;
 | 
			
		||||
                        if (isPublic)
 | 
			
		||||
                        {
 | 
			
		||||
                            await ch.SendConfirmAsync($"Thanks for voting **{Context.User.Username}**.").ConfigureAwait(false);
 | 
			
		||||
                            //if public, channel must be the same the poll started in
 | 
			
		||||
                            if (originalMessage.Channel.Id != imsg.Channel.Id)
 | 
			
		||||
                                return;
 | 
			
		||||
                            ch = imsg.Channel;
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            var toDelete = await ch.SendConfirmAsync($"{Context.User.Mention} cast their vote.").ConfigureAwait(false);
 | 
			
		||||
                            await Task.Delay(5000);
 | 
			
		||||
                            await toDelete.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            //if private, channel must be dm channel
 | 
			
		||||
                            if ((ch = Context.Channel as IDMChannel) == null)
 | 
			
		||||
                                return;
 | 
			
		||||
 | 
			
		||||
                            // user must be a member of the guild this poll is in
 | 
			
		||||
                            var guildUsers = await guild.GetUsersAsync().ConfigureAwait(false);
 | 
			
		||||
                            if (!guildUsers.Any(u => u.Id == Context.User.Id))
 | 
			
		||||
                                return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        //user can vote only once
 | 
			
		||||
                        if (participants.TryAdd(Context.User.Id, vote))
 | 
			
		||||
                        {
 | 
			
		||||
                            if (!isPublic)
 | 
			
		||||
                            {
 | 
			
		||||
                                await ch.SendConfirmAsync($"Thanks for voting **{Context.User.Username}**.").ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                var toDelete = await ch.SendConfirmAsync($"{Context.User.Mention} cast their vote.").ConfigureAwait(false);
 | 
			
		||||
                                await Task.Delay(5000);
 | 
			
		||||
                                await toDelete.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
            });
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
                    catch { }
 | 
			
		||||
                });
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -107,7 +107,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
 | 
			
		||||
            private Task AnswerReceived(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                if (Context.User.IsBot)
 | 
			
		||||
                if (imsg.Author.IsBot)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                var msg = imsg as IUserMessage;
 | 
			
		||||
                if (msg == null)
 | 
			
		||||
@@ -122,12 +122,12 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
 | 
			
		||||
                        var distance = CurrentSentence.LevenshteinDistance(guess);
 | 
			
		||||
                        var decision = Judge(distance, guess.Length);
 | 
			
		||||
                        if (decision && !finishedUserIds.Contains(Context.User.Id))
 | 
			
		||||
                        if (decision && !finishedUserIds.Contains(imsg.Author.Id))
 | 
			
		||||
                        {
 | 
			
		||||
                            var wpm = CurrentSentence.Length / WORD_VALUE / sw.Elapsed.Seconds * 60;
 | 
			
		||||
                            finishedUserIds.Add(Context.User.Id);
 | 
			
		||||
                            await Extensions.Extensions.EmbedAsync(this.Channel, (Discord.API.Embed)new EmbedBuilder().WithColor((uint)NadekoBot.OkColor)
 | 
			
		||||
                                .WithTitle((string)$"{Context.User} finished the race!")
 | 
			
		||||
                            finishedUserIds.Add(imsg.Author.Id);
 | 
			
		||||
                            await Extensions.Extensions.EmbedAsync(this.Channel, new EmbedBuilder().WithColor(NadekoBot.OkColor)
 | 
			
		||||
                                .WithTitle((string)$"{imsg.Author} finished the race!")
 | 
			
		||||
                                .AddField(efb => efb.WithName("Place").WithValue($"#{finishedUserIds.Count}").WithIsInline(true))
 | 
			
		||||
                                .AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F2} *[{sw.Elapsed.Seconds.ToString()}sec]*").WithIsInline(true))
 | 
			
		||||
                                .AddField(efb => efb.WithName((string)"Errors").WithValue((string)distance.ToString()).WithIsInline((bool)true))
 | 
			
		||||
@@ -148,7 +148,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class SpeedTypingCommands
 | 
			
		||||
        public class SpeedTypingCommands : ModuleBase
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            public static List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
 | 
			
		||||
@@ -205,7 +205,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            [OwnerOnly]
 | 
			
		||||
            public async Task Typeadd(IUserMessage imsg, [Remainder] string text)
 | 
			
		||||
            public async Task Typeadd([Remainder] string text)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -222,7 +222,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Typelist(IUserMessage imsg, int page = 1)
 | 
			
		||||
            public async Task Typelist(int page = 1)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -244,7 +244,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            [OwnerOnly]
 | 
			
		||||
            public async Task Typedel(IUserMessage imsg, int index)
 | 
			
		||||
            public async Task Typedel(int index)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,18 +14,16 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
    public partial class Games
 | 
			
		||||
    {
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class TriviaCommands
 | 
			
		||||
        public class TriviaCommands : ModuleBase
 | 
			
		||||
        {
 | 
			
		||||
            public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias = new ConcurrentDictionary<ulong, TriviaGame>();
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Trivia(IUserMessage umsg, params string[] args)
 | 
			
		||||
            public async Task Trivia(params string[] args)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
                TriviaGame trivia;
 | 
			
		||||
                if (!RunningTrivias.TryGetValue(channel.Guild.Id, out trivia))
 | 
			
		||||
                if (!RunningTrivias.TryGetValue(Context.Guild.Id, out trivia))
 | 
			
		||||
                {
 | 
			
		||||
                    var showHints = !args.Contains("nohint");
 | 
			
		||||
                    var number = args.Select(s =>
 | 
			
		||||
@@ -35,14 +33,14 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
                    }).Where(t => t.Item1).Select(t => t.Item2).FirstOrDefault();
 | 
			
		||||
                    if (number < 0)
 | 
			
		||||
                        return;
 | 
			
		||||
                    var triviaGame = new TriviaGame(channel.Guild, (ITextChannel)Context.Channel, showHints, number == 0 ? 10 : number);
 | 
			
		||||
                    if (RunningTrivias.TryAdd(channel.Guild.Id, triviaGame))
 | 
			
		||||
                        await channel.SendConfirmAsync($"**Trivia game started! {triviaGame.WinRequirement} points needed to win.**").ConfigureAwait(false);
 | 
			
		||||
                    var triviaGame = new TriviaGame(Context.Guild, (ITextChannel)Context.Channel, showHints, number == 0 ? 10 : number);
 | 
			
		||||
                    if (RunningTrivias.TryAdd(Context.Guild.Id, triviaGame))
 | 
			
		||||
                        await Context.Channel.SendConfirmAsync($"**Trivia game started! {triviaGame.WinRequirement} points needed to win.**").ConfigureAwait(false);
 | 
			
		||||
                    else
 | 
			
		||||
                        await triviaGame.StopGame().ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                    await channel.SendErrorAsync("Trivia game is already running on this server.\n" + trivia.CurrentQuestion).ConfigureAwait(false);
 | 
			
		||||
                    await Context.Channel.SendErrorAsync("Trivia game is already running on this server.\n" + trivia.CurrentQuestion).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
 
 | 
			
		||||
@@ -27,40 +27,34 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Choose(IUserMessage umsg, [Remainder] string list = null)
 | 
			
		||||
        public async Task Choose([Remainder] string list = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(list))
 | 
			
		||||
                return;
 | 
			
		||||
            var listArr = list.Split(';');
 | 
			
		||||
            if (listArr.Count() < 2)
 | 
			
		||||
                return;
 | 
			
		||||
            var rng = new NadekoRandom();
 | 
			
		||||
            await channel.SendConfirmAsync("🤔", listArr[rng.Next(0, listArr.Length)]).ConfigureAwait(false);
 | 
			
		||||
            await Context.Channel.SendConfirmAsync("🤔", listArr[rng.Next(0, listArr.Length)]).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task _8Ball(IUserMessage umsg, [Remainder] string question = null)
 | 
			
		||||
        public async Task _8Ball([Remainder] string question = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(question))
 | 
			
		||||
                return;
 | 
			
		||||
                var rng = new NadekoRandom();
 | 
			
		||||
 | 
			
		||||
            await channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
 | 
			
		||||
            await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
 | 
			
		||||
                               .AddField(efb => efb.WithName("❓ Question").WithValue(question).WithIsInline(false))
 | 
			
		||||
                               .AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses.Shuffle().FirstOrDefault()).WithIsInline(false))
 | 
			
		||||
                               );
 | 
			
		||||
                               .AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses.Shuffle().FirstOrDefault()).WithIsInline(false)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Rps(IUserMessage umsg, string input)
 | 
			
		||||
        public async Task Rps(string input)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            Func<int,string> GetRPSPick = (p) =>
 | 
			
		||||
            {
 | 
			
		||||
                if (p == 0)
 | 
			
		||||
@@ -102,16 +96,14 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            else
 | 
			
		||||
                msg = $"{Context.User.Mention} won! {GetRPSPick(pick)} beats {GetRPSPick(nadekoPick)}";
 | 
			
		||||
 | 
			
		||||
            await channel.SendConfirmAsync(msg).ConfigureAwait(false);
 | 
			
		||||
            await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Linux(IUserMessage umsg, string guhnoo, string loonix)
 | 
			
		||||
        public async Task Linux(string guhnoo, string loonix)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            await channel.SendConfirmAsync(
 | 
			
		||||
            await Context.Channel.SendConfirmAsync(
 | 
			
		||||
$@"I'd just like to interject for moment. What you're refering to as {loonix}, is in fact, {guhnoo}/{loonix}, or as I've recently taken to calling it, {guhnoo} plus {loonix}. {loonix} is not an operating system unto itself, but rather another free component of a fully functioning {guhnoo} system made useful by the {guhnoo} corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX.
 | 
			
		||||
 | 
			
		||||
Many computer users run a modified version of the {guhnoo} system every day, without realizing it. Through a peculiar turn of events, the version of {guhnoo} which is widely used today is often called {loonix}, and many of its users are not aware that it is basically the {guhnoo} system, developed by the {guhnoo} Project.
 | 
			
		||||
 
 | 
			
		||||
@@ -51,11 +51,11 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(module))
 | 
			
		||||
                return;
 | 
			
		||||
            var cmds = NadekoBot.CommandService.Commands.Where(c => c.Module.Name.ToUpperInvariant().StartsWith(module))
 | 
			
		||||
                                                  .OrderBy(c => c.Text)
 | 
			
		||||
                                                  .OrderBy(c => c.Aliases.First())
 | 
			
		||||
                                                  .Distinct(new CommandTextEqualityComparer())
 | 
			
		||||
                                                  .AsEnumerable();
 | 
			
		||||
 | 
			
		||||
            var cmdsArray = cmds as Command[] ?? cmds.ToArray();
 | 
			
		||||
            var cmdsArray = cmds as CommandInfo[] ?? cmds.ToArray();
 | 
			
		||||
            if (!cmdsArray.Any())
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendErrorAsync("That module does not exist.").ConfigureAwait(false);
 | 
			
		||||
@@ -63,11 +63,11 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
            }
 | 
			
		||||
            if (module != "customreactions" && module != "conversations")
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendTableAsync("📃 **List Of Commands:**\n", cmdsArray, el => $"{el.Text,-15} {"["+el.Aliases.Skip(1).FirstOrDefault()+"]",-8}").ConfigureAwait(false);
 | 
			
		||||
                await channel.SendTableAsync("📃 **List Of Commands:**\n", cmdsArray, el => $"{el.Aliases.First(),-15} {"["+el.Aliases.Skip(1).FirstOrDefault()+"]",-8}").ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendMessageAsync("📃 **List Of Commands:**\n• " + string.Join("\n• ", cmdsArray.Select(c => $"{c.Text}")));
 | 
			
		||||
                await channel.SendMessageAsync("📃 **List Of Commands:**\n• " + string.Join("\n• ", cmdsArray.Select(c => $"{c.Aliases.First()}")));
 | 
			
		||||
            }
 | 
			
		||||
            await channel.SendConfirmAsync($"ℹ️ **Type** `\"{NadekoBot.ModulePrefixes[typeof(Help).Name]}h CommandName\"` **to see the help for that specified command.** ***e.g.*** `-h >8ball`").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
@@ -84,36 +84,37 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
                await ch.SendMessageAsync(HelpString).ConfigureAwait(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            var com = NadekoBot.CommandService.Commands.FirstOrDefault(c => c.Text.ToLowerInvariant() == comToFind || c.Aliases.Select(a=>a.ToLowerInvariant()).Contains(comToFind));
 | 
			
		||||
            var com = NadekoBot.CommandService.Commands.FirstOrDefault(c => c.Aliases.Select(a=>a.ToLowerInvariant()).Contains(comToFind));
 | 
			
		||||
 | 
			
		||||
            if (com == null)
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendErrorAsync("I can't find that command. Please check the **command** and **command prefix** before trying again.");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            var str = $"**`{com.Text}`**";
 | 
			
		||||
            var str = $"**`{com.Aliases.First()}`**";
 | 
			
		||||
            var alias = com.Aliases.Skip(1).FirstOrDefault();
 | 
			
		||||
            if (alias != null)
 | 
			
		||||
                str += $" **/ `{alias}`**";
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                .AddField(fb => fb.WithIndex(1).WithName(str).WithValue($"{ string.Format(com.Summary, com.Module.Prefix)} { GetCommandRequirements(com)}").WithIsInline(true))
 | 
			
		||||
                .AddField(fb => fb.WithIndex(2).WithName("**Usage**").WithValue($"{string.Format(com.Remarks, com.Module.Prefix)}").WithIsInline(false))
 | 
			
		||||
                .AddField(fb => fb.WithName(str).WithValue($"{ string.Format(com.Summary, com.Module.Aliases.First())} { GetCommandRequirements(com)}").WithIsInline(true))
 | 
			
		||||
                .AddField(fb => fb.WithName("**Usage**").WithValue($"{string.Format(com.Remarks, com.Module.Aliases.First())}").WithIsInline(false))
 | 
			
		||||
                .WithColor(NadekoBot.OkColor);
 | 
			
		||||
            await channel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetCommandRequirements(Command cmd)
 | 
			
		||||
        private string GetCommandRequirements(CommandInfo cmd)
 | 
			
		||||
        {
 | 
			
		||||
            return String.Join(" ", cmd.Source.CustomAttributes
 | 
			
		||||
                      .Where(ca => ca.AttributeType == typeof(OwnerOnlyAttribute) || ca.AttributeType == typeof(RequireUserPermissionAttribute))
 | 
			
		||||
            return String.Join(" ", cmd.Preconditions
 | 
			
		||||
                      .Where(ca => ca is OwnerOnlyAttribute || ca is RequireUserPermissionAttribute)
 | 
			
		||||
                      .Select(ca =>
 | 
			
		||||
                      {
 | 
			
		||||
                          if (ca.AttributeType == typeof(OwnerOnlyAttribute))
 | 
			
		||||
                          if (ca is OwnerOnlyAttribute)
 | 
			
		||||
                              return "**Bot Owner only.**";
 | 
			
		||||
                          else if (ca.AttributeType == typeof(RequireUserPermissionAttribute))
 | 
			
		||||
                              return $"**Requires {(GuildPermission)ca.ConstructorArguments.FirstOrDefault().Value} server permission.**".Replace("Guild", "Server");
 | 
			
		||||
                          var cau = (RequireUserPermissionAttribute)ca;
 | 
			
		||||
                          if (cau.GuildPermission != null)
 | 
			
		||||
                              return $"**Requires {cau.GuildPermission} server permission.**".Replace("Guild", "Server");
 | 
			
		||||
                          else
 | 
			
		||||
                              return $"**Requires {(GuildPermission)ca.ConstructorArguments.FirstOrDefault().Value} channel permission.**".Replace("Guild", "Server");
 | 
			
		||||
                              return $"**Requires {cau.ChannelPermission} channel permission.**".Replace("Guild", "Server");
 | 
			
		||||
                      }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -128,7 +129,7 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
            helpstr.AppendLine(string.Join("\n", NadekoBot.CommandService.Modules.Where(m => m.Name.ToLowerInvariant() != "help").OrderBy(m => m.Name).Prepend(NadekoBot.CommandService.Modules.FirstOrDefault(m=>m.Name.ToLowerInvariant()=="help")).Select(m => $"- [{m.Name}](#{m.Name.ToLowerInvariant()})")));
 | 
			
		||||
            helpstr.AppendLine();
 | 
			
		||||
            string lastModule = null;
 | 
			
		||||
            foreach (var com in NadekoBot.CommandService.Commands.OrderBy(com=>com.Module.Name).GroupBy(c=>c.Text).Select(g=>g.First()))
 | 
			
		||||
            foreach (var com in NadekoBot.CommandService.Commands.OrderBy(com => com.Module.Name).GroupBy(c => c.Aliases.First()).Select(g => g.First()))
 | 
			
		||||
            {
 | 
			
		||||
                if (com.Module.Name != lastModule)
 | 
			
		||||
                {
 | 
			
		||||
@@ -143,7 +144,7 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
                    helpstr.AppendLine("----------------|--------------|-------");
 | 
			
		||||
                    lastModule = com.Module.Name;
 | 
			
		||||
                }
 | 
			
		||||
                helpstr.AppendLine($"`{com.Text}` {string.Join(" ", com.Aliases.Skip(1).Select(a=>"`"+a+"`"))} | {string.Format(com.Summary, com.Module.Prefix)} {GetCommandRequirements(com)} | {string.Format(com.Remarks, com.Module.Prefix)}");
 | 
			
		||||
                helpstr.AppendLine($"{string.Join(" ", com.Aliases.Select(a => "`" + a + "`"))} | {string.Format(com.Summary, com.Module.Prefix)} {GetCommandRequirements(com)} | {string.Format(com.Remarks, com.Module.Prefix)}");
 | 
			
		||||
            }
 | 
			
		||||
            helpstr = helpstr.Replace(NadekoBot.Client.CurrentUser().Username , "@BotName");
 | 
			
		||||
            File.WriteAllText("../../docs/Commands List.md", helpstr.ToString());
 | 
			
		||||
@@ -176,11 +177,11 @@ Don't forget to leave your discord name or id in the message.
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class CommandTextEqualityComparer : IEqualityComparer<Command>
 | 
			
		||||
    public class CommandTextEqualityComparer : IEqualityComparer<CommandInfo>
 | 
			
		||||
    {
 | 
			
		||||
        public bool Equals(Command x, Command y) => x.Text == y.Text;
 | 
			
		||||
        public bool Equals(CommandInfo x, CommandInfo y) => x.Aliases.First() == y.Aliases.First();
 | 
			
		||||
 | 
			
		||||
        public int GetHashCode(Command obj) => obj.Text.GetHashCode();
 | 
			
		||||
        public int GetHashCode(CommandInfo obj) => obj.Aliases.First().GetHashCode();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,38 +29,38 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
        {
 | 
			
		||||
            //it can fail if its currenctly opened or doesn't exist. Either way i don't care
 | 
			
		||||
            try { Directory.Delete(MusicDataPath, true); } catch { }
 | 
			
		||||
	    
 | 
			
		||||
	    NadekoBot.Client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
 | 
			
		||||
        
 | 
			
		||||
        NadekoBot.Client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
 | 
			
		||||
 | 
			
		||||
            Directory.CreateDirectory(MusicDataPath);
 | 
			
		||||
        }
 | 
			
		||||
	
 | 
			
		||||
	private Task Client_UserVoiceStateUpdated(IUser iusr, IVoiceState oldState, IVoiceState newState)
 | 
			
		||||
    
 | 
			
		||||
    private async Task Client_UserVoiceStateUpdated(SocketUser iusr, SocketVoiceState oldState, SocketVoiceState newState)
 | 
			
		||||
        {
 | 
			
		||||
            var usr = iusr as IGuildUser;
 | 
			
		||||
            if (usr == null ||
 | 
			
		||||
                oldState.VoiceChannel == newState.VoiceChannel)
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            MusicPlayer player;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(usr.Guild.Id, out player))
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var users = await player.PlaybackVoiceChannel.GetUsersAsync().Flatten().ConfigureAwait(false);
 | 
			
		||||
            if ((player.PlaybackVoiceChannel == newState.VoiceChannel && //if joined first, and player paused, unpause 
 | 
			
		||||
                    player.Paused &&
 | 
			
		||||
                    player.PlaybackVoiceChannel.GetUsers().Count == 2) ||  // keep in mind bot is in the channel (+1)
 | 
			
		||||
                    users.Count() == 2) ||  // keep in mind bot is in the channel (+1)
 | 
			
		||||
                (player.PlaybackVoiceChannel == oldState.VoiceChannel && // if left last, and player unpaused, pause
 | 
			
		||||
                    !player.Paused &&
 | 
			
		||||
                    player.PlaybackVoiceChannel.GetUsers().Count == 1))
 | 
			
		||||
                    users.Count() == 1))
 | 
			
		||||
            {
 | 
			
		||||
                player.TogglePause();
 | 
			
		||||
            }
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public Task Next(IUserMessage umsg, int skipCount = 1)
 | 
			
		||||
        public Task Next(int skipCount = 1)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -126,7 +126,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Queue(IUserMessage umsg, [Remainder] string query)
 | 
			
		||||
        public async Task Queue([Remainder] string query)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -134,13 +134,13 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
            if (channel.Guild.GetCurrentUser().GetPermissions(channel).ManageMessages)
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                await ((IUserMessage)umsg).DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                await Context.Message.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task SoundCloudQueue(IUserMessage umsg, [Remainder] string query)
 | 
			
		||||
        public async Task SoundCloudQueue([Remainder] string query)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -148,13 +148,13 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
            if (channel.Guild.GetCurrentUser().GetPermissions(channel).ManageMessages)
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                await ((IUserMessage)umsg).DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                await Context.Message.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task ListQueue(IUserMessage umsg, int page = 1)
 | 
			
		||||
        public async Task ListQueue(int page = 1)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
@@ -176,7 +176,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //var toSend = $"🎵 Currently Playing {currentSong.PrettyName} " + $"`{currentSong.PrettyCurrentTime()}`\n";
 | 
			
		||||
	    var toSend = $"🎵 Currently Playing {currentSong.PrettyName}\n";
 | 
			
		||||
        var toSend = $"🎵 Currently Playing {currentSong.PrettyName}\n";
 | 
			
		||||
            if (musicPlayer.RepeatSong)
 | 
			
		||||
                toSend += "🔂";
 | 
			
		||||
            else if (musicPlayer.RepeatPlaylist)
 | 
			
		||||
@@ -197,40 +197,40 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
        public async Task NowPlaying()
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
	    
 | 
			
		||||
        
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(channel.Guild.Id, out musicPlayer))
 | 
			
		||||
                return;
 | 
			
		||||
            var currentSong = musicPlayer.CurrentSong;
 | 
			
		||||
            if (currentSong == null)
 | 
			
		||||
                return;
 | 
			
		||||
		var videoid = Regex.Match(currentSong.SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+");
 | 
			
		||||
        var videoid = Regex.Match(currentSong.SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+");
 | 
			
		||||
 | 
			
		||||
            if (currentSong.TotalLength == TimeSpan.Zero)
 | 
			
		||||
            {
 | 
			
		||||
                await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
		var embed = new EmbedBuilder()
 | 
			
		||||
			    	.WithAuthor(eab => eab.WithName("Now Playing").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png"))
 | 
			
		||||
				.WithTitle($"{currentSong.SongInfo.Title}")
 | 
			
		||||
				.WithUrl($"{currentSong.SongInfo.Query}")
 | 
			
		||||
				.WithDescription($"{currentSong.PrettyCurrentTime()}")
 | 
			
		||||
				.WithFooter(ef => ef.WithText($"{currentSong.PrettyProvider} | {currentSong.PrettyUser}"))
 | 
			
		||||
                		.WithColor(NadekoBot.OkColor);
 | 
			
		||||
		if (currentSong.SongInfo.Provider.Equals("YouTube", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
		{
 | 
			
		||||
				embed.WithThumbnail(tn => tn.Url = $"https://img.youtube.com/vi/{videoid}/0.jpg");
 | 
			
		||||
		}
 | 
			
		||||
		else if (currentSong.SongInfo.Provider.Equals("SoundCloud", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
		{
 | 
			
		||||
				embed.WithThumbnail(tn => tn.Url = $"{currentSong.SongInfo.AlbumArt}");
 | 
			
		||||
		}
 | 
			
		||||
            	await channel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithAuthor(eab => eab.WithName("Now Playing").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png"))
 | 
			
		||||
                .WithTitle($"{currentSong.SongInfo.Title}")
 | 
			
		||||
                .WithUrl($"{currentSong.SongInfo.Query}")
 | 
			
		||||
                .WithDescription($"{currentSong.PrettyCurrentTime()}")
 | 
			
		||||
                .WithFooter(ef => ef.WithText($"{currentSong.PrettyProvider} | {currentSong.PrettyUser}"))
 | 
			
		||||
                        .WithColor(NadekoBot.OkColor);
 | 
			
		||||
        if (currentSong.SongInfo.Provider.Equals("YouTube", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
        {
 | 
			
		||||
                embed.WithThumbnailUrl($"https://img.youtube.com/vi/{videoid}/0.jpg");
 | 
			
		||||
        }
 | 
			
		||||
        else if (currentSong.SongInfo.Provider.Equals("SoundCloud", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
        {
 | 
			
		||||
                embed.WithThumbnailUrl($"{currentSong.SongInfo.AlbumArt}");
 | 
			
		||||
        }
 | 
			
		||||
                await channel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Volume(IUserMessage umsg, int val)
 | 
			
		||||
        public async Task Volume(int val)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
@@ -246,7 +246,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Defvol(IUserMessage umsg, [Remainder] int val)
 | 
			
		||||
        public async Task Defvol([Remainder] int val)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -285,7 +285,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Playlist(IUserMessage umsg, [Remainder] string playlist)
 | 
			
		||||
        public async Task Playlist([Remainder] string playlist)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            var arg = playlist;
 | 
			
		||||
@@ -326,7 +326,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task SoundCloudPl(IUserMessage umsg, [Remainder] string pl)
 | 
			
		||||
        public async Task SoundCloudPl([Remainder] string pl)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            pl = pl?.Trim();
 | 
			
		||||
@@ -364,7 +364,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [OwnerOnly]
 | 
			
		||||
        public async Task LocalPl(IUserMessage umsg, [Remainder] string directory)
 | 
			
		||||
        public async Task LocalPl([Remainder] string directory)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            var arg = directory;
 | 
			
		||||
@@ -394,7 +394,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Radio(IUserMessage umsg, string radio_link)
 | 
			
		||||
        public async Task Radio(string radio_link)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            if (((IGuildUser)Context.User).VoiceChannel?.Guild != channel.Guild)
 | 
			
		||||
@@ -406,14 +406,14 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
            if (channel.Guild.GetCurrentUser().GetPermissions(channel).ManageMessages)
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(10000).ConfigureAwait(false);
 | 
			
		||||
                await ((IUserMessage)umsg).DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                await Context.Message.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [OwnerOnly]
 | 
			
		||||
        public async Task Local(IUserMessage umsg, [Remainder] string path)
 | 
			
		||||
        public async Task Local([Remainder] string path)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            var arg = path;
 | 
			
		||||
@@ -438,7 +438,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [Priority(0)]
 | 
			
		||||
        public async Task Remove(IUserMessage umsg, int num)
 | 
			
		||||
        public async Task Remove(int num)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -459,7 +459,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [Priority(1)]
 | 
			
		||||
        public async Task Remove(IUserMessage umsg, string all)
 | 
			
		||||
        public async Task Remove(string all)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -474,7 +474,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task MoveSong(IUserMessage umsg, [Remainder] string fromto)
 | 
			
		||||
        public async Task MoveSong([Remainder] string fromto)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
@@ -502,14 +502,14 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
            playlist.Insert(n2 - 1, s);
 | 
			
		||||
            var nn1 = n2 < n1 ? n1 : n1 - 1;
 | 
			
		||||
            playlist.RemoveAt(nn1);
 | 
			
		||||
	    
 | 
			
		||||
	    var embed = new EmbedBuilder()
 | 
			
		||||
	    	.WithTitle($"{s.SongInfo.Title.TrimTo(70)}")
 | 
			
		||||
		.WithUrl($"{s.SongInfo.Query}")
 | 
			
		||||
		.WithAuthor(eab => eab.WithName("Song Moved").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png"))
 | 
			
		||||
		.AddField(fb => fb.WithName("**From Position**").WithValue($"#{n1}").WithIsInline(true))
 | 
			
		||||
		.AddField(fb => fb.WithName("**To Position**").WithValue($"#{n2}").WithIsInline(true))
 | 
			
		||||
		.WithColor(NadekoBot.OkColor);
 | 
			
		||||
        
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
            .WithTitle($"{s.SongInfo.Title.TrimTo(70)}")
 | 
			
		||||
        .WithUrl($"{s.SongInfo.Query}")
 | 
			
		||||
        .WithAuthor(eab => eab.WithName("Song Moved").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png"))
 | 
			
		||||
        .AddField(fb => fb.WithName("**From Position**").WithValue($"#{n1}").WithIsInline(true))
 | 
			
		||||
        .AddField(fb => fb.WithName("**To Position**").WithValue($"#{n2}").WithIsInline(true))
 | 
			
		||||
        .WithColor(NadekoBot.OkColor);
 | 
			
		||||
            await channel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            //await channel.SendConfirmAsync($"🎵Moved {s.PrettyName} `from #{n1} to #{n2}`").ConfigureAwait(false);
 | 
			
		||||
@@ -519,7 +519,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task SetMaxQueue(IUserMessage umsg, uint size)
 | 
			
		||||
        public async Task SetMaxQueue(uint size)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
@@ -563,7 +563,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Save(IUserMessage umsg, [Remainder] string name)
 | 
			
		||||
        public async Task Save([Remainder] string name)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
@@ -599,7 +599,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Load(IUserMessage umsg, [Remainder] int id)
 | 
			
		||||
        public async Task Load([Remainder] int id)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -632,7 +632,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Playlists(IUserMessage umsg, [Remainder] int num = 1)
 | 
			
		||||
        public async Task Playlists([Remainder] int num = 1)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -654,7 +654,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
        //todo only author or owner
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task DeletePlaylist(IUserMessage umsg, [Remainder] int id)
 | 
			
		||||
        public async Task DeletePlaylist([Remainder] int id)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -692,7 +692,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Goto(IUserMessage umsg, int time)
 | 
			
		||||
        public async Task Goto(int time)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
@@ -729,7 +729,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task GetLink(IUserMessage umsg, int index = 0)
 | 
			
		||||
        public async Task GetLink(int index = 0)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            MusicPlayer musicPlayer;
 | 
			
		||||
@@ -797,7 +797,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
                }
 | 
			
		||||
                var mp = new MusicPlayer(voiceCh, vol);
 | 
			
		||||
                IUserMessage playingMessage = null;
 | 
			
		||||
		IUserMessage lastFinishedMessage = null;
 | 
			
		||||
        IUserMessage lastFinishedMessage = null;
 | 
			
		||||
                mp.OnCompleted += async (s, song) =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (song.PrintStatusMessage)
 | 
			
		||||
@@ -829,7 +829,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
                        try { playingMessage = await textCh.SendConfirmAsync(msgTxt).ConfigureAwait(false); } catch { }
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
		mp.OnPauseChanged += async (paused) =>
 | 
			
		||||
        mp.OnPauseChanged += async (paused) =>
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -21,11 +21,8 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Hentai(IUserMessage umsg, [Remainder] string tag = null)
 | 
			
		||||
        public async Task Hentai([Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
 | 
			
		||||
            tag = "rating%3Aexplicit+" + tag;
 | 
			
		||||
@@ -51,17 +48,14 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
            }
 | 
			
		||||
            var link = await provider.ConfigureAwait(false);
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(link))
 | 
			
		||||
                await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
            else
 | 
			
		||||
                await channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task HentaiBomb(IUserMessage umsg, [Remainder] string tag = null)
 | 
			
		||||
        public async Task HentaiBomb([Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            tag = "rating%3Aexplicit+" + tag;
 | 
			
		||||
 | 
			
		||||
@@ -72,11 +66,11 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
 | 
			
		||||
            if (links.All(l => l == null))
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await channel.SendMessageAsync(String.Join("\n\n", links)).ConfigureAwait(false);
 | 
			
		||||
            await Context.Channel.SendMessageAsync(String.Join("\n\n", links)).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public static async Task<string> GetYandereImageLink(string tag)
 | 
			
		||||
@@ -99,103 +93,80 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Yandere(IUserMessage umsg, [Remainder] string tag = null)
 | 
			
		||||
        public async Task Yandere([Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetYandereImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(link))
 | 
			
		||||
                await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
            else
 | 
			
		||||
                await channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Danbooru(IUserMessage umsg, [Remainder] string tag = null)
 | 
			
		||||
        public async Task Danbooru([Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetDanbooruImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(link))
 | 
			
		||||
                await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
            else
 | 
			
		||||
                await channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Konachan(IUserMessage umsg, [Remainder] string tag = null)
 | 
			
		||||
        public async Task Konachan([Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetKonachanImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(link))
 | 
			
		||||
                await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
            else
 | 
			
		||||
                await channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Gelbooru(IUserMessage umsg, [Remainder] string tag = null)
 | 
			
		||||
        public async Task Gelbooru([Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetGelbooruImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(link))
 | 
			
		||||
                await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
            else
 | 
			
		||||
                await channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Rule34(IUserMessage umsg, [Remainder] string tag = null)
 | 
			
		||||
        public async Task Rule34([Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetRule34ImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(link))
 | 
			
		||||
                await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
            else
 | 
			
		||||
                await channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task E621(IUserMessage umsg, [Remainder] string tag = null)
 | 
			
		||||
        public async Task E621([Remainder] string tag = null)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            tag = tag?.Trim() ?? "";
 | 
			
		||||
            var link = await GetE621ImageLink(tag).ConfigureAwait(false);
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(link))
 | 
			
		||||
                await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false);
 | 
			
		||||
            else
 | 
			
		||||
                await channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendMessageAsync(link).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Cp()
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            await channel.SendMessageAsync("http://i.imgur.com/MZkY1md.jpg").ConfigureAwait(false);
 | 
			
		||||
            await Context.Channel.SendMessageAsync("http://i.imgur.com/MZkY1md.jpg").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Boobs()
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                JToken obj;
 | 
			
		||||
@@ -203,20 +174,17 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
                {
 | 
			
		||||
                    obj = JArray.Parse(await http.GetStringAsync($"http://api.oboobs.ru/boobs/{ new NadekoRandom().Next(0, 10229) }").ConfigureAwait(false))[0];
 | 
			
		||||
                }
 | 
			
		||||
                await channel.SendMessageAsync($"http://media.oboobs.ru/{ obj["preview"].ToString() }").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendMessageAsync($"http://media.oboobs.ru/{ obj["preview"].ToString() }").ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendErrorAsync(ex.Message).ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendErrorAsync(ex.Message).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Butts()
 | 
			
		||||
        {
 | 
			
		||||
            var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                JToken obj;
 | 
			
		||||
@@ -224,11 +192,11 @@ namespace NadekoBot.Modules.NSFW
 | 
			
		||||
                {
 | 
			
		||||
                    obj = JArray.Parse(await http.GetStringAsync($"http://api.obutts.ru/butts/{ new NadekoRandom().Next(0, 4222) }").ConfigureAwait(false))[0];
 | 
			
		||||
                }
 | 
			
		||||
                await channel.SendMessageAsync($"http://media.obutts.ru/{ obj["preview"].ToString() }").ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendMessageAsync($"http://media.obutts.ru/{ obj["preview"].ToString() }").ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                await channel.SendErrorAsync(ex.Message).ConfigureAwait(false);
 | 
			
		||||
                await Context.Channel.SendErrorAsync(ex.Message).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Permissions
 | 
			
		||||
                    {
 | 
			
		||||
                        var cc = new CommandCooldown()
 | 
			
		||||
                        {
 | 
			
		||||
                            CommandName = command.Text.ToLowerInvariant(),
 | 
			
		||||
                            CommandName = command.Aliases.First().ToLowerInvariant(),
 | 
			
		||||
                            Seconds = secs,
 | 
			
		||||
                        };
 | 
			
		||||
                        config.CommandCooldowns.Add(cc);
 | 
			
		||||
@@ -67,7 +67,7 @@ namespace NadekoBot.Modules.Permissions
 | 
			
		||||
                if (secs == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    var activeCds = activeCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<ActiveCooldown>());
 | 
			
		||||
                    activeCds.RemoveWhere(ac => ac.Command == command.Text.ToLowerInvariant());
 | 
			
		||||
                    activeCds.RemoveWhere(ac => ac.Command == command.Aliases.First().ToLowerInvariant());
 | 
			
		||||
                    await channel.SendConfirmAsync($"🚮 Command **{command}** has no coooldown now and all existing cooldowns have been cleared.")
 | 
			
		||||
                                 .ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
@@ -91,16 +91,16 @@ namespace NadekoBot.Modules.Permissions
 | 
			
		||||
                    await channel.SendTableAsync("", localSet.Select(c => c.CommandName + ": " + c.Seconds + " secs"), s => $"{s,-30}", 2).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public static bool HasCooldown(Command cmd, IGuild guild, IUser user)
 | 
			
		||||
            public static bool HasCooldown(CommandInfo cmd, IGuild guild, IUser user)
 | 
			
		||||
            {
 | 
			
		||||
                if (guild == null)
 | 
			
		||||
                    return false;
 | 
			
		||||
                var cmdcds = CmdCdsCommands.commandCooldowns.GetOrAdd(guild.Id, new ConcurrentHashSet<CommandCooldown>());
 | 
			
		||||
                CommandCooldown cdRule;
 | 
			
		||||
                if ((cdRule = cmdcds.FirstOrDefault(cc => cc.CommandName == cmd.Text.ToLowerInvariant())) != null)
 | 
			
		||||
                if ((cdRule = cmdcds.FirstOrDefault(cc => cc.CommandName == cmd.Aliases.First().ToLowerInvariant())) != null)
 | 
			
		||||
                {
 | 
			
		||||
                    var activeCdsForGuild = activeCooldowns.GetOrAdd(guild.Id, new ConcurrentHashSet<ActiveCooldown>());
 | 
			
		||||
                    if (activeCdsForGuild.FirstOrDefault(ac => ac.UserId == user.Id && ac.Command == cmd.Text.ToLowerInvariant()) != null)
 | 
			
		||||
                    if (activeCdsForGuild.FirstOrDefault(ac => ac.UserId == user.Id && ac.Command == cmd.Aliases.First().ToLowerInvariant()) != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
@@ -109,14 +109,14 @@ namespace NadekoBot.Modules.Permissions
 | 
			
		||||
                        activeCdsForGuild.Add(new ActiveCooldown()
 | 
			
		||||
                        {
 | 
			
		||||
                            UserId = user.Id,
 | 
			
		||||
                            Command = cmd.Text.ToLowerInvariant(),
 | 
			
		||||
                            Command = cmd.Aliases.First().ToLowerInvariant(),
 | 
			
		||||
                        });
 | 
			
		||||
                        var t = Task.Run(async () =>
 | 
			
		||||
                        {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await Task.Delay(cdRule.Seconds * 1000);
 | 
			
		||||
                                activeCdsForGuild.RemoveWhere(ac => ac.Command == cmd.Text.ToLowerInvariant() && ac.UserId == user.Id);
 | 
			
		||||
                                activeCdsForGuild.RemoveWhere(ac => ac.Command == cmd.Aliases.First().ToLowerInvariant() && ac.UserId == user.Id);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch { }
 | 
			
		||||
                        });
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user