1.4-alpha builds and runs, for now
This commit is contained in:
		@@ -33,13 +33,12 @@ namespace NadekoBot.Attributes
 | 
			
		||||
 | 
			
		||||
        private static string GetModulePrefix(string moduleName, string defaultPrefix)
 | 
			
		||||
        {
 | 
			
		||||
            string prefix = null;
 | 
			
		||||
            if (!ModulePrefixes.TryGetValue(moduleName, out prefix))
 | 
			
		||||
            if (!ModulePrefixes.TryGetValue(moduleName, out string prefix))
 | 
			
		||||
            {
 | 
			
		||||
                NadekoBot.ModulePrefixes.TryAdd(moduleName, defaultPrefix);
 | 
			
		||||
                NLog.LogManager.GetCurrentClassLogger().Warn("Prefix not found for {0}. Will use default one: {1}", moduleName, defaultPrefix);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            return prefix ?? defaultPrefix;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
    [NadekoModule("Administration", ".")]
 | 
			
		||||
    public partial class Administration : NadekoTopLevelModule
 | 
			
		||||
    {
 | 
			
		||||
        private static ConcurrentHashSet<ulong> deleteMessagesOnCommand { get; }
 | 
			
		||||
        private static readonly ConcurrentHashSet<ulong> deleteMessagesOnCommand;
 | 
			
		||||
 | 
			
		||||
        private new static readonly Logger _log;
 | 
			
		||||
 | 
			
		||||
@@ -122,7 +122,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                return;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await usr.AddRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                await usr.AddRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                await ReplyConfirmLocalized("setrole", Format.Bold(role.Name), Format.Bold(usr.ToString()))
 | 
			
		||||
                    .ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
@@ -144,7 +144,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                return;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await usr.RemoveRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                await usr.RemoveRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                await ReplyConfirmLocalized("remrole", Format.Bold(role.Name), Format.Bold(usr.ToString())).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
 
 | 
			
		||||
@@ -17,20 +17,19 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        public class AutoAssignRoleCommands : NadekoSubmodule
 | 
			
		||||
        {
 | 
			
		||||
            //guildid/roleid
 | 
			
		||||
            private static ConcurrentDictionary<ulong, ulong> autoAssignedRoles { get; }
 | 
			
		||||
            private static ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; }
 | 
			
		||||
 | 
			
		||||
            static AutoAssignRoleCommands()
 | 
			
		||||
            {
 | 
			
		||||
                var log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
 | 
			
		||||
                autoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0)
 | 
			
		||||
                AutoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0)
 | 
			
		||||
                    .ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId));
 | 
			
		||||
                NadekoBot.Client.UserJoined += async (user) =>
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        ulong roleId;
 | 
			
		||||
                        autoAssignedRoles.TryGetValue(user.Guild.Id, out roleId);
 | 
			
		||||
                        AutoAssignedRoles.TryGetValue(user.Guild.Id, out ulong roleId);
 | 
			
		||||
 | 
			
		||||
                        if (roleId == 0)
 | 
			
		||||
                            return;
 | 
			
		||||
@@ -38,7 +37,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        var role = user.Guild.Roles.FirstOrDefault(r => r.Id == roleId);
 | 
			
		||||
 | 
			
		||||
                        if (role != null)
 | 
			
		||||
                            await user.AddRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                            await user.AddRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex) { log.Warn(ex); }
 | 
			
		||||
                };
 | 
			
		||||
@@ -60,13 +59,12 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    if (role == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        conf.AutoAssignRoleId = 0;
 | 
			
		||||
                        ulong throwaway;
 | 
			
		||||
                        autoAssignedRoles.TryRemove(Context.Guild.Id, out throwaway);
 | 
			
		||||
                        AutoAssignedRoles.TryRemove(Context.Guild.Id, out ulong throwaway);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        conf.AutoAssignRoleId = role.Id;
 | 
			
		||||
                        autoAssignedRoles.AddOrUpdate(Context.Guild.Id, role.Id, (key, val) => role.Id);
 | 
			
		||||
                        AutoAssignedRoles.AddOrUpdate(Context.Guild.Id, role.Id, (key, val) => role.Id);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    await uow.CompleteAsync().ConfigureAwait(false);
 | 
			
		||||
 
 | 
			
		||||
@@ -22,23 +22,23 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class LogCommands : NadekoSubmodule
 | 
			
		||||
        {
 | 
			
		||||
            private static DiscordShardedClient client { get; }
 | 
			
		||||
            private static DiscordShardedClient Client { get; }
 | 
			
		||||
            private new static Logger _log { get; }
 | 
			
		||||
 | 
			
		||||
            private static string prettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】";
 | 
			
		||||
            private static string currentTime => $"{DateTime.Now:HH:mm:ss}";
 | 
			
		||||
            private static string PrettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】";
 | 
			
		||||
            private static string CurrentTime => $"{DateTime.Now:HH:mm:ss}";
 | 
			
		||||
 | 
			
		||||
            public static ConcurrentDictionary<ulong, LogSetting> GuildLogSettings { get; }
 | 
			
		||||
 | 
			
		||||
            private static ConcurrentDictionary<ITextChannel, List<string>> presenceUpdates { get; } = new ConcurrentDictionary<ITextChannel, List<string>>();
 | 
			
		||||
            private static ConcurrentDictionary<ITextChannel, List<string>> PresenceUpdates { get; } = new ConcurrentDictionary<ITextChannel, List<string>>();
 | 
			
		||||
            private static readonly Timer _timerReference;
 | 
			
		||||
 | 
			
		||||
            static LogCommands()
 | 
			
		||||
            {
 | 
			
		||||
                client = NadekoBot.Client;
 | 
			
		||||
                Client = NadekoBot.Client;
 | 
			
		||||
                _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
                var sw = Stopwatch.StartNew();
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                GuildLogSettings = new ConcurrentDictionary<ulong, LogSetting>(NadekoBot.AllGuildConfigs
 | 
			
		||||
                    .ToDictionary(g => g.GuildId, g => g.LogSetting));
 | 
			
		||||
 | 
			
		||||
@@ -46,12 +46,11 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        var keys = presenceUpdates.Keys.ToList();
 | 
			
		||||
                        var keys = PresenceUpdates.Keys.ToList();
 | 
			
		||||
 | 
			
		||||
                        await Task.WhenAll(keys.Select(async key =>
 | 
			
		||||
                        {
 | 
			
		||||
                            List<string> messages;
 | 
			
		||||
                            if (presenceUpdates.TryRemove(key, out messages))
 | 
			
		||||
                            if (PresenceUpdates.TryRemove(key, out List<string> messages))
 | 
			
		||||
                                try { await key.SendConfirmAsync(key.Guild.GetLogText("presence_updates"), string.Join(Environment.NewLine, messages)); }
 | 
			
		||||
                                catch
 | 
			
		||||
                                {
 | 
			
		||||
@@ -69,22 +68,22 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
 | 
			
		||||
 | 
			
		||||
                //_client.MessageReceived += _client_MessageReceived;
 | 
			
		||||
                client.MessageUpdated += _client_MessageUpdated;
 | 
			
		||||
                client.MessageDeleted += _client_MessageDeleted;
 | 
			
		||||
                client.UserBanned += _client_UserBanned;
 | 
			
		||||
                client.UserUnbanned += _client_UserUnbanned;
 | 
			
		||||
                client.UserJoined += _client_UserJoined;
 | 
			
		||||
                client.UserLeft += _client_UserLeft;
 | 
			
		||||
                client.UserPresenceUpdated += _client_UserPresenceUpdated;
 | 
			
		||||
                client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
 | 
			
		||||
                client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS;
 | 
			
		||||
                client.GuildMemberUpdated += _client_GuildUserUpdated;
 | 
			
		||||
                Client.MessageUpdated += _client_MessageUpdated;
 | 
			
		||||
                Client.MessageDeleted += _client_MessageDeleted;
 | 
			
		||||
                Client.UserBanned += _client_UserBanned;
 | 
			
		||||
                Client.UserUnbanned += _client_UserUnbanned;
 | 
			
		||||
                Client.UserJoined += _client_UserJoined;
 | 
			
		||||
                Client.UserLeft += _client_UserLeft;
 | 
			
		||||
                Client.UserPresenceUpdated += _client_UserPresenceUpdated;
 | 
			
		||||
                Client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
 | 
			
		||||
                Client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS;
 | 
			
		||||
                Client.GuildMemberUpdated += _client_GuildUserUpdated;
 | 
			
		||||
#if !GLOBAL_NADEKO
 | 
			
		||||
                client.UserUpdated += _client_UserUpdated;
 | 
			
		||||
                Client.UserUpdated += _client_UserUpdated;
 | 
			
		||||
#endif
 | 
			
		||||
                client.ChannelCreated += _client_ChannelCreated;
 | 
			
		||||
                client.ChannelDestroyed += _client_ChannelDestroyed;
 | 
			
		||||
                client.ChannelUpdated += _client_ChannelUpdated;
 | 
			
		||||
                Client.ChannelCreated += _client_ChannelCreated;
 | 
			
		||||
                Client.ChannelDestroyed += _client_ChannelDestroyed;
 | 
			
		||||
                Client.ChannelUpdated += _client_ChannelUpdated;
 | 
			
		||||
 | 
			
		||||
                MuteCommands.UserMuted += MuteCommands_UserMuted;
 | 
			
		||||
                MuteCommands.UserUnmuted += MuteCommands_UserUnmuted;
 | 
			
		||||
@@ -101,8 +100,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
                    var g = after.Guild;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(g.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(g.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.UserUpdatedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
@@ -119,16 +117,16 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                            .WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
 | 
			
		||||
                            .AddField(fb => fb.WithName("Old Name").WithValue($"{before.Username}").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName("New Name").WithValue($"{after.Username}").WithIsInline(true))
 | 
			
		||||
                            .WithFooter(fb => fb.WithText(currentTime))
 | 
			
		||||
                            .WithFooter(fb => fb.WithText(CurrentTime))
 | 
			
		||||
                            .WithOkColor();
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (before.AvatarUrl != after.AvatarUrl)
 | 
			
		||||
                    else if (before.AvatarId != after.AvatarId)
 | 
			
		||||
                    {
 | 
			
		||||
                        embed.WithTitle("👥" + g.GetLogText("avatar_changed"))
 | 
			
		||||
                            .WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
 | 
			
		||||
                            .WithThumbnailUrl(before.AvatarUrl)
 | 
			
		||||
                            .WithImageUrl(after.AvatarUrl)
 | 
			
		||||
                            .WithFooter(fb => fb.WithText(currentTime))
 | 
			
		||||
                            .WithThumbnailUrl(before.GetAvatarUrl())
 | 
			
		||||
                            .WithImageUrl(after.GetAvatarUrl())
 | 
			
		||||
                            .WithFooter(fb => fb.WithText(CurrentTime))
 | 
			
		||||
                            .WithOkColor();
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
@@ -173,8 +171,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    if (beforeVch == afterVch)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.LogVoicePresenceTTSId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
@@ -208,8 +205,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.UserMutedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
@@ -233,7 +229,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
                    var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName(mutes))
 | 
			
		||||
                            .WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
 | 
			
		||||
                            .WithFooter(fb => fb.WithText(currentTime))
 | 
			
		||||
                            .WithFooter(fb => fb.WithText(CurrentTime))
 | 
			
		||||
                            .WithOkColor();
 | 
			
		||||
 | 
			
		||||
                    await logChannel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
@@ -248,8 +244,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.UserMutedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
@@ -274,7 +269,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
                    var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName(mutes))
 | 
			
		||||
                            .WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
 | 
			
		||||
                            .WithFooter(fb => fb.WithText($"{currentTime}"))
 | 
			
		||||
                            .WithFooter(fb => fb.WithText($"{CurrentTime}"))
 | 
			
		||||
                            .WithOkColor();
 | 
			
		||||
 | 
			
		||||
                    await logChannel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
@@ -292,8 +287,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    if (users.Length == 0)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(users.First().Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(users.First().Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.LogOtherId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
@@ -320,7 +314,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName($"🛡 Anti-{protection}"))
 | 
			
		||||
                            .WithTitle(logChannel.Guild.GetLogText("users") + " " + punishment)
 | 
			
		||||
                            .WithDescription(string.Join("\n", users.Select(u => u.ToString())))
 | 
			
		||||
                            .WithFooter(fb => fb.WithText($"{currentTime}"))
 | 
			
		||||
                            .WithFooter(fb => fb.WithText($"{CurrentTime}"))
 | 
			
		||||
                            .WithOkColor();
 | 
			
		||||
 | 
			
		||||
                    await logChannel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
@@ -335,15 +329,14 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(before.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(before.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.UserUpdatedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(currentTime))
 | 
			
		||||
                    var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(CurrentTime))
 | 
			
		||||
                        .WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}");
 | 
			
		||||
                    if (before.Nickname != after.Nickname)
 | 
			
		||||
                    {
 | 
			
		||||
@@ -352,17 +345,17 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                            .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_nick")).WithValue($"{before.Nickname}#{before.Discriminator}"))
 | 
			
		||||
                            .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_nick")).WithValue($"{after.Nickname}#{after.Discriminator}"));
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (!before.RoleIds.SequenceEqual(after.RoleIds))
 | 
			
		||||
                    else if (!before.Roles.SequenceEqual(after.Roles))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (before.RoleIds.Count < after.RoleIds.Count)
 | 
			
		||||
                        if (before.Roles.Count < after.Roles.Count)
 | 
			
		||||
                        {
 | 
			
		||||
                            var diffRoles = after.RoleIds.Where(r => !before.RoleIds.Contains(r)).Select(r => before.Guild.GetRole(r).Name);
 | 
			
		||||
                            var diffRoles = after.Roles.Where(r => !before.Roles.Contains(r)).Select(r => r.Name);
 | 
			
		||||
                            embed.WithAuthor(eab => eab.WithName("⚔ " + logChannel.Guild.GetLogText("user_role_add")))
 | 
			
		||||
                                .WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (before.RoleIds.Count > after.RoleIds.Count)
 | 
			
		||||
                        else if (before.Roles.Count > after.Roles.Count)
 | 
			
		||||
                        {
 | 
			
		||||
                            var diffRoles = before.RoleIds.Where(r => !after.RoleIds.Contains(r)).Select(r => before.Guild.GetRole(r).Name);
 | 
			
		||||
                            var diffRoles = before.Roles.Where(r => !after.Roles.Contains(r)).Select(r => r.Name);
 | 
			
		||||
                            embed.WithAuthor(eab => eab.WithName("⚔ " + logChannel.Guild.GetLogText("user_role_rem")))
 | 
			
		||||
                                .WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
 | 
			
		||||
                        }
 | 
			
		||||
@@ -386,8 +379,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        return;
 | 
			
		||||
                    var after = (IGuildChannel)cafter;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(before.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(before.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.ChannelUpdatedId == null)
 | 
			
		||||
                        || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == after.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
@@ -396,7 +388,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.ChannelUpdated)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(currentTime));
 | 
			
		||||
                    var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText(CurrentTime));
 | 
			
		||||
 | 
			
		||||
                    var beforeTextChannel = cbefore as ITextChannel;
 | 
			
		||||
                    var afterTextChannel = cafter as ITextChannel;
 | 
			
		||||
@@ -433,8 +425,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    if (ch == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.ChannelDestroyedId == null)
 | 
			
		||||
                        || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == ch.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
@@ -453,7 +444,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithTitle("🆕 " + title)
 | 
			
		||||
                        .WithDescription($"{ch.Name} | {ch.Id}")
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
@@ -469,8 +460,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    if (ch == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.ChannelCreatedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
@@ -488,7 +478,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithTitle("🆕 " + title)
 | 
			
		||||
                        .WithDescription($"{ch.Name} | {ch.Id}")
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
@@ -507,8 +497,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    if (beforeVch == afterVch)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.LogVoicePresenceId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
@@ -519,24 +508,24 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    string str = null;
 | 
			
		||||
                    if (beforeVch?.Guild == afterVch?.Guild)
 | 
			
		||||
                    {
 | 
			
		||||
                        str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vmoved",
 | 
			
		||||
                        str = "🎙" + Format.Code(PrettyCurrentTime) + logChannel.Guild.GetLogText("user_vmoved",
 | 
			
		||||
                                "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
 | 
			
		||||
                                Format.Bold(beforeVch?.Name ?? ""), Format.Bold(afterVch?.Name ?? ""));
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (beforeVch == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vjoined",
 | 
			
		||||
                        str = "🎙" + Format.Code(PrettyCurrentTime) + logChannel.Guild.GetLogText("user_vjoined",
 | 
			
		||||
                                "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
 | 
			
		||||
                                Format.Bold(afterVch.Name ?? ""));
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (afterVch == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vleft",
 | 
			
		||||
                        str = "🎙" + Format.Code(PrettyCurrentTime) + logChannel.Guild.GetLogText("user_vleft",
 | 
			
		||||
                                "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
 | 
			
		||||
                                Format.Bold(beforeVch.Name ?? ""));
 | 
			
		||||
                    }
 | 
			
		||||
                    if (str != null)
 | 
			
		||||
                        presenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
 | 
			
		||||
                        PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
@@ -553,8 +542,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    if (guild == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.LogUserPresenceId == null)
 | 
			
		||||
                        || before.Status == after.Status)
 | 
			
		||||
                        return;
 | 
			
		||||
@@ -564,7 +552,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        return;
 | 
			
		||||
                    string str = "";
 | 
			
		||||
                    if (before.Status != after.Status)
 | 
			
		||||
                        str = "🎭" + Format.Code(prettyCurrentTime) +
 | 
			
		||||
                        str = "🎭" + Format.Code(PrettyCurrentTime) +
 | 
			
		||||
                              logChannel.Guild.GetLogText("user_status_change",
 | 
			
		||||
                                    "👤" + Format.Bold(usr.Username),
 | 
			
		||||
                                    Format.Bold(after.Status.ToString()));
 | 
			
		||||
@@ -576,7 +564,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    //    str += $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game?.Name}**.";
 | 
			
		||||
                    //}
 | 
			
		||||
 | 
			
		||||
                    presenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
 | 
			
		||||
                    PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
@@ -588,8 +576,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.UserLeftId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
@@ -600,10 +587,10 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    await logChannel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithTitle("❌ " + logChannel.Guild.GetLogText("user_left"))
 | 
			
		||||
                        .WithThumbnailUrl(usr.AvatarUrl)
 | 
			
		||||
                        .WithThumbnailUrl(usr.GetAvatarUrl())
 | 
			
		||||
                        .WithDescription(usr.ToString())
 | 
			
		||||
                        .AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
@@ -615,8 +602,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.UserJoinedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
@@ -627,10 +613,10 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    await logChannel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithTitle("✅ " + logChannel.Guild.GetLogText("user_joined"))
 | 
			
		||||
                        .WithThumbnailUrl(usr.AvatarUrl)
 | 
			
		||||
                        .WithThumbnailUrl(usr.GetAvatarUrl())
 | 
			
		||||
                        .WithDescription($"{usr}")
 | 
			
		||||
                        .AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
@@ -639,8 +625,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.UserUnbannedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
@@ -651,10 +636,10 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    await logChannel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithTitle("♻️ " + logChannel.Guild.GetLogText("user_unbanned"))
 | 
			
		||||
                        .WithThumbnailUrl(usr.AvatarUrl)
 | 
			
		||||
                        .WithThumbnailUrl(usr.GetAvatarUrl())
 | 
			
		||||
                        .WithDescription(usr.ToString())
 | 
			
		||||
                        .AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
@@ -663,8 +648,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.UserBannedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
@@ -674,29 +658,28 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    await logChannel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithTitle("🚫 " + logChannel.Guild.GetLogText("user_banned"))
 | 
			
		||||
                        .WithThumbnailUrl(usr.AvatarUrl)
 | 
			
		||||
                        .WithThumbnailUrl(usr.GetAvatarUrl())
 | 
			
		||||
                        .WithDescription(usr.ToString())
 | 
			
		||||
                        .AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(CurrentTime))).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private static async Task _client_MessageDeleted(ulong arg1, Optional<SocketMessage> imsg)
 | 
			
		||||
            private static async Task _client_MessageDeleted(Cacheable<IMessage, ulong> optMsg, ISocketMessageChannel ch)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var msg = (imsg.IsSpecified ? imsg.Value : null) as IUserMessage;
 | 
			
		||||
                    var msg = (optMsg.HasValue ? optMsg.Value : null) as IUserMessage;
 | 
			
		||||
                    if (msg == null || msg.IsAuthor())
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var channel = msg.Channel as ITextChannel;
 | 
			
		||||
                    var channel = ch as ITextChannel;
 | 
			
		||||
                    if (channel == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.MessageDeletedId == null)
 | 
			
		||||
                        || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == channel.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
@@ -710,7 +693,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        .WithDescription(msg.Author.ToString())
 | 
			
		||||
                        .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("content")).WithValue(string.IsNullOrWhiteSpace(msg.Content) ? "-" : msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
 | 
			
		||||
                        .AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false))
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(currentTime));
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(CurrentTime));
 | 
			
		||||
                    if (msg.Attachments.Any())
 | 
			
		||||
                        embed.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.Url))).WithIsInline(false));
 | 
			
		||||
 | 
			
		||||
@@ -723,7 +706,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private static async Task _client_MessageUpdated(Optional<SocketMessage> optmsg, SocketMessage imsg2)
 | 
			
		||||
            private static async Task _client_MessageUpdated(Cacheable<IMessage, ulong> optmsg, SocketMessage imsg2, ISocketMessageChannel ch)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
@@ -731,19 +714,18 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    if (after == null || after.IsAuthor())
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var before = (optmsg.IsSpecified ? optmsg.Value : null) as IUserMessage;
 | 
			
		||||
                    var before = (optmsg.HasValue ? optmsg.Value : null) as IUserMessage;
 | 
			
		||||
                    if (before == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var channel = after.Channel as ITextChannel;
 | 
			
		||||
                    var channel = ch as ITextChannel;
 | 
			
		||||
                    if (channel == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    if (before.Content == after.Content)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out logSetting)
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out LogSetting logSetting)
 | 
			
		||||
                        || (logSetting.MessageUpdatedId == null)
 | 
			
		||||
                        || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == channel.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
@@ -759,7 +741,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_msg")).WithValue(string.IsNullOrWhiteSpace(before.Content) ? "-" : before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
 | 
			
		||||
                        .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_msg")).WithValue(string.IsNullOrWhiteSpace(after.Content) ? "-" : after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
 | 
			
		||||
                        .AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false))
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(currentTime));
 | 
			
		||||
                        .WithFooter(efb => efb.WithText(CurrentTime));
 | 
			
		||||
 | 
			
		||||
                    await logChannel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,9 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class MuteCommands : NadekoSubmodule
 | 
			
		||||
        {
 | 
			
		||||
            private static ConcurrentDictionary<ulong, string> guildMuteRoles { get; }
 | 
			
		||||
            private static ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> mutedUsers { get; }
 | 
			
		||||
            private static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>> unmuteTimers { get; }
 | 
			
		||||
            private static ConcurrentDictionary<ulong, string> GuildMuteRoles { get; }
 | 
			
		||||
            private static ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> MutedUsers { get; }
 | 
			
		||||
            private static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>> UnmuteTimers { get; }
 | 
			
		||||
                = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>>();
 | 
			
		||||
 | 
			
		||||
            public static event Action<IGuildUser, MuteType> UserMuted = delegate { };
 | 
			
		||||
@@ -40,11 +40,11 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            static MuteCommands()
 | 
			
		||||
            {
 | 
			
		||||
                var configs = NadekoBot.AllGuildConfigs;
 | 
			
		||||
                guildMuteRoles = new ConcurrentDictionary<ulong, string>(configs
 | 
			
		||||
                GuildMuteRoles = new ConcurrentDictionary<ulong, string>(configs
 | 
			
		||||
                        .Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
 | 
			
		||||
                        .ToDictionary(c => c.GuildId, c => c.MuteRoleName));
 | 
			
		||||
 | 
			
		||||
                mutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(configs.ToDictionary(
 | 
			
		||||
                MutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(configs.ToDictionary(
 | 
			
		||||
                    k => k.GuildId,
 | 
			
		||||
                    v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId))
 | 
			
		||||
                ));
 | 
			
		||||
@@ -73,8 +73,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    ConcurrentHashSet<ulong> muted;
 | 
			
		||||
                    mutedUsers.TryGetValue(usr.Guild.Id, out muted);
 | 
			
		||||
                    MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted);
 | 
			
		||||
 | 
			
		||||
                    if (muted == null || !muted.Contains(usr.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
@@ -92,7 +91,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                await usr.ModifyAsync(x => x.Mute = true).ConfigureAwait(false);
 | 
			
		||||
                var muteRole = await GetMuteRole(usr.Guild);
 | 
			
		||||
                if (!usr.RoleIds.Contains(muteRole.Id))
 | 
			
		||||
                    await usr.AddRolesAsync(muteRole).ConfigureAwait(false);
 | 
			
		||||
                    await usr.AddRoleAsync(muteRole).ConfigureAwait(false);
 | 
			
		||||
                StopUnmuteTimer(usr.GuildId, usr.Id);
 | 
			
		||||
                using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                {
 | 
			
		||||
@@ -103,8 +102,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    {
 | 
			
		||||
                        UserId = usr.Id
 | 
			
		||||
                    });
 | 
			
		||||
                    ConcurrentHashSet<ulong> muted;
 | 
			
		||||
                    if (mutedUsers.TryGetValue(usr.Guild.Id, out muted))
 | 
			
		||||
                    if (MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted))
 | 
			
		||||
                        muted.Add(usr.Id);
 | 
			
		||||
 | 
			
		||||
                    config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id);
 | 
			
		||||
@@ -118,7 +116,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                StopUnmuteTimer(usr.GuildId, usr.Id);
 | 
			
		||||
                try { await usr.ModifyAsync(x => x.Mute = false).ConfigureAwait(false); } catch { }
 | 
			
		||||
                try { await usr.RemoveRolesAsync(await GetMuteRole(usr.Guild)).ConfigureAwait(false); } catch { /*ignore*/ }
 | 
			
		||||
                try { await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild)).ConfigureAwait(false); } catch { /*ignore*/ }
 | 
			
		||||
                using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                {
 | 
			
		||||
                    var config = uow.GuildConfigs.For(usr.Guild.Id, set => set.Include(gc => gc.MutedUsers)
 | 
			
		||||
@@ -127,8 +125,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    {
 | 
			
		||||
                        UserId = usr.Id
 | 
			
		||||
                    });
 | 
			
		||||
                    ConcurrentHashSet<ulong> muted;
 | 
			
		||||
                    if (mutedUsers.TryGetValue(usr.Guild.Id, out muted))
 | 
			
		||||
                    if (MutedUsers.TryGetValue(usr.Guild.Id, out ConcurrentHashSet<ulong> muted))
 | 
			
		||||
                        muted.TryRemove(usr.Id);
 | 
			
		||||
 | 
			
		||||
                    config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id);
 | 
			
		||||
@@ -142,7 +139,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                const string defaultMuteRoleName = "nadeko-mute";
 | 
			
		||||
 | 
			
		||||
                var muteRoleName = guildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName);
 | 
			
		||||
                var muteRoleName = GuildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName);
 | 
			
		||||
 | 
			
		||||
                var muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName);
 | 
			
		||||
                if (muteRole == null)
 | 
			
		||||
@@ -198,7 +195,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            public static void StartUnmuteTimer(ulong guildId, ulong userId, TimeSpan after)
 | 
			
		||||
            {
 | 
			
		||||
                //load the unmute timers for this guild
 | 
			
		||||
                var userUnmuteTimers = unmuteTimers.GetOrAdd(guildId, new ConcurrentDictionary<ulong, Timer>());
 | 
			
		||||
                var userUnmuteTimers = UnmuteTimers.GetOrAdd(guildId, new ConcurrentDictionary<ulong, Timer>());
 | 
			
		||||
 | 
			
		||||
                //unmute timer to be added
 | 
			
		||||
                var toAdd = new Timer(async _ =>
 | 
			
		||||
@@ -232,11 +229,9 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
            public static void StopUnmuteTimer(ulong guildId, ulong userId)
 | 
			
		||||
            {
 | 
			
		||||
                ConcurrentDictionary<ulong, Timer> userUnmuteTimers;
 | 
			
		||||
                if (!unmuteTimers.TryGetValue(guildId, out userUnmuteTimers)) return;
 | 
			
		||||
                if (!UnmuteTimers.TryGetValue(guildId, out ConcurrentDictionary<ulong, Timer> userUnmuteTimers)) return;
 | 
			
		||||
 | 
			
		||||
                Timer removed;
 | 
			
		||||
                if(userUnmuteTimers.TryRemove(userId, out removed))
 | 
			
		||||
                if (userUnmuteTimers.TryRemove(userId, out Timer removed))
 | 
			
		||||
                {
 | 
			
		||||
                    removed.Change(Timeout.Infinite, Timeout.Infinite);
 | 
			
		||||
                }
 | 
			
		||||
@@ -266,7 +261,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                {
 | 
			
		||||
                    var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
 | 
			
		||||
                    config.MuteRoleName = name;
 | 
			
		||||
                    guildMuteRoles.AddOrUpdate(Context.Guild.Id, name, (id, old) => name);
 | 
			
		||||
                    GuildMuteRoles.AddOrUpdate(Context.Guild.Id, name, (id, old) => name);
 | 
			
		||||
                    await uow.CompleteAsync().ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                await ReplyConfirmLocalized("mute_role_set").ConfigureAwait(false);
 | 
			
		||||
@@ -342,7 +337,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await user.AddRolesAsync(await GetMuteRole(Context.Guild).ConfigureAwait(false)).ConfigureAwait(false);
 | 
			
		||||
                    await user.AddRoleAsync(await GetMuteRole(Context.Guild).ConfigureAwait(false)).ConfigureAwait(false);
 | 
			
		||||
                    UserMuted(user, MuteType.Chat);
 | 
			
		||||
                    await ReplyConfirmLocalized("user_chat_mute", Format.Bold(user.ToString())).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
@@ -359,7 +354,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await user.RemoveRolesAsync(await GetMuteRole(Context.Guild).ConfigureAwait(false)).ConfigureAwait(false);
 | 
			
		||||
                    await user.RemoveRoleAsync(await GetMuteRole(Context.Guild).ConfigureAwait(false)).ConfigureAwait(false);
 | 
			
		||||
                    UserUnmuted(user, MuteType.Chat);
 | 
			
		||||
                    await ReplyConfirmLocalized("user_chat_unmute", Format.Bold(user.ToString())).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -73,8 +73,8 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
            public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } =
 | 
			
		||||
                new Dictionary<string, Func<string>> {
 | 
			
		||||
                    { "%servers%", () => NadekoBot.Client.GetGuildCount().ToString()},
 | 
			
		||||
                    { "%users%", () => NadekoBot.Client.GetGuilds().Sum(s => s.Users.Count).ToString()},
 | 
			
		||||
                    { "%servers%", () => NadekoBot.Client.Guilds.Count.ToString()},
 | 
			
		||||
                    { "%users%", () => NadekoBot.Client.Guilds.Sum(s => s.Users.Count).ToString()},
 | 
			
		||||
                    { "%playing%", () => {
 | 
			
		||||
                            var cnt = Music.Music.MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null);
 | 
			
		||||
                            if (cnt != 1) return cnt.ToString();
 | 
			
		||||
 
 | 
			
		||||
@@ -40,17 +40,14 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                public int MaxMessages { get; set; }
 | 
			
		||||
                public int PerSeconds { get; set; }
 | 
			
		||||
 | 
			
		||||
                public CancellationTokenSource cancelSource { get; set; } = new CancellationTokenSource();
 | 
			
		||||
                public CancellationTokenSource CancelSource { get; set; } = new CancellationTokenSource();
 | 
			
		||||
 | 
			
		||||
                public ConcurrentDictionary<ulong, RatelimitedUser> Users { get; set; } = new ConcurrentDictionary<ulong, RatelimitedUser>();
 | 
			
		||||
 | 
			
		||||
                public bool CheckUserRatelimit(ulong id, ulong guildId, SocketGuildUser optUser)
 | 
			
		||||
                {
 | 
			
		||||
                    HashSet<ulong> ignoreUsers;
 | 
			
		||||
                    HashSet<ulong> ignoreRoles;
 | 
			
		||||
 | 
			
		||||
                    if ((IgnoredUsers.TryGetValue(guildId, out ignoreUsers) && ignoreUsers.Contains(id)) || 
 | 
			
		||||
                        (optUser != null && IgnoredRoles.TryGetValue(guildId, out ignoreRoles) && optUser.RoleIds.Any(x => ignoreRoles.Contains(x))))
 | 
			
		||||
                    if ((IgnoredUsers.TryGetValue(guildId, out HashSet<ulong> ignoreUsers) && ignoreUsers.Contains(id)) ||
 | 
			
		||||
                        (optUser != null && IgnoredRoles.TryGetValue(guildId, out HashSet<ulong> ignoreRoles) && optUser.Roles.Any(x => ignoreRoles.Contains(x.Id))))
 | 
			
		||||
                        return false;
 | 
			
		||||
 | 
			
		||||
                    var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id });
 | 
			
		||||
@@ -63,7 +60,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            await Task.Delay(PerSeconds * 1000, cancelSource.Token);
 | 
			
		||||
                            await Task.Delay(PerSeconds * 1000, CancelSource.Token);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (OperationCanceledException) { }
 | 
			
		||||
                        usr.MessageCount--;
 | 
			
		||||
@@ -95,8 +92,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
                         if (channel == null || usrMsg.IsAuthor())
 | 
			
		||||
                             return;
 | 
			
		||||
                         Ratelimiter limiter;
 | 
			
		||||
                         if (!RatelimitingChannels.TryGetValue(channel.Id, out limiter))
 | 
			
		||||
                         if (!RatelimitingChannels.TryGetValue(channel.Id, out Ratelimiter limiter))
 | 
			
		||||
                             return;
 | 
			
		||||
 | 
			
		||||
                         if (limiter.CheckUserRatelimit(usrMsg.Author.Id, channel.Guild.Id, usrMsg.Author as SocketGuildUser))
 | 
			
		||||
@@ -111,10 +107,9 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            [RequireUserPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
            public async Task Slowmode()
 | 
			
		||||
            {
 | 
			
		||||
                Ratelimiter throwaway;
 | 
			
		||||
                if (RatelimitingChannels.TryRemove(Context.Channel.Id, out throwaway))
 | 
			
		||||
                if (RatelimitingChannels.TryRemove(Context.Channel.Id, out Ratelimiter throwaway))
 | 
			
		||||
                {
 | 
			
		||||
                    throwaway.cancelSource.Cancel();
 | 
			
		||||
                    throwaway.CancelSource.Cancel();
 | 
			
		||||
                    await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -185,7 +185,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        var sameRole = Context.Guild.GetRole(sameRoleId);
 | 
			
		||||
                        if (sameRole != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            await guildUser.RemoveRolesAsync(sameRole).ConfigureAwait(false);
 | 
			
		||||
                            await guildUser.RemoveRoleAsync(sameRole).ConfigureAwait(false);
 | 
			
		||||
                            await Task.Delay(500).ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        //await ReplyErrorLocalized("self_assign_already_excl", Format.Bold(sameRole?.Name)).ConfigureAwait(false);
 | 
			
		||||
@@ -194,7 +194,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                }
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await guildUser.AddRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                    await guildUser.AddRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
@@ -236,7 +236,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                }
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await guildUser.RemoveRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                    await guildUser.RemoveRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception)
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -289,7 +289,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyConfirmLocalized("shard_reconnecting", Format.Bold("#" + shardid)).ConfigureAwait(false);
 | 
			
		||||
                    await shard.ConnectAsync().ConfigureAwait(false);
 | 
			
		||||
                    await shard.StartAsync().ConfigureAwait(false);
 | 
			
		||||
                    await ReplyConfirmLocalized("shard_reconnected", Format.Bold("#" + shardid)).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
@@ -303,8 +303,8 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            public async Task Leave([Remainder] string guildStr)
 | 
			
		||||
            {
 | 
			
		||||
                guildStr = guildStr.Trim().ToUpperInvariant();
 | 
			
		||||
                var server = NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Id.ToString() == guildStr) ??
 | 
			
		||||
                    NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == guildStr);
 | 
			
		||||
                var server = NadekoBot.Client.Guilds.FirstOrDefault(g => g.Id.ToString() == guildStr) ??
 | 
			
		||||
                    NadekoBot.Client.Guilds.FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == guildStr);
 | 
			
		||||
 | 
			
		||||
                if (server == null)
 | 
			
		||||
                {
 | 
			
		||||
@@ -414,7 +414,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                if (ids.Length != 2)
 | 
			
		||||
                    return;
 | 
			
		||||
                var sid = ulong.Parse(ids[0]);
 | 
			
		||||
                var server = NadekoBot.Client.GetGuilds().FirstOrDefault(s => s.Id == sid);
 | 
			
		||||
                var server = NadekoBot.Client.Guilds.FirstOrDefault(s => s.Id == sid);
 | 
			
		||||
 | 
			
		||||
                if (server == null)
 | 
			
		||||
                    return;
 | 
			
		||||
@@ -451,7 +451,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            [OwnerOnly]
 | 
			
		||||
            public async Task Announce([Remainder] string message)
 | 
			
		||||
            {
 | 
			
		||||
                var channels = NadekoBot.Client.GetGuilds().Select(g => g.DefaultChannel).ToArray();
 | 
			
		||||
                var channels = NadekoBot.Client.Guilds.Select(g => g.DefaultChannel).ToArray();
 | 
			
		||||
                if (channels == null)
 | 
			
		||||
                    return;
 | 
			
		||||
                await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync(GetText("message_from_bo", Context.User.ToString()), message)))
 | 
			
		||||
 
 | 
			
		||||
@@ -18,12 +18,12 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class VcRoleCommands : NadekoSubmodule
 | 
			
		||||
        {
 | 
			
		||||
            private static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> vcRoles { get; }
 | 
			
		||||
            private static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; }
 | 
			
		||||
 | 
			
		||||
            static VcRoleCommands()
 | 
			
		||||
            {
 | 
			
		||||
                NadekoBot.Client.UserVoiceStateUpdated += ClientOnUserVoiceStateUpdated;
 | 
			
		||||
                vcRoles = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>>();
 | 
			
		||||
                VcRoles = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>>();
 | 
			
		||||
                foreach (var gconf in NadekoBot.AllGuildConfigs)
 | 
			
		||||
                {
 | 
			
		||||
                    var g = NadekoBot.Client.GetGuild(gconf.GuildId);
 | 
			
		||||
@@ -31,7 +31,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        continue; //todo delete everything from db if guild doesn't exist?
 | 
			
		||||
 | 
			
		||||
                    var infos = new ConcurrentDictionary<ulong, IRole>();
 | 
			
		||||
                    vcRoles.TryAdd(gconf.GuildId, infos);
 | 
			
		||||
                    VcRoles.TryAdd(gconf.GuildId, infos);
 | 
			
		||||
                    foreach (var ri in gconf.VcRoleInfos)
 | 
			
		||||
                    {
 | 
			
		||||
                        var role = g.GetRole(ri.RoleId);
 | 
			
		||||
@@ -62,24 +62,22 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                            ulong guildId;
 | 
			
		||||
                            guildId = newVc?.Guild.Id ?? oldVc.Guild.Id;
 | 
			
		||||
 | 
			
		||||
                            ConcurrentDictionary<ulong, IRole> guildVcRoles;
 | 
			
		||||
                            if (vcRoles.TryGetValue(guildId, out guildVcRoles))
 | 
			
		||||
                            if (VcRoles.TryGetValue(guildId, out ConcurrentDictionary<ulong, IRole> guildVcRoles))
 | 
			
		||||
                            {
 | 
			
		||||
                                IRole role;
 | 
			
		||||
                                //remove old
 | 
			
		||||
                                if (oldVc != null && guildVcRoles.TryGetValue(oldVc.Id, out role))
 | 
			
		||||
                                if (oldVc != null && guildVcRoles.TryGetValue(oldVc.Id, out IRole role))
 | 
			
		||||
                                {
 | 
			
		||||
                                    if (gusr.RoleIds.Contains(role.Id))
 | 
			
		||||
                                    if (gusr.Roles.Contains(role))
 | 
			
		||||
                                    {
 | 
			
		||||
                                        try
 | 
			
		||||
                                        {
 | 
			
		||||
                                            await gusr.RemoveRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                                            await gusr.RemoveRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                                            await Task.Delay(500).ConfigureAwait(false);
 | 
			
		||||
                                        }
 | 
			
		||||
                                        catch
 | 
			
		||||
                                        {
 | 
			
		||||
                                            await Task.Delay(200).ConfigureAwait(false);
 | 
			
		||||
                                            await gusr.RemoveRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                                            await gusr.RemoveRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                                            await Task.Delay(500).ConfigureAwait(false);
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
@@ -87,10 +85,10 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                                //add new
 | 
			
		||||
                                if (newVc != null && guildVcRoles.TryGetValue(newVc.Id, out role))
 | 
			
		||||
                                {
 | 
			
		||||
                                    if (!gusr.RoleIds.Contains(role.Id))
 | 
			
		||||
                                        await gusr.AddRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                                    if (!gusr.Roles.Contains(role))
 | 
			
		||||
                                        await gusr.AddRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                                }
 | 
			
		||||
                                
 | 
			
		||||
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
@@ -120,7 +118,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var guildVcRoles = vcRoles.GetOrAdd(user.GuildId, new ConcurrentDictionary<ulong, IRole>());
 | 
			
		||||
                var guildVcRoles = VcRoles.GetOrAdd(user.GuildId, new ConcurrentDictionary<ulong, IRole>());
 | 
			
		||||
 | 
			
		||||
                if (role == null)
 | 
			
		||||
                {
 | 
			
		||||
@@ -159,8 +157,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                var guild = (SocketGuild) Context.Guild;
 | 
			
		||||
                string text;
 | 
			
		||||
                ConcurrentDictionary<ulong, IRole> roles;
 | 
			
		||||
                if (vcRoles.TryGetValue(Context.Guild.Id, out roles))
 | 
			
		||||
                if (VcRoles.TryGetValue(Context.Guild.Id, out ConcurrentDictionary<ulong, IRole> roles))
 | 
			
		||||
                {
 | 
			
		||||
                    if (!roles.Any())
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -98,7 +98,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                                    try
 | 
			
		||||
                                    {
 | 
			
		||||
                                        _log.Info("Removing role " + beforeRoleName + " from user " + user.Username);
 | 
			
		||||
                                        await user.RemoveRolesAsync(beforeRole).ConfigureAwait(false);
 | 
			
		||||
                                        await user.RemoveRoleAsync(beforeRole).ConfigureAwait(false);
 | 
			
		||||
                                        await Task.Delay(200).ConfigureAwait(false);
 | 
			
		||||
                                    }
 | 
			
		||||
                                    catch (Exception ex)
 | 
			
		||||
@@ -119,7 +119,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                                {
 | 
			
		||||
                                    var created = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false));
 | 
			
		||||
 | 
			
		||||
                                    try { await guild.CurrentUser.AddRolesAsync(roleToAdd).ConfigureAwait(false); } catch {/*ignored*/}
 | 
			
		||||
                                    try { await guild.CurrentUser.AddRoleAsync(roleToAdd).ConfigureAwait(false); } catch {/*ignored*/}
 | 
			
		||||
                                    await Task.Delay(50).ConfigureAwait(false);
 | 
			
		||||
                                    await created.AddPermissionOverwriteAsync(roleToAdd, new OverwritePermissions(
 | 
			
		||||
                                        readMessages: PermValue.Allow,
 | 
			
		||||
@@ -133,7 +133,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                                    await Task.Delay(50).ConfigureAwait(false);
 | 
			
		||||
                                }
 | 
			
		||||
                                _log.Warn("Adding role " + roleToAdd.Name + " to user " + user.Username);
 | 
			
		||||
                                await user.AddRolesAsync(roleToAdd).ConfigureAwait(false);
 | 
			
		||||
                                await user.AddRoleAsync(roleToAdd).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        finally
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public async Task SneakyGameStatusEvent(CommandContext context, int? arg)
 | 
			
		||||
            public async Task SneakyGameStatusEvent(ICommandContext context, int? arg)
 | 
			
		||||
            {
 | 
			
		||||
                int num;
 | 
			
		||||
                if (arg == null || arg < 5)
 | 
			
		||||
@@ -115,7 +115,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
                return Task.Delay(0);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public async Task FlowerReactionEvent(CommandContext context, int amount)
 | 
			
		||||
            public async Task FlowerReactionEvent(ICommandContext context, int amount)
 | 
			
		||||
            {
 | 
			
		||||
                if (amount <= 0)
 | 
			
		||||
                    amount = 100;
 | 
			
		||||
@@ -134,7 +134,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
 | 
			
		||||
    public abstract class CurrencyEvent
 | 
			
		||||
    {
 | 
			
		||||
        public abstract Task Start(IUserMessage msg, CommandContext channel, int amount);
 | 
			
		||||
        public abstract Task Start(IUserMessage msg, ICommandContext channel, int amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class FlowerReactionEvent : CurrencyEvent
 | 
			
		||||
@@ -142,31 +142,31 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        private readonly ConcurrentHashSet<ulong> _flowerReactionAwardedUsers = new ConcurrentHashSet<ulong>();
 | 
			
		||||
        private readonly Logger _log;
 | 
			
		||||
 | 
			
		||||
        private IUserMessage msg { get; set; }
 | 
			
		||||
        private IUserMessage StartingMessage { get; set; }
 | 
			
		||||
 | 
			
		||||
        private CancellationTokenSource source { get; }
 | 
			
		||||
        private CancellationToken cancelToken { get; }
 | 
			
		||||
        private CancellationTokenSource Source { get; }
 | 
			
		||||
        private CancellationToken CancelToken { get; }
 | 
			
		||||
 | 
			
		||||
        public FlowerReactionEvent()
 | 
			
		||||
        {
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
            source = new CancellationTokenSource();
 | 
			
		||||
            cancelToken = source.Token;
 | 
			
		||||
            Source = new CancellationTokenSource();
 | 
			
		||||
            CancelToken = Source.Token;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task End()
 | 
			
		||||
        {
 | 
			
		||||
            if(msg != null)
 | 
			
		||||
                await msg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
            if(StartingMessage != null)
 | 
			
		||||
                await StartingMessage.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            if(!source.IsCancellationRequested)
 | 
			
		||||
                source.Cancel();
 | 
			
		||||
            if(!Source.IsCancellationRequested)
 | 
			
		||||
                Source.Cancel();
 | 
			
		||||
 | 
			
		||||
            NadekoBot.Client.MessageDeleted -= MessageDeletedEventHandler;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task MessageDeletedEventHandler(ulong id, Optional<SocketMessage> _) {
 | 
			
		||||
            if (msg?.Id == id)
 | 
			
		||||
        private Task MessageDeletedEventHandler(Cacheable<IMessage, ulong> msg, ISocketMessageChannel channel) {
 | 
			
		||||
            if (StartingMessage?.Id == msg.Id)
 | 
			
		||||
            {
 | 
			
		||||
                _log.Warn("Stopping flower reaction event because message is deleted.");
 | 
			
		||||
                var __ = Task.Run(End);
 | 
			
		||||
@@ -175,22 +175,22 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override async Task Start(IUserMessage umsg, CommandContext context, int amount)
 | 
			
		||||
        public override async Task Start(IUserMessage umsg, ICommandContext context, int amount)
 | 
			
		||||
        {
 | 
			
		||||
            msg = umsg;
 | 
			
		||||
            StartingMessage = umsg;
 | 
			
		||||
            NadekoBot.Client.MessageDeleted += MessageDeletedEventHandler;
 | 
			
		||||
 | 
			
		||||
            try { await msg.AddReactionAsync("🌸").ConfigureAwait(false); }
 | 
			
		||||
            try { await StartingMessage.AddReactionAsync("🌸").ConfigureAwait(false); }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                try { await msg.AddReactionAsync("🌸").ConfigureAwait(false); }
 | 
			
		||||
                try { await StartingMessage.AddReactionAsync("🌸").ConfigureAwait(false); }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
                    try { await msg.DeleteAsync().ConfigureAwait(false); }
 | 
			
		||||
                    try { await StartingMessage.DeleteAsync().ConfigureAwait(false); }
 | 
			
		||||
                    catch { return; }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            using (msg.OnReaction(async (r) =>
 | 
			
		||||
            using (StartingMessage.OnReaction(async (r) =>
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
@@ -208,13 +208,13 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await Task.Delay(TimeSpan.FromHours(24), cancelToken).ConfigureAwait(false);
 | 
			
		||||
                    await Task.Delay(TimeSpan.FromHours(24), CancelToken).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (OperationCanceledException)
 | 
			
		||||
                {
 | 
			
		||||
                    
 | 
			
		||||
                }
 | 
			
		||||
                if (cancelToken.IsCancellationRequested)
 | 
			
		||||
                if (CancelToken.IsCancellationRequested)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                _log.Warn("Stopping flower reaction event because it expired.");
 | 
			
		||||
 
 | 
			
		||||
@@ -102,7 +102,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            await guser.AddRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                            await guser.AddRoleAsync(role).ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (Exception ex)
 | 
			
		||||
                        {
 | 
			
		||||
@@ -200,10 +200,12 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
                };
 | 
			
		||||
                using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                {
 | 
			
		||||
                    var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigs.For(Context.Guild.Id, 
 | 
			
		||||
                    var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigs.For(Context.Guild.Id,
 | 
			
		||||
                        set => set.Include(x => x.ShopEntries)
 | 
			
		||||
                                  .ThenInclude(x => x.Items)).ShopEntries);
 | 
			
		||||
                    entries.Add(entry);
 | 
			
		||||
                                  .ThenInclude(x => x.Items)).ShopEntries)
 | 
			
		||||
                    {
 | 
			
		||||
                        entry
 | 
			
		||||
                    };
 | 
			
		||||
                    uow.GuildConfigs.For(Context.Guild.Id, set => set).ShopEntries = entries;
 | 
			
		||||
                    uow.Complete();
 | 
			
		||||
                }
 | 
			
		||||
@@ -228,8 +230,10 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
                {
 | 
			
		||||
                    var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigs.For(Context.Guild.Id,
 | 
			
		||||
                        set => set.Include(x => x.ShopEntries)
 | 
			
		||||
                                  .ThenInclude(x => x.Items)).ShopEntries);
 | 
			
		||||
                    entries.Add(entry);
 | 
			
		||||
                                  .ThenInclude(x => x.Items)).ShopEntries)
 | 
			
		||||
                    {
 | 
			
		||||
                        entry
 | 
			
		||||
                    };
 | 
			
		||||
                    uow.GuildConfigs.For(Context.Guild.Id, set => set).ShopEntries = entries;
 | 
			
		||||
                    uow.Complete();
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        {
 | 
			
		||||
            role = role ?? Context.Guild.EveryoneRole;
 | 
			
		||||
 | 
			
		||||
            var members = role.Members().Where(u => u.Status != UserStatus.Offline && u.Status != UserStatus.Unknown);
 | 
			
		||||
            var members = role.Members().Where(u => u.Status != UserStatus.Offline);
 | 
			
		||||
            var membersArray = members as IUser[] ?? members.ToArray();
 | 
			
		||||
            var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)];
 | 
			
		||||
            await Context.Channel.SendConfirmAsync("🎟 "+ GetText("raffled_user"), $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false);
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
    public class MusicPlayer
 | 
			
		||||
    {
 | 
			
		||||
        private IAudioClient audioClient { get; set; }
 | 
			
		||||
        private IAudioClient AudioClient { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Player will prioritize different queuer name
 | 
			
		||||
@@ -55,7 +55,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Users who recently got their music wish
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private ConcurrentHashSet<string> recentlyPlayedUsers { get; } = new ConcurrentHashSet<string>();
 | 
			
		||||
        private ConcurrentHashSet<string> RecentlyPlayedUsers { get; } = new ConcurrentHashSet<string>();
 | 
			
		||||
 | 
			
		||||
        private readonly List<Song> _playlist = new List<Song>();
 | 
			
		||||
        private readonly Logger _log;
 | 
			
		||||
@@ -64,7 +64,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
        public Song CurrentSong { get; private set; }
 | 
			
		||||
        public CancellationTokenSource SongCancelSource { get; private set; }
 | 
			
		||||
        private CancellationToken cancelToken { get; set; }
 | 
			
		||||
        private CancellationToken CancelToken { get; set; }
 | 
			
		||||
 | 
			
		||||
        public bool Paused { get; set; }
 | 
			
		||||
 | 
			
		||||
@@ -77,13 +77,13 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
        public IVoiceChannel PlaybackVoiceChannel { get; private set; }
 | 
			
		||||
        public ITextChannel OutputTextChannel { get; set; }
 | 
			
		||||
 | 
			
		||||
        private bool destroyed { get; set; }
 | 
			
		||||
        private bool Destroyed { get; set; }
 | 
			
		||||
        public bool RepeatSong { get; private set; }
 | 
			
		||||
        public bool RepeatPlaylist { get; private set; }
 | 
			
		||||
        public bool Autoplay { get; set; }
 | 
			
		||||
        public uint MaxQueueSize { get; set; } = 0;
 | 
			
		||||
 | 
			
		||||
        private ConcurrentQueue<Action> actionQueue { get; } = new ConcurrentQueue<Action>();
 | 
			
		||||
        private ConcurrentQueue<Action> ActionQueue { get; } = new ConcurrentQueue<Action>();
 | 
			
		||||
 | 
			
		||||
        public string PrettyVolume => $"🔉 {(int)(Volume * 100)}%";
 | 
			
		||||
 | 
			
		||||
@@ -91,28 +91,24 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
        public MusicPlayer(IVoiceChannel startingVoiceChannel, ITextChannel outputChannel, float? defaultVolume)
 | 
			
		||||
        {
 | 
			
		||||
            if (startingVoiceChannel == null)
 | 
			
		||||
                throw new ArgumentNullException(nameof(startingVoiceChannel));
 | 
			
		||||
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
 | 
			
		||||
            OutputTextChannel = outputChannel;
 | 
			
		||||
            Volume = defaultVolume ?? 1.0f;
 | 
			
		||||
 | 
			
		||||
            PlaybackVoiceChannel = startingVoiceChannel;
 | 
			
		||||
            PlaybackVoiceChannel = startingVoiceChannel ?? throw new ArgumentNullException(nameof(startingVoiceChannel));
 | 
			
		||||
            SongCancelSource = new CancellationTokenSource();
 | 
			
		||||
            cancelToken = SongCancelSource.Token;
 | 
			
		||||
            CancelToken = SongCancelSource.Token;
 | 
			
		||||
 | 
			
		||||
            Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    while (!destroyed)
 | 
			
		||||
                    while (!Destroyed)
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            Action action;
 | 
			
		||||
                            if (actionQueue.TryDequeue(out action))
 | 
			
		||||
                            if (ActionQueue.TryDequeue(out Action action))
 | 
			
		||||
                            {
 | 
			
		||||
                                action();
 | 
			
		||||
                            }
 | 
			
		||||
@@ -132,7 +128,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
            var t = new Thread(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                while (!destroyed)
 | 
			
		||||
                while (!Destroyed)
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
@@ -141,9 +137,9 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                        if (CurrentSong == null)
 | 
			
		||||
                            continue;
 | 
			
		||||
 | 
			
		||||
                        if (audioClient != null)
 | 
			
		||||
                            try { await audioClient.DisconnectAsync().ConfigureAwait(false); } catch { }
 | 
			
		||||
                        audioClient = await PlaybackVoiceChannel.ConnectAsync().ConfigureAwait(false);
 | 
			
		||||
                        if (AudioClient != null)
 | 
			
		||||
                            try { await AudioClient.StopAsync().ConfigureAwait(false); } catch { }
 | 
			
		||||
                        AudioClient = await PlaybackVoiceChannel.ConnectAsync().ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                        var index = _playlist.IndexOf(CurrentSong);
 | 
			
		||||
                        if (index != -1)
 | 
			
		||||
@@ -152,7 +148,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                        OnStarted(this, CurrentSong);
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            await CurrentSong.Play(audioClient, cancelToken);
 | 
			
		||||
                            await CurrentSong.Play(AudioClient, CancelToken);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (OperationCanceledException)
 | 
			
		||||
                        {
 | 
			
		||||
@@ -178,12 +174,12 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                    }
 | 
			
		||||
                    finally
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!cancelToken.IsCancellationRequested)
 | 
			
		||||
                        if (!CancelToken.IsCancellationRequested)
 | 
			
		||||
                        {
 | 
			
		||||
                            SongCancelSource.Cancel();
 | 
			
		||||
                        }
 | 
			
		||||
                        SongCancelSource = new CancellationTokenSource();
 | 
			
		||||
                        cancelToken = SongCancelSource.Token;
 | 
			
		||||
                        CancelToken = SongCancelSource.Token;
 | 
			
		||||
                        CurrentSong = null;
 | 
			
		||||
                        await Task.Delay(300).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
@@ -195,7 +191,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
        public void Next()
 | 
			
		||||
        {
 | 
			
		||||
            actionQueue.Enqueue(() =>
 | 
			
		||||
            ActionQueue.Enqueue(() =>
 | 
			
		||||
            {
 | 
			
		||||
                Paused = false;
 | 
			
		||||
                SongCancelSource.Cancel();
 | 
			
		||||
@@ -204,7 +200,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
        public void Stop()
 | 
			
		||||
        {
 | 
			
		||||
            actionQueue.Enqueue(() =>
 | 
			
		||||
            ActionQueue.Enqueue(() =>
 | 
			
		||||
            {
 | 
			
		||||
                RepeatPlaylist = false;
 | 
			
		||||
                RepeatSong = false;
 | 
			
		||||
@@ -234,24 +230,24 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
            {
 | 
			
		||||
                return _playlist.FirstOrDefault();
 | 
			
		||||
            }
 | 
			
		||||
            var song = _playlist.FirstOrDefault(c => !recentlyPlayedUsers.Contains(c.QueuerName))
 | 
			
		||||
            var song = _playlist.FirstOrDefault(c => !RecentlyPlayedUsers.Contains(c.QueuerName))
 | 
			
		||||
                ?? _playlist.FirstOrDefault();
 | 
			
		||||
 | 
			
		||||
            if (song == null)
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            if (recentlyPlayedUsers.Contains(song.QueuerName))
 | 
			
		||||
            if (RecentlyPlayedUsers.Contains(song.QueuerName))
 | 
			
		||||
            {
 | 
			
		||||
                recentlyPlayedUsers.Clear();
 | 
			
		||||
                RecentlyPlayedUsers.Clear();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            recentlyPlayedUsers.Add(song.QueuerName);
 | 
			
		||||
            RecentlyPlayedUsers.Add(song.QueuerName);
 | 
			
		||||
            return song;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Shuffle()
 | 
			
		||||
        {
 | 
			
		||||
            actionQueue.Enqueue(() =>
 | 
			
		||||
            ActionQueue.Enqueue(() =>
 | 
			
		||||
            {
 | 
			
		||||
                var oldPlaylist = _playlist.ToArray();
 | 
			
		||||
                _playlist.Clear();
 | 
			
		||||
@@ -264,7 +260,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
            if (s == null)
 | 
			
		||||
                throw new ArgumentNullException(nameof(s));
 | 
			
		||||
            ThrowIfQueueFull();
 | 
			
		||||
            actionQueue.Enqueue(() =>
 | 
			
		||||
            ActionQueue.Enqueue(() =>
 | 
			
		||||
            {
 | 
			
		||||
                s.MusicPlayer = this;
 | 
			
		||||
                s.QueuerName = username.TrimTo(10);
 | 
			
		||||
@@ -276,7 +272,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
        {
 | 
			
		||||
            if (s == null)
 | 
			
		||||
                throw new ArgumentNullException(nameof(s));
 | 
			
		||||
            actionQueue.Enqueue(() =>
 | 
			
		||||
            ActionQueue.Enqueue(() =>
 | 
			
		||||
            {
 | 
			
		||||
                _playlist.Insert(index, s);
 | 
			
		||||
            });
 | 
			
		||||
@@ -286,7 +282,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
        {
 | 
			
		||||
            if (s == null)
 | 
			
		||||
                throw new ArgumentNullException(nameof(s));
 | 
			
		||||
            actionQueue.Enqueue(() =>
 | 
			
		||||
            ActionQueue.Enqueue(() =>
 | 
			
		||||
            {
 | 
			
		||||
                _playlist.Remove(s);
 | 
			
		||||
            });
 | 
			
		||||
@@ -294,7 +290,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
        public void RemoveSongAt(int index, bool silent = false)
 | 
			
		||||
        {
 | 
			
		||||
            actionQueue.Enqueue(() =>
 | 
			
		||||
            ActionQueue.Enqueue(() =>
 | 
			
		||||
            {
 | 
			
		||||
                if (index < 0 || index >= _playlist.Count)
 | 
			
		||||
                    return;
 | 
			
		||||
@@ -309,7 +305,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
        public void ClearQueue()
 | 
			
		||||
        {
 | 
			
		||||
            actionQueue.Enqueue(() =>
 | 
			
		||||
            ActionQueue.Enqueue(() =>
 | 
			
		||||
            {
 | 
			
		||||
                _playlist.Clear();
 | 
			
		||||
            });
 | 
			
		||||
@@ -347,15 +343,15 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
        public void Destroy()
 | 
			
		||||
        {
 | 
			
		||||
            actionQueue.Enqueue(async () =>
 | 
			
		||||
            ActionQueue.Enqueue(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                RepeatPlaylist = false;
 | 
			
		||||
                RepeatSong = false;
 | 
			
		||||
                Autoplay = false;
 | 
			
		||||
                destroyed = true;
 | 
			
		||||
                Destroyed = true;
 | 
			
		||||
                _playlist.Clear();
 | 
			
		||||
 | 
			
		||||
                try { await audioClient.DisconnectAsync(); } catch { }
 | 
			
		||||
                try { await AudioClient.StopAsync(); } catch { }
 | 
			
		||||
                if (!SongCancelSource.IsCancellationRequested)
 | 
			
		||||
                    SongCancelSource.Cancel();
 | 
			
		||||
            });
 | 
			
		||||
 
 | 
			
		||||
@@ -29,13 +29,13 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
        public string QueuerName { get; set; }
 | 
			
		||||
 | 
			
		||||
        public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
 | 
			
		||||
        public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / (float)_frameBytes / (1000 / (float)_milliseconds));
 | 
			
		||||
        public TimeSpan CurrentTime => TimeSpan.FromSeconds(BytesSent / (float)_frameBytes / (1000 / (float)_milliseconds));
 | 
			
		||||
 | 
			
		||||
        private const int _milliseconds = 20;
 | 
			
		||||
        private const int _samplesPerFrame = (48000 / 1000) * _milliseconds;
 | 
			
		||||
        private const int _frameBytes = 3840; //16-bit, 2 channels
 | 
			
		||||
 | 
			
		||||
        private ulong bytesSent { get; set; }
 | 
			
		||||
        private ulong BytesSent { get; set; }
 | 
			
		||||
 | 
			
		||||
        //pwetty
 | 
			
		||||
 | 
			
		||||
@@ -138,7 +138,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
 | 
			
		||||
        public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
 | 
			
		||||
        {
 | 
			
		||||
            bytesSent = (ulong) SkipTo * 3840 * 50;
 | 
			
		||||
            BytesSent = (ulong) SkipTo * 3840 * 50;
 | 
			
		||||
            var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
 | 
			
		||||
 | 
			
		||||
            var inStream = new SongBuffer(MusicPlayer, filename, SongInfo, SkipTo, _frameBytes * 100);
 | 
			
		||||
@@ -188,7 +188,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                sw.Stop();
 | 
			
		||||
                _log.Debug("Prebuffering successfully completed in " + sw.Elapsed);
 | 
			
		||||
 | 
			
		||||
                var outStream = voiceClient.CreatePCMStream(960);
 | 
			
		||||
                var outStream = voiceClient.CreatePCMStream(AudioApplication.Music);
 | 
			
		||||
 | 
			
		||||
                int nextTime = Environment.TickCount + _milliseconds;
 | 
			
		||||
 | 
			
		||||
@@ -203,7 +203,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
                        _log.Debug("read {0}", read);
 | 
			
		||||
                    unchecked
 | 
			
		||||
                    {
 | 
			
		||||
                        bytesSent += (ulong)read;
 | 
			
		||||
                        BytesSent += (ulong)read;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (read < _frameBytes)
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(guildName))
 | 
			
		||||
                    guild = channel.Guild;
 | 
			
		||||
                else
 | 
			
		||||
                    guild = NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Name.ToUpperInvariant() == guildName.ToUpperInvariant());
 | 
			
		||||
                    guild = NadekoBot.Client.Guilds.FirstOrDefault(g => g.Name.ToUpperInvariant() == guildName.ToUpperInvariant());
 | 
			
		||||
                if (guild == null)
 | 
			
		||||
                    return;
 | 
			
		||||
                var ownername = await guild.GetUserAsync(guild.OwnerId);
 | 
			
		||||
 
 | 
			
		||||
@@ -384,9 +384,9 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        public async Task ShardId(ulong guildid)
 | 
			
		||||
        public async Task ShardId(IGuild guild)
 | 
			
		||||
        {
 | 
			
		||||
            var shardId = NadekoBot.Client.GetShardIdFor(guildid);
 | 
			
		||||
            var shardId = NadekoBot.Client.GetShardIdFor(guild);
 | 
			
		||||
 | 
			
		||||
            await Context.Channel.SendConfirmAsync(shardId.ToString()).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
@@ -397,7 +397,7 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
            var stats = NadekoBot.Stats;
 | 
			
		||||
 | 
			
		||||
            var shardId = Context.Guild != null
 | 
			
		||||
                ? NadekoBot.Client.GetShardIdFor(Context.Guild.Id)
 | 
			
		||||
                ? NadekoBot.Client.GetShardIdFor(Context.Guild)
 | 
			
		||||
                : 0;
 | 
			
		||||
 | 
			
		||||
            await Context.Channel.EmbedAsync(
 | 
			
		||||
@@ -415,7 +415,7 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
                    .AddField(efb => efb.WithName(GetText("uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true))
 | 
			
		||||
                    .AddField(efb => efb.WithName(GetText("presence")).WithValue(
 | 
			
		||||
                        GetText("presence_txt",
 | 
			
		||||
                            NadekoBot.Client.GetGuildCount(), stats.TextChannels, stats.VoiceChannels)).WithIsInline(true))
 | 
			
		||||
                            NadekoBot.Client.Guilds.Count, stats.TextChannels, stats.VoiceChannels)).WithIsInline(true))
 | 
			
		||||
#if !GLOBAL_NADEKO
 | 
			
		||||
                    .WithFooter(efb => efb.WithText(GetText("stats_songs",
 | 
			
		||||
                        Music.Music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null),
 | 
			
		||||
@@ -446,7 +446,7 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
            if (page < 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var guilds = await Task.Run(() => NadekoBot.Client.GetGuilds().OrderBy(g => g.Name).Skip((page - 1) * 15).Take(15)).ConfigureAwait(false);
 | 
			
		||||
            var guilds = await Task.Run(() => NadekoBot.Client.Guilds.OrderBy(g => g.Name).Skip((page - 1) * 15).Take(15)).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            if (!guilds.Any())
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ using NadekoBot.Modules.Music;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
using System.Resources;
 | 
			
		||||
using NadekoBot.Resources;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot
 | 
			
		||||
{
 | 
			
		||||
@@ -74,7 +75,6 @@ namespace NadekoBot
 | 
			
		||||
            //create client
 | 
			
		||||
            Client = new DiscordShardedClient(new DiscordSocketConfig
 | 
			
		||||
            {
 | 
			
		||||
                AudioMode = Discord.Audio.AudioMode.Outgoing,
 | 
			
		||||
                MessageCacheSize = 10,
 | 
			
		||||
                LogLevel = LogSeverity.Warning,
 | 
			
		||||
                TotalShards = Credentials.TotalShards,
 | 
			
		||||
@@ -119,8 +119,17 @@ namespace NadekoBot
 | 
			
		||||
            var sw = Stopwatch.StartNew();
 | 
			
		||||
            //connect
 | 
			
		||||
            await Client.LoginAsync(TokenType.Bot, Credentials.Token).ConfigureAwait(false);
 | 
			
		||||
            await Client.ConnectAsync().ConfigureAwait(false);
 | 
			
		||||
            await Client.StartAsync().ConfigureAwait(false);
 | 
			
		||||
            //await Client.DownloadAllUsersAsync().ConfigureAwait(false);
 | 
			
		||||
            
 | 
			
		||||
            // wait for all shards to be ready
 | 
			
		||||
            int readyCount = 0;
 | 
			
		||||
            foreach (var s in Client.Shards)
 | 
			
		||||
                s.Ready += () => Task.FromResult(Interlocked.Increment(ref readyCount));
 | 
			
		||||
 | 
			
		||||
            while (readyCount < Client.Shards.Count)
 | 
			
		||||
                await Task.Delay(100).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            Stats.Initialize();
 | 
			
		||||
 | 
			
		||||
            sw.Stop();
 | 
			
		||||
@@ -162,10 +171,10 @@ namespace NadekoBot
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var logConfig = new LoggingConfiguration();
 | 
			
		||||
                var consoleTarget = new ColoredConsoleTarget();
 | 
			
		||||
 | 
			
		||||
                consoleTarget.Layout = @"${date:format=HH\:mm\:ss} ${logger} | ${message}";
 | 
			
		||||
 | 
			
		||||
                var consoleTarget = new ColoredConsoleTarget()
 | 
			
		||||
                {
 | 
			
		||||
                    Layout = @"${date:format=HH\:mm\:ss} ${logger} | ${message}"
 | 
			
		||||
                };
 | 
			
		||||
                logConfig.AddTarget("Console", consoleTarget);
 | 
			
		||||
 | 
			
		||||
                logConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, consoleTarget));
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
    <Description>General purpose Discord bot written in C#.</Description>
 | 
			
		||||
    <Copyright>Kwoth</Copyright>
 | 
			
		||||
    <Authors>Kwoth</Authors>
 | 
			
		||||
    <TargetFramework>netcoreapp1.0</TargetFramework>
 | 
			
		||||
    <TargetFramework>netcoreapp1.1</TargetFramework>
 | 
			
		||||
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
 | 
			
		||||
    <AssemblyName>NadekoBot</AssemblyName>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
@@ -30,13 +30,9 @@
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\Discord.Net\src\Discord.Net.Commands\Discord.Net.Commands.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\Discord.Net\src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="AngleSharp" Version="0.9.9" />
 | 
			
		||||
    <PackageReference Include="Discord.Net" Version="1.0.0-rc2-00014" />
 | 
			
		||||
    <PackageReference Include="libvideo" Version="1.0.1" />
 | 
			
		||||
    <PackageReference Include="CoreCLR-NCalc" Version="2.1.2" />
 | 
			
		||||
    <PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.19.0.138" />
 | 
			
		||||
@@ -67,5 +63,4 @@
 | 
			
		||||
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
 | 
			
		||||
    <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ namespace NadekoBot.Services
 | 
			
		||||
        private readonly CommandService _commandService;
 | 
			
		||||
        private readonly Logger _log;
 | 
			
		||||
 | 
			
		||||
        private List<IDMChannel> ownerChannels { get; set; } = new List<IDMChannel>();
 | 
			
		||||
        private List<IDMChannel> OwnerChannels { get; set; } = new List<IDMChannel>();
 | 
			
		||||
 | 
			
		||||
        public event Func<IUserMessage, CommandInfo, Task> CommandExecuted = delegate { return Task.CompletedTask; };
 | 
			
		||||
 | 
			
		||||
@@ -60,7 +60,7 @@ namespace NadekoBot.Services
 | 
			
		||||
            var _ = Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(5000).ConfigureAwait(false);
 | 
			
		||||
                ownerChannels = (await Task.WhenAll(_client.GetGuilds().SelectMany(g => g.Users)
 | 
			
		||||
                OwnerChannels = (await Task.WhenAll(_client.Guilds.SelectMany(g => g.Users)
 | 
			
		||||
                        .Where(u => NadekoBot.Credentials.OwnerIds.Contains(u.Id))
 | 
			
		||||
                        .Distinct(new GuildUserComparer())
 | 
			
		||||
                        .Select(async u =>
 | 
			
		||||
@@ -78,14 +78,14 @@ namespace NadekoBot.Services
 | 
			
		||||
                    .OrderBy(x => NadekoBot.Credentials.OwnerIds.IndexOf(x.Id))
 | 
			
		||||
                    .ToList();
 | 
			
		||||
 | 
			
		||||
                if (!ownerChannels.Any())
 | 
			
		||||
                if (!OwnerChannels.Any())
 | 
			
		||||
                    _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
 | 
			
		||||
                else
 | 
			
		||||
                    _log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Length} owner message channels.");
 | 
			
		||||
                    _log.Info($"Created {OwnerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Length} owner message channels.");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            _client.MessageReceived += MessageReceivedHandler;
 | 
			
		||||
            _client.MessageUpdated += (oldmsg, newMsg) =>
 | 
			
		||||
            _client.MessageUpdated += (oldmsg, newMsg, channel) =>
 | 
			
		||||
            {
 | 
			
		||||
                var ignore = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
@@ -115,18 +115,15 @@ namespace NadekoBot.Services
 | 
			
		||||
                return false;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                Games.ChatterBotSession cbs;
 | 
			
		||||
                var message = Games.CleverBotCommands.PrepareMessage(usrMsg, out cbs);
 | 
			
		||||
                if(message == null || cbs == null)
 | 
			
		||||
                var message = Games.CleverBotCommands.PrepareMessage(usrMsg, out Games.ChatterBotSession cbs);
 | 
			
		||||
                if (message == null || cbs == null)
 | 
			
		||||
                    return false;
 | 
			
		||||
 | 
			
		||||
                PermissionCache pc = Permissions.GetCache(guild.Id);
 | 
			
		||||
                int index;
 | 
			
		||||
                if (
 | 
			
		||||
                    !pc.Permissions.CheckPermissions(usrMsg,
 | 
			
		||||
                        NadekoBot.ModulePrefixes[typeof(Games).Name] + "cleverbot",
 | 
			
		||||
                        typeof(Games).Name,
 | 
			
		||||
                        out index))
 | 
			
		||||
                if (!pc.Permissions.CheckPermissions(usrMsg,
 | 
			
		||||
                    NadekoBot.ModulePrefixes[typeof(Games).Name] + "cleverbot",
 | 
			
		||||
                    typeof(Games).Name,
 | 
			
		||||
                    out int index))
 | 
			
		||||
                {
 | 
			
		||||
                    //todo print in guild actually
 | 
			
		||||
                    var returnMsg =
 | 
			
		||||
@@ -316,11 +313,9 @@ namespace NadekoBot.Services
 | 
			
		||||
                    if (guild != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        PermissionCache pc = Permissions.GetCache(guild.Id);
 | 
			
		||||
                        
 | 
			
		||||
                        int index;
 | 
			
		||||
                        if (
 | 
			
		||||
                            !pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions",
 | 
			
		||||
                                out index))
 | 
			
		||||
 | 
			
		||||
                        if (!pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions",
 | 
			
		||||
                            out int index))
 | 
			
		||||
                        {
 | 
			
		||||
                            //todo print in guild actually
 | 
			
		||||
                            var returnMsg =
 | 
			
		||||
@@ -349,8 +344,7 @@ namespace NadekoBot.Services
 | 
			
		||||
            string messageContent = usrMsg.Content;
 | 
			
		||||
            if (guild != null)
 | 
			
		||||
            {
 | 
			
		||||
                ConcurrentDictionary<string, string> maps;
 | 
			
		||||
                if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out maps))
 | 
			
		||||
                if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out ConcurrentDictionary<string, string> maps))
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                    var keys = maps.Keys
 | 
			
		||||
@@ -367,7 +361,7 @@ namespace NadekoBot.Services
 | 
			
		||||
                        else
 | 
			
		||||
                            continue;
 | 
			
		||||
 | 
			
		||||
                            _log.Info(@"--Mapping Command--
 | 
			
		||||
                        _log.Info(@"--Mapping Command--
 | 
			
		||||
    GuildId: {0}
 | 
			
		||||
    Trigger: {1}
 | 
			
		||||
    Mapping: {2}", guild.Id, messageContent, newMessageContent);
 | 
			
		||||
@@ -405,12 +399,11 @@ namespace NadekoBot.Services
 | 
			
		||||
                {
 | 
			
		||||
                    // rofl, gotta do this to prevent dm help message being sent to 
 | 
			
		||||
                    // users who are voting on private polls (sending a number in a DM)
 | 
			
		||||
                    int vote;
 | 
			
		||||
                    if (int.TryParse(usrMsg.Content, out vote)) return;
 | 
			
		||||
                    if (int.TryParse(usrMsg.Content, out int vote)) return;
 | 
			
		||||
 | 
			
		||||
                    await usrMsg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                    await SelfCommands.HandleDmForwarding(usrMsg, ownerChannels).ConfigureAwait(false);
 | 
			
		||||
                    await SelfCommands.HandleDmForwarding(usrMsg, OwnerChannels).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -470,8 +463,7 @@ namespace NadekoBot.Services
 | 
			
		||||
                if (context.Guild != null)
 | 
			
		||||
                {
 | 
			
		||||
                    PermissionCache pc = Permissions.GetCache(context.Guild.Id);
 | 
			
		||||
                    int index;
 | 
			
		||||
                    if (!resetCommand && !pc.Permissions.CheckPermissions(context.Message, cmd.Aliases.First(), module.Name, out index))
 | 
			
		||||
                    if (!resetCommand && !pc.Permissions.CheckPermissions(context.Message, cmd.Aliases.First(), module.Name, out int index))
 | 
			
		||||
                    {
 | 
			
		||||
                        var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand((SocketGuild)context.Guild)}** is preventing this action.";
 | 
			
		||||
                        return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, returnMsg));
 | 
			
		||||
 
 | 
			
		||||
@@ -17,20 +17,18 @@ namespace NadekoBot.Services.Discord
 | 
			
		||||
 | 
			
		||||
        public ReactionEventWrapper(IUserMessage msg)
 | 
			
		||||
        {
 | 
			
		||||
            if (msg == null)
 | 
			
		||||
                throw new ArgumentNullException(nameof(msg));
 | 
			
		||||
            Message = msg;
 | 
			
		||||
            Message = msg ?? throw new ArgumentNullException(nameof(msg));
 | 
			
		||||
 | 
			
		||||
            NadekoBot.Client.ReactionAdded += Discord_ReactionAdded;
 | 
			
		||||
            NadekoBot.Client.ReactionRemoved += Discord_ReactionRemoved;
 | 
			
		||||
            NadekoBot.Client.ReactionsCleared += Discord_ReactionsCleared;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Discord_ReactionsCleared(ulong messageId, Optional<SocketUserMessage> reaction)
 | 
			
		||||
        private Task Discord_ReactionsCleared(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (messageId == Message.Id)
 | 
			
		||||
                if (msg.Id == Message.Id)
 | 
			
		||||
                    OnReactionsCleared?.Invoke();
 | 
			
		||||
            }
 | 
			
		||||
            catch { }
 | 
			
		||||
@@ -38,11 +36,11 @@ namespace NadekoBot.Services.Discord
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Discord_ReactionRemoved(ulong messageId, Optional<SocketUserMessage> arg2, SocketReaction reaction)
 | 
			
		||||
        private Task Discord_ReactionRemoved(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel, SocketReaction reaction)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (messageId == Message.Id)
 | 
			
		||||
                if (msg.Id == Message.Id)
 | 
			
		||||
                    OnReactionRemoved?.Invoke(reaction);
 | 
			
		||||
            }
 | 
			
		||||
            catch { }
 | 
			
		||||
@@ -50,11 +48,11 @@ namespace NadekoBot.Services.Discord
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Discord_ReactionAdded(ulong messageId, Optional<SocketUserMessage> message, SocketReaction reaction)
 | 
			
		||||
        private Task Discord_ReactionAdded(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel, SocketReaction reaction)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (messageId == Message.Id)
 | 
			
		||||
                if (msg.Id == Message.Id)
 | 
			
		||||
                    OnReactionAdded?.Invoke(reaction);
 | 
			
		||||
            }
 | 
			
		||||
            catch { }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl
 | 
			
		||||
        private readonly DiscordShardedClient _client;
 | 
			
		||||
        private readonly DateTime _started;
 | 
			
		||||
 | 
			
		||||
        public const string BotVersion = "1.3a";
 | 
			
		||||
        public const string BotVersion = "1.4-alpha";
 | 
			
		||||
 | 
			
		||||
        public string Author => "Kwoth#2560";
 | 
			
		||||
        public string Library => "Discord.Net";
 | 
			
		||||
@@ -124,7 +124,7 @@ namespace NadekoBot.Services.Impl
 | 
			
		||||
                    {
 | 
			
		||||
                        using (var content = new FormUrlEncodedContent(
 | 
			
		||||
                            new Dictionary<string, string> {
 | 
			
		||||
                                { "servercount", _client.GetGuildCount().ToString() },
 | 
			
		||||
                                { "servercount", _client.Guilds.Count.ToString() },
 | 
			
		||||
                                { "key", NadekoBot.Credentials.CarbonKey }}))
 | 
			
		||||
                        {
 | 
			
		||||
                            content.Headers.Clear();
 | 
			
		||||
@@ -143,21 +143,23 @@ namespace NadekoBot.Services.Impl
 | 
			
		||||
 | 
			
		||||
        public void Initialize()
 | 
			
		||||
        {
 | 
			
		||||
            var guilds = _client.GetGuilds().ToArray();
 | 
			
		||||
            var guilds = _client.Guilds.ToArray();
 | 
			
		||||
            _textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel));
 | 
			
		||||
            _voiceChannels = guilds.Sum(g => g.Channels.Count) - _textChannels;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Task<string> Print()
 | 
			
		||||
        {
 | 
			
		||||
            var curUser = _client.CurrentUser;
 | 
			
		||||
            SocketSelfUser curUser;
 | 
			
		||||
            while ((curUser = _client.CurrentUser) == null) Task.Delay(1000).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            return Task.FromResult($@"
 | 
			
		||||
Author: [{Author}] | Library: [{Library}]
 | 
			
		||||
Bot Version: [{BotVersion}]
 | 
			
		||||
Bot ID: {curUser.Id}
 | 
			
		||||
Owner ID(s): {string.Join(", ", NadekoBot.Credentials.OwnerIds)}
 | 
			
		||||
Uptime: {GetUptimeString()}
 | 
			
		||||
Servers: {_client.GetGuildCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
 | 
			
		||||
Servers: {_client.Guilds.Count} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
 | 
			
		||||
Commands Ran this session: {CommandsRan}
 | 
			
		||||
Messages: {MessageCounter} [{MessagesPerSecond:F2}/sec] Heap: [{Heap} MB]");
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ namespace NadekoBot.TypeReaders
 | 
			
		||||
        public override Task<TypeReaderResult> Read(ICommandContext context, string input)
 | 
			
		||||
        {
 | 
			
		||||
            input = input.Trim().ToLowerInvariant();
 | 
			
		||||
            var guilds = NadekoBot.Client.GetGuilds();
 | 
			
		||||
            var guilds = NadekoBot.Client.Guilds;
 | 
			
		||||
            var guild = guilds.FirstOrDefault(g => g.Id.ToString().Trim().ToLowerInvariant() == input) ?? //by id
 | 
			
		||||
                        guilds.FirstOrDefault(g => g.Name.Trim().ToLowerInvariant() == input); //by name
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -448,7 +448,7 @@ namespace NadekoBot.Extensions
 | 
			
		||||
        {
 | 
			
		||||
            return usr.AvatarId.StartsWith("a_")
 | 
			
		||||
                    ? $"{DiscordConfig.CDNUrl}avatars/{usr.Id}/{usr.AvatarId}.gif"
 | 
			
		||||
                    : usr.AvatarUrl;
 | 
			
		||||
                    : usr.GetAvatarUrl(ImageFormat.Auto);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user