mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
* dev: Greet stuff moved to its own table in the database. GreetSettings
* fix: Fixed placeholders not working * fix: Fixed some countries in countries.yml for hangman game * add: Added custom status overload for \`.adpl\` * dev: Removed some unused strings * fix: Fixed postgres support in Nadeko * remove: Removed mysql support, it was broken for a while and some queries weren't compiling. * dev: Updated image library * fix: Some command strings fixed and clarified
This commit is contained in:
@@ -71,6 +71,22 @@ public static class EnumerableExtensions
|
||||
this IEnumerable<KeyValuePair<TKey, TValue>> dict)
|
||||
where TKey : notnull
|
||||
=> new(dict);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDictionary{TKey,TValue}" /> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}" />
|
||||
/// has the default concurrency level, has the default initial capacity,
|
||||
/// and uses the default comparer for the key type.
|
||||
/// </summary>
|
||||
/// <param name="dict">
|
||||
/// The <see cref="IEnumerable{T}" /> whose elements are copied to the new
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}" />.
|
||||
/// </param>
|
||||
/// <returns>A new instance of the <see cref="ConcurrentDictionary{TKey,TValue}" /> class</returns>
|
||||
public static ConcurrentHashSet<TValue> ToConcurrentSet<TValue>(
|
||||
this IReadOnlyCollection<TValue> dict)
|
||||
where TValue : notnull
|
||||
=> new(dict);
|
||||
|
||||
public static IndexedCollection<T> ToIndexed<T>(this IEnumerable<T> enumerable)
|
||||
where T : class, IIndexed
|
||||
|
@@ -13,7 +13,7 @@ namespace NadekoBot.Common.Configs;
|
||||
public sealed partial class BotConfig : ICloneable<BotConfig>
|
||||
{
|
||||
[Comment("""DO NOT CHANGE""")]
|
||||
public int Version { get; set; } = 7;
|
||||
public int Version { get; set; } = 8;
|
||||
|
||||
[Comment("""
|
||||
Most commands, when executed, have a small colored line
|
||||
@@ -85,19 +85,6 @@ public sealed partial class BotConfig : ICloneable<BotConfig>
|
||||
[Comment("""Which string will be used to recognize the commands""")]
|
||||
public string Prefix { get; set; }
|
||||
|
||||
[Comment("""
|
||||
Toggles whether your bot will group greet/bye messages into a single message every 5 seconds.
|
||||
1st user who joins will get greeted immediately
|
||||
If more users join within the next 5 seconds, they will be greeted in groups of 5.
|
||||
This will cause %user.mention% and other placeholders to be replaced with multiple users.
|
||||
Keep in mind this might break some of your embeds - for example if you have %user.avatar% in the thumbnail,
|
||||
it will become invalid, as it will resolve to a list of avatars of grouped users.
|
||||
note: This setting is primarily used if you're afraid of raids, or you're running medium/large bots where some
|
||||
servers might get hundreds of people join at once. This is used to prevent the bot from getting ratelimited,
|
||||
and (slightly) reduce the greet spam in those servers.
|
||||
""")]
|
||||
public bool GroupGreets { get; set; }
|
||||
|
||||
[Comment("""
|
||||
Whether the bot will rotate through all specified statuses.
|
||||
This setting can be changed via .ropl command.
|
||||
@@ -145,7 +132,6 @@ public sealed partial class BotConfig : ICloneable<BotConfig>
|
||||
Blocked = blocked;
|
||||
Prefix = ".";
|
||||
RotateStatuses = false;
|
||||
GroupGreets = false;
|
||||
DmHelpTextKeywords =
|
||||
[
|
||||
"help",
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace NadekoBot.Common;
|
||||
|
@@ -7,7 +7,7 @@ public sealed class ReplacementContext
|
||||
public DiscordSocketClient? Client { get; }
|
||||
public IGuild? Guild { get; }
|
||||
public IMessageChannel? Channel { get; }
|
||||
public IUser[]? Users { get; }
|
||||
public IUser? User { get; }
|
||||
|
||||
private readonly List<ReplacementInfo> _overrides = new();
|
||||
private readonly HashSet<string> _tokens = new();
|
||||
@@ -21,10 +21,11 @@ public sealed class ReplacementContext
|
||||
public IReadOnlyList<RegexReplacementInfo> RegexOverrides
|
||||
=> _regexOverrides.AsReadOnly();
|
||||
|
||||
public ReplacementContext(ICommandContext cmdContext) : this(cmdContext.Client as DiscordSocketClient,
|
||||
cmdContext.Guild,
|
||||
cmdContext.Channel,
|
||||
cmdContext.User)
|
||||
public ReplacementContext(ICommandContext cmdContext)
|
||||
: this(cmdContext.Client as DiscordSocketClient,
|
||||
cmdContext.Guild,
|
||||
cmdContext.Channel,
|
||||
cmdContext.User)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -32,12 +33,12 @@ public sealed class ReplacementContext
|
||||
DiscordSocketClient? client = null,
|
||||
IGuild? guild = null,
|
||||
IMessageChannel? channel = null,
|
||||
params IUser[]? users)
|
||||
IUser? user = null)
|
||||
{
|
||||
Client = client;
|
||||
Guild = guild;
|
||||
Channel = channel;
|
||||
Users = users;
|
||||
User = user;
|
||||
}
|
||||
|
||||
public ReplacementContext WithOverride(string key, Func<ValueTask<string>> repFactory)
|
||||
|
@@ -61,6 +61,18 @@ public sealed partial class ReplacementPatternStore
|
||||
|
||||
private void WithUsers()
|
||||
{
|
||||
Register("%user%", static (IUser user) => user.Mention);
|
||||
Register("%user.mention%", static (IUser user) => user.Mention);
|
||||
Register("%user.fullname%", static (IUser user) => user.ToString()!);
|
||||
Register("%user.name%", static (IUser user) => user.Username);
|
||||
Register("%user.discrim%", static (IUser user) => user.Discriminator);
|
||||
Register("%user.avatar%", static (IUser user) => user.RealAvatarUrl().ToString());
|
||||
Register("%user.id%", static (IUser user) => user.Id.ToString());
|
||||
Register("%user.created_time%", static (IUser user) => user.CreatedAt.ToString("HH:mm"));
|
||||
Register("%user.created_date%", static (IUser user) => user.CreatedAt.ToString("dd.MM.yyyy"));
|
||||
Register("%user.joined_time%", static (IGuildUser user) => user.JoinedAt?.ToString("HH:mm"));
|
||||
Register("%user.joined_date%", static (IGuildUser user) => user.JoinedAt?.ToString("dd.MM.yyyy"));
|
||||
|
||||
Register("%user%",
|
||||
static (IUser[] users) => string.Join(" ", users.Select(user => user.Mention)));
|
||||
Register("%user.mention%",
|
||||
|
@@ -40,8 +40,8 @@ public sealed class ReplacementService : IReplacementService, INService
|
||||
if (repCtx.Guild is not null)
|
||||
obj.Add(repCtx.Guild);
|
||||
|
||||
if (repCtx.Users is not null)
|
||||
obj.Add(repCtx.Users);
|
||||
if (repCtx.User is not null)
|
||||
obj.Add(repCtx.User);
|
||||
|
||||
if (repCtx.Channel is not null)
|
||||
obj.Add(repCtx.Channel);
|
||||
@@ -86,9 +86,9 @@ public sealed class ReplacementService : IReplacementService, INService
|
||||
objs.Add(repCtx.Channel);
|
||||
}
|
||||
|
||||
if (repCtx.Users is not null)
|
||||
if (repCtx.User is not null)
|
||||
{
|
||||
objs.Add(repCtx.Users);
|
||||
objs.Add(repCtx.User);
|
||||
}
|
||||
|
||||
if (repCtx.Guild is not null)
|
||||
@@ -117,9 +117,9 @@ public sealed class ReplacementService : IReplacementService, INService
|
||||
objs.Add(repCtx.Channel);
|
||||
}
|
||||
|
||||
if (repCtx.Users is not null)
|
||||
if (repCtx.User is not null)
|
||||
{
|
||||
objs.Add(repCtx.Users);
|
||||
objs.Add(repCtx.User);
|
||||
}
|
||||
|
||||
if (repCtx.Guild is not null)
|
||||
|
@@ -9,8 +9,8 @@ public sealed partial class Replacer
|
||||
private readonly IEnumerable<RegexReplacementInfo> _regexReps;
|
||||
private readonly object[] _inputData;
|
||||
|
||||
[GeneratedRegex(@"\%[\p{L}\p{N}\._]*[\p{L}\p{N}]+[\p{L}\p{N}\._]*\%")]
|
||||
private static partial Regex TokenExtractionRegex();
|
||||
// [GeneratedRegex(@"\%[\p{L}\p{N}\._]*[\p{L}\p{N}]+[\p{L}\p{N}\._]*\%")]
|
||||
// private static partial Regex TokenExtractionRegex();
|
||||
|
||||
public Replacer(IEnumerable<ReplacementInfo> reps, IEnumerable<RegexReplacementInfo> regexReps, object[] inputData)
|
||||
{
|
||||
@@ -24,19 +24,19 @@ public sealed partial class Replacer
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return input;
|
||||
|
||||
var matches = TokenExtractionRegex().IsMatch(input);
|
||||
// var matches = TokenExtractionRegex().IsMatch(input);
|
||||
|
||||
if (matches)
|
||||
// if (matches)
|
||||
// {
|
||||
foreach (var rep in _reps)
|
||||
{
|
||||
foreach (var rep in _reps)
|
||||
if (input.Contains(rep.Token, StringComparison.InvariantCulture))
|
||||
{
|
||||
if (input.Contains(rep.Token, StringComparison.InvariantCulture))
|
||||
{
|
||||
var objs = GetParams(rep.InputTypes);
|
||||
input = input.Replace(rep.Token, await rep.GetValueAsync(objs), StringComparison.InvariantCulture);
|
||||
}
|
||||
var objs = GetParams(rep.InputTypes);
|
||||
input = input.Replace(rep.Token, await rep.GetValueAsync(objs), StringComparison.InvariantCulture);
|
||||
}
|
||||
}
|
||||
// }
|
||||
|
||||
foreach (var rep in _regexReps)
|
||||
{
|
||||
@@ -47,7 +47,7 @@ public sealed partial class Replacer
|
||||
if (match.Success)
|
||||
{
|
||||
sb.Append(input, 0, match.Index)
|
||||
.Append(await rep.GetValueAsync(match, objs));
|
||||
.Append(await rep.GetValueAsync(match, objs));
|
||||
|
||||
var lastIndex = match.Index + match.Length;
|
||||
sb.Append(input, lastIndex, input.Length - lastIndex);
|
||||
@@ -91,16 +91,18 @@ public sealed partial class Replacer
|
||||
=> new()
|
||||
{
|
||||
Embeds = await embedArr.Embeds.Map(async e => await ReplaceAsync(e) with
|
||||
{
|
||||
Color = e.Color
|
||||
}).WhenAll(),
|
||||
{
|
||||
Color = e.Color
|
||||
})
|
||||
.WhenAll(),
|
||||
Content = await ReplaceAsync(embedArr.Content)
|
||||
};
|
||||
|
||||
private async ValueTask<SmartPlainText> ReplaceAsync(SmartPlainText plain)
|
||||
=> await ReplaceAsync(plain.Text);
|
||||
|
||||
private async Task<T> ReplaceAsync<T>(T embedData) where T : SmartEmbedTextBase, new()
|
||||
private async Task<T> ReplaceAsync<T>(T embedData)
|
||||
where T : SmartEmbedTextBase, new()
|
||||
{
|
||||
var newEmbedData = new T
|
||||
{
|
||||
@@ -117,13 +119,14 @@ public sealed partial class Replacer
|
||||
IconUrl = await ReplaceAsync(embedData.Author.IconUrl)
|
||||
},
|
||||
Fields = await Task.WhenAll(embedData
|
||||
.Fields?
|
||||
.Map(async f => new SmartTextEmbedField
|
||||
{
|
||||
Name = await ReplaceAsync(f.Name),
|
||||
Value = await ReplaceAsync(f.Value),
|
||||
Inline = f.Inline
|
||||
}) ?? []),
|
||||
.Fields?
|
||||
.Map(async f => new SmartTextEmbedField
|
||||
{
|
||||
Name = await ReplaceAsync(f.Name),
|
||||
Value = await ReplaceAsync(f.Value),
|
||||
Inline = f.Inline
|
||||
})
|
||||
?? []),
|
||||
Footer = embedData.Footer is null
|
||||
? null
|
||||
: new()
|
||||
|
@@ -69,5 +69,11 @@ public sealed class BotConfigService : ConfigServiceBase<BotConfig>
|
||||
c.Version = 7;
|
||||
c.IgnoreOtherBots = true;
|
||||
});
|
||||
|
||||
if(data.Version < 8)
|
||||
ModifyConfig(c =>
|
||||
{
|
||||
c.Version = 8;
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user