mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 00:34:26 -05:00 
			
		
		
		
	Part2 of the response system rework
This commit is contained in:
		@@ -357,3 +357,4 @@ resharper_arrange_redundant_parentheses_highlighting = hint
 | 
			
		||||
 | 
			
		||||
# IDE0011: Add braces
 | 
			
		||||
dotnet_diagnostic.IDE0011.severity = warning
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -49,9 +49,9 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    {
 | 
			
		||||
        var newValue = await _somethingOnly.ToggleImageOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
 | 
			
		||||
        if (newValue)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.imageonly_enable);
 | 
			
		||||
            await Response().Confirm(strs.imageonly_enable).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyPendingLocalizedAsync(strs.imageonly_disable);
 | 
			
		||||
            await Response().Pending(strs.imageonly_disable).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -62,9 +62,9 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    {
 | 
			
		||||
        var newValue = await _somethingOnly.ToggleLinkOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
 | 
			
		||||
        if (newValue)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.linkonly_enable);
 | 
			
		||||
            await Response().Confirm(strs.linkonly_enable).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyPendingLocalizedAsync(strs.linkonly_disable);
 | 
			
		||||
            await Response().Pending(strs.linkonly_disable).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -95,7 +95,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
        var guild = (SocketGuild)ctx.Guild;
 | 
			
		||||
        var (enabled, channels) = _service.GetDelMsgOnCmdData(ctx.Guild.Id);
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
                       .WithOkColor()
 | 
			
		||||
                       .WithTitle(GetText(strs.server_delmsgoncmd))
 | 
			
		||||
                       .WithDescription(enabled ? "✅" : "❌");
 | 
			
		||||
@@ -113,7 +113,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
 | 
			
		||||
        embed.AddField(GetText(strs.channel_delmsgoncmd), str);
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(embed);
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -126,12 +126,12 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
        if (_service.ToggleDeleteMessageOnCommand(ctx.Guild.Id))
 | 
			
		||||
        {
 | 
			
		||||
            _service.DeleteMessagesOnCommand.Add(ctx.Guild.Id);
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.delmsg_on);
 | 
			
		||||
            await Response().Confirm(strs.delmsg_on).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            _service.DeleteMessagesOnCommand.TryRemove(ctx.Guild.Id);
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.delmsg_off);
 | 
			
		||||
            await Response().Confirm(strs.delmsg_off).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -154,11 +154,11 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
        await _service.SetDelMsgOnCmdState(ctx.Guild.Id, actualChId, s);
 | 
			
		||||
 | 
			
		||||
        if (s == State.Disable)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.delmsg_channel_off);
 | 
			
		||||
            await Response().Confirm(strs.delmsg_channel_off).SendAsync();
 | 
			
		||||
        else if (s == State.Enable)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.delmsg_channel_on);
 | 
			
		||||
            await Response().Confirm(strs.delmsg_channel_on).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.delmsg_channel_inherit);
 | 
			
		||||
            await Response().Confirm(strs.delmsg_channel_inherit).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -168,7 +168,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    public async Task Deafen(params IGuildUser[] users)
 | 
			
		||||
    {
 | 
			
		||||
        await _service.DeafenUsers(true, users);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.deafen);
 | 
			
		||||
        await Response().Confirm(strs.deafen).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -178,7 +178,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    public async Task UnDeafen(params IGuildUser[] users)
 | 
			
		||||
    {
 | 
			
		||||
        await _service.DeafenUsers(false, users);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.undeafen);
 | 
			
		||||
        await Response().Confirm(strs.undeafen).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -188,7 +188,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    public async Task DelVoiChanl([Leftover] IVoiceChannel voiceChannel)
 | 
			
		||||
    {
 | 
			
		||||
        await voiceChannel.DeleteAsync();
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.delvoich(Format.Bold(voiceChannel.Name)));
 | 
			
		||||
        await Response().Confirm(strs.delvoich(Format.Bold(voiceChannel.Name))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -198,7 +198,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    public async Task CreatVoiChanl([Leftover] string channelName)
 | 
			
		||||
    {
 | 
			
		||||
        var ch = await ctx.Guild.CreateVoiceChannelAsync(channelName);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.createvoich(Format.Bold(ch.Name)));
 | 
			
		||||
        await Response().Confirm(strs.createvoich(Format.Bold(ch.Name))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -208,7 +208,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    public async Task DelTxtChanl([Leftover] ITextChannel toDelete)
 | 
			
		||||
    {
 | 
			
		||||
        await toDelete.DeleteAsync();
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.deltextchan(Format.Bold(toDelete.Name)));
 | 
			
		||||
        await Response().Confirm(strs.deltextchan(Format.Bold(toDelete.Name))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -218,7 +218,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    public async Task CreaTxtChanl([Leftover] string channelName)
 | 
			
		||||
    {
 | 
			
		||||
        var txtCh = await ctx.Guild.CreateTextChannelAsync(channelName); 
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.createtextchan(Format.Bold(txtCh.Name)));
 | 
			
		||||
        await Response().Confirm(strs.createtextchan(Format.Bold(txtCh.Name))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -230,7 +230,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
        var channel = (ITextChannel)ctx.Channel;
 | 
			
		||||
        topic ??= "";
 | 
			
		||||
        await channel.ModifyAsync(c => c.Topic = topic);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.set_topic);
 | 
			
		||||
        await Response().Confirm(strs.set_topic).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -241,7 +241,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    {
 | 
			
		||||
        var channel = (ITextChannel)ctx.Channel;
 | 
			
		||||
        await channel.ModifyAsync(c => c.Name = name);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.set_channel_name);
 | 
			
		||||
        await Response().Confirm(strs.set_channel_name).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -256,9 +256,9 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
        await channel.ModifyAsync(c => c.IsNsfw = !isEnabled);
 | 
			
		||||
 | 
			
		||||
        if (isEnabled)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.nsfw_set_false);
 | 
			
		||||
            await Response().Confirm(strs.nsfw_set_false).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.nsfw_set_true);
 | 
			
		||||
            await Response().Confirm(strs.nsfw_set_true).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -277,13 +277,13 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
        var botPerms = ((SocketGuild)ctx.Guild).CurrentUser.GetPermissions(channel);
 | 
			
		||||
        if (!userPerms.Has(ChannelPermission.ManageMessages))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.insuf_perms_u);
 | 
			
		||||
            await Response().Error(strs.insuf_perms_u).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!botPerms.Has(ChannelPermission.ViewChannel))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.insuf_perms_i);
 | 
			
		||||
            await Response().Error(strs.insuf_perms_i).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -312,13 +312,13 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
        var botPerms = ((SocketGuild)ctx.Guild).CurrentUser.GetPermissions(channel);
 | 
			
		||||
        if (!userPerms.Has(ChannelPermission.ManageMessages))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.insuf_perms_u);
 | 
			
		||||
            await Response().Error(strs.insuf_perms_u).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!botPerms.Has(ChannelPermission.ManageMessages))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.insuf_perms_i);
 | 
			
		||||
            await Response().Error(strs.insuf_perms_i).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -326,7 +326,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
        var msg = await channel.GetMessageAsync(messageId);
 | 
			
		||||
        if (msg is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.msg_not_found);
 | 
			
		||||
            await Response().Error(strs.msg_not_found).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -342,7 +342,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.time_too_long);
 | 
			
		||||
            await Response().Error(strs.time_too_long).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -373,7 +373,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
 | 
			
		||||
        if (t is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_found);
 | 
			
		||||
            await Response().Error(strs.not_found).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
@@ -387,7 +387,7 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    {
 | 
			
		||||
        if (ctx.Channel.GetChannelType() != ChannelType.News)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.req_announcement_channel);
 | 
			
		||||
            await Response().Error(strs.req_announcement_channel).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -395,11 +395,11 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
 | 
			
		||||
        if (newState)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.autopublish_enable);
 | 
			
		||||
            await Response().Confirm(strs.autopublish_enable).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.autopublish_disable);
 | 
			
		||||
            await Response().Confirm(strs.autopublish_disable).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -21,17 +21,17 @@ public partial class Administration
 | 
			
		||||
            // the user can't aar the role which is higher or equal to his highest role
 | 
			
		||||
            if (ctx.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.hierarchy);
 | 
			
		||||
                await Response().Error(strs.hierarchy).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var roles = await _service.ToggleAarAsync(ctx.Guild.Id, role.Id);
 | 
			
		||||
            if (roles.Count == 0)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.aar_disabled);
 | 
			
		||||
                await Response().Confirm(strs.aar_disabled).SendAsync();
 | 
			
		||||
            else if (roles.Contains(role.Id))
 | 
			
		||||
                await AutoAssignRole();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.aar_role_removed(Format.Bold(role.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.aar_role_removed(Format.Bold(role.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -42,7 +42,7 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            if (!_service.TryGetRoles(ctx.Guild.Id, out var roles))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.aar_none);
 | 
			
		||||
                await Response().Confirm(strs.aar_none).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -51,8 +51,10 @@ public partial class Administration
 | 
			
		||||
            if (existing.Count != roles.Count)
 | 
			
		||||
                await _service.SetAarRolesAsync(ctx.Guild.Id, existing.Select(x => x.Id));
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.aar_roles(
 | 
			
		||||
                '\n' + existing.Select(x => Format.Bold(x.ToString())).Join(",\n")));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.aar_roles(
 | 
			
		||||
                      '\n' + existing.Select(x => Format.Bold(x.ToString())).Join(",\n")))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -41,9 +41,9 @@ public partial class Administration
 | 
			
		||||
                    var items = result.Results.Skip(cur * 20).Take(20).ToList();
 | 
			
		||||
 | 
			
		||||
                    if (!items.Any())
 | 
			
		||||
                        return _eb.Create().WithErrorColor().WithFooter(sql).WithDescription("-");
 | 
			
		||||
                        return new EmbedBuilder().WithErrorColor().WithFooter(sql).WithDescription("-");
 | 
			
		||||
 | 
			
		||||
                    return _eb.Create()
 | 
			
		||||
                    return new EmbedBuilder()
 | 
			
		||||
                              .WithOkColor()
 | 
			
		||||
                              .WithFooter(sql)
 | 
			
		||||
                              .WithTitle(string.Join(" ║ ", result.ColumnNames))
 | 
			
		||||
@@ -99,7 +99,7 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithTitle(GetText(strs.sql_confirm_exec))
 | 
			
		||||
                               .WithDescription(Format.Code(sql));
 | 
			
		||||
 | 
			
		||||
@@ -107,11 +107,11 @@ public partial class Administration
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var res = await _ds.ExecuteSql(sql);
 | 
			
		||||
                await SendConfirmAsync(res.ToString());
 | 
			
		||||
                await Response().Confirm(res.ToString()).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync(ex.ToString());
 | 
			
		||||
                await Response().Error(ex.ToString()).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -119,7 +119,7 @@ public partial class Administration
 | 
			
		||||
        [OwnerOnly]
 | 
			
		||||
        public async Task PurgeUser(ulong userId)
 | 
			
		||||
        {
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString()))));
 | 
			
		||||
 | 
			
		||||
            if (!await PromptUserConfirmAsync(embed))
 | 
			
		||||
 
 | 
			
		||||
@@ -18,18 +18,18 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (vch is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_in_voice);
 | 
			
		||||
                await Response().Error(strs.not_in_voice).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var id = _service.ToggleGameVoiceChannel(ctx.Guild.Id, vch.Id);
 | 
			
		||||
 | 
			
		||||
            if (id is null)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.gvc_disabled);
 | 
			
		||||
                await Response().Confirm(strs.gvc_disabled).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _service.GameVoiceChannels.Add(vch.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.gvc_enabled(Format.Bold(vch.Name)));
 | 
			
		||||
                await Response().Confirm(strs.gvc_enabled(Format.Bold(vch.Name))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,9 +13,9 @@ public partial class Administration
 | 
			
		||||
            var enabled = await _service.ToggleBoost(ctx.Guild.Id, ctx.Channel.Id);
 | 
			
		||||
 | 
			
		||||
            if (enabled)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.boost_on);
 | 
			
		||||
                await Response().Confirm(strs.boost_on).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.boost_off);
 | 
			
		||||
                await Response().Pending(strs.boost_off).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -29,9 +29,9 @@ public partial class Administration
 | 
			
		||||
            await _service.SetBoostDel(ctx.Guild.Id, timer);
 | 
			
		||||
 | 
			
		||||
            if (timer > 0)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.boostdel_on(timer));
 | 
			
		||||
                await Response().Confirm(strs.boostdel_on(timer)).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.boostdel_off);
 | 
			
		||||
                await Response().Pending(strs.boostdel_off).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -42,15 +42,15 @@ public partial class Administration
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(text))
 | 
			
		||||
            {
 | 
			
		||||
                var boostMessage = _service.GetBoostMessage(ctx.Guild.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.boostmsg_cur(boostMessage?.SanitizeMentions()));
 | 
			
		||||
                await Response().Confirm(strs.boostmsg_cur(boostMessage?.SanitizeMentions())).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var sendBoostEnabled = _service.SetBoostMessage(ctx.Guild.Id, ref text);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.boostmsg_new);
 | 
			
		||||
            await Response().Confirm(strs.boostmsg_new).SendAsync();
 | 
			
		||||
            if (!sendBoostEnabled)
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.boostmsg_enable($"`{prefix}boost`"));
 | 
			
		||||
                await Response().Pending(strs.boostmsg_enable($"`{prefix}boost`")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -64,9 +64,9 @@ public partial class Administration
 | 
			
		||||
            await _service.SetGreetDel(ctx.Guild.Id, timer);
 | 
			
		||||
 | 
			
		||||
            if (timer > 0)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.greetdel_on(timer));
 | 
			
		||||
                await Response().Confirm(strs.greetdel_on(timer)).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.greetdel_off);
 | 
			
		||||
                await Response().Pending(strs.greetdel_off).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -77,9 +77,9 @@ public partial class Administration
 | 
			
		||||
            var enabled = await _service.SetGreet(ctx.Guild.Id, ctx.Channel.Id);
 | 
			
		||||
 | 
			
		||||
            if (enabled)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.greet_on);
 | 
			
		||||
                await Response().Confirm(strs.greet_on).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.greet_off);
 | 
			
		||||
                await Response().Pending(strs.greet_off).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -90,16 +90,16 @@ public partial class Administration
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(text))
 | 
			
		||||
            {
 | 
			
		||||
                var greetMsg = _service.GetGreetMsg(ctx.Guild.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.greetmsg_cur(greetMsg?.SanitizeMentions()));
 | 
			
		||||
                await Response().Confirm(strs.greetmsg_cur(greetMsg?.SanitizeMentions())).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var sendGreetEnabled = _service.SetGreetMessage(ctx.Guild.Id, ref text);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.greetmsg_new);
 | 
			
		||||
            await Response().Confirm(strs.greetmsg_new).SendAsync();
 | 
			
		||||
 | 
			
		||||
            if (!sendGreetEnabled)
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.greetmsg_enable($"`{prefix}greet`"));
 | 
			
		||||
                await Response().Pending(strs.greetmsg_enable($"`{prefix}greet`")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -110,9 +110,9 @@ public partial class Administration
 | 
			
		||||
            var enabled = await _service.SetGreetDm(ctx.Guild.Id);
 | 
			
		||||
 | 
			
		||||
            if (enabled)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.greetdm_on);
 | 
			
		||||
                await Response().Confirm(strs.greetdm_on).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.greetdm_off);
 | 
			
		||||
                await Response().Confirm(strs.greetdm_off).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -123,15 +123,15 @@ public partial class Administration
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(text))
 | 
			
		||||
            {
 | 
			
		||||
                var dmGreetMsg = _service.GetDmGreetMsg(ctx.Guild.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.greetdmmsg_cur(dmGreetMsg?.SanitizeMentions()));
 | 
			
		||||
                await Response().Confirm(strs.greetdmmsg_cur(dmGreetMsg?.SanitizeMentions())).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var sendGreetEnabled = _service.SetGreetDmMessage(ctx.Guild.Id, ref text);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.greetdmmsg_new);
 | 
			
		||||
            await Response().Confirm(strs.greetdmmsg_new).SendAsync();
 | 
			
		||||
            if (!sendGreetEnabled)
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.greetdmmsg_enable($"`{prefix}greetdm`"));
 | 
			
		||||
                await Response().Pending(strs.greetdmmsg_enable($"`{prefix}greetdm`")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -142,9 +142,9 @@ public partial class Administration
 | 
			
		||||
            var enabled = await _service.SetBye(ctx.Guild.Id, ctx.Channel.Id);
 | 
			
		||||
 | 
			
		||||
            if (enabled)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.bye_on);
 | 
			
		||||
                await Response().Confirm(strs.bye_on).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.bye_off);
 | 
			
		||||
                await Response().Confirm(strs.bye_off).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -155,15 +155,15 @@ public partial class Administration
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(text))
 | 
			
		||||
            {
 | 
			
		||||
                var byeMsg = _service.GetByeMessage(ctx.Guild.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.byemsg_cur(byeMsg?.SanitizeMentions()));
 | 
			
		||||
                await Response().Confirm(strs.byemsg_cur(byeMsg?.SanitizeMentions())).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var sendByeEnabled = _service.SetByeMessage(ctx.Guild.Id, ref text);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.byemsg_new);
 | 
			
		||||
            await Response().Confirm(strs.byemsg_new).SendAsync();
 | 
			
		||||
            if (!sendByeEnabled)
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.byemsg_enable($"`{prefix}bye`"));
 | 
			
		||||
                await Response().Pending(strs.byemsg_enable($"`{prefix}bye`")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -174,9 +174,9 @@ public partial class Administration
 | 
			
		||||
            await _service.SetByeDel(ctx.Guild.Id, timer);
 | 
			
		||||
 | 
			
		||||
            if (timer > 0)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.byedel_on(timer));
 | 
			
		||||
                await Response().Confirm(strs.byedel_on(timer)).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.byedel_off);
 | 
			
		||||
                await Response().Pending(strs.byedel_off).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -191,7 +191,7 @@ public partial class Administration
 | 
			
		||||
            await _service.ByeTest((ITextChannel)ctx.Channel, user);
 | 
			
		||||
            var enabled = _service.GetByeEnabled(ctx.Guild.Id);
 | 
			
		||||
            if (!enabled)
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.byemsg_enable($"`{prefix}bye`"));
 | 
			
		||||
                await Response().Pending(strs.byemsg_enable($"`{prefix}bye`")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -205,7 +205,7 @@ public partial class Administration
 | 
			
		||||
            await _service.GreetTest((ITextChannel)ctx.Channel, user);
 | 
			
		||||
            var enabled = _service.GetGreetEnabled(ctx.Guild.Id);
 | 
			
		||||
            if (!enabled)
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.greetmsg_enable($"`{prefix}greet`"));
 | 
			
		||||
                await Response().Pending(strs.greetmsg_enable($"`{prefix}greet`")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -223,7 +223,7 @@ public partial class Administration
 | 
			
		||||
                await ctx.WarningAsync();
 | 
			
		||||
            var enabled = _service.GetGreetDmEnabled(ctx.Guild.Id);
 | 
			
		||||
            if (!enabled)
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.greetdmmsg_enable($"`{prefix}greetdm`"));
 | 
			
		||||
                await Response().Pending(strs.greetdmmsg_enable($"`{prefix}greetdm`")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -42,8 +42,8 @@ public partial class Administration
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [Priority(0)]
 | 
			
		||||
        public async Task LanguageSet()
 | 
			
		||||
            => await ReplyConfirmLocalizedAsync(strs.lang_set_show(Format.Bold(Culture.ToString()),
 | 
			
		||||
                Format.Bold(Culture.NativeName)));
 | 
			
		||||
            => await Response().Confirm(strs.lang_set_show(Format.Bold(Culture.ToString()),
 | 
			
		||||
                Format.Bold(Culture.NativeName))).SendAsync();
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
@@ -68,11 +68,11 @@ public partial class Administration
 | 
			
		||||
                var nativeName = ci.NativeName;
 | 
			
		||||
                if (ci.Name == "ts-TS")
 | 
			
		||||
                    nativeName = _supportedLocales[ci.Name];
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.lang_set(Format.Bold(ci.ToString()), Format.Bold(nativeName)));
 | 
			
		||||
                await Response().Confirm(strs.lang_set(Format.Bold(ci.ToString()), Format.Bold(nativeName))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.lang_set_fail);
 | 
			
		||||
                await Response().Error(strs.lang_set_fail).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -80,7 +80,7 @@ public partial class Administration
 | 
			
		||||
        public async Task LanguageSetDefault()
 | 
			
		||||
        {
 | 
			
		||||
            var cul = _localization.DefaultCultureInfo;
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.lang_set_bot_show(cul, cul.NativeName));
 | 
			
		||||
            await Response().Error(strs.lang_set_bot_show(cul, cul.NativeName)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -101,23 +101,23 @@ public partial class Administration
 | 
			
		||||
                    _localization.SetDefaultCulture(ci);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.lang_set_bot(Format.Bold(ci.ToString()),
 | 
			
		||||
                    Format.Bold(ci.NativeName)));
 | 
			
		||||
                await Response().Confirm(strs.lang_set_bot(Format.Bold(ci.ToString()),
 | 
			
		||||
                    Format.Bold(ci.NativeName))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.lang_set_fail);
 | 
			
		||||
                await Response().Error(strs.lang_set_fail).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        public async Task LanguagesList()
 | 
			
		||||
            => await EmbedAsync(_eb.Create()
 | 
			
		||||
            => await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                               .WithOkColor()
 | 
			
		||||
                                               .WithTitle(GetText(strs.lang_list))
 | 
			
		||||
                                               .WithDescription(string.Join("\n",
 | 
			
		||||
                                                   _supportedLocales.Select(
 | 
			
		||||
                                                       x => $"{Format.Code(x.Key),-10} => {x.Value}"))));
 | 
			
		||||
                                                       x => $"{Format.Code(x.Key),-10} => {x.Value}")))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
/* list of language codes for reference. 
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ public partial class Administration
 | 
			
		||||
            if (runnerUser.Id != ctx.Guild.OwnerId
 | 
			
		||||
                && runnerUserRoles.Max(x => x.Position) <= targetUserRoles.Max(x => x.Position))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.mute_perms);
 | 
			
		||||
                await Response().Error(strs.mute_perms).SendAsync();
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -31,20 +31,20 @@ public partial class Administration
 | 
			
		||||
            if (role is null)
 | 
			
		||||
            {
 | 
			
		||||
                var muteRole = await _service.GetMuteRole(ctx.Guild);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.mute_role(Format.Code(muteRole.Name)));
 | 
			
		||||
                await Response().Confirm(strs.mute_role(Format.Code(muteRole.Name))).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (ctx.User.Id != ctx.Guild.OwnerId
 | 
			
		||||
                && role.Position >= ((SocketGuildUser)ctx.User).Roles.Max(x => x.Position))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.insuf_perms_u);
 | 
			
		||||
                await Response().Error(strs.insuf_perms_u).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await _service.SetMuteRoleAsync(ctx.Guild.Id, role.Name);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.mute_role_set);
 | 
			
		||||
            await Response().Confirm(strs.mute_role_set).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -59,12 +59,12 @@ public partial class Administration
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                await _service.MuteUser(target, ctx.User, reason: reason);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.user_muted(Format.Bold(target.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.user_muted(Format.Bold(target.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning(ex, "Exception in the mute command");
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.mute_error);
 | 
			
		||||
                await Response().Error(strs.mute_error).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -82,13 +82,13 @@ public partial class Administration
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                await _service.TimedMute(user, ctx.User, time.Time, reason: reason);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.user_muted_time(Format.Bold(user.ToString()),
 | 
			
		||||
                    (int)time.Time.TotalMinutes));
 | 
			
		||||
                await Response().Confirm(strs.user_muted_time(Format.Bold(user.ToString()),
 | 
			
		||||
                    (int)time.Time.TotalMinutes)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning(ex, "Error in mute command");
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.mute_error);
 | 
			
		||||
                await Response().Error(strs.mute_error).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -100,11 +100,11 @@ public partial class Administration
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await _service.UnmuteUser(user.GuildId, user.Id, ctx.User, reason: reason);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.user_unmuted(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.user_unmuted(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.mute_error);
 | 
			
		||||
                await Response().Error(strs.mute_error).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -120,12 +120,12 @@ public partial class Administration
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                await _service.MuteUser(user, ctx.User, MuteType.Chat, reason);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.user_chat_mute(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.user_chat_mute(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning(ex, "Exception in the chatmute command");
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.mute_error);
 | 
			
		||||
                await Response().Error(strs.mute_error).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -143,13 +143,13 @@ public partial class Administration
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                await _service.TimedMute(user, ctx.User, time.Time, MuteType.Chat, reason);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.user_chat_mute_time(Format.Bold(user.ToString()),
 | 
			
		||||
                    (int)time.Time.TotalMinutes));
 | 
			
		||||
                await Response().Confirm(strs.user_chat_mute_time(Format.Bold(user.ToString()),
 | 
			
		||||
                    (int)time.Time.TotalMinutes)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning(ex, "Error in chatmute command");
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.mute_error);
 | 
			
		||||
                await Response().Error(strs.mute_error).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -161,11 +161,11 @@ public partial class Administration
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await _service.UnmuteUser(user.Guild.Id, user.Id, ctx.User, MuteType.Chat, reason);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.user_chat_unmute(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.user_chat_unmute(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.mute_error);
 | 
			
		||||
                await Response().Error(strs.mute_error).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -181,11 +181,11 @@ public partial class Administration
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                await _service.MuteUser(user, ctx.User, MuteType.Voice, reason);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.user_voice_mute(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.user_voice_mute(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.mute_error);
 | 
			
		||||
                await Response().Error(strs.mute_error).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -203,12 +203,12 @@ public partial class Administration
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                await _service.TimedMute(user, ctx.User, time.Time, MuteType.Voice, reason);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.user_voice_mute_time(Format.Bold(user.ToString()),
 | 
			
		||||
                    (int)time.Time.TotalMinutes));
 | 
			
		||||
                await Response().Confirm(strs.user_voice_mute_time(Format.Bold(user.ToString()),
 | 
			
		||||
                    (int)time.Time.TotalMinutes)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.mute_error);
 | 
			
		||||
                await Response().Error(strs.mute_error).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -220,11 +220,11 @@ public partial class Administration
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await _service.UnmuteUser(user.GuildId, user.Id, ctx.User, MuteType.Voice, reason);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.user_voice_unmute(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.user_voice_unmute(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.mute_error);
 | 
			
		||||
                await Response().Error(strs.mute_error).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -122,7 +122,7 @@ public class MuteService : INService
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(reason))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        _ = Task.Run(() => user.SendMessageAsync(embed: _eb.Create()
 | 
			
		||||
        _ = Task.Run(() => user.SendMessageAsync(embed: new EmbedBuilder()
 | 
			
		||||
                                                           .WithDescription(
 | 
			
		||||
                                                               $"You've been muted in {user.Guild} server")
 | 
			
		||||
                                                           .AddField("Mute Type", type.ToString())
 | 
			
		||||
@@ -140,7 +140,7 @@ public class MuteService : INService
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(reason))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        _ = Task.Run(() => user.SendMessageAsync(embed: _eb.Create()
 | 
			
		||||
        _ = Task.Run(() => user.SendMessageAsync(embed: new EmbedBuilder()
 | 
			
		||||
                                                           .WithDescription(
 | 
			
		||||
                                                               $"You've been unmuted in {user.Guild} server")
 | 
			
		||||
                                                           .AddField("Unmute Type", type.ToString())
 | 
			
		||||
 
 | 
			
		||||
@@ -18,15 +18,15 @@ public partial class Administration
 | 
			
		||||
            if (perms is null || perms.Length == 0)
 | 
			
		||||
            {
 | 
			
		||||
                await _service.RemoveOverride(ctx.Guild.Id, cmd.Name);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.perm_override_reset);
 | 
			
		||||
                await Response().Confirm(strs.perm_override_reset).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var aggregatePerms = perms.Aggregate((acc, seed) => seed | acc);
 | 
			
		||||
            await _service.AddOverride(ctx.Guild.Id, cmd.Name, aggregatePerms);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.perm_override(Format.Bold(aggregatePerms.ToString()),
 | 
			
		||||
                Format.Code(cmd.Name)));
 | 
			
		||||
            await Response().Confirm(strs.perm_override(Format.Bold(aggregatePerms.ToString()),
 | 
			
		||||
                Format.Code(cmd.Name))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -34,7 +34,7 @@ public partial class Administration
 | 
			
		||||
        [UserPerm(GuildPerm.Administrator)]
 | 
			
		||||
        public async Task DiscordPermOverrideReset()
 | 
			
		||||
        {
 | 
			
		||||
            var result = await PromptUserConfirmAsync(_eb.Create()
 | 
			
		||||
            var result = await PromptUserConfirmAsync(new EmbedBuilder()
 | 
			
		||||
                                                         .WithOkColor()
 | 
			
		||||
                                                         .WithDescription(GetText(strs.perm_override_all_confirm)));
 | 
			
		||||
 | 
			
		||||
@@ -43,7 +43,7 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            await _service.ClearAllOverrides(ctx.Guild.Id);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.perm_override_all);
 | 
			
		||||
            await Response().Confirm(strs.perm_override_all).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -59,7 +59,7 @@ public partial class Administration
 | 
			
		||||
            await ctx.SendPaginatedConfirmAsync(page,
 | 
			
		||||
                curPage =>
 | 
			
		||||
                {
 | 
			
		||||
                    var eb = _eb.Create().WithTitle(GetText(strs.perm_overrides)).WithOkColor();
 | 
			
		||||
                    var eb = new EmbedBuilder().WithTitle(GetText(strs.perm_overrides)).WithOkColor();
 | 
			
		||||
 | 
			
		||||
                    var thisPageOverrides = overrides.Skip(9 * curPage).Take(9).ToList();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,9 +13,9 @@ public partial class Administration
 | 
			
		||||
        public async Task RotatePlaying()
 | 
			
		||||
        {
 | 
			
		||||
            if (_service.ToggleRotatePlaying())
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.ropl_enabled);
 | 
			
		||||
                await Response().Confirm(strs.ropl_enabled).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.ropl_disabled);
 | 
			
		||||
                await Response().Confirm(strs.ropl_disabled).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -24,7 +24,7 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            await _service.AddPlaying(t, status);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.ropl_added);
 | 
			
		||||
            await Response().Confirm(strs.ropl_added).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -34,12 +34,14 @@ public partial class Administration
 | 
			
		||||
            var statuses = _service.GetRotatingStatuses();
 | 
			
		||||
 | 
			
		||||
            if (!statuses.Any())
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.ropl_not_set);
 | 
			
		||||
                await Response().Error(strs.ropl_not_set).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var i = 1;
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.ropl_list(string.Join("\n\t",
 | 
			
		||||
                    statuses.Select(rs => $"`{i++}.` *{rs.Type}* {rs.Status}"))));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.ropl_list(string.Join("\n\t",
 | 
			
		||||
                          statuses.Select(rs => $"`{i++}.` *{rs.Type}* {rs.Status}"))))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -54,7 +56,7 @@ public partial class Administration
 | 
			
		||||
            if (msg is null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.reprm(msg));
 | 
			
		||||
            await Response().Confirm(strs.reprm(msg)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -14,7 +14,7 @@ public partial class Administration
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [Priority(1)]
 | 
			
		||||
        public async Task Prefix()
 | 
			
		||||
            => await ReplyConfirmLocalizedAsync(strs.prefix_current(Format.Code(_cmdHandler.GetPrefix(ctx.Guild))));
 | 
			
		||||
            => await Response().Confirm(strs.prefix_current(Format.Code(_cmdHandler.GetPrefix(ctx.Guild)))).SendAsync();
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
@@ -35,7 +35,7 @@ public partial class Administration
 | 
			
		||||
            var oldPrefix = prefix;
 | 
			
		||||
            var newPrefix = _cmdHandler.SetPrefix(ctx.Guild, toSet);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.prefix_new(Format.Code(oldPrefix), Format.Code(newPrefix)));
 | 
			
		||||
            await Response().Confirm(strs.prefix_new(Format.Code(oldPrefix), Format.Code(newPrefix))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -44,14 +44,14 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(toSet))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.defprefix_current(_cmdHandler.GetPrefix()));
 | 
			
		||||
                await Response().Confirm(strs.defprefix_current(_cmdHandler.GetPrefix())).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var oldPrefix = _cmdHandler.GetPrefix();
 | 
			
		||||
            var newPrefix = _cmdHandler.SetDefaultPrefix(toSet);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.defprefix_new(Format.Code(oldPrefix), Format.Code(newPrefix)));
 | 
			
		||||
            await Response().Confirm(strs.defprefix_new(Format.Code(oldPrefix), Format.Code(newPrefix))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,11 +17,11 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            if (await _service.TryStopAntiAlt(ctx.Guild.Id))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.prot_disable("Anti-Alt"));
 | 
			
		||||
                await Response().Confirm(strs.prot_disable("Anti-Alt")).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.protection_not_running("Anti-Alt"));
 | 
			
		||||
            await Response().Confirm(strs.protection_not_running("Anti-Alt")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -74,8 +74,8 @@ public partial class Administration
 | 
			
		||||
        public Task AntiRaid()
 | 
			
		||||
        {
 | 
			
		||||
            if (_service.TryStopAntiRaid(ctx.Guild.Id))
 | 
			
		||||
                return ReplyConfirmLocalizedAsync(strs.prot_disable("Anti-Raid"));
 | 
			
		||||
            return ReplyPendingLocalizedAsync(strs.protection_not_running("Anti-Raid"));
 | 
			
		||||
                return Response().Confirm(strs.prot_disable("Anti-Raid")).SendAsync();
 | 
			
		||||
            return Response().Pending(strs.protection_not_running("Anti-Raid")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -104,33 +104,33 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            if (action == PunishmentAction.AddRole)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.punishment_unsupported(action));
 | 
			
		||||
                await Response().Error(strs.punishment_unsupported(action)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (userThreshold is < 2 or > 30)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.raid_cnt(2, 30));
 | 
			
		||||
                await Response().Error(strs.raid_cnt(2, 30)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (seconds is < 2 or > 300)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.raid_time(2, 300));
 | 
			
		||||
                await Response().Error(strs.raid_time(2, 300)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (punishTime is not null)
 | 
			
		||||
            {
 | 
			
		||||
                if (!_service.IsDurationAllowed(action))
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.prot_cant_use_time);
 | 
			
		||||
                    await Response().Error(strs.prot_cant_use_time).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var time = (int?)punishTime?.Time.TotalMinutes ?? 0;
 | 
			
		||||
            if (time is < 0 or > 60 * 24)
 | 
			
		||||
                return;
 | 
			
		||||
            
 | 
			
		||||
            if(action is PunishmentAction.TimeOut && time < 1)
 | 
			
		||||
 | 
			
		||||
            if (action is PunishmentAction.TimeOut && time < 1)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var stats = await _service.StartAntiRaidAsync(ctx.Guild.Id, userThreshold, seconds, action, time);
 | 
			
		||||
@@ -138,8 +138,10 @@ public partial class Administration
 | 
			
		||||
            if (stats is null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            await SendConfirmAsync(GetText(strs.prot_enable("Anti-Raid")),
 | 
			
		||||
                $"{ctx.User.Mention} {GetAntiRaidString(stats)}");
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(GetText(strs.prot_enable("Anti-Raid")),
 | 
			
		||||
                      $"{ctx.User.Mention} {GetAntiRaidString(stats)}")
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -148,8 +150,8 @@ public partial class Administration
 | 
			
		||||
        public Task AntiSpam()
 | 
			
		||||
        {
 | 
			
		||||
            if (_service.TryStopAntiSpam(ctx.Guild.Id))
 | 
			
		||||
                return ReplyConfirmLocalizedAsync(strs.prot_disable("Anti-Spam"));
 | 
			
		||||
            return ReplyPendingLocalizedAsync(strs.protection_not_running("Anti-Spam"));
 | 
			
		||||
                return Response().Confirm(strs.prot_disable("Anti-Spam")).SendAsync();
 | 
			
		||||
            return Response().Pending(strs.protection_not_running("Anti-Spam")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -190,7 +192,7 @@ public partial class Administration
 | 
			
		||||
            if (timeData is not null)
 | 
			
		||||
            {
 | 
			
		||||
                if (!_service.IsDurationAllowed(action))
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.prot_cant_use_time);
 | 
			
		||||
                    await Response().Error(strs.prot_cant_use_time).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var time = (int?)timeData?.Time.TotalMinutes ?? 0;
 | 
			
		||||
@@ -202,8 +204,10 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            var stats = await _service.StartAntiSpamAsync(ctx.Guild.Id, messageCount, action, time, role?.Id);
 | 
			
		||||
 | 
			
		||||
            await SendConfirmAsync(GetText(strs.prot_enable("Anti-Spam")),
 | 
			
		||||
                $"{ctx.User.Mention} {GetAntiSpamString(stats)}");
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(GetText(strs.prot_enable("Anti-Spam")),
 | 
			
		||||
                      $"{ctx.User.Mention} {GetAntiSpamString(stats)}")
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -215,14 +219,14 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (added is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.protection_not_running("Anti-Spam"));
 | 
			
		||||
                await Response().Error(strs.protection_not_running("Anti-Spam")).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (added.Value)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.spam_ignore("Anti-Spam"));
 | 
			
		||||
                await Response().Confirm(strs.spam_ignore("Anti-Spam")).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.spam_not_ignore("Anti-Spam"));
 | 
			
		||||
                await Response().Confirm(strs.spam_not_ignore("Anti-Spam")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -233,11 +237,11 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (spam is null && raid is null && alt is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.prot_none);
 | 
			
		||||
                await Response().Confirm(strs.prot_none).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create().WithOkColor().WithTitle(GetText(strs.prot_active));
 | 
			
		||||
            var embed = new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.prot_active));
 | 
			
		||||
 | 
			
		||||
            if (spam is not null)
 | 
			
		||||
                embed.AddField("Anti-Spam", GetAntiSpamString(spam).TrimTo(1024), true);
 | 
			
		||||
@@ -248,7 +252,7 @@ public partial class Administration
 | 
			
		||||
            if (alt is not null)
 | 
			
		||||
                embed.AddField("Anti-Alt", GetAntiAltString(alt), true);
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetAntiAltString(AntiAltStats alt)
 | 
			
		||||
 
 | 
			
		||||
@@ -33,13 +33,13 @@ public partial class Administration
 | 
			
		||||
            var msg = await ctx.Channel.GetMessageAsync(messageId);
 | 
			
		||||
            if (msg is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_found);
 | 
			
		||||
                await Response().Error(strs.not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (ctx.User.Id != ctx.Guild.OwnerId && ((IGuildUser)ctx.User).GetRoles().Max(x => x.Position) <= role.Position)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.hierarchy);
 | 
			
		||||
                await Response().Error(strs.hierarchy).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -58,8 +58,8 @@ public partial class Administration
 | 
			
		||||
                {
 | 
			
		||||
                    _ = msg.RemoveReactionAsync(emote, ctx.Client.CurrentUser);
 | 
			
		||||
                    return !fl.IsPatronLimit
 | 
			
		||||
                        ? ReplyErrorLocalizedAsync(strs.limit_reached(fl.Quota))
 | 
			
		||||
                        : ReplyPendingLocalizedAsync(strs.feature_limit_reached_owner(fl.Quota, fl.Name));
 | 
			
		||||
                        ? Response().Error(strs.limit_reached(fl.Quota)).SendAsync()
 | 
			
		||||
                        : Response().Pending(strs.feature_limit_reached_owner(fl.Quota, fl.Name)).SendAsync();
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -76,7 +76,7 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            await ctx.SendPaginatedConfirmAsync(page, curPage =>
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create(ctx)
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithOkColor();
 | 
			
		||||
 | 
			
		||||
                var content = string.Empty;
 | 
			
		||||
 
 | 
			
		||||
@@ -36,13 +36,13 @@ public partial class Administration
 | 
			
		||||
            {
 | 
			
		||||
                await targetUser.AddRoleAsync(roleToAdd);
 | 
			
		||||
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.setrole(Format.Bold(roleToAdd.Name),
 | 
			
		||||
                    Format.Bold(targetUser.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.setrole(Format.Bold(roleToAdd.Name),
 | 
			
		||||
                    Format.Bold(targetUser.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning(ex, "Error in setrole command");
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.setrole_err);
 | 
			
		||||
                await Response().Error(strs.setrole_err).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -59,12 +59,12 @@ public partial class Administration
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await targetUser.RemoveRoleAsync(roleToRemove);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.remrole(Format.Bold(roleToRemove.Name),
 | 
			
		||||
                    Format.Bold(targetUser.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.remrole(Format.Bold(roleToRemove.Name),
 | 
			
		||||
                    Format.Bold(targetUser.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.remrole_err);
 | 
			
		||||
                await Response().Error(strs.remrole_err).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -81,16 +81,16 @@ public partial class Administration
 | 
			
		||||
            {
 | 
			
		||||
                if (roleToEdit.Position > (await ctx.Guild.GetCurrentUserAsync()).GetRoles().Max(r => r.Position))
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.renrole_perms);
 | 
			
		||||
                    await Response().Error(strs.renrole_perms).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await roleToEdit.ModifyAsync(g => g.Name = newname);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.renrole);
 | 
			
		||||
                await Response().Confirm(strs.renrole).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.renrole_err);
 | 
			
		||||
                await Response().Error(strs.renrole_err).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -111,11 +111,11 @@ public partial class Administration
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await user.RemoveRolesAsync(userRoles);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.rar(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.rar(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.rar_err);
 | 
			
		||||
                await Response().Error(strs.rar_err).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -129,7 +129,7 @@ public partial class Administration
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var r = await ctx.Guild.CreateRoleAsync(roleName, isMentionable: false);
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.cr(Format.Bold(r.Name)));
 | 
			
		||||
            await Response().Confirm(strs.cr(Format.Bold(r.Name))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -143,7 +143,7 @@ public partial class Administration
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            await role.DeleteAsync();
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.dr(Format.Bold(role.Name)));
 | 
			
		||||
            await Response().Confirm(strs.dr(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -155,16 +155,16 @@ public partial class Administration
 | 
			
		||||
            var newHoisted = !role.IsHoisted;
 | 
			
		||||
            await role.ModifyAsync(r => r.Hoist = newHoisted);
 | 
			
		||||
            if (newHoisted)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.rolehoist_enabled(Format.Bold(role.Name)));
 | 
			
		||||
                await Response().Confirm(strs.rolehoist_enabled(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.rolehoist_disabled(Format.Bold(role.Name)));
 | 
			
		||||
                await Response().Confirm(strs.rolehoist_disabled(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [Priority(1)]
 | 
			
		||||
        public async Task RoleColor([Leftover] IRole role)
 | 
			
		||||
            => await SendConfirmAsync("Role Color", role.Color.RawValue.ToString("x6"));
 | 
			
		||||
            => await Response().Confirm("Role Color", role.Color.RawValue.ToString("x6")).SendAsync();
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
@@ -177,11 +177,11 @@ public partial class Administration
 | 
			
		||||
            {
 | 
			
		||||
                var rgba32 = color.ToPixel<Rgba32>();
 | 
			
		||||
                await role.ModifyAsync(r => r.Color = new Discord.Color(rgba32.R, rgba32.G, rgba32.B));
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.rc(Format.Bold(role.Name)));
 | 
			
		||||
                await Response().Confirm(strs.rc(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.rc_perms);
 | 
			
		||||
                await Response().Error(strs.rc_perms).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -195,11 +195,11 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (newState)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.sticky_roles_enabled);
 | 
			
		||||
                await Response().Confirm(strs.sticky_roles_enabled).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.sticky_roles_disabled);
 | 
			
		||||
                await Response().Confirm(strs.sticky_roles_disabled).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ public sealed class CheckForUpdatesService : INService, IReadyExecutor
 | 
			
		||||
                            if (user is null)
 | 
			
		||||
                                return;
 | 
			
		||||
 | 
			
		||||
                            var eb = _ebs.Create()
 | 
			
		||||
                            var eb = new EmbedBuilder()
 | 
			
		||||
                                .WithOkColor()
 | 
			
		||||
                                .WithAuthor($"NadekoBot v{latestVersion} Released!")
 | 
			
		||||
                                .WithTitle("Changelog")
 | 
			
		||||
 
 | 
			
		||||
@@ -50,22 +50,22 @@ public partial class Administration
 | 
			
		||||
        public async Task CacheUsers(IGuild guild)
 | 
			
		||||
        {
 | 
			
		||||
            var downloadUsersTask = guild.DownloadUsersAsync();
 | 
			
		||||
            var message = await ReplyPendingLocalizedAsync(strs.cache_users_pending);
 | 
			
		||||
            var message = await Response().Pending(strs.cache_users_pending).SendAsync();
 | 
			
		||||
            using var dbContext = _db.GetDbContext();
 | 
			
		||||
 | 
			
		||||
            await downloadUsersTask;
 | 
			
		||||
 | 
			
		||||
            var users = (await guild.GetUsersAsync(CacheMode.CacheOnly))
 | 
			
		||||
                .Cast<IUser>()
 | 
			
		||||
                .ToList();
 | 
			
		||||
                        .Cast<IUser>()
 | 
			
		||||
                        .ToList();
 | 
			
		||||
 | 
			
		||||
            var (added, updated) = await _service.RefreshUsersAsync(users);
 | 
			
		||||
 | 
			
		||||
            await message.ModifyAsync(x =>
 | 
			
		||||
                x.Embed = _eb.Create()
 | 
			
		||||
                    .WithDescription(GetText(strs.cache_users_done(added, updated)))
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .Build()
 | 
			
		||||
                x.Embed = new EmbedBuilder()
 | 
			
		||||
                             .WithDescription(GetText(strs.cache_users_done(added, updated)))
 | 
			
		||||
                             .WithOkColor()
 | 
			
		||||
                             .Build()
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -76,16 +76,17 @@ public partial class Administration
 | 
			
		||||
            if (ctx.User is not IGuildUser { GuildPermissions.Administrator: true })
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (ctx.Guild is SocketGuild sg && ctx.Channel is ISocketMessageChannel ch
 | 
			
		||||
            if (ctx.Guild is SocketGuild sg
 | 
			
		||||
                && ctx.Channel is ISocketMessageChannel ch
 | 
			
		||||
                && ctx.Message is SocketUserMessage msg)
 | 
			
		||||
            {
 | 
			
		||||
                var fakeMessage = new DoAsUserMessage(msg, user, message);
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                await _cmdHandler.TryRunCommand(sg, ch, fakeMessage);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.error_occured);
 | 
			
		||||
                await Response().Error(strs.error_occured).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -112,14 +113,14 @@ public partial class Administration
 | 
			
		||||
            };
 | 
			
		||||
            _service.AddNewAutoCommand(cmd);
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(_eb.Create()
 | 
			
		||||
                                            .WithOkColor()
 | 
			
		||||
                                            .WithTitle(GetText(strs.scadd))
 | 
			
		||||
                                            .AddField(GetText(strs.server),
 | 
			
		||||
                                                cmd.GuildId is null ? "-" : $"{cmd.GuildName}/{cmd.GuildId}",
 | 
			
		||||
                                                true)
 | 
			
		||||
                                            .AddField(GetText(strs.channel), $"{cmd.ChannelName}/{cmd.ChannelId}", true)
 | 
			
		||||
                                            .AddField(GetText(strs.command_text), cmdText));
 | 
			
		||||
            await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                .WithOkColor()
 | 
			
		||||
                                .WithTitle(GetText(strs.scadd))
 | 
			
		||||
                                .AddField(GetText(strs.server),
 | 
			
		||||
                                    cmd.GuildId is null ? "-" : $"{cmd.GuildName}/{cmd.GuildId}",
 | 
			
		||||
                                    true)
 | 
			
		||||
                                .AddField(GetText(strs.channel), $"{cmd.ChannelName}/{cmd.ChannelId}", true)
 | 
			
		||||
                                .AddField(GetText(strs.command_text), cmdText)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -148,7 +149,7 @@ public partial class Administration
 | 
			
		||||
            };
 | 
			
		||||
            _service.AddNewAutoCommand(cmd);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.autocmd_add(Format.Code(Format.Sanitize(cmdText)), cmd.Interval));
 | 
			
		||||
            await Response().Confirm(strs.autocmd_add(Format.Code(Format.Sanitize(cmdText)), cmd.Interval)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -162,18 +163,20 @@ public partial class Administration
 | 
			
		||||
            var scmds = _service.GetStartupCommands().Skip(page * 5).Take(5).ToList();
 | 
			
		||||
 | 
			
		||||
            if (scmds.Count == 0)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.startcmdlist_none);
 | 
			
		||||
                await Response().Error(strs.startcmdlist_none).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var i = 0;
 | 
			
		||||
                await SendConfirmAsync(text: string.Join("\n",
 | 
			
		||||
                        scmds.Select(x => $@"```css
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(text: string.Join("\n",
 | 
			
		||||
                              scmds.Select(x => $@"```css
 | 
			
		||||
#{++i + (page * 5)}
 | 
			
		||||
[{GetText(strs.server)}]: {(x.GuildId.HasValue ? $"{x.GuildName} #{x.GuildId}" : "-")}
 | 
			
		||||
[{GetText(strs.channel)}]: {x.ChannelName} #{x.ChannelId}
 | 
			
		||||
[{GetText(strs.command_text)}]: {x.CommandText}```")),
 | 
			
		||||
                    title: string.Empty,
 | 
			
		||||
                    footer: GetText(strs.page(page + 1)));
 | 
			
		||||
                          title: string.Empty,
 | 
			
		||||
                          footer: GetText(strs.page(page + 1)))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -187,19 +190,21 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            var scmds = _service.GetAutoCommands().Skip(page * 5).Take(5).ToList();
 | 
			
		||||
            if (!scmds.Any())
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.autocmdlist_none);
 | 
			
		||||
                await Response().Error(strs.autocmdlist_none).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var i = 0;
 | 
			
		||||
                await SendConfirmAsync(text: string.Join("\n",
 | 
			
		||||
                        scmds.Select(x => $@"```css
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(text: string.Join("\n",
 | 
			
		||||
                              scmds.Select(x => $@"```css
 | 
			
		||||
#{++i + (page * 5)}
 | 
			
		||||
[{GetText(strs.server)}]: {(x.GuildId.HasValue ? $"{x.GuildName} #{x.GuildId}" : "-")}
 | 
			
		||||
[{GetText(strs.channel)}]: {x.ChannelName} #{x.ChannelId}
 | 
			
		||||
{GetIntervalText(x.Interval)}
 | 
			
		||||
[{GetText(strs.command_text)}]: {x.CommandText}```")),
 | 
			
		||||
                    title: string.Empty,
 | 
			
		||||
                    footer: GetText(strs.page(page + 1)));
 | 
			
		||||
                          title: string.Empty,
 | 
			
		||||
                          footer: GetText(strs.page(page + 1)))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -215,7 +220,7 @@ public partial class Administration
 | 
			
		||||
            ctx.Message.DeleteAfter(0);
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var msg = await SendConfirmAsync($"⏲ {miliseconds}ms");
 | 
			
		||||
                var msg = await Response().Confirm($"⏲ {miliseconds}ms").SendAsync();
 | 
			
		||||
                msg.DeleteAfter(miliseconds / 1000);
 | 
			
		||||
            }
 | 
			
		||||
            catch { }
 | 
			
		||||
@@ -231,7 +236,7 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            if (!_service.RemoveAutoCommand(--index, out _))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.acrm_fail);
 | 
			
		||||
                await Response().Error(strs.acrm_fail).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -244,9 +249,9 @@ public partial class Administration
 | 
			
		||||
        public async Task StartupCommandRemove([Leftover] int index)
 | 
			
		||||
        {
 | 
			
		||||
            if (!_service.RemoveStartupCommand(--index, out _))
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.scrm_fail);
 | 
			
		||||
                await Response().Error(strs.scrm_fail).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.scrm);
 | 
			
		||||
                await Response().Confirm(strs.scrm).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -257,7 +262,7 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            _service.ClearStartupCommands();
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.startcmds_cleared);
 | 
			
		||||
            await Response().Confirm(strs.startcmds_cleared).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -267,9 +272,9 @@ public partial class Administration
 | 
			
		||||
            var enabled = _service.ForwardMessages();
 | 
			
		||||
 | 
			
		||||
            if (enabled)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.fwdm_start);
 | 
			
		||||
                await Response().Confirm(strs.fwdm_start).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.fwdm_stop);
 | 
			
		||||
                await Response().Pending(strs.fwdm_stop).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -279,9 +284,9 @@ public partial class Administration
 | 
			
		||||
            var enabled = _service.ForwardToAll();
 | 
			
		||||
 | 
			
		||||
            if (enabled)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.fwall_start);
 | 
			
		||||
                await Response().Confirm(strs.fwall_start).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.fwall_stop);
 | 
			
		||||
                await Response().Pending(strs.fwall_stop).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -292,9 +297,9 @@ public partial class Administration
 | 
			
		||||
            var enabled = _service.ForwardToChannel(ctx.Channel.Id);
 | 
			
		||||
 | 
			
		||||
            if (enabled)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.fwch_start);
 | 
			
		||||
                await Response().Confirm(strs.fwch_start).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.fwch_stop);
 | 
			
		||||
                await Response().Pending(strs.fwch_stop).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -331,7 +336,7 @@ public partial class Administration
 | 
			
		||||
                    if (string.IsNullOrWhiteSpace(str))
 | 
			
		||||
                        str = GetText(strs.no_shards_on_page);
 | 
			
		||||
 | 
			
		||||
                    return _eb.Create().WithOkColor().WithDescription($"{status}\n\n{str}");
 | 
			
		||||
                    return new EmbedBuilder().WithOkColor().WithDescription($"{status}\n\n{str}");
 | 
			
		||||
                },
 | 
			
		||||
                allShardStrings.Length,
 | 
			
		||||
                25);
 | 
			
		||||
@@ -355,9 +360,9 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            var success = _coord.RestartShard(shardId);
 | 
			
		||||
            if (success)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.shard_reconnecting(Format.Bold("#" + shardId)));
 | 
			
		||||
                await Response().Confirm(strs.shard_reconnecting(Format.Bold("#" + shardId))).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.no_shard_id);
 | 
			
		||||
                await Response().Error(strs.no_shard_id).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -393,7 +398,7 @@ public partial class Administration
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.deleted_x_servers(toLeave.Count));
 | 
			
		||||
            await Response().Confirm(strs.deleted_x_servers(toLeave.Count)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -403,8 +408,8 @@ public partial class Administration
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await _client.SetStatusAsync(UserStatus.Invisible);
 | 
			
		||||
                _ =  _client.StopAsync();
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.shutting_down);
 | 
			
		||||
                _ = _client.StopAsync();
 | 
			
		||||
                await Response().Confirm(strs.shutting_down).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
@@ -422,11 +427,11 @@ public partial class Administration
 | 
			
		||||
            var success = _coord.RestartBot();
 | 
			
		||||
            if (!success)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.restart_fail);
 | 
			
		||||
                await Response().Error(strs.restart_fail).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            try { await ReplyConfirmLocalizedAsync(strs.restarting); }
 | 
			
		||||
            try { await Response().Confirm(strs.restarting).SendAsync(); }
 | 
			
		||||
            catch { }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -446,7 +451,7 @@ public partial class Administration
 | 
			
		||||
                Log.Warning("You've been ratelimited. Wait 2 hours to change your name");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.bot_name(Format.Bold(newName)));
 | 
			
		||||
            await Response().Confirm(strs.bot_name(Format.Bold(newName))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -460,7 +465,7 @@ public partial class Administration
 | 
			
		||||
            var curUser = await ctx.Guild.GetCurrentUserAsync();
 | 
			
		||||
            await curUser.ModifyAsync(u => u.Nickname = newNick);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.bot_nick(Format.Bold(newNick) ?? "-"));
 | 
			
		||||
            await Response().Confirm(strs.bot_nick(Format.Bold(newNick) ?? "-")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -473,13 +478,15 @@ public partial class Administration
 | 
			
		||||
            if (sg.OwnerId == gu.Id
 | 
			
		||||
                || gu.GetRoles().Max(r => r.Position) >= sg.CurrentUser.GetRoles().Max(r => r.Position))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.insuf_perms_i);
 | 
			
		||||
                await Response().Error(strs.insuf_perms_i).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await gu.ModifyAsync(u => u.Nickname = newNick);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.user_nick(Format.Bold(gu.ToString()), Format.Bold(newNick) ?? "-"));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.user_nick(Format.Bold(gu.ToString()), Format.Bold(newNick) ?? "-"))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -488,7 +495,7 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            await _client.SetStatusAsync(SettableUserStatusToUserStatus(status));
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.bot_status(Format.Bold(status.ToString())));
 | 
			
		||||
            await Response().Confirm(strs.bot_status(Format.Bold(status.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -498,9 +505,9 @@ public partial class Administration
 | 
			
		||||
            var success = await _service.SetAvatar(img);
 | 
			
		||||
 | 
			
		||||
            if (success)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.set_avatar);
 | 
			
		||||
                await Response().Confirm(strs.set_avatar).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [OwnerOnly]
 | 
			
		||||
        public async Task SetBanner([Leftover] string img = null)
 | 
			
		||||
@@ -508,7 +515,7 @@ public partial class Administration
 | 
			
		||||
            var success = await _service.SetBanner(img);
 | 
			
		||||
 | 
			
		||||
            if (success)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.set_banner);
 | 
			
		||||
                await Response().Confirm(strs.set_banner).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -520,7 +527,7 @@ public partial class Administration
 | 
			
		||||
            var repCtx = new ReplacementContext(ctx);
 | 
			
		||||
            await _service.SetGameAsync(game is null ? game : await repSvc.ReplaceAsync(game, repCtx), type);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.set_game);
 | 
			
		||||
            await Response().Confirm(strs.set_game).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -531,7 +538,7 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            await _service.SetStreamAsync(name, url);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.set_stream);
 | 
			
		||||
            await Response().Confirm(strs.set_stream).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -574,11 +581,11 @@ public partial class Administration
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.invalid_format);
 | 
			
		||||
                await Response().Error(strs.invalid_format).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.message_sent);
 | 
			
		||||
            await Response().Confirm(strs.message_sent).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -587,7 +594,7 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            _strings.Reload();
 | 
			
		||||
            await _medusaLoader.ReloadStrings();
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.bot_strings_reloaded);
 | 
			
		||||
            await Response().Confirm(strs.bot_strings_reloaded).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
 
 | 
			
		||||
@@ -225,7 +225,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await ownerCh.SendConfirmAsync(_eb, title, toSend);
 | 
			
		||||
                        await ownerCh.Response(_strings, _eb).Confirm(title, toSend).SendAsync();
 | 
			
		||||
                    }
 | 
			
		||||
                    catch
 | 
			
		||||
                    {
 | 
			
		||||
@@ -238,7 +238,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    if (_client.GetChannel(cid) is ITextChannel ch)
 | 
			
		||||
                        await ch.SendConfirmAsync(_eb, title, toSend);
 | 
			
		||||
                        await ch.Response(_strings, _eb).Confirm(title, toSend).SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
@@ -252,7 +252,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await firstOwnerChannel.SendConfirmAsync(_eb, title, toSend);
 | 
			
		||||
                        await firstOwnerChannel.Response(_strings, _eb).Confirm(title, toSend).SendAsync();
 | 
			
		||||
                    }
 | 
			
		||||
                    catch
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,9 @@ public partial class Administration
 | 
			
		||||
            var newVal = _service.ToggleAdSarm(ctx.Guild.Id);
 | 
			
		||||
 | 
			
		||||
            if (newVal)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.adsarm_enable(prefix));
 | 
			
		||||
                await Response().Confirm(strs.adsarm_enable(prefix)).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.adsarm_disable(prefix));
 | 
			
		||||
                await Response().Confirm(strs.adsarm_disable(prefix)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -46,11 +46,12 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (succ)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.role_added(Format.Bold(role.Name),
 | 
			
		||||
                    Format.Bold(@group.ToString())));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.role_added(Format.Bold(role.Name), Format.Bold(group.ToString())))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.role_in_list(Format.Bold(role.Name)));
 | 
			
		||||
                await Response().Error(strs.role_in_list(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -64,11 +65,12 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (set)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(
 | 
			
		||||
                    strs.group_name_added(Format.Bold(@group.ToString()), Format.Bold(name)));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.group_name_added(Format.Bold(group.ToString()), Format.Bold(name)))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.group_name_removed(Format.Bold(group.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.group_name_removed(Format.Bold(group.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -82,9 +84,9 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            var success = _service.RemoveSar(role.Guild.Id, role.Id);
 | 
			
		||||
            if (!success)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.self_assign_not);
 | 
			
		||||
                await Response().Error(strs.self_assign_not).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.self_assign_rem(Format.Bold(role.Name)));
 | 
			
		||||
                await Response().Confirm(strs.self_assign_rem(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -133,7 +135,7 @@ public partial class Administration
 | 
			
		||||
                        rolesStr.AppendLine();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return _eb.Create()
 | 
			
		||||
                    return new EmbedBuilder()
 | 
			
		||||
                              .WithOkColor()
 | 
			
		||||
                              .WithTitle(Format.Bold(GetText(strs.self_assign_list(roles.Count()))))
 | 
			
		||||
                              .WithDescription(rolesStr.ToString())
 | 
			
		||||
@@ -153,9 +155,9 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            var areExclusive = _service.ToggleEsar(ctx.Guild.Id);
 | 
			
		||||
            if (areExclusive)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.self_assign_excl);
 | 
			
		||||
                await Response().Confirm(strs.self_assign_excl).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.self_assign_no_excl);
 | 
			
		||||
                await Response().Confirm(strs.self_assign_no_excl).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -171,12 +173,14 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (!succ)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.self_assign_not);
 | 
			
		||||
                await Response().Error(strs.self_assign_not).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.self_assign_level_req(Format.Bold(role.Name),
 | 
			
		||||
                Format.Bold(level.ToString())));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.self_assign_level_req(Format.Bold(role.Name),
 | 
			
		||||
                      Format.Bold(level.ToString())))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -189,15 +193,15 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            IUserMessage msg;
 | 
			
		||||
            if (result == SelfAssignedRolesService.AssignResult.ErrNotAssignable)
 | 
			
		||||
                msg = await ReplyErrorLocalizedAsync(strs.self_assign_not);
 | 
			
		||||
                msg = await Response().Error(strs.self_assign_not).SendAsync();
 | 
			
		||||
            else if (result == SelfAssignedRolesService.AssignResult.ErrLvlReq)
 | 
			
		||||
                msg = await ReplyErrorLocalizedAsync(strs.self_assign_not_level(Format.Bold(extra.ToString())));
 | 
			
		||||
                msg = await Response().Error(strs.self_assign_not_level(Format.Bold(extra.ToString()))).SendAsync();
 | 
			
		||||
            else if (result == SelfAssignedRolesService.AssignResult.ErrAlreadyHave)
 | 
			
		||||
                msg = await ReplyErrorLocalizedAsync(strs.self_assign_already(Format.Bold(role.Name)));
 | 
			
		||||
                msg = await Response().Error(strs.self_assign_already(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
            else if (result == SelfAssignedRolesService.AssignResult.ErrNotPerms)
 | 
			
		||||
                msg = await ReplyErrorLocalizedAsync(strs.self_assign_perms);
 | 
			
		||||
                msg = await Response().Error(strs.self_assign_perms).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                msg = await ReplyConfirmLocalizedAsync(strs.self_assign_success(Format.Bold(role.Name)));
 | 
			
		||||
                msg = await Response().Confirm(strs.self_assign_success(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
 | 
			
		||||
            if (autoDelete)
 | 
			
		||||
            {
 | 
			
		||||
@@ -216,13 +220,13 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            IUserMessage msg;
 | 
			
		||||
            if (result == SelfAssignedRolesService.RemoveResult.ErrNotAssignable)
 | 
			
		||||
                msg = await ReplyErrorLocalizedAsync(strs.self_assign_not);
 | 
			
		||||
                msg = await Response().Error(strs.self_assign_not).SendAsync();
 | 
			
		||||
            else if (result == SelfAssignedRolesService.RemoveResult.ErrNotHave)
 | 
			
		||||
                msg = await ReplyErrorLocalizedAsync(strs.self_assign_not_have(Format.Bold(role.Name)));
 | 
			
		||||
                msg = await Response().Error(strs.self_assign_not_have(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
            else if (result == SelfAssignedRolesService.RemoveResult.ErrNotPerms)
 | 
			
		||||
                msg = await ReplyErrorLocalizedAsync(strs.self_assign_perms);
 | 
			
		||||
                msg = await Response().Error(strs.self_assign_perms).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                msg = await ReplyConfirmLocalizedAsync(strs.self_assign_remove(Format.Bold(role.Name)));
 | 
			
		||||
                msg = await Response().Confirm(strs.self_assign_remove(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
 | 
			
		||||
            if (autoDelete)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
    private readonly ConcurrentHashSet<ulong> _ignoreMessageIds = new();
 | 
			
		||||
    private readonly UserPunishService _punishService;
 | 
			
		||||
    private readonly IMessageSenderService _sender;
 | 
			
		||||
 | 
			
		||||
    public LogCommandService(
 | 
			
		||||
        DiscordSocketClient client,
 | 
			
		||||
@@ -37,7 +38,8 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
        GuildTimezoneService tz,
 | 
			
		||||
        IMemoryCache memoryCache,
 | 
			
		||||
        IEmbedBuilderService eb,
 | 
			
		||||
        UserPunishService punishService)
 | 
			
		||||
        UserPunishService punishService,
 | 
			
		||||
        IMessageSenderService sender)
 | 
			
		||||
    {
 | 
			
		||||
        _client = client;
 | 
			
		||||
        _memoryCache = memoryCache;
 | 
			
		||||
@@ -48,6 +50,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
        _prot = prot;
 | 
			
		||||
        _tz = tz;
 | 
			
		||||
        _punishService = punishService;
 | 
			
		||||
        _sender = sender;
 | 
			
		||||
 | 
			
		||||
        using (var uow = db.GetDbContext())
 | 
			
		||||
        {
 | 
			
		||||
@@ -165,7 +168,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
                var title = GetText(logChannel.Guild, strs.thread_deleted);
 | 
			
		||||
 | 
			
		||||
                await logChannel.EmbedAsync(_eb.Create()
 | 
			
		||||
                await logChannel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("🗑 " + title)
 | 
			
		||||
                    .WithDescription($"{ch.Name} | {ch.Id}")
 | 
			
		||||
@@ -195,7 +198,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
                var title = GetText(logChannel.Guild, strs.thread_created);
 | 
			
		||||
 | 
			
		||||
                await logChannel.EmbedAsync(_eb.Create()
 | 
			
		||||
                await logChannel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("🆕 " + title)
 | 
			
		||||
                    .WithDescription($"{ch.Name} | {ch.Id}")
 | 
			
		||||
@@ -229,16 +232,16 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
            {
 | 
			
		||||
                var keys = PresenceUpdates.Keys.ToList();
 | 
			
		||||
 | 
			
		||||
                await keys.Select(key =>
 | 
			
		||||
                await keys.Select(channel =>
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!((SocketGuild)key.Guild).CurrentUser.GetPermissions(key).SendMessages)
 | 
			
		||||
                        if (!((SocketGuild)channel.Guild).CurrentUser.GetPermissions(channel).SendMessages)
 | 
			
		||||
                            return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                        if (PresenceUpdates.TryRemove(key, out var msgs))
 | 
			
		||||
                        if (PresenceUpdates.TryRemove(channel, out var msgs))
 | 
			
		||||
                        {
 | 
			
		||||
                            var title = GetText(key.Guild, strs.presence_updates);
 | 
			
		||||
                            var title = GetText(channel.Guild, strs.presence_updates);
 | 
			
		||||
                            var desc = string.Join(Environment.NewLine, msgs);
 | 
			
		||||
                            return key.SendConfirmAsync(_eb, title, desc.TrimTo(2048)!);
 | 
			
		||||
                            return _sender.Response(channel).Confirm(title, desc.TrimTo(2048)!).SendAsync();
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
@@ -328,7 +331,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
        if ((logChannel = await TryGetLogChannel(g, logSetting, LogType.UserWarned)) is null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
            .WithOkColor()
 | 
			
		||||
            .WithTitle($"⚠️ User Warned")
 | 
			
		||||
            .WithDescription($"<@{arg.UserId}> | {arg.UserId}")
 | 
			
		||||
@@ -357,7 +360,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                if ((logChannel = await TryGetLogChannel(g, logSetting, LogType.UserUpdated)) is null)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create();
 | 
			
		||||
                var embed = new EmbedBuilder();
 | 
			
		||||
 | 
			
		||||
                if (before.Username != after.Username)
 | 
			
		||||
                {
 | 
			
		||||
@@ -542,7 +545,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithAuthor(mutes)
 | 
			
		||||
                    .WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
 | 
			
		||||
                    .WithFooter(CurrentTime(usr.Guild))
 | 
			
		||||
@@ -589,7 +592,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithAuthor(mutes)
 | 
			
		||||
                    .WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
 | 
			
		||||
                    .WithFooter($"{CurrentTime(usr.Guild)}")
 | 
			
		||||
@@ -643,7 +646,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithAuthor($"🛡 Anti-{protection}")
 | 
			
		||||
                    .WithTitle(GetText(logChannel.Guild, strs.users) + " " + punishment)
 | 
			
		||||
                    .WithDescription(string.Join("\n", users.Select(u => u.ToString())))
 | 
			
		||||
@@ -696,7 +699,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                if (logSetting.UserUpdatedId is not null
 | 
			
		||||
                    && (logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) is not null)
 | 
			
		||||
                {
 | 
			
		||||
                    var embed = _eb.Create()
 | 
			
		||||
                    var embed = new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithFooter(CurrentTime(before.Guild))
 | 
			
		||||
                        .WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}");
 | 
			
		||||
@@ -767,7 +770,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.ChannelUpdated)) is null)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create().WithOkColor().WithFooter(CurrentTime(before.Guild));
 | 
			
		||||
                var embed = new EmbedBuilder().WithOkColor().WithFooter(CurrentTime(before.Guild));
 | 
			
		||||
 | 
			
		||||
                var beforeTextChannel = cbefore as ITextChannel;
 | 
			
		||||
                var afterTextChannel = cafter as ITextChannel;
 | 
			
		||||
@@ -823,7 +826,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                else
 | 
			
		||||
                    title = GetText(logChannel.Guild, strs.text_chan_destroyed);
 | 
			
		||||
 | 
			
		||||
                await logChannel.EmbedAsync(_eb.Create()
 | 
			
		||||
                await logChannel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("🆕 " + title)
 | 
			
		||||
                    .WithDescription($"{ch.Name} | {ch.Id}")
 | 
			
		||||
@@ -859,7 +862,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                else
 | 
			
		||||
                    title = GetText(logChannel.Guild, strs.text_chan_created);
 | 
			
		||||
 | 
			
		||||
                await logChannel.EmbedAsync(_eb.Create()
 | 
			
		||||
                await logChannel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("🆕 " + title)
 | 
			
		||||
                    .WithDescription($"{ch.Name} | {ch.Id}")
 | 
			
		||||
@@ -962,7 +965,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                ITextChannel? logChannel;
 | 
			
		||||
                if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserLeft)) is null)
 | 
			
		||||
                    return;
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("❌ " + GetText(logChannel.Guild, strs.user_left))
 | 
			
		||||
                    .WithDescription(usr.ToString())
 | 
			
		||||
@@ -995,7 +998,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserJoined)) is null)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("✅ " + GetText(logChannel.Guild, strs.user_joined))
 | 
			
		||||
                    .WithDescription($"{usr.Mention} `{usr}`")
 | 
			
		||||
@@ -1036,7 +1039,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                ITextChannel? logChannel;
 | 
			
		||||
                if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserUnbanned)) is null)
 | 
			
		||||
                    return;
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("♻️ " + GetText(logChannel.Guild, strs.user_unbanned))
 | 
			
		||||
                    .WithDescription(usr.ToString()!)
 | 
			
		||||
@@ -1083,7 +1086,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                {
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("🚫 " + GetText(logChannel.Guild, strs.user_banned))
 | 
			
		||||
                    .WithDescription(usr.ToString()!)
 | 
			
		||||
@@ -1134,7 +1137,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var resolvedMessage = msg.Resolve(TagHandling.FullName);
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("🗑 "
 | 
			
		||||
                               + GetText(logChannel.Guild, strs.msg_del(((ITextChannel)msg.Channel).Name)))
 | 
			
		||||
@@ -1194,7 +1197,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
                    || logChannel.Id == after.Channel.Id)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("📝 "
 | 
			
		||||
                               + GetText(logChannel.Guild,
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,9 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            await _service.LogServer(ctx.Guild.Id, ctx.Channel.Id, action.Value);
 | 
			
		||||
            if (action.Value)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.log_all);
 | 
			
		||||
                await Response().Confirm(strs.log_all).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.log_disabled);
 | 
			
		||||
                await Response().Confirm(strs.log_disabled).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -35,7 +35,7 @@ public partial class Administration
 | 
			
		||||
            var usrs = settings?.LogIgnores.Where(x => x.ItemType == IgnoredItemType.User).ToList()
 | 
			
		||||
                       ?? new List<IgnoredLogItem>();
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .AddField(GetText(strs.log_ignored_channels),
 | 
			
		||||
                            chs.Count == 0
 | 
			
		||||
@@ -46,7 +46,7 @@ public partial class Administration
 | 
			
		||||
                                ? "-"
 | 
			
		||||
                                : string.Join('\n', usrs.Select(x => $"{x.LogItemId} | <@{x.LogItemId}>")));
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(eb);
 | 
			
		||||
            await Response().Embed(eb).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -59,13 +59,17 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (!removed)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(
 | 
			
		||||
                    strs.log_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")")));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(
 | 
			
		||||
                          strs.log_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")")))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(
 | 
			
		||||
                    strs.log_not_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")")));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(
 | 
			
		||||
                          strs.log_not_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")")))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -79,13 +83,15 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (!removed)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(
 | 
			
		||||
                    strs.log_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")")));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.log_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")")))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(
 | 
			
		||||
                    strs.log_not_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")")));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.log_not_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")")))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -106,7 +112,7 @@ public partial class Administration
 | 
			
		||||
                        return Format.Bold(x);
 | 
			
		||||
                    }));
 | 
			
		||||
 | 
			
		||||
            await SendConfirmAsync(Format.Bold(GetText(strs.log_events)) + "\n" + str);
 | 
			
		||||
            await Response().Confirm(Format.Bold(GetText(strs.log_events)) + "\n" + str).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static ulong? GetLogProperty(LogSetting l, LogType type)
 | 
			
		||||
@@ -163,9 +169,9 @@ public partial class Administration
 | 
			
		||||
            var val = _service.Log(ctx.Guild.Id, ctx.Channel.Id, type);
 | 
			
		||||
 | 
			
		||||
            if (val)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.log(Format.Bold(type.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.log(Format.Bold(type.ToString()))).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.log_stop(Format.Bold(type.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.log_stop(Format.Bold(type.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -37,7 +37,7 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            await ctx.SendPaginatedConfirmAsync(page,
 | 
			
		||||
                curPage => _eb.Create()
 | 
			
		||||
                curPage => new EmbedBuilder()
 | 
			
		||||
                              .WithOkColor()
 | 
			
		||||
                              .WithTitle(GetText(strs.timezones_available))
 | 
			
		||||
                              .WithDescription(string.Join("\n",
 | 
			
		||||
@@ -49,7 +49,7 @@ public partial class Administration
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Timezone()
 | 
			
		||||
            => await ReplyConfirmLocalizedAsync(strs.timezone_guild(_service.GetTimeZoneOrUtc(ctx.Guild.Id)));
 | 
			
		||||
            => await Response().Confirm(strs.timezone_guild(_service.GetTimeZoneOrUtc(ctx.Guild.Id))).SendAsync();
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
@@ -63,13 +63,13 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (tz is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.timezone_not_found);
 | 
			
		||||
                await Response().Error(strs.timezone_not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _service.SetTimeZone(ctx.Guild.Id, tz);
 | 
			
		||||
 | 
			
		||||
            await SendConfirmAsync(tz.ToString());
 | 
			
		||||
            await Response().Confirm(tz.ToString()).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -38,7 +38,7 @@ public partial class Administration
 | 
			
		||||
                || (ctx.User.Id != ownerId && targetMaxRole >= modMaxRole)
 | 
			
		||||
                || target.Id == ownerId)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.hierarchy);
 | 
			
		||||
                await Response().Error(strs.hierarchy).SendAsync();
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -65,7 +65,7 @@ public partial class Administration
 | 
			
		||||
            var dmFailed = false;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await user.EmbedAsync(_eb.Create()
 | 
			
		||||
                await user.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                                         .WithErrorColor()
 | 
			
		||||
                                         .WithDescription(GetText(strs.warned_on(ctx.Guild.ToString())))
 | 
			
		||||
                                         .AddField(GetText(strs.moderator), ctx.User.ToString())
 | 
			
		||||
@@ -84,16 +84,16 @@ public partial class Administration
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning(ex, "Exception occured while warning a user");
 | 
			
		||||
                var errorEmbed = _eb.Create().WithErrorColor().WithDescription(GetText(strs.cant_apply_punishment));
 | 
			
		||||
                var errorEmbed = new EmbedBuilder().WithErrorColor().WithDescription(GetText(strs.cant_apply_punishment));
 | 
			
		||||
 | 
			
		||||
                if (dmFailed)
 | 
			
		||||
                    errorEmbed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
 | 
			
		||||
 | 
			
		||||
                await ctx.Channel.EmbedAsync(errorEmbed);
 | 
			
		||||
                await Response().Embed(errorEmbed).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create().WithOkColor();
 | 
			
		||||
            var embed = new EmbedBuilder().WithOkColor();
 | 
			
		||||
            if (punishment is null)
 | 
			
		||||
                embed.WithDescription(GetText(strs.user_warned(Format.Bold(user.ToString()))));
 | 
			
		||||
            else
 | 
			
		||||
@@ -105,7 +105,7 @@ public partial class Administration
 | 
			
		||||
            if (dmFailed)
 | 
			
		||||
                embed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -118,9 +118,9 @@ public partial class Administration
 | 
			
		||||
            var expireDays = await _service.GetWarnExpire(ctx.Guild.Id);
 | 
			
		||||
 | 
			
		||||
            if (expireDays == 0)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.warns_dont_expire);
 | 
			
		||||
                await Response().Confirm(strs.warns_dont_expire).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.warns_expire_in(expireDays));
 | 
			
		||||
                await Response().Error(strs.warns_expire_in(expireDays)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -140,14 +140,14 @@ public partial class Administration
 | 
			
		||||
            await _service.WarnExpireAsync(ctx.Guild.Id, days, opts.Delete);
 | 
			
		||||
            if (days == 0)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.warn_expire_reset);
 | 
			
		||||
                await Response().Confirm(strs.warn_expire_reset).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (opts.Delete)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.warn_expire_set_delete(Format.Bold(days.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.warn_expire_set_delete(Format.Bold(days.ToString()))).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.warn_expire_set_clear(Format.Bold(days.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.warn_expire_set_clear(Format.Bold(days.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -200,7 +200,7 @@ public partial class Administration
 | 
			
		||||
                    var warnings = allWarnings.Skip(page * 9).Take(9).ToArray();
 | 
			
		||||
 | 
			
		||||
                    var user = (ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString();
 | 
			
		||||
                    var embed = _eb.Create().WithOkColor().WithTitle(GetText(strs.warnlog_for(user)));
 | 
			
		||||
                    var embed = new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.warnlog_for(user)));
 | 
			
		||||
 | 
			
		||||
                    if (!warnings.Any())
 | 
			
		||||
                        embed.WithDescription(GetText(strs.warnings_none));
 | 
			
		||||
@@ -260,7 +260,7 @@ public partial class Administration
 | 
			
		||||
                                                + $" | {total} ({all} - {forgiven})";
 | 
			
		||||
                                     });
 | 
			
		||||
 | 
			
		||||
                    return _eb.Create()
 | 
			
		||||
                    return new EmbedBuilder()
 | 
			
		||||
                              .WithOkColor()
 | 
			
		||||
                              .WithTitle(GetText(strs.warnings_list))
 | 
			
		||||
                              .WithDescription(string.Join("\n", ws));
 | 
			
		||||
@@ -285,13 +285,13 @@ public partial class Administration
 | 
			
		||||
            var success = await _service.WarnClearAsync(ctx.Guild.Id, userId, index, ctx.User.ToString());
 | 
			
		||||
            var userStr = Format.Bold((ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString());
 | 
			
		||||
            if (index == 0)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.warnings_cleared(userStr));
 | 
			
		||||
                await Response().Error(strs.warnings_cleared(userStr)).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (success)
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.warning_cleared(Format.Bold(index.ToString()), userStr));
 | 
			
		||||
                    await Response().Confirm(strs.warning_cleared(Format.Bold(index.ToString()), userStr)).SendAsync();
 | 
			
		||||
                else
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.warning_clear_fail);
 | 
			
		||||
                    await Response().Error(strs.warning_clear_fail).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -310,7 +310,7 @@ public partial class Administration
 | 
			
		||||
            if (ctx.Guild.OwnerId != ctx.User.Id
 | 
			
		||||
                && role.Position >= ((IGuildUser)ctx.User).GetRoles().Max(x => x.Position))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.role_too_high);
 | 
			
		||||
                await Response().Error(strs.role_too_high).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -321,14 +321,18 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (time is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.warn_punish_set(Format.Bold(punish.ToString()),
 | 
			
		||||
                    Format.Bold(number.ToString())));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.warn_punish_set(Format.Bold(punish.ToString()),
 | 
			
		||||
                          Format.Bold(number.ToString())))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
 | 
			
		||||
                    Format.Bold(number.ToString()),
 | 
			
		||||
                    Format.Bold(time.Input)));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
 | 
			
		||||
                          Format.Bold(number.ToString()),
 | 
			
		||||
                          Format.Bold(time.Input)))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -353,14 +357,18 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (time is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.warn_punish_set(Format.Bold(punish.ToString()),
 | 
			
		||||
                    Format.Bold(number.ToString())));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.warn_punish_set(Format.Bold(punish.ToString()),
 | 
			
		||||
                          Format.Bold(number.ToString())))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
 | 
			
		||||
                    Format.Bold(number.ToString()),
 | 
			
		||||
                    Format.Bold(time.Input)));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
 | 
			
		||||
                          Format.Bold(number.ToString()),
 | 
			
		||||
                          Format.Bold(time.Input)))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -372,7 +380,7 @@ public partial class Administration
 | 
			
		||||
            if (!_service.WarnPunishRemove(ctx.Guild.Id, number))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.warn_punish_rem(Format.Bold(number.ToString())));
 | 
			
		||||
            await Response().Confirm(strs.warn_punish_rem(Format.Bold(number.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -391,7 +399,7 @@ public partial class Administration
 | 
			
		||||
            else
 | 
			
		||||
                list = GetText(strs.warnpl_none);
 | 
			
		||||
 | 
			
		||||
            await SendConfirmAsync(GetText(strs.warn_punish_list), list);
 | 
			
		||||
            await Response().Confirm(GetText(strs.warn_punish_list), list).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -401,7 +409,7 @@ public partial class Administration
 | 
			
		||||
        [Priority(1)]
 | 
			
		||||
        public Task Ban(StoopidTime time, IUser user, [Leftover] string msg = null)
 | 
			
		||||
            => Ban(time, user.Id, msg);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [UserPerm(GuildPerm.BanMembers)]
 | 
			
		||||
@@ -413,7 +421,7 @@ public partial class Administration
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var guildUser = await ((DiscordSocketClient)Context.Client).Rest.GetGuildUserAsync(ctx.Guild.Id, userId);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if (guildUser is not null && !await CheckRoleHierarchy(guildUser))
 | 
			
		||||
                return;
 | 
			
		||||
@@ -438,10 +446,10 @@ public partial class Administration
 | 
			
		||||
            var user = await ctx.Client.GetUserAsync(userId);
 | 
			
		||||
            var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
 | 
			
		||||
            await _mute.TimedBan(ctx.Guild, userId, time.Time, (ctx.User + " | " + msg).TrimTo(512), banPrune);
 | 
			
		||||
            var toSend = _eb.Create()
 | 
			
		||||
            var toSend = new EmbedBuilder()
 | 
			
		||||
                            .WithOkColor()
 | 
			
		||||
                            .WithTitle("⛔️ " + GetText(strs.banned_user))
 | 
			
		||||
                            .AddField(GetText(strs.username),  user?.ToString() ?? userId.ToString(), true)
 | 
			
		||||
                            .AddField(GetText(strs.username), user?.ToString() ?? userId.ToString(), true)
 | 
			
		||||
                            .AddField("ID", userId.ToString(), true)
 | 
			
		||||
                            .AddField(GetText(strs.duration),
 | 
			
		||||
                                time.Time.Humanize(3, minUnit: TimeUnit.Minute, culture: Culture),
 | 
			
		||||
@@ -450,7 +458,7 @@ public partial class Administration
 | 
			
		||||
            if (dmFailed)
 | 
			
		||||
                toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(toSend);
 | 
			
		||||
            await Response().Embed(toSend).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -466,7 +474,7 @@ public partial class Administration
 | 
			
		||||
                var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
 | 
			
		||||
                await ctx.Guild.AddBanAsync(userId, banPrune, (ctx.User + " | " + msg).TrimTo(512));
 | 
			
		||||
 | 
			
		||||
                await ctx.Channel.EmbedAsync(_eb.Create()
 | 
			
		||||
                await ctx.Channel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                                                .WithOkColor()
 | 
			
		||||
                                                .WithTitle("⛔️ " + GetText(strs.banned_user))
 | 
			
		||||
                                                .AddField("ID", userId.ToString(), true));
 | 
			
		||||
@@ -502,7 +510,7 @@ public partial class Administration
 | 
			
		||||
            var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
 | 
			
		||||
            await ctx.Guild.AddBanAsync(user, banPrune, (ctx.User + " | " + msg).TrimTo(512));
 | 
			
		||||
 | 
			
		||||
            var toSend = _eb.Create()
 | 
			
		||||
            var toSend = new EmbedBuilder()
 | 
			
		||||
                            .WithOkColor()
 | 
			
		||||
                            .WithTitle("⛔️ " + GetText(strs.banned_user))
 | 
			
		||||
                            .AddField(GetText(strs.username), user.ToString(), true)
 | 
			
		||||
@@ -511,7 +519,7 @@ public partial class Administration
 | 
			
		||||
            if (dmFailed)
 | 
			
		||||
                toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(toSend);
 | 
			
		||||
            await Response().Embed(toSend).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -522,16 +530,16 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            if (days < 0 || days > 7)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.invalid_input);
 | 
			
		||||
                await Response().Error(strs.invalid_input).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            await _service.SetBanPruneAsync(ctx.Guild.Id, days);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            if (days == 0)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.ban_prune_disabled);
 | 
			
		||||
                await Response().Confirm(strs.ban_prune_disabled).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.ban_prune(days));
 | 
			
		||||
                await Response().Confirm(strs.ban_prune(days)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -545,11 +553,11 @@ public partial class Administration
 | 
			
		||||
                var template = _service.GetBanTemplate(ctx.Guild.Id);
 | 
			
		||||
                if (template is null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.banmsg_default);
 | 
			
		||||
                    await Response().Confirm(strs.banmsg_default).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await SendConfirmAsync(template);
 | 
			
		||||
                await Response().Confirm(template).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -586,10 +594,14 @@ public partial class Administration
 | 
			
		||||
        private async Task InternalBanMessageTest(string reason, TimeSpan? duration)
 | 
			
		||||
        {
 | 
			
		||||
            var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), reason));
 | 
			
		||||
            var embed = await _service.GetBanUserDmEmbed(Context, (IGuildUser)ctx.User, defaultMessage, reason, duration);
 | 
			
		||||
            var embed = await _service.GetBanUserDmEmbed(Context,
 | 
			
		||||
                (IGuildUser)ctx.User,
 | 
			
		||||
                defaultMessage,
 | 
			
		||||
                reason,
 | 
			
		||||
                duration);
 | 
			
		||||
 | 
			
		||||
            if (embed is null)
 | 
			
		||||
                await ConfirmLocalizedAsync(strs.banmsg_disabled);
 | 
			
		||||
                await Response().Confirm(strs.banmsg_disabled).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
@@ -598,7 +610,7 @@ public partial class Administration
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.unable_to_dm_user);
 | 
			
		||||
                    await Response().Error(strs.unable_to_dm_user).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -618,7 +630,7 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (bun is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.user_not_found);
 | 
			
		||||
                await Response().Error(strs.user_not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -635,7 +647,7 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (bun is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.user_not_found);
 | 
			
		||||
                await Response().Error(strs.user_not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -646,7 +658,7 @@ public partial class Administration
 | 
			
		||||
        {
 | 
			
		||||
            await ctx.Guild.RemoveBanAsync(user);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.unbanned_user(Format.Bold(user.ToString())));
 | 
			
		||||
            await Response().Confirm(strs.unbanned_user(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -678,7 +690,10 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await user.SendErrorAsync(_eb, GetText(strs.sbdm(Format.Bold(ctx.Guild.Name), msg)));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Channel(await user.CreateDMChannelAsync())
 | 
			
		||||
                      .Error(GetText(strs.sbdm(Format.Bold(ctx.Guild.Name), msg)))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
@@ -690,7 +705,7 @@ public partial class Administration
 | 
			
		||||
            try { await ctx.Guild.RemoveBanAsync(user); }
 | 
			
		||||
            catch { await ctx.Guild.RemoveBanAsync(user); }
 | 
			
		||||
 | 
			
		||||
            var toSend = _eb.Create()
 | 
			
		||||
            var toSend = new EmbedBuilder()
 | 
			
		||||
                            .WithOkColor()
 | 
			
		||||
                            .WithTitle("☣ " + GetText(strs.sb_user))
 | 
			
		||||
                            .AddField(GetText(strs.username), user.ToString(), true)
 | 
			
		||||
@@ -699,7 +714,7 @@ public partial class Administration
 | 
			
		||||
            if (dmFailed)
 | 
			
		||||
                toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(toSend);
 | 
			
		||||
            await Response().Embed(toSend).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -733,7 +748,10 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await user.SendErrorAsync(_eb, GetText(strs.kickdm(Format.Bold(ctx.Guild.Name), msg)));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Channel(await user.CreateDMChannelAsync())
 | 
			
		||||
                      .Error(GetText(strs.kickdm(Format.Bold(ctx.Guild.Name), msg)))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
@@ -742,7 +760,7 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            await user.KickAsync((ctx.User + " | " + msg).TrimTo(512));
 | 
			
		||||
 | 
			
		||||
            var toSend = _eb.Create()
 | 
			
		||||
            var toSend = new EmbedBuilder()
 | 
			
		||||
                            .WithOkColor()
 | 
			
		||||
                            .WithTitle(GetText(strs.kicked_user))
 | 
			
		||||
                            .AddField(GetText(strs.username), user.ToString(), true)
 | 
			
		||||
@@ -751,21 +769,21 @@ public partial class Administration
 | 
			
		||||
            if (dmFailed)
 | 
			
		||||
                toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(toSend);
 | 
			
		||||
            await Response().Embed(toSend).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [UserPerm(GuildPerm.ModerateMembers)]
 | 
			
		||||
        [BotPerm(GuildPerm.ModerateMembers)]
 | 
			
		||||
        [Priority(2)]
 | 
			
		||||
        public async Task Timeout(IUser globalUser, StoopidTime time,  [Leftover] string msg = null)
 | 
			
		||||
        public async Task Timeout(IUser globalUser, StoopidTime time, [Leftover] string msg = null)
 | 
			
		||||
        {
 | 
			
		||||
            var user = await ctx.Guild.GetUserAsync(globalUser.Id);
 | 
			
		||||
 | 
			
		||||
            if (user is null)
 | 
			
		||||
                return;
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            if (!await CheckRoleHierarchy(user))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
@@ -774,27 +792,27 @@ public partial class Administration
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var dmMessage = GetText(strs.timeoutdm(Format.Bold(ctx.Guild.Name), msg));
 | 
			
		||||
                await user.EmbedAsync(_eb.Create(ctx)
 | 
			
		||||
                        .WithPendingColor()
 | 
			
		||||
                        .WithDescription(dmMessage));
 | 
			
		||||
                await user.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                                         .WithPendingColor()
 | 
			
		||||
                                         .WithDescription(dmMessage));
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                dmFailed = true;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            await user.SetTimeOutAsync(time.Time);
 | 
			
		||||
 | 
			
		||||
            var toSend = _eb.Create()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithTitle("⏳ " + GetText(strs.timedout_user))
 | 
			
		||||
                .AddField(GetText(strs.username), user.ToString(), true)
 | 
			
		||||
                .AddField("ID", user.Id.ToString(), true);
 | 
			
		||||
            var toSend = new EmbedBuilder()
 | 
			
		||||
                            .WithOkColor()
 | 
			
		||||
                            .WithTitle("⏳ " + GetText(strs.timedout_user))
 | 
			
		||||
                            .AddField(GetText(strs.username), user.ToString(), true)
 | 
			
		||||
                            .AddField("ID", user.Id.ToString(), true);
 | 
			
		||||
 | 
			
		||||
            if (dmFailed)
 | 
			
		||||
                toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(toSend);
 | 
			
		||||
            await Response().Embed(toSend).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -846,12 +864,12 @@ public partial class Administration
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(missStr))
 | 
			
		||||
                missStr = "-";
 | 
			
		||||
 | 
			
		||||
            var toSend = _eb.Create(ctx)
 | 
			
		||||
            var toSend = new EmbedBuilder()
 | 
			
		||||
                            .WithDescription(GetText(strs.mass_ban_in_progress(banning.Count)))
 | 
			
		||||
                            .AddField(GetText(strs.invalid(missing.Count)), missStr)
 | 
			
		||||
                            .WithPendingColor();
 | 
			
		||||
 | 
			
		||||
            var banningMessage = await ctx.Channel.EmbedAsync(toSend);
 | 
			
		||||
            var banningMessage = await Response().Embed(toSend).SendAsync();
 | 
			
		||||
 | 
			
		||||
            var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
 | 
			
		||||
            foreach (var toBan in banning)
 | 
			
		||||
@@ -866,7 +884,7 @@ public partial class Administration
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await banningMessage.ModifyAsync(x => x.Embed = _eb.Create()
 | 
			
		||||
            await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder()
 | 
			
		||||
                                                               .WithDescription(
 | 
			
		||||
                                                                   GetText(strs.mass_ban_completed(banning.Count())))
 | 
			
		||||
                                                               .AddField(GetText(strs.invalid(missing.Count)), missStr)
 | 
			
		||||
@@ -891,7 +909,7 @@ public partial class Administration
 | 
			
		||||
                missStr = "-";
 | 
			
		||||
 | 
			
		||||
            //send a message but don't wait for it
 | 
			
		||||
            var banningMessageTask = ctx.Channel.EmbedAsync(_eb.Create()
 | 
			
		||||
            var banningMessageTask = ctx.Channel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                                                               .WithDescription(
 | 
			
		||||
                                                                   GetText(strs.mass_kill_in_progress(bans.Count())))
 | 
			
		||||
                                                               .AddField(GetText(strs.invalid(missing)), missStr)
 | 
			
		||||
@@ -911,7 +929,7 @@ public partial class Administration
 | 
			
		||||
            //wait for the message and edit it
 | 
			
		||||
            var banningMessage = await banningMessageTask;
 | 
			
		||||
 | 
			
		||||
            await banningMessage.ModifyAsync(x => x.Embed = _eb.Create()
 | 
			
		||||
            await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder()
 | 
			
		||||
                                                               .WithDescription(
 | 
			
		||||
                                                                   GetText(strs.mass_kill_completed(bans.Count())))
 | 
			
		||||
                                                               .AddField(GetText(strs.invalid(missing)), missStr)
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,9 @@ public partial class Administration
 | 
			
		||||
        public async Task VcRoleRm(ulong vcId)
 | 
			
		||||
        {
 | 
			
		||||
            if (_service.RemoveVcRole(ctx.Guild.Id, vcId))
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.vcrole_removed(Format.Bold(vcId.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.vcrole_removed(Format.Bold(vcId.ToString()))).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.vcrole_not_found);
 | 
			
		||||
                await Response().Error(strs.vcrole_not_found).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -32,19 +32,19 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            if (vc is null || vc.GuildId != user.GuildId)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.must_be_in_voice);
 | 
			
		||||
                await Response().Error(strs.must_be_in_voice).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (role is null)
 | 
			
		||||
            {
 | 
			
		||||
                if (_service.RemoveVcRole(ctx.Guild.Id, vc.Id))
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.vcrole_removed(Format.Bold(vc.Name)));
 | 
			
		||||
                    await Response().Confirm(strs.vcrole_removed(Format.Bold(vc.Name))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _service.AddVcRole(ctx.Guild.Id, role, vc.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.vcrole_added(Format.Bold(vc.Name), Format.Bold(role.Name)));
 | 
			
		||||
                await Response().Confirm(strs.vcrole_added(Format.Bold(vc.Name), Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -68,10 +68,10 @@ public partial class Administration
 | 
			
		||||
            else
 | 
			
		||||
                text = GetText(strs.no_vcroles);
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(_eb.Create()
 | 
			
		||||
            await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                            .WithOkColor()
 | 
			
		||||
                                            .WithTitle(GetText(strs.vc_role_list))
 | 
			
		||||
                                            .WithDescription(text));
 | 
			
		||||
                                            .WithDescription(text)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -32,13 +32,13 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
 | 
			
		||||
        var ex = await _service.AddAsync(ctx.Guild?.Id, key, message);
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(_eb.Create()
 | 
			
		||||
                                        .WithOkColor()
 | 
			
		||||
                                        .WithTitle(GetText(strs.expr_new))
 | 
			
		||||
                                        .WithDescription($"#{new kwum(ex.Id)}")
 | 
			
		||||
                                        .AddField(GetText(strs.trigger), key)
 | 
			
		||||
                                        .AddField(GetText(strs.response),
 | 
			
		||||
                                            message.Length > 1024 ? GetText(strs.redacted_too_long) : message));
 | 
			
		||||
        await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                            .WithOkColor()
 | 
			
		||||
                            .WithTitle(GetText(strs.expr_new))
 | 
			
		||||
                            .WithDescription($"#{new kwum(ex.Id)}")
 | 
			
		||||
                            .AddField(GetText(strs.trigger), key)
 | 
			
		||||
                            .AddField(GetText(strs.response),
 | 
			
		||||
                                message.Length > 1024 ? GetText(strs.redacted_too_long) : message)).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -47,11 +47,11 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
    {
 | 
			
		||||
        var result = await _service.ToggleGlobalExpressionsAsync(ctx.Guild.Id);
 | 
			
		||||
        if (result)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.expr_global_disabled);
 | 
			
		||||
            await Response().Confirm(strs.expr_global_disabled).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.expr_global_enabled);
 | 
			
		||||
            await Response().Confirm(strs.expr_global_enabled).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
    [UserPerm(GuildPerm.Administrator)]
 | 
			
		||||
    public async Task ExprAddServer(string key, [Leftover] string message)
 | 
			
		||||
@@ -74,7 +74,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
 | 
			
		||||
        if (!AdminInGuildOrOwnerInDm())
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
 | 
			
		||||
            await Response().Error(strs.expr_insuff_perms).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -93,14 +93,14 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
        if ((channel is null && !_creds.IsOwner(ctx.User))
 | 
			
		||||
            || (channel is not null && !((IGuildUser)ctx.User).GuildPermissions.Administrator))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
 | 
			
		||||
            await Response().Error(strs.expr_insuff_perms).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var ex = await _service.EditAsync(ctx.Guild?.Id, id, message);
 | 
			
		||||
        if (ex is not null)
 | 
			
		||||
        {
 | 
			
		||||
            await ctx.Channel.EmbedAsync(_eb.Create()
 | 
			
		||||
            await ctx.Channel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                                            .WithOkColor()
 | 
			
		||||
                                            .WithTitle(GetText(strs.expr_edited))
 | 
			
		||||
                                            .WithDescription($"#{id}")
 | 
			
		||||
@@ -110,7 +110,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
 | 
			
		||||
            await Response().Error(strs.expr_no_found_id).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -127,7 +127,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
 | 
			
		||||
        if (expressions is null || !expressions.Any())
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_no_found);
 | 
			
		||||
            await Response().Error(strs.expr_no_found).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -146,7 +146,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
                                                        : " // " + string.Join(" ", ex.GetReactions())))
 | 
			
		||||
                                      .Join('\n');
 | 
			
		||||
 | 
			
		||||
                return _eb.Create().WithOkColor().WithTitle(GetText(strs.expressions)).WithDescription(desc);
 | 
			
		||||
                return new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.expressions)).WithDescription(desc);
 | 
			
		||||
            },
 | 
			
		||||
            expressions.Length,
 | 
			
		||||
            20);
 | 
			
		||||
@@ -159,11 +159,11 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
 | 
			
		||||
        if (found is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
 | 
			
		||||
            await Response().Error(strs.expr_no_found_id).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await ctx.Channel.EmbedAsync(_eb.Create()
 | 
			
		||||
        await ctx.Channel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                                        .WithOkColor()
 | 
			
		||||
                                        .WithDescription($"#{id}")
 | 
			
		||||
                                        .AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024))
 | 
			
		||||
@@ -177,7 +177,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
 | 
			
		||||
        if (ex is not null)
 | 
			
		||||
        {
 | 
			
		||||
            await ctx.Channel.EmbedAsync(_eb.Create()
 | 
			
		||||
            await ctx.Channel.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                                            .WithOkColor()
 | 
			
		||||
                                            .WithTitle(GetText(strs.expr_deleted))
 | 
			
		||||
                                            .WithDescription($"#{id}")
 | 
			
		||||
@@ -186,7 +186,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
 | 
			
		||||
            await Response().Error(strs.expr_no_found_id).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -201,7 +201,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
    {
 | 
			
		||||
        if (!AdminInGuildOrOwnerInDm())
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
 | 
			
		||||
            await Response().Error(strs.expr_insuff_perms).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -213,21 +213,21 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
    {
 | 
			
		||||
        if (!AdminInGuildOrOwnerInDm())
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
 | 
			
		||||
            await Response().Error(strs.expr_insuff_perms).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var ex = _service.GetExpression(ctx.Guild?.Id, id);
 | 
			
		||||
        if (ex is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
 | 
			
		||||
            await Response().Error(strs.expr_no_found_id).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (emojiStrs.Length == 0)
 | 
			
		||||
        {
 | 
			
		||||
            await _service.ResetExprReactions(ctx.Guild?.Id, id);
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.expr_reset(Format.Bold(id.ToString())));
 | 
			
		||||
            await Response().Confirm(strs.expr_reset(Format.Bold(id.ToString()))).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -253,15 +253,17 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
 | 
			
		||||
        if (succ.Count == 0)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.invalid_emojis);
 | 
			
		||||
            await Response().Error(strs.invalid_emojis).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await _service.SetExprReactions(ctx.Guild?.Id, id, succ);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.expr_set(Format.Bold(id.ToString()),
 | 
			
		||||
            succ.Select(static x => x.ToString()).Join(", ")));
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Confirm(strs.expr_set(Format.Bold(id.ToString()),
 | 
			
		||||
                  succ.Select(static x => x.ToString()).Join(", ")))
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -293,26 +295,30 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
    {
 | 
			
		||||
        if (!AdminInGuildOrOwnerInDm())
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
 | 
			
		||||
            await Response().Error(strs.expr_insuff_perms).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var (success, newVal) = await _service.ToggleExprOptionAsync(ctx.Guild?.Id, id, option);
 | 
			
		||||
        if (!success)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
 | 
			
		||||
            await Response().Error(strs.expr_no_found_id).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (newVal)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.option_enabled(Format.Code(option.ToString()),
 | 
			
		||||
                Format.Code(id.ToString())));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.option_enabled(Format.Code(option.ToString()),
 | 
			
		||||
                      Format.Code(id.ToString())))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.option_disabled(Format.Code(option.ToString()),
 | 
			
		||||
                Format.Code(id.ToString())));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.option_disabled(Format.Code(option.ToString()),
 | 
			
		||||
                      Format.Code(id.ToString())))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -321,12 +327,12 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
    [UserPerm(GuildPerm.Administrator)]
 | 
			
		||||
    public async Task ExprClear()
 | 
			
		||||
    {
 | 
			
		||||
        if (await PromptUserConfirmAsync(_eb.Create()
 | 
			
		||||
        if (await PromptUserConfirmAsync(new EmbedBuilder()
 | 
			
		||||
                                            .WithTitle("Expression clear")
 | 
			
		||||
                                            .WithDescription("This will delete all expressions on this server.")))
 | 
			
		||||
        {
 | 
			
		||||
            var count = _service.DeleteAllExpressions(ctx.Guild.Id);
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.exprs_cleared(count));
 | 
			
		||||
            await Response().Confirm(strs.exprs_cleared(count)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -335,7 +341,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
    {
 | 
			
		||||
        if (!AdminInGuildOrOwnerInDm())
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
 | 
			
		||||
            await Response().Error(strs.expr_insuff_perms).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -354,7 +360,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
    {
 | 
			
		||||
        if (!AdminInGuildOrOwnerInDm())
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
 | 
			
		||||
            await Response().Error(strs.expr_insuff_perms).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -367,7 +373,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
            var attachment = ctx.Message.Attachments.FirstOrDefault();
 | 
			
		||||
            if (attachment is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
 | 
			
		||||
                await Response().Error(strs.expr_import_no_input).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -376,7 +382,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(input))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
 | 
			
		||||
                await Response().Error(strs.expr_import_no_input).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -384,7 +390,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
 | 
			
		||||
        var succ = await _service.ImportExpressionsAsync(ctx.Guild?.Id, input);
 | 
			
		||||
        if (!succ)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.expr_import_invalid_data);
 | 
			
		||||
            await Response().Error(strs.expr_import_invalid_data).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -33,14 +33,14 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
 | 
			
		||||
        """;
 | 
			
		||||
 | 
			
		||||
    private static readonly ISerializer _exportSerializer = new SerializerBuilder()
 | 
			
		||||
        .WithEventEmitter(args
 | 
			
		||||
            => new MultilineScalarFlowStyleEmitter(args))
 | 
			
		||||
        .WithNamingConvention(CamelCaseNamingConvention.Instance)
 | 
			
		||||
        .WithIndentedSequences()
 | 
			
		||||
        .ConfigureDefaultValuesHandling(DefaultValuesHandling
 | 
			
		||||
            .OmitDefaults)
 | 
			
		||||
        .DisableAliases()
 | 
			
		||||
        .Build();
 | 
			
		||||
                                                            .WithEventEmitter(args
 | 
			
		||||
                                                                => new MultilineScalarFlowStyleEmitter(args))
 | 
			
		||||
                                                            .WithNamingConvention(CamelCaseNamingConvention.Instance)
 | 
			
		||||
                                                            .WithIndentedSequences()
 | 
			
		||||
                                                            .ConfigureDefaultValuesHandling(DefaultValuesHandling
 | 
			
		||||
                                                                .OmitDefaults)
 | 
			
		||||
                                                            .DisableAliases()
 | 
			
		||||
                                                            .Build();
 | 
			
		||||
 | 
			
		||||
    public int Priority
 | 
			
		||||
        => 0;
 | 
			
		||||
@@ -112,36 +112,39 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
 | 
			
		||||
    private async Task ReloadInternal(IReadOnlyList<ulong> allGuildIds)
 | 
			
		||||
    {
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
        var guildItems = await uow.Set<NadekoExpression>().AsNoTracking()
 | 
			
		||||
            .Where(x => allGuildIds.Contains(x.GuildId.Value))
 | 
			
		||||
            .ToListAsync();
 | 
			
		||||
        var guildItems = await uow.Set<NadekoExpression>()
 | 
			
		||||
                                  .AsNoTracking()
 | 
			
		||||
                                  .Where(x => allGuildIds.Contains(x.GuildId.Value))
 | 
			
		||||
                                  .ToListAsync();
 | 
			
		||||
 | 
			
		||||
        newguildExpressions = guildItems.GroupBy(k => k.GuildId!.Value)
 | 
			
		||||
            .ToDictionary(g => g.Key,
 | 
			
		||||
                g => g.Select(x =>
 | 
			
		||||
                    {
 | 
			
		||||
                        x.Trigger = x.Trigger.Replace(MENTION_PH, _client.CurrentUser.Mention);
 | 
			
		||||
                        return x;
 | 
			
		||||
                    })
 | 
			
		||||
                    .ToArray())
 | 
			
		||||
            .ToConcurrent();
 | 
			
		||||
                                        .ToDictionary(g => g.Key,
 | 
			
		||||
                                            g => g.Select(x =>
 | 
			
		||||
                                                  {
 | 
			
		||||
                                                      x.Trigger = x.Trigger.Replace(MENTION_PH,
 | 
			
		||||
                                                          _client.CurrentUser.Mention);
 | 
			
		||||
                                                      return x;
 | 
			
		||||
                                                  })
 | 
			
		||||
                                                  .ToArray())
 | 
			
		||||
                                        .ToConcurrent();
 | 
			
		||||
 | 
			
		||||
        _disabledGlobalExpressionGuilds = new(await uow.Set<GuildConfig>()
 | 
			
		||||
            .Where(x => x.DisableGlobalExpressions)
 | 
			
		||||
            .Select(x => x.GuildId)
 | 
			
		||||
            .ToListAsyncLinqToDB());
 | 
			
		||||
                                                       .Where(x => x.DisableGlobalExpressions)
 | 
			
		||||
                                                       .Select(x => x.GuildId)
 | 
			
		||||
                                                       .ToListAsyncLinqToDB());
 | 
			
		||||
 | 
			
		||||
        lock (_gexprWriteLock)
 | 
			
		||||
        {
 | 
			
		||||
            var globalItems = uow.Set<NadekoExpression>().AsNoTracking()
 | 
			
		||||
                .Where(x => x.GuildId == null || x.GuildId == 0)
 | 
			
		||||
                .AsEnumerable()
 | 
			
		||||
                .Select(x =>
 | 
			
		||||
                {
 | 
			
		||||
                    x.Trigger = x.Trigger.Replace(MENTION_PH, _client.CurrentUser.Mention);
 | 
			
		||||
                    return x;
 | 
			
		||||
                })
 | 
			
		||||
                .ToArray();
 | 
			
		||||
            var globalItems = uow.Set<NadekoExpression>()
 | 
			
		||||
                                 .AsNoTracking()
 | 
			
		||||
                                 .Where(x => x.GuildId == null || x.GuildId == 0)
 | 
			
		||||
                                 .AsEnumerable()
 | 
			
		||||
                                 .Select(x =>
 | 
			
		||||
                                 {
 | 
			
		||||
                                     x.Trigger = x.Trigger.Replace(MENTION_PH, _client.CurrentUser.Mention);
 | 
			
		||||
                                     return x;
 | 
			
		||||
                                 })
 | 
			
		||||
                                 .ToArray();
 | 
			
		||||
 | 
			
		||||
            globalExpressions = globalItems;
 | 
			
		||||
        }
 | 
			
		||||
@@ -262,7 +265,10 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            await msg.Channel.SendErrorAsync(_eb, permissionMessage);
 | 
			
		||||
                            await msg.Channel
 | 
			
		||||
                                     .Response(_strings, _eb)
 | 
			
		||||
                                     .Error(permissionMessage)
 | 
			
		||||
                                     .SendAsync();
 | 
			
		||||
                        }
 | 
			
		||||
                        catch
 | 
			
		||||
                        {
 | 
			
		||||
@@ -552,19 +558,20 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
 | 
			
		||||
        foreach (var entry in data)
 | 
			
		||||
        {
 | 
			
		||||
            var trigger = entry.Key;
 | 
			
		||||
            await uow.Set<NadekoExpression>().AddRangeAsync(entry.Value
 | 
			
		||||
                .Where(expr => !string.IsNullOrWhiteSpace(expr.Res))
 | 
			
		||||
                .Select(expr => new NadekoExpression
 | 
			
		||||
                {
 | 
			
		||||
                    GuildId = guildId,
 | 
			
		||||
                    Response = expr.Res,
 | 
			
		||||
                    Reactions = expr.React?.Join("@@@"),
 | 
			
		||||
                    Trigger = trigger,
 | 
			
		||||
                    AllowTarget = expr.At,
 | 
			
		||||
                    ContainsAnywhere = expr.Ca,
 | 
			
		||||
                    DmResponse = expr.Dm,
 | 
			
		||||
                    AutoDeleteTrigger = expr.Ad
 | 
			
		||||
                }));
 | 
			
		||||
            await uow.Set<NadekoExpression>()
 | 
			
		||||
                     .AddRangeAsync(entry.Value
 | 
			
		||||
                                         .Where(expr => !string.IsNullOrWhiteSpace(expr.Res))
 | 
			
		||||
                                         .Select(expr => new NadekoExpression
 | 
			
		||||
                                         {
 | 
			
		||||
                                             GuildId = guildId,
 | 
			
		||||
                                             Response = expr.Res,
 | 
			
		||||
                                             Reactions = expr.React?.Join("@@@"),
 | 
			
		||||
                                             Trigger = trigger,
 | 
			
		||||
                                             AllowTarget = expr.At,
 | 
			
		||||
                                             ContainsAnywhere = expr.Ca,
 | 
			
		||||
                                             DmResponse = expr.Dm,
 | 
			
		||||
                                             AutoDeleteTrigger = expr.Ad
 | 
			
		||||
                                         }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await uow.SaveChangesAsync();
 | 
			
		||||
@@ -651,8 +658,13 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
    #region Basic Operations
 | 
			
		||||
 | 
			
		||||
    public async Task<NadekoExpression> AddAsync(ulong? guildId, string key, string message,
 | 
			
		||||
        bool ca = false, bool ad = false, bool dm = false)
 | 
			
		||||
    public async Task<NadekoExpression> AddAsync(
 | 
			
		||||
        ulong? guildId,
 | 
			
		||||
        string key,
 | 
			
		||||
        string message,
 | 
			
		||||
        bool ca = false,
 | 
			
		||||
        bool ad = false,
 | 
			
		||||
        bool dm = false)
 | 
			
		||||
    {
 | 
			
		||||
        key = key.ToLowerInvariant();
 | 
			
		||||
        var expr = new NadekoExpression
 | 
			
		||||
@@ -679,8 +691,13 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
 | 
			
		||||
        return expr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task<NadekoExpression> EditAsync(ulong? guildId, int id, string message,
 | 
			
		||||
        bool? ca = null, bool? ad = null, bool? dm = null)
 | 
			
		||||
    public async Task<NadekoExpression> EditAsync(
 | 
			
		||||
        ulong? guildId,
 | 
			
		||||
        int id,
 | 
			
		||||
        string message,
 | 
			
		||||
        bool? ca = null,
 | 
			
		||||
        bool? ad = null,
 | 
			
		||||
        bool? dm = null)
 | 
			
		||||
    {
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
        var expr = uow.Set<NadekoExpression>().GetById(id);
 | 
			
		||||
@@ -756,17 +773,19 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public async Task<(IReadOnlyCollection<NadekoExpression> Exprs, int TotalCount)> FindExpressionsAsync(ulong guildId,
 | 
			
		||||
        string query, int page)
 | 
			
		||||
    public async Task<(IReadOnlyCollection<NadekoExpression> Exprs, int TotalCount)> FindExpressionsAsync(
 | 
			
		||||
        ulong guildId,
 | 
			
		||||
        string query,
 | 
			
		||||
        int page)
 | 
			
		||||
    {
 | 
			
		||||
        await using var ctx = _db.GetDbContext();
 | 
			
		||||
 | 
			
		||||
        if (newguildExpressions.TryGetValue(guildId, out var exprs))
 | 
			
		||||
        {
 | 
			
		||||
            return (exprs.Where(x => x.Trigger.Contains(query))
 | 
			
		||||
                .Skip(page * 9)
 | 
			
		||||
                .Take(9)
 | 
			
		||||
                .ToArray(), exprs.Length);
 | 
			
		||||
                         .Skip(page * 9)
 | 
			
		||||
                         .Take(9)
 | 
			
		||||
                         .ToArray(), exprs.Length);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ([], 0);
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,9 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            var ar = new AnimalRace(options, _cs, _gamesConf.Data.RaceAnimals.Shuffle());
 | 
			
		||||
            if (!_service.AnimalRaces.TryAdd(ctx.Guild.Id, ar))
 | 
			
		||||
                return SendErrorAsync(GetText(strs.animal_race), GetText(strs.animal_race_already_started));
 | 
			
		||||
                return Response()
 | 
			
		||||
                       .Error(GetText(strs.animal_race), GetText(strs.animal_race_already_started))
 | 
			
		||||
                       .SendAsync();
 | 
			
		||||
 | 
			
		||||
            ar.Initialize();
 | 
			
		||||
 | 
			
		||||
@@ -71,15 +73,19 @@ public partial class Gambling
 | 
			
		||||
                var winner = race.FinishedUsers[0];
 | 
			
		||||
                if (race.FinishedUsers[0].Bet > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    return SendConfirmAsync(GetText(strs.animal_race),
 | 
			
		||||
                        GetText(strs.animal_race_won_money(Format.Bold(winner.Username),
 | 
			
		||||
                            winner.Animal.Icon,
 | 
			
		||||
                            (race.FinishedUsers[0].Bet * (race.Users.Count - 1)) + CurrencySign)));
 | 
			
		||||
                    return Response()
 | 
			
		||||
                           .Confirm(GetText(strs.animal_race),
 | 
			
		||||
                               GetText(strs.animal_race_won_money(Format.Bold(winner.Username),
 | 
			
		||||
                                   winner.Animal.Icon,
 | 
			
		||||
                                   (race.FinishedUsers[0].Bet * (race.Users.Count - 1)) + CurrencySign)))
 | 
			
		||||
                           .SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ar.Dispose();
 | 
			
		||||
                return SendConfirmAsync(GetText(strs.animal_race),
 | 
			
		||||
                    GetText(strs.animal_race_won(Format.Bold(winner.Username), winner.Animal.Icon)));
 | 
			
		||||
                return Response()
 | 
			
		||||
                       .Confirm(GetText(strs.animal_race),
 | 
			
		||||
                           GetText(strs.animal_race_won(Format.Bold(winner.Username), winner.Animal.Icon)))
 | 
			
		||||
                       .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ar.OnStartingFailed += Ar_OnStartingFailed;
 | 
			
		||||
@@ -88,17 +94,21 @@ public partial class Gambling
 | 
			
		||||
            ar.OnStarted += Ar_OnStarted;
 | 
			
		||||
            _client.MessageReceived += ClientMessageReceived;
 | 
			
		||||
 | 
			
		||||
            return SendConfirmAsync(GetText(strs.animal_race),
 | 
			
		||||
                GetText(strs.animal_race_starting(options.StartTime)),
 | 
			
		||||
                footer: GetText(strs.animal_race_join_instr(prefix)));
 | 
			
		||||
            return Response()
 | 
			
		||||
                   .Confirm(GetText(strs.animal_race),
 | 
			
		||||
                       GetText(strs.animal_race_starting(options.StartTime)),
 | 
			
		||||
                       footer: GetText(strs.animal_race_join_instr(prefix)))
 | 
			
		||||
                   .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Ar_OnStarted(AnimalRace race)
 | 
			
		||||
        {
 | 
			
		||||
            if (race.Users.Count == race.MaxUsers)
 | 
			
		||||
                return SendConfirmAsync(GetText(strs.animal_race), GetText(strs.animal_race_full));
 | 
			
		||||
            return SendConfirmAsync(GetText(strs.animal_race),
 | 
			
		||||
                GetText(strs.animal_race_starting_with_x(race.Users.Count)));
 | 
			
		||||
                return Response().Confirm(GetText(strs.animal_race), GetText(strs.animal_race_full)).SendAsync();
 | 
			
		||||
            return Response()
 | 
			
		||||
                   .Confirm(GetText(strs.animal_race),
 | 
			
		||||
                       GetText(strs.animal_race_starting_with_x(race.Users.Count)))
 | 
			
		||||
                   .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task Ar_OnStateUpdate(AnimalRace race)
 | 
			
		||||
@@ -115,10 +125,10 @@ public partial class Gambling
 | 
			
		||||
            var msg = raceMessage;
 | 
			
		||||
 | 
			
		||||
            if (msg is null)
 | 
			
		||||
                raceMessage = await SendConfirmAsync(text);
 | 
			
		||||
                raceMessage = await Response().Confirm(text).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await msg.ModifyAsync(x => x.Embed = _eb.Create()
 | 
			
		||||
                await msg.ModifyAsync(x => x.Embed = new EmbedBuilder()
 | 
			
		||||
                                                        .WithTitle(GetText(strs.animal_race))
 | 
			
		||||
                                                        .WithDescription(text)
 | 
			
		||||
                                                        .WithOkColor()
 | 
			
		||||
@@ -130,7 +140,7 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            _service.AnimalRaces.TryRemove(ctx.Guild.Id, out _);
 | 
			
		||||
            race.Dispose();
 | 
			
		||||
            return ReplyErrorLocalizedAsync(strs.animal_race_failed);
 | 
			
		||||
            return Response().Error(strs.animal_race_failed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -142,7 +152,7 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            if (!_service.AnimalRaces.TryGetValue(ctx.Guild.Id, out var ar))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.race_not_exist);
 | 
			
		||||
                await Response().Error(strs.race_not_exist).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -151,12 +161,16 @@ public partial class Gambling
 | 
			
		||||
                var user = await ar.JoinRace(ctx.User.Id, ctx.User.ToString(), amount);
 | 
			
		||||
                if (amount > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    await SendConfirmAsync(GetText(strs.animal_race_join_bet(ctx.User.Mention,
 | 
			
		||||
                        user.Animal.Icon,
 | 
			
		||||
                        amount + CurrencySign)));
 | 
			
		||||
                    await Response()
 | 
			
		||||
                          .Confirm(GetText(strs.animal_race_join_bet(ctx.User.Mention,
 | 
			
		||||
                              user.Animal.Icon,
 | 
			
		||||
                              amount + CurrencySign)))
 | 
			
		||||
                          .SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                    await SendConfirmAsync(GetText(strs.animal_race_join(ctx.User.Mention, user.Animal.Icon)));
 | 
			
		||||
                    await Response()
 | 
			
		||||
                          .Confirm(GetText(strs.animal_race_join(ctx.User.Mention, user.Animal.Icon)))
 | 
			
		||||
                          .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (ArgumentOutOfRangeException)
 | 
			
		||||
            {
 | 
			
		||||
@@ -172,11 +186,11 @@ public partial class Gambling
 | 
			
		||||
            }
 | 
			
		||||
            catch (AnimalRaceFullException)
 | 
			
		||||
            {
 | 
			
		||||
                await SendConfirmAsync(GetText(strs.animal_race), GetText(strs.animal_race_full));
 | 
			
		||||
                await Response().Confirm(GetText(strs.animal_race), GetText(strs.animal_race_full)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (NotEnoughFundsException)
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync(GetText(strs.not_enough(CurrencySign)));
 | 
			
		||||
                await Response().Error(GetText(strs.not_enough(CurrencySign))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -30,11 +30,11 @@ public partial class Gambling
 | 
			
		||||
            
 | 
			
		||||
            if (await _bank.DepositAsync(ctx.User.Id, amount))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.bank_deposited(N(amount)));
 | 
			
		||||
                await Response().Confirm(strs.bank_deposited(N(amount))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
@@ -46,11 +46,11 @@ public partial class Gambling
 | 
			
		||||
            
 | 
			
		||||
            if (await _bank.WithdrawAsync(ctx.User.Id, amount))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.bank_withdrew(N(amount)));
 | 
			
		||||
                await Response().Confirm(strs.bank_withdrew(N(amount))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.bank_withdraw_insuff(CurrencySign));
 | 
			
		||||
                await Response().Error(strs.bank_withdraw_insuff(CurrencySign)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
@@ -59,7 +59,7 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            var bal = await _bank.GetBalanceAsync(ctx.User.Id);
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithDescription(GetText(strs.bank_balance(N(bal))));
 | 
			
		||||
 | 
			
		||||
@@ -70,7 +70,7 @@ public partial class Gambling
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.cant_dm);
 | 
			
		||||
                await Response().Error(strs.cant_dm).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -82,10 +82,10 @@ public partial class Gambling
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.take_fail(N(amount),
 | 
			
		||||
            await Response().Error(strs.take_fail(N(amount),
 | 
			
		||||
                _client.GetUser(userId)?.ToString()
 | 
			
		||||
                ?? userId.ToString(),
 | 
			
		||||
                CurrencySign));
 | 
			
		||||
                CurrencySign)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private async Task BankAwardInternalAsync(long amount, ulong userId)
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ public partial class Gambling
 | 
			
		||||
                if (!await bj.Join(ctx.User, amount))
 | 
			
		||||
                {
 | 
			
		||||
                    _service.Games.TryRemove(ctx.Channel.Id, out _);
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                    await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -50,12 +50,12 @@ public partial class Gambling
 | 
			
		||||
                bj.GameEnded += Bj_GameEnded;
 | 
			
		||||
                bj.Start();
 | 
			
		||||
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.bj_created);
 | 
			
		||||
                await Response().Confirm(strs.bj_created).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (await bj.Join(ctx.User, amount))
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.bj_joined);
 | 
			
		||||
                    await Response().Confirm(strs.bj_joined).SendAsync();
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    Log.Information("{User} can't join a blackjack game as it's in {BlackjackState} state already",
 | 
			
		||||
@@ -95,7 +95,7 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
                var cStr = string.Concat(c.Select(x => x[..^1] + " "));
 | 
			
		||||
                cStr += "\n" + string.Concat(c.Select(x => x.Last() + " "));
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithOkColor()
 | 
			
		||||
                               .WithTitle("BlackJack")
 | 
			
		||||
                               .AddField($"{dealerIcon} Dealer's Hand | Value: {bj.Dealer.GetHandValue()}", cStr);
 | 
			
		||||
@@ -128,7 +128,7 @@ public partial class Gambling
 | 
			
		||||
                    embed.AddField(full, cStr);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                msg = await EmbedAsync(embed);
 | 
			
		||||
                msg = await Response().Embed(embed).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
@@ -174,7 +174,7 @@ public partial class Gambling
 | 
			
		||||
            else if (a == BjAction.Double)
 | 
			
		||||
            {
 | 
			
		||||
                if (!await bj.Double(ctx.User))
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                    await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ctx.Message.DeleteAsync();
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ public partial class Gambling
 | 
			
		||||
            {
 | 
			
		||||
                if (!await _cs.RemoveAsync(ctx.User.Id, options.Bet, new("connect4", "bet")))
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                    await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
                    _service.Connect4Games.TryRemove(ctx.Channel.Id, out _);
 | 
			
		||||
                    game.Dispose();
 | 
			
		||||
                    return;
 | 
			
		||||
@@ -82,9 +82,9 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            game.Initialize();
 | 
			
		||||
            if (options.Bet == 0)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.connect4_created);
 | 
			
		||||
                await Response().Confirm(strs.connect4_created).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.connect4_created_bet(N(options.Bet)));
 | 
			
		||||
                await Response().Error(strs.connect4_created_bet(N(options.Bet))).SendAsync();
 | 
			
		||||
 | 
			
		||||
            Task ClientMessageReceived(SocketMessage arg)
 | 
			
		||||
            {
 | 
			
		||||
@@ -125,7 +125,7 @@ public partial class Gambling
 | 
			
		||||
                    toDispose.Dispose();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return ErrorLocalizedAsync(strs.connect4_failed_to_start);
 | 
			
		||||
                return Response().Error(strs.connect4_failed_to_start).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Task GameOnGameEnded(Connect4Game arg, Connect4Game.Result result)
 | 
			
		||||
@@ -150,7 +150,7 @@ public partial class Gambling
 | 
			
		||||
                else
 | 
			
		||||
                    title = GetText(strs.connect4_draw);
 | 
			
		||||
 | 
			
		||||
                return msg.ModifyAsync(x => x.Embed = _eb.Create()
 | 
			
		||||
                return msg.ModifyAsync(x => x.Embed = new EmbedBuilder()
 | 
			
		||||
                                                         .WithTitle(title)
 | 
			
		||||
                                                         .WithDescription(GetGameStateText(game))
 | 
			
		||||
                                                         .WithOkColor()
 | 
			
		||||
@@ -160,14 +160,14 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
        private async Task Game_OnGameStateUpdated(Connect4Game game)
 | 
			
		||||
        {
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithTitle($"{game.CurrentPlayer.Username} vs {game.OtherPlayer.Username}")
 | 
			
		||||
                           .WithDescription(GetGameStateText(game))
 | 
			
		||||
                           .WithOkColor();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if (msg is null)
 | 
			
		||||
                msg = await EmbedAsync(embed);
 | 
			
		||||
                msg = await Response().Embed(embed).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await msg.ModifyAsync(x => x.Embed = embed.Build());
 | 
			
		||||
        }
 | 
			
		||||
@@ -198,6 +198,7 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            for (var i = 0; i < Connect4Game.NUMBER_OF_COLUMNS; i++)
 | 
			
		||||
                sb.Append(_numbers[i]);
 | 
			
		||||
            
 | 
			
		||||
            return sb.ToString();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            var fileName = $"dice.{format.FileExtensions.First()}";
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithAuthor(ctx.User)
 | 
			
		||||
                .AddField(GetText(strs.roll2), gen)
 | 
			
		||||
@@ -74,7 +74,7 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            if (num is < 1 or > 30)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.dice_invalid_number(1, 30));
 | 
			
		||||
                await Response().Error(strs.dice_invalid_number(1, 30)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -115,7 +115,7 @@ public partial class Gambling
 | 
			
		||||
                d.Dispose();
 | 
			
		||||
 | 
			
		||||
            var imageName = $"dice.{format.FileExtensions.First()}";
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithAuthor(ctx.User)
 | 
			
		||||
                .AddField(GetText(strs.rolls), values.Select(x => Format.Code(x.ToString())).Join(' '), true)
 | 
			
		||||
@@ -141,14 +141,14 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
                for (var i = 0; i < n1; i++)
 | 
			
		||||
                    rolls.Add(_fateRolls[rng.Next(0, _fateRolls.Length)]);
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithOkColor()
 | 
			
		||||
                               .WithAuthor(ctx.User)
 | 
			
		||||
                               .WithDescription(GetText(strs.dice_rolled_num(Format.Bold(n1.ToString()))))
 | 
			
		||||
                               .AddField(Format.Bold("Result"),
 | 
			
		||||
                                   string.Join(" ", rolls.Select(c => Format.Code($"[{c}]"))));
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else if ((match = _dndRegex.Match(arg)).Length != 0)
 | 
			
		||||
            {
 | 
			
		||||
@@ -170,7 +170,7 @@ public partial class Gambling
 | 
			
		||||
                        arr[i] = rng.Next(1, n2 + 1);
 | 
			
		||||
 | 
			
		||||
                    var sum = arr.Sum();
 | 
			
		||||
                    var embed = _eb.Create()
 | 
			
		||||
                    var embed = new EmbedBuilder()
 | 
			
		||||
                                   .WithOkColor()
 | 
			
		||||
                                   .WithAuthor(ctx.User)
 | 
			
		||||
                                   .WithDescription(GetText(strs.dice_rolled_num(n1 + $"`1 - {n2}`")))
 | 
			
		||||
@@ -180,7 +180,7 @@ public partial class Gambling
 | 
			
		||||
                                               => Format.Code(x.ToString()))))
 | 
			
		||||
                                   .AddField(Format.Bold("Sum"),
 | 
			
		||||
                                       sum + " + " + add + " - " + sub + " = " + (sum + add - sub));
 | 
			
		||||
                    await EmbedAsync(embed);
 | 
			
		||||
                    await Response().Embed(embed).SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -194,7 +194,7 @@ public partial class Gambling
 | 
			
		||||
                var arr = range.Split('-').Take(2).Select(int.Parse).ToArray();
 | 
			
		||||
                if (arr[0] > arr[1])
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.second_larger_than_first);
 | 
			
		||||
                    await Response().Error(strs.second_larger_than_first).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -203,7 +203,7 @@ public partial class Gambling
 | 
			
		||||
            else
 | 
			
		||||
                rolled = new NadekoRandom().Next(0, int.Parse(range) + 1);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.dice_rolled(Format.Bold(rolled.ToString())));
 | 
			
		||||
            await Response().Confirm(strs.dice_rolled(Format.Bold(rolled.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<Image<Rgba32>> GetDiceAsync(int num)
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ public partial class Gambling
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await ReplyErrorLocalizedAsync(strs.no_more_cards);
 | 
			
		||||
                        await Response().Error(strs.no_more_cards).SendAsync();
 | 
			
		||||
                    }
 | 
			
		||||
                    catch
 | 
			
		||||
                    {
 | 
			
		||||
@@ -55,7 +55,7 @@ public partial class Gambling
 | 
			
		||||
            foreach (var i in images)
 | 
			
		||||
                i.Dispose();
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                .WithOkColor();
 | 
			
		||||
            
 | 
			
		||||
            var toSend = string.Empty;
 | 
			
		||||
@@ -131,7 +131,7 @@ public partial class Gambling
 | 
			
		||||
                    return c;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.deck_reshuffled);
 | 
			
		||||
            await Response().Confirm(strs.deck_reshuffled).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -156,11 +156,11 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            if (!res.TryPickT0(out var result, out _))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithAuthor(ctx.User)
 | 
			
		||||
                .WithDescription(result.Card.GetEmoji())
 | 
			
		||||
 
 | 
			
		||||
@@ -24,18 +24,18 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            var (opts, _) = OptionsParser.ParseFrom(new EventOptions(), options);
 | 
			
		||||
            if (!await _service.TryCreateEventAsync(ctx.Guild.Id, ctx.Channel.Id, ev, opts, GetEmbed))
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.start_event_fail);
 | 
			
		||||
                await Response().Error(strs.start_event_fail).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private IEmbedBuilder GetEmbed(CurrencyEvent.Type type, EventOptions opts, long currentPot)
 | 
			
		||||
        private EmbedBuilder GetEmbed(CurrencyEvent.Type type, EventOptions opts, long currentPot)
 | 
			
		||||
            => type switch
 | 
			
		||||
            {
 | 
			
		||||
                CurrencyEvent.Type.Reaction => _eb.Create()
 | 
			
		||||
                CurrencyEvent.Type.Reaction => new EmbedBuilder()
 | 
			
		||||
                                                  .WithOkColor()
 | 
			
		||||
                                                  .WithTitle(GetText(strs.event_title(type.ToString())))
 | 
			
		||||
                                                  .WithDescription(GetReactionDescription(opts.Amount, currentPot))
 | 
			
		||||
                                                  .WithFooter(GetText(strs.event_duration_footer(opts.Hours))),
 | 
			
		||||
                CurrencyEvent.Type.GameStatus => _eb.Create()
 | 
			
		||||
                CurrencyEvent.Type.GameStatus => new EmbedBuilder()
 | 
			
		||||
                                                    .WithOkColor()
 | 
			
		||||
                                                    .WithTitle(GetText(strs.event_title(type.ToString())))
 | 
			
		||||
                                                    .WithDescription(GetGameStatusDescription(opts.Amount, currentPot))
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ public class CurrencyEventsService : INService
 | 
			
		||||
        ulong channelId,
 | 
			
		||||
        CurrencyEvent.Type type,
 | 
			
		||||
        EventOptions opts,
 | 
			
		||||
        Func<CurrencyEvent.Type, EventOptions, long, IEmbedBuilder> embed)
 | 
			
		||||
        Func<CurrencyEvent.Type, EventOptions, long, EmbedBuilder> embed)
 | 
			
		||||
    {
 | 
			
		||||
        var g = _client.GetGuild(guildId);
 | 
			
		||||
        if (g?.GetChannel(channelId) is not ITextChannel ch)
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ public class GameStatusEvent : ICurrencyEvent
 | 
			
		||||
    private readonly ICurrencyService _cs;
 | 
			
		||||
    private readonly long _amount;
 | 
			
		||||
 | 
			
		||||
    private readonly Func<CurrencyEvent.Type, EventOptions, long, IEmbedBuilder> _embedFunc;
 | 
			
		||||
    private readonly Func<CurrencyEvent.Type, EventOptions, long, EmbedBuilder> _embedFunc;
 | 
			
		||||
    private readonly bool _isPotLimited;
 | 
			
		||||
    private readonly ITextChannel _channel;
 | 
			
		||||
    private readonly ConcurrentHashSet<ulong> _awardedUsers = new();
 | 
			
		||||
@@ -43,7 +43,7 @@ public class GameStatusEvent : ICurrencyEvent
 | 
			
		||||
        SocketGuild g,
 | 
			
		||||
        ITextChannel ch,
 | 
			
		||||
        EventOptions opt,
 | 
			
		||||
        Func<CurrencyEvent.Type, EventOptions, long, IEmbedBuilder> embedFunc)
 | 
			
		||||
        Func<CurrencyEvent.Type, EventOptions, long, EmbedBuilder> embedFunc)
 | 
			
		||||
    {
 | 
			
		||||
        _client = client;
 | 
			
		||||
        _guild = g;
 | 
			
		||||
@@ -113,7 +113,7 @@ public class GameStatusEvent : ICurrencyEvent
 | 
			
		||||
        _t.Change(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private IEmbedBuilder GetEmbed(long pot)
 | 
			
		||||
    private EmbedBuilder GetEmbed(long pot)
 | 
			
		||||
        => _embedFunc(CurrencyEvent.Type.GameStatus, _opts, pot);
 | 
			
		||||
 | 
			
		||||
    private async Task OnMessageDeleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> cacheable)
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ public class ReactionEvent : ICurrencyEvent
 | 
			
		||||
    private readonly ICurrencyService _cs;
 | 
			
		||||
    private readonly long _amount;
 | 
			
		||||
 | 
			
		||||
    private readonly Func<CurrencyEvent.Type, EventOptions, long, IEmbedBuilder> _embedFunc;
 | 
			
		||||
    private readonly Func<CurrencyEvent.Type, EventOptions, long, EmbedBuilder> _embedFunc;
 | 
			
		||||
    private readonly bool _isPotLimited;
 | 
			
		||||
    private readonly ITextChannel _channel;
 | 
			
		||||
    private readonly ConcurrentHashSet<ulong> _awardedUsers = new();
 | 
			
		||||
@@ -38,7 +38,7 @@ public class ReactionEvent : ICurrencyEvent
 | 
			
		||||
        ITextChannel ch,
 | 
			
		||||
        EventOptions opt,
 | 
			
		||||
        GamblingConfig config,
 | 
			
		||||
        Func<CurrencyEvent.Type, EventOptions, long, IEmbedBuilder> embedFunc)
 | 
			
		||||
        Func<CurrencyEvent.Type, EventOptions, long, EmbedBuilder> embedFunc)
 | 
			
		||||
    {
 | 
			
		||||
        _client = client;
 | 
			
		||||
        _guild = g;
 | 
			
		||||
@@ -109,7 +109,7 @@ public class ReactionEvent : ICurrencyEvent
 | 
			
		||||
        _t.Change(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private IEmbedBuilder GetEmbed(long pot)
 | 
			
		||||
    private EmbedBuilder GetEmbed(long pot)
 | 
			
		||||
        => _embedFunc(CurrencyEvent.Type.Reaction, _opts, pot);
 | 
			
		||||
 | 
			
		||||
    private async Task OnMessageDeleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> cacheable)
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            if (count is > 10 or < 1)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.flip_invalid(10));
 | 
			
		||||
                await Response().Error(strs.flip_invalid(10)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -84,7 +84,7 @@ public partial class Gambling
 | 
			
		||||
                    ? Format.Bold(GetText(strs.heads))
 | 
			
		||||
                    : Format.Bold(GetText(strs.tails))));
 | 
			
		||||
            
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithAuthor(ctx.User)
 | 
			
		||||
                .WithDescription(msg)
 | 
			
		||||
@@ -104,7 +104,7 @@ public partial class Gambling
 | 
			
		||||
            var res = await _service.BetFlipAsync(ctx.User.Id, amount, (byte)guess);
 | 
			
		||||
            if (!res.TryPickT0(out var result, out _))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -130,11 +130,11 @@ public partial class Gambling
 | 
			
		||||
                str = Format.Bold(GetText(strs.better_luck));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(_eb.Create()
 | 
			
		||||
            await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                .WithAuthor(ctx.User)
 | 
			
		||||
                                            .WithDescription(str)
 | 
			
		||||
                                            .WithOkColor()
 | 
			
		||||
                                            .WithImageUrl(imageToSend.ToString()));
 | 
			
		||||
                                            .WithImageUrl(imageToSend.ToString())).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -73,18 +73,18 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
    {
 | 
			
		||||
        var stats = await _gamblingTxTracker.GetAllAsync();
 | 
			
		||||
 | 
			
		||||
        var eb = _eb.Create(ctx)
 | 
			
		||||
            .WithOkColor();
 | 
			
		||||
        var eb = new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor();
 | 
			
		||||
 | 
			
		||||
        var str = "` Feature `|`   Bet  `|`Paid Out`|`  RoI  `\n";
 | 
			
		||||
        str += "――――――――――――――――――――\n";
 | 
			
		||||
        foreach (var stat in stats)
 | 
			
		||||
        {
 | 
			
		||||
            var perc = (stat.PaidOut / stat.Bet).ToString("P2", Culture);
 | 
			
		||||
            str += $"`{stat.Feature.PadBoth(9)}`" +
 | 
			
		||||
                   $"|`{stat.Bet.ToString("N0").PadLeft(8, ' ')}`" +
 | 
			
		||||
                   $"|`{stat.PaidOut.ToString("N0").PadLeft(8, ' ')}`" +
 | 
			
		||||
                   $"|`{perc.PadLeft(6, ' ')}`\n";
 | 
			
		||||
            str += $"`{stat.Feature.PadBoth(9)}`"
 | 
			
		||||
                   + $"|`{stat.Bet.ToString("N0").PadLeft(8, ' ')}`"
 | 
			
		||||
                   + $"|`{stat.PaidOut.ToString("N0").PadLeft(8, ' ')}`"
 | 
			
		||||
                   + $"|`{perc.PadLeft(6, ' ')}`\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var bet = stats.Sum(x => x.Bet);
 | 
			
		||||
@@ -95,14 +95,14 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        var tPerc = (paidOut / bet).ToString("P2", Culture);
 | 
			
		||||
        str += "――――――――――――――――――――\n";
 | 
			
		||||
        str += $"` {("TOTAL").PadBoth(7)}` " +
 | 
			
		||||
               $"|**{N(bet).PadLeft(8, ' ')}**" +
 | 
			
		||||
               $"|**{N(paidOut).PadLeft(8, ' ')}**" +
 | 
			
		||||
               $"|`{tPerc.PadLeft(6, ' ')}`";
 | 
			
		||||
        str += $"` {("TOTAL").PadBoth(7)}` "
 | 
			
		||||
               + $"|**{N(bet).PadLeft(8, ' ')}**"
 | 
			
		||||
               + $"|**{N(paidOut).PadLeft(8, ' ')}**"
 | 
			
		||||
               + $"|`{tPerc.PadLeft(6, ' ')}`";
 | 
			
		||||
 | 
			
		||||
        eb.WithDescription(str);
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(eb);
 | 
			
		||||
        await Response().Embed(eb).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -118,19 +118,19 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // [21:03] Bob Page: Kinda remids me of US economy
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
            .WithTitle(GetText(strs.economy_state))
 | 
			
		||||
            .AddField(GetText(strs.currency_owned), N(ec.Cash - ec.Bot))
 | 
			
		||||
            .AddField(GetText(strs.currency_one_percent), (onePercent * 100).ToString("F2") + "%")
 | 
			
		||||
            .AddField(GetText(strs.currency_planted), N(ec.Planted))
 | 
			
		||||
            .AddField(GetText(strs.owned_waifus_total), N(ec.Waifus))
 | 
			
		||||
            .AddField(GetText(strs.bot_currency), N(ec.Bot))
 | 
			
		||||
            .AddField(GetText(strs.bank_accounts), N(ec.Bank))
 | 
			
		||||
            .AddField(GetText(strs.total), N(ec.Cash + ec.Planted + ec.Waifus + ec.Bank))
 | 
			
		||||
            .WithOkColor();
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
                       .WithTitle(GetText(strs.economy_state))
 | 
			
		||||
                       .AddField(GetText(strs.currency_owned), N(ec.Cash - ec.Bot))
 | 
			
		||||
                       .AddField(GetText(strs.currency_one_percent), (onePercent * 100).ToString("F2") + "%")
 | 
			
		||||
                       .AddField(GetText(strs.currency_planted), N(ec.Planted))
 | 
			
		||||
                       .AddField(GetText(strs.owned_waifus_total), N(ec.Waifus))
 | 
			
		||||
                       .AddField(GetText(strs.bot_currency), N(ec.Bot))
 | 
			
		||||
                       .AddField(GetText(strs.bank_accounts), N(ec.Bank))
 | 
			
		||||
                       .AddField(GetText(strs.total), N(ec.Cash + ec.Planted + ec.Waifus + ec.Bank))
 | 
			
		||||
                       .WithOkColor();
 | 
			
		||||
 | 
			
		||||
        // ec.Cash already contains ec.Bot as it's the total of all values in the CurrencyAmount column of the DiscordUser table
 | 
			
		||||
        await EmbedAsync(embed);
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static readonly FeatureLimitKey _timelyKey = new FeatureLimitKey()
 | 
			
		||||
@@ -153,7 +153,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        await smc.RespondConfirmAsync(_eb, GetText(strs.remind_timely(tt)), ephemeral: true);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    private NadekoInteraction CreateRemindMeInteraction(int period)
 | 
			
		||||
    {
 | 
			
		||||
        return _inter
 | 
			
		||||
@@ -174,10 +174,10 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        var period = Config.Timely.Cooldown;
 | 
			
		||||
        if (val <= 0 || period <= 0)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.timely_none);
 | 
			
		||||
            await Response().Error(strs.timely_none).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        var inter = CreateRemindMeInteraction(period);
 | 
			
		||||
 | 
			
		||||
        if (await _service.ClaimTimelyAsync(ctx.User.Id, period) is { } rem)
 | 
			
		||||
@@ -187,10 +187,10 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            {
 | 
			
		||||
                inter = null;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            var now = DateTime.UtcNow;
 | 
			
		||||
            var relativeTag = TimestampTag.FromDateTime(now.Add(rem), TimestampTagStyles.Relative);
 | 
			
		||||
            await ReplyPendingLocalizedAsync(strs.timely_already_claimed(relativeTag), inter);
 | 
			
		||||
            await Response().Pending(strs.timely_already_claimed(relativeTag)).Interaction(inter).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -200,15 +200,15 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        await _cs.AddAsync(ctx.User.Id, val, new("timely", "claim"));
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.timely(N(val), period), inter);
 | 
			
		||||
        await Response().Confirm(strs.timely(N(val), period)).Interaction(inter).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
    [OwnerOnly]
 | 
			
		||||
    public async Task TimelyReset()
 | 
			
		||||
    {
 | 
			
		||||
        await _service.RemoveAllTimelyClaimsAsync();
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.timely_reset);
 | 
			
		||||
        await Response().Confirm(strs.timely_reset).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -228,11 +228,13 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        if (amount == 0)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.timely_set_none);
 | 
			
		||||
            await Response().Confirm(strs.timely_set_none).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.timely_set(Format.Bold(N(amount)), Format.Bold(period.ToString())));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.timely_set(Format.Bold(N(amount)), Format.Bold(period.ToString())))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -250,9 +252,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)];
 | 
			
		||||
        await SendConfirmAsync("🎟 " + GetText(strs.raffled_user),
 | 
			
		||||
            $"**{usr.Username}**",
 | 
			
		||||
            footer: $"ID: {usr.Id}");
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Confirm("🎟 " + GetText(strs.raffled_user),
 | 
			
		||||
                  $"**{usr.Username}**",
 | 
			
		||||
                  footer: $"ID: {usr.Id}")
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -269,9 +273,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)];
 | 
			
		||||
        await SendConfirmAsync("🎟 " + GetText(strs.raffled_user),
 | 
			
		||||
            $"**{usr.Username}**",
 | 
			
		||||
            footer: $"ID: {usr.Id}");
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Confirm("🎟 " + GetText(strs.raffled_user),
 | 
			
		||||
                  $"**{usr.Username}**",
 | 
			
		||||
                  footer: $"ID: {usr.Id}")
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -304,10 +310,10 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            trs = await uow.Set<CurrencyTransaction>().GetPageFor(userId, page);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
            .WithTitle(GetText(strs.transactions(((SocketGuild)ctx.Guild)?.GetUser(userId)?.ToString()
 | 
			
		||||
                                                 ?? $"{userId}")))
 | 
			
		||||
            .WithOkColor();
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
                       .WithTitle(GetText(strs.transactions(((SocketGuild)ctx.Guild)?.GetUser(userId)?.ToString()
 | 
			
		||||
                                                            ?? $"{userId}")))
 | 
			
		||||
                       .WithOkColor();
 | 
			
		||||
 | 
			
		||||
        var sb = new StringBuilder();
 | 
			
		||||
        foreach (var tr in trs)
 | 
			
		||||
@@ -331,7 +337,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        embed.WithDescription(sb.ToString());
 | 
			
		||||
        embed.WithFooter(GetText(strs.page(page + 1)));
 | 
			
		||||
        await EmbedAsync(embed);
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static string GetFormattedCurtrDate(CurrencyTransaction ct)
 | 
			
		||||
@@ -343,17 +349,18 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        int intId = id;
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
 | 
			
		||||
        var tr = await uow.Set<CurrencyTransaction>().ToLinqToDBTable()
 | 
			
		||||
            .Where(x => x.Id == intId && x.UserId == ctx.User.Id)
 | 
			
		||||
            .FirstOrDefaultAsync();
 | 
			
		||||
        var tr = await uow.Set<CurrencyTransaction>()
 | 
			
		||||
                          .ToLinqToDBTable()
 | 
			
		||||
                          .Where(x => x.Id == intId && x.UserId == ctx.User.Id)
 | 
			
		||||
                          .FirstOrDefaultAsync();
 | 
			
		||||
 | 
			
		||||
        if (tr is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_found);
 | 
			
		||||
            await Response().Error(strs.not_found).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var eb = _eb.Create(ctx).WithOkColor();
 | 
			
		||||
        var eb = new EmbedBuilder().WithOkColor();
 | 
			
		||||
 | 
			
		||||
        eb.WithAuthor(ctx.User);
 | 
			
		||||
        eb.WithTitle(GetText(strs.transaction));
 | 
			
		||||
@@ -374,7 +381,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        eb.WithFooter(GetFormattedCurtrDate(tr));
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(eb);
 | 
			
		||||
        await Response().Embed(eb).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private string GetHumanReadableTransaction(string type, string subType, ulong? maybeUserId)
 | 
			
		||||
@@ -398,7 +405,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
    public async Task Cash(ulong userId)
 | 
			
		||||
    {
 | 
			
		||||
        var cur = await GetBalanceStringAsync(userId);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.has(Format.Code(userId.ToString()), cur));
 | 
			
		||||
        await Response().Confirm(strs.has(Format.Code(userId.ToString()), cur)).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task BankAction(SocketMessageComponent smc, object _)
 | 
			
		||||
@@ -406,9 +413,9 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        var balance = await _bank.GetBalanceAsync(ctx.User.Id);
 | 
			
		||||
 | 
			
		||||
        await N(balance)
 | 
			
		||||
            .Pipe(strs.bank_balance)
 | 
			
		||||
            .Pipe(GetText)
 | 
			
		||||
            .Pipe(text => smc.RespondConfirmAsync(_eb, text, ephemeral: true));
 | 
			
		||||
              .Pipe(strs.bank_balance)
 | 
			
		||||
              .Pipe(GetText)
 | 
			
		||||
              .Pipe(text => smc.RespondConfirmAsync(_eb, text, ephemeral: true));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private NadekoInteraction CreateCashInteraction()
 | 
			
		||||
@@ -429,18 +436,24 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            ? CreateCashInteraction()
 | 
			
		||||
            : null;
 | 
			
		||||
 | 
			
		||||
        await ConfirmLocalizedAsync(
 | 
			
		||||
            user.ToString()
 | 
			
		||||
                .Pipe(Format.Bold)
 | 
			
		||||
                .With(cur)
 | 
			
		||||
                .Pipe(strs.has),
 | 
			
		||||
            inter);
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Confirm(
 | 
			
		||||
                  user.ToString()
 | 
			
		||||
                      .Pipe(Format.Bold)
 | 
			
		||||
                      .With(cur)
 | 
			
		||||
                      .Pipe(strs.has))
 | 
			
		||||
              .Interaction(inter)
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
    [RequireContext(ContextType.Guild)]
 | 
			
		||||
    [Priority(0)]
 | 
			
		||||
    public async Task Give([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, IGuildUser receiver, [Leftover] string msg)
 | 
			
		||||
    public async Task Give(
 | 
			
		||||
        [OverrideTypeReader(typeof(BalanceTypeReader))]
 | 
			
		||||
        long amount,
 | 
			
		||||
        IGuildUser receiver,
 | 
			
		||||
        [Leftover] string msg)
 | 
			
		||||
    {
 | 
			
		||||
        if (amount <= 0 || ctx.User.Id == receiver.Id || receiver.IsBot)
 | 
			
		||||
        {
 | 
			
		||||
@@ -449,11 +462,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        if (!await _cs.TransferAsync(_eb, ctx.User, receiver, amount, msg, N(amount)))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
            await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.gifted(N(amount), Format.Bold(receiver.ToString())));
 | 
			
		||||
        await Response().Confirm(strs.gifted(N(amount), Format.Bold(receiver.ToString()))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -490,12 +503,12 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        if (usr is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.user_not_found);
 | 
			
		||||
            await Response().Error(strs.user_not_found).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await _cs.AddAsync(usr.Id, amount, new("award", ctx.User.ToString()!, msg, ctx.User.Id));
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.awarded(N(amount), $"<@{usrId}>"));
 | 
			
		||||
        await Response().Confirm(strs.awarded(N(amount), $"<@{usrId}>")).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -510,9 +523,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            amount,
 | 
			
		||||
            new("award", ctx.User.ToString()!, role.Name, ctx.User.Id));
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.mass_award(N(amount),
 | 
			
		||||
            Format.Bold(users.Count.ToString()),
 | 
			
		||||
            Format.Bold(role.Name)));
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Confirm(strs.mass_award(N(amount),
 | 
			
		||||
                  Format.Bold(users.Count.ToString()),
 | 
			
		||||
                  Format.Bold(role.Name)))
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -527,9 +542,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            amount,
 | 
			
		||||
            new("take", ctx.User.ToString()!, null, ctx.User.Id));
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.mass_take(N(amount),
 | 
			
		||||
            Format.Bold(users.Count.ToString()),
 | 
			
		||||
            Format.Bold(role.Name)));
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Confirm(strs.mass_take(N(amount),
 | 
			
		||||
                  Format.Bold(users.Count.ToString()),
 | 
			
		||||
                  Format.Bold(role.Name)))
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -547,11 +564,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        if (await _cs.RemoveAsync(user.Id, amount, extra))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.take(N(amount), Format.Bold(user.ToString())));
 | 
			
		||||
            await Response().Confirm(strs.take(N(amount), Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.take_fail(N(amount), Format.Bold(user.ToString()), CurrencySign));
 | 
			
		||||
            await Response().Error(strs.take_fail(N(amount), Format.Bold(user.ToString()), CurrencySign)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -568,11 +585,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        if (await _cs.RemoveAsync(usrId, amount, extra))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.take(N(amount), $"<@{usrId}>"));
 | 
			
		||||
            await Response().Confirm(strs.take(N(amount), $"<@{usrId}>")).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.take_fail(N(amount), Format.Code(usrId.ToString()), CurrencySign));
 | 
			
		||||
            await Response().Error(strs.take_fail(N(amount), Format.Code(usrId.ToString()), CurrencySign)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -607,7 +624,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create().WithOkColor().WithTitle(GetText(strs.roll_duel));
 | 
			
		||||
        var embed = new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.roll_duel));
 | 
			
		||||
 | 
			
		||||
        var description = string.Empty;
 | 
			
		||||
 | 
			
		||||
@@ -617,7 +634,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        {
 | 
			
		||||
            if (other.Amount != amount)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.roll_duel_already_challenged);
 | 
			
		||||
                await Response().Error(strs.roll_duel_already_challenged).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
@@ -632,9 +649,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            game.OnGameTick += GameOnGameTick;
 | 
			
		||||
            game.OnEnded += GameOnEnded;
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.roll_duel_challenge(Format.Bold(ctx.User.ToString()),
 | 
			
		||||
                Format.Bold(u.ToString()),
 | 
			
		||||
                Format.Bold(N(amount))));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.roll_duel_challenge(Format.Bold(ctx.User.ToString()),
 | 
			
		||||
                      Format.Bold(u.ToString()),
 | 
			
		||||
                      Format.Bold(N(amount))))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        async Task GameOnGameTick(RollDuelGame arg)
 | 
			
		||||
@@ -648,7 +667,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
            if (rdMsg is null)
 | 
			
		||||
            {
 | 
			
		||||
                rdMsg = await ctx.Channel.EmbedAsync(embed);
 | 
			
		||||
                rdMsg = await Response().Embed(embed).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
@@ -671,11 +690,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
                }
 | 
			
		||||
                else if (reason == RollDuelGame.Reason.Timeout)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.roll_duel_timeout);
 | 
			
		||||
                    await Response().Error(strs.roll_duel_timeout).SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
                else if (reason == RollDuelGame.Reason.NoFunds)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.roll_duel_no_funds);
 | 
			
		||||
                    await Response().Error(strs.roll_duel_no_funds).SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
@@ -696,7 +715,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        var maybeResult = await _gs.BetRollAsync(ctx.User.Id, amount);
 | 
			
		||||
        if (!maybeResult.TryPickT0(out var result, out _))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
            await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -712,13 +731,13 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            str = GetText(strs.better_luck);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var eb = _eb.Create(ctx)
 | 
			
		||||
            .WithAuthor(ctx.User)
 | 
			
		||||
            .WithDescription(Format.Bold(str))
 | 
			
		||||
            .AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture))
 | 
			
		||||
            .WithOkColor();
 | 
			
		||||
        var eb = new EmbedBuilder()
 | 
			
		||||
                    .WithAuthor(ctx.User)
 | 
			
		||||
                    .WithDescription(Format.Bold(str))
 | 
			
		||||
                    .AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture))
 | 
			
		||||
                    .WithOkColor();
 | 
			
		||||
 | 
			
		||||
        await ctx.Channel.EmbedAsync(eb);
 | 
			
		||||
        await Response().Embed(eb).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -768,7 +787,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        await ctx.SendPaginatedConfirmAsync(page,
 | 
			
		||||
            async curPage =>
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create().WithOkColor().WithTitle(CurrencySign + " " + GetText(strs.leaderboard));
 | 
			
		||||
                var embed = new EmbedBuilder().WithOkColor().WithTitle(CurrencySign + " " + GetText(strs.leaderboard));
 | 
			
		||||
 | 
			
		||||
                List<DiscordUser> toSend;
 | 
			
		||||
                if (!opts.Clean)
 | 
			
		||||
@@ -838,11 +857,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
 | 
			
		||||
        if (!res.TryPickT0(out var result, out _))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
            await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create();
 | 
			
		||||
        var embed = new EmbedBuilder();
 | 
			
		||||
 | 
			
		||||
        string msg;
 | 
			
		||||
        if (result.Result == RpsResultType.Draw)
 | 
			
		||||
@@ -869,7 +888,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            .WithOkColor()
 | 
			
		||||
            .WithDescription(msg);
 | 
			
		||||
 | 
			
		||||
        await ctx.Channel.EmbedAsync(embed);
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static readonly ImmutableArray<string> _emojis =
 | 
			
		||||
@@ -884,7 +903,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        var res = await _gs.LulaAsync(ctx.User.Id, amount);
 | 
			
		||||
        if (!res.TryPickT0(out var result, out _))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
            await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -903,15 +922,15 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            sb.AppendLine();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var eb = _eb.Create(ctx)
 | 
			
		||||
            .WithOkColor()
 | 
			
		||||
            .WithDescription(sb.ToString())
 | 
			
		||||
            .AddField(GetText(strs.multiplier), $"{result.Multiplier:0.##}x", true)
 | 
			
		||||
            .AddField(GetText(strs.won), $"{(long)result.Won}", true)
 | 
			
		||||
            .WithAuthor(ctx.User);
 | 
			
		||||
        var eb = new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithDescription(sb.ToString())
 | 
			
		||||
                    .AddField(GetText(strs.multiplier), $"{result.Multiplier:0.##}x", true)
 | 
			
		||||
                    .AddField(GetText(strs.won), $"{(long)result.Won}", true)
 | 
			
		||||
                    .WithAuthor(ctx.User);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        await ctx.Channel.EmbedAsync(eb);
 | 
			
		||||
        await Response().Embed(eb).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -935,8 +954,8 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        var values = Enum.GetValues<GambleTestTarget>()
 | 
			
		||||
                         .Select(x => $"`{x}`")
 | 
			
		||||
                         .Join(", ");
 | 
			
		||||
        
 | 
			
		||||
        await SendConfirmAsync(GetText(strs.available_tests), values);
 | 
			
		||||
 | 
			
		||||
        await Response().Confirm(GetText(strs.available_tests), values).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -1006,8 +1025,10 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        sb.AppendLine($"Longest win streak: `{maxW}`");
 | 
			
		||||
        sb.AppendLine($"Longest lose streak: `{maxL}`");
 | 
			
		||||
 | 
			
		||||
        await SendConfirmAsync(GetText(strs.test_results_for(target)),
 | 
			
		||||
            sb.ToString(),
 | 
			
		||||
            footer: $"Total Bet: {tests} | Payout: {payout:F0} | {payout * 1.0M / tests * 100}%");
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Confirm(GetText(strs.test_results_for(target)),
 | 
			
		||||
                  sb.ToString(),
 | 
			
		||||
                  footer: $"Total Bet: {tests} | Payout: {payout:F0} | {payout * 1.0M / tests * 100}%")
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -26,13 +26,13 @@ public abstract class GamblingModule<TService> : NadekoModule<TService>
 | 
			
		||||
            return false;
 | 
			
		||||
        if (amount < Config.MinBet)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.min_bet_limit(Format.Bold(Config.MinBet.ToString()) + CurrencySign));
 | 
			
		||||
            await Response().Error(strs.min_bet_limit(Format.Bold(Config.MinBet.ToString()) + CurrencySign)).SendAsync();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (Config.MaxBet > 0 && amount > Config.MaxBet)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.max_bet_limit(Format.Bold(Config.MaxBet.ToString()) + CurrencySign));
 | 
			
		||||
            await Response().Error(strs.max_bet_limit(Format.Bold(Config.MaxBet.ToString()) + CurrencySign)).SendAsync();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            if (picked > 0)
 | 
			
		||||
            {
 | 
			
		||||
                var msg = await ReplyConfirmLocalizedAsync(strs.picked(N(picked)));
 | 
			
		||||
                var msg = await Response().Confirm(strs.picked(N(picked))).SendAsync();
 | 
			
		||||
                msg.DeleteAfter(10);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -66,7 +66,7 @@ public partial class Gambling
 | 
			
		||||
                pass);
 | 
			
		||||
 | 
			
		||||
            if (!success)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -79,9 +79,9 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            var enabled = _service.ToggleCurrencyGeneration(ctx.Guild.Id, ctx.Channel.Id);
 | 
			
		||||
            if (enabled)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.curgen_enabled);
 | 
			
		||||
                await Response().Confirm(strs.curgen_enabled).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.curgen_disabled);
 | 
			
		||||
                await Response().Confirm(strs.curgen_disabled).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -100,9 +100,9 @@ public partial class Gambling
 | 
			
		||||
                    var items = enabledIn.Skip(page * 9).Take(9).ToList();
 | 
			
		||||
 | 
			
		||||
                    if (!items.Any())
 | 
			
		||||
                        return _eb.Create().WithErrorColor().WithDescription("-");
 | 
			
		||||
                        return new EmbedBuilder().WithErrorColor().WithDescription("-");
 | 
			
		||||
 | 
			
		||||
                    return items.Aggregate(_eb.Create().WithOkColor(),
 | 
			
		||||
                    return items.Aggregate(new EmbedBuilder().WithOkColor(),
 | 
			
		||||
                        (eb, i) => eb.AddField(i.GuildId.ToString(), i.ChannelId));
 | 
			
		||||
                },
 | 
			
		||||
                enabledIn.Count(),
 | 
			
		||||
 
 | 
			
		||||
@@ -32,25 +32,29 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            async Task OnEnded(IUser arg, long won)
 | 
			
		||||
            {
 | 
			
		||||
                await SendConfirmAsync(GetText(strs.rafflecur_ended(CurrencyName,
 | 
			
		||||
                    Format.Bold(arg.ToString()),
 | 
			
		||||
                    won + CurrencySign)));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(GetText(strs.rafflecur_ended(CurrencyName,
 | 
			
		||||
                          Format.Bold(arg.ToString()),
 | 
			
		||||
                          won + CurrencySign)))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var res = await _service.JoinOrCreateGame(ctx.Channel.Id, ctx.User, amount, mixed, OnEnded);
 | 
			
		||||
 | 
			
		||||
            if (res.Item1 is not null)
 | 
			
		||||
            {
 | 
			
		||||
                await SendConfirmAsync(GetText(strs.rafflecur(res.Item1.GameType.ToString())),
 | 
			
		||||
                    string.Join("\n", res.Item1.Users.Select(x => $"{x.DiscordUser} ({N(x.Amount)})")),
 | 
			
		||||
                    footer: GetText(strs.rafflecur_joined(ctx.User.ToString())));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(GetText(strs.rafflecur(res.Item1.GameType.ToString())),
 | 
			
		||||
                          string.Join("\n", res.Item1.Users.Select(x => $"{x.DiscordUser} ({N(x.Amount)})")),
 | 
			
		||||
                          footer: GetText(strs.rafflecur_joined(ctx.User.ToString())))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (res.Item2 == CurrencyRaffleService.JoinErrorType.AlreadyJoinedOrInvalidAmount)
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.rafflecur_already_joined);
 | 
			
		||||
                    await Response().Error(strs.rafflecur_already_joined).SendAsync();
 | 
			
		||||
                else if (res.Item2 == CurrencyRaffleService.JoinErrorType.NotEnoughCurrency)
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                    await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -54,8 +54,8 @@ public partial class Gambling
 | 
			
		||||
                    var theseEntries = entries.Skip(curPage * 9).Take(9).ToArray();
 | 
			
		||||
 | 
			
		||||
                    if (!theseEntries.Any())
 | 
			
		||||
                        return _eb.Create().WithErrorColor().WithDescription(GetText(strs.shop_none));
 | 
			
		||||
                    var embed = _eb.Create().WithOkColor().WithTitle(GetText(strs.shop));
 | 
			
		||||
                        return new EmbedBuilder().WithErrorColor().WithDescription(GetText(strs.shop_none));
 | 
			
		||||
                    var embed = new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.shop));
 | 
			
		||||
 | 
			
		||||
                    for (var i = 0; i < theseEntries.Length; i++)
 | 
			
		||||
                    {
 | 
			
		||||
@@ -100,7 +100,7 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            if (entry is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.shop_item_not_found);
 | 
			
		||||
                await Response().Error(strs.shop_item_not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -109,14 +109,14 @@ public partial class Gambling
 | 
			
		||||
                var role = ctx.Guild.GetRole(reqRoleId);
 | 
			
		||||
                if (role is null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.shop_item_req_role_not_found);
 | 
			
		||||
                    await Response().Error(strs.shop_item_req_role_not_found).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var guser = (IGuildUser)ctx.User;
 | 
			
		||||
                if (!guser.RoleIds.Contains(reqRoleId))
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.shop_item_req_role_unfulfilled(Format.Bold(role.ToString())));
 | 
			
		||||
                    await Response().Error(strs.shop_item_req_role_unfulfilled(Format.Bold(role.ToString()))).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -128,13 +128,13 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
                if (role is null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.shop_role_not_found);
 | 
			
		||||
                    await Response().Error(strs.shop_role_not_found).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (guser.RoleIds.Any(id => id == role.Id))
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.shop_role_already_bought);
 | 
			
		||||
                    await Response().Error(strs.shop_role_already_bought).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -148,18 +148,18 @@ public partial class Gambling
 | 
			
		||||
                    {
 | 
			
		||||
                        Log.Warning(ex, "Error adding shop role");
 | 
			
		||||
                        await _cs.AddAsync(ctx.User.Id, entry.Price, new("shop", "error-refund"));
 | 
			
		||||
                        await ReplyErrorLocalizedAsync(strs.shop_role_purchase_error);
 | 
			
		||||
                        await Response().Error(strs.shop_role_purchase_error).SendAsync();
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var profit = GetProfitAmount(entry.Price);
 | 
			
		||||
                    await _cs.AddAsync(entry.AuthorId, profit, new("shop", "sell", $"Shop sell item - {entry.Type}"));
 | 
			
		||||
                    await _cs.AddAsync(ctx.Client.CurrentUser.Id, entry.Price - profit, new("shop", "cut"));
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.shop_role_purchase(Format.Bold(role.Name)));
 | 
			
		||||
                    await Response().Confirm(strs.shop_role_purchase(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -167,7 +167,7 @@ public partial class Gambling
 | 
			
		||||
            {
 | 
			
		||||
                if (entry.Items.Count == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.out_of_stock);
 | 
			
		||||
                    await Response().Error(strs.out_of_stock).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -183,7 +183,7 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await ctx.User.EmbedAsync(_eb.Create()
 | 
			
		||||
                        await ctx.User.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                            .WithOkColor()
 | 
			
		||||
                            .WithTitle(GetText(strs.shop_purchase(ctx.Guild.Name)))
 | 
			
		||||
                            .AddField(GetText(strs.item), item.Text)
 | 
			
		||||
@@ -211,14 +211,14 @@ public partial class Gambling
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        await ReplyErrorLocalizedAsync(strs.shop_buy_error);
 | 
			
		||||
                        await Response().Error(strs.shop_buy_error).SendAsync();
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.shop_item_purchase);
 | 
			
		||||
                    await Response().Confirm(strs.shop_item_purchase).SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                    await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else if (entry.Type == ShopEntryType.Command)
 | 
			
		||||
            {
 | 
			
		||||
@@ -229,24 +229,24 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
                if (guild is null || channel is null || msg is null || user is null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.shop_command_invalid_context);
 | 
			
		||||
                    await Response().Error(strs.shop_command_invalid_context).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!await _cs.RemoveAsync(ctx.User.Id, entry.Price, new("shop", "buy", entry.Type.ToString())))
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                    await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    var cmd = entry.Command.Replace("%you%", ctx.User.Id.ToString());
 | 
			
		||||
                    var eb = _eb.Create()
 | 
			
		||||
                    var eb = new EmbedBuilder()
 | 
			
		||||
                        .WithPendingColor()
 | 
			
		||||
                        .WithTitle("Executing shop command")
 | 
			
		||||
                        .WithDescription(cmd);
 | 
			
		||||
 | 
			
		||||
                    var msgTask = EmbedAsync(eb);
 | 
			
		||||
                    var msgTask = Response().Embed(eb).SendAsync();
 | 
			
		||||
 | 
			
		||||
                    await _cs.AddAsync(entry.AuthorId,
 | 
			
		||||
                        GetProfitAmount(entry.Price),
 | 
			
		||||
@@ -290,7 +290,7 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            var entry = await _service.AddShopCommandAsync(ctx.Guild.Id, ctx.User.Id, price, command);
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(EntryToEmbed(entry).WithTitle(GetText(strs.shop_item_add)));
 | 
			
		||||
            await Response().Embed(EntryToEmbed(entry).WithTitle(GetText(strs.shop_item_add))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -324,7 +324,7 @@ public partial class Gambling
 | 
			
		||||
                uow.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(EntryToEmbed(entry).WithTitle(GetText(strs.shop_item_add)));
 | 
			
		||||
            await Response().Embed(EntryToEmbed(entry).WithTitle(GetText(strs.shop_item_add))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -356,7 +356,7 @@ public partial class Gambling
 | 
			
		||||
                uow.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(EntryToEmbed(entry).WithTitle(GetText(strs.shop_item_add)));
 | 
			
		||||
            await Response().Embed(EntryToEmbed(entry).WithTitle(GetText(strs.shop_item_add))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -392,13 +392,13 @@ public partial class Gambling
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (entry is null)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.shop_item_not_found);
 | 
			
		||||
                await Response().Error(strs.shop_item_not_found).SendAsync();
 | 
			
		||||
            else if (!rightType)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.shop_item_wrong_type);
 | 
			
		||||
                await Response().Error(strs.shop_item_wrong_type).SendAsync();
 | 
			
		||||
            else if (added == false)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.shop_list_item_not_unique);
 | 
			
		||||
                await Response().Error(strs.shop_list_item_not_unique).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.shop_list_item_added);
 | 
			
		||||
                await Response().Confirm(strs.shop_list_item_added).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -426,9 +426,9 @@ public partial class Gambling
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (removed is null)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.shop_item_not_found);
 | 
			
		||||
                await Response().Error(strs.shop_item_not_found).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ctx.Channel.EmbedAsync(EntryToEmbed(removed).WithTitle(GetText(strs.shop_item_rm)));
 | 
			
		||||
                await Response().Embed(EntryToEmbed(removed).WithTitle(GetText(strs.shop_item_rm))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -514,19 +514,19 @@ public partial class Gambling
 | 
			
		||||
            var succ = await _service.SetItemRoleRequirementAsync(ctx.Guild.Id, itemIndex, role?.Id);
 | 
			
		||||
            if (!succ)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.shop_item_not_found);
 | 
			
		||||
                await Response().Error(strs.shop_item_not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (role is null)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.shop_item_role_no_req(itemIndex));
 | 
			
		||||
                await Response().Confirm(strs.shop_item_role_no_req(itemIndex)).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.shop_item_role_req(itemIndex + 1, role));
 | 
			
		||||
                await Response().Confirm(strs.shop_item_role_req(itemIndex + 1, role)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEmbedBuilder EntryToEmbed(ShopEntry entry)
 | 
			
		||||
        public EmbedBuilder EntryToEmbed(ShopEntry entry)
 | 
			
		||||
        {
 | 
			
		||||
            var embed = _eb.Create().WithOkColor();
 | 
			
		||||
            var embed = new EmbedBuilder().WithOkColor();
 | 
			
		||||
 | 
			
		||||
            if (entry.Type == ShopEntryType.Role)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            if (await InternalSlotAsync(amount) is not SlotResult result)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -69,7 +69,7 @@ public partial class Gambling
 | 
			
		||||
            await using var imgStream = await image.ToStreamAsync();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                .WithAuthor(ctx.User)
 | 
			
		||||
                .WithDescription(Format.Bold(text))
 | 
			
		||||
                .WithImageUrl($"attachment://result.png")
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ public partial class Gambling
 | 
			
		||||
        public async Task WaifuReset()
 | 
			
		||||
        {
 | 
			
		||||
            var price = _service.GetResetPrice(ctx.User);
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithTitle(GetText(strs.waifu_reset_confirm))
 | 
			
		||||
                           .WithDescription(GetText(strs.waifu_reset_price(Format.Bold(N(price)))));
 | 
			
		||||
 | 
			
		||||
@@ -29,11 +29,11 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            if (await _service.TryReset(ctx.User))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.waifu_reset);
 | 
			
		||||
                await Response().Confirm(strs.waifu_reset).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.waifu_reset_fail);
 | 
			
		||||
            await Response().Error(strs.waifu_reset_fail).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -42,13 +42,13 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            if (amount < Config.Waifu.MinPrice)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.waifu_isnt_cheap(Config.Waifu.MinPrice + CurrencySign));
 | 
			
		||||
                await Response().Error(strs.waifu_isnt_cheap(Config.Waifu.MinPrice + CurrencySign)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (target.Id == ctx.User.Id)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.waifu_not_yourself);
 | 
			
		||||
                await Response().Error(strs.waifu_not_yourself).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -56,14 +56,16 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            if (result == WaifuClaimResult.InsufficientAmount)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(
 | 
			
		||||
                    strs.waifu_not_enough(N((long)Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f)))));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Error(
 | 
			
		||||
                          strs.waifu_not_enough(N((long)Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f)))))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (result == WaifuClaimResult.NotEnoughFunds)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -72,7 +74,7 @@ public partial class Gambling
 | 
			
		||||
                msg += "\n" + GetText(strs.waifu_fulfilled(target, N(w.Price)));
 | 
			
		||||
            else
 | 
			
		||||
                msg = " " + msg;
 | 
			
		||||
            await SendConfirmAsync(ctx.User.Mention + msg);
 | 
			
		||||
            await Response().Confirm(ctx.User.Mention + msg).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -82,13 +84,15 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            if (!await _service.WaifuTransfer(ctx.User, waifuId, newOwner))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.waifu_transfer_fail);
 | 
			
		||||
                await Response().Error(strs.waifu_transfer_fail).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.waifu_transfer_success(Format.Bold(waifuId.ToString()),
 | 
			
		||||
                Format.Bold(ctx.User.ToString()),
 | 
			
		||||
                Format.Bold(newOwner.ToString())));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.waifu_transfer_success(Format.Bold(waifuId.ToString()),
 | 
			
		||||
                      Format.Bold(ctx.User.ToString()),
 | 
			
		||||
                      Format.Bold(newOwner.ToString())))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -98,13 +102,15 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            if (!await _service.WaifuTransfer(ctx.User, waifu.Id, newOwner))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.waifu_transfer_fail);
 | 
			
		||||
                await Response().Error(strs.waifu_transfer_fail).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.waifu_transfer_success(Format.Bold(waifu.ToString()),
 | 
			
		||||
                Format.Bold(ctx.User.ToString()),
 | 
			
		||||
                Format.Bold(newOwner.ToString())));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.waifu_transfer_success(Format.Bold(waifu.ToString()),
 | 
			
		||||
                      Format.Bold(ctx.User.ToString()),
 | 
			
		||||
                      Format.Bold(newOwner.ToString())))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -114,7 +120,7 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            var waifuUserId = _service.GetWaifuUserId(ctx.User.Id, target);
 | 
			
		||||
            if (waifuUserId == default)
 | 
			
		||||
                return ReplyErrorLocalizedAsync(strs.waifu_not_yours);
 | 
			
		||||
                return Response().Error(strs.waifu_not_yours).SendAsync();
 | 
			
		||||
 | 
			
		||||
            return Divorce(waifuUserId);
 | 
			
		||||
        }
 | 
			
		||||
@@ -137,18 +143,22 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            if (result == DivorceResult.SucessWithPenalty)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.waifu_divorced_like(Format.Bold(w.Waifu.ToString()),
 | 
			
		||||
                    N(amount)));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.waifu_divorced_like(Format.Bold(w.Waifu.ToString()),
 | 
			
		||||
                          N(amount)))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else if (result == DivorceResult.Success)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.waifu_divorced_notlike(N(amount)));
 | 
			
		||||
                await Response().Confirm(strs.waifu_divorced_notlike(N(amount))).SendAsync();
 | 
			
		||||
            else if (result == DivorceResult.NotYourWife)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.waifu_not_yours);
 | 
			
		||||
                await Response().Error(strs.waifu_not_yours).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.waifu_recent_divorce(
 | 
			
		||||
                    Format.Bold(((int)remaining?.TotalHours).ToString()),
 | 
			
		||||
                    Format.Bold(remaining?.Minutes.ToString())));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Error(strs.waifu_recent_divorce(
 | 
			
		||||
                          Format.Bold(((int)remaining?.TotalHours).ToString()),
 | 
			
		||||
                          Format.Bold(remaining?.Minutes.ToString())))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -158,7 +168,7 @@ public partial class Gambling
 | 
			
		||||
        {
 | 
			
		||||
            if (user?.Id == ctx.User.Id)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.waifu_egomaniac);
 | 
			
		||||
                await Response().Error(strs.waifu_egomaniac).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -167,24 +177,28 @@ public partial class Gambling
 | 
			
		||||
            {
 | 
			
		||||
                if (remaining is not null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.waifu_affinity_cooldown(
 | 
			
		||||
                        Format.Bold(((int)remaining?.TotalHours).ToString()),
 | 
			
		||||
                        Format.Bold(remaining?.Minutes.ToString())));
 | 
			
		||||
                    await Response()
 | 
			
		||||
                          .Error(strs.waifu_affinity_cooldown(
 | 
			
		||||
                              Format.Bold(((int)remaining?.TotalHours).ToString()),
 | 
			
		||||
                              Format.Bold(remaining?.Minutes.ToString())))
 | 
			
		||||
                          .SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.waifu_affinity_already);
 | 
			
		||||
                    await Response().Error(strs.waifu_affinity_already).SendAsync();
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (user is null)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.waifu_affinity_reset);
 | 
			
		||||
                await Response().Confirm(strs.waifu_affinity_reset).SendAsync();
 | 
			
		||||
            else if (oldAff is null)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.waifu_affinity_set(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.waifu_affinity_set(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.waifu_affinity_changed(Format.Bold(oldAff.ToString()),
 | 
			
		||||
                    Format.Bold(user.ToString())));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.waifu_affinity_changed(Format.Bold(oldAff.ToString()),
 | 
			
		||||
                          Format.Bold(user.ToString())))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -204,11 +218,11 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            if (waifus.Count == 0)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.waifus_none);
 | 
			
		||||
                await Response().Confirm(strs.waifus_none).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create().WithTitle(GetText(strs.waifus_top_waifus)).WithOkColor();
 | 
			
		||||
            var embed = new EmbedBuilder().WithTitle(GetText(strs.waifus_top_waifus)).WithOkColor();
 | 
			
		||||
 | 
			
		||||
            var i = 0;
 | 
			
		||||
            foreach (var w in waifus)
 | 
			
		||||
@@ -217,7 +231,7 @@ public partial class Gambling
 | 
			
		||||
                embed.AddField("#" + ((page * 9) + j + 1) + " - " + N(w.Price), GetLbString(w));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetLbString(WaifuLbResult w)
 | 
			
		||||
@@ -284,15 +298,15 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            var fansList = await _service.GetFansNames(wi.WaifuId);
 | 
			
		||||
            var fansStr = fansList
 | 
			
		||||
                .Shuffle()
 | 
			
		||||
                .Take(30)
 | 
			
		||||
                .Select((x) => claimsNames.Contains(x) ? $"{x} 💞" : x)
 | 
			
		||||
                .Join('\n');
 | 
			
		||||
                          .Shuffle()
 | 
			
		||||
                          .Take(30)
 | 
			
		||||
                          .Select((x) => claimsNames.Contains(x) ? $"{x} 💞" : x)
 | 
			
		||||
                          .Join('\n');
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(fansStr))
 | 
			
		||||
                fansStr = "-";
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithTitle(GetText(strs.waifu)
 | 
			
		||||
                                      + " "
 | 
			
		||||
@@ -312,7 +326,7 @@ public partial class Gambling
 | 
			
		||||
                               true)
 | 
			
		||||
                           .AddField(GetText(strs.gifts), itemsStr, true);
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -327,7 +341,7 @@ public partial class Gambling
 | 
			
		||||
            await ctx.SendPaginatedConfirmAsync(page,
 | 
			
		||||
                cur =>
 | 
			
		||||
                {
 | 
			
		||||
                    var embed = _eb.Create().WithTitle(GetText(strs.waifu_gift_shop)).WithOkColor();
 | 
			
		||||
                    var embed = new EmbedBuilder().WithTitle(GetText(strs.waifu_gift_shop)).WithOkColor();
 | 
			
		||||
 | 
			
		||||
                    waifuItems.OrderBy(x => x.Negative)
 | 
			
		||||
                              .ThenBy(x => x.Price)
 | 
			
		||||
@@ -357,7 +371,7 @@ public partial class Gambling
 | 
			
		||||
            var item = allItems.FirstOrDefault(x => x.Name.ToLowerInvariant() == itemName.ToLowerInvariant());
 | 
			
		||||
            if (item is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.waifu_gift_not_exist);
 | 
			
		||||
                await Response().Error(strs.waifu_gift_not_exist).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -365,11 +379,13 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
            if (sucess)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.waifu_gift(Format.Bold(item + " " + item.ItemEmoji),
 | 
			
		||||
                    Format.Bold(waifu.ToString())));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.waifu_gift(Format.Bold(item + " " + item.ItemEmoji),
 | 
			
		||||
                          Format.Bold(waifu.ToString())))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -43,7 +43,7 @@ public partial class Games
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.acro_running);
 | 
			
		||||
                await Response().Error(strs.acro_running).SendAsync();
 | 
			
		||||
 | 
			
		||||
            Task ClientMessageReceived(SocketMessage msg)
 | 
			
		||||
            {
 | 
			
		||||
@@ -67,18 +67,18 @@ public partial class Games
 | 
			
		||||
 | 
			
		||||
        private Task Game_OnStarted(AcrophobiaGame game)
 | 
			
		||||
        {
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithTitle(GetText(strs.acrophobia))
 | 
			
		||||
                           .WithDescription(
 | 
			
		||||
                               GetText(strs.acro_started(Format.Bold(string.Join(".", game.StartingLetters)))))
 | 
			
		||||
                           .WithFooter(GetText(strs.acro_started_footer(game.Opts.SubmissionTime)));
 | 
			
		||||
 | 
			
		||||
            return EmbedAsync(embed);
 | 
			
		||||
            return Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Game_OnUserVoted(string user)
 | 
			
		||||
            => SendConfirmAsync(GetText(strs.acrophobia), GetText(strs.acro_vote_cast(Format.Bold(user))));
 | 
			
		||||
            => Response().Confirm(GetText(strs.acrophobia), GetText(strs.acro_vote_cast(Format.Bold(user)))).SendAsync();
 | 
			
		||||
 | 
			
		||||
        private async Task Game_OnVotingStarted(
 | 
			
		||||
            AcrophobiaGame game,
 | 
			
		||||
@@ -86,24 +86,24 @@ public partial class Games
 | 
			
		||||
        {
 | 
			
		||||
            if (submissions.Length == 0)
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync(GetText(strs.acrophobia), GetText(strs.acro_ended_no_sub));
 | 
			
		||||
                await Response().Error(GetText(strs.acrophobia), GetText(strs.acro_ended_no_sub)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (submissions.Length == 1)
 | 
			
		||||
            {
 | 
			
		||||
                await EmbedAsync(_eb.Create()
 | 
			
		||||
                await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                                .WithOkColor()
 | 
			
		||||
                                                .WithDescription(GetText(
 | 
			
		||||
                                                    strs.acro_winner_only(
 | 
			
		||||
                                                        Format.Bold(submissions.First().Key.UserName))))
 | 
			
		||||
                                                .WithFooter(submissions.First().Key.Input));
 | 
			
		||||
                                                .WithFooter(submissions.First().Key.Input)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var i = 0;
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithTitle(GetText(strs.acrophobia) + " - " + GetText(strs.submissions_closed))
 | 
			
		||||
                           .WithDescription(GetText(strs.acro_nym_was(
 | 
			
		||||
@@ -114,27 +114,27 @@ public partial class Games
 | 
			
		||||
--")))
 | 
			
		||||
                           .WithFooter(GetText(strs.acro_vote));
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task Game_OnEnded(AcrophobiaGame game, ImmutableArray<KeyValuePair<AcrophobiaUser, int>> votes)
 | 
			
		||||
        {
 | 
			
		||||
            if (!votes.Any() || votes.All(x => x.Value == 0))
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync(GetText(strs.acrophobia), GetText(strs.acro_no_votes_cast));
 | 
			
		||||
                await Response().Error(GetText(strs.acrophobia), GetText(strs.acro_no_votes_cast)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var table = votes.OrderByDescending(v => v.Value);
 | 
			
		||||
            var winner = table.First();
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithTitle(GetText(strs.acrophobia))
 | 
			
		||||
                           .WithDescription(GetText(strs.acro_winner(Format.Bold(winner.Key.UserName),
 | 
			
		||||
                               Format.Bold(winner.Value.ToString()))))
 | 
			
		||||
                           .WithFooter(winner.Key.Input);
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -26,6 +26,7 @@ public class ChatterBotService : IExecOnMessage
 | 
			
		||||
    private readonly IHttpClientFactory _httpFactory;
 | 
			
		||||
    private readonly IPatronageService _ps;
 | 
			
		||||
    private readonly GamesConfigService _gcs;
 | 
			
		||||
    private readonly IMessageSenderService _sender;
 | 
			
		||||
 | 
			
		||||
    public ChatterBotService(
 | 
			
		||||
        DiscordSocketClient client,
 | 
			
		||||
@@ -37,7 +38,8 @@ public class ChatterBotService : IExecOnMessage
 | 
			
		||||
        IBotCredentials creds,
 | 
			
		||||
        IEmbedBuilderService eb,
 | 
			
		||||
        IPatronageService ps,
 | 
			
		||||
        GamesConfigService gcs)
 | 
			
		||||
        GamesConfigService gcs,
 | 
			
		||||
        IMessageSenderService sender)
 | 
			
		||||
    {
 | 
			
		||||
        _client = client;
 | 
			
		||||
        _perms = perms;
 | 
			
		||||
@@ -49,6 +51,7 @@ public class ChatterBotService : IExecOnMessage
 | 
			
		||||
        _ps = ps;
 | 
			
		||||
        _perms = perms;
 | 
			
		||||
        _gcs = gcs;
 | 
			
		||||
        _sender = sender;
 | 
			
		||||
 | 
			
		||||
        _flKey = new FeatureLimitKey()
 | 
			
		||||
        {
 | 
			
		||||
@@ -133,7 +136,7 @@ public class ChatterBotService : IExecOnMessage
 | 
			
		||||
                usrMsg.Author,
 | 
			
		||||
                "games",
 | 
			
		||||
                CleverBotResponseStr.CLEVERBOT_RESPONSE);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            if (!res.IsAllowed)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
@@ -163,20 +166,24 @@ public class ChatterBotService : IExecOnMessage
 | 
			
		||||
                {
 | 
			
		||||
                    if (ql.Quota == 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        await channel.SendErrorAsync(_eb,
 | 
			
		||||
                            null!,
 | 
			
		||||
                            text:
 | 
			
		||||
                            "In order to use the cleverbot feature, the owner of this server should be [Patron Tier X](https://patreon.com/join/nadekobot) on patreon.",
 | 
			
		||||
                            footer:
 | 
			
		||||
                            "You may disable the cleverbot feature, and this message via '.cleverbot' command");
 | 
			
		||||
                        await channel
 | 
			
		||||
                              .Response(_strings, _eb)
 | 
			
		||||
                              .Error(null,
 | 
			
		||||
                                  text:
 | 
			
		||||
                                  "In order to use the cleverbot feature, the owner of this server should be [Patron Tier X](https://patreon.com/join/nadekobot) on patreon.",
 | 
			
		||||
                                  footer:
 | 
			
		||||
                                  "You may disable the cleverbot feature, and this message via '.cleverbot' command")
 | 
			
		||||
                              .SendAsync();
 | 
			
		||||
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    await channel.SendErrorAsync(_eb,
 | 
			
		||||
                        null!,
 | 
			
		||||
                        $"You've reached your quota limit of **{ql.Quota}** responses {ql.QuotaPeriod.ToFullName()} for the cleverbot feature.",
 | 
			
		||||
                        footer: "You may wait for the quota reset or .");
 | 
			
		||||
                    await channel.Response(_strings, _eb)
 | 
			
		||||
                                 .Error(
 | 
			
		||||
                                     null!,
 | 
			
		||||
                                     $"You've reached your quota limit of **{ql.Quota}** responses {ql.QuotaPeriod.ToFullName()} for the cleverbot feature.",
 | 
			
		||||
                                     footer: "You may wait for the quota reset or .")
 | 
			
		||||
                                 .SendAsync();
 | 
			
		||||
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
@@ -184,19 +191,17 @@ public class ChatterBotService : IExecOnMessage
 | 
			
		||||
 | 
			
		||||
            _ = channel.TriggerTypingAsync();
 | 
			
		||||
            var response = await cbs.Think(message, usrMsg.Author.ToString());
 | 
			
		||||
            await channel.SendConfirmAsync(_eb,
 | 
			
		||||
                title: null,
 | 
			
		||||
                response.SanitizeMentions(true)
 | 
			
		||||
                // , footer: counter > 0 ? counter.ToString() : null
 | 
			
		||||
            );
 | 
			
		||||
            await _sender.Response(channel)
 | 
			
		||||
                         .Confirm(response)
 | 
			
		||||
                         .SendAsync();
 | 
			
		||||
 | 
			
		||||
            Log.Information("""
 | 
			
		||||
                CleverBot Executed
 | 
			
		||||
                Server: {GuildName} [{GuildId}]
 | 
			
		||||
                Channel: {ChannelName} [{ChannelId}]
 | 
			
		||||
                UserId: {Author} [{AuthorId}]
 | 
			
		||||
                Message: {Content}
 | 
			
		||||
                """,
 | 
			
		||||
                            CleverBot Executed
 | 
			
		||||
                            Server: {GuildName} [{GuildId}]
 | 
			
		||||
                            Channel: {ChannelName} [{ChannelId}]
 | 
			
		||||
                            UserId: {Author} [{AuthorId}]
 | 
			
		||||
                            Message: {Content}
 | 
			
		||||
                            """,
 | 
			
		||||
                guild.Name,
 | 
			
		||||
                guild.Id,
 | 
			
		||||
                usrMsg.Channel?.Name,
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ public partial class Games
 | 
			
		||||
                    await uow.SaveChangesAsync();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.cleverbot_disabled);
 | 
			
		||||
                await Response().Confirm(strs.cleverbot_disabled).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -42,7 +42,7 @@ public partial class Games
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.cleverbot_enabled);
 | 
			
		||||
            await Response().Confirm(strs.cleverbot_enabled).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -28,7 +28,7 @@ public partial class Games : NadekoModule<GamesService>
 | 
			
		||||
        if (listArr.Length < 2)
 | 
			
		||||
            return;
 | 
			
		||||
        var rng = new NadekoRandom();
 | 
			
		||||
        await SendConfirmAsync("🤔", listArr[rng.Next(0, listArr.Length)]);
 | 
			
		||||
        await Response().Confirm("🤔", listArr[rng.Next(0, listArr.Length)]).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -38,10 +38,10 @@ public partial class Games : NadekoModule<GamesService>
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var res = _service.GetEightballResponse(ctx.User.Id, question);
 | 
			
		||||
        await EmbedAsync(_eb.Create()
 | 
			
		||||
        await Response().Embed(new EmbedBuilder()
 | 
			
		||||
            .WithOkColor()
 | 
			
		||||
            .WithDescription(ctx.User.ToString())
 | 
			
		||||
            .AddField("❓ " + GetText(strs.question), question)
 | 
			
		||||
            .AddField("🎱 " + GetText(strs._8ball), res));
 | 
			
		||||
            .AddField("🎱 " + GetText(strs._8ball), res)).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -10,7 +10,7 @@ public partial class Games
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Hangmanlist()
 | 
			
		||||
            => await SendConfirmAsync(GetText(strs.hangman_types(prefix)), _service.GetHangmanTypes().Join('\n'));
 | 
			
		||||
            => await Response().Confirm(GetText(strs.hangman_types(prefix)), _service.GetHangmanTypes().Join('\n')).SendAsync();
 | 
			
		||||
 | 
			
		||||
        private static string Draw(HangmanGame.State state)
 | 
			
		||||
            => $"""
 | 
			
		||||
@@ -23,11 +23,11 @@ public partial class Games
 | 
			
		||||
            /-\
 | 
			
		||||
            """;
 | 
			
		||||
 | 
			
		||||
        public static IEmbedBuilder GetEmbed(IEmbedBuilderService eb, HangmanGame.State state)
 | 
			
		||||
        public static EmbedBuilder GetEmbed(IEmbedBuilderService eb, HangmanGame.State state)
 | 
			
		||||
        {
 | 
			
		||||
            if (state.Phase == HangmanGame.Phase.Running)
 | 
			
		||||
            {
 | 
			
		||||
                return eb.Create()
 | 
			
		||||
                return new EmbedBuilder()
 | 
			
		||||
                         .WithOkColor()
 | 
			
		||||
                         .AddField("Hangman", Draw(state))
 | 
			
		||||
                         .AddField("Guess", Format.Code(state.Word))
 | 
			
		||||
@@ -36,14 +36,14 @@ public partial class Games
 | 
			
		||||
 | 
			
		||||
            if (state.Phase == HangmanGame.Phase.Ended && state.Failed)
 | 
			
		||||
            {
 | 
			
		||||
                return eb.Create()
 | 
			
		||||
                return new EmbedBuilder()
 | 
			
		||||
                         .WithErrorColor()
 | 
			
		||||
                         .AddField("Hangman", Draw(state))
 | 
			
		||||
                         .AddField("Guess", Format.Code(state.Word))
 | 
			
		||||
                         .WithFooter(state.MissedLetters.Join(' '));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return eb.Create()
 | 
			
		||||
            return new EmbedBuilder()
 | 
			
		||||
                     .WithOkColor()
 | 
			
		||||
                     .AddField("Hangman", Draw(state))
 | 
			
		||||
                     .AddField("Guess", Format.Code(state.Word))
 | 
			
		||||
@@ -56,13 +56,13 @@ public partial class Games
 | 
			
		||||
        {
 | 
			
		||||
            if (!_service.StartHangman(ctx.Channel.Id, type, out var hangman))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.hangman_running);
 | 
			
		||||
                await Response().Error(strs.hangman_running).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var eb = GetEmbed(_eb, hangman);
 | 
			
		||||
            eb.WithDescription(GetText(strs.hangman_game_started));
 | 
			
		||||
            await EmbedAsync(eb);
 | 
			
		||||
            await Response().Embed(eb).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -70,7 +70,7 @@ public partial class Games
 | 
			
		||||
        public async Task HangmanStop()
 | 
			
		||||
        {
 | 
			
		||||
            if (await _service.StopHangman(ctx.Channel.Id))
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.hangman_stopped);
 | 
			
		||||
                await Response().Confirm(strs.hangman_stopped).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -25,17 +25,16 @@ public partial class Games
 | 
			
		||||
            if ((nunchi = _service.NunchiGames.GetOrAdd(ctx.Guild.Id, newNunchi)) != newNunchi)
 | 
			
		||||
            {
 | 
			
		||||
                // join it
 | 
			
		||||
                // if you failed joining, that means game is running or just ended
 | 
			
		||||
                if (!await nunchi.Join(ctx.User.Id, ctx.User.ToString()))
 | 
			
		||||
                    // if you failed joining, that means game is running or just ended
 | 
			
		||||
                    // await ReplyErrorLocalized("nunchi_already_started");
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.nunchi_joined(nunchi.ParticipantCount));
 | 
			
		||||
                await Response().Error(strs.nunchi_joined(nunchi.ParticipantCount)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            try { await ConfirmLocalizedAsync(strs.nunchi_created); }
 | 
			
		||||
            try { await Response().Confirm(strs.nunchi_created).SendAsync(); }
 | 
			
		||||
            catch { }
 | 
			
		||||
 | 
			
		||||
            nunchi.OnGameEnded += NunchiOnGameEnded;
 | 
			
		||||
@@ -50,7 +49,7 @@ public partial class Games
 | 
			
		||||
            {
 | 
			
		||||
                if (_service.NunchiGames.TryRemove(ctx.Guild.Id, out var game))
 | 
			
		||||
                    game.Dispose();
 | 
			
		||||
                await ConfirmLocalizedAsync(strs.nunchi_failed_to_start);
 | 
			
		||||
                await Response().Confirm(strs.nunchi_failed_to_start).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Task ClientMessageReceived(SocketMessage arg)
 | 
			
		||||
@@ -82,30 +81,34 @@ public partial class Games
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (arg2 is null)
 | 
			
		||||
                    return ConfirmLocalizedAsync(strs.nunchi_ended_no_winner);
 | 
			
		||||
                return ConfirmLocalizedAsync(strs.nunchi_ended(Format.Bold(arg2)));
 | 
			
		||||
                    return Response().Confirm(strs.nunchi_ended_no_winner).SendAsync();
 | 
			
		||||
                return Response().Confirm(strs.nunchi_ended(Format.Bold(arg2))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Nunchi_OnRoundStarted(NunchiGame arg, int cur)
 | 
			
		||||
            => ConfirmLocalizedAsync(strs.nunchi_round_started(Format.Bold(arg.ParticipantCount.ToString()),
 | 
			
		||||
                Format.Bold(cur.ToString())));
 | 
			
		||||
            => Response()
 | 
			
		||||
               .Confirm(strs.nunchi_round_started(Format.Bold(arg.ParticipantCount.ToString()),
 | 
			
		||||
                   Format.Bold(cur.ToString())))
 | 
			
		||||
               .SendAsync();
 | 
			
		||||
 | 
			
		||||
        private Task Nunchi_OnUserGuessed(NunchiGame arg)
 | 
			
		||||
            => ConfirmLocalizedAsync(strs.nunchi_next_number(Format.Bold(arg.CurrentNumber.ToString())));
 | 
			
		||||
            => Response().Confirm(strs.nunchi_next_number(Format.Bold(arg.CurrentNumber.ToString()))).SendAsync();
 | 
			
		||||
 | 
			
		||||
        private Task Nunchi_OnRoundEnded(NunchiGame arg1, (ulong Id, string Name)? arg2)
 | 
			
		||||
        {
 | 
			
		||||
            if (arg2.HasValue)
 | 
			
		||||
                return ConfirmLocalizedAsync(strs.nunchi_round_ended(Format.Bold(arg2.Value.Name)));
 | 
			
		||||
            return ConfirmLocalizedAsync(strs.nunchi_round_ended_boot(
 | 
			
		||||
                Format.Bold("\n"
 | 
			
		||||
                            + string.Join("\n, ",
 | 
			
		||||
                                arg1.Participants.Select(x
 | 
			
		||||
                                    => x.Name))))); // this won't work if there are too many users
 | 
			
		||||
                return Response().Confirm(strs.nunchi_round_ended(Format.Bold(arg2.Value.Name))).SendAsync();
 | 
			
		||||
            return Response()
 | 
			
		||||
                   .Confirm(strs.nunchi_round_ended_boot(
 | 
			
		||||
                       Format.Bold("\n"
 | 
			
		||||
                                   + string.Join("\n, ",
 | 
			
		||||
                                       arg1.Participants.Select(x
 | 
			
		||||
                                           => x.Name)))))
 | 
			
		||||
                   .SendAsync(); // this won't work if there are too many users
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Nunchi_OnGameStarted(NunchiGame arg)
 | 
			
		||||
            => ConfirmLocalizedAsync(strs.nunchi_started(Format.Bold(arg.ParticipantCount.ToString())));
 | 
			
		||||
            => Response().Confirm(strs.nunchi_started(Format.Bold(arg.ParticipantCount.ToString()))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -27,10 +27,10 @@ public partial class Games
 | 
			
		||||
            var channel = (ITextChannel)ctx.Channel;
 | 
			
		||||
 | 
			
		||||
            var game = _service.RunningContests.GetOrAdd(ctx.Guild.Id,
 | 
			
		||||
                _ => new(_games, _client, channel, prefix, options, _eb));
 | 
			
		||||
                _ => new(_games, _client, channel, prefix, options, _sender));
 | 
			
		||||
 | 
			
		||||
            if (game.IsActive)
 | 
			
		||||
                await SendErrorAsync($"Contest already running in {game.Channel.Mention} channel.");
 | 
			
		||||
                await Response().Error($"Contest already running in {game.Channel.Mention} channel.").SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await game.Start();
 | 
			
		||||
        }
 | 
			
		||||
@@ -45,7 +45,7 @@ public partial class Games
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await SendErrorAsync("No contest to stop on this channel.");
 | 
			
		||||
            await Response().Error("No contest to stop on this channel.").SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -59,7 +59,7 @@ public partial class Games
 | 
			
		||||
 | 
			
		||||
            _games.AddTypingArticle(ctx.User, text);
 | 
			
		||||
 | 
			
		||||
            await SendConfirmAsync("Added new article for typing game.");
 | 
			
		||||
            await Response().Confirm("Added new article for typing game.").SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -73,13 +73,15 @@ public partial class Games
 | 
			
		||||
 | 
			
		||||
            if (!articles.Any())
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync($"{ctx.User.Mention} `No articles found on that page.`");
 | 
			
		||||
                await Response().Error($"{ctx.User.Mention} `No articles found on that page.`").SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var i = (page - 1) * 15;
 | 
			
		||||
            await SendConfirmAsync("List of articles for Type Race",
 | 
			
		||||
                string.Join("\n", articles.Select(a => $"`#{++i}` - {a.Text.TrimTo(50)}")));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm("List of articles for Type Race",
 | 
			
		||||
                      string.Join("\n", articles.Select(a => $"`#{++i}` - {a.Text.TrimTo(50)}")))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -92,12 +94,12 @@ public partial class Games
 | 
			
		||||
            if (removed is null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithTitle($"Removed typing article #{index + 1}")
 | 
			
		||||
                           .WithDescription(removed.Text.TrimTo(50))
 | 
			
		||||
                           .WithOkColor();
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,7 +17,7 @@ public class TypingGame
 | 
			
		||||
    private readonly GamesService _games;
 | 
			
		||||
    private readonly string _prefix;
 | 
			
		||||
    private readonly Options _options;
 | 
			
		||||
    private readonly IEmbedBuilderService _eb;
 | 
			
		||||
    private readonly IMessageSenderService _sender;
 | 
			
		||||
 | 
			
		||||
    public TypingGame(
 | 
			
		||||
        GamesService games,
 | 
			
		||||
@@ -25,13 +25,13 @@ public class TypingGame
 | 
			
		||||
        ITextChannel channel,
 | 
			
		||||
        string prefix,
 | 
			
		||||
        Options options,
 | 
			
		||||
        IEmbedBuilderService eb)
 | 
			
		||||
        IMessageSenderService sender)
 | 
			
		||||
    {
 | 
			
		||||
        _games = games;
 | 
			
		||||
        _client = client;
 | 
			
		||||
        _prefix = prefix;
 | 
			
		||||
        _options = options;
 | 
			
		||||
        _eb = eb;
 | 
			
		||||
        _sender = sender;
 | 
			
		||||
 | 
			
		||||
        Channel = channel;
 | 
			
		||||
        IsActive = false;
 | 
			
		||||
@@ -50,7 +50,9 @@ public class TypingGame
 | 
			
		||||
        _sw.Reset();
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            await Channel.SendConfirmAsync(_eb, "Typing contest stopped.");
 | 
			
		||||
            await _sender.Response(Channel)
 | 
			
		||||
                         .Confirm("Typing contest stopped.")
 | 
			
		||||
                         .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        catch
 | 
			
		||||
        {
 | 
			
		||||
@@ -68,8 +70,10 @@ public class TypingGame
 | 
			
		||||
        var i = (int)(CurrentSentence.Length / WORD_VALUE * 1.7f);
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            await Channel.SendConfirmAsync(_eb,
 | 
			
		||||
                $":clock2: Next contest will last for {i} seconds. Type the bolded text as fast as you can.");
 | 
			
		||||
            await _sender.Response(Channel)
 | 
			
		||||
                         .Confirm(
 | 
			
		||||
                             $":clock2: Next contest will last for {i} seconds. Type the bolded text as fast as you can.")
 | 
			
		||||
                         .SendAsync();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var time = _options.StartTime;
 | 
			
		||||
@@ -139,18 +143,26 @@ public class TypingGame
 | 
			
		||||
                    var elapsed = _sw.Elapsed;
 | 
			
		||||
                    var wpm = CurrentSentence.Length / WORD_VALUE / elapsed.TotalSeconds * 60;
 | 
			
		||||
                    _finishedUserIds.Add(msg.Author.Id);
 | 
			
		||||
                    await Channel.EmbedAsync(_eb.Create()
 | 
			
		||||
                                                .WithOkColor()
 | 
			
		||||
                                                .WithTitle($"{msg.Author} finished the race!")
 | 
			
		||||
                                                .AddField("Place", $"#{_finishedUserIds.Count}", true)
 | 
			
		||||
                                                .AddField("WPM", $"{wpm:F1} *[{elapsed.TotalSeconds:F2}sec]*", true)
 | 
			
		||||
                                                .AddField("Errors", distance.ToString(), true));
 | 
			
		||||
 | 
			
		||||
                    await _sender.Response(Channel)
 | 
			
		||||
                                 .Embed(eb => new EmbedBuilder()
 | 
			
		||||
                                                  .WithOkColor()
 | 
			
		||||
                                                  .WithTitle($"{msg.Author} finished the race!")
 | 
			
		||||
                                                  .AddField("Place", $"#{_finishedUserIds.Count}", true)
 | 
			
		||||
                                                  .AddField("WPM", $"{wpm:F1} *[{elapsed.TotalSeconds:F2}sec]*", true)
 | 
			
		||||
                                                  .AddField("Errors", distance.ToString(), true))
 | 
			
		||||
                                 .SendAsync();
 | 
			
		||||
 | 
			
		||||
                    if (_finishedUserIds.Count % 4 == 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        await Channel.SendConfirmAsync(_eb,
 | 
			
		||||
                            ":exclamation: A lot of people finished, here is the text for those still typing:"
 | 
			
		||||
                            + $"\n\n**{Format.Sanitize(CurrentSentence.Replace(" ", " \x200B", StringComparison.InvariantCulture)).SanitizeMentions(true)}**");
 | 
			
		||||
                        await _sender.Response(Channel)
 | 
			
		||||
                                     .Confirm(
 | 
			
		||||
                                         $"""
 | 
			
		||||
                                          :exclamation: A lot of people finished, here is the text for those still typing:
 | 
			
		||||
 | 
			
		||||
                                          **{Format.Sanitize(CurrentSentence.Replace(" ", " \x200B", StringComparison.InvariantCulture)).SanitizeMentions(true)}**
 | 
			
		||||
                                          """)
 | 
			
		||||
                                     .SendAsync();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -71,9 +71,9 @@ public class TicTacToe
 | 
			
		||||
        return sb.ToString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IEmbedBuilder GetEmbed(string title = null)
 | 
			
		||||
    public EmbedBuilder GetEmbed(string title = null)
 | 
			
		||||
    {
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
                       .WithOkColor()
 | 
			
		||||
                       .WithDescription(Environment.NewLine + GetState())
 | 
			
		||||
                       .WithAuthor(GetText(strs.vs(_users[0], _users[1])));
 | 
			
		||||
@@ -115,13 +115,13 @@ public class TicTacToe
 | 
			
		||||
    {
 | 
			
		||||
        if (phase is Phase.Started or Phase.Ended)
 | 
			
		||||
        {
 | 
			
		||||
            await _channel.SendErrorAsync(_eb, user.Mention + GetText(strs.ttt_already_running));
 | 
			
		||||
            await _channel.Response(_strings, _eb).Error(user.Mention + GetText(strs.ttt_already_running)).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (_users[0] == user)
 | 
			
		||||
        {
 | 
			
		||||
            await _channel.SendErrorAsync(_eb, user.Mention + GetText(strs.ttt_against_yourself));
 | 
			
		||||
            await _channel.Response(_strings, _eb).Error(user.Mention + GetText(strs.ttt_against_yourself)).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@ public partial class Games
 | 
			
		||||
 | 
			
		||||
                game = new(Strings, _client, channel, (IGuildUser)ctx.User, options, _eb);
 | 
			
		||||
                _service.TicTacToeGames.Add(channel.Id, game);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.ttt_created);
 | 
			
		||||
                await Response().Confirm(strs.ttt_created).SendAsync();
 | 
			
		||||
 | 
			
		||||
                game.OnEnded += _ =>
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,9 @@ public partial class Games
 | 
			
		||||
            var (opts, _) = OptionsParser.ParseFrom(new TriviaOptions(), args);
 | 
			
		||||
 | 
			
		||||
            var config = _gamesConfig.Data;
 | 
			
		||||
            if (opts.WinRequirement != 0 && config.Trivia.MinimumWinReq > 0 && config.Trivia.MinimumWinReq > opts.WinRequirement)
 | 
			
		||||
            if (opts.WinRequirement != 0
 | 
			
		||||
                && config.Trivia.MinimumWinReq > 0
 | 
			
		||||
                && config.Trivia.MinimumWinReq > opts.WinRequirement)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var trivia = new TriviaGame(opts, _cache);
 | 
			
		||||
@@ -49,11 +51,11 @@ public partial class Games
 | 
			
		||||
 | 
			
		||||
            if (_service.RunningTrivias.TryGetValue(ctx.Guild.Id, out var tg))
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync(GetText(strs.trivia_already_running));
 | 
			
		||||
                await Response().Error(GetText(strs.trivia_already_running)).SendAsync();
 | 
			
		||||
                await tg.TriggerQuestionAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Tl()
 | 
			
		||||
@@ -64,7 +66,7 @@ public partial class Games
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.trivia_none);
 | 
			
		||||
            await Response().Error(strs.trivia_none).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -79,9 +81,9 @@ public partial class Games
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        await ctx.Channel.SendConfirmAsync(_eb,
 | 
			
		||||
                            GetText(strs.trivia_game),
 | 
			
		||||
                            GetText(strs.trivia_stopping));
 | 
			
		||||
                        await Response()
 | 
			
		||||
                              .Confirm(GetText(strs.trivia_game), GetText(strs.trivia_stopping))
 | 
			
		||||
                              .SendAsync();
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    {
 | 
			
		||||
@@ -92,7 +94,7 @@ public partial class Games
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.trivia_none);
 | 
			
		||||
            await Response().Error(strs.trivia_none).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetLeaderboardString(TriviaGame tg)
 | 
			
		||||
@@ -103,13 +105,12 @@ public partial class Games
 | 
			
		||||
                sb.AppendLine(GetText(strs.trivia_points(Format.Bold($"<@{id}>"), pts)));
 | 
			
		||||
 | 
			
		||||
            return sb.ToString();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private IEmbedBuilder? questionEmbed = null;
 | 
			
		||||
        private EmbedBuilder? questionEmbed = null;
 | 
			
		||||
        private IUserMessage? questionMessage = null;
 | 
			
		||||
        private bool showHowToQuit = false;
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        private void RegisterEvents(TriviaGame trivia)
 | 
			
		||||
        {
 | 
			
		||||
            trivia.OnQuestion += OnTriviaQuestion;
 | 
			
		||||
@@ -119,7 +120,7 @@ public partial class Games
 | 
			
		||||
            trivia.OnStats += OnTriviaStats;
 | 
			
		||||
            trivia.OnTimeout += OnTriviaTimeout;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        private void UnregisterEvents(TriviaGame trivia)
 | 
			
		||||
        {
 | 
			
		||||
            trivia.OnQuestion -= OnTriviaQuestion;
 | 
			
		||||
@@ -141,7 +142,8 @@ public partial class Games
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (questionEmbed is not null)
 | 
			
		||||
                    await questionMessage.ModifyAsync(m => m.Embed = questionEmbed.WithFooter(question.GetHint()).Build());
 | 
			
		||||
                    await questionMessage.ModifyAsync(m
 | 
			
		||||
                        => m.Embed = questionEmbed.WithFooter(question.GetHint()).Build());
 | 
			
		||||
            }
 | 
			
		||||
            catch (HttpException ex) when (ex.HttpCode is HttpStatusCode.NotFound or HttpStatusCode.Forbidden)
 | 
			
		||||
            {
 | 
			
		||||
@@ -158,11 +160,11 @@ public partial class Games
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                questionEmbed = _eb.Create()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle(GetText(strs.trivia_game))
 | 
			
		||||
                    .AddField(GetText(strs.category), question.Category)
 | 
			
		||||
                    .AddField(GetText(strs.question), question.Question);
 | 
			
		||||
                questionEmbed = new EmbedBuilder()
 | 
			
		||||
                                   .WithOkColor()
 | 
			
		||||
                                   .WithTitle(GetText(strs.trivia_game))
 | 
			
		||||
                                   .AddField(GetText(strs.category), question.Category)
 | 
			
		||||
                                   .AddField(GetText(strs.question), question.Question);
 | 
			
		||||
 | 
			
		||||
                showHowToQuit = !showHowToQuit;
 | 
			
		||||
                if (showHowToQuit)
 | 
			
		||||
@@ -171,9 +173,10 @@ public partial class Games
 | 
			
		||||
                if (Uri.IsWellFormedUriString(question.ImageUrl, UriKind.Absolute))
 | 
			
		||||
                    questionEmbed.WithImageUrl(question.ImageUrl);
 | 
			
		||||
 | 
			
		||||
                questionMessage = await EmbedAsync(questionEmbed);
 | 
			
		||||
                questionMessage = await Response().Embed(questionEmbed).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (HttpException ex) when (ex.HttpCode is HttpStatusCode.NotFound or HttpStatusCode.Forbidden
 | 
			
		||||
            catch (HttpException ex) when (ex.HttpCode is HttpStatusCode.NotFound
 | 
			
		||||
                                               or HttpStatusCode.Forbidden
 | 
			
		||||
                                               or HttpStatusCode.BadRequest)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning("Unable to send trivia questions. Stopping immediately");
 | 
			
		||||
@@ -186,15 +189,15 @@ public partial class Games
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                    .WithErrorColor()
 | 
			
		||||
                    .WithTitle(GetText(strs.trivia_game))
 | 
			
		||||
                    .WithDescription(GetText(strs.trivia_times_up(Format.Bold(question.Answer))));
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithErrorColor()
 | 
			
		||||
                               .WithTitle(GetText(strs.trivia_game))
 | 
			
		||||
                               .WithDescription(GetText(strs.trivia_times_up(Format.Bold(question.Answer))));
 | 
			
		||||
 | 
			
		||||
                if (Uri.IsWellFormedUriString(question.AnswerImageUrl, UriKind.Absolute))
 | 
			
		||||
                    embed.WithImageUrl(question.AnswerImageUrl);
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
@@ -206,7 +209,7 @@ public partial class Games
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await SendConfirmAsync(GetText(strs.leaderboard), GetLeaderboardString(game));
 | 
			
		||||
                await Response().Confirm(GetText(strs.leaderboard), GetLeaderboardString(game)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
@@ -218,11 +221,11 @@ public partial class Games
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await EmbedAsync(_eb.Create(ctx)
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithAuthor(GetText(strs.trivia_ended))
 | 
			
		||||
                    .WithTitle(GetText(strs.leaderboard))
 | 
			
		||||
                    .WithDescription(GetLeaderboardString(game)));
 | 
			
		||||
                await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                    .WithOkColor()
 | 
			
		||||
                                    .WithAuthor(GetText(strs.trivia_ended))
 | 
			
		||||
                                    .WithTitle(GetText(strs.leaderboard))
 | 
			
		||||
                                    .WithDescription(GetLeaderboardString(game))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
@@ -236,15 +239,19 @@ public partial class Games
 | 
			
		||||
            UnregisterEvents(game);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task OnTriviaGuess(TriviaGame _, TriviaUser user, TriviaQuestion question, bool isWin)
 | 
			
		||||
        private async Task OnTriviaGuess(
 | 
			
		||||
            TriviaGame _,
 | 
			
		||||
            TriviaUser user,
 | 
			
		||||
            TriviaQuestion question,
 | 
			
		||||
            bool isWin)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle(GetText(strs.trivia_game))
 | 
			
		||||
                    .WithDescription(GetText(strs.trivia_win(user.Name,
 | 
			
		||||
                        Format.Bold(question.Answer))));
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithOkColor()
 | 
			
		||||
                               .WithTitle(GetText(strs.trivia_game))
 | 
			
		||||
                               .WithDescription(GetText(strs.trivia_win(user.Name,
 | 
			
		||||
                                   Format.Bold(question.Answer))));
 | 
			
		||||
 | 
			
		||||
                if (Uri.IsWellFormedUriString(question.AnswerImageUrl, UriKind.Absolute))
 | 
			
		||||
                    embed.WithImageUrl(question.AnswerImageUrl);
 | 
			
		||||
@@ -252,7 +259,7 @@ public partial class Games
 | 
			
		||||
 | 
			
		||||
                if (isWin)
 | 
			
		||||
                {
 | 
			
		||||
                    await EmbedAsync(embed);
 | 
			
		||||
                    await Response().Embed(embed).SendAsync();
 | 
			
		||||
 | 
			
		||||
                    var reward = _gamesConfig.Data.Trivia.CurrencyReward;
 | 
			
		||||
                    if (reward > 0)
 | 
			
		||||
@@ -264,7 +271,7 @@ public partial class Games
 | 
			
		||||
                embed.WithDescription(GetText(strs.trivia_guess(user.Name,
 | 
			
		||||
                    Format.Bold(question.Answer))));
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -56,10 +56,10 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
 | 
			
		||||
        var clientId = await _lazyClientId.Value;
 | 
			
		||||
        var repCtx = new ReplacementContext(Context)
 | 
			
		||||
            .WithOverride("{0}", () => clientId.ToString())
 | 
			
		||||
            .WithOverride("{1}", () => prefix)
 | 
			
		||||
            .WithOverride("%prefix%", () => prefix)
 | 
			
		||||
            .WithOverride("%bot.prefix%", () => prefix);
 | 
			
		||||
                     .WithOverride("{0}", () => clientId.ToString())
 | 
			
		||||
                     .WithOverride("{1}", () => prefix)
 | 
			
		||||
                     .WithOverride("%prefix%", () => prefix)
 | 
			
		||||
                     .WithOverride("%bot.prefix%", () => prefix);
 | 
			
		||||
 | 
			
		||||
        var text = SmartText.CreateFrom(botSettings.HelpText);
 | 
			
		||||
        return await repSvc.ReplaceAsync(text, repCtx);
 | 
			
		||||
@@ -74,8 +74,11 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
        var topLevelModules = new List<ModuleInfo>();
 | 
			
		||||
        foreach (var m in _cmds.Modules.GroupBy(x => x.GetTopLevelModule()).Select(x => x.Key))
 | 
			
		||||
        {
 | 
			
		||||
            var result = await _perms.CheckPermsAsync(ctx.Guild, ctx.Channel, ctx.User,
 | 
			
		||||
                m.Name, null);
 | 
			
		||||
            var result = await _perms.CheckPermsAsync(ctx.Guild,
 | 
			
		||||
                ctx.Channel,
 | 
			
		||||
                ctx.User,
 | 
			
		||||
                m.Name,
 | 
			
		||||
                null);
 | 
			
		||||
 | 
			
		||||
            if (result.IsAllowed)
 | 
			
		||||
                topLevelModules.Add(m);
 | 
			
		||||
@@ -84,7 +87,7 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
        await ctx.SendPaginatedConfirmAsync(page,
 | 
			
		||||
            cur =>
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create().WithOkColor().WithTitle(GetText(strs.list_of_modules));
 | 
			
		||||
                var embed = new EmbedBuilder().WithOkColor().WithTitle(GetText(strs.list_of_modules));
 | 
			
		||||
 | 
			
		||||
                var localModules = topLevelModules.Skip(12 * cur).Take(12).ToList();
 | 
			
		||||
 | 
			
		||||
@@ -95,12 +98,12 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                localModules.OrderBy(module => module.Name)
 | 
			
		||||
                    .ToList()
 | 
			
		||||
                    .ForEach(module => embed.AddField($"{GetModuleEmoji(module.Name)} {module.Name}",
 | 
			
		||||
                        GetModuleDescription(module.Name)
 | 
			
		||||
                        + "\n"
 | 
			
		||||
                        + Format.Code(GetText(strs.module_footer(prefix, module.Name.ToLowerInvariant()))),
 | 
			
		||||
                        true));
 | 
			
		||||
                            .ToList()
 | 
			
		||||
                            .ForEach(module => embed.AddField($"{GetModuleEmoji(module.Name)} {module.Name}",
 | 
			
		||||
                                GetModuleDescription(module.Name)
 | 
			
		||||
                                + "\n"
 | 
			
		||||
                                + Format.Code(GetText(strs.module_footer(prefix, module.Name.ToLowerInvariant()))),
 | 
			
		||||
                                true));
 | 
			
		||||
 | 
			
		||||
                return embed;
 | 
			
		||||
            },
 | 
			
		||||
@@ -116,11 +119,11 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
        if (key.Key == strs.module_description_missing.Key)
 | 
			
		||||
        {
 | 
			
		||||
            var desc = _medusae
 | 
			
		||||
                .GetLoadedMedusae(Culture)
 | 
			
		||||
                .FirstOrDefault(m => m.Sneks
 | 
			
		||||
                    .Any(x => x.Name.Equals(moduleName,
 | 
			
		||||
                        StringComparison.InvariantCultureIgnoreCase)))
 | 
			
		||||
                ?.Description;
 | 
			
		||||
                       .GetLoadedMedusae(Culture)
 | 
			
		||||
                       .FirstOrDefault(m => m.Sneks
 | 
			
		||||
                                             .Any(x => x.Name.Equals(moduleName,
 | 
			
		||||
                                                 StringComparison.InvariantCultureIgnoreCase)))
 | 
			
		||||
                       ?.Description;
 | 
			
		||||
 | 
			
		||||
            if (desc is not null)
 | 
			
		||||
                return desc;
 | 
			
		||||
@@ -216,20 +219,23 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
        var allowed = new List<CommandInfo>();
 | 
			
		||||
 | 
			
		||||
        foreach (var cmd in _cmds.Commands
 | 
			
		||||
                     .Where(c => c.Module.GetTopLevelModule()
 | 
			
		||||
                         .Name
 | 
			
		||||
                         .StartsWith(module, StringComparison.InvariantCultureIgnoreCase)))
 | 
			
		||||
                                 .Where(c => c.Module.GetTopLevelModule()
 | 
			
		||||
                                              .Name
 | 
			
		||||
                                              .StartsWith(module, StringComparison.InvariantCultureIgnoreCase)))
 | 
			
		||||
        {
 | 
			
		||||
            var result = await _perms.CheckPermsAsync(ctx.Guild, ctx.Channel, ctx.User, cmd.Module.GetTopLevelModule().Name,
 | 
			
		||||
            var result = await _perms.CheckPermsAsync(ctx.Guild,
 | 
			
		||||
                ctx.Channel,
 | 
			
		||||
                ctx.User,
 | 
			
		||||
                cmd.Module.GetTopLevelModule().Name,
 | 
			
		||||
                cmd.Name);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            if (result.IsAllowed)
 | 
			
		||||
                allowed.Add(cmd);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var cmds = allowed.OrderBy(c => c.Aliases[0])
 | 
			
		||||
            .DistinctBy(x => x.Aliases[0])
 | 
			
		||||
            .ToList();
 | 
			
		||||
                          .DistinctBy(x => x.Aliases[0])
 | 
			
		||||
                          .ToList();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // check preconditions for all commands, but only if it's not 'all'
 | 
			
		||||
@@ -238,12 +244,12 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
        if (opts.View != CommandsOptions.ViewType.All)
 | 
			
		||||
        {
 | 
			
		||||
            succ = new((await cmds.Select(async x =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var pre = await x.CheckPreconditionsAsync(Context, _services);
 | 
			
		||||
                        return (Cmd: x, Succ: pre.IsSuccess);
 | 
			
		||||
                    })
 | 
			
		||||
                    .WhenAll()).Where(x => x.Succ)
 | 
			
		||||
                .Select(x => x.Cmd));
 | 
			
		||||
                                  {
 | 
			
		||||
                                      var pre = await x.CheckPreconditionsAsync(Context, _services);
 | 
			
		||||
                                      return (Cmd: x, Succ: pre.IsSuccess);
 | 
			
		||||
                                  })
 | 
			
		||||
                                  .WhenAll()).Where(x => x.Succ)
 | 
			
		||||
                                             .Select(x => x.Cmd));
 | 
			
		||||
 | 
			
		||||
            if (opts.View == CommandsOptions.ViewType.Hide)
 | 
			
		||||
                // if hidden is specified, completely remove these commands from the list
 | 
			
		||||
@@ -251,63 +257,62 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var cmdsWithGroup = cmds.GroupBy(c => c.Module.GetGroupName())
 | 
			
		||||
            .OrderBy(x => x.Key == x.First().Module.Name ? int.MaxValue : x.Count())
 | 
			
		||||
            .ToList();
 | 
			
		||||
                                .OrderBy(x => x.Key == x.First().Module.Name ? int.MaxValue : x.Count())
 | 
			
		||||
                                .ToList();
 | 
			
		||||
 | 
			
		||||
        if (cmdsWithGroup.Count == 0)
 | 
			
		||||
        {
 | 
			
		||||
            if (opts.View != CommandsOptions.ViewType.Hide)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.module_not_found);
 | 
			
		||||
                await Response().Error(strs.module_not_found).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.module_not_found_or_cant_exec);
 | 
			
		||||
                await Response().Error(strs.module_not_found_or_cant_exec).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var cnt = 0;
 | 
			
		||||
        var groups = cmdsWithGroup.GroupBy(_ => cnt++ / 48).ToArray();
 | 
			
		||||
        var embed = _eb.Create().WithOkColor();
 | 
			
		||||
        var embed = new EmbedBuilder().WithOkColor();
 | 
			
		||||
        foreach (var g in groups)
 | 
			
		||||
        {
 | 
			
		||||
            var last = g.Count();
 | 
			
		||||
            for (var i = 0; i < last; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var transformed = g.ElementAt(i)
 | 
			
		||||
                    .Select(x =>
 | 
			
		||||
                    {
 | 
			
		||||
                        //if cross is specified, and the command doesn't satisfy the requirements, cross it out
 | 
			
		||||
                        if (opts.View == CommandsOptions.ViewType.Cross)
 | 
			
		||||
                        {
 | 
			
		||||
                            return
 | 
			
		||||
                                $"{(succ.Contains(x) ? "✅" : "❌")} {prefix + x.Aliases[0]}";
 | 
			
		||||
                        }
 | 
			
		||||
                                   .Select(x =>
 | 
			
		||||
                                   {
 | 
			
		||||
                                       //if cross is specified, and the command doesn't satisfy the requirements, cross it out
 | 
			
		||||
                                       if (opts.View == CommandsOptions.ViewType.Cross)
 | 
			
		||||
                                       {
 | 
			
		||||
                                           return
 | 
			
		||||
                                               $"{(succ.Contains(x) ? "✅" : "❌")} {prefix + x.Aliases[0]}";
 | 
			
		||||
                                       }
 | 
			
		||||
 | 
			
		||||
                        if (x.Aliases.Count == 1)
 | 
			
		||||
                            return prefix + x.Aliases[0];
 | 
			
		||||
                                       if (x.Aliases.Count == 1)
 | 
			
		||||
                                           return prefix + x.Aliases[0];
 | 
			
		||||
 | 
			
		||||
                                       return prefix + x.Aliases[0] + " / " + prefix + x.Aliases[1];
 | 
			
		||||
                                   });
 | 
			
		||||
 | 
			
		||||
                        return prefix + x.Aliases[0] + " / " + prefix + x.Aliases[1];
 | 
			
		||||
                        
 | 
			
		||||
                    });
 | 
			
		||||
                
 | 
			
		||||
                embed.AddField(g.ElementAt(i).Key, "" + string.Join("\n", transformed) + "", true);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        embed.WithFooter(GetText(strs.commands_instr(prefix)));
 | 
			
		||||
        await EmbedAsync(embed);
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task Group(ModuleInfo group)
 | 
			
		||||
    {
 | 
			
		||||
        var eb = _eb.Create(ctx)
 | 
			
		||||
            .WithTitle(GetText(strs.cmd_group_commands(group.Name)))
 | 
			
		||||
            .WithOkColor();
 | 
			
		||||
        var eb = new EmbedBuilder()
 | 
			
		||||
                    .WithTitle(GetText(strs.cmd_group_commands(group.Name)))
 | 
			
		||||
                    .WithOkColor();
 | 
			
		||||
 | 
			
		||||
        foreach (var cmd in group.Commands.DistinctBy(x => x.Aliases[0]))
 | 
			
		||||
        {
 | 
			
		||||
            eb.AddField(prefix + cmd.Aliases.First(), cmd.RealSummary(_strings, _medusae, Culture, prefix));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(eb);
 | 
			
		||||
        await Response().Embed(eb).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -326,9 +331,9 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
            fail = fail.Substring(prefix.Length);
 | 
			
		||||
 | 
			
		||||
        var group = _cmds.Modules
 | 
			
		||||
            .SelectMany(x => x.Submodules)
 | 
			
		||||
            .Where(x => !string.IsNullOrWhiteSpace(x.Group))
 | 
			
		||||
            .FirstOrDefault(x => x.Group.Equals(fail, StringComparison.InvariantCultureIgnoreCase));
 | 
			
		||||
                         .SelectMany(x => x.Submodules)
 | 
			
		||||
                         .Where(x => !string.IsNullOrWhiteSpace(x.Group))
 | 
			
		||||
                         .FirstOrDefault(x => x.Group.Equals(fail, StringComparison.InvariantCultureIgnoreCase));
 | 
			
		||||
 | 
			
		||||
        if (group is not null)
 | 
			
		||||
        {
 | 
			
		||||
@@ -336,7 +341,7 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await ReplyErrorLocalizedAsync(strs.command_not_found);
 | 
			
		||||
        await Response().Error(strs.command_not_found).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -364,7 +369,7 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.cant_dm);
 | 
			
		||||
                await Response().Error(strs.cant_dm).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
@@ -383,29 +388,29 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
        // order commands by top level module name
 | 
			
		||||
        // and make a dictionary of <ModuleName, Array<JsonCommandData>>
 | 
			
		||||
        var cmdData = _cmds.Commands.GroupBy(x => x.Module.GetTopLevelModule().Name)
 | 
			
		||||
            .OrderBy(x => x.Key)
 | 
			
		||||
            .ToDictionary(x => x.Key,
 | 
			
		||||
                x => x.DistinctBy(c => c.Aliases.First())
 | 
			
		||||
                    .Select(com =>
 | 
			
		||||
                    {
 | 
			
		||||
                        List<string> optHelpStr = null;
 | 
			
		||||
                           .OrderBy(x => x.Key)
 | 
			
		||||
                           .ToDictionary(x => x.Key,
 | 
			
		||||
                               x => x.DistinctBy(c => c.Aliases.First())
 | 
			
		||||
                                     .Select(com =>
 | 
			
		||||
                                     {
 | 
			
		||||
                                         List<string> optHelpStr = null;
 | 
			
		||||
 | 
			
		||||
                        var opt = CommandsUtilityService.GetNadekoOptionType(com.Attributes);
 | 
			
		||||
                        if (opt is not null)
 | 
			
		||||
                            optHelpStr = CommandsUtilityService.GetCommandOptionHelpList(opt);
 | 
			
		||||
                                         var opt = CommandsUtilityService.GetNadekoOptionType(com.Attributes);
 | 
			
		||||
                                         if (opt is not null)
 | 
			
		||||
                                             optHelpStr = CommandsUtilityService.GetCommandOptionHelpList(opt);
 | 
			
		||||
 | 
			
		||||
                        return new CommandJsonObject
 | 
			
		||||
                        {
 | 
			
		||||
                            Aliases = com.Aliases.Select(alias => prefix + alias).ToArray(),
 | 
			
		||||
                            Description = com.RealSummary(_strings, _medusae, Culture, prefix),
 | 
			
		||||
                            Usage = com.RealRemarksArr(_strings, _medusae, Culture, prefix),
 | 
			
		||||
                            Submodule = com.Module.Name,
 | 
			
		||||
                            Module = com.Module.GetTopLevelModule().Name,
 | 
			
		||||
                            Options = optHelpStr,
 | 
			
		||||
                            Requirements = CommandsUtilityService.GetCommandRequirements(com)
 | 
			
		||||
                        };
 | 
			
		||||
                    })
 | 
			
		||||
                    .ToList());
 | 
			
		||||
                                         return new CommandJsonObject
 | 
			
		||||
                                         {
 | 
			
		||||
                                             Aliases = com.Aliases.Select(alias => prefix + alias).ToArray(),
 | 
			
		||||
                                             Description = com.RealSummary(_strings, _medusae, Culture, prefix),
 | 
			
		||||
                                             Usage = com.RealRemarksArr(_strings, _medusae, Culture, prefix),
 | 
			
		||||
                                             Submodule = com.Module.Name,
 | 
			
		||||
                                             Module = com.Module.GetTopLevelModule().Name,
 | 
			
		||||
                                             Options = optHelpStr,
 | 
			
		||||
                                             Requirements = CommandsUtilityService.GetCommandRequirements(com)
 | 
			
		||||
                                         };
 | 
			
		||||
                                     })
 | 
			
		||||
                                     .ToList());
 | 
			
		||||
 | 
			
		||||
        var readableData = JsonConvert.SerializeObject(cmdData, Formatting.Indented);
 | 
			
		||||
        var uploadData = JsonConvert.SerializeObject(cmdData, Formatting.None);
 | 
			
		||||
@@ -498,21 +503,23 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
    public async Task Guide()
 | 
			
		||||
        => await ConfirmLocalizedAsync(strs.guide("https://nadeko.bot/commands",
 | 
			
		||||
            "https://nadekobot.readthedocs.io/en/latest/"));
 | 
			
		||||
        => await Response()
 | 
			
		||||
                 .Confirm(strs.guide("https://nadeko.bot/commands",
 | 
			
		||||
                     "https://nadekobot.readthedocs.io/en/latest/"))
 | 
			
		||||
                 .SendAsync();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private Task SelfhostAction(SocketMessageComponent smc, object _)
 | 
			
		||||
        => smc.RespondConfirmAsync(_eb,
 | 
			
		||||
            """
 | 
			
		||||
                - In case you don't want or cannot Donate to NadekoBot project, but you 
 | 
			
		||||
                - NadekoBot is a completely free and fully [open source](https://gitlab.com/kwoth/nadekobot) project which means you can run your own "selfhosted" instance on your computer or server for free.
 | 
			
		||||
                
 | 
			
		||||
                *Keep in mind that running the bot on your computer means that the bot will be offline when you turn off your computer*
 | 
			
		||||
                
 | 
			
		||||
                - You can find the selfhosting guides by using the `.guide` command and clicking on the second link that pops up.
 | 
			
		||||
                - If you decide to selfhost the bot, still consider [supporting the project](https://patreon.com/join/nadekobot) to keep the development going :)
 | 
			
		||||
                """,
 | 
			
		||||
            - In case you don't want or cannot Donate to NadekoBot project, but you
 | 
			
		||||
            - NadekoBot is a completely free and fully [open source](https://gitlab.com/kwoth/nadekobot) project which means you can run your own "selfhosted" instance on your computer or server for free.
 | 
			
		||||
 | 
			
		||||
            *Keep in mind that running the bot on your computer means that the bot will be offline when you turn off your computer*
 | 
			
		||||
 | 
			
		||||
            - You can find the selfhosting guides by using the `.guide` command and clicking on the second link that pops up.
 | 
			
		||||
            - If you decide to selfhost the bot, still consider [supporting the project](https://patreon.com/join/nadekobot) to keep the development going :)
 | 
			
		||||
            """,
 | 
			
		||||
            true);
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -527,9 +534,9 @@ public sealed class Help : NadekoModule<HelpService>
 | 
			
		||||
                    label: "Selfhosting"),
 | 
			
		||||
                SelfhostAction));
 | 
			
		||||
 | 
			
		||||
        var eb = _eb.Create(ctx)
 | 
			
		||||
            .WithOkColor()
 | 
			
		||||
            .WithTitle("Thank you for considering to donate to the NadekoBot project!");
 | 
			
		||||
        var eb = new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle("Thank you for considering to donate to the NadekoBot project!");
 | 
			
		||||
 | 
			
		||||
        eb
 | 
			
		||||
            .WithDescription("NadekoBot relies on donations to keep the servers, services and APIs running.\n"
 | 
			
		||||
@@ -558,13 +565,13 @@ Nadeko will DM you the welcome instructions, and you may start using the patron-
 | 
			
		||||
")
 | 
			
		||||
            .AddField("Troubleshooting",
 | 
			
		||||
                """
 | 
			
		||||
                    
 | 
			
		||||
                    *In case you didn't receive the rewards within 5 minutes:*
 | 
			
		||||
                    `1.` Make sure your DMs are open to everyone. Maybe your pledge was processed successfully but the bot was unable to DM you. Use the `.patron` command to check your status.
 | 
			
		||||
                    `2.` Make sure you've connected the CORRECT Discord account. Quite often users log in to different Discord accounts in their browser. You may also try disconnecting and reconnecting your account.
 | 
			
		||||
                    `3.` Make sure your payment has been processed and not declined by Patreon.
 | 
			
		||||
                    `4.` If any of the previous steps don't help, you can join the nadeko support server <https://discord.nadeko.bot> and ask for help in the #help channel
 | 
			
		||||
                    """);
 | 
			
		||||
 | 
			
		||||
                *In case you didn't receive the rewards within 5 minutes:*
 | 
			
		||||
                `1.` Make sure your DMs are open to everyone. Maybe your pledge was processed successfully but the bot was unable to DM you. Use the `.patron` command to check your status.
 | 
			
		||||
                `2.` Make sure you've connected the CORRECT Discord account. Quite often users log in to different Discord accounts in their browser. You may also try disconnecting and reconnecting your account.
 | 
			
		||||
                `3.` Make sure your payment has been processed and not declined by Patreon.
 | 
			
		||||
                `4.` If any of the previous steps don't help, you can join the nadeko support server <https://discord.nadeko.bot> and ask for help in the #help channel
 | 
			
		||||
                """);
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
@@ -573,7 +580,7 @@ Nadeko will DM you the welcome instructions, and you may start using the patron-
 | 
			
		||||
        }
 | 
			
		||||
        catch
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.cant_dm);
 | 
			
		||||
            await Response().Error(strs.cant_dm).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -29,14 +29,14 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
 | 
			
		||||
            if (unloaded.Length == 0)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.no_medusa_available);
 | 
			
		||||
                await Response().Pending(strs.no_medusa_available).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ctx.SendPaginatedConfirmAsync(0,
 | 
			
		||||
                page =>
 | 
			
		||||
                {
 | 
			
		||||
                    return _eb.Create(ctx)
 | 
			
		||||
                    return new EmbedBuilder()
 | 
			
		||||
                              .WithOkColor()
 | 
			
		||||
                              .WithTitle(GetText(strs.list_of_unloaded))
 | 
			
		||||
                              .WithDescription(unloaded.Skip(10 * page).Take(10).Join('\n'));
 | 
			
		||||
@@ -48,7 +48,7 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
 | 
			
		||||
        var res = await _service.LoadMedusaAsync(name);
 | 
			
		||||
        if (res == MedusaLoadResult.Success)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.medusa_loaded(Format.Code(name)));
 | 
			
		||||
            await Response().Confirm(strs.medusa_loaded(Format.Code(name))).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            var locStr = res switch
 | 
			
		||||
@@ -60,7 +60,7 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
                _ => strs.error_occured
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            await ReplyErrorLocalizedAsync(locStr);
 | 
			
		||||
            await Response().Error(locStr).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
@@ -73,22 +73,22 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
            var loaded = _service.GetLoadedMedusae();
 | 
			
		||||
            if (loaded.Count == 0)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyPendingLocalizedAsync(strs.no_medusa_loaded);
 | 
			
		||||
                await Response().Pending(strs.no_medusa_loaded).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(_eb.Create(ctx)
 | 
			
		||||
            await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                            .WithOkColor()
 | 
			
		||||
                                            .WithTitle(GetText(strs.loaded_medusae))
 | 
			
		||||
                                            .WithDescription(loaded.Select(x => x.Name)
 | 
			
		||||
                                                                   .Join("\n")));
 | 
			
		||||
                                                                   .Join("\n"))).SendAsync();
 | 
			
		||||
            
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        var res = await _service.UnloadMedusaAsync(name);
 | 
			
		||||
        if (res == MedusaUnloadResult.Success)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.medusa_unloaded(Format.Code(name)));
 | 
			
		||||
            await Response().Confirm(strs.medusa_unloaded(Format.Code(name))).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            var locStr = res switch
 | 
			
		||||
@@ -98,7 +98,7 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
                _ => strs.error_occured
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            await ReplyErrorLocalizedAsync(locStr);
 | 
			
		||||
            await Response().Error(locStr).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -110,7 +110,7 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
 | 
			
		||||
        if (all.Count == 0)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyPendingLocalizedAsync(strs.no_medusa_available);
 | 
			
		||||
            await Response().Pending(strs.no_medusa_available).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
@@ -128,7 +128,7 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        await ctx.SendPaginatedConfirmAsync(0,
 | 
			
		||||
            page => _eb.Create(ctx)
 | 
			
		||||
            page => new EmbedBuilder()
 | 
			
		||||
                       .WithOkColor()
 | 
			
		||||
                       .WithTitle(GetText(strs.list_of_medusae))
 | 
			
		||||
                       .WithDescription(output.Skip(page * 10).Take(10).Join('\n')),
 | 
			
		||||
@@ -150,7 +150,7 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
            
 | 
			
		||||
            if (found is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.medusa_name_not_found);
 | 
			
		||||
                await Response().Error(strs.medusa_name_not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -161,7 +161,7 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
                                       : $"{x.Prefix} {x.Name}"))
 | 
			
		||||
                                   .Join("\n");
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithAuthor(GetText(strs.medusa_info))
 | 
			
		||||
                        .WithTitle(found.Name)
 | 
			
		||||
@@ -177,20 +177,20 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
                                : cmdNames,
 | 
			
		||||
                            true);
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(eb);
 | 
			
		||||
            await Response().Embed(eb).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (medusae.Count == 0)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyPendingLocalizedAsync(strs.no_medusa_loaded);
 | 
			
		||||
            await Response().Pending(strs.no_medusa_loaded).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        await ctx.SendPaginatedConfirmAsync(0,
 | 
			
		||||
            page =>
 | 
			
		||||
            {
 | 
			
		||||
                var eb = _eb.Create(ctx)
 | 
			
		||||
                var eb = new EmbedBuilder()
 | 
			
		||||
                            .WithOkColor();
 | 
			
		||||
 | 
			
		||||
                foreach (var medusa in medusae.Skip(page * 9).Take(9))
 | 
			
		||||
@@ -212,7 +212,7 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
    [OwnerOnly]
 | 
			
		||||
    public async Task MedusaSearch()
 | 
			
		||||
    {
 | 
			
		||||
        var eb = _eb.Create()
 | 
			
		||||
        var eb = new EmbedBuilder()
 | 
			
		||||
                    .WithTitle(GetText(strs.list_of_medusae))
 | 
			
		||||
                    .WithOkColor();
 | 
			
		||||
        
 | 
			
		||||
@@ -224,6 +224,6 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
 | 
			
		||||
                """, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(eb);
 | 
			
		||||
        await Response().Embed(eb).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -33,14 +33,14 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (userVoiceChannelId is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.must_be_in_voice);
 | 
			
		||||
            await Response().Error(strs.must_be_in_voice).SendAsync();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var currentUser = await ctx.Guild.GetCurrentUserAsync();
 | 
			
		||||
        if (currentUser.VoiceChannel?.Id != userVoiceChannelId)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_with_bot_in_voice);
 | 
			
		||||
            await Response().Error(strs.not_with_bot_in_voice).SendAsync();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -69,7 +69,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (voiceChannelId is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.must_be_in_voice);
 | 
			
		||||
            await Response().Error(strs.must_be_in_voice).SendAsync();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -80,7 +80,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (botUser.VoiceChannel?.Id != voiceChannelId)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_with_bot_in_voice);
 | 
			
		||||
            await Response().Error(strs.not_with_bot_in_voice).SendAsync();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -96,20 +96,20 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel);
 | 
			
		||||
        if (mp is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var (trackInfo, index) = await mp.TryEnqueueTrackAsync(query, ctx.User.ToString(), asNext, forcePlatform);
 | 
			
		||||
        if (trackInfo is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.track_not_found);
 | 
			
		||||
            await Response().Error(strs.track_not_found).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithAuthor(GetText(strs.queued_track) + " #" + (index + 1), MUSIC_ICON_URL)
 | 
			
		||||
                           .WithDescription($"{trackInfo.PrettyName()}\n{GetText(strs.queue)} ")
 | 
			
		||||
@@ -122,7 +122,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
            queuedMessage?.DeleteAfter(10, _logService);
 | 
			
		||||
            if (mp.IsStopped)
 | 
			
		||||
            {
 | 
			
		||||
                var msg = await ReplyPendingLocalizedAsync(strs.queue_stopped(Format.Code(prefix + "play")));
 | 
			
		||||
                var msg = await Response().Pending(strs.queue_stopped(Format.Code(prefix + "play"))).SendAsync();
 | 
			
		||||
                msg.DeleteAfter(10, _logService);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -144,7 +144,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel);
 | 
			
		||||
        if (mp is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -162,7 +162,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (voiceChannelId is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.must_be_in_voice);
 | 
			
		||||
            await Response().Error(strs.must_be_in_voice).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -218,7 +218,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
    {
 | 
			
		||||
        if (vol is < 0 or > 100)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.volume_input_invalid);
 | 
			
		||||
            await Response().Error(strs.volume_input_invalid).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -227,7 +227,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        await _service.SetVolumeAsync(ctx.Guild.Id, vol);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.volume_set(vol));
 | 
			
		||||
        await Response().Confirm(strs.volume_set(vol)).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -240,7 +240,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        var success = await _service.PlayAsync(ctx.Guild.Id, ((IGuildUser)ctx.User).VoiceChannel.Id);
 | 
			
		||||
        if (!success)
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // list queue, relevant page
 | 
			
		||||
@@ -251,7 +251,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        // show page with the current track
 | 
			
		||||
        if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -269,11 +269,11 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        IReadOnlyCollection<IQueuedTrackInfo> tracks;
 | 
			
		||||
        if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp) || (tracks = mp.GetQueuedTracks()).Count == 0)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        IEmbedBuilder PrintAction(int curPage)
 | 
			
		||||
        EmbedBuilder PrintAction(int curPage)
 | 
			
		||||
        {
 | 
			
		||||
            var desc = string.Empty;
 | 
			
		||||
            var current = mp.GetCurrentTrack(out var currentIndex);
 | 
			
		||||
@@ -315,7 +315,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(add))
 | 
			
		||||
                desc = add + "\n" + desc;
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithAuthor(GetText(strs.player_queue(curPage + 1, (tracks.Count / LQ_ITEMS_PER_PAGE) + 1)),
 | 
			
		||||
                               MUSIC_ICON_URL)
 | 
			
		||||
                           .WithDescription(desc)
 | 
			
		||||
@@ -339,13 +339,13 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (videos.Count == 0)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.track_not_found);
 | 
			
		||||
            await Response().Error(strs.track_not_found).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var resultsString = videos.Select((x, i) => $"`{i + 1}.`\n\t{Format.Bold(x.Title)}\n\t{x.Url}").Join('\n');
 | 
			
		||||
 | 
			
		||||
        var msg = await SendConfirmAsync(resultsString);
 | 
			
		||||
        var msg = await Response().Confirm(resultsString).SendAsync();
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
@@ -388,7 +388,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
    {
 | 
			
		||||
        if (index < 1)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.removed_track_error);
 | 
			
		||||
            await Response().Error(strs.removed_track_error).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -398,17 +398,17 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!mp.TryRemoveTrackAt(index - 1, out var track))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.removed_track_error);
 | 
			
		||||
            await Response().Error(strs.removed_track_error).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
                       .WithAuthor(GetText(strs.removed_track) + " #" + index, MUSIC_ICON_URL)
 | 
			
		||||
                       .WithDescription(track.PrettyName())
 | 
			
		||||
                       .WithFooter(track.PrettyInfo())
 | 
			
		||||
@@ -428,12 +428,12 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        mp.Clear();
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.queue_cleared);
 | 
			
		||||
        await Response().Confirm(strs.queue_cleared).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -446,7 +446,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -473,11 +473,11 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        await _service.SetRepeatAsync(ctx.Guild.Id, InputToDbType(type));
 | 
			
		||||
 | 
			
		||||
        if (type == InputRepeatType.None)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.repeating_none);
 | 
			
		||||
            await Response().Confirm(strs.repeating_none).SendAsync();
 | 
			
		||||
        else if (type == InputRepeatType.Queue)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.repeating_queue);
 | 
			
		||||
            await Response().Confirm(strs.repeating_queue).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.repeating_track);
 | 
			
		||||
            await Response().Confirm(strs.repeating_track).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -490,7 +490,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp) || mp.GetCurrentTrack(out _) is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -521,7 +521,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (voiceChannelId is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.must_be_in_voice);
 | 
			
		||||
            await Response().Error(strs.must_be_in_voice).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -532,20 +532,20 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
 | 
			
		||||
        if (botUser.VoiceChannel?.Id != voiceChannelId)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_with_bot_in_voice);
 | 
			
		||||
            await Response().Error(strs.not_with_bot_in_voice).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel);
 | 
			
		||||
        if (mp is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await _service.EnqueueDirectoryAsync(mp, dirPath, ctx.User.ToString());
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.dir_queue_complete);
 | 
			
		||||
        await Response().Confirm(strs.dir_queue_complete).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -554,7 +554,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
    {
 | 
			
		||||
        if (--from < 0 || --to < 0 || from == to)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.invalid_input);
 | 
			
		||||
            await Response().Error(strs.invalid_input).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -565,18 +565,18 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel);
 | 
			
		||||
        if (mp is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var track = mp.MoveTrack(from, to);
 | 
			
		||||
        if (track is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.invalid_input);
 | 
			
		||||
            await Response().Error(strs.invalid_input).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
                       .WithTitle(track.Title.TrimTo(65))
 | 
			
		||||
                       .WithAuthor(GetText(strs.track_moved), MUSIC_ICON_URL)
 | 
			
		||||
                       .AddField(GetText(strs.from_position), $"#{from + 1}", true)
 | 
			
		||||
@@ -586,7 +586,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        if (Uri.IsWellFormedUriString(track.Url, UriKind.Absolute))
 | 
			
		||||
            embed.WithUrl(track.Url);
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(embed);
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -603,7 +603,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel);
 | 
			
		||||
        if (mp is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -613,7 +613,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        var queuedCount = await _service.EnqueueYoutubePlaylistAsync(mp, playlistQuery, ctx.User.ToString());
 | 
			
		||||
        if (queuedCount == 0)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_search_results);
 | 
			
		||||
            await Response().Error(strs.no_search_results).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -627,7 +627,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel);
 | 
			
		||||
        if (mp is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -635,7 +635,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        if (currentTrack is null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
                       .WithOkColor()
 | 
			
		||||
                       .WithAuthor(GetText(strs.now_playing), MUSIC_ICON_URL)
 | 
			
		||||
                       .WithDescription(currentTrack.PrettyName())
 | 
			
		||||
@@ -643,7 +643,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
                       .WithFooter(
 | 
			
		||||
                           $"{mp.PrettyVolume()} | {mp.PrettyTotalTime()} | {currentTrack.Platform} | {currentTrack.Queuer}");
 | 
			
		||||
 | 
			
		||||
        await ctx.Channel.EmbedAsync(embed);
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -657,12 +657,12 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel);
 | 
			
		||||
        if (mp is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        mp.ShuffleQueue();
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.queue_shuffled);
 | 
			
		||||
        await Response().Confirm(strs.queue_shuffled).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -672,7 +672,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
    {
 | 
			
		||||
        await _service.SetMusicChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.set_music_channel);
 | 
			
		||||
        await Response().Confirm(strs.set_music_channel).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -682,7 +682,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
    {
 | 
			
		||||
        await _service.SetMusicChannelAsync(ctx.Guild.Id, null);
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.unset_music_channel);
 | 
			
		||||
        await Response().Confirm(strs.unset_music_channel).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -692,9 +692,9 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
        var newState = await _service.ToggleAutoDisconnectAsync(ctx.Guild.Id);
 | 
			
		||||
 | 
			
		||||
        if (newState)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.autodc_enable);
 | 
			
		||||
            await Response().Confirm(strs.autodc_enable).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.autodc_disable);
 | 
			
		||||
            await Response().Confirm(strs.autodc_disable).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -703,7 +703,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
    public async Task MusicQuality()
 | 
			
		||||
    {
 | 
			
		||||
        var quality = await _service.GetMusicQualityAsync(ctx.Guild.Id);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.current_music_quality(Format.Bold(quality.ToString())));
 | 
			
		||||
        await Response().Confirm(strs.current_music_quality(Format.Bold(quality.ToString()))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -712,7 +712,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
    public async Task MusicQuality(QualityPreset preset)
 | 
			
		||||
    {
 | 
			
		||||
        await _service.SetMusicQualityAsync(ctx.Guild.Id, preset);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.music_quality_set(Format.Bold(preset.ToString())));
 | 
			
		||||
        await Response().Confirm(strs.music_quality_set(Format.Bold(preset.ToString()))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -721,9 +721,9 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
    {
 | 
			
		||||
        var newValue = await _service.ToggleQueueAutoPlayAsync(ctx.Guild.Id);
 | 
			
		||||
        if (newValue)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.music_autoplay_on);
 | 
			
		||||
            await Response().Confirm(strs.music_autoplay_on).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.music_autoplay_off);
 | 
			
		||||
            await Response().Confirm(strs.music_autoplay_off).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -732,8 +732,8 @@ public sealed partial class Music : NadekoModule<IMusicService>
 | 
			
		||||
    {
 | 
			
		||||
        var newValue = await _service.FairplayAsync(ctx.Guild.Id);
 | 
			
		||||
        if (newValue)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.music_fairplay);
 | 
			
		||||
            await Response().Confirm(strs.music_fairplay).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
            await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -50,13 +50,13 @@ public sealed partial class Music
 | 
			
		||||
                playlists = uow.Set<MusicPlaylist>().GetPlaylistsOnPage(num);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create(ctx)
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithAuthor(GetText(strs.playlists_page(num)), MUSIC_ICON_URL)
 | 
			
		||||
                           .WithDescription(string.Join("\n",
 | 
			
		||||
                               playlists.Select(r => GetText(strs.playlists(r.Id, r.Name, r.Author, r.Songs.Count)))))
 | 
			
		||||
                           .WithOkColor();
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -85,9 +85,9 @@ public sealed partial class Music
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!success)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.playlist_delete_fail);
 | 
			
		||||
                await Response().Error(strs.playlist_delete_fail).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.playlist_deleted);
 | 
			
		||||
                await Response().Confirm(strs.playlist_deleted).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -111,7 +111,7 @@ public sealed partial class Music
 | 
			
		||||
                        mpl.Songs.Skip(cur * 20)
 | 
			
		||||
                           .Take(20)
 | 
			
		||||
                           .Select(x => $"`{++i}.` [{x.Title.TrimTo(45)}]({x.Query}) `{x.Provider}`"));
 | 
			
		||||
                    return _eb.Create().WithTitle($"\"{mpl.Name}\" by {mpl.Author}").WithOkColor().WithDescription(str);
 | 
			
		||||
                    return new EmbedBuilder().WithTitle($"\"{mpl.Name}\" by {mpl.Author}").WithOkColor().WithDescription(str);
 | 
			
		||||
                },
 | 
			
		||||
                mpl.Songs.Count,
 | 
			
		||||
                20);
 | 
			
		||||
@@ -123,7 +123,7 @@ public sealed partial class Music
 | 
			
		||||
        {
 | 
			
		||||
            if (!_service.TryGetMusicPlayer(ctx.Guild.Id, out var mp))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
                await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -151,11 +151,11 @@ public sealed partial class Music
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(_eb.Create()
 | 
			
		||||
            await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                .WithOkColor()
 | 
			
		||||
                                .WithTitle(GetText(strs.playlist_saved))
 | 
			
		||||
                                .AddField(GetText(strs.name), name)
 | 
			
		||||
                                .AddField(GetText(strs.id), playlist.Id.ToString()));
 | 
			
		||||
                                .AddField(GetText(strs.id), playlist.Id.ToString())).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -171,7 +171,7 @@ public sealed partial class Music
 | 
			
		||||
 | 
			
		||||
                if (voiceChannelId is null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.must_be_in_voice);
 | 
			
		||||
                    await Response().Error(strs.must_be_in_voice).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -182,14 +182,14 @@ public sealed partial class Music
 | 
			
		||||
 | 
			
		||||
                if (botUser.VoiceChannel?.Id != voiceChannelId)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.not_with_bot_in_voice);
 | 
			
		||||
                    await Response().Error(strs.not_with_bot_in_voice).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var mp = await _service.GetOrCreateMusicPlayerAsync((ITextChannel)ctx.Channel);
 | 
			
		||||
                if (mp is null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.no_player);
 | 
			
		||||
                    await Response().Error(strs.no_player).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -201,7 +201,7 @@ public sealed partial class Music
 | 
			
		||||
 | 
			
		||||
                if (mpl is null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.playlist_id_not_found);
 | 
			
		||||
                    await Response().Error(strs.playlist_id_not_found).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ public interface IMusicService : IPlaceholderProvider
 | 
			
		||||
    bool TryGetMusicPlayer(ulong guildId, [MaybeNullWhen(false)] out IMusicPlayer musicPlayer);
 | 
			
		||||
    Task<int> EnqueueYoutubePlaylistAsync(IMusicPlayer mp, string playlistId, string queuer);
 | 
			
		||||
    Task EnqueueDirectoryAsync(IMusicPlayer mp, string dirPath, string queuer);
 | 
			
		||||
    Task<IUserMessage?> SendToOutputAsync(ulong guildId, IEmbedBuilder embed);
 | 
			
		||||
    Task<IUserMessage?> SendToOutputAsync(ulong guildId, EmbedBuilder embed);
 | 
			
		||||
    Task<bool> PlayAsync(ulong guildId, ulong voiceChannelId);
 | 
			
		||||
    Task<IList<(string Title, string Url)>> SearchVideosAsync(string query);
 | 
			
		||||
    Task<bool> SetMusicChannelAsync(ulong guildId, ulong? channelId);
 | 
			
		||||
 
 | 
			
		||||
@@ -159,7 +159,7 @@ public sealed class MusicService : IMusicService
 | 
			
		||||
        return mp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task<IUserMessage?> SendToOutputAsync(ulong guildId, IEmbedBuilder embed)
 | 
			
		||||
    public async Task<IUserMessage?> SendToOutputAsync(ulong guildId, EmbedBuilder embed)
 | 
			
		||||
    {
 | 
			
		||||
        if (_outputChannels.TryGetValue(guildId, out var chan))
 | 
			
		||||
        {
 | 
			
		||||
@@ -176,7 +176,7 @@ public sealed class MusicService : IMusicService
 | 
			
		||||
        return async (mp, trackInfo) =>
 | 
			
		||||
        {
 | 
			
		||||
            _ = lastFinishedMessage?.DeleteAsync();
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithAuthor(GetText(guildId, strs.finished_track), Music.MUSIC_ICON_URL)
 | 
			
		||||
                .WithDescription(trackInfo.PrettyName())
 | 
			
		||||
@@ -192,7 +192,7 @@ public sealed class MusicService : IMusicService
 | 
			
		||||
        return async (mp, trackInfo, index) =>
 | 
			
		||||
        {
 | 
			
		||||
            _ = lastPlayingMessage?.DeleteAsync();
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithAuthor(GetText(guildId, strs.playing_track(index + 1)), Music.MUSIC_ICON_URL)
 | 
			
		||||
                .WithDescription(trackInfo.PrettyName())
 | 
			
		||||
 
 | 
			
		||||
@@ -171,7 +171,7 @@ public sealed class CurrencyRewardService : INService, IDisposable
 | 
			
		||||
            if (user is null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create()
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithDescription(message);
 | 
			
		||||
            
 | 
			
		||||
 
 | 
			
		||||
@@ -31,10 +31,10 @@ public partial class Patronage : NadekoModule
 | 
			
		||||
        _ = ctx.Channel.TriggerTypingAsync();
 | 
			
		||||
        var result = await _service.SendMessageToPatronsAsync(tierAndHigher, message);
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.patron_msg_sent(
 | 
			
		||||
        await Response().Confirm(strs.patron_msg_sent(
 | 
			
		||||
            Format.Code(tierAndHigher.ToString()),
 | 
			
		||||
            Format.Bold(result.Success.ToString()),
 | 
			
		||||
            Format.Bold(result.Failed.ToString())));
 | 
			
		||||
            Format.Bold(result.Failed.ToString()))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // [OwnerOnly]
 | 
			
		||||
@@ -47,12 +47,12 @@ public partial class Patronage : NadekoModule
 | 
			
		||||
    //     
 | 
			
		||||
    //     var patron = _service.GiftPatronAsync(user, amount);
 | 
			
		||||
    //
 | 
			
		||||
    //     var eb = _eb.Create(ctx);
 | 
			
		||||
    //     var eb = new EmbedBuilder();
 | 
			
		||||
    //
 | 
			
		||||
    //     await EmbedAsync(eb.WithDescription($"Added **{days}** days of Patron benefits to {user.Mention}!")
 | 
			
		||||
    //     await Response().Embed(eb.WithDescription($"Added **{days}** days of Patron benefits to {user.Mention}!")
 | 
			
		||||
    //                                    .AddField("Tier", Format.Bold(patron.Tier.ToString()), true)
 | 
			
		||||
    //                                    .AddField("Amount", $"**{patron.Amount / 100.0f:N1}$**", true)
 | 
			
		||||
    //                                    .AddField("Until", TimestampTag.FromDateTime(patron.ValidThru.AddDays(1))));
 | 
			
		||||
    //                                    .AddField("Until", TimestampTag.FromDateTime(patron.ValidThru.AddDays(1)))).SendAsync();
 | 
			
		||||
    //     
 | 
			
		||||
    //
 | 
			
		||||
    // }
 | 
			
		||||
@@ -61,14 +61,14 @@ public partial class Patronage : NadekoModule
 | 
			
		||||
    {
 | 
			
		||||
        if (!_pConf.Data.IsEnabled)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.patron_not_enabled);
 | 
			
		||||
            await Response().Error(strs.patron_not_enabled).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var patron = await _service.GetPatronAsync(user.Id);
 | 
			
		||||
        var quotaStats = await _service.GetUserQuotaStatistic(user.Id);
 | 
			
		||||
 | 
			
		||||
        var eb = _eb.Create(ctx)
 | 
			
		||||
        var eb = new EmbedBuilder()
 | 
			
		||||
            .WithAuthor(user)
 | 
			
		||||
            .WithTitle(GetText(strs.patron_info))
 | 
			
		||||
            .WithOkColor();
 | 
			
		||||
@@ -119,7 +119,7 @@ public partial class Patronage : NadekoModule
 | 
			
		||||
        }
 | 
			
		||||
        catch
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.cant_dm);
 | 
			
		||||
            await Response().Error(strs.cant_dm).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,11 +30,13 @@ public sealed class PatronageService
 | 
			
		||||
    private readonly DiscordSocketClient _client;
 | 
			
		||||
    private readonly ISubscriptionHandler _subsHandler;
 | 
			
		||||
    private readonly IEmbedBuilderService _eb;
 | 
			
		||||
    private static readonly TypedKey<long> _quotaKey 
 | 
			
		||||
 | 
			
		||||
    private static readonly TypedKey<long> _quotaKey
 | 
			
		||||
        = new($"quota:last_hourly_reset");
 | 
			
		||||
 | 
			
		||||
    private readonly IBotCache _cache;
 | 
			
		||||
    private readonly IBotCredsProvider _creds;
 | 
			
		||||
    private readonly IMessageSenderService _sender;
 | 
			
		||||
 | 
			
		||||
    public PatronageService(
 | 
			
		||||
        PatronageConfig pConf,
 | 
			
		||||
@@ -42,8 +44,9 @@ public sealed class PatronageService
 | 
			
		||||
        DiscordSocketClient client,
 | 
			
		||||
        ISubscriptionHandler subsHandler,
 | 
			
		||||
        IEmbedBuilderService eb,
 | 
			
		||||
        IBotCache cache, 
 | 
			
		||||
        IBotCredsProvider creds)
 | 
			
		||||
        IBotCache cache,
 | 
			
		||||
        IBotCredsProvider creds,
 | 
			
		||||
        IMessageSenderService sender)
 | 
			
		||||
    {
 | 
			
		||||
        _pConf = pConf;
 | 
			
		||||
        _db = db;
 | 
			
		||||
@@ -52,6 +55,7 @@ public sealed class PatronageService
 | 
			
		||||
        _eb = eb;
 | 
			
		||||
        _cache = cache;
 | 
			
		||||
        _creds = creds;
 | 
			
		||||
        _sender = sender;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Task OnReadyAsync()
 | 
			
		||||
@@ -167,7 +171,7 @@ public sealed class PatronageService
 | 
			
		||||
        {
 | 
			
		||||
            if (subscriber.LastCharge is null)
 | 
			
		||||
                continue;
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
            var lastChargeUtc = subscriber.LastCharge.Value.ToUniversalTime();
 | 
			
		||||
            var dateInOneMonth = lastChargeUtc.Date.AddMonths(1);
 | 
			
		||||
            // await using var tran = await ctx.Database.BeginTransactionAsync();
 | 
			
		||||
@@ -176,7 +180,7 @@ public sealed class PatronageService
 | 
			
		||||
                var dbPatron = await ctx.GetTable<PatronUser>()
 | 
			
		||||
                                        .FirstOrDefaultAsync(x
 | 
			
		||||
                                            => x.UniquePlatformUserId == subscriber.UniquePlatformUserId);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
                if (dbPatron is null)
 | 
			
		||||
                {
 | 
			
		||||
                    // if the user is not in the database alrady
 | 
			
		||||
@@ -189,16 +193,17 @@ public sealed class PatronageService
 | 
			
		||||
                                            LastCharge = lastChargeUtc,
 | 
			
		||||
                                            ValidThru = dateInOneMonth,
 | 
			
		||||
                                        });
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
                    // await tran.CommitAsync();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
                    var newPatron = PatronUserToPatron(dbPatron);
 | 
			
		||||
                    _ = SendWelcomeMessage(newPatron);
 | 
			
		||||
                    await OnNewPatronPayment(newPatron);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    if (dbPatron.LastCharge.Month < lastChargeUtc.Month || dbPatron.LastCharge.Year < lastChargeUtc.Year)
 | 
			
		||||
                    if (dbPatron.LastCharge.Month < lastChargeUtc.Month
 | 
			
		||||
                        || dbPatron.LastCharge.Year < lastChargeUtc.Year)
 | 
			
		||||
                    {
 | 
			
		||||
                        // user is charged again for this month
 | 
			
		||||
                        // if his sub would end in teh future, extend it by one month.
 | 
			
		||||
@@ -215,16 +220,16 @@ public sealed class PatronageService
 | 
			
		||||
                                                     ? old.ValidThru.AddMonths(1)
 | 
			
		||||
                                                     : dateInOneMonth,
 | 
			
		||||
                                             });
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
                        // this should never happen
 | 
			
		||||
                        if (count == 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            // await tran.RollbackAsync();
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
                        // await tran.CommitAsync();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
                        await OnNewPatronPayment(PatronUserToPatron(dbPatron));
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (dbPatron.AmountCents != subscriber.Cents // if user changed the amount 
 | 
			
		||||
@@ -245,7 +250,7 @@ public sealed class PatronageService
 | 
			
		||||
                        var newPatron = dbPatron.Clone();
 | 
			
		||||
                        newPatron.AmountCents = cents;
 | 
			
		||||
                        newPatron.UserId = subscriber.UserId;
 | 
			
		||||
                        
 | 
			
		||||
 | 
			
		||||
                        // idk what's going on but UpdateWithOutputAsync doesn't work properly here
 | 
			
		||||
                        // nor does firstordefault after update. I'm not seeing something obvious
 | 
			
		||||
                        await OnPatronUpdated(
 | 
			
		||||
@@ -261,31 +266,32 @@ public sealed class PatronageService
 | 
			
		||||
                    subscriber.UserId);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        var expiredDate = DateTime.MinValue;
 | 
			
		||||
        foreach (var patron in subscribers.Where(x => x.ChargeStatus == SubscriptionChargeStatus.Refunded))
 | 
			
		||||
        {
 | 
			
		||||
            // if the subscription is refunded, Disable user's valid thru 
 | 
			
		||||
            var changedCount = await ctx.GetTable<PatronUser>()
 | 
			
		||||
                                  .Where(x => x.UniquePlatformUserId == patron.UniquePlatformUserId
 | 
			
		||||
                                              && x.ValidThru != expiredDate)
 | 
			
		||||
                                  .UpdateAsync(old => new()
 | 
			
		||||
                                  {
 | 
			
		||||
                                      ValidThru = expiredDate
 | 
			
		||||
                                  });
 | 
			
		||||
        
 | 
			
		||||
                                        .Where(x => x.UniquePlatformUserId == patron.UniquePlatformUserId
 | 
			
		||||
                                                    && x.ValidThru != expiredDate)
 | 
			
		||||
                                        .UpdateAsync(old => new()
 | 
			
		||||
                                        {
 | 
			
		||||
                                            ValidThru = expiredDate
 | 
			
		||||
                                        });
 | 
			
		||||
 | 
			
		||||
            if (changedCount == 0)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            var updated = await ctx.GetTable<PatronUser>()
 | 
			
		||||
                                  .Where(x => x.UniquePlatformUserId == patron.UniquePlatformUserId)
 | 
			
		||||
                                  .FirstAsync();
 | 
			
		||||
            
 | 
			
		||||
                                   .Where(x => x.UniquePlatformUserId == patron.UniquePlatformUserId)
 | 
			
		||||
                                   .FirstAsync();
 | 
			
		||||
 | 
			
		||||
            await OnPatronRefunded(PatronUserToPatron(updated));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task<bool> ExecPreCommandAsync(ICommandContext ctx,
 | 
			
		||||
    public async Task<bool> ExecPreCommandAsync(
 | 
			
		||||
        ICommandContext ctx,
 | 
			
		||||
        string moduleName,
 | 
			
		||||
        CommandInfo command)
 | 
			
		||||
    {
 | 
			
		||||
@@ -303,7 +309,7 @@ public sealed class PatronageService
 | 
			
		||||
            _ => false,
 | 
			
		||||
            ins =>
 | 
			
		||||
            {
 | 
			
		||||
                var eb = _eb.Create(ctx)
 | 
			
		||||
                var eb = new EmbedBuilder()
 | 
			
		||||
                            .WithPendingColor()
 | 
			
		||||
                            .WithTitle("Insufficient Patron Tier")
 | 
			
		||||
                            .AddField("For", $"{ins.FeatureType}: `{ins.Feature}`", true)
 | 
			
		||||
@@ -322,7 +328,10 @@ public sealed class PatronageService
 | 
			
		||||
                _ = ctx.WarningAsync();
 | 
			
		||||
 | 
			
		||||
                if (ctx.Guild?.OwnerId == ctx.User.Id)
 | 
			
		||||
                    _ = ctx.Channel.EmbedAsync(eb, replyTo: ctx.Message);
 | 
			
		||||
                    _ = _sender.Response(ctx)
 | 
			
		||||
                               .Context(ctx)
 | 
			
		||||
                               .Embed(eb)
 | 
			
		||||
                               .SendAsync();
 | 
			
		||||
                else
 | 
			
		||||
                    _ = ctx.User.EmbedAsync(eb);
 | 
			
		||||
 | 
			
		||||
@@ -330,7 +339,7 @@ public sealed class PatronageService
 | 
			
		||||
            },
 | 
			
		||||
            quota =>
 | 
			
		||||
            {
 | 
			
		||||
                var eb = _eb.Create(ctx)
 | 
			
		||||
                var eb = new EmbedBuilder()
 | 
			
		||||
                            .WithPendingColor()
 | 
			
		||||
                            .WithTitle("Quota Limit Reached");
 | 
			
		||||
 | 
			
		||||
@@ -356,7 +365,9 @@ public sealed class PatronageService
 | 
			
		||||
 | 
			
		||||
                // send the message in the server in case it's the owner
 | 
			
		||||
                if (ctx.Guild?.OwnerId == ctx.User.Id)
 | 
			
		||||
                    _ = ctx.Channel.EmbedAsync(eb, replyTo: ctx.Message);
 | 
			
		||||
                    _ = _sender.Response(ctx)
 | 
			
		||||
                               .Embed(eb)
 | 
			
		||||
                               .SendAsync();
 | 
			
		||||
                else
 | 
			
		||||
                    _ = ctx.User.EmbedAsync(eb);
 | 
			
		||||
 | 
			
		||||
@@ -386,7 +397,8 @@ public sealed class PatronageService
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns either the current usage counter if limit wasn't reached, or QuotaLimit if it is.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public async ValueTask<OneOf<(uint Hourly, uint Daily, uint Monthly), QuotaLimit>> TryIncrementQuotaCounterAsync(ulong userId,
 | 
			
		||||
    public async ValueTask<OneOf<(uint Hourly, uint Daily, uint Monthly), QuotaLimit>> TryIncrementQuotaCounterAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        bool isSelf,
 | 
			
		||||
        FeatureType featureType,
 | 
			
		||||
        string featureName,
 | 
			
		||||
@@ -698,8 +710,8 @@ public sealed class PatronageService
 | 
			
		||||
                Quota = defaultValue,
 | 
			
		||||
                IsPatronLimit = false
 | 
			
		||||
            };
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if (!conf.Quotas.Features.TryGetValue(key.Key, out var data))
 | 
			
		||||
            return new()
 | 
			
		||||
            {
 | 
			
		||||
@@ -769,7 +781,7 @@ public sealed class PatronageService
 | 
			
		||||
            if (user is null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create()
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithTitle("❤️ Thank you for supporting NadekoBot! ❤️")
 | 
			
		||||
                        .WithDescription(
 | 
			
		||||
@@ -782,15 +794,15 @@ public sealed class PatronageService
 | 
			
		||||
                            true)
 | 
			
		||||
                        .AddField("Instructions",
 | 
			
		||||
                            """
 | 
			
		||||
                                *- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.*
 | 
			
		||||
                                *- You can check your benefits on <https://www.patreon.com/join/nadekobot>*
 | 
			
		||||
                                *- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands*
 | 
			
		||||
                                *- **ALL** of the servers that you **own** will enjoy your Patron benefits.*
 | 
			
		||||
                                *- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)*
 | 
			
		||||
                                *- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Nadeko's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.*
 | 
			
		||||
                                *- Permission guide can be found here if you're not familiar with it: <https://nadekobot.readthedocs.io/en/latest/permissions-system/>*
 | 
			
		||||
                                """,
 | 
			
		||||
                            isInline: false)
 | 
			
		||||
                            *- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.*
 | 
			
		||||
                            *- You can check your benefits on <https://www.patreon.com/join/nadekobot>*
 | 
			
		||||
                            *- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands*
 | 
			
		||||
                            *- **ALL** of the servers that you **own** will enjoy your Patron benefits.*
 | 
			
		||||
                            *- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)*
 | 
			
		||||
                            *- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Nadeko's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.*
 | 
			
		||||
                            *- Permission guide can be found here if you're not familiar with it: <https://nadekobot.readthedocs.io/en/latest/permissions-system/>*
 | 
			
		||||
                            """,
 | 
			
		||||
                            inline: false)
 | 
			
		||||
                        .WithFooter($"platform id: {patron.UniquePlatformUserId}");
 | 
			
		||||
 | 
			
		||||
            await user.EmbedAsync(eb);
 | 
			
		||||
@@ -806,11 +818,11 @@ public sealed class PatronageService
 | 
			
		||||
        await using var ctx = _db.GetDbContext();
 | 
			
		||||
 | 
			
		||||
        var patrons = await ctx.GetTable<PatronUser>()
 | 
			
		||||
                 .Where(x => x.ValidThru > DateTime.UtcNow)
 | 
			
		||||
                 .ToArrayAsync();
 | 
			
		||||
                               .Where(x => x.ValidThru > DateTime.UtcNow)
 | 
			
		||||
                               .ToArrayAsync();
 | 
			
		||||
 | 
			
		||||
        var text = SmartText.CreateFrom(message);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        var succ = 0;
 | 
			
		||||
        var fail = 0;
 | 
			
		||||
        foreach (var patron in patrons)
 | 
			
		||||
@@ -828,7 +840,7 @@ public sealed class PatronageService
 | 
			
		||||
 | 
			
		||||
            await Task.Delay(1000);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        return (succ, fail);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -58,9 +58,9 @@ public partial class Permissions
 | 
			
		||||
                    var pageItems = items.Skip(10 * curPage).Take(10).ToList();
 | 
			
		||||
 | 
			
		||||
                    if (pageItems.Count == 0)
 | 
			
		||||
                        return _eb.Create().WithOkColor().WithTitle(title).WithDescription(GetText(strs.empty_page));
 | 
			
		||||
                        return new EmbedBuilder().WithOkColor().WithTitle(title).WithDescription(GetText(strs.empty_page));
 | 
			
		||||
 | 
			
		||||
                    return _eb.Create().WithTitle(title).WithDescription(pageItems.Join('\n')).WithOkColor();
 | 
			
		||||
                    return new EmbedBuilder().WithTitle(title).WithDescription(pageItems.Join('\n')).WithOkColor();
 | 
			
		||||
                },
 | 
			
		||||
                items.Length,
 | 
			
		||||
                10);
 | 
			
		||||
@@ -130,13 +130,13 @@ public partial class Permissions
 | 
			
		||||
 | 
			
		||||
            if (action == AddRemove.Add)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.blacklisted(Format.Code(type.ToString()),
 | 
			
		||||
                    Format.Code(id.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.blacklisted(Format.Code(type.ToString()),
 | 
			
		||||
                    Format.Code(id.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.unblacklisted(Format.Code(type.ToString()),
 | 
			
		||||
                    Format.Code(id.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.unblacklisted(Format.Code(type.ToString()),
 | 
			
		||||
                    Format.Code(id.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ public partial class Permissions
 | 
			
		||||
            var channel = (ITextChannel)ctx.Channel;
 | 
			
		||||
            if (secs is < 0 or > 3600)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.invalid_second_param_between(0, 3600));
 | 
			
		||||
                await Response().Error(strs.invalid_second_param_between(0, 3600)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -56,10 +56,10 @@ public partial class Permissions
 | 
			
		||||
            if (secs == 0)
 | 
			
		||||
            {
 | 
			
		||||
                _service.ClearCooldowns(ctx.Guild.Id, cmdName);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.cmdcd_cleared(Format.Bold(name)));
 | 
			
		||||
                await Response().Confirm(strs.cmdcd_cleared(Format.Bold(name))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.cmdcd_add(Format.Bold(name), Format.Bold(secs.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.cmdcd_add(Format.Bold(name), Format.Bold(secs.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -85,7 +85,7 @@ public partial class Permissions
 | 
			
		||||
            var localSet = _service.GetCommandCooldowns(ctx.Guild.Id);
 | 
			
		||||
 | 
			
		||||
            if (!localSet.Any())
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.cmdcd_none);
 | 
			
		||||
                await Response().Confirm(strs.cmdcd_none).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ctx.SendPaginatedConfirmAsync(page, curPage =>
 | 
			
		||||
@@ -94,7 +94,7 @@ public partial class Permissions
 | 
			
		||||
                        .Take(15)
 | 
			
		||||
                        .Select(x => $"{Format.Code(x.CommandName)}: {x.Seconds.Seconds().Humanize(maxUnit: TimeUnit.Second, culture: Culture)}");
 | 
			
		||||
 | 
			
		||||
                    return _eb.Create(ctx)
 | 
			
		||||
                    return new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithDescription(items.Join("\n"));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,14 +22,14 @@ public partial class Permissions
 | 
			
		||||
        public async Task FwClear()
 | 
			
		||||
        {
 | 
			
		||||
            _service.ClearFilteredWords(ctx.Guild.Id);
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.fw_cleared);
 | 
			
		||||
            await Response().Confirm(strs.fw_cleared).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task FilterList()
 | 
			
		||||
        {
 | 
			
		||||
            var embed = _eb.Create(ctx)
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithTitle("Server filter settings");
 | 
			
		||||
 | 
			
		||||
@@ -63,7 +63,7 @@ public partial class Permissions
 | 
			
		||||
            embed.AddField($"{GetEnabledEmoji(config.FilterInvitesEnabled)} Filter Invites",
 | 
			
		||||
                await GetChannelListAsync(config.FilterInvitesChannels));
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -83,12 +83,12 @@ public partial class Permissions
 | 
			
		||||
            if (enabled)
 | 
			
		||||
            {
 | 
			
		||||
                _service.InviteFilteringServers.Add(channel.Guild.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.invite_filter_server_on);
 | 
			
		||||
                await Response().Confirm(strs.invite_filter_server_on).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _service.InviteFilteringServers.TryRemove(channel.Guild.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.invite_filter_server_off);
 | 
			
		||||
                await Response().Confirm(strs.invite_filter_server_off).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -119,12 +119,12 @@ public partial class Permissions
 | 
			
		||||
            if (removed is null)
 | 
			
		||||
            {
 | 
			
		||||
                _service.InviteFilteringChannels.Add(channel.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.invite_filter_channel_on);
 | 
			
		||||
                await Response().Confirm(strs.invite_filter_channel_on).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _service.InviteFilteringChannels.TryRemove(channel.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.invite_filter_channel_off);
 | 
			
		||||
                await Response().Confirm(strs.invite_filter_channel_off).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -145,12 +145,12 @@ public partial class Permissions
 | 
			
		||||
            if (enabled)
 | 
			
		||||
            {
 | 
			
		||||
                _service.LinkFilteringServers.Add(channel.Guild.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.link_filter_server_on);
 | 
			
		||||
                await Response().Confirm(strs.link_filter_server_on).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _service.LinkFilteringServers.TryRemove(channel.Guild.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.link_filter_server_off);
 | 
			
		||||
                await Response().Confirm(strs.link_filter_server_off).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -181,12 +181,12 @@ public partial class Permissions
 | 
			
		||||
            if (removed is null)
 | 
			
		||||
            {
 | 
			
		||||
                _service.LinkFilteringChannels.Add(channel.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.link_filter_channel_on);
 | 
			
		||||
                await Response().Confirm(strs.link_filter_channel_on).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _service.LinkFilteringChannels.TryRemove(channel.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.link_filter_channel_off);
 | 
			
		||||
                await Response().Confirm(strs.link_filter_channel_off).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -207,12 +207,12 @@ public partial class Permissions
 | 
			
		||||
            if (enabled)
 | 
			
		||||
            {
 | 
			
		||||
                _service.WordFilteringServers.Add(channel.Guild.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.word_filter_server_on);
 | 
			
		||||
                await Response().Confirm(strs.word_filter_server_on).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _service.WordFilteringServers.TryRemove(channel.Guild.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.word_filter_server_off);
 | 
			
		||||
                await Response().Confirm(strs.word_filter_server_off).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -243,12 +243,12 @@ public partial class Permissions
 | 
			
		||||
            if (removed is null)
 | 
			
		||||
            {
 | 
			
		||||
                _service.WordFilteringChannels.Add(channel.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.word_filter_channel_on);
 | 
			
		||||
                await Response().Confirm(strs.word_filter_channel_on).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _service.WordFilteringChannels.TryRemove(channel.Id);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.word_filter_channel_off);
 | 
			
		||||
                await Response().Confirm(strs.word_filter_channel_off).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -289,12 +289,12 @@ public partial class Permissions
 | 
			
		||||
            if (removed is null)
 | 
			
		||||
            {
 | 
			
		||||
                filteredWords.Add(word);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.filter_word_add(Format.Code(word)));
 | 
			
		||||
                await Response().Confirm(strs.filter_word_add(Format.Code(word))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                filteredWords.TryRemove(word);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.filter_word_remove(Format.Code(word)));
 | 
			
		||||
                await Response().Confirm(strs.filter_word_remove(Format.Code(word))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -313,7 +313,7 @@ public partial class Permissions
 | 
			
		||||
            var fws = fwHash.ToArray();
 | 
			
		||||
 | 
			
		||||
            await ctx.SendPaginatedConfirmAsync(page,
 | 
			
		||||
                curPage => _eb.Create()
 | 
			
		||||
                curPage => new EmbedBuilder()
 | 
			
		||||
                              .WithTitle(GetText(strs.filter_word_list))
 | 
			
		||||
                              .WithDescription(string.Join("\n", fws.Skip(curPage * 10).Take(10)))
 | 
			
		||||
                              .WithOkColor(),
 | 
			
		||||
 
 | 
			
		||||
@@ -26,11 +26,11 @@ public partial class Permissions
 | 
			
		||||
            var blockedCommands = _service.BlockedCommands;
 | 
			
		||||
            if (!blockedModule.Any() && !blockedCommands.Any())
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.lgp_none);
 | 
			
		||||
                await Response().Error(strs.lgp_none).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create().WithOkColor();
 | 
			
		||||
            var embed = new EmbedBuilder().WithOkColor();
 | 
			
		||||
 | 
			
		||||
            if (blockedModule.Any())
 | 
			
		||||
                embed.AddField(GetText(strs.blocked_modules), string.Join("\n", _service.BlockedModules));
 | 
			
		||||
@@ -38,7 +38,7 @@ public partial class Permissions
 | 
			
		||||
            if (blockedCommands.Any())
 | 
			
		||||
                embed.AddField(GetText(strs.blocked_commands), string.Join("\n", _service.BlockedCommands));
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -51,11 +51,11 @@ public partial class Permissions
 | 
			
		||||
 | 
			
		||||
            if (added)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.gmod_add(Format.Bold(module.Name)));
 | 
			
		||||
                await Response().Confirm(strs.gmod_add(Format.Bold(module.Name))).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.gmod_remove(Format.Bold(module.Name)));
 | 
			
		||||
            await Response().Confirm(strs.gmod_remove(Format.Bold(module.Name))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -67,11 +67,11 @@ public partial class Permissions
 | 
			
		||||
 | 
			
		||||
            if (added)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.gcmd_add(Format.Bold(cmd.Name)));
 | 
			
		||||
                await Response().Confirm(strs.gcmd_add(Format.Bold(cmd.Name))).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.gcmd_remove(Format.Bold(cmd.Name)));
 | 
			
		||||
            await Response().Confirm(strs.gcmd_remove(Format.Bold(cmd.Name))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -32,9 +32,9 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.verbose_true);
 | 
			
		||||
            await Response().Confirm(strs.verbose_true).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.verbose_false);
 | 
			
		||||
            await Response().Confirm(strs.verbose_false).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -51,9 +51,9 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
            var cache = _service.GetCacheFor(ctx.Guild.Id);
 | 
			
		||||
            if (!ulong.TryParse(cache.PermRole, out var roleId)
 | 
			
		||||
                || (role = ((SocketGuild)ctx.Guild).GetRole(roleId)) is null)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.permrole_not_set);
 | 
			
		||||
                await Response().Confirm(strs.permrole_not_set).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.permrole(Format.Bold(role.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.permrole(Format.Bold(role.ToString()))).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -65,7 +65,7 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
            _service.UpdateCache(config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.permrole_changed(Format.Bold(role.Name)));
 | 
			
		||||
        await Response().Confirm(strs.permrole_changed(Format.Bold(role.Name))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -82,7 +82,7 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
            _service.UpdateCache(config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.permrole_reset);
 | 
			
		||||
        await Response().Confirm(strs.permrole_reset).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -115,7 +115,7 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
                                  return str;
 | 
			
		||||
                              }));
 | 
			
		||||
 | 
			
		||||
        await SendConfirmAsync(toSend);
 | 
			
		||||
        await Response().Confirm(toSend).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -139,12 +139,14 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
                _service.UpdateCache(config);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.removed(index + 1,
 | 
			
		||||
                Format.Code(p.GetCommand(prefix, (SocketGuild)ctx.Guild))));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.removed(index + 1,
 | 
			
		||||
                      Format.Code(p.GetCommand(prefix, (SocketGuild)ctx.Guild))))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        catch (IndexOutOfRangeException)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.perm_out_of_range);
 | 
			
		||||
            await Response().Error(strs.perm_out_of_range).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -164,33 +166,35 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
                    var config = uow.GcWithPermissionsFor(ctx.Guild.Id);
 | 
			
		||||
                    var permsCol = new PermissionsCollection<Permissionv2>(config.Permissions);
 | 
			
		||||
 | 
			
		||||
                    var fromFound = @from < permsCol.Count;
 | 
			
		||||
                    var fromFound = from < permsCol.Count;
 | 
			
		||||
                    var toFound = to < permsCol.Count;
 | 
			
		||||
 | 
			
		||||
                    if (!fromFound)
 | 
			
		||||
                    {
 | 
			
		||||
                        await ReplyErrorLocalizedAsync(strs.perm_not_found(++@from));
 | 
			
		||||
                        await Response().Error(strs.perm_not_found(++from)).SendAsync();
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (!toFound)
 | 
			
		||||
                    {
 | 
			
		||||
                        await ReplyErrorLocalizedAsync(strs.perm_not_found(++to));
 | 
			
		||||
                        await Response().Error(strs.perm_not_found(++to)).SendAsync();
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    fromPerm = permsCol[@from];
 | 
			
		||||
                    fromPerm = permsCol[from];
 | 
			
		||||
 | 
			
		||||
                    permsCol.RemoveAt(@from);
 | 
			
		||||
                    permsCol.RemoveAt(from);
 | 
			
		||||
                    permsCol.Insert(to, fromPerm);
 | 
			
		||||
                    await uow.SaveChangesAsync();
 | 
			
		||||
                    _service.UpdateCache(config);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.moved_permission(
 | 
			
		||||
                    Format.Code(fromPerm.GetCommand(prefix, (SocketGuild)ctx.Guild)),
 | 
			
		||||
                    ++@from,
 | 
			
		||||
                    ++to));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(strs.moved_permission(
 | 
			
		||||
                          Format.Code(fromPerm.GetCommand(prefix, (SocketGuild)ctx.Guild)),
 | 
			
		||||
                          ++from,
 | 
			
		||||
                          ++to))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
@@ -199,7 +203,7 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.perm_out_of_range);
 | 
			
		||||
        await Response().Confirm(strs.perm_out_of_range).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -218,9 +222,9 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.sx_enable(Format.Code(command.Name), GetText(strs.of_command)));
 | 
			
		||||
            await Response().Confirm(strs.sx_enable(Format.Code(command.Name), GetText(strs.of_command))).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.sx_disable(Format.Code(command.Name), GetText(strs.of_command)));
 | 
			
		||||
            await Response().Confirm(strs.sx_disable(Format.Code(command.Name), GetText(strs.of_command))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -238,9 +242,9 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.sx_enable(Format.Code(module.Name), GetText(strs.of_module)));
 | 
			
		||||
            await Response().Confirm(strs.sx_enable(Format.Code(module.Name), GetText(strs.of_module))).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.sx_disable(Format.Code(module.Name), GetText(strs.of_module)));
 | 
			
		||||
            await Response().Confirm(strs.sx_disable(Format.Code(module.Name), GetText(strs.of_module))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -260,15 +264,19 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.ux_enable(Format.Code(command.Name),
 | 
			
		||||
                GetText(strs.of_command),
 | 
			
		||||
                Format.Code(user.ToString())));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.ux_enable(Format.Code(command.Name),
 | 
			
		||||
                      GetText(strs.of_command),
 | 
			
		||||
                      Format.Code(user.ToString())))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.ux_disable(Format.Code(command.Name),
 | 
			
		||||
                GetText(strs.of_command),
 | 
			
		||||
                Format.Code(user.ToString())));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.ux_disable(Format.Code(command.Name),
 | 
			
		||||
                      GetText(strs.of_command),
 | 
			
		||||
                      Format.Code(user.ToString())))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -288,15 +296,19 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.ux_enable(Format.Code(module.Name),
 | 
			
		||||
                GetText(strs.of_module),
 | 
			
		||||
                Format.Code(user.ToString())));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.ux_enable(Format.Code(module.Name),
 | 
			
		||||
                      GetText(strs.of_module),
 | 
			
		||||
                      Format.Code(user.ToString())))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.ux_disable(Format.Code(module.Name),
 | 
			
		||||
                GetText(strs.of_module),
 | 
			
		||||
                Format.Code(user.ToString())));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.ux_disable(Format.Code(module.Name),
 | 
			
		||||
                      GetText(strs.of_module),
 | 
			
		||||
                      Format.Code(user.ToString())))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -320,15 +332,19 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.rx_enable(Format.Code(command.Name),
 | 
			
		||||
                GetText(strs.of_command),
 | 
			
		||||
                Format.Code(role.Name)));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.rx_enable(Format.Code(command.Name),
 | 
			
		||||
                      GetText(strs.of_command),
 | 
			
		||||
                      Format.Code(role.Name)))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.rx_disable(Format.Code(command.Name),
 | 
			
		||||
                GetText(strs.of_command),
 | 
			
		||||
                Format.Code(role.Name)));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.rx_disable(Format.Code(command.Name),
 | 
			
		||||
                      GetText(strs.of_command),
 | 
			
		||||
                      Format.Code(role.Name)))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -352,15 +368,19 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.rx_enable(Format.Code(module.Name),
 | 
			
		||||
                GetText(strs.of_module),
 | 
			
		||||
                Format.Code(role.Name)));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.rx_enable(Format.Code(module.Name),
 | 
			
		||||
                      GetText(strs.of_module),
 | 
			
		||||
                      Format.Code(role.Name)))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.rx_disable(Format.Code(module.Name),
 | 
			
		||||
                GetText(strs.of_module),
 | 
			
		||||
                Format.Code(role.Name)));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.rx_disable(Format.Code(module.Name),
 | 
			
		||||
                      GetText(strs.of_module),
 | 
			
		||||
                      Format.Code(role.Name)))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -381,15 +401,19 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.cx_enable(Format.Code(command.Name),
 | 
			
		||||
                GetText(strs.of_command),
 | 
			
		||||
                Format.Code(chnl.Name)));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.cx_enable(Format.Code(command.Name),
 | 
			
		||||
                      GetText(strs.of_command),
 | 
			
		||||
                      Format.Code(chnl.Name)))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.cx_disable(Format.Code(command.Name),
 | 
			
		||||
                GetText(strs.of_command),
 | 
			
		||||
                Format.Code(chnl.Name)));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.cx_disable(Format.Code(command.Name),
 | 
			
		||||
                      GetText(strs.of_command),
 | 
			
		||||
                      Format.Code(chnl.Name)))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -409,15 +433,19 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.cx_enable(Format.Code(module.Name),
 | 
			
		||||
                GetText(strs.of_module),
 | 
			
		||||
                Format.Code(chnl.Name)));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.cx_enable(Format.Code(module.Name),
 | 
			
		||||
                      GetText(strs.of_module),
 | 
			
		||||
                      Format.Code(chnl.Name)))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.cx_disable(Format.Code(module.Name),
 | 
			
		||||
                GetText(strs.of_module),
 | 
			
		||||
                Format.Code(chnl.Name)));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Confirm(strs.cx_disable(Format.Code(module.Name),
 | 
			
		||||
                      GetText(strs.of_module),
 | 
			
		||||
                      Format.Code(chnl.Name)))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -436,9 +464,9 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.acm_enable(Format.Code(chnl.Name)));
 | 
			
		||||
            await Response().Confirm(strs.acm_enable(Format.Code(chnl.Name))).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.acm_disable(Format.Code(chnl.Name)));
 | 
			
		||||
            await Response().Confirm(strs.acm_disable(Format.Code(chnl.Name))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -459,9 +487,9 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.arm_enable(Format.Code(role.Name)));
 | 
			
		||||
            await Response().Confirm(strs.arm_enable(Format.Code(role.Name))).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.arm_disable(Format.Code(role.Name)));
 | 
			
		||||
            await Response().Confirm(strs.arm_disable(Format.Code(role.Name))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -479,9 +507,9 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.aum_enable(Format.Code(user.ToString())));
 | 
			
		||||
            await Response().Confirm(strs.aum_enable(Format.Code(user.ToString()))).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.aum_disable(Format.Code(user.ToString())));
 | 
			
		||||
            await Response().Confirm(strs.aum_disable(Format.Code(user.ToString()))).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -509,8 +537,8 @@ public partial class Permissions : NadekoModule<PermissionService>
 | 
			
		||||
        await _service.AddPermissions(ctx.Guild.Id, newPerm, allowUser);
 | 
			
		||||
 | 
			
		||||
        if (action.Value)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.asm_enable);
 | 
			
		||||
            await Response().Confirm(strs.asm_enable).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.asm_disable);
 | 
			
		||||
            await Response().Confirm(strs.asm_disable).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -18,18 +18,21 @@ public class PermissionService : IExecPreCommand, INService
 | 
			
		||||
    private readonly CommandHandler _cmd;
 | 
			
		||||
    private readonly IBotStrings _strings;
 | 
			
		||||
    private readonly IEmbedBuilderService _eb;
 | 
			
		||||
    private readonly IMessageSenderService _sender;
 | 
			
		||||
 | 
			
		||||
    public PermissionService(
 | 
			
		||||
        DiscordSocketClient client,
 | 
			
		||||
        DbService db,
 | 
			
		||||
        CommandHandler cmd,
 | 
			
		||||
        IBotStrings strings,
 | 
			
		||||
        IEmbedBuilderService eb)
 | 
			
		||||
        IEmbedBuilderService eb,
 | 
			
		||||
        IMessageSenderService sender)
 | 
			
		||||
    {
 | 
			
		||||
        _db = db;
 | 
			
		||||
        _cmd = cmd;
 | 
			
		||||
        _strings = strings;
 | 
			
		||||
        _eb = eb;
 | 
			
		||||
        _sender = sender;
 | 
			
		||||
 | 
			
		||||
        using var uow = _db.GetDbContext();
 | 
			
		||||
        foreach (var x in uow.Set<GuildConfig>().PermissionsForAll(client.Guilds.ToArray().Select(x => x.Id).ToList()))
 | 
			
		||||
@@ -115,11 +118,12 @@ public class PermissionService : IExecPreCommand, INService
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await channel.SendErrorAsync(_eb,
 | 
			
		||||
                        _strings.GetText(strs.perm_prevent(index + 1,
 | 
			
		||||
                                Format.Bold(pc.Permissions[index]
 | 
			
		||||
                                              .GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild))),
 | 
			
		||||
                            guild.Id));
 | 
			
		||||
                    await _sender.Response(channel)
 | 
			
		||||
                                 .Error(_strings.GetText(strs.perm_prevent(index + 1,
 | 
			
		||||
                                         Format.Bold(pc.Permissions[index]
 | 
			
		||||
                                                       .GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild))),
 | 
			
		||||
                                     guild.Id))
 | 
			
		||||
                                 .SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
@@ -148,7 +152,7 @@ public class PermissionService : IExecPreCommand, INService
 | 
			
		||||
                returnMsg = "You need Admin permissions in order to use permission commands.";
 | 
			
		||||
                if (pc.Verbose)
 | 
			
		||||
                {
 | 
			
		||||
                    try { await channel.SendErrorAsync(_eb, returnMsg); }
 | 
			
		||||
                    try { await _sender.Response(channel).Error(returnMsg).SendAsync(); }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -160,7 +164,7 @@ public class PermissionService : IExecPreCommand, INService
 | 
			
		||||
                returnMsg = $"You need the {Format.Bold(role.Name)} role in order to use permission commands.";
 | 
			
		||||
                if (pc.Verbose)
 | 
			
		||||
                {
 | 
			
		||||
                    try { await channel.SendErrorAsync(_eb, returnMsg); }
 | 
			
		||||
                    try { await _sender.Response(channel).Error(returnMsg).SendAsync(); }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ public partial class Permissions
 | 
			
		||||
        public async Task ResetPerms()
 | 
			
		||||
        {
 | 
			
		||||
            await _perms.Reset(ctx.Guild.Id);
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.perms_reset);
 | 
			
		||||
            await Response().Confirm(strs.perms_reset).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -31,7 +31,7 @@ public partial class Permissions
 | 
			
		||||
        public async Task ResetGlobalPerms()
 | 
			
		||||
        {
 | 
			
		||||
            await _gps.Reset();
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.global_perms_reset);
 | 
			
		||||
            await Response().Confirm(strs.global_perms_reset).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -20,11 +20,11 @@ public partial class Searches
 | 
			
		||||
        //
 | 
			
		||||
        //     if (novelData is null)
 | 
			
		||||
        //     {
 | 
			
		||||
        //         await ReplyErrorLocalizedAsync(strs.failed_finding_novel);
 | 
			
		||||
        //         await Response().Error(strs.failed_finding_novel).SendAsync();
 | 
			
		||||
        //         return;
 | 
			
		||||
        //     }
 | 
			
		||||
        //
 | 
			
		||||
        //     var embed = _eb.Create()
 | 
			
		||||
        //     var embed = new EmbedBuilder()
 | 
			
		||||
        //         .WithOkColor()
 | 
			
		||||
        //         .WithDescription(novelData.Description.Replace("<br>", Environment.NewLine, StringComparison.InvariantCulture))
 | 
			
		||||
        //         .WithTitle(novelData.Title)
 | 
			
		||||
@@ -35,7 +35,7 @@ public partial class Searches
 | 
			
		||||
        //         .AddField(GetText(strs.genres), string.Join(" ", novelData.Genres.Any() ? novelData.Genres : new[] { "none" }), true)
 | 
			
		||||
        //         .WithFooter($"{GetText(strs.score)} {novelData.Score}");
 | 
			
		||||
        //     
 | 
			
		||||
        //     await EmbedAsync(embed);
 | 
			
		||||
        //     await Response().Embed(embed).SendAsync();
 | 
			
		||||
        // }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -86,7 +86,7 @@ public partial class Searches
 | 
			
		||||
                                      .Select(x => x.TextContent.Split(':').Select(y => y.Trim()).ToArray())
 | 
			
		||||
                                      .ToArray();
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithTitle(GetText(strs.mal_profile(name)))
 | 
			
		||||
                           .AddField("💚 " + GetText(strs.watching), stats[0], true)
 | 
			
		||||
@@ -110,7 +110,7 @@ public partial class Searches
 | 
			
		||||
                 .WithUrl(fullQueryLink)
 | 
			
		||||
                 .WithImageUrl(imageUrl);
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static string MalInfoToEmoji(string info)
 | 
			
		||||
@@ -147,11 +147,11 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (animeData is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.failed_finding_anime);
 | 
			
		||||
                await Response().Error(strs.failed_finding_anime).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithDescription(animeData.Synopsis.Replace("<br>",
 | 
			
		||||
                               Environment.NewLine,
 | 
			
		||||
@@ -165,7 +165,7 @@ public partial class Searches
 | 
			
		||||
                               string.Join(",\n", animeData.Genres.Any() ? animeData.Genres : new[] { "none" }),
 | 
			
		||||
                               true)
 | 
			
		||||
                           .WithFooter($"{GetText(strs.score)} {animeData.AverageScore} / 100");
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -179,11 +179,11 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (mangaData is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.failed_finding_manga);
 | 
			
		||||
                await Response().Error(strs.failed_finding_manga).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithDescription(mangaData.Synopsis.Replace("<br>",
 | 
			
		||||
                               Environment.NewLine,
 | 
			
		||||
@@ -198,7 +198,7 @@ public partial class Searches
 | 
			
		||||
                               true)
 | 
			
		||||
                           .WithFooter($"{GetText(strs.score)} {mangaData.AverageScore} / 100");
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -30,12 +30,12 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
                if (symbols.Count == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.not_found);
 | 
			
		||||
                    await Response().Error(strs.not_found).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var symbol = symbols.First();
 | 
			
		||||
                var promptEmbed = _eb.Create()
 | 
			
		||||
                var promptEmbed = new EmbedBuilder()
 | 
			
		||||
                                     .WithDescription(symbol.Description)
 | 
			
		||||
                                     .WithTitle(GetText(strs.did_you_mean(symbol.Symbol)));
 | 
			
		||||
                
 | 
			
		||||
@@ -47,7 +47,7 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
                if (stock is null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.not_found);
 | 
			
		||||
                    await Response().Error(strs.not_found).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -79,7 +79,7 @@ public partial class Searches
 | 
			
		||||
            
 | 
			
		||||
            var price = stock.Price.ToString("C2", localCulture);
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create()
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithAuthor(stock.Symbol)
 | 
			
		||||
                        .WithUrl($"https://www.tradingview.com/chart/?symbol={stock.Symbol}")
 | 
			
		||||
@@ -92,7 +92,7 @@ public partial class Searches
 | 
			
		||||
                        // .AddField("Change 200d", $"{sign200}{change200}", true)
 | 
			
		||||
                        .WithFooter(stock.Exchange);
 | 
			
		||||
            
 | 
			
		||||
            var message = await EmbedAsync(eb);
 | 
			
		||||
            var message = await Response().Embed(eb).SendAsync();
 | 
			
		||||
            await using var imageData = await stockImageTask;
 | 
			
		||||
            if (imageData is null)
 | 
			
		||||
                return;
 | 
			
		||||
@@ -127,7 +127,7 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (nearest is not null)
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithTitle(GetText(strs.crypto_not_found))
 | 
			
		||||
                               .WithDescription(
 | 
			
		||||
                                   GetText(strs.did_you_mean(Format.Bold($"{nearest.Name} ({nearest.Symbol})"))));
 | 
			
		||||
@@ -138,7 +138,7 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (crypto is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.crypto_not_found);
 | 
			
		||||
                await Response().Error(strs.crypto_not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -160,7 +160,7 @@ public partial class Searches
 | 
			
		||||
            await using var sparkline = await _service.GetSparklineAsync(crypto.Id, usd.PercentChange7d >= 0);
 | 
			
		||||
            var fileName = $"{crypto.Slug}_7d.png";
 | 
			
		||||
            
 | 
			
		||||
            var toSend = _eb.Create()
 | 
			
		||||
            var toSend = new EmbedBuilder()
 | 
			
		||||
                            .WithOkColor()
 | 
			
		||||
                            .WithAuthor($"#{crypto.CmcRank}")
 | 
			
		||||
                            .WithTitle($"{crypto.Name} ({crypto.Symbol})")
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ public partial class Searches
 | 
			
		||||
        {
 | 
			
		||||
            var m = _ytChannelRegex.Match(url);
 | 
			
		||||
            if (!m.Success)
 | 
			
		||||
                return ReplyErrorLocalizedAsync(strs.invalid_input);
 | 
			
		||||
                return Response().Error(strs.invalid_input).SendAsync();
 | 
			
		||||
 | 
			
		||||
            if (!((IGuildUser)ctx.User).GetPermissions(channel).MentionEveryone)
 | 
			
		||||
                message = message?.SanitizeAllMentions();
 | 
			
		||||
@@ -55,7 +55,7 @@ public partial class Searches
 | 
			
		||||
            if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)
 | 
			
		||||
                || (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.feed_invalid_url);
 | 
			
		||||
                await Response().Error(strs.feed_invalid_url).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -70,7 +70,7 @@ public partial class Searches
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Information(ex, "Unable to get feeds from that url");
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.feed_cant_parse);
 | 
			
		||||
                await Response().Error(strs.feed_cant_parse).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -80,19 +80,19 @@ public partial class Searches
 | 
			
		||||
            var result = _service.AddFeed(ctx.Guild.Id, channel.Id, url, message);
 | 
			
		||||
            if (result == FeedAddResult.Success)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.feed_added);
 | 
			
		||||
                await Response().Confirm(strs.feed_added).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (result == FeedAddResult.Duplicate)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.feed_duplicate);
 | 
			
		||||
                await Response().Error(strs.feed_duplicate).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (result == FeedAddResult.LimitReached)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.feed_limit_reached);
 | 
			
		||||
                await Response().Error(strs.feed_limit_reached).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -103,9 +103,9 @@ public partial class Searches
 | 
			
		||||
        public async Task FeedRemove(int index)
 | 
			
		||||
        {
 | 
			
		||||
            if (_service.RemoveFeed(ctx.Guild.Id, --index))
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.feed_removed);
 | 
			
		||||
                await Response().Confirm(strs.feed_removed).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.feed_out_of_range);
 | 
			
		||||
                await Response().Error(strs.feed_out_of_range).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -117,14 +117,14 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (!feeds.Any())
 | 
			
		||||
            {
 | 
			
		||||
                await EmbedAsync(_eb.Create().WithOkColor().WithDescription(GetText(strs.feed_no_feed)));
 | 
			
		||||
                await Response().Embed(new EmbedBuilder().WithOkColor().WithDescription(GetText(strs.feed_no_feed))).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ctx.SendPaginatedConfirmAsync(0,
 | 
			
		||||
                cur =>
 | 
			
		||||
                {
 | 
			
		||||
                    var embed = _eb.Create().WithOkColor();
 | 
			
		||||
                    var embed = new EmbedBuilder().WithOkColor();
 | 
			
		||||
                    var i = 0;
 | 
			
		||||
                    var fs = string.Join("\n",
 | 
			
		||||
                        feeds.Skip(cur * 10).Take(10).Select(x => $"`{(cur * 10) + ++i}.` <#{x.ChannelId}> {x.Url}"));
 | 
			
		||||
 
 | 
			
		||||
@@ -115,7 +115,7 @@ public class FeedsService : INService
 | 
			
		||||
                        if (itemUpdateDate <= lastFeedUpdate)
 | 
			
		||||
                            continue;
 | 
			
		||||
 | 
			
		||||
                        var embed = _eb.Create().WithFooter(rssUrl);
 | 
			
		||||
                        var embed = new EmbedBuilder().WithFooter(rssUrl);
 | 
			
		||||
 | 
			
		||||
                        _lastPosts[kvp.Key] = itemUpdateDate;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,30 +10,30 @@ public partial class Searches
 | 
			
		||||
    {
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        public async Task Yomama()
 | 
			
		||||
            => await SendConfirmAsync(await _service.GetYomamaJoke());
 | 
			
		||||
            => await Response().Confirm(await _service.GetYomamaJoke()).SendAsync();
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        public async Task Randjoke()
 | 
			
		||||
        {
 | 
			
		||||
            var (setup, punchline) = await _service.GetRandomJoke();
 | 
			
		||||
            await SendConfirmAsync(setup, punchline);
 | 
			
		||||
            await Response().Confirm(setup, punchline).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        public async Task ChuckNorris()
 | 
			
		||||
            => await SendConfirmAsync(await _service.GetChuckNorrisJoke());
 | 
			
		||||
            => await Response().Confirm(await _service.GetChuckNorrisJoke()).SendAsync();
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        public async Task WowJoke()
 | 
			
		||||
        {
 | 
			
		||||
            if (!_service.WowJokes.Any())
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.jokes_not_loaded);
 | 
			
		||||
                await Response().Error(strs.jokes_not_loaded).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var joke = _service.WowJokes[new NadekoRandom().Next(0, _service.WowJokes.Count)];
 | 
			
		||||
            await SendConfirmAsync(joke.Question, joke.Answer);
 | 
			
		||||
            await Response().Confirm(joke.Question, joke.Answer).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -41,13 +41,13 @@ public partial class Searches
 | 
			
		||||
        {
 | 
			
		||||
            if (!_service.MagicItems.Any())
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.magicitems_not_loaded);
 | 
			
		||||
                await Response().Error(strs.magicitems_not_loaded).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var item = _service.MagicItems[new NadekoRandom().Next(0, _service.MagicItems.Count)];
 | 
			
		||||
 | 
			
		||||
            await SendConfirmAsync("✨" + item.Name, item.Description);
 | 
			
		||||
            await Response().Confirm("✨" + item.Name, item.Description).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -46,7 +46,7 @@ public partial class Searches
 | 
			
		||||
                    var templates = string.Empty;
 | 
			
		||||
                    foreach (var template in data.Skip(curPage * 15).Take(15))
 | 
			
		||||
                        templates += $"**{template.Name}:**\n key: `{template.Id}`\n";
 | 
			
		||||
                    var embed = _eb.Create().WithOkColor().WithDescription(templates);
 | 
			
		||||
                    var embed = new EmbedBuilder().WithOkColor().WithDescription(templates);
 | 
			
		||||
 | 
			
		||||
                    return embed;
 | 
			
		||||
                },
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ public partial class Searches
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(_creds.OsuApiKey))
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.osu_api_key);
 | 
			
		||||
                    await Response().Error(strs.osu_api_key).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -42,14 +42,14 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
                if (objs.Count == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.osu_user_not_found);
 | 
			
		||||
                    await Response().Error(strs.osu_user_not_found).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var obj = objs[0];
 | 
			
		||||
                var userId = obj.UserId;
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(_eb.Create()
 | 
			
		||||
                await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                                .WithOkColor()
 | 
			
		||||
                                                .WithTitle($"osu! {smode} profile for {user}")
 | 
			
		||||
                                                .WithThumbnailUrl($"https://a.ppy.sh/{userId}")
 | 
			
		||||
@@ -61,15 +61,15 @@ public partial class Searches
 | 
			
		||||
                                                .AddField("Total PP", Math.Round(obj.PpRaw, 2), true)
 | 
			
		||||
                                                .AddField("Accuracy", Math.Round(obj.Accuracy, 2) + "%", true)
 | 
			
		||||
                                                .AddField("Playcount", obj.Playcount, true)
 | 
			
		||||
                                                .AddField("Level", Math.Round(obj.Level), true));
 | 
			
		||||
                                                .AddField("Level", Math.Round(obj.Level), true)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (ArgumentOutOfRangeException)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.osu_user_not_found);
 | 
			
		||||
                await Response().Error(strs.osu_user_not_found).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.osu_failed);
 | 
			
		||||
                await Response().Error(strs.osu_failed).SendAsync();
 | 
			
		||||
                Log.Warning(ex, "Osu command failed");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -86,7 +86,7 @@ public partial class Searches
 | 
			
		||||
            var statsResponse = JsonConvert.DeserializeObject<GatariUserStatsResponse>(resString);
 | 
			
		||||
            if (statsResponse.Code != 200 || statsResponse.Stats.Id == 0)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.osu_user_not_found);
 | 
			
		||||
                await Response().Error(strs.osu_user_not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -95,7 +95,7 @@ public partial class Searches
 | 
			
		||||
            var userData = JsonConvert.DeserializeObject<GatariUserResponse>(usrResString).Users[0];
 | 
			
		||||
            var userStats = statsResponse.Stats;
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithTitle($"osu!Gatari {modeStr} profile for {user}")
 | 
			
		||||
                           .WithThumbnailUrl($"https://a.gatari.pw/{userStats.Id}")
 | 
			
		||||
@@ -109,7 +109,7 @@ public partial class Searches
 | 
			
		||||
                           .AddField("Playcount", userStats.Playcount, true)
 | 
			
		||||
                           .AddField("Level", userStats.Level, true);
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -117,13 +117,13 @@ public partial class Searches
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(_creds.OsuApiKey))
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync("An osu! API key is required.");
 | 
			
		||||
                await Response().Error("An osu! API key is required.").SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(user))
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync("Please provide a username.");
 | 
			
		||||
                await Response().Error("Please provide a username.").SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -166,13 +166,13 @@ public partial class Searches
 | 
			
		||||
                return (title, desc);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create().WithOkColor().WithTitle($"Top 5 plays for {user}");
 | 
			
		||||
            var eb = new EmbedBuilder().WithOkColor().WithTitle($"Top 5 plays for {user}");
 | 
			
		||||
 | 
			
		||||
            var mapData = await mapTasks.WhenAll();
 | 
			
		||||
            foreach (var (title, desc) in mapData.Where(x => x != default))
 | 
			
		||||
                eb.AddField(title, desc);
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(eb);
 | 
			
		||||
            await Response().Embed(eb).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //https://osu.ppy.sh/wiki/Accuracy
 | 
			
		||||
 
 | 
			
		||||
@@ -121,7 +121,7 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(usr))
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync("Please provide an account name.");
 | 
			
		||||
                await Response().Error("Please provide an account name.").SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -135,9 +135,9 @@ public partial class Searches
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create().WithDescription(GetText(strs.account_not_found)).WithErrorColor();
 | 
			
		||||
                var embed = new EmbedBuilder().WithDescription(GetText(strs.account_not_found)).WithErrorColor();
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -147,7 +147,7 @@ public partial class Searches
 | 
			
		||||
            await ctx.SendPaginatedConfirmAsync(page,
 | 
			
		||||
                curPage =>
 | 
			
		||||
                {
 | 
			
		||||
                    var embed = _eb.Create()
 | 
			
		||||
                    var embed = new EmbedBuilder()
 | 
			
		||||
                                   .WithAuthor($"Characters on {usr}'s account",
 | 
			
		||||
                                       "https://web.poecdn.com/image/favicon/ogimage.png",
 | 
			
		||||
                                       $"{PROFILE_URL}{usr}")
 | 
			
		||||
@@ -190,13 +190,13 @@ public partial class Searches
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                var eembed = _eb.Create().WithDescription(GetText(strs.leagues_not_found)).WithErrorColor();
 | 
			
		||||
                var eembed = new EmbedBuilder().WithDescription(GetText(strs.leagues_not_found)).WithErrorColor();
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(eembed);
 | 
			
		||||
                await Response().Embed(eembed).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithAuthor("Path of Exile Leagues",
 | 
			
		||||
                               "https://web.poecdn.com/image/favicon/ogimage.png",
 | 
			
		||||
                               "https://www.pathofexile.com")
 | 
			
		||||
@@ -215,7 +215,7 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            embed.WithDescription(sb.ToString());
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -226,13 +226,13 @@ public partial class Searches
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(leagueName))
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync("Please provide league name.");
 | 
			
		||||
                await Response().Error("Please provide league name.").SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(currencyName))
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync("Please provide currency name.");
 | 
			
		||||
                await Response().Error("Please provide currency name.").SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -273,7 +273,7 @@ public partial class Searches
 | 
			
		||||
                        CultureInfo.InvariantCulture);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithAuthor($"{leagueName} Currency Exchange",
 | 
			
		||||
                                   "https://web.poecdn.com/image/favicon/ogimage.png",
 | 
			
		||||
                                   "http://poe.ninja")
 | 
			
		||||
@@ -281,13 +281,13 @@ public partial class Searches
 | 
			
		||||
                               .AddField($"{cleanConvert} Equivalent", chaosEquivalent / conversionEquivalent, true)
 | 
			
		||||
                               .WithOkColor();
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create().WithDescription(GetText(strs.ninja_not_found)).WithErrorColor();
 | 
			
		||||
                var embed = new EmbedBuilder().WithDescription(GetText(strs.ninja_not_found)).WithErrorColor();
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ public partial class Searches
 | 
			
		||||
                if (kvp.Key.ToUpperInvariant() == pokemon.ToUpperInvariant())
 | 
			
		||||
                {
 | 
			
		||||
                    var p = kvp.Value;
 | 
			
		||||
                    await EmbedAsync(_eb.Create()
 | 
			
		||||
                    await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                                    .WithOkColor()
 | 
			
		||||
                                                    .WithTitle(kvp.Key.ToTitleCase())
 | 
			
		||||
                                                    .WithDescription(p.BaseStats.ToString())
 | 
			
		||||
@@ -37,12 +37,12 @@ public partial class Searches
 | 
			
		||||
                                                        true)
 | 
			
		||||
                                                    .AddField(GetText(strs.abilities),
 | 
			
		||||
                                                        string.Join("\n", p.Abilities.Select(a => a.Value)),
 | 
			
		||||
                                                        true));
 | 
			
		||||
                                                        true)).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.pokemon_none);
 | 
			
		||||
            await Response().Error(strs.pokemon_none).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -55,7 +55,7 @@ public partial class Searches
 | 
			
		||||
            {
 | 
			
		||||
                if (kvp.Key.ToUpperInvariant() == ability)
 | 
			
		||||
                {
 | 
			
		||||
                    await EmbedAsync(_eb.Create()
 | 
			
		||||
                    await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                                    .WithOkColor()
 | 
			
		||||
                                                    .WithTitle(kvp.Value.Name)
 | 
			
		||||
                                                    .WithDescription(string.IsNullOrWhiteSpace(kvp.Value.Desc)
 | 
			
		||||
@@ -63,12 +63,12 @@ public partial class Searches
 | 
			
		||||
                                                        : kvp.Value.Desc)
 | 
			
		||||
                                                    .AddField(GetText(strs.rating),
 | 
			
		||||
                                                        kvp.Value.Rating.ToString(Culture),
 | 
			
		||||
                                                        true));
 | 
			
		||||
                                                        true)).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.pokemon_ability_none);
 | 
			
		||||
            await Response().Error(strs.pokemon_ability_none).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -24,7 +24,7 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
            {
 | 
			
		||||
                await ErrorLocalizedAsync(strs.specify_search_params);
 | 
			
		||||
                await Response().Error(strs.specify_search_params).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -35,7 +35,7 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (data is null or { Entries: null or { Count: 0 } })
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.no_results);
 | 
			
		||||
                await Response().Error(strs.no_results).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -59,7 +59,7 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            descStr = descStr.TrimTo(4096);
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithAuthor(ctx.User)
 | 
			
		||||
                           .WithTitle(query.TrimTo(64)!)
 | 
			
		||||
@@ -68,7 +68,7 @@ public partial class Searches
 | 
			
		||||
                               GetText(strs.results_in(data.Info.TotalResults, data.Info.SearchTime)),
 | 
			
		||||
                               "https://i.imgur.com/G46fm8J.png");
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -78,7 +78,7 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
            {
 | 
			
		||||
                await ErrorLocalizedAsync(strs.specify_search_params);
 | 
			
		||||
                await Response().Error(strs.specify_search_params).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -89,16 +89,16 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (data is null or { Entries: null or { Count: 0 } })
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.no_search_results);
 | 
			
		||||
                await Response().Error(strs.no_search_results).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embeds = new List<IEmbedBuilder>(4);
 | 
			
		||||
            var embeds = new List<EmbedBuilder>(4);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            IEmbedBuilder CreateEmbed(IImageSearchResultEntry entry)
 | 
			
		||||
            EmbedBuilder CreateEmbed(IImageSearchResultEntry entry)
 | 
			
		||||
            {
 | 
			
		||||
                return _eb.Create(ctx)
 | 
			
		||||
                return new EmbedBuilder()
 | 
			
		||||
                          .WithOkColor()
 | 
			
		||||
                          .WithAuthor(ctx.User)
 | 
			
		||||
                          .WithTitle(query)
 | 
			
		||||
@@ -121,7 +121,7 @@ public partial class Searches
 | 
			
		||||
                embeds.Add(CreateEmbed(entry));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(null, embeds: embeds);
 | 
			
		||||
            await Response().Embeds(embeds).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private TypedKey<string> GetYtCacheKey(string query)
 | 
			
		||||
@@ -150,7 +150,7 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
            {
 | 
			
		||||
                await ErrorLocalizedAsync(strs.specify_search_params);
 | 
			
		||||
                await Response().Error(strs.specify_search_params).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -160,7 +160,7 @@ public partial class Searches
 | 
			
		||||
                              ?? await _searchFactory.GetYoutubeSearchService().SearchAsync(query);
 | 
			
		||||
            if (maybeResult is not {} result || result is {Url: null})
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.no_results);
 | 
			
		||||
                await Response().Error(strs.no_results).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -180,7 +180,7 @@ public partial class Searches
 | 
			
		||||
//         var data = await _service.DuckDuckGoSearchAsync(query);
 | 
			
		||||
//         if (data is null)
 | 
			
		||||
//         {
 | 
			
		||||
//             await ReplyErrorLocalizedAsync(strs.no_results);
 | 
			
		||||
//             await Response().Error(strs.no_results).SendAsync();
 | 
			
		||||
//             return;
 | 
			
		||||
//         }
 | 
			
		||||
//
 | 
			
		||||
@@ -190,13 +190,13 @@ public partial class Searches
 | 
			
		||||
//
 | 
			
		||||
//         var descStr = string.Join("\n\n", desc);
 | 
			
		||||
//
 | 
			
		||||
//         var embed = _eb.Create()
 | 
			
		||||
//         var embed = new EmbedBuilder()
 | 
			
		||||
//                        .WithAuthor(ctx.User.ToString(),
 | 
			
		||||
//                            "https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png")
 | 
			
		||||
//                        .WithDescription($"{GetText(strs.search_for)} **{query}**\n\n" + descStr)
 | 
			
		||||
//                        .WithOkColor();
 | 
			
		||||
//
 | 
			
		||||
//         await EmbedAsync(embed);
 | 
			
		||||
//         await Response().Embed(embed).SendAsync();
 | 
			
		||||
//     }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -54,7 +54,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
        if (!await ValidateQuery(query))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create();
 | 
			
		||||
        var embed = new EmbedBuilder();
 | 
			
		||||
        var data = await _service.GetWeatherDataAsync(query);
 | 
			
		||||
 | 
			
		||||
        if (data is null)
 | 
			
		||||
@@ -93,7 +93,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
                    $"https://openweathermap.org/img/w/{data.Weather[0].Icon}.png");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(embed);
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -124,22 +124,22 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyErrorLocalizedAsync(errorKey);
 | 
			
		||||
            await Response().Error(errorKey).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(data.TimeZoneName))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.timezone_db_api_key);
 | 
			
		||||
            await Response().Error(strs.timezone_db_api_key).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var eb = _eb.Create()
 | 
			
		||||
            .WithOkColor()
 | 
			
		||||
            .WithTitle(GetText(strs.time_new))
 | 
			
		||||
            .WithDescription(Format.Code(data.Time.ToString(Culture)))
 | 
			
		||||
            .AddField(GetText(strs.location), string.Join('\n', data.Address.Split(", ")), true)
 | 
			
		||||
            .AddField(GetText(strs.timezone), data.TimeZoneName, true);
 | 
			
		||||
        var eb = new EmbedBuilder()
 | 
			
		||||
                 .WithOkColor()
 | 
			
		||||
                 .WithTitle(GetText(strs.time_new))
 | 
			
		||||
                 .WithDescription(Format.Code(data.Time.ToString(Culture)))
 | 
			
		||||
                 .AddField(GetText(strs.location), string.Join('\n', data.Address.Split(", ")), true)
 | 
			
		||||
                 .AddField(GetText(strs.timezone), data.TimeZoneName, true);
 | 
			
		||||
 | 
			
		||||
        await ctx.Channel.SendMessageAsync(embed: eb.Build());
 | 
			
		||||
    }
 | 
			
		||||
@@ -155,19 +155,21 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
        var movie = await _service.GetMovieDataAsync(query);
 | 
			
		||||
        if (movie is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.imdb_fail);
 | 
			
		||||
            await Response().Error(strs.imdb_fail).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(_eb.Create()
 | 
			
		||||
            .WithOkColor()
 | 
			
		||||
            .WithTitle(movie.Title)
 | 
			
		||||
            .WithUrl($"https://www.imdb.com/title/{movie.ImdbId}/")
 | 
			
		||||
            .WithDescription(movie.Plot.TrimTo(1000))
 | 
			
		||||
            .AddField("Rating", movie.ImdbRating, true)
 | 
			
		||||
            .AddField("Genre", movie.Genre, true)
 | 
			
		||||
            .AddField("Year", movie.Year, true)
 | 
			
		||||
            .WithImageUrl(movie.Poster));
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Embed(new EmbedBuilder()
 | 
			
		||||
                     .WithOkColor()
 | 
			
		||||
                     .WithTitle(movie.Title)
 | 
			
		||||
                     .WithUrl($"https://www.imdb.com/title/{movie.ImdbId}/")
 | 
			
		||||
                     .WithDescription(movie.Plot.TrimTo(1000))
 | 
			
		||||
                     .AddField("Rating", movie.ImdbRating, true)
 | 
			
		||||
                     .AddField("Genre", movie.Genre, true)
 | 
			
		||||
                     .AddField("Year", movie.Year, true)
 | 
			
		||||
                     .WithImageUrl(movie.Poster))
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -189,7 +191,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
    private Task InternalRandomImage(SearchesService.ImageTag tag)
 | 
			
		||||
    {
 | 
			
		||||
        var url = _service.GetRandomImageUrl(tag);
 | 
			
		||||
        return EmbedAsync(_eb.Create().WithOkColor().WithImageUrl(url));
 | 
			
		||||
        return Response().Embed(new EmbedBuilder().WithOkColor().WithImageUrl(url)).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -199,7 +201,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var shortenedUrl = await _google.ShortenUrl($"https://letmegooglethat.com/?q={Uri.EscapeDataString(ffs)}");
 | 
			
		||||
        await SendConfirmAsync($"<{shortenedUrl}>");
 | 
			
		||||
        await Response().Confirm($"<{shortenedUrl}>").SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -239,10 +241,12 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(_eb.Create()
 | 
			
		||||
            .WithOkColor()
 | 
			
		||||
            .AddField(GetText(strs.original_url), $"<{query}>")
 | 
			
		||||
            .AddField(GetText(strs.short_url), $"<{shortLink}>"));
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Embed(new EmbedBuilder()
 | 
			
		||||
                     .WithOkColor()
 | 
			
		||||
                     .AddField(GetText(strs.original_url), $"<{query}>")
 | 
			
		||||
                     .AddField(GetText(strs.short_url), $"<{shortLink}>"))
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -256,20 +260,20 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
 | 
			
		||||
        if (card is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.card_not_found);
 | 
			
		||||
            await Response().Error(strs.card_not_found).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
            .WithOkColor()
 | 
			
		||||
            .WithTitle(card.Name)
 | 
			
		||||
            .WithDescription(card.Description)
 | 
			
		||||
            .WithImageUrl(card.ImageUrl)
 | 
			
		||||
            .AddField(GetText(strs.store_url), card.StoreUrl, true)
 | 
			
		||||
            .AddField(GetText(strs.cost), card.ManaCost, true)
 | 
			
		||||
            .AddField(GetText(strs.types), card.Types, true);
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
                    .WithOkColor()
 | 
			
		||||
                    .WithTitle(card.Name)
 | 
			
		||||
                    .WithDescription(card.Description)
 | 
			
		||||
                    .WithImageUrl(card.ImageUrl)
 | 
			
		||||
                    .AddField(GetText(strs.store_url), card.StoreUrl, true)
 | 
			
		||||
                    .AddField(GetText(strs.cost), card.ManaCost, true)
 | 
			
		||||
                    .AddField(GetText(strs.types), card.Types, true);
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(embed);
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -280,7 +284,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(_creds.RapidApiKey))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.mashape_api_missing);
 | 
			
		||||
            await Response().Error(strs.mashape_api_missing).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -289,16 +293,16 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
 | 
			
		||||
        if (card is null)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.card_not_found);
 | 
			
		||||
            await Response().Error(strs.card_not_found).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var embed = _eb.Create().WithOkColor().WithImageUrl(card.Img);
 | 
			
		||||
        var embed = new EmbedBuilder().WithOkColor().WithImageUrl(card.Img);
 | 
			
		||||
 | 
			
		||||
        if (!string.IsNullOrWhiteSpace(card.Flavor))
 | 
			
		||||
            embed.WithDescription(card.Flavor);
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(embed);
 | 
			
		||||
        await Response().Embed(embed).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -321,11 +325,11 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
                        p =>
 | 
			
		||||
                        {
 | 
			
		||||
                            var item = items[p];
 | 
			
		||||
                            return _eb.Create()
 | 
			
		||||
                                .WithOkColor()
 | 
			
		||||
                                .WithUrl(item.Permalink)
 | 
			
		||||
                                .WithTitle(item.Word)
 | 
			
		||||
                                .WithDescription(item.Definition);
 | 
			
		||||
                            return new EmbedBuilder()
 | 
			
		||||
                                   .WithOkColor()
 | 
			
		||||
                                   .WithUrl(item.Permalink)
 | 
			
		||||
                                   .WithTitle(item.Word)
 | 
			
		||||
                                   .WithDescription(item.Definition);
 | 
			
		||||
                        },
 | 
			
		||||
                        items.Length,
 | 
			
		||||
                        1);
 | 
			
		||||
@@ -337,7 +341,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await ReplyErrorLocalizedAsync(strs.ud_error);
 | 
			
		||||
        await Response().Error(strs.ud_error).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -361,28 +365,28 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
            var data = JsonConvert.DeserializeObject<DefineModel>(res);
 | 
			
		||||
 | 
			
		||||
            var datas = data.Results
 | 
			
		||||
                .Where(x => x.Senses is not null
 | 
			
		||||
                            && x.Senses.Count > 0
 | 
			
		||||
                            && x.Senses[0].Definition is not null)
 | 
			
		||||
                .Select(x => (Sense: x.Senses[0], x.PartOfSpeech))
 | 
			
		||||
                .ToList();
 | 
			
		||||
                            .Where(x => x.Senses is not null
 | 
			
		||||
                                        && x.Senses.Count > 0
 | 
			
		||||
                                        && x.Senses[0].Definition is not null)
 | 
			
		||||
                            .Select(x => (Sense: x.Senses[0], x.PartOfSpeech))
 | 
			
		||||
                            .ToList();
 | 
			
		||||
 | 
			
		||||
            if (!datas.Any())
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning("Definition not found: {Word}", word);
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.define_unknown);
 | 
			
		||||
                await Response().Error(strs.define_unknown).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var col = datas.Select(x => (
 | 
			
		||||
                    Definition: x.Sense.Definition is string
 | 
			
		||||
                        ? x.Sense.Definition.ToString()
 | 
			
		||||
                        : ((JArray)JToken.Parse(x.Sense.Definition.ToString())).First.ToString(),
 | 
			
		||||
                    Example: x.Sense.Examples is null || x.Sense.Examples.Count == 0
 | 
			
		||||
                        ? string.Empty
 | 
			
		||||
                        : x.Sense.Examples[0].Text, Word: word,
 | 
			
		||||
                    WordType: string.IsNullOrWhiteSpace(x.PartOfSpeech) ? "-" : x.PartOfSpeech))
 | 
			
		||||
                .ToList();
 | 
			
		||||
                               Definition: x.Sense.Definition is string
 | 
			
		||||
                                   ? x.Sense.Definition.ToString()
 | 
			
		||||
                                   : ((JArray)JToken.Parse(x.Sense.Definition.ToString())).First.ToString(),
 | 
			
		||||
                               Example: x.Sense.Examples is null || x.Sense.Examples.Count == 0
 | 
			
		||||
                                   ? string.Empty
 | 
			
		||||
                                   : x.Sense.Examples[0].Text, Word: word,
 | 
			
		||||
                               WordType: string.IsNullOrWhiteSpace(x.PartOfSpeech) ? "-" : x.PartOfSpeech))
 | 
			
		||||
                           .ToList();
 | 
			
		||||
 | 
			
		||||
            Log.Information("Sending {Count} definition for: {Word}", col.Count, word);
 | 
			
		||||
 | 
			
		||||
@@ -390,12 +394,12 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
                page =>
 | 
			
		||||
                {
 | 
			
		||||
                    var model = col.Skip(page).First();
 | 
			
		||||
                    var embed = _eb.Create()
 | 
			
		||||
                        .WithDescription(ctx.User.Mention)
 | 
			
		||||
                        .AddField(GetText(strs.word), model.Word, true)
 | 
			
		||||
                        .AddField(GetText(strs._class), model.WordType, true)
 | 
			
		||||
                        .AddField(GetText(strs.definition), model.Definition)
 | 
			
		||||
                        .WithOkColor();
 | 
			
		||||
                    var embed = new EmbedBuilder()
 | 
			
		||||
                                .WithDescription(ctx.User.Mention)
 | 
			
		||||
                                .AddField(GetText(strs.word), model.Word, true)
 | 
			
		||||
                                .AddField(GetText(strs._class), model.WordType, true)
 | 
			
		||||
                                .AddField(GetText(strs.definition), model.Definition)
 | 
			
		||||
                                .WithOkColor();
 | 
			
		||||
 | 
			
		||||
                    if (!string.IsNullOrWhiteSpace(model.Example))
 | 
			
		||||
                        embed.AddField(GetText(strs.example), model.Example);
 | 
			
		||||
@@ -418,7 +422,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
        var response = await http.GetStringAsync("https://catfact.ninja/fact");
 | 
			
		||||
 | 
			
		||||
        var fact = JObject.Parse(response)["fact"].ToString();
 | 
			
		||||
        await SendConfirmAsync("🐈" + GetText(strs.catfact), fact);
 | 
			
		||||
        await Response().Confirm("🐈" + GetText(strs.catfact), fact).SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -435,7 +439,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
            + Uri.EscapeDataString(query));
 | 
			
		||||
        var data = JsonConvert.DeserializeObject<WikipediaApiModel>(result);
 | 
			
		||||
        if (data.Query.Pages[0].Missing || string.IsNullOrWhiteSpace(data.Query.Pages[0].FullUrl))
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.wiki_page_not_found);
 | 
			
		||||
            await Response().Error(strs.wiki_page_not_found).SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
            await ctx.Channel.SendMessageAsync(data.Query.Pages[0].FullUrl);
 | 
			
		||||
    }
 | 
			
		||||
@@ -468,13 +472,14 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
 | 
			
		||||
        var avatarUrl = usr.RealAvatarUrl(2048);
 | 
			
		||||
 | 
			
		||||
        await EmbedAsync(
 | 
			
		||||
            _eb.Create()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .AddField("Username", usr.ToString())
 | 
			
		||||
                .AddField("Avatar Url", avatarUrl)
 | 
			
		||||
                .WithThumbnailUrl(avatarUrl.ToString()),
 | 
			
		||||
            ctx.User.Mention);
 | 
			
		||||
        await Response()
 | 
			
		||||
              .Embed(
 | 
			
		||||
                  new EmbedBuilder()
 | 
			
		||||
                      .WithOkColor()
 | 
			
		||||
                      .AddField("Username", usr.ToString())
 | 
			
		||||
                      .AddField("Avatar Url", avatarUrl)
 | 
			
		||||
                      .WithThumbnailUrl(avatarUrl.ToString()))
 | 
			
		||||
              .SendAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -482,7 +487,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
    {
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(target) || string.IsNullOrWhiteSpace(query))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.wikia_input_error);
 | 
			
		||||
            await Response().Error(strs.wikia_input_error).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -502,7 +507,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(title))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.wikia_error);
 | 
			
		||||
                await Response().Error(strs.wikia_error).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -513,7 +518,7 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
        }
 | 
			
		||||
        catch
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.wikia_error);
 | 
			
		||||
            await Response().Error(strs.wikia_error).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -532,14 +537,16 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (obj.Error is not null || obj.Verses is null || obj.Verses.Length == 0)
 | 
			
		||||
            await SendErrorAsync(obj.Error ?? "No verse found.");
 | 
			
		||||
            await Response().Error(obj.Error ?? "No verse found.").SendAsync();
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            var v = obj.Verses[0];
 | 
			
		||||
            await EmbedAsync(_eb.Create()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithTitle($"{v.BookName} {v.Chapter}:{v.Verse}")
 | 
			
		||||
                .WithDescription(v.Text));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Embed(new EmbedBuilder()
 | 
			
		||||
                         .WithOkColor()
 | 
			
		||||
                         .WithTitle($"{v.BookName} {v.Chapter}:{v.Verse}")
 | 
			
		||||
                         .WithDescription(v.Text))
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -554,11 +561,11 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
        var appId = await _service.GetSteamAppIdByName(query);
 | 
			
		||||
        if (appId == -1)
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_found);
 | 
			
		||||
            await Response().Error(strs.not_found).SendAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //var embed = _eb.Create()
 | 
			
		||||
        //var embed = new EmbedBuilder()
 | 
			
		||||
        //    .WithOkColor()
 | 
			
		||||
        //    .WithDescription(gameData.ShortDescription)
 | 
			
		||||
        //    .WithTitle(gameData.Name)
 | 
			
		||||
@@ -576,12 +583,13 @@ public partial class Searches : NadekoModule<SearchesService>
 | 
			
		||||
        if (!string.IsNullOrWhiteSpace(query))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        await ErrorLocalizedAsync(strs.specify_search_params);
 | 
			
		||||
        await Response().Error(strs.specify_search_params).SendAsync();
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class ShortenData
 | 
			
		||||
    {
 | 
			
		||||
        [JsonProperty("result_url")] public string ResultUrl { get; set; }
 | 
			
		||||
        [JsonProperty("result_url")]
 | 
			
		||||
        public string ResultUrl { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -24,12 +24,15 @@ public partial class Searches
 | 
			
		||||
            var data = await _service.FollowStream(ctx.Guild.Id, ctx.Channel.Id, link);
 | 
			
		||||
            if (data is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.stream_not_added);
 | 
			
		||||
                await Response().Error(strs.stream_not_added).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embed = _service.GetEmbed(ctx.Guild.Id, data);
 | 
			
		||||
            await EmbedAsync(embed, GetText(strs.stream_tracked));
 | 
			
		||||
            await Response()
 | 
			
		||||
                  .Embed(embed)
 | 
			
		||||
                  .Text(strs.stream_tracked)
 | 
			
		||||
                  .SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -44,11 +47,11 @@ public partial class Searches
 | 
			
		||||
            var fs = await _service.UnfollowStreamAsync(ctx.Guild.Id, index);
 | 
			
		||||
            if (fs is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.stream_no);
 | 
			
		||||
                await Response().Error(strs.stream_no).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.stream_removed(Format.Bold(fs.Username), fs.Type));
 | 
			
		||||
            await Response().Confirm(strs.stream_removed(Format.Bold(fs.Username), fs.Type)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -57,7 +60,7 @@ public partial class Searches
 | 
			
		||||
        public async Task StreamsClear()
 | 
			
		||||
        {
 | 
			
		||||
            await _service.ClearAllStreams(ctx.Guild.Id);
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.streams_cleared);
 | 
			
		||||
            await Response().Confirm(strs.streams_cleared).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -93,9 +96,9 @@ public partial class Searches
 | 
			
		||||
                                   .ToList();
 | 
			
		||||
 | 
			
		||||
                    if (elements.Count == 0)
 | 
			
		||||
                        return _eb.Create().WithDescription(GetText(strs.streams_none)).WithErrorColor();
 | 
			
		||||
                        return new EmbedBuilder().WithDescription(GetText(strs.streams_none)).WithErrorColor();
 | 
			
		||||
 | 
			
		||||
                    var eb = _eb.Create().WithTitle(GetText(strs.streams_follow_title)).WithOkColor();
 | 
			
		||||
                    var eb = new EmbedBuilder().WithTitle(GetText(strs.streams_follow_title)).WithOkColor();
 | 
			
		||||
                    for (var index = 0; index < elements.Count; index++)
 | 
			
		||||
                    {
 | 
			
		||||
                        var elem = elements[index];
 | 
			
		||||
@@ -117,11 +120,11 @@ public partial class Searches
 | 
			
		||||
        {
 | 
			
		||||
            var newValue = _service.ToggleStreamOffline(ctx.Guild.Id);
 | 
			
		||||
            if (newValue)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_off_enabled);
 | 
			
		||||
                await Response().Confirm(strs.stream_off_enabled).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_off_disabled);
 | 
			
		||||
                await Response().Confirm(strs.stream_off_disabled).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [UserPerm(GuildPerm.ManageMessages)]
 | 
			
		||||
@@ -129,9 +132,9 @@ public partial class Searches
 | 
			
		||||
        {
 | 
			
		||||
            var newValue = _service.ToggleStreamOnlineDelete(ctx.Guild.Id);
 | 
			
		||||
            if (newValue)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_online_delete_enabled);
 | 
			
		||||
                await Response().Confirm(strs.stream_online_delete_enabled).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_online_delete_disabled);
 | 
			
		||||
                await Response().Confirm(strs.stream_online_delete_disabled).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -144,14 +147,14 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (!_service.SetStreamMessage(ctx.Guild.Id, index, message, out var fs))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_not_following);
 | 
			
		||||
                await Response().Confirm(strs.stream_not_following).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(message))
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_message_reset(Format.Bold(fs.Username)));
 | 
			
		||||
                await Response().Confirm(strs.stream_message_reset(Format.Bold(fs.Username))).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_message_set(Format.Bold(fs.Username)));
 | 
			
		||||
                await Response().Confirm(strs.stream_message_set(Format.Bold(fs.Username))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -163,11 +166,11 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (count == 0)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_not_following_any);
 | 
			
		||||
                await Response().Confirm(strs.stream_not_following_any).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.stream_message_set_all(count));
 | 
			
		||||
            await Response().Confirm(strs.stream_message_set_all(count)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -179,21 +182,23 @@ public partial class Searches
 | 
			
		||||
                var data = await _service.GetStreamDataAsync(url);
 | 
			
		||||
                if (data is null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.no_channel_found);
 | 
			
		||||
                    await Response().Error(strs.no_channel_found).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (data.IsLive)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.streamer_online(Format.Bold(data.Name),
 | 
			
		||||
                        Format.Bold(data.Viewers.ToString())));
 | 
			
		||||
                    await Response()
 | 
			
		||||
                          .Confirm(strs.streamer_online(Format.Bold(data.Name),
 | 
			
		||||
                              Format.Bold(data.Viewers.ToString())))
 | 
			
		||||
                          .SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.streamer_offline(data.Name));
 | 
			
		||||
                    await Response().Confirm(strs.streamer_offline(data.Name)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.no_channel_found);
 | 
			
		||||
                await Response().Error(strs.no_channel_found).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -479,9 +479,9 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
 | 
			
		||||
        return data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IEmbedBuilder GetEmbed(ulong guildId, StreamData status, bool showViewers = true)
 | 
			
		||||
    public EmbedBuilder GetEmbed(ulong guildId, StreamData status, bool showViewers = true)
 | 
			
		||||
    {
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
        var embed = new EmbedBuilder()
 | 
			
		||||
            .WithTitle(status.Name)
 | 
			
		||||
            .WithUrl(status.StreamUrl)
 | 
			
		||||
            .WithDescription(status.StreamUrl)
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ public sealed class TranslateService : ITranslateService, IExecNoCommand, IReady
 | 
			
		||||
                || msg.Content.Equals(output, StringComparison.InvariantCultureIgnoreCase))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create().WithOkColor();
 | 
			
		||||
            var embed = new EmbedBuilder().WithOkColor();
 | 
			
		||||
 | 
			
		||||
            if (autoDelete)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,13 +20,13 @@ public partial class Searches
 | 
			
		||||
                await ctx.Channel.TriggerTypingAsync();
 | 
			
		||||
                var translation = await _service.Translate(from, to, text);
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create(ctx).WithOkColor().AddField(from, text).AddField(to, translation);
 | 
			
		||||
                var embed = new EmbedBuilder().WithOkColor().AddField(from, text).AddField(to, translation);
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.bad_input_format);
 | 
			
		||||
                await Response().Error(strs.bad_input_format).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -40,9 +40,9 @@ public partial class Searches
 | 
			
		||||
            var toggle =
 | 
			
		||||
                await _service.ToggleAtl(ctx.Guild.Id, ctx.Channel.Id, autoDelete == AutoDeleteAutoTranslate.Del);
 | 
			
		||||
            if (toggle)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.atl_started);
 | 
			
		||||
                await Response().Confirm(strs.atl_started).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.atl_stopped);
 | 
			
		||||
                await Response().Confirm(strs.atl_stopped).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -50,7 +50,7 @@ public partial class Searches
 | 
			
		||||
        public async Task AutoTransLang()
 | 
			
		||||
        {
 | 
			
		||||
            if (await _service.UnregisterUser(ctx.Channel.Id, ctx.User.Id))
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.atl_removed);
 | 
			
		||||
                await Response().Confirm(strs.atl_removed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -61,17 +61,17 @@ public partial class Searches
 | 
			
		||||
 | 
			
		||||
            if (succ is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.atl_not_enabled);
 | 
			
		||||
                await Response().Error(strs.atl_not_enabled).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (succ is false)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.invalid_lang);
 | 
			
		||||
                await Response().Error(strs.invalid_lang).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.atl_set(from, to));
 | 
			
		||||
            await Response().Confirm(strs.atl_set(from, to)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -80,16 +80,16 @@ public partial class Searches
 | 
			
		||||
        {
 | 
			
		||||
            var langs = _service.GetLanguages().ToList();
 | 
			
		||||
            
 | 
			
		||||
            var eb = _eb.Create()
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                        .WithTitle(GetText(strs.supported_languages))
 | 
			
		||||
                        .WithOkColor();
 | 
			
		||||
 | 
			
		||||
            foreach (var chunk in langs.Chunk(15))
 | 
			
		||||
            {
 | 
			
		||||
                eb.AddField("", chunk.Join("\n"), isInline: true);
 | 
			
		||||
                eb.AddField("", chunk.Join("\n"), inline: true);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(eb);
 | 
			
		||||
            await Response().Embed(eb).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -25,13 +25,13 @@ public partial class Searches
 | 
			
		||||
                    using var http = _httpFactory.CreateClient();
 | 
			
		||||
                    var res = await http.GetStringAsync($"{XKCD_URL}/info.0.json");
 | 
			
		||||
                    var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
 | 
			
		||||
                    var embed = _eb.Create()
 | 
			
		||||
                    var embed = new EmbedBuilder()
 | 
			
		||||
                                   .WithOkColor()
 | 
			
		||||
                                   .WithImageUrl(comic.ImageLink)
 | 
			
		||||
                                   .WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{XKCD_URL}/{comic.Num}")
 | 
			
		||||
                                   .AddField(GetText(strs.comic_number), comic.Num.ToString(), true)
 | 
			
		||||
                                   .AddField(GetText(strs.date), $"{comic.Month}/{comic.Year}", true);
 | 
			
		||||
                    var sent = await EmbedAsync(embed);
 | 
			
		||||
                    var sent = await Response().Embed(embed).SendAsync();
 | 
			
		||||
 | 
			
		||||
                    await Task.Delay(10000);
 | 
			
		||||
 | 
			
		||||
@@ -39,7 +39,7 @@ public partial class Searches
 | 
			
		||||
                }
 | 
			
		||||
                catch (HttpRequestException)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.comic_not_found);
 | 
			
		||||
                    await Response().Error(strs.comic_not_found).SendAsync();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
@@ -60,14 +60,14 @@ public partial class Searches
 | 
			
		||||
                var res = await http.GetStringAsync($"{XKCD_URL}/{num}/info.0.json");
 | 
			
		||||
 | 
			
		||||
                var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithOkColor()
 | 
			
		||||
                               .WithImageUrl(comic.ImageLink)
 | 
			
		||||
                               .WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{XKCD_URL}/{num}")
 | 
			
		||||
                               .AddField(GetText(strs.comic_number), comic.Num.ToString(), true)
 | 
			
		||||
                               .AddField(GetText(strs.date), $"{comic.Month}/{comic.Year}", true);
 | 
			
		||||
 | 
			
		||||
                var sent = await EmbedAsync(embed);
 | 
			
		||||
                var sent = await Response().Embed(embed).SendAsync();
 | 
			
		||||
 | 
			
		||||
                await Task.Delay(10000);
 | 
			
		||||
 | 
			
		||||
@@ -75,7 +75,7 @@ public partial class Searches
 | 
			
		||||
            }
 | 
			
		||||
            catch (HttpRequestException)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.comic_not_found);
 | 
			
		||||
                await Response().Error(strs.comic_not_found).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,11 +13,11 @@ public partial class Searches
 | 
			
		||||
    //         var succ = await _service.ToggleChannelFollowAsync(ctx.Guild.Id, ctx.Channel.Id, ytChannelId, uploadMessage);
 | 
			
		||||
    //         if(succ)
 | 
			
		||||
    //         {
 | 
			
		||||
    //             await ReplyConfirmLocalizedAsync(strs.yt_follow_added);
 | 
			
		||||
    //             await Response().Confirm(strs.yt_follow_added).SendAsync();
 | 
			
		||||
    //         }
 | 
			
		||||
    //         else
 | 
			
		||||
    //         {
 | 
			
		||||
    //             await ReplyConfirmLocalizedAsync(strs.yt_follow_fail);
 | 
			
		||||
    //             await Response().Confirm(strs.yt_follow_fail).SendAsync();
 | 
			
		||||
    //         }
 | 
			
		||||
    //     }
 | 
			
		||||
    //     
 | 
			
		||||
@@ -28,11 +28,11 @@ public partial class Searches
 | 
			
		||||
    //         //var succ = await _service.ToggleChannelTrackingAsync(ctx.Guild.Id, ctx.Channel.Id, ytChannelId, uploadMessage);
 | 
			
		||||
    //         //if (succ)
 | 
			
		||||
    //         //{
 | 
			
		||||
    //         //    await ReplyConfirmLocalizedAsync(strs.yt_track_added);
 | 
			
		||||
    //         //    await Response().Confirm(strs.yt_track_added).SendAsync();
 | 
			
		||||
    //         //}
 | 
			
		||||
    //         //else
 | 
			
		||||
    //         //{
 | 
			
		||||
    //         //    await ReplyConfirmLocalizedAsync(strs.yt_track_fail);
 | 
			
		||||
    //         //    await Response().Confirm(strs.yt_track_fail).SendAsync();
 | 
			
		||||
    //         //}
 | 
			
		||||
    //     }
 | 
			
		||||
    //     
 | 
			
		||||
@@ -43,11 +43,11 @@ public partial class Searches
 | 
			
		||||
    //         //var succ = await _service.ToggleChannelTrackingAsync(ctx.Guild.Id, ctx.Channel.Id, ytChannelId, uploadMessage);
 | 
			
		||||
    //         //if (succ)
 | 
			
		||||
    //         //{
 | 
			
		||||
    //         //    await ReplyConfirmLocalizedAsync(strs.yt_track_added);
 | 
			
		||||
    //         //    await Response().Confirm(strs.yt_track_added).SendAsync();
 | 
			
		||||
    //         //}
 | 
			
		||||
    //         //else
 | 
			
		||||
    //         //{
 | 
			
		||||
    //         //    await ReplyConfirmLocalizedAsync(strs.yt_track_fail);
 | 
			
		||||
    //         //    await Response().Confirm(strs.yt_track_fail).SendAsync();
 | 
			
		||||
    //         //}
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ public partial class Utility
 | 
			
		||||
        public async Task AliasesClear()
 | 
			
		||||
        {
 | 
			
		||||
            var count = _service.ClearAliases(ctx.Guild.Id);
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.aliases_cleared(count));
 | 
			
		||||
            await Response().Confirm(strs.aliases_cleared(count)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -43,7 +43,7 @@ public partial class Utility
 | 
			
		||||
            {
 | 
			
		||||
                if (!_service.AliasMaps.TryGetValue(ctx.Guild.Id, out var maps) || !maps.TryRemove(trigger, out _))
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.alias_remove_fail(Format.Code(trigger)));
 | 
			
		||||
                    await Response().Error(strs.alias_remove_fail(Format.Code(trigger))).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -56,7 +56,7 @@ public partial class Utility
 | 
			
		||||
                    uow.SaveChanges();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.alias_removed(Format.Code(trigger)));
 | 
			
		||||
                await Response().Confirm(strs.alias_removed(Format.Code(trigger))).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -100,7 +100,7 @@ public partial class Utility
 | 
			
		||||
                    return map;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.alias_added(Format.Code(trigger), Format.Code(mapping)));
 | 
			
		||||
            await Response().Confirm(strs.alias_added(Format.Code(trigger), Format.Code(mapping))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -115,7 +115,7 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            if (!_service.AliasMaps.TryGetValue(ctx.Guild.Id, out var maps) || !maps.Any())
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.aliases_none);
 | 
			
		||||
                await Response().Error(strs.aliases_none).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -124,7 +124,7 @@ public partial class Utility
 | 
			
		||||
            await ctx.SendPaginatedConfirmAsync(page,
 | 
			
		||||
                curPage =>
 | 
			
		||||
                {
 | 
			
		||||
                    return _eb.Create()
 | 
			
		||||
                    return new EmbedBuilder()
 | 
			
		||||
                              .WithOkColor()
 | 
			
		||||
                              .WithTitle(GetText(strs.alias_list))
 | 
			
		||||
                              .WithDescription(string.Join("\n",
 | 
			
		||||
 
 | 
			
		||||
@@ -9,13 +9,16 @@ namespace NadekoBot.Modules.Utility.Services;
 | 
			
		||||
public class AliasService : IInputTransformer, INService
 | 
			
		||||
{
 | 
			
		||||
    public ConcurrentDictionary<ulong, ConcurrentDictionary<string, string>> AliasMaps { get; } = new();
 | 
			
		||||
    private readonly IEmbedBuilderService _eb;
 | 
			
		||||
 | 
			
		||||
    private readonly DbService _db;
 | 
			
		||||
    private readonly IMessageSenderService _sender;
 | 
			
		||||
 | 
			
		||||
    public AliasService(DiscordSocketClient client, DbService db, IEmbedBuilderService eb)
 | 
			
		||||
    public AliasService(
 | 
			
		||||
        DiscordSocketClient client,
 | 
			
		||||
        DbService db,
 | 
			
		||||
        IMessageSenderService sender)
 | 
			
		||||
    {
 | 
			
		||||
        _eb = eb;
 | 
			
		||||
        _sender = sender;
 | 
			
		||||
 | 
			
		||||
        using var uow = db.GetDbContext();
 | 
			
		||||
        var guildIds = client.Guilds.Select(x => x.Id).ToList();
 | 
			
		||||
@@ -53,7 +56,7 @@ public class AliasService : IInputTransformer, INService
 | 
			
		||||
    {
 | 
			
		||||
        if (guild is null || string.IsNullOrWhiteSpace(input))
 | 
			
		||||
            return null;
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        if (AliasMaps.TryGetValue(guild.Id, out var maps))
 | 
			
		||||
        {
 | 
			
		||||
            string newInput = null;
 | 
			
		||||
@@ -75,7 +78,9 @@ public class AliasService : IInputTransformer, INService
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        var toDelete = await channel.SendConfirmAsync(_eb, $"{input} => {newInput}");
 | 
			
		||||
                        var toDelete = await _sender.Response(channel)
 | 
			
		||||
                                                    .Confirm($"{input} => {newInput}")
 | 
			
		||||
                                                    .SendAsync();
 | 
			
		||||
                        toDelete.DeleteAfter(1.5f);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,9 @@ public partial class Utility
 | 
			
		||||
            expr.EvaluateParameter += Expr_EvaluateParameter;
 | 
			
		||||
            var result = expr.Evaluate();
 | 
			
		||||
            if (!expr.HasErrors())
 | 
			
		||||
                await SendConfirmAsync("⚙ " + GetText(strs.result), result.ToString());
 | 
			
		||||
                await Response().Confirm("⚙ " + GetText(strs.result), result.ToString()).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await SendErrorAsync("⚙ " + GetText(strs.error), expr.Error);
 | 
			
		||||
                await Response().Error("⚙ " + GetText(strs.error), expr.Error).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void Expr_EvaluateParameter(string name, ParameterArgs args)
 | 
			
		||||
@@ -42,7 +42,7 @@ public partial class Utility
 | 
			
		||||
                                        .DistinctBy(x => x.Name)
 | 
			
		||||
                                        .Select(x => x.Name)
 | 
			
		||||
                                        .Except(new[] { "ToString", "Equals", "GetHashCode", "GetType" });
 | 
			
		||||
            await SendConfirmAsync(GetText(strs.calcops(prefix)), string.Join(", ", selection));
 | 
			
		||||
            await Response().Confirm(GetText(strs.calcops(prefix)), string.Join(", ", selection)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -20,12 +20,12 @@ public partial class Utility
 | 
			
		||||
            if (setting is null)
 | 
			
		||||
            {
 | 
			
		||||
                var configNames = _settingServices.Select(x => x.Name);
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithErrorColor()
 | 
			
		||||
                               .WithDescription(GetText(strs.config_not_found(Format.Code(name))))
 | 
			
		||||
                               .AddField(GetText(strs.config_list), string.Join("\n", configNames));
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -43,12 +43,12 @@ public partial class Utility
 | 
			
		||||
            name = name?.ToLowerInvariant();
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(name))
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithOkColor()
 | 
			
		||||
                               .WithTitle(GetText(strs.config_list))
 | 
			
		||||
                               .WithDescription(string.Join("\n", configNames));
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -58,12 +58,12 @@ public partial class Utility
 | 
			
		||||
            // if config name is not found, print error and the list of configs
 | 
			
		||||
            if (setting is null)
 | 
			
		||||
            {
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithErrorColor()
 | 
			
		||||
                               .WithDescription(GetText(strs.config_not_found(Format.Code(name))))
 | 
			
		||||
                               .AddField(GetText(strs.config_list), string.Join("\n", configNames));
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -75,10 +75,10 @@ public partial class Utility
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(prop))
 | 
			
		||||
            {
 | 
			
		||||
                var propStrings = GetPropsAndValuesString(setting, propNames);
 | 
			
		||||
                var embed = _eb.Create().WithOkColor().WithTitle($"⚙️ {setting.Name}").WithDescription(propStrings);
 | 
			
		||||
                var embed = new EmbedBuilder().WithOkColor().WithTitle($"⚙️ {setting.Name}").WithDescription(propStrings);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            // if the prop is invalid -> print error and list of 
 | 
			
		||||
@@ -88,13 +88,13 @@ public partial class Utility
 | 
			
		||||
            if (!exists)
 | 
			
		||||
            {
 | 
			
		||||
                var propStrings = GetPropsAndValuesString(setting, propNames);
 | 
			
		||||
                var propErrorEmbed = _eb.Create()
 | 
			
		||||
                var propErrorEmbed = new EmbedBuilder()
 | 
			
		||||
                                        .WithErrorColor()
 | 
			
		||||
                                        .WithDescription(GetText(
 | 
			
		||||
                                            strs.config_prop_not_found(Format.Code(prop), Format.Code(name))))
 | 
			
		||||
                                        .AddField($"⚙️ {setting.Name}", propStrings);
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(propErrorEmbed);
 | 
			
		||||
                await Response().Embed(propErrorEmbed).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -110,7 +110,7 @@ public partial class Utility
 | 
			
		||||
                if (prop != "currency.sign")
 | 
			
		||||
                    value = Format.Code(Format.Sanitize(value.TrimTo(1000)), "json");
 | 
			
		||||
 | 
			
		||||
                var embed = _eb.Create()
 | 
			
		||||
                var embed = new EmbedBuilder()
 | 
			
		||||
                               .WithOkColor()
 | 
			
		||||
                               .AddField("Config", Format.Code(setting.Name), true)
 | 
			
		||||
                               .AddField("Prop", Format.Code(prop), true)
 | 
			
		||||
@@ -120,7 +120,7 @@ public partial class Utility
 | 
			
		||||
                if (!string.IsNullOrWhiteSpace(comment))
 | 
			
		||||
                    embed.AddField("Comment", comment);
 | 
			
		||||
 | 
			
		||||
                await EmbedAsync(embed);
 | 
			
		||||
                await Response().Embed(embed).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -128,7 +128,7 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            if (!success)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.config_edit_fail(Format.Code(prop), Format.Code(value)));
 | 
			
		||||
                await Response().Error(strs.config_edit_fail(Format.Code(prop), Format.Code(value))).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,16 +13,16 @@ public partial class Utility
 | 
			
		||||
        {
 | 
			
		||||
            if (duration > TimeSpan.FromDays(30))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.giveaway_duration_invalid);
 | 
			
		||||
                await Response().Error(strs.giveaway_duration_invalid).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                .WithPendingColor()
 | 
			
		||||
                .WithTitle(GetText(strs.giveaway_starting))
 | 
			
		||||
                .WithDescription(message);
 | 
			
		||||
 | 
			
		||||
            var startingMsg = await EmbedAsync(eb);
 | 
			
		||||
            var startingMsg = await Response().Embed(eb).SendAsync();
 | 
			
		||||
 | 
			
		||||
            var maybeId =
 | 
			
		||||
                await _service.StartGiveawayAsync(ctx.Guild.Id, ctx.Channel.Id, startingMsg.Id, duration, message);
 | 
			
		||||
@@ -31,7 +31,7 @@ public partial class Utility
 | 
			
		||||
            if (maybeId is not int id)
 | 
			
		||||
            {
 | 
			
		||||
                await startingMsg.DeleteAsync();
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.giveaway_max_amount_reached);
 | 
			
		||||
                await Response().Error(strs.giveaway_max_amount_reached).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -52,7 +52,7 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
           if(!success)
 | 
			
		||||
           {
 | 
			
		||||
               await ReplyErrorLocalizedAsync(strs.giveaway_not_found);
 | 
			
		||||
               await Response().Error(strs.giveaway_not_found).SendAsync();
 | 
			
		||||
               return;
 | 
			
		||||
           }
 | 
			
		||||
 | 
			
		||||
@@ -67,7 +67,7 @@ public partial class Utility
 | 
			
		||||
            var success = await _service.RerollGiveawayAsync(ctx.Guild.Id, id);
 | 
			
		||||
            if (!success)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.giveaway_not_found);
 | 
			
		||||
                await Response().Error(strs.giveaway_not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
@@ -84,11 +84,11 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            if (!success)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.giveaway_not_found);
 | 
			
		||||
                await Response().Confirm(strs.giveaway_not_found).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.giveaway_cancelled);
 | 
			
		||||
            await Response().Confirm(strs.giveaway_cancelled).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -99,11 +99,11 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            if (!giveaways.Any())
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.no_givaways);
 | 
			
		||||
                await Response().Error(strs.no_givaways).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                .WithTitle(GetText(strs.giveaway_list))
 | 
			
		||||
                .WithOkColor();
 | 
			
		||||
 | 
			
		||||
@@ -112,7 +112,7 @@ public partial class Utility
 | 
			
		||||
                eb.AddField($"id:  {new kwum(g.Id)}", g.Message, true);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(eb);
 | 
			
		||||
            await Response().Embed(eb).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -54,7 +54,7 @@ public partial class Utility
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(features))
 | 
			
		||||
                features = "-";
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithAuthor(GetText(strs.server_info))
 | 
			
		||||
                           .WithTitle(guild.Name)
 | 
			
		||||
                           .AddField(GetText(strs.id), guild.Id.ToString(), true)
 | 
			
		||||
@@ -75,7 +75,7 @@ public partial class Utility
 | 
			
		||||
                    string.Join(" ", guild.Emotes.Shuffle().Take(20).Select(e => $"{e.Name} {e}")).TrimTo(1020));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -87,14 +87,14 @@ public partial class Utility
 | 
			
		||||
                return;
 | 
			
		||||
            var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(ch.Id >> 22);
 | 
			
		||||
            var usercount = (await ch.GetUsersAsync().FlattenAsync()).Count();
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithTitle(ch.Name)
 | 
			
		||||
                           .WithDescription(ch.Topic?.SanitizeMentions(true))
 | 
			
		||||
                           .AddField(GetText(strs.id), ch.Id.ToString(), true)
 | 
			
		||||
                           .AddField(GetText(strs.created_at), $"{createdAt:dd.MM.yyyy HH:mm}", true)
 | 
			
		||||
                           .AddField(GetText(strs.users), usercount.ToString(), true)
 | 
			
		||||
                           .WithOkColor();
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -107,7 +107,7 @@ public partial class Utility
 | 
			
		||||
            var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)
 | 
			
		||||
                .AddMilliseconds(role.Id >> 22);
 | 
			
		||||
            var usercount = role.Members.LongCount();
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                .WithTitle(role.Name.TrimTo(128))
 | 
			
		||||
                .WithDescription(role.Permissions.ToList().Join(" | "))
 | 
			
		||||
                .AddField(GetText(strs.id), role.Id.ToString(), true)
 | 
			
		||||
@@ -121,7 +121,7 @@ public partial class Utility
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(role.GetIconUrl()))
 | 
			
		||||
                embed = embed.WithThumbnailUrl(role.GetIconUrl());
 | 
			
		||||
            
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -133,7 +133,7 @@ public partial class Utility
 | 
			
		||||
            if (user is null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create().AddField(GetText(strs.name), $"**{user.Username}**#{user.Discriminator}", true);
 | 
			
		||||
            var embed = new EmbedBuilder().AddField(GetText(strs.name), $"**{user.Username}**#{user.Discriminator}", true);
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(user.Nickname))
 | 
			
		||||
                embed.AddField(GetText(strs.nickname), user.Nickname, true);
 | 
			
		||||
 | 
			
		||||
@@ -165,7 +165,7 @@ public partial class Utility
 | 
			
		||||
            if (av.IsAbsoluteUri)
 | 
			
		||||
                embed.WithThumbnailUrl(av.ToString());
 | 
			
		||||
            
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private DateTimeOffset? GetJoinedAt(IGuildUser user)
 | 
			
		||||
@@ -204,12 +204,12 @@ public partial class Utility
 | 
			
		||||
                    kvp.Value)));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(_eb.Create()
 | 
			
		||||
            await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                                            .WithTitle(GetText(strs.activity_page(page + 1)))
 | 
			
		||||
                                            .WithOkColor()
 | 
			
		||||
                                            .WithFooter(GetText(
 | 
			
		||||
                                                strs.activity_users_total(_cmdHandler.UserMessagesSent.Count)))
 | 
			
		||||
                                            .WithDescription(str.ToString()));
 | 
			
		||||
                                            .WithDescription(str.ToString())).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -22,7 +22,7 @@ public partial class Utility
 | 
			
		||||
            var ch = (ITextChannel)ctx.Channel;
 | 
			
		||||
            var invite = await ch.CreateInviteAsync(opts.Expire, opts.MaxUses, opts.Temporary, opts.Unique);
 | 
			
		||||
 | 
			
		||||
            await SendConfirmAsync($"{ctx.User.Mention} https://discord.gg/{invite.Code}");
 | 
			
		||||
            await Response().Confirm($"{ctx.User.Mention} https://discord.gg/{invite.Code}").SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -44,9 +44,9 @@ public partial class Utility
 | 
			
		||||
                    var invs = invites.Skip(cur * 9).Take(9).ToList();
 | 
			
		||||
 | 
			
		||||
                    if (!invs.Any())
 | 
			
		||||
                        return _eb.Create().WithErrorColor().WithDescription(GetText(strs.no_invites));
 | 
			
		||||
                        return new EmbedBuilder().WithErrorColor().WithDescription(GetText(strs.no_invites));
 | 
			
		||||
 | 
			
		||||
                    var embed = _eb.Create().WithOkColor();
 | 
			
		||||
                    var embed = new EmbedBuilder().WithOkColor();
 | 
			
		||||
                    foreach (var inv in invites)
 | 
			
		||||
                    {
 | 
			
		||||
                        var expiryString = inv.MaxAge is null or 0 || inv.CreatedAt is null
 | 
			
		||||
 
 | 
			
		||||
@@ -14,24 +14,24 @@ public partial class Utility
 | 
			
		||||
    {
 | 
			
		||||
        private const string PREPEND_EXPORT =
 | 
			
		||||
            """
 | 
			
		||||
                # Keys are keywords, Each key has a LIST of quotes in the following format:
 | 
			
		||||
                # - id: Alphanumeric id used for commands related to the quote. (Note, when using .quotesimport, a new id will be generated.) 
 | 
			
		||||
                #   an: Author name 
 | 
			
		||||
                #   aid: Author id 
 | 
			
		||||
                #   txt: Quote text
 | 
			
		||||
            # Keys are keywords, Each key has a LIST of quotes in the following format:
 | 
			
		||||
            # - id: Alphanumeric id used for commands related to the quote. (Note, when using .quotesimport, a new id will be generated.)
 | 
			
		||||
            #   an: Author name
 | 
			
		||||
            #   aid: Author id
 | 
			
		||||
            #   txt: Quote text
 | 
			
		||||
 | 
			
		||||
                """;
 | 
			
		||||
            """;
 | 
			
		||||
 | 
			
		||||
        private static readonly ISerializer _exportSerializer = new SerializerBuilder()
 | 
			
		||||
            .WithEventEmitter(args
 | 
			
		||||
                => new MultilineScalarFlowStyleEmitter(args))
 | 
			
		||||
            .WithNamingConvention(
 | 
			
		||||
                CamelCaseNamingConvention.Instance)
 | 
			
		||||
            .WithIndentedSequences()
 | 
			
		||||
            .ConfigureDefaultValuesHandling(DefaultValuesHandling
 | 
			
		||||
                .OmitDefaults)
 | 
			
		||||
            .DisableAliases()
 | 
			
		||||
            .Build();
 | 
			
		||||
                                                                .WithEventEmitter(args
 | 
			
		||||
                                                                    => new MultilineScalarFlowStyleEmitter(args))
 | 
			
		||||
                                                                .WithNamingConvention(
 | 
			
		||||
                                                                    CamelCaseNamingConvention.Instance)
 | 
			
		||||
                                                                .WithIndentedSequences()
 | 
			
		||||
                                                                .ConfigureDefaultValuesHandling(DefaultValuesHandling
 | 
			
		||||
                                                                    .OmitDefaults)
 | 
			
		||||
                                                                .DisableAliases()
 | 
			
		||||
                                                                .Build();
 | 
			
		||||
 | 
			
		||||
        private readonly DbService _db;
 | 
			
		||||
        private readonly IHttpClientFactory _http;
 | 
			
		||||
@@ -67,13 +67,15 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            if (quotes.Any())
 | 
			
		||||
            {
 | 
			
		||||
                await SendConfirmAsync(GetText(strs.quotes_page(page + 1)),
 | 
			
		||||
                    string.Join("\n",
 | 
			
		||||
                        quotes.Select(q
 | 
			
		||||
                            => $"`#{q.Id}` {Format.Bold(q.Keyword.SanitizeAllMentions()),-20} by {q.AuthorName.SanitizeAllMentions()}")));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm(GetText(strs.quotes_page(page + 1)),
 | 
			
		||||
                          string.Join("\n",
 | 
			
		||||
                              quotes.Select(q
 | 
			
		||||
                                  => $"`#{q.Id}` {Format.Bold(q.Keyword.SanitizeAllMentions()),-20} by {q.AuthorName.SanitizeAllMentions()}")))
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.quotes_page_none);
 | 
			
		||||
                await Response().Error(strs.quotes_page_none).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -121,7 +123,7 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            if (quote is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.quotes_notfound);
 | 
			
		||||
                await Response().Error(strs.quotes_notfound).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -130,26 +132,26 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
        private async Task ShowQuoteData(Quote data)
 | 
			
		||||
        {
 | 
			
		||||
            var eb = _eb.Create(ctx)
 | 
			
		||||
                          .WithOkColor()
 | 
			
		||||
                          .WithTitle($"{GetText(strs.quote_id($"#{data.Id}"))} | {GetText(strs.response)}:")
 | 
			
		||||
                          .WithDescription(Format.Sanitize(data.Text).Replace("](", "]\\(").TrimTo(4096))
 | 
			
		||||
                          .AddField(GetText(strs.trigger), data.Keyword)
 | 
			
		||||
                          .WithFooter(
 | 
			
		||||
                              GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})")))
 | 
			
		||||
                          .Build();
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithTitle($"{GetText(strs.quote_id($"#{data.Id}"))} | {GetText(strs.response)}:")
 | 
			
		||||
                        .WithDescription(Format.Sanitize(data.Text).Replace("](", "]\\(").TrimTo(4096))
 | 
			
		||||
                        .AddField(GetText(strs.trigger), data.Keyword)
 | 
			
		||||
                        .WithFooter(
 | 
			
		||||
                            GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})")))
 | 
			
		||||
                        .Build();
 | 
			
		||||
 | 
			
		||||
            if (!(data.Text.Length > 4096))
 | 
			
		||||
            {
 | 
			
		||||
                await ctx.Channel.SendMessageAsync(embed: eb);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.SendFileAsync(
 | 
			
		||||
                attachment: new FileAttachment(await data.Text.ToStream(), "quote.txt"),
 | 
			
		||||
                embed: eb);
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
        private async Task QuoteSearchinternalAsync(string? keyword, string textOrAuthor)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(textOrAuthor))
 | 
			
		||||
@@ -177,7 +179,7 @@ public partial class Utility
 | 
			
		||||
        [Priority(0)]
 | 
			
		||||
        public Task QuoteSearch(string textOrAuthor)
 | 
			
		||||
            => QuoteSearchinternalAsync(null, textOrAuthor);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [Priority(1)]
 | 
			
		||||
@@ -202,7 +204,7 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            if (quote is null || quote.GuildId != ctx.Guild.Id)
 | 
			
		||||
            {
 | 
			
		||||
                await SendErrorAsync(GetText(strs.quotes_notfound));
 | 
			
		||||
                await Response().Error(GetText(strs.quotes_notfound)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -228,18 +230,19 @@ public partial class Utility
 | 
			
		||||
            Quote q;
 | 
			
		||||
            await using (var uow = _db.GetDbContext())
 | 
			
		||||
            {
 | 
			
		||||
                uow.Set<Quote>().Add(q = new()
 | 
			
		||||
                {
 | 
			
		||||
                    AuthorId = ctx.Message.Author.Id,
 | 
			
		||||
                    AuthorName = ctx.Message.Author.Username,
 | 
			
		||||
                    GuildId = ctx.Guild.Id,
 | 
			
		||||
                    Keyword = keyword,
 | 
			
		||||
                    Text = text
 | 
			
		||||
                });
 | 
			
		||||
                uow.Set<Quote>()
 | 
			
		||||
                   .Add(q = new()
 | 
			
		||||
                   {
 | 
			
		||||
                       AuthorId = ctx.Message.Author.Id,
 | 
			
		||||
                       AuthorName = ctx.Message.Author.Username,
 | 
			
		||||
                       GuildId = ctx.Guild.Id,
 | 
			
		||||
                       Keyword = keyword,
 | 
			
		||||
                       Text = text
 | 
			
		||||
                   });
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.quote_added_new(Format.Code(q.Id.ToString())));
 | 
			
		||||
            await Response().Confirm(strs.quote_added_new(Format.Code(q.Id.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -266,16 +269,16 @@ public partial class Utility
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (success)
 | 
			
		||||
                await SendConfirmAsync(response);
 | 
			
		||||
                await Response().Confirm(response).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await SendErrorAsync(response);
 | 
			
		||||
                await Response().Error(response).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public Task QuoteDeleteAuthor(IUser user)
 | 
			
		||||
            => QuoteDeleteAuthor(user.Id);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task QuoteDeleteAuthor(ulong userId)
 | 
			
		||||
@@ -285,11 +288,11 @@ public partial class Utility
 | 
			
		||||
            if (userId == ctx.User.Id || hasManageMessages)
 | 
			
		||||
            {
 | 
			
		||||
                var deleted = await _qs.DeleteAllAuthorQuotesAsync(ctx.Guild.Id, userId);
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.quotes_deleted_count(deleted));
 | 
			
		||||
                await Response().Confirm(strs.quotes_deleted_count(deleted)).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.insuf_perms_u);
 | 
			
		||||
                await Response().Error(strs.insuf_perms_u).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -310,7 +313,7 @@ public partial class Utility
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.quotes_deleted(Format.Bold(keyword.SanitizeAllMentions())));
 | 
			
		||||
            await Response().Confirm(strs.quotes_deleted(Format.Bold(keyword.SanitizeAllMentions()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -325,7 +328,7 @@ public partial class Utility
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var exprsDict = quotes.GroupBy(x => x.Keyword)
 | 
			
		||||
                .ToDictionary(x => x.Key, x => x.Select(ExportedQuote.FromModel));
 | 
			
		||||
                                  .ToDictionary(x => x.Key, x => x.Select(ExportedQuote.FromModel));
 | 
			
		||||
 | 
			
		||||
            var text = PREPEND_EXPORT + _exportSerializer.Serialize(exprsDict).UnescapeUnicodeCodePoints();
 | 
			
		||||
 | 
			
		||||
@@ -351,7 +354,7 @@ public partial class Utility
 | 
			
		||||
                var attachment = ctx.Message.Attachments.FirstOrDefault();
 | 
			
		||||
                if (attachment is null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
 | 
			
		||||
                    await Response().Error(strs.expr_import_no_input).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -360,7 +363,7 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(input))
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
 | 
			
		||||
                    await Response().Error(strs.expr_import_no_input).SendAsync();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -368,7 +371,7 @@ public partial class Utility
 | 
			
		||||
            var succ = await ImportExprsAsync(ctx.Guild.Id, input);
 | 
			
		||||
            if (!succ)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.expr_import_invalid_data);
 | 
			
		||||
                await Response().Error(strs.expr_import_invalid_data).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -393,15 +396,16 @@ public partial class Utility
 | 
			
		||||
            foreach (var entry in data)
 | 
			
		||||
            {
 | 
			
		||||
                var keyword = entry.Key;
 | 
			
		||||
                await uow.Set<Quote>().AddRangeAsync(entry.Value.Where(quote => !string.IsNullOrWhiteSpace(quote.Txt))
 | 
			
		||||
                    .Select(quote => new Quote
 | 
			
		||||
                    {
 | 
			
		||||
                        GuildId = guildId,
 | 
			
		||||
                        Keyword = keyword,
 | 
			
		||||
                        Text = quote.Txt,
 | 
			
		||||
                        AuthorId = quote.Aid,
 | 
			
		||||
                        AuthorName = quote.An
 | 
			
		||||
                    }));
 | 
			
		||||
                await uow.Set<Quote>()
 | 
			
		||||
                         .AddRangeAsync(entry.Value.Where(quote => !string.IsNullOrWhiteSpace(quote.Txt))
 | 
			
		||||
                                             .Select(quote => new Quote
 | 
			
		||||
                                             {
 | 
			
		||||
                                                 GuildId = guildId,
 | 
			
		||||
                                                 Keyword = keyword,
 | 
			
		||||
                                                 Text = quote.Txt,
 | 
			
		||||
                                                 AuthorId = quote.Aid,
 | 
			
		||||
                                                 AuthorName = quote.An
 | 
			
		||||
                                             }));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await uow.SaveChangesAsync();
 | 
			
		||||
 
 | 
			
		||||
@@ -41,10 +41,10 @@ public partial class Utility
 | 
			
		||||
        {
 | 
			
		||||
            if (!_service.TryParseRemindMessage(remindString, out var remindData))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.remind_invalid);
 | 
			
		||||
                await Response().Error(strs.remind_invalid).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            ulong target;
 | 
			
		||||
            target = meorhere == MeOrHere.Me ? ctx.User.Id : ctx.Channel.Id;
 | 
			
		||||
            if (!await RemindInternal(target,
 | 
			
		||||
@@ -52,7 +52,7 @@ public partial class Utility
 | 
			
		||||
                    remindData.Time,
 | 
			
		||||
                    remindData.What,
 | 
			
		||||
                    ReminderType.User))
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.remind_too_long);
 | 
			
		||||
                await Response().Error(strs.remind_too_long).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -64,19 +64,19 @@ public partial class Utility
 | 
			
		||||
            var perms = ((IGuildUser)ctx.User).GetPermissions(channel);
 | 
			
		||||
            if (!perms.SendMessages || !perms.ViewChannel)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.cant_read_or_send);
 | 
			
		||||
                await Response().Error(strs.cant_read_or_send).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!_service.TryParseRemindMessage(remindString, out var remindData))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.remind_invalid);
 | 
			
		||||
                await Response().Error(strs.remind_invalid).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if (!await RemindInternal(channel.Id, false, remindData.Time, remindData.What, ReminderType.User))
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.remind_too_long);
 | 
			
		||||
                await Response().Error(strs.remind_too_long).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -96,7 +96,7 @@ public partial class Utility
 | 
			
		||||
            if (--page < 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create()
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                           .WithOkColor()
 | 
			
		||||
                           .WithTitle(GetText(isServer ? strs.reminder_server_list : strs.reminder_list));
 | 
			
		||||
 | 
			
		||||
@@ -128,7 +128,7 @@ public partial class Utility
 | 
			
		||||
                embed.WithDescription(GetText(strs.reminders_none));
 | 
			
		||||
 | 
			
		||||
            embed.AddPaginatedFooter(page + 1, null);
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -165,9 +165,9 @@ public partial class Utility
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (rem is null)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.reminder_not_exist);
 | 
			
		||||
                await Response().Error(strs.reminder_not_exist).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.reminder_deleted(index + 1));
 | 
			
		||||
                await Response().Confirm(strs.reminder_deleted(index + 1)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<bool> RemindInternal(
 | 
			
		||||
@@ -208,13 +208,14 @@ public partial class Utility
 | 
			
		||||
            var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id));
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await SendConfirmAsync("⏰ "
 | 
			
		||||
                                       + GetText(strs.remind(
 | 
			
		||||
                                           Format.Bold(!isPrivate ? $"<#{targetId}>" : ctx.User.Username),
 | 
			
		||||
                                           Format.Bold(message),
 | 
			
		||||
                                           ts.Humanize(3, minUnit: TimeUnit.Second, culture: Culture),
 | 
			
		||||
                                           gTime,
 | 
			
		||||
                                           gTime)));
 | 
			
		||||
                await Response()
 | 
			
		||||
                      .Confirm($"\u23f0 {GetText(strs.remind(
 | 
			
		||||
                          Format.Bold(!isPrivate ? $"<#{targetId}>" : ctx.User.Username),
 | 
			
		||||
                          Format.Bold(message),
 | 
			
		||||
                          ts.Humanize(3, minUnit: TimeUnit.Second, culture: Culture),
 | 
			
		||||
                          gTime,
 | 
			
		||||
                          gTime))}")
 | 
			
		||||
                      .SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -205,7 +205,7 @@ public class RemindService : INService, IReadyExecutor, IRemindService
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ch.EmbedAsync(_eb.Create()
 | 
			
		||||
                await ch.EmbedAsync(new EmbedBuilder()
 | 
			
		||||
                        .WithOkColor()
 | 
			
		||||
                        .WithTitle("Reminder")
 | 
			
		||||
                        .AddField("Created At",
 | 
			
		||||
 
 | 
			
		||||
@@ -21,17 +21,17 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            if (result is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.index_out_of_range);
 | 
			
		||||
                await Response().Error(strs.index_out_of_range).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (result is true)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.repeater_skip_next);
 | 
			
		||||
                await Response().Confirm(strs.repeater_skip_next).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.repeater_dont_skip_next);
 | 
			
		||||
                await Response().Confirm(strs.repeater_dont_skip_next).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -45,7 +45,7 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            var success = await _service.TriggerExternal(ctx.Guild.Id, index);
 | 
			
		||||
            if (!success)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.repeat_invoke_none);
 | 
			
		||||
                await Response().Error(strs.repeat_invoke_none).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -59,15 +59,15 @@ public partial class Utility
 | 
			
		||||
            var removed = await _service.RemoveByIndexAsync(ctx.Guild.Id, index);
 | 
			
		||||
            if (removed is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.repeater_remove_fail);
 | 
			
		||||
                await Response().Error(strs.repeater_remove_fail).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var description = GetRepeaterInfoString(removed);
 | 
			
		||||
            await EmbedAsync(_eb.Create()
 | 
			
		||||
            await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithTitle(GetText(strs.repeater_removed(index + 1)))
 | 
			
		||||
                .WithDescription(description));
 | 
			
		||||
                .WithDescription(description)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -82,14 +82,14 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            if (result is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.index_out_of_range);
 | 
			
		||||
                await Response().Error(strs.index_out_of_range).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (result.Value)
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.repeater_redundant_no(index + 1));
 | 
			
		||||
                await Response().Error(strs.repeater_redundant_no(index + 1)).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.repeater_redundant_yes(index + 1));
 | 
			
		||||
                await Response().Confirm(strs.repeater_redundant_yes(index + 1)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -182,15 +182,15 @@ public partial class Utility
 | 
			
		||||
 | 
			
		||||
            if (runner is null)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.repeater_exceed_limit(5));
 | 
			
		||||
                await Response().Error(strs.repeater_exceed_limit(5)).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var description = GetRepeaterInfoString(runner);
 | 
			
		||||
            await EmbedAsync(_eb.Create()
 | 
			
		||||
            await Response().Embed(new EmbedBuilder()
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithTitle(GetText(strs.repeater_created))
 | 
			
		||||
                .WithDescription(description));
 | 
			
		||||
                .WithDescription(description)).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -201,11 +201,11 @@ public partial class Utility
 | 
			
		||||
            var repeaters = _service.GetRepeaters(ctx.Guild.Id);
 | 
			
		||||
            if (repeaters.Count == 0)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.repeaters_none);
 | 
			
		||||
                await Response().Confirm(strs.repeaters_none).SendAsync();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var embed = _eb.Create().WithTitle(GetText(strs.list_of_repeaters)).WithOkColor();
 | 
			
		||||
            var embed = new EmbedBuilder().WithTitle(GetText(strs.list_of_repeaters)).WithOkColor();
 | 
			
		||||
 | 
			
		||||
            var i = 0;
 | 
			
		||||
            foreach (var runner in repeaters.OrderBy(r => r.Repeater.Id))
 | 
			
		||||
@@ -215,7 +215,7 @@ public partial class Utility
 | 
			
		||||
                embed.AddField(name, description);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await EmbedAsync(embed);
 | 
			
		||||
            await Response().Embed(embed).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string GetRepeaterInfoString(RunningRepeater runner)
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,8 @@ public partial class Utility
 | 
			
		||||
        {
 | 
			
		||||
            await _service.SetStreamRole(fromRole, addRole);
 | 
			
		||||
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.stream_role_enabled(Format.Bold(fromRole.ToString()),
 | 
			
		||||
                Format.Bold(addRole.ToString())));
 | 
			
		||||
            await Response().Confirm(strs.stream_role_enabled(Format.Bold(fromRole.ToString()),
 | 
			
		||||
                Format.Bold(addRole.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -27,7 +27,7 @@ public partial class Utility
 | 
			
		||||
        public async Task StreamRole()
 | 
			
		||||
        {
 | 
			
		||||
            await _service.StopStreamRole(ctx.Guild);
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.stream_role_disabled);
 | 
			
		||||
            await Response().Confirm(strs.stream_role_disabled).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -39,9 +39,9 @@ public partial class Utility
 | 
			
		||||
            var kw = await _service.SetKeyword(ctx.Guild, keyword);
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(keyword))
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_role_kw_reset);
 | 
			
		||||
                await Response().Confirm(strs.stream_role_kw_reset).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_role_kw_set(Format.Bold(kw)));
 | 
			
		||||
                await Response().Confirm(strs.stream_role_kw_set(Format.Bold(kw))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -59,14 +59,14 @@ public partial class Utility
 | 
			
		||||
            if (action == AddRemove.Add)
 | 
			
		||||
            {
 | 
			
		||||
                if (success)
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.stream_role_bl_add(Format.Bold(user.ToString())));
 | 
			
		||||
                    await Response().Confirm(strs.stream_role_bl_add(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
                else
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.stream_role_bl_add_fail(Format.Bold(user.ToString())));
 | 
			
		||||
                    await Response().Confirm(strs.stream_role_bl_add_fail(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else if (success)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_role_bl_rem(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.stream_role_bl_rem(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.stream_role_bl_rem_fail(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Error(strs.stream_role_bl_rem_fail(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
@@ -84,14 +84,14 @@ public partial class Utility
 | 
			
		||||
            if (action == AddRemove.Add)
 | 
			
		||||
            {
 | 
			
		||||
                if (success)
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.stream_role_wl_add(Format.Bold(user.ToString())));
 | 
			
		||||
                    await Response().Confirm(strs.stream_role_wl_add(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
                else
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.stream_role_wl_add_fail(Format.Bold(user.ToString())));
 | 
			
		||||
                    await Response().Confirm(strs.stream_role_wl_add_fail(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            }
 | 
			
		||||
            else if (success)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_role_wl_rem(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Confirm(strs.stream_role_wl_rem(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.stream_role_wl_rem_fail(Format.Bold(user.ToString())));
 | 
			
		||||
                await Response().Error(strs.stream_role_wl_rem_fail(Format.Bold(user.ToString()))).SendAsync();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user