Added many more braces for multiline if's, Improved .crypto command quite a bit and applied locale-specific format

This commit is contained in:
Kwoth
2022-02-04 06:00:17 +01:00
parent f77f2f433f
commit eda38e64d1
129 changed files with 635 additions and 233 deletions

View File

@@ -349,7 +349,7 @@ resharper_csharp_place_type_constraints_on_same_line = false
resharper_csharp_wrap_before_extends_colon = true
resharper_csharp_place_constructor_initializer_on_same_line = false
resharper_force_attribute_style = separate
resharper_csharp_braces_for_ifelse = required_for_complex
resharper_csharp_braces_for_ifelse = required_for_multiline_statement
resharper_csharp_braces_for_foreach = required_for_multiline
resharper_csharp_braces_for_while = required_for_multiline
resharper_csharp_braces_for_for = required_for_multiline

View File

@@ -123,9 +123,11 @@ public sealed class Bot
if (Environment.GetEnvironmentVariable("NADEKOBOT_IS_COORDINATED") != "1")
svcs.AddSingleton<ICoordinator, SingleProcessCoordinator>();
else
{
svcs.AddSingleton<RemoteGrpcCoordinator>()
.AddSingleton<ICoordinator>(x => x.GetRequiredService<RemoteGrpcCoordinator>())
.AddSingleton<IReadyExecutor>(x => x.GetRequiredService<RemoteGrpcCoordinator>());
}
svcs.AddSingleton<RedisLocalDataCache>()
.AddSingleton<ILocalDataCache>(x => x.GetRequiredService<RedisLocalDataCache>())

View File

@@ -385,8 +385,10 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
count += tables.CountPerLock[i];
if (array.Length - count < arrayIndex || count < 0) //"count" itself or "count + arrayIndex" can overflow
{
throw new ArgumentException(
"The index is equal to or greater than the length of the array, or the number of elements in the set is greater than the available space from index to the end of the destination array.");
}
CopyToItems(array, arrayIndex);
}

View File

@@ -53,6 +53,7 @@ public class EventPubSub : IPubSub
// get subscriptions which have the same action hash code
// note: having this as a list allows for multiple subscriptions of
// the same insance's/static method
{
if (actions.TryGetValue(action, out var sameActions))
{
// remove last subscription
@@ -71,6 +72,7 @@ public class EventPubSub : IPubSub
_actions.Remove(key.Key);
}
}
}
return Task.CompletedTask;
}

View File

@@ -36,8 +36,10 @@ public sealed class RedisPubSub : IPubSub
if (dataObj is not null)
await action(dataObj);
else
{
Log.Warning("Publishing event {EventName} with a null value. This is not allowed",
eventName);
}
}
catch (Exception ex)
{

View File

@@ -63,8 +63,10 @@ public class ReplacementBuilder
{
var to = TimeZoneInfo.Local;
if (g is not null)
{
if (GuildTimezoneService.AllServices.TryGetValue(client.CurrentUser.Id, out var tz))
to = tz.GetTimeZoneOrDefault(g.Id) ?? TimeZoneInfo.Local;
}
return TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Utc, to).ToString("HH:mm ")
+ to.StandardName.GetInitials();

View File

@@ -54,11 +54,13 @@ public class Replacer
Url = Replace(embedData.Url)
};
if (embedData.Author is not null)
{
newEmbedData.Author = new()
{
Name = Replace(embedData.Author.Name),
IconUrl = Replace(embedData.Author.IconUrl)
};
}
if (embedData.Fields is not null)
{
@@ -78,11 +80,13 @@ public class Replacer
}
if (embedData.Footer is not null)
{
newEmbedData.Footer = new()
{
Text = Replace(embedData.Footer.Text),
IconUrl = Replace(embedData.Footer.IconUrl)
};
}
newEmbedData.Color = embedData.Color;

View File

@@ -54,6 +54,7 @@ public sealed record SmartEmbedText : SmartText
};
if (eb.Fields.Length > 0)
{
set.Fields = eb.Fields.Select(field
=> new SmartTextEmbedField
{
@@ -62,6 +63,7 @@ public sealed record SmartEmbedText : SmartText
Value = field.Value
})
.ToArray();
}
set.Color = eb.Color?.RawValue ?? 0;
return set;
@@ -81,12 +83,14 @@ public sealed record SmartEmbedText : SmartText
embed.WithUrl(Url);
if (Footer is not null)
{
embed.WithFooter(efb =>
{
efb.WithText(Footer.Text);
if (Uri.IsWellFormedUriString(Footer.IconUrl, UriKind.Absolute))
efb.WithIconUrl(Footer.IconUrl);
});
}
if (Thumbnail is not null && Uri.IsWellFormedUriString(Thumbnail, UriKind.Absolute))
embed.WithThumbnailUrl(Thumbnail);
@@ -105,11 +109,13 @@ public sealed record SmartEmbedText : SmartText
}
if (Fields is not null)
{
foreach (var f in Fields)
{
if (!string.IsNullOrWhiteSpace(f.Name) && !string.IsNullOrWhiteSpace(f.Value))
embed.AddField(f.Name, f.Value, f.Inline);
}
}
return embed;
}
@@ -117,10 +123,12 @@ public sealed record SmartEmbedText : SmartText
public void NormalizeFields()
{
if (Fields is { Length: > 0 })
{
foreach (var f in Fields)
{
f.Name = f.Name.TrimTo(256);
f.Value = f.Value.TrimTo(1024);
}
}
}
}

View File

@@ -53,8 +53,10 @@ public sealed class CommandOrCrTypeReader : NadekoTypeReader<CommandOrCrInfo>
var cmd = await new CommandTypeReader(_commandHandler, _cmds).ReadAsync(ctx, input);
if (cmd.IsSuccess)
{
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name,
CommandOrCrInfo.Type.Normal));
}
return TypeReaderResult.FromError<CommandOrCrInfo>(CommandError.ParseFailed, "No such command or cr found.");
}

View File

@@ -14,8 +14,10 @@ public sealed class GuildDateTimeTypeReader : NadekoTypeReader<GuildDateTime>
{
var gdt = Parse(context.Guild.Id, input);
if (gdt is null)
{
return new(TypeReaderResult.FromError<GuildDateTime>(CommandError.ParseFailed,
"Input string is in an incorrect format."));
}
return new(TypeReaderResult.FromSuccess(gdt));
}

View File

@@ -19,13 +19,11 @@ public class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor
&& !string.IsNullOrWhiteSpace(commentsDescriptor.Comment))
{
var parts = commentsDescriptor.Comment.Split('\n');
foreach (var part in parts)
{
context.Emit(new Comment(part.Trim(), false));
}
}
return base.EnterMapping(key, value, context);
}
}

View File

@@ -21,10 +21,12 @@ public class MultilineScalarFlowStyleEmitter : ChainedEventEmitter
{
var isMultiLine = value.IndexOfAny(new[] { '\r', '\n', '\x85', '\x2028', '\x2029' }) >= 0;
if (isMultiLine)
{
eventInfo = new(eventInfo.Source)
{
Style = ScalarStyle.Literal
};
}
}
}

View File

@@ -127,6 +127,7 @@ WHERE UserId={userId};");
// just update the amount, there is no new user data
if (!updatedUserData)
{
ctx.Database.ExecuteSqlInterpolated($@"
UPDATE OR IGNORE DiscordUser
SET CurrencyAmount=CurrencyAmount+{amount}
@@ -135,7 +136,9 @@ WHERE UserId={userId};
INSERT OR IGNORE INTO DiscordUser (UserId, Username, Discriminator, AvatarId, CurrencyAmount, TotalXp)
VALUES ({userId}, {name}, {discrim}, {avatarId}, {amount}, 0);
");
}
else
{
ctx.Database.ExecuteSqlInterpolated($@"
UPDATE OR IGNORE DiscordUser
SET CurrencyAmount=CurrencyAmount+{amount},
@@ -147,6 +150,7 @@ WHERE UserId={userId};
INSERT OR IGNORE INTO DiscordUser (UserId, Username, Discriminator, AvatarId, CurrencyAmount, TotalXp)
VALUES ({userId}, {name}, {discrim}, {avatarId}, {amount}, 0);
");
}
return true;
}

View File

@@ -74,9 +74,7 @@ public static class GuildConfigExtensions
GuildConfig config;
if (includes is null)
{
config = ctx.GuildConfigs.IncludeEverything().FirstOrDefault(c => c.GuildId == guildId);
}
else
{
var set = includes(ctx.GuildConfigs);

View File

@@ -13,6 +13,7 @@ public static class UserXpExtensions
var usr = ctx.UserXpStats.FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId);
if (usr is null)
{
ctx.Add(usr = new()
{
Xp = 0,
@@ -20,6 +21,7 @@ public static class UserXpExtensions
NotifyOnLevelUp = XpNotificationLocation.None,
GuildId = guildId
});
}
return usr;
}
@@ -42,12 +44,6 @@ public static class UserXpExtensions
.ToList();
public static int GetUserGuildRanking(this DbSet<UserXpStats> xps, ulong userId, ulong guildId)
// @"SELECT COUNT(*) + 1
//FROM UserXpStats
//WHERE GuildId = @p1 AND ((Xp + AwardedXp) > (SELECT Xp + AwardedXp
// FROM UserXpStats
// WHERE UserId = @p2 AND GuildId = @p1
// LIMIT 1));";
=> xps.AsQueryable()
.AsNoTracking()
.Where(x => x.GuildId == guildId

View File

@@ -28,11 +28,13 @@ public static class WaifuExtensions
Func<DbSet<WaifuInfo>, IQueryable<WaifuInfo>> includes = null)
{
if (includes is null)
{
return waifus.Include(wi => wi.Waifu)
.Include(wi => wi.Affinity)
.Include(wi => wi.Claimer)
.Include(wi => wi.Items)
.FirstOrDefault(wi => wi.Waifu.UserId == userId);
}
return includes(waifus).AsQueryable().FirstOrDefault(wi => wi.Waifu.UserId == userId);
}

View File

@@ -32,8 +32,11 @@ public class WaifuInfo : DbEntity
else if (AffinityId == ClaimerId)
status = $"... and {waifuUsername} likes {claimerUsername} too <3";
else
{
status =
$"... but {waifuUsername}'s heart belongs to {Affinity.Username.TrimTo(20)}#{Affinity.Discriminator}";
}
return $"**{waifuUsername}#{Waifu.Discriminator}** - claimed by **{claimer}**\n\t{status}";
}
}

View File

@@ -314,9 +314,7 @@ public partial class Administration : NadekoModule<AdministrationService>
}
if (time is null)
{
await msg.DeleteAsync();
}
else if (time.Time <= TimeSpan.FromDays(7))
{
_ = Task.Run(async () =>

View File

@@ -115,13 +115,9 @@ public class AdministrationService : INService
{
}
else if (newState == Administration.State.Enable)
{
DeleteMessagesOnCommandChannels[chId] = true;
}
else
{
DeleteMessagesOnCommandChannels.TryRemove(chId, out _);
}
}
public async Task DeafenUsers(bool value, params IGuildUser[] users)

View File

@@ -25,9 +25,7 @@ public partial class Administration
var id = _service.ToggleGameVoiceChannel(ctx.Guild.Id, vch.Id);
if (id is null)
{
await ReplyConfirmLocalizedAsync(strs.gvc_disabled);
}
else
{
_service.GameVoiceChannels.Add(vch.Id);

View File

@@ -42,8 +42,10 @@ public class GameVoiceChannelService : INService
{
if (activity is { Type: ActivityType.Playing })
//trigger gvc
{
if (await TriggerGvc(newUser, activity.Name))
return;
}
}
}
catch (Exception ex)

View File

@@ -141,9 +141,7 @@ public class GreetService : INService, IReadyExecutor
}
}
else
{
await ByeUsers(conf, channel, new[] { user });
}
}
catch
{
@@ -255,10 +253,12 @@ public class GreetService : INService, IReadyExecutor
text = rep.Replace(text);
if (text is SmartPlainText pt)
{
text = new SmartEmbedText()
{
PlainText = pt.Text
};
}
((SmartEmbedText)text).Footer = new()
{
@@ -308,9 +308,7 @@ public class GreetService : INService, IReadyExecutor
}
}
else
{
await GreetUsers(conf, channel, new[] { user });
}
}
}

View File

@@ -75,9 +75,7 @@ public sealed class ImageOnlyChannelService : IEarlyBehavior
var newState = false;
using var uow = _db.GetDbContext();
if (forceDisable || (_enabledOn.TryGetValue(guildId, out var channels) && channels.TryRemove(channelId)))
{
uow.ImageOnlyChannels.Delete(x => x.ChannelId == channelId);
}
else
{
uow.ImageOnlyChannels.Add(new()

View File

@@ -66,9 +66,7 @@ public class MuteService : INService
{
TimeSpan after;
if (x.UnmuteAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
{
after = TimeSpan.FromMinutes(2);
}
else
{
var unmute = x.UnmuteAt - DateTime.UtcNow;
@@ -82,9 +80,7 @@ public class MuteService : INService
{
TimeSpan after;
if (x.UnbanAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
{
after = TimeSpan.FromMinutes(2);
}
else
{
var unban = x.UnbanAt - DateTime.UtcNow;
@@ -98,9 +94,7 @@ public class MuteService : INService
{
TimeSpan after;
if (x.UnbanAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
{
after = TimeSpan.FromMinutes(2);
}
else
{
var unban = x.UnbanAt - DateTime.UtcNow;
@@ -306,6 +300,7 @@ public class MuteService : INService
var muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName);
if (muteRole is null)
//if it doesn't exist, create it
{
try { muteRole = await guild.CreateRoleAsync(muteRoleName, isMentionable: false); }
catch
{
@@ -313,6 +308,7 @@ public class MuteService : INService
muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName)
?? await guild.CreateRoleAsync(defaultMuteRoleName, isMentionable: false);
}
}
foreach (var toOverwrite in await guild.GetTextChannelsAsync())
{
@@ -414,6 +410,7 @@ public class MuteService : INService
var toAdd = new Timer(async _ =>
{
if (type == TimerType.Ban)
{
try
{
RemoveTimerFromDb(guildId, userId, type);
@@ -426,7 +423,9 @@ public class MuteService : INService
{
Log.Warning(ex, "Couldn't unban user {UserId} in guild {GuildId}", userId, guildId);
}
}
else if (type == TimerType.AddRole)
{
try
{
if (roleId is null)
@@ -444,7 +443,9 @@ public class MuteService : INService
{
Log.Warning(ex, "Couldn't remove role from user {UserId} in guild {GuildId}", userId, guildId);
}
}
else
{
try
{
// unmute the user, this will also remove the timer from the db
@@ -455,6 +456,7 @@ public class MuteService : INService
RemoveTimerFromDb(guildId, userId, type); // if unmute errored, just remove unmute from db
Log.Warning(ex, "Couldn't unmute user {UserId} in guild {GuildId}", userId, guildId);
}
}
},
null,
after,

View File

@@ -67,8 +67,10 @@ public partial class Administration
if (thisPageOverrides.Count == 0)
eb.WithDescription(GetText(strs.perm_override_page_none));
else
{
eb.WithDescription(thisPageOverrides.Select(ov => $"{ov.Command} => {ov.Perm.ToString()}")
.Join("\n"));
}
return eb;
},

View File

@@ -56,6 +56,7 @@ public class DiscordPermOverrideService : INService, ILateBlocker
.FirstOrDefaultAsync(x => x.GuildId == guildId && commandName == x.Command);
if (over is null)
{
uow.Set<DiscordPermOverride>()
.Add(over = new()
{
@@ -63,6 +64,7 @@ public class DiscordPermOverrideService : INService, ILateBlocker
Perm = perm,
GuildId = guildId
});
}
else
over.Perm = perm;

View File

@@ -34,9 +34,7 @@ public partial class Administration
var statuses = _service.GetRotatingStatuses();
if (!statuses.Any())
{
await ReplyErrorLocalizedAsync(strs.ropl_not_set);
}
else
{
var i = 1;

View File

@@ -114,8 +114,10 @@ public partial class Administration
}
if (punishTime is not null)
{
if (!_service.IsDurationAllowed(action))
await ReplyErrorLocalizedAsync(strs.prot_cant_use_time);
}
var time = (int?)punishTime?.Time.TotalMinutes ?? 0;
if (time is < 0 or > 60 * 24)
@@ -176,8 +178,10 @@ public partial class Administration
return;
if (timeData is not null)
{
if (!_service.IsDurationAllowed(action))
await ReplyErrorLocalizedAsync(strs.prot_cant_use_time);
}
var time = (int?)timeData?.Time.TotalMinutes ?? 0;
if (time is < 0 or > 60 * 24)

View File

@@ -136,10 +136,12 @@ public class ProtectionService : INService
}
if (spam is not null)
{
_antiSpamGuilds[gc.GuildId] = new()
{
AntiSpamSettings = spam
};
}
var alt = gc.AntiAltSetting;
if (alt is not null)
@@ -160,6 +162,7 @@ public class ProtectionService : INService
_ = Task.Run(async () =>
{
if (maybeAlts is { } alts)
{
if (user.CreatedAt != default)
{
var diff = DateTime.UtcNow - user.CreatedAt.UtcDateTime;
@@ -176,6 +179,7 @@ public class ProtectionService : INService
return;
}
}
}
try
{
@@ -234,6 +238,7 @@ public class ProtectionService : INService
});
if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold)
{
if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats))
{
var settings = spamSettings.AntiSpamSettings;
@@ -243,6 +248,7 @@ public class ProtectionService : INService
settings.RoleId,
(IGuildUser)msg.Author);
}
}
}
catch
{
@@ -392,9 +398,7 @@ public class ProtectionService : INService
gc.AntiSpamSetting.RoleId = stats.AntiSpamSettings.RoleId;
}
else
{
gc.AntiSpamSetting = stats.AntiSpamSettings;
}
await uow.SaveChangesAsync();
return stats;

View File

@@ -71,13 +71,17 @@ public partial class Administration
count = 1000;
if (parameter is "-s" or "--safe")
{
await _service.PruneWhere((ITextChannel)ctx.Channel,
count,
m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks && !m.IsPinned);
}
else
{
await _service.PruneWhere((ITextChannel)ctx.Channel,
count,
m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks);
}
}
}
}

View File

@@ -52,10 +52,12 @@ public class PruneService : INService
//100 messages, Maybe this needs to be reduced by msgs.Length instead of 100
amount -= 50;
if (amount > 0)
{
msgs = (await channel.GetMessagesAsync(lastMessage, Direction.Before, 50).FlattenAsync())
.Where(predicate)
.Take(amount)
.ToArray();
}
}
}
catch

View File

@@ -143,9 +143,7 @@ public partial class Administration
{
var embed = _eb.Create().WithOkColor();
if (!_service.Get(ctx.Guild.Id, out var rrs) || !rrs.Any())
{
embed.WithDescription(GetText(strs.no_reaction_roles));
}
else
{
var g = (SocketGuild)ctx.Guild;

View File

@@ -101,9 +101,7 @@ public partial class Administration
var scmds = _service.GetStartupCommands().Skip(page * 5).Take(5).ToList();
if (scmds.Count == 0)
{
await ReplyErrorLocalizedAsync(strs.startcmdlist_none);
}
else
{
var i = 0;
@@ -128,9 +126,7 @@ public partial class Administration
var scmds = _service.GetAutoCommands().Skip(page * 5).Take(5).ToList();
if (!scmds.Any())
{
await ReplyErrorLocalizedAsync(strs.autocmdlist_none);
}
else
{
var i = 0;

View File

@@ -190,12 +190,16 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
.ToImmutableDictionary();
if (!ownerChannels.Any())
{
Log.Warning(
"No owner channels created! Make sure you've specified the correct OwnerId in the creds.yml file and invited the bot to a Discord server");
}
else
{
Log.Information("Created {OwnerChannelCount} out of {TotalOwnerChannelCount} owner message channels",
ownerChannels.Count,
_creds.OwnerIds.Count);
}
}
public Task LeaveGuild(string guildStr)
@@ -214,8 +218,10 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
var toSend = msg.Content;
if (msg.Attachments.Count > 0)
{
toSend += $"\n\n{Format.Code(attachamentsTxt)}:\n"
+ string.Join("\n", msg.Attachments.Select(a => a.ProxyUrl));
}
if (bs.ForwardToAllOwners)
{
@@ -237,6 +243,7 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
{
var firstOwnerChannel = ownerChannels.Values.First();
if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
{
try
{
await firstOwnerChannel.SendConfirmAsync(_eb, title, toSend);
@@ -245,6 +252,7 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
{
// ignored
}
}
}
}
}
@@ -273,8 +281,11 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
{
uow.Remove(cmd);
if (autoCommands.TryGetValue(cmd.GuildId, out var autos))
{
if (autos.TryRemove(cmd.Id, out var timer))
timer.Change(Timeout.Infinite, Timeout.Infinite);
}
uow.SaveChanges();
return true;
}

View File

@@ -45,8 +45,10 @@ public partial class Administration
var succ = _service.AddNew(ctx.Guild.Id, role, group);
if (succ)
{
await ReplyConfirmLocalizedAsync(strs.role_added(Format.Bold(role.Name),
Format.Bold(group.ToString())));
Format.Bold(@group.ToString())));
}
else
await ReplyErrorLocalizedAsync(strs.role_in_list(Format.Bold(role.Name)));
}
@@ -61,8 +63,10 @@ public partial class Administration
var set = await _service.SetNameAsync(ctx.Guild.Id, group, name);
if (set)
{
await ReplyConfirmLocalizedAsync(
strs.group_name_added(Format.Bold(group.ToString()), Format.Bold(name)));
strs.group_name_added(Format.Bold(@group.ToString()), Format.Bold(name)));
}
else
await ReplyConfirmLocalizedAsync(strs.group_name_removed(Format.Bold(group.ToString())));
}

View File

@@ -85,6 +85,7 @@ public class SelfAssignedRolesService : INService
{
var sameRole = guildUser.Guild.GetRole(roleId);
if (sameRole is not null)
{
try
{
await guildUser.RemoveRoleAsync(sameRole);
@@ -94,6 +95,7 @@ public class SelfAssignedRolesService : INService
{
// ignored
}
}
}
}
@@ -192,9 +194,7 @@ public class SelfAssignedRolesService : INService
uow.SaveChanges();
}
else
{
return false;
}
return true;
}

View File

@@ -21,7 +21,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
private readonly GuildTimezoneService _tz;
private readonly IEmbedBuilderService _eb;
private readonly IMemoryCache _memoryCache;
private readonly ConcurrentHashSet<ulong> _ignoreMessageIds = new();
public LogCommandService(
@@ -89,9 +89,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
{
using var timer = new PeriodicTimer(TimeSpan.FromHours(1));
while (await timer.WaitForNextTickAsync())
{
_ignoreMessageIds.Clear();
}
}
private async Task PresenceUpdateTask()
@@ -108,7 +106,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
{
if (!((SocketGuild)key.Guild).CurrentUser.GetPermissions(key).SendMessages)
return Task.CompletedTask;
if (PresenceUpdates.TryRemove(key, out var msgs))
{
var title = GetText(key.Guild, strs.presence_updates);
@@ -234,9 +232,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
embed.WithImageUrl(aav.ToString());
}
else
{
return;
}
await logChannel.EmbedAsync(embed);
}
@@ -656,14 +652,18 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
var afterTextChannel = cafter as ITextChannel;
if (before.Name != after.Name)
{
embed.WithTitle(" " + GetText(logChannel.Guild, strs.ch_name_change))
.WithDescription($"{after} | {after.Id}")
.AddField(GetText(logChannel.Guild, strs.ch_old_name), before.Name);
}
else if (beforeTextChannel?.Topic != afterTextChannel?.Topic)
{
embed.WithTitle(" " + GetText(logChannel.Guild, strs.ch_topic_change))
.WithDescription($"{after} | {after.Id}")
.AddField(GetText(logChannel.Guild, strs.old_topic), beforeTextChannel?.Topic ?? "-")
.AddField(GetText(logChannel.Guild, strs.new_topic), afterTextChannel?.Topic ?? "-");
}
else
return;
@@ -778,26 +778,33 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
var str = string.Empty;
if (beforeVch?.Guild == afterVch?.Guild)
{
str = "🎙"
+ Format.Code(PrettyCurrentTime(usr.Guild))
+ GetText(logChannel.Guild,
strs.user_vmoved("👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
Format.Bold(beforeVch?.Name ?? ""),
Format.Bold(afterVch?.Name ?? "")));
}
else if (beforeVch is null)
{
str = "🎙"
+ Format.Code(PrettyCurrentTime(usr.Guild))
+ GetText(logChannel.Guild,
strs.user_vjoined("👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
Format.Bold(afterVch?.Name ?? "")));
}
else if (afterVch is null)
{
str = "🎙"
+ Format.Code(PrettyCurrentTime(usr.Guild))
+ GetText(logChannel.Guild,
strs.user_vleft("👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
Format.Bold(beforeVch.Name ?? "")));
}
if (!string.IsNullOrWhiteSpace(str))
{
PresenceUpdates.AddOrUpdate(logChannel,
new List<string>
{
@@ -808,6 +815,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
list.Add(str);
return list;
});
}
}
catch
{
@@ -1001,8 +1009,10 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
.AddField("Id", msg.Id.ToString())
.WithFooter(CurrentTime(channel.Guild));
if (msg.Attachments.Any())
{
embed.AddField(GetText(logChannel.Guild, strs.attachments),
string.Join(", ", msg.Attachments.Select(a => a.Url)));
}
await logChannel.EmbedAsync(embed);
}

View File

@@ -58,11 +58,15 @@ public partial class Administration
var removed = _service.LogIgnore(ctx.Guild.Id, target.Id, IgnoredItemType.Channel);
if (!removed)
{
await ReplyConfirmLocalizedAsync(
strs.log_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")")));
}
else
{
await ReplyConfirmLocalizedAsync(
strs.log_not_ignore_chan(Format.Bold(target.Mention + "(" + target.Id + ")")));
}
}
[Cmd]
@@ -74,11 +78,15 @@ public partial class Administration
var removed = _service.LogIgnore(ctx.Guild.Id, target.Id, IgnoredItemType.User);
if (!removed)
{
await ReplyConfirmLocalizedAsync(
strs.log_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")")));
}
else
{
await ReplyConfirmLocalizedAsync(
strs.log_not_ignore_user(Format.Bold(target.Mention + "(" + target.Id + ")")));
}
}
[Cmd]

View File

@@ -100,8 +100,10 @@ public partial class Administration
if (punishment is null)
embed.WithDescription(GetText(strs.user_warned(Format.Bold(user.ToString()))));
else
{
embed.WithDescription(GetText(strs.user_warned_and_punished(Format.Bold(user.ToString()),
Format.Bold(punishment.Punishment.ToString()))));
}
if (dmFailed)
embed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
@@ -204,9 +206,7 @@ public partial class Administration
var embed = _eb.Create().WithOkColor().WithTitle(GetText(strs.warnlog_for(user)));
if (!warnings.Any())
{
embed.WithDescription(GetText(strs.warnings_none));
}
else
{
var descText = GetText(strs.warn_count(
@@ -288,9 +288,7 @@ 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));
}
else
{
if (success)
@@ -325,12 +323,16 @@ public partial class Administration
return;
if (time is null)
{
await ReplyConfirmLocalizedAsync(strs.warn_punish_set(Format.Bold(punish.ToString()),
Format.Bold(number.ToString())));
}
else
{
await ReplyConfirmLocalizedAsync(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
Format.Bold(number.ToString()),
Format.Bold(time.Input)));
}
}
[Cmd]
@@ -348,12 +350,16 @@ public partial class Administration
return;
if (time is null)
{
await ReplyConfirmLocalizedAsync(strs.warn_punish_set(Format.Bold(punish.ToString()),
Format.Bold(number.ToString())));
}
else
{
await ReplyConfirmLocalizedAsync(strs.warn_punish_set_timed(Format.Bold(punish.ToString()),
Format.Bold(number.ToString()),
Format.Bold(time.Input)));
}
}
[Cmd]
@@ -375,11 +381,14 @@ public partial class Administration
string list;
if (ps.Any())
{
list = string.Join("\n",
ps.Select(x
=> $"{x.Count} -> {x.Punishment} {(x.Punishment == PunishmentAction.AddRole ? $"<@&{x.RoleId}>" : "")} {(x.Time <= 0 ? "" : x.Time + "m")} "));
}
else
list = GetText(strs.warnpl_none);
await SendConfirmAsync(GetText(strs.warn_punish_list), list);
}
@@ -401,6 +410,7 @@ public partial class Administration
var dmFailed = false;
if (guildUser is not null)
{
try
{
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg));
@@ -412,6 +422,7 @@ public partial class Administration
{
dmFailed = true;
}
}
await _mute.TimedBan(ctx.Guild, user, time.Time, (ctx.User + " | " + msg).TrimTo(512));
var toSend = _eb.Create()
@@ -447,9 +458,7 @@ public partial class Administration
.AddField("ID", userId.ToString(), true));
}
else
{
await Ban(user, msg);
}
}
[Cmd]
@@ -545,9 +554,7 @@ public partial class Administration
var embed = _service.GetBanUserDmEmbed(Context, (IGuildUser)ctx.User, defaultMessage, reason, duration);
if (embed is null)
{
await ConfirmLocalizedAsync(strs.banmsg_disabled);
}
else
{
try
@@ -755,9 +762,7 @@ public partial class Administration
banning.Add(user);
}
else
{
missing.Add(userStr);
}
}
var missStr = string.Join("\n", missing);

View File

@@ -233,9 +233,11 @@ WHERE GuildId in (SELECT GuildId FROM GuildConfigs WHERE WarnExpireHours > 0 AND
AND DateAdded < datetime('now', (SELECT '-' || WarnExpireHours || ' hours' FROM GuildConfigs as gc WHERE gc.GuildId = Warnings.GuildId));");
if (cleared > 0 || deleted > 0)
{
Log.Information("Cleared {ClearedWarnings} warnings and deleted {DeletedWarnings} warnings due to expiry",
cleared,
deleted);
}
}
public async Task CheckWarnExpiresAsync(ulong guildId)
@@ -248,16 +250,20 @@ WHERE GuildId in (SELECT GuildId FROM GuildConfigs WHERE WarnExpireHours > 0 AND
var hours = $"{-config.WarnExpireHours} hours";
if (config.WarnExpireAction == WarnExpireAction.Clear)
{
await uow.Database.ExecuteSqlInterpolatedAsync($@"UPDATE warnings
SET Forgiven = 1,
ForgivenBy = 'Expiry'
WHERE GuildId={guildId}
AND Forgiven = 0
AND DateAdded < datetime('now', {hours})");
}
else if (config.WarnExpireAction == WarnExpireAction.Delete)
{
await uow.Database.ExecuteSqlInterpolatedAsync($@"DELETE FROM warnings
WHERE GuildId={guildId}
AND DateAdded < datetime('now', {hours})");
}
await uow.SaveChangesAsync();
}
@@ -436,9 +442,7 @@ WHERE GuildId={guildId}
});
}
else
{
template.Text = text;
}
uow.SaveChanges();
}
@@ -487,22 +491,26 @@ WHERE GuildId={guildId}
// if template isn't set, use the old message style
if (string.IsNullOrWhiteSpace(template))
{
template = JsonConvert.SerializeObject(new
{
color = _bcs.Data.Color.Error.PackedValue >> 8,
description = defaultMessage
});
}
// if template is set to "-" do not dm the user
else if (template == "-")
return default;
// if template is an embed, send that embed with replacements
// otherwise, treat template as a regular string with replacements
else if (!SmartText.CreateFrom(template).IsEmbed)
{
template = JsonConvert.SerializeObject(new
{
color = _bcs.Data.Color.Error.PackedValue >> 8,
description = template
});
}
var output = SmartText.CreateFrom(template);
return replacer.Replace(output);

View File

@@ -59,14 +59,14 @@ public partial class Administration
if (!roles.Any())
text = GetText(strs.no_vcroles);
else
{
text = string.Join("\n",
roles.Select(x
=> $"{Format.Bold(guild.GetVoiceChannel(x.Key)?.Name ?? x.Key.ToString())} => {x.Value}"));
}
}
else
{
text = GetText(strs.no_vcroles);
}
await ctx.Channel.EmbedAsync(_eb.Create()
.WithOkColor()

View File

@@ -64,9 +64,7 @@ public static class NadekoExpressionExtensions
return WordPosition.End;
}
else if (str.IsValidWordDivider(wordIndex - 1) && str.IsValidWordDivider(wordIndex + word.Length))
{
return WordPosition.Middle;
}
return WordPosition.None;
}

View File

@@ -249,11 +249,15 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
}
if (newVal)
{
await ReplyConfirmLocalizedAsync(strs.option_enabled(Format.Code(option.ToString()),
Format.Code(id.ToString())));
}
else
{
await ReplyConfirmLocalizedAsync(strs.option_disabled(Format.Code(option.ToString()),
Format.Code(id.ToString())));
}
}
[Cmd]

View File

@@ -290,6 +290,7 @@ public sealed class NadekoExpressionsService : IEarlyBehavior, IReadyExecutor
}
if (expr.AutoDeleteTrigger)
{
try
{
await msg.DeleteAsync();
@@ -297,6 +298,7 @@ public sealed class NadekoExpressionsService : IEarlyBehavior, IReadyExecutor
catch
{
}
}
Log.Information("s: {GuildId} c: {ChannelId} u: {UserId} | {UserName} executed expression {Expr}",
guild.Id,
@@ -341,6 +343,7 @@ public sealed class NadekoExpressionsService : IEarlyBehavior, IReadyExecutor
private void UpdateInternal(ulong? maybeGuildId, NadekoExpression expr)
{
if (maybeGuildId is { } guildId)
{
newGuildReactions.AddOrUpdate(guildId,
new[] { expr },
(_, old) =>
@@ -354,7 +357,9 @@ public sealed class NadekoExpressionsService : IEarlyBehavior, IReadyExecutor
return newArray;
});
}
else
{
lock (_gexprWriteLock)
{
var exprs = globalReactions;
@@ -364,6 +369,7 @@ public sealed class NadekoExpressionsService : IEarlyBehavior, IReadyExecutor
exprs[i] = expr;
}
}
}
}
private Task AddInternalAsync(ulong? maybeGuildId, NadekoExpression expr)

View File

@@ -131,9 +131,11 @@ public sealed class AnimalRace : IDisposable
}
if (FinishedUsers[0].Bet > 0)
{
await _currency.AddAsync(FinishedUsers[0].UserId,
FinishedUsers[0].Bet * (_users.Count - 1),
new("animalrace", "win"));
}
_ = OnEnded?.Invoke(this);
});

View File

@@ -53,8 +53,10 @@ public partial class Gambling
try
{
if (arg.Channel.Id == ctx.Channel.Id)
{
if (ar.CurrentPhase == AnimalRace.Phase.Running && ++count % 9 == 0)
raceMessage = null;
}
}
catch { }
});
@@ -67,10 +69,13 @@ public partial class Gambling
_service.AnimalRaces.TryRemove(ctx.Guild.Id, out _);
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 SendConfirmAsync(GetText(strs.animal_race),
GetText(strs.animal_race_won(Format.Bold(winner.Username), winner.Animal.Icon)));
}
@@ -110,11 +115,13 @@ public partial class Gambling
if (msg is null)
raceMessage = await SendConfirmAsync(text);
else
{
await msg.ModifyAsync(x => x.Embed = _eb.Create()
.WithTitle(GetText(strs.animal_race))
.WithDescription(text)
.WithOkColor()
.Build());
}
}
private Task Ar_OnStartingFailed(AnimalRace race)
@@ -140,9 +147,11 @@ 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)));
}
else
await SendConfirmAsync(GetText(strs.animal_race_join(ctx.User.Mention, user.Animal.Icon)));
}

View File

@@ -56,9 +56,11 @@ public partial class Gambling
if (await bj.Join(ctx.User, amount))
await ReplyConfirmLocalizedAsync(strs.bj_joined);
else
{
Log.Information("{User} can't join a blackjack game as it's in {BlackjackState} state already",
ctx.User,
bj.State);
}
}
await ctx.Message.DeleteAsync();
@@ -114,21 +116,13 @@ public partial class Gambling
full = "✅ " + full;
}
else if (p == bj.CurrentUser)
{
full = "▶ " + full;
}
else if (p.State == User.UserState.Stand)
{
full = "⏹ " + full;
}
else if (p.State == User.UserState.Bust)
{
full = "💥 " + full;
}
else if (p.State == User.UserState.Blackjack)
{
full = "💰 " + full;
}
embed.AddField(full, cStr);
}
@@ -177,8 +171,10 @@ public partial class Gambling
else if (a == BjAction.Stand)
await bj.Stand(ctx.User);
else if (a == BjAction.Double)
{
if (!await bj.Double(ctx.User))
await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
}
await ctx.Message.DeleteAsync();
}

View File

@@ -202,6 +202,7 @@ public class Blackjack
}
if (hw > 21)
{
foreach (var usr in Players)
{
if (usr.State is User.UserState.Stand or User.UserState.Blackjack)
@@ -209,7 +210,9 @@ public class Blackjack
else
usr.State = User.UserState.Lost;
}
}
else
{
foreach (var usr in Players)
{
if (usr.State == User.UserState.Blackjack)
@@ -219,6 +222,7 @@ public class Blackjack
else
usr.State = User.UserState.Lost;
}
}
foreach (var usr in Players)
{

View File

@@ -129,9 +129,7 @@ public sealed class Connect4Game : IDisposable
_players[0] = (userId, userName);
}
else //else join as a second player
{
_players[1] = (userId, userName);
}
CurrentPhase = Phase.P1Move; //start the game
playerTimeoutTimer = new(async _ =>
@@ -197,6 +195,7 @@ public sealed class Connect4Game : IDisposable
var first = _gameState[i + (j * NUMBER_OF_ROWS)];
if (first != Field.Empty)
{
for (var k = 1; k < 4; k++)
{
var next = _gameState[i + k + (j * NUMBER_OF_ROWS)];
@@ -208,10 +207,9 @@ public sealed class Connect4Game : IDisposable
continue;
}
else
{
break;
}
}
}
}
}
@@ -228,17 +226,21 @@ public sealed class Connect4Game : IDisposable
var first = _gameState[j + (i * NUMBER_OF_ROWS)];
if (first != Field.Empty)
{
for (var k = 1; k < 4; k++)
{
var next = _gameState[j + ((i + k) * NUMBER_OF_ROWS)];
if (next == first)
{
if (k == 3)
EndGame(Result.CurrentPlayerWon, CurrentPlayer.UserId);
else
continue;
}
else
break;
}
}
}
}

View File

@@ -65,6 +65,7 @@ public partial class Gambling
}
if (options.Bet > 0)
{
if (!await _cs.RemoveAsync(ctx.User.Id, options.Bet, new("connect4", "bet")))
{
await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
@@ -72,6 +73,7 @@ public partial class Gambling
game.Dispose();
return;
}
}
game.OnGameStateUpdated += Game_OnGameStateUpdated;
game.OnGameFailedToStart += GameOnGameFailedToStart;
@@ -106,8 +108,10 @@ public partial class Gambling
return;
RepostCounter++;
if (RepostCounter == 0)
{
try { msg = await ctx.Channel.SendMessageAsync("", embed: (Embed)msg.Embeds.First()); }
catch { }
}
}
});
return Task.CompletedTask;
@@ -134,11 +138,15 @@ public partial class Gambling
string title;
if (result == Connect4Game.Result.CurrentPlayerWon)
{
title = GetText(strs.connect4_won(Format.Bold(arg.CurrentPlayer.Username),
Format.Bold(arg.OtherPlayer.Username)));
}
else if (result == Connect4Game.Result.OtherPlayerWon)
{
title = GetText(strs.connect4_won(Format.Bold(arg.OtherPlayer.Username),
Format.Bold(arg.CurrentPlayer.Username)));
}
else
title = GetText(strs.connect4_draw);

View File

@@ -82,6 +82,7 @@ public partial class Gambling
if (randomNumber == 6 || dice.Count == 0)
toInsert = 0;
else if (randomNumber != 1)
{
for (var j = 0; j < dice.Count; j++)
{
if (values[j] < randomNumber)
@@ -90,11 +91,10 @@ public partial class Gambling
break;
}
}
}
}
else
{
toInsert = dice.Count;
}
dice.Insert(toInsert, GetDice(randomNumber));
values.Insert(toInsert, randomNumber);
@@ -190,9 +190,7 @@ public partial class Gambling
rolled = new NadekoRandom().Next(arr[0], arr[1] + 1);
}
else
{
rolled = new NadekoRandom().Next(0, int.Parse(range) + 1);
}
await ReplyConfirmLocalizedAsync(strs.dice_rolled(Format.Bold(rolled.ToString())));
}

View File

@@ -43,6 +43,7 @@ public class CurrencyEventsService : INService
var added = _events.TryAdd(guildId, ce);
if (added)
{
try
{
ce.OnEnded += OnEventEnded;
@@ -54,6 +55,7 @@ public class CurrencyEventsService : INService
_events.TryRemove(guildId, out ce);
return false;
}
}
return added;
}

View File

@@ -82,6 +82,7 @@ public class GameStatusEvent : ICurrencyEvent
);
if (_isPotLimited)
{
await msg.ModifyAsync(m =>
{
m.Embed = GetEmbed(PotSize).Build();
@@ -90,6 +91,7 @@ public class GameStatusEvent : ICurrencyEvent
{
RetryMode = RetryMode.AlwaysRetry
});
}
Log.Information("Awarded {Count} users {Amount} currency.{Remaining}",
toAward.Count,
@@ -179,6 +181,7 @@ public class GameStatusEvent : ICurrencyEvent
private bool TryTakeFromPot()
{
if (_isPotLimited)
{
lock (_potLock)
{
if (PotSize < _amount)
@@ -187,6 +190,7 @@ public class GameStatusEvent : ICurrencyEvent
PotSize -= _amount;
return true;
}
}
return true;
}

View File

@@ -75,6 +75,7 @@ public class ReactionEvent : ICurrencyEvent
await _cs.AddBulkAsync(toAward, _amount, new("event", "reaction"));
if (_isPotLimited)
{
await msg.ModifyAsync(m =>
{
m.Embed = GetEmbed(PotSize).Build();
@@ -83,6 +84,7 @@ public class ReactionEvent : ICurrencyEvent
{
RetryMode = RetryMode.AlwaysRetry
});
}
Log.Information("Awarded {Count} users {Amount} currency.{Remaining}",
toAward.Count,
@@ -178,6 +180,7 @@ public class ReactionEvent : ICurrencyEvent
private bool TryTakeFromPot()
{
if (_isPotLimited)
{
lock (_potLock)
{
if (PotSize < _amount)
@@ -186,6 +189,7 @@ public class ReactionEvent : ICurrencyEvent
PotSize -= _amount;
return true;
}
}
return true;
}

View File

@@ -75,7 +75,7 @@ public partial class Gambling
+ GetText(strs.flipped(headCount > 0
? Format.Bold(GetText(strs.heads))
: Format.Bold(GetText(strs.tails))));
await ctx.Channel.SendFileAsync(stream, $"{count} coins.{format.FileExtensions.First()}", msg);
}
@@ -114,9 +114,7 @@ public partial class Gambling
await _cs.AddAsync(ctx.User, toWin, new("betflip", "win"));
}
else
{
str = Format.Bold(ctx.User.ToString()) + " " + GetText(strs.better_luck);
}
await ctx.Channel.EmbedAsync(_eb.Create()
.WithDescription(str)

View File

@@ -8,7 +8,6 @@ using NadekoBot.Modules.Gambling.Services;
using NadekoBot.Services.Currency;
using NadekoBot.Services.Database.Models;
using System.Globalization;
using System.Numerics;
using System.Text;
namespace NadekoBot.Modules.Gambling;
@@ -79,13 +78,15 @@ public partial class Gambling : GamblingModule<GamblingService>
// This stops the top 1% from owning more than 100% of the money
if (ec.Cash > 0)
{
onePercent = ec.OnePercent / (ec.Cash - ec.Bot);
}
// [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)))
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))
@@ -132,7 +133,9 @@ public partial class Gambling : GamblingModule<GamblingService>
public async partial Task TimelySet(int amount, int period = 24)
{
if (amount < 0 || period < 0)
{
return;
}
_configService.ModifyConfig(gs =>
{
@@ -141,9 +144,13 @@ public partial class Gambling : GamblingModule<GamblingService>
});
if (amount == 0)
{
await ReplyConfirmLocalizedAsync(strs.timely_set_none);
}
else
{
await ReplyConfirmLocalizedAsync(strs.timely_set(Format.Bold(N(amount)), Format.Bold(period.ToString())));
}
}
[Cmd]
@@ -155,7 +162,10 @@ public partial class Gambling : GamblingModule<GamblingService>
var members = (await role.GetMembersAsync()).Where(u => u.Status != UserStatus.Offline);
var membersArray = members as IUser[] ?? members.ToArray();
if (membersArray.Length == 0)
{
return;
}
var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)];
await SendConfirmAsync("🎟 " + GetText(strs.raffled_user),
$"**{usr.Username}#{usr.Discriminator}**",
@@ -171,7 +181,10 @@ public partial class Gambling : GamblingModule<GamblingService>
var members = await role.GetMembersAsync();
var membersArray = members as IUser[] ?? members.ToArray();
if (membersArray.Length == 0)
{
return;
}
var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)];
await SendConfirmAsync("🎟 " + GetText(strs.raffled_user),
$"**{usr.Username}#{usr.Discriminator}**",
@@ -198,7 +211,9 @@ public partial class Gambling : GamblingModule<GamblingService>
private async Task InternalCurrencyTransactions(ulong userId, int page)
{
if (--page < 0)
{
return;
}
List<CurrencyTransaction> trs;
await using (var uow = _db.GetDbContext())
@@ -222,10 +237,14 @@ public partial class Gambling : GamblingModule<GamblingService>
sb.AppendLine($"\\{change} {date} {Format.Bold(N(tr.Amount))}");
var transactionString = GetHumanReadableTransaction(tr.Type, tr.Extra, tr.OtherId);
if (transactionString is not null)
{
sb.AppendLine(transactionString);
}
if (!string.IsNullOrWhiteSpace(tr.Note))
{
sb.AppendLine($"\t`Note:` {tr.Note.TrimTo(50)}");
}
}
embed.WithDescription(sb.ToString());
@@ -264,10 +283,14 @@ public partial class Gambling : GamblingModule<GamblingService>
eb.AddField("Extra", tr.Extra, true);
if (tr.OtherId is ulong other)
{
eb.AddField("From Id", other);
}
if (!string.IsNullOrWhiteSpace(tr.Note))
{
eb.AddField("Note", tr.Note);
}
eb.WithFooter(GetFormattedCurtrDate(tr));
@@ -313,7 +336,9 @@ public partial class Gambling : GamblingModule<GamblingService>
public async partial Task Give(ShmartNumber amount, IGuildUser receiver, [Leftover] string msg)
{
if (amount <= 0 || ctx.User.Id == receiver.Id || receiver.IsBot)
{
return;
}
if (!await _cs.TransferAsync(ctx.User.Id, receiver.Id, amount, ctx.User.ToString(), msg))
{
@@ -350,7 +375,9 @@ public partial class Gambling : GamblingModule<GamblingService>
public async partial Task Award(long amount, ulong usrId, [Leftover] string msg = null)
{
if (amount <= 0)
{
return;
}
var usr = await ((DiscordSocketClient)Context.Client).Rest.GetUserAsync(usrId);
@@ -414,7 +441,9 @@ public partial class Gambling : GamblingModule<GamblingService>
public async partial Task Take(long amount, [Leftover] IGuildUser user)
{
if (amount <= 0)
{
return;
}
var extra = new TxData("take",
ctx.User.ToString()!,
@@ -422,9 +451,13 @@ public partial class Gambling : GamblingModule<GamblingService>
ctx.User.Id);
if (await _cs.RemoveAsync(user.Id, amount, extra))
{
await ReplyConfirmLocalizedAsync(strs.take(N(amount), Format.Bold(user.ToString())));
}
else
{
await ReplyErrorLocalizedAsync(strs.take_fail(N(amount), Format.Bold(user.ToString()), CurrencySign));
}
}
@@ -433,7 +466,9 @@ public partial class Gambling : GamblingModule<GamblingService>
public async partial Task Take(long amount, [Leftover] ulong usrId)
{
if (amount <= 0)
{
return;
}
var extra = new TxData("take",
ctx.User.ToString()!,
@@ -441,9 +476,13 @@ public partial class Gambling : GamblingModule<GamblingService>
ctx.User.Id);
if (await _cs.RemoveAsync(usrId, amount, extra))
{
await ReplyConfirmLocalizedAsync(strs.take(N(amount), $"<@{usrId}>"));
}
else
{
await ReplyErrorLocalizedAsync(strs.take_fail(N(amount), Format.Code(usrId.ToString()), CurrencySign));
}
}
[Cmd]
@@ -451,12 +490,16 @@ public partial class Gambling : GamblingModule<GamblingService>
public async partial Task RollDuel(IUser u)
{
if (ctx.User.Id == u.Id)
{
return;
}
//since the challenge is created by another user, we need to reverse the ids
//if it gets removed, means challenge is accepted
if (_service.Duels.TryRemove((ctx.User.Id, u.Id), out var game))
{
await game.StartGame();
}
}
[Cmd]
@@ -464,10 +507,14 @@ public partial class Gambling : GamblingModule<GamblingService>
public async partial Task RollDuel(ShmartNumber amount, IUser u)
{
if (ctx.User.Id == u.Id)
{
return;
}
if (amount <= 0)
{
return;
}
var embed = _eb.Create().WithOkColor().WithTitle(GetText(strs.roll_duel));
@@ -478,9 +525,14 @@ public partial class Gambling : GamblingModule<GamblingService>
if (_service.Duels.TryGetValue((ctx.User.Id, u.Id), out var other))
{
if (other.Amount != amount)
{
await ReplyErrorLocalizedAsync(strs.roll_duel_already_challenged);
}
else
{
await RollDuel(u);
}
return;
}
@@ -504,12 +556,16 @@ public partial class Gambling : GamblingModule<GamblingService>
embed = embed.WithDescription(description);
if (rdMsg is null)
{
rdMsg = await ctx.Channel.EmbedAsync(embed);
}
else
{
await rdMsg.ModifyAsync(x =>
{
x.Embed = embed.Build();
});
}
}
async Task GameOnEnded(RollDuelGame rdGame, RollDuelGame.Reason reason)
@@ -544,7 +600,9 @@ public partial class Gambling : GamblingModule<GamblingService>
private async Task InternallBetroll(long amount)
{
if (!await CheckBetMandatory(amount))
{
return;
}
if (!await _cs.RemoveAsync(ctx.User, amount, new("betroll", "bet")))
{
@@ -588,14 +646,18 @@ public partial class Gambling : GamblingModule<GamblingService>
public async partial Task Leaderboard(int page = 1, params string[] args)
{
if (--page < 0)
{
return;
}
var (opts, _) = OptionsParser.ParseFrom(new LbOpts(), args);
List<DiscordUser> cleanRichest;
// it's pointless to have clean on dm context
if (ctx.Guild is null)
{
opts.Clean = false;
}
if (opts.Clean)
{
@@ -658,7 +720,9 @@ public partial class Gambling : GamblingModule<GamblingService>
public async partial Task Rps(RpsPick pick, ShmartNumber amount = default)
{
if (!await CheckBetOptional(amount) || amount == 1)
{
return;
}
string GetRpsPick(RpsPick p)
{
@@ -678,6 +742,7 @@ public partial class Gambling : GamblingModule<GamblingService>
var nadekoPick = (RpsPick)new NadekoRandom().Next(0, 3);
if (amount > 0)
{
if (!await _cs.RemoveAsync(ctx.User.Id,
amount,
new("rps", "bet", "")))
@@ -685,6 +750,7 @@ public partial class Gambling : GamblingModule<GamblingService>
await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
return;
}
}
string msg;
if (pick == nadekoPick)

View File

@@ -14,11 +14,10 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
private readonly IEnumerable<WaifuItemModel> _antiGiftSeed = new[]
{
new WaifuItemModel("🥀", 100, "WiltedRose", true),
new WaifuItemModel("✂️", 1000, "Haircut", true),
new WaifuItemModel("🥀", 100, "WiltedRose", true), new WaifuItemModel("✂️", 1000, "Haircut", true),
new WaifuItemModel("🧻", 10000, "ToiletPaper", true)
};
public GamblingConfigService(IConfigSeria serializer, IPubSub pubSub)
: base(FILE_PATH, serializer, pubSub, _changeKey)
{
@@ -26,7 +25,7 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
gs => gs.Currency.Name,
ConfigParsers.String,
ConfigPrinters.ToString);
AddParsedProp("currency.sign",
gs => gs.Currency.Sign,
ConfigParsers.String,
@@ -37,7 +36,7 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
int.TryParse,
ConfigPrinters.ToString,
val => val >= 0);
AddParsedProp("maxbet",
gs => gs.MaxBet,
int.TryParse,
@@ -49,19 +48,19 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
int.TryParse,
ConfigPrinters.ToString,
val => val >= 1);
AddParsedProp("gen.max",
gs => gs.Generation.MaxAmount,
int.TryParse,
ConfigPrinters.ToString,
val => val >= 1);
AddParsedProp("gen.cd",
gs => gs.Generation.GenCooldown,
int.TryParse,
ConfigPrinters.ToString,
val => val > 0);
AddParsedProp("gen.chance",
gs => gs.Generation.Chance,
decimal.TryParse,
@@ -72,73 +71,73 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
gs => gs.Generation.HasPassword,
bool.TryParse,
ConfigPrinters.ToString);
AddParsedProp("bf.multi",
gs => gs.BetFlip.Multiplier,
decimal.TryParse,
ConfigPrinters.ToString,
val => val >= 1);
AddParsedProp("waifu.min_price",
gs => gs.Waifu.MinPrice,
long.TryParse,
ConfigPrinters.ToString,
val => val >= 0);
AddParsedProp("waifu.multi.reset",
gs => gs.Waifu.Multipliers.WaifuReset,
int.TryParse,
ConfigPrinters.ToString,
val => val >= 0);
AddParsedProp("waifu.multi.crush_claim",
gs => gs.Waifu.Multipliers.CrushClaim,
decimal.TryParse,
ConfigPrinters.ToString,
val => val >= 0);
AddParsedProp("waifu.multi.normal_claim",
gs => gs.Waifu.Multipliers.NormalClaim,
decimal.TryParse,
ConfigPrinters.ToString,
val => val > 0);
AddParsedProp("waifu.multi.divorce_value",
gs => gs.Waifu.Multipliers.DivorceNewValue,
decimal.TryParse,
ConfigPrinters.ToString,
val => val > 0);
AddParsedProp("waifu.multi.all_gifts",
gs => gs.Waifu.Multipliers.AllGiftPrices,
decimal.TryParse,
ConfigPrinters.ToString,
val => val > 0);
AddParsedProp("waifu.multi.gift_effect",
gs => gs.Waifu.Multipliers.GiftEffect,
decimal.TryParse,
ConfigPrinters.ToString,
val => val >= 0);
AddParsedProp("waifu.multi.negative_gift_effect",
gs => gs.Waifu.Multipliers.NegativeGiftEffect,
decimal.TryParse,
ConfigPrinters.ToString,
val => val >= 0);
AddParsedProp("decay.percent",
gs => gs.Decay.Percent,
decimal.TryParse,
ConfigPrinters.ToString,
val => val is >= 0 and <= 1);
AddParsedProp("decay.maxdecay",
gs => gs.Decay.MaxDecay,
int.TryParse,
ConfigPrinters.ToString,
val => val >= 0);
AddParsedProp("decay.threshold",
gs => gs.Decay.MinThreshold,
int.TryParse,
@@ -151,23 +150,29 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
public void Migrate()
{
if (data.Version < 2)
{
ModifyConfig(c =>
{
c.Waifu.Items = c.Waifu.Items.Concat(_antiGiftSeed).ToList();
c.Version = 2;
});
}
if (data.Version < 3)
{
ModifyConfig(c =>
{
c.Version = 3;
c.VoteReward = 100;
});
if(data.Version < 5)
}
if (data.Version < 5)
{
ModifyConfig(c =>
{
c.Version = 5;
});
}
}
}

View File

@@ -70,12 +70,12 @@ public class GamblingService : INService, IReadyExecutor
}
}
}
private async Task CurrencyDecayLoopAsync()
{
if (_bot.Client.ShardId != 0)
return;
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));
while (await timer.WaitForNextTickAsync())
{
@@ -125,16 +125,18 @@ WHERE CurrencyAmount > {config.Decay.MinThreshold} AND UserId!={_client.CurrentU
}
}
}
public async Task<SlotResponse> SlotAsync(ulong userId, long amount)
{
var takeRes = await _cs.RemoveAsync(userId, amount, new("slot", "bet"));
if (!takeRes)
{
return new()
{
Error = GamblingError.NotEnough
};
}
var game = new SlotGame();
var result = game.Spin();
@@ -161,11 +163,13 @@ WHERE CurrencyAmount > {config.Decay.MinThreshold} AND UserId!={_client.CurrentU
public EconomyResult GetEconomy()
{
if (_cache.TryGetEconomy(out var data))
{
try
{
return JsonConvert.DeserializeObject<EconomyResult>(data);
}
catch { }
}
decimal cash;
decimal onePercent;

View File

@@ -1,7 +1,6 @@
#nullable disable
using NadekoBot.Modules.Gambling.Services;
using System.Globalization;
using System.Runtime;
namespace NadekoBot.Modules.Gambling.Common;
@@ -39,8 +38,9 @@ public abstract class GamblingModule<TService> : NadekoModule<TService>
return true;
}
protected string N<T>(T cur) where T : INumber<T>
protected string N<T>(T cur)
where T : INumber<T>
{
var flowersCi = (CultureInfo)Culture.Clone();
flowersCi.NumberFormat.CurrencySymbol = CurrencySign;

View File

@@ -31,12 +31,14 @@ public partial class Gambling
}
if (((SocketGuild)ctx.Guild).CurrentUser.GuildPermissions.ManageMessages)
{
try
{
_logService.AddDeleteIgnore(ctx.Message.Id);
await ctx.Message.DeleteAsync();
}
catch { }
}
}
[Cmd]
@@ -61,7 +63,7 @@ public partial class Gambling
ctx.User.ToString(),
amount,
pass);
if (!success)
await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
}

View File

@@ -52,6 +52,7 @@ public class CurrencyRaffleService : INService
}
if (newGame)
{
_ = Task.Run(async () =>
{
await Task.Delay(60000);
@@ -68,6 +69,7 @@ public class CurrencyRaffleService : INService
catch { }
finally { _locker.Release(); }
});
}
return (crg, null);
}

View File

@@ -182,8 +182,10 @@ public partial class Gambling
.ShopEntries);
entry = entries.ElementAtOrDefault(index);
if (entry is not null)
{
if (entry.Items.Add(item))
uow.SaveChanges();
}
}
await ReplyErrorLocalizedAsync(strs.shop_buy_error);
@@ -193,9 +195,7 @@ public partial class Gambling
await ReplyConfirmLocalizedAsync(strs.shop_item_purchase);
}
else
{
await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
}
}
}
@@ -291,11 +291,13 @@ public partial class Gambling
.ShopEntries);
entry = entries.ElementAtOrDefault(index);
if (entry is not null && (rightType = entry.Type == ShopEntryType.List))
{
if (entry.Items.Add(item))
{
added = true;
uow.SaveChanges();
}
}
}
if (entry is null)
@@ -353,9 +355,7 @@ public partial class Gambling
await ctx.OkAsync();
}
else
{
await ctx.ErrorAsync();
}
}
[Cmd]
@@ -373,9 +373,7 @@ public partial class Gambling
await ctx.OkAsync();
}
else
{
await ctx.ErrorAsync();
}
}
[Cmd]
@@ -393,9 +391,7 @@ public partial class Gambling
await ctx.OkAsync();
}
else
{
await ctx.ErrorAsync();
}
}
[Cmd]
@@ -413,9 +409,7 @@ public partial class Gambling
await ctx.OkAsync();
}
else
{
await ctx.ErrorAsync();
}
}
public IEmbedBuilder EntryToEmbed(ShopEntry entry)
@@ -423,6 +417,7 @@ public partial class Gambling
var embed = _eb.Create().WithOkColor();
if (entry.Type == ShopEntryType.Role)
{
return embed
.AddField(GetText(strs.name),
GetText(strs.shop_role(Format.Bold(ctx.Guild.GetRole(entry.RoleId)?.Name
@@ -430,11 +425,14 @@ public partial class Gambling
true)
.AddField(GetText(strs.price), N(entry.Price), true)
.AddField(GetText(strs.type), entry.Type.ToString(), true);
}
if (entry.Type == ShopEntryType.List)
{
return embed.AddField(GetText(strs.name), entry.Name, true)
.AddField(GetText(strs.price), N(entry.Price), true)
.AddField(GetText(strs.type), GetText(strs.random_unique_item), true);
}
//else if (entry.Type == ShopEntryType.Infinite_List)
// return embed.AddField(GetText(strs.name), GetText(strs.shop_role(Format.Bold(entry.RoleName)), true))

View File

@@ -135,16 +135,20 @@ public partial class Gambling
var (w, result, amount, remaining) = await _service.DivorceWaifuAsync(ctx.User, targetId);
if (result == DivorceResult.SucessWithPenalty)
{
await ReplyConfirmLocalizedAsync(strs.waifu_divorced_like(Format.Bold(w.Waifu.ToString()),
N(amount)));
}
else if (result == DivorceResult.Success)
await ReplyConfirmLocalizedAsync(strs.waifu_divorced_notlike(N(amount)));
else if (result == DivorceResult.NotYourWife)
await ReplyErrorLocalizedAsync(strs.waifu_not_yours);
else
{
await ReplyErrorLocalizedAsync(strs.waifu_recent_divorce(
Format.Bold(((int)remaining?.TotalHours).ToString()),
Format.Bold(remaining?.Minutes.ToString())));
}
}
[Cmd]
@@ -161,11 +165,14 @@ public partial class Gambling
if (!sucess)
{
if (remaining is not null)
{
await ReplyErrorLocalizedAsync(strs.waifu_affinity_cooldown(
Format.Bold(((int)remaining?.TotalHours).ToString()),
Format.Bold(remaining?.Minutes.ToString())));
}
else
await ReplyErrorLocalizedAsync(strs.waifu_affinity_already);
return;
}
@@ -174,8 +181,10 @@ public partial class Gambling
else if (oldAff is null)
await ReplyConfirmLocalizedAsync(strs.waifu_affinity_set(Format.Bold(user.ToString())));
else
{
await ReplyConfirmLocalizedAsync(strs.waifu_affinity_changed(Format.Bold(oldAff.ToString()),
Format.Bold(user.ToString())));
}
}
[Cmd]
@@ -323,8 +332,10 @@ public partial class Gambling
var sucess = await _service.GiftWaifuAsync(ctx.User, waifu, item);
if (sucess)
{
await ReplyConfirmLocalizedAsync(strs.waifu_gift(Format.Bold(item + " " + item.ItemEmoji),
Format.Bold(waifu.ToString())));
}
else
await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
}

View File

@@ -99,7 +99,8 @@ public class WaifuService : INService, IReadyExecutor
.GroupBy(x => x.New)
.Count();
return (long)Math.Ceiling(waifu.Price * 1.25f) + ((divorces + affs + 2) * settings.Waifu.Multipliers.WaifuReset);
return (long)Math.Ceiling(waifu.Price * 1.25f)
+ ((divorces + affs + 2) * settings.Waifu.Multipliers.WaifuReset);
}
public async Task<bool> TryReset(IUser user)
@@ -154,9 +155,7 @@ public class WaifuService : INService, IReadyExecutor
var claimer = uow.GetOrCreateUser(user);
var waifu = uow.GetOrCreateUser(target);
if (!await _cs.RemoveAsync(user.Id, amount, new("waifu", "claim")))
{
result = WaifuClaimResult.NotEnoughFunds;
}
else
{
uow.WaifuInfo.Add(w = new()
@@ -179,9 +178,7 @@ public class WaifuService : INService, IReadyExecutor
else if (isAffinity && amount > w.Price * settings.Waifu.Multipliers.CrushClaim)
{
if (!await _cs.RemoveAsync(user.Id, amount, new("waifu", "claim")))
{
result = WaifuClaimResult.NotEnoughFunds;
}
else
{
var oldClaimer = w.Claimer;
@@ -201,9 +198,7 @@ public class WaifuService : INService, IReadyExecutor
else if (amount >= w.Price * settings.Waifu.Multipliers.NormalClaim) // if no affinity
{
if (!await _cs.RemoveAsync(user.Id, amount, new("waifu", "claim")))
{
result = WaifuClaimResult.NotEnoughFunds;
}
else
{
var oldClaimer = w.Claimer;
@@ -221,9 +216,7 @@ public class WaifuService : INService, IReadyExecutor
}
}
else
{
result = WaifuClaimResult.InsufficientAmount;
}
await uow.SaveChangesAsync();
@@ -311,13 +304,9 @@ public class WaifuService : INService, IReadyExecutor
{
w = uow.WaifuInfo.ByWaifuUserId(targetId);
if (w?.Claimer is null || w.Claimer.UserId != user.Id)
{
result = DivorceResult.NotYourWife;
}
else if (!_cache.TryAddDivorceCooldown(user.Id, out remaining))
{
result = DivorceResult.Cooldown;
}
else
{
amount = w.Price / 2;
@@ -361,6 +350,7 @@ public class WaifuService : INService, IReadyExecutor
await using var uow = _db.GetDbContext();
var w = uow.WaifuInfo.ByWaifuUserId(giftedWaifu.Id, set => set.Include(x => x.Items).Include(x => x.Claimer));
if (w is null)
{
uow.WaifuInfo.Add(w = new()
{
Affinity = null,
@@ -368,6 +358,7 @@ public class WaifuService : INService, IReadyExecutor
Price = 1,
Waifu = uow.GetOrCreateUser(giftedWaifu)
});
}
if (!itemObj.Negative)
{
@@ -399,6 +390,7 @@ public class WaifuService : INService, IReadyExecutor
using var uow = _db.GetDbContext();
var wi = uow.GetWaifuInfo(targetId);
if (wi is null)
{
wi = new()
{
AffinityCount = 0,
@@ -412,6 +404,7 @@ public class WaifuService : INService, IReadyExecutor
Items = new(),
Price = 1
};
}
return wi;
}
@@ -498,7 +491,7 @@ public class WaifuService : INService, IReadyExecutor
// only decay waifu values from shard 0
if (_client.ShardId != 0)
return;
var redisKey = $"{_creds.RedisKey()}_last_waifu_decay";
while (true)
{
@@ -509,9 +502,7 @@ public class WaifuService : INService, IReadyExecutor
var decayInterval = _gss.Data.Waifu.Decay.HourInterval;
if (multi is < 0f or > 1f || decayInterval < 0)
{
continue;
}
var val = await _cache.Redis.GetDatabase().StringGetAsync(redisKey);
if (val != default)
@@ -520,9 +511,7 @@ public class WaifuService : INService, IReadyExecutor
var toWait = decayInterval.Hours() - (DateTime.UtcNow - lastDecay);
if (toWait > 0.Hours())
{
continue;
}
}
await _cache.Redis.GetDatabase().StringSetAsync(redisKey, DateTime.UtcNow.ToBinary());

View File

@@ -18,11 +18,13 @@ public class Betroll
var pair = _thresholdPairs.FirstOrDefault(x => x.WhenAbove < roll);
if (pair is null)
{
return new()
{
Multiplier = 0,
Roll = roll
};
}
return new()
{

View File

@@ -25,6 +25,7 @@ public partial class Games
var game = new AcrophobiaGame(options);
if (_service.AcrophobiaGames.TryAdd(channel.Id, game))
{
try
{
game.OnStarted += Game_OnStarted;
@@ -40,6 +41,7 @@ public partial class Games
_service.AcrophobiaGames.TryRemove(channel.Id, out game);
game?.Dispose();
}
}
else
await ReplyErrorLocalizedAsync(strs.acro_running);

View File

@@ -35,6 +35,7 @@ public sealed class GamesConfigService : ConfigServiceBase<GamesConfig>
private void Migrate()
{
if (data.Version < 1)
{
ModifyConfig(c =>
{
c.Version = 1;
@@ -43,5 +44,6 @@ public sealed class GamesConfigService : ConfigServiceBase<GamesConfig>
CurrencyReward = 0
};
});
}
}
}

View File

@@ -62,9 +62,7 @@ public class GamesService : INService, IReadyExecutor
// reset rating once a day
using var timer = new PeriodicTimer(TimeSpan.FromDays(1));
while (await timer.WaitForNextTickAsync())
{
GirlRatings.Clear();
}
}
private async Task<RatingTexts> GetRatingTexts()

View File

@@ -24,18 +24,23 @@ public partial class Games
public static IEmbedBuilder GetEmbed(IEmbedBuilderService eb, HangmanGame.State state)
{
if (state.Phase == HangmanGame.Phase.Running)
{
return eb.Create()
.WithOkColor()
.AddField("Hangman", Draw(state))
.AddField("Guess", Format.Code(state.Word))
.WithFooter(state.MissedLetters.Join(' '));
}
if (state.Phase == HangmanGame.Phase.Ended && state.Failed)
{
return eb.Create()
.WithErrorColor()
.AddField("Hangman", Draw(state))
.AddField("Guess", Format.Code(state.Word))
.WithFooter(state.MissedLetters.Join(' '));
}
return eb.Create()
.WithOkColor()
.AddField("Hangman", Draw(state))

View File

@@ -87,16 +87,20 @@ public sealed class HangmanService : IHangmanService, ILateExecutor
return;
if (state.GuessResult is HangmanGame.GuessResult.Incorrect or HangmanGame.GuessResult.AlreadyTried)
{
_cdCache.Set(msg.Author.Id,
string.Empty,
new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3)
});
}
if (state.Phase == HangmanGame.Phase.Ended)
{
if (_hangmanGames.TryRemove(msg.Channel.Id, out _))
rew = _gcs.Data.Hangman.CurrencyReward;
}
}
if (rew > 0)

View File

@@ -31,6 +31,7 @@ public partial class Games
}
if (_service.StartPoll(poll))
{
await ctx.Channel.EmbedAsync(_eb.Create()
.WithOkColor()
.WithTitle(GetText(strs.poll_created(ctx.User.ToString())))
@@ -39,6 +40,7 @@ public partial class Games
+ string.Join("\n",
poll.Answers.Select(x
=> $"`{x.Index + 1}.` {Format.Bold(x.Text)}"))));
}
else
await ReplyErrorLocalizedAsync(strs.poll_already_running);
}

View File

@@ -116,11 +116,13 @@ public class PollService : IEarlyBehavior
var voted = await poll.TryVote(msg);
if (voted)
{
Log.Information("User {UserName} [{UserId}] voted in a poll on {GuildName} [{GuildId}] server",
msg.Author.ToString(),
msg.Author.Id,
guild.Name,
guild.Id);
}
return voted;
}

View File

@@ -151,9 +151,11 @@ public class TypingGame
.AddField("Errors", distance.ToString(), true));
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)}**");
}
}
}
catch (Exception ex)

View File

@@ -89,9 +89,7 @@ public class TicTacToe
embed.WithFooter(GetText(strs.ttt_users_move(_users[curUserIndex])));
}
else
{
embed.WithFooter(GetText(strs.ttt_has_won(winner)));
}
return embed;
}

View File

@@ -123,6 +123,7 @@ public class TriviaGame
//hint
await Task.Delay(_options.QuestionTimer * 1000 / 2, triviaCancelSource.Token);
if (!_options.NoHint)
{
try
{
await questionMessage.ModifyAsync(m
@@ -134,6 +135,7 @@ public class TriviaGame
break;
}
catch (Exception ex) { Log.Warning(ex, "Error editing triva message"); }
}
//timeout
await Task.Delay(_options.QuestionTimer * 1000 / 2, triviaCancelSource.Token);
@@ -147,6 +149,7 @@ public class TriviaGame
}
if (!triviaCancelSource.IsCancellationRequested)
{
try
{
var embed = _eb.Create()
@@ -165,6 +168,7 @@ public class TriviaGame
{
Log.Warning(ex, "Error sending trivia time's up message");
}
}
await Task.Delay(5000);
}
@@ -186,6 +190,7 @@ public class TriviaGame
var old = ShouldStopGame;
ShouldStopGame = true;
if (!old)
{
try
{
await Channel.SendConfirmAsync(_eb, GetText(strs.trivia_game), GetText(strs.trivia_stopping));
@@ -194,6 +199,7 @@ public class TriviaGame
{
Log.Warning(ex, "Error sending trivia stopping message");
}
}
}
private Task PotentialGuess(SocketMessage imsg)

View File

@@ -232,13 +232,17 @@ public partial class Help : NadekoModule<HelpService>
{
//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.First(),-15} {"[" + x.Aliases.Skip(1).FirstOrDefault() + "]",-8}";
}
return
$"{prefix + x.Aliases.First(),-15} {"[" + x.Aliases.Skip(1).FirstOrDefault() + "]",-8}";
});
if (i == last - 1 && (i + 1) % 2 != 0)
{
transformed = transformed.Chunk(2)
.Select(x =>
{
@@ -246,6 +250,8 @@ public partial class Help : NadekoModule<HelpService>
return $"{x.First()}";
return string.Concat(x);
});
}
embed.AddField(g.ElementAt(i).Key, "```css\n" + string.Join("\n", transformed) + "\n```", true);
}
}

View File

@@ -288,9 +288,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
// if (mps > 0)
// add += Format.Bold(GetText(strs.song_skips_after(TimeSpan.FromSeconds(mps).ToString("HH\\:mm\\:ss")))) + "\n";
if (repeatType == PlayerRepeatType.Track)
{
add += "🔂 " + GetText(strs.repeating_track) + "\n";
}
else
{
// if (mp.Autoplay)

View File

@@ -69,12 +69,14 @@ public sealed partial class Music
var pl = uow.MusicPlaylists.FirstOrDefault(x => x.Id == id);
if (pl is not null)
{
if (_creds.IsOwner(ctx.User) || pl.AuthorId == ctx.User.Id)
{
uow.MusicPlaylists.Remove(pl);
await uow.SaveChangesAsync();
success = true;
}
}
}
catch (Exception ex)
{

View File

@@ -219,8 +219,10 @@ public sealed class MusicService : IMusicService
=> _ =>
{
if (_settings.TryGetValue(guildId, out var settings))
{
if (settings.AutoDisconnect)
return LeaveVoiceChannelAsync(guildId);
}
return Task.CompletedTask;
};
@@ -232,9 +234,11 @@ public sealed class MusicService : IMusicService
return false;
if (mp.IsStopped)
{
if (!_voiceStateService.TryGetProxy(guildId, out var proxy)
|| proxy.State == VoiceProxy.VoiceProxyState.Stopped)
await JoinVoiceChannelAsync(guildId, voiceChannelId);
}
mp.Next();
return true;

View File

@@ -44,6 +44,7 @@ public class RadioResolver : IRadioResolver
if (query.Contains(".pls"))
//File1=http://armitunes.com:8000/
//Regex.Match(query)
{
try
{
var m = _plsRegex.Match(file);
@@ -55,6 +56,7 @@ public class RadioResolver : IRadioResolver
Log.Warning("Failed reading .pls:\n{PlsFile}", file);
return null;
}
}
if (query.Contains(".m3u"))
/*
@@ -62,6 +64,7 @@ public class RadioResolver : IRadioResolver
C:\xxx4xx\xxxxxx3x\xx2xxxx\xx.mp3
C:\xxx5xx\x6xxxxxx\x7xxxxx\xx.mp3
*/
{
try
{
var m = _m3URegex.Match(file);
@@ -73,9 +76,11 @@ public class RadioResolver : IRadioResolver
Log.Warning("Failed reading .m3u:\n{M3uFile}", file);
return null;
}
}
if (query.Contains(".asx"))
//<ref href="http://armitunes.com:8000"/>
{
try
{
var m = _asxRegex.Match(file);
@@ -87,6 +92,7 @@ public class RadioResolver : IRadioResolver
Log.Warning("Failed reading .asx:\n{AsxFile}", file);
return null;
}
}
if (query.Contains(".xspf"))
/*
@@ -95,6 +101,7 @@ public class RadioResolver : IRadioResolver
<trackList>
<track><location>file:///mp3s/song_1.mp3</location></track>
*/
{
try
{
var m = _xspfRegex.Match(file);
@@ -106,6 +113,7 @@ public class RadioResolver : IRadioResolver
Log.Warning("Failed reading .xspf:\n{XspfFile}", file);
return null;
}
}
return query;
}

View File

@@ -205,9 +205,7 @@ public sealed class YtdlYoutubeResolver : IYoutubeResolver
yield return info;
}
else
{
data += Environment.NewLine;
}
}
await _trackCacher.CachePlaylistTrackIdsAsync(playlistId, MusicPlatform.Youtube, trackIds);

View File

@@ -81,9 +81,7 @@ public partial class NSFW : NadekoModule<ISearchImagesService>
try
{
if (tags is null || tags.Length == 0)
{
await InternalDapiCommand(null, true, _service.Hentai);
}
else
{
var groups = tags.Split('|');

View File

@@ -245,9 +245,7 @@ public class SearchImageCacher : INService
page = _rng.Next(0, maxPage);
}
else
{
page = _rng.Next(0, 11);
}
var result = await DownloadImagesAsync(tags, isExplicit, type, page, cancel);

View File

@@ -75,11 +75,13 @@ public class SearchImagesService : ISearchImagesService, INService
CancellationToken cancel)
{
if (!tags.All(x => IsValidTag(x)))
{
return new()
{
Error = "One or more tags are invalid.",
Url = ""
};
}
Log.Information("Getting {V} image for Guild: {GuildId}...", dapi.ToString(), guildId);
try
@@ -87,27 +89,33 @@ public class SearchImagesService : ISearchImagesService, INService
BlacklistedTags.TryGetValue(guildId, out var blTags);
if (dapi == Booru.E621)
{
for (var i = 0; i < tags.Length; ++i)
{
if (tags[i] == "yuri")
tags[i] = "female/female";
}
}
if (dapi == Booru.Derpibooru)
{
for (var i = 0; i < tags.Length; ++i)
{
if (tags[i] == "yuri")
tags[i] = "lesbian";
}
}
var result = await _cache.GetImageNew(tags, forceExplicit, dapi, blTags ?? new HashSet<string>(), cancel);
if (result is null)
{
return new()
{
Error = "Image not found.",
Url = ""
};
}
var reply = new UrlReply
{

View File

@@ -129,11 +129,15 @@ public partial class Permissions
_service.UnBlacklist(type, id);
if (action == AddRemove.Add)
{
await ReplyConfirmLocalizedAsync(strs.blacklisted(Format.Code(type.ToString()),
Format.Code(id.ToString())));
}
else
{
await ReplyConfirmLocalizedAsync(strs.unblacklisted(Format.Code(type.ToString()),
Format.Code(id.ToString())));
}
}
}
}

View File

@@ -69,9 +69,7 @@ public partial class Permissions
await ReplyConfirmLocalizedAsync(strs.cmdcd_cleared(Format.Bold(name)));
}
else
{
await ReplyConfirmLocalizedAsync(strs.cmdcd_add(Format.Bold(name), Format.Bold(secs.ToString())));
}
}
[Cmd]
@@ -84,10 +82,12 @@ public partial class Permissions
if (!localSet.Any())
await ReplyConfirmLocalizedAsync(strs.cmdcd_none);
else
{
await channel.SendTableAsync("",
localSet.Select(c => c.CommandName + ": " + c.Seconds + GetText(strs.sec)),
s => $"{s,-30}",
2);
}
}
}
}

View File

@@ -230,10 +230,12 @@ public partial class Permissions
removed = config.FilteredWords.FirstOrDefault(fw => fw.Word.Trim().ToLowerInvariant() == word);
if (removed is null)
{
config.FilteredWords.Add(new()
{
Word = word
});
}
else
uow.Remove(removed);

View File

@@ -132,6 +132,7 @@ public sealed class FilterService : IEarlyBehavior
var filteredServerWords = FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet<string>();
var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0)
{
foreach (var word in wordsInMessage)
{
if (filteredChannelWords.Contains(word) || filteredServerWords.Contains(word))
@@ -155,6 +156,7 @@ public sealed class FilterService : IEarlyBehavior
return true;
}
}
}
return false;
}

View File

@@ -43,9 +43,7 @@ public class GlobalPermissionService : ILateBlocker, INService
_bss.ModifyConfig(bs =>
{
if (bs.Blocked.Modules.Add(moduleName))
{
added = true;
}
else
{
bs.Blocked.Modules.Remove(moduleName);
@@ -67,9 +65,7 @@ public class GlobalPermissionService : ILateBlocker, INService
_bss.ModifyConfig(bs =>
{
if (bs.Blocked.Commands.Add(commandName))
{
added = true;
}
else
{
bs.Blocked.Commands.Remove(commandName);

View File

@@ -155,6 +155,7 @@ public partial class Permissions : NadekoModule<PermissionService>
from -= 1;
to -= 1;
if (!(from == to || from < 0 || to < 0))
{
try
{
Permissionv2 fromPerm;
@@ -163,12 +164,12 @@ 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 ReplyErrorLocalizedAsync(strs.perm_not_found(++@from));
return;
}
@@ -178,9 +179,9 @@ public partial class Permissions : NadekoModule<PermissionService>
return;
}
fromPerm = permsCol[from];
fromPerm = permsCol[@from];
permsCol.RemoveAt(from);
permsCol.RemoveAt(@from);
permsCol.Insert(to, fromPerm);
await uow.SaveChangesAsync();
_service.UpdateCache(config);
@@ -188,7 +189,7 @@ public partial class Permissions : NadekoModule<PermissionService>
await ReplyConfirmLocalizedAsync(strs.moved_permission(
Format.Code(fromPerm.GetCommand(prefix, (SocketGuild)ctx.Guild)),
++from,
++@from,
++to));
return;
@@ -196,6 +197,7 @@ public partial class Permissions : NadekoModule<PermissionService>
catch (Exception e) when (e is ArgumentOutOfRangeException or IndexOutOfRangeException)
{
}
}
await ReplyConfirmLocalizedAsync(strs.perm_out_of_range);
}
@@ -257,13 +259,17 @@ 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())));
}
else
{
await ReplyConfirmLocalizedAsync(strs.ux_disable(Format.Code(command.Name),
GetText(strs.of_command),
Format.Code(user.ToString())));
}
}
[Cmd]
@@ -281,13 +287,17 @@ 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())));
}
else
{
await ReplyConfirmLocalizedAsync(strs.ux_disable(Format.Code(module.Name),
GetText(strs.of_module),
Format.Code(user.ToString())));
}
}
[Cmd]
@@ -309,13 +319,17 @@ 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)));
}
else
{
await ReplyConfirmLocalizedAsync(strs.rx_disable(Format.Code(command.Name),
GetText(strs.of_command),
Format.Code(role.Name)));
}
}
[Cmd]
@@ -337,13 +351,17 @@ 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)));
}
else
{
await ReplyConfirmLocalizedAsync(strs.rx_disable(Format.Code(module.Name),
GetText(strs.of_module),
Format.Code(role.Name)));
}
}
[Cmd]
@@ -362,13 +380,17 @@ 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)));
}
else
{
await ReplyConfirmLocalizedAsync(strs.cx_disable(Format.Code(command.Name),
GetText(strs.of_command),
Format.Code(chnl.Name)));
}
}
[Cmd]
@@ -386,13 +408,17 @@ 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)));
}
else
{
await ReplyConfirmLocalizedAsync(strs.cx_disable(Format.Code(module.Name),
GetText(strs.of_module),
Format.Code(chnl.Name)));
}
}
[Cmd]

View File

@@ -112,6 +112,7 @@ public class PermissionService : ILateBlocker, INService
if (!resetCommand && !pc.Permissions.CheckPermissions(msg, commandName, moduleName, out var index))
{
if (pc.Verbose)
{
try
{
await channel.SendErrorAsync(_eb,
@@ -123,6 +124,7 @@ public class PermissionService : ILateBlocker, INService
catch
{
}
}
return true;
}
@@ -145,8 +147,10 @@ public class PermissionService : ILateBlocker, INService
{
returnMsg = "You need Admin permissions in order to use permission commands.";
if (pc.Verbose)
{
try { await channel.SendErrorAsync(_eb, returnMsg); }
catch { }
}
return true;
}
@@ -155,8 +159,10 @@ public class PermissionService : ILateBlocker, 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); }
catch { }
}
return true;
}

View File

@@ -65,6 +65,7 @@ public partial class Searches
var favAnime = GetText(strs.anime_no_fav);
if (favorites.Length > 0 && favorites[0].QuerySelector("p") is null)
{
favAnime = string.Join("\n",
favorites[0]
.QuerySelectorAll("ul > li > div.di-tc.va-t > a")
@@ -75,6 +76,7 @@ public partial class Searches
var elem = (IHtmlAnchorElement)x;
return $"[{elem.InnerHtml}]({elem.Href})";
}));
}
var info = document.QuerySelectorAll("ul.user-status:nth-child(3) > li.clearfix")
.Select(x => Tuple.Create(x.Children[0].InnerHtml, x.Children[1].InnerHtml))

View File

@@ -1,5 +1,6 @@
#nullable disable
using NadekoBot.Modules.Searches.Services;
using System.Globalization;
namespace NadekoBot.Modules.Searches;
@@ -36,30 +37,50 @@ public partial class Searches
var usd = crypto.Quote["USD"];
var sevenDay = usd.PercentChange7d.ToString("F2", Culture);
var lastDay = usd.PercentChange24h.ToString("F2", Culture);
var localCulture = (CultureInfo)Culture.Clone();
localCulture.NumberFormat.CurrencySymbol = "$";
var sevenDay = (usd.PercentChange7d / 100).ToString("P2", localCulture);
var lastDay = (usd.PercentChange24h / 100).ToString("P2", localCulture);
var price = usd.Price < 0.01
? usd.Price.ToString(Culture)
: usd.Price.ToString("F2", Culture);
? usd.Price.ToString(localCulture)
: usd.Price.ToString("C2", localCulture);
var volume = usd.Volume24h.ToString("n0", Culture);
var marketCap = usd.MarketCap.ToString("n0", Culture);
var volume = usd.Volume24h.ToString("C0", localCulture);
var marketCap = usd.MarketCap.ToString("C0", localCulture);
var dominance = (usd.MarketCapDominance / 100).ToString("P2", localCulture);
await ctx.Channel.EmbedAsync(_eb.Create()
.WithOkColor()
.WithAuthor($"#{crypto.CmcRank}")
.WithTitle($"{crypto.Name} ({crypto.Symbol})")
.WithUrl($"https://coinmarketcap.com/currencies/{crypto.Slug}/")
.WithThumbnailUrl(
$"https://s3.coinmarketcap.com/static/img/coins/128x128/{crypto.Id}.png")
.AddField(GetText(strs.market_cap),
$"${marketCap}",
true)
.AddField(GetText(strs.price), $"${price}", true)
.AddField(GetText(strs.volume_24h), $"${volume}", true)
.AddField(GetText(strs.change_7d_24h), $"{sevenDay}% / {lastDay}%", true)
.WithImageUrl(
$"https://s3.coinmarketcap.com/generated/sparklines/web/7d/usd/{crypto.Id}.png"));
var toSend = _eb.Create()
.WithOkColor()
.WithAuthor($"#{crypto.CmcRank}")
.WithTitle($"{crypto.Name} ({crypto.Symbol})")
.WithUrl($"https://coinmarketcap.com/currencies/{crypto.Slug}/")
.WithThumbnailUrl( $"https://s3.coinmarketcap.com/static/img/coins/128x128/{crypto.Id}.png")
.AddField(GetText(strs.market_cap), marketCap, true)
.AddField(GetText(strs.price), price, true)
.AddField(GetText(strs.volume_24h), volume, true)
.AddField(GetText(strs.change_7d_24h), $"{sevenDay} / {lastDay}", true)
.AddField(GetText(strs.market_cap_dominance), dominance, true)
.WithImageUrl($"https://s3.coinmarketcap.com/generated/sparklines/web/7d/usd/{crypto.Id}.png");
if (crypto.CirculatingSupply is double cs)
{
var csStr = cs.ToString("N0", localCulture);
if (crypto.MaxSupply is double ms)
{
var perc = (cs / ms).ToString("P1", localCulture);
toSend.AddField(GetText(strs.circulating_supply), $"{csStr} ({perc})", true);
}
else
{
toSend.AddField(GetText(strs.circulating_supply), csStr, true);
}
}
await ctx.Channel.EmbedAsync(toSend);
}
}
}

View File

@@ -69,8 +69,10 @@ public class FeedsService : INService
.ToList();
if (!_lastPosts.TryGetValue(kvp.Key, out var lastFeedUpdate))
{
lastFeedUpdate = _lastPosts[kvp.Key] =
items.Any() ? items[items.Count - 1].LastUpdate : DateTime.UtcNow;
}
foreach (var (feedItem, itemUpdateDate) in items)
{
@@ -106,8 +108,10 @@ public class FeedsService : INService
.FirstOrDefault(x => x.Name.LocalName == "preview");
if (previewElement is null)
{
previewElement = afi.Element.Elements()
.FirstOrDefault(x => x.Name.LocalName == "thumbnail");
}
if (previewElement is not null)
{

View File

@@ -251,9 +251,7 @@ public partial class Searches
// poe.ninja API does not include a "chaosEquivalent" property for Chaos Orbs.
if (cleanCurrency == "Chaos Orb")
{
chaosEquivalent = 1.0F;
}
else
{
var currencyInput = obj["lines"]
@@ -265,9 +263,7 @@ public partial class Searches
}
if (cleanConvert == "Chaos Orb")
{
conversionEquivalent = 1.0F;
}
else
{
var currencyOutput = obj["lines"]

View File

@@ -60,9 +60,7 @@ public partial class Searches : NadekoModule<SearchesService>
var data = await _service.GetWeatherDataAsync(query);
if (data is null)
{
embed.WithDescription(GetText(strs.city_not_found)).WithErrorColor();
}
else
{
var f = StandardConversions.CelsiusToFahrenheit;
@@ -284,6 +282,7 @@ public partial class Searches : NadekoModule<SearchesService>
query = query.Trim();
if (!_cachedShortenedLinks.TryGetValue(query, out var shortLink))
{
try
{
using var http = _httpFactory.CreateClient();
@@ -310,6 +309,7 @@ public partial class Searches : NadekoModule<SearchesService>
Log.Error(ex, "Error shortening a link: {Message}", ex.Message);
return;
}
}
await ctx.Channel.EmbedAsync(_eb.Create()
.WithOkColor()
@@ -693,9 +693,7 @@ 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.");
}
else
{
var v = obj.Verses[0];

View File

@@ -76,9 +76,7 @@ public class SearchesService : INService
Log.Warning("data/magicitems.json is missing. Magic items are not loaded");
if (File.Exists("data/yomama.txt"))
{
_yomamaJokes = File.ReadAllLines("data/yomama.txt").Shuffle().ToList();
}
else
{
_yomamaJokes = new();

View File

@@ -172,8 +172,10 @@ public partial class Searches
}
if (data.IsLive)
{
await ReplyConfirmLocalizedAsync(strs.streamer_online(Format.Bold(data.Name),
Format.Bold(data.Viewers.ToString())));
}
else
await ReplyConfirmLocalizedAsync(strs.streamer_offline(data.Name));
}

View File

@@ -127,7 +127,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
{
if (_client.ShardId != 0)
return;
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(30));
while (await timer.WaitForNextTickAsync())
{
@@ -185,10 +185,12 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
if (_trackCounter.ContainsKey(key))
_trackCounter[key].Add(info.GuildId);
else
{
_trackCounter[key] = new()
{
info.GuildId
};
}
}
return default;
@@ -230,6 +232,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
{
var key = stream.CreateKey();
if (_shardTrackedStreams.TryGetValue(key, out var fss))
{
await fss
// send offline stream notifications only to guilds which enable it with .stoff
.SelectMany(x => x.Value)
@@ -238,6 +241,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
?.GetTextChannel(fs.ChannelId)
?.EmbedAsync(GetEmbed(fs.GuildId, stream)))
.WhenAll();
}
}
}
@@ -247,6 +251,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
{
var key = stream.CreateKey();
if (_shardTrackedStreams.TryGetValue(key, out var fss))
{
await fss.SelectMany(x => x.Value)
.Select(fs =>
{
@@ -264,6 +269,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
return textChannel.EmbedAsync(GetEmbed(fs.GuildId, stream), message);
})
.WhenAll();
}
}
}

View File

@@ -15,9 +15,12 @@ public class ImageCacherObject : IComparable<ImageCacherObject>
if (type == Booru.Danbooru && !Uri.IsWellFormedUriString(obj.FileUrl, UriKind.Absolute))
FileUrl = "https://danbooru.donmai.us" + obj.FileUrl;
else
{
FileUrl = obj.FileUrl.StartsWith("http", StringComparison.InvariantCulture)
? obj.FileUrl
: "https:" + obj.FileUrl;
}
SearchType = type;
Rating = obj.Rating;
Tags = new((obj.Tags ?? obj.TagString).Split(' '));

Some files were not shown because too many files have changed in this diff Show More