mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
Full support for embed arrays in .greet/.bye, .say and other commands which use embeds
- Website to create them is live at eb2.nadeko.bot (it will soon be replacing eb.nadeko.bot) - Embed arrays don't have a plainText property (it's renamed to 'content') - Embed arrays use color hex values instead of an integer - Old embed format will still work - There shouldn't be any breaking changes
This commit is contained in:
@@ -34,69 +34,59 @@ public class Replacer
|
|||||||
public SmartText Replace(SmartText data)
|
public SmartText Replace(SmartText data)
|
||||||
=> data switch
|
=> data switch
|
||||||
{
|
{
|
||||||
SmartEmbedText embedData => Replace(embedData),
|
SmartEmbedText embedData => Replace(embedData) with
|
||||||
|
{
|
||||||
|
PlainText = Replace(embedData.PlainText),
|
||||||
|
Color = embedData.Color
|
||||||
|
},
|
||||||
SmartPlainText plain => Replace(plain),
|
SmartPlainText plain => Replace(plain),
|
||||||
SmartEmbedTextArray arr => Replace(arr),
|
SmartEmbedTextArray arr => Replace(arr),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(data), "Unsupported argument type")
|
_ => throw new ArgumentOutOfRangeException(nameof(data), "Unsupported argument type")
|
||||||
};
|
};
|
||||||
|
|
||||||
public SmartEmbedTextArray Replace(SmartEmbedTextArray embedArr)
|
private SmartEmbedTextArray Replace(SmartEmbedTextArray embedArr)
|
||||||
=> new()
|
=> new()
|
||||||
{
|
{
|
||||||
Embeds = embedArr.Embeds.Map(Replace),
|
Embeds = embedArr.Embeds.Map(e => Replace(e) with
|
||||||
PlainText = Replace(embedArr.PlainText)
|
{
|
||||||
|
Color = e.Color
|
||||||
|
}),
|
||||||
|
Content = Replace(embedArr.Content)
|
||||||
};
|
};
|
||||||
|
|
||||||
public SmartPlainText Replace(SmartPlainText plainText)
|
private SmartPlainText Replace(SmartPlainText plain)
|
||||||
=> Replace(plainText.Text);
|
=> Replace(plain.Text);
|
||||||
|
|
||||||
public SmartEmbedText Replace(SmartEmbedText embedData)
|
private T Replace<T>(T embedData) where T: SmartEmbedTextBase, new()
|
||||||
{
|
{
|
||||||
var newEmbedData = new SmartEmbedText
|
var newEmbedData = new T
|
||||||
{
|
{
|
||||||
PlainText = Replace(embedData.PlainText),
|
|
||||||
Description = Replace(embedData.Description),
|
Description = Replace(embedData.Description),
|
||||||
Title = Replace(embedData.Title),
|
Title = Replace(embedData.Title),
|
||||||
Thumbnail = Replace(embedData.Thumbnail),
|
Thumbnail = Replace(embedData.Thumbnail),
|
||||||
Image = Replace(embedData.Image),
|
Image = Replace(embedData.Image),
|
||||||
Url = Replace(embedData.Url)
|
Url = Replace(embedData.Url),
|
||||||
};
|
Author = embedData.Author is null
|
||||||
if (embedData.Author is not null)
|
? null
|
||||||
{
|
: new()
|
||||||
newEmbedData.Author = new()
|
|
||||||
{
|
|
||||||
Name = Replace(embedData.Author.Name),
|
|
||||||
IconUrl = Replace(embedData.Author.IconUrl)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (embedData.Fields is not null)
|
|
||||||
{
|
|
||||||
var fields = new List<SmartTextEmbedField>();
|
|
||||||
foreach (var f in embedData.Fields)
|
|
||||||
{
|
|
||||||
var newF = new SmartTextEmbedField
|
|
||||||
{
|
{
|
||||||
Name = Replace(f.Name),
|
Name = Replace(embedData.Author.Name),
|
||||||
Value = Replace(f.Value),
|
IconUrl = Replace(embedData.Author.IconUrl)
|
||||||
Inline = f.Inline
|
},
|
||||||
};
|
Fields = embedData.Fields?.Map(f => new SmartTextEmbedField
|
||||||
fields.Add(newF);
|
|
||||||
}
|
|
||||||
|
|
||||||
newEmbedData.Fields = fields.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (embedData.Footer is not null)
|
|
||||||
{
|
|
||||||
newEmbedData.Footer = new()
|
|
||||||
{
|
{
|
||||||
Text = Replace(embedData.Footer.Text),
|
Name = Replace(f.Name),
|
||||||
IconUrl = Replace(embedData.Footer.IconUrl)
|
Value = Replace(f.Value),
|
||||||
};
|
Inline = f.Inline
|
||||||
}
|
}),
|
||||||
|
Footer = embedData.Footer is null
|
||||||
newEmbedData.Color = embedData.Color;
|
? null
|
||||||
|
: new()
|
||||||
|
{
|
||||||
|
Text = Replace(embedData.Footer.Text),
|
||||||
|
IconUrl = Replace(embedData.Footer.IconUrl)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return newEmbedData;
|
return newEmbedData;
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +1,64 @@
|
|||||||
#nullable disable
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
namespace NadekoBot;
|
namespace NadekoBot;
|
||||||
|
|
||||||
public sealed record SmartEmbedText : SmartText
|
public sealed record SmartEmbedArrayElementText : SmartEmbedTextBase
|
||||||
{
|
{
|
||||||
public string PlainText { get; set; }
|
public string Color { get; init; } = string.Empty;
|
||||||
public string Title { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public string Url { get; set; }
|
|
||||||
public string Thumbnail { get; set; }
|
|
||||||
public string Image { get; set; }
|
|
||||||
|
|
||||||
public SmartTextEmbedAuthor Author { get; set; }
|
public SmartEmbedArrayElementText() : base()
|
||||||
public SmartTextEmbedFooter Footer { get; set; }
|
{
|
||||||
public SmartTextEmbedField[] Fields { get; set; }
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public SmartEmbedArrayElementText(IEmbed eb) : base(eb)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public uint Color { get; set; } = 7458112;
|
protected override EmbedBuilder GetEmbedInternal()
|
||||||
|
{
|
||||||
|
var embed = base.GetEmbedInternal();
|
||||||
|
return embed.WithColor(Rgba32.ParseHex(Color).ToDiscordColor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed record SmartEmbedText : SmartEmbedTextBase
|
||||||
|
{
|
||||||
|
public string PlainText { get; init; }
|
||||||
|
|
||||||
|
public uint Color { get; init; } = 7458112;
|
||||||
|
|
||||||
|
public SmartEmbedText()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmartEmbedText(IEmbed eb, string plainText = null)
|
||||||
|
: base(eb)
|
||||||
|
=> (PlainText, Color) = (plainText, eb.Color?.RawValue ?? 0);
|
||||||
|
|
||||||
|
public static SmartEmbedText FromEmbed(IEmbed eb, string plainText = null)
|
||||||
|
=> new(eb, plainText);
|
||||||
|
|
||||||
|
protected override EmbedBuilder GetEmbedInternal()
|
||||||
|
{
|
||||||
|
var embed = base.GetEmbedInternal();
|
||||||
|
return embed.WithColor(Color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract record SmartEmbedTextBase : SmartText
|
||||||
|
{
|
||||||
|
public string Title { get; init; }
|
||||||
|
public string Description { get; init; }
|
||||||
|
public string Url { get; init; }
|
||||||
|
public string Thumbnail { get; init; }
|
||||||
|
public string Image { get; init; }
|
||||||
|
|
||||||
|
public SmartTextEmbedAuthor Author { get; init; }
|
||||||
|
public SmartTextEmbedFooter Footer { get; init; }
|
||||||
|
public SmartTextEmbedField[] Fields { get; init; }
|
||||||
|
|
||||||
public bool IsValid
|
public bool IsValid
|
||||||
=> !string.IsNullOrWhiteSpace(Title)
|
=> !string.IsNullOrWhiteSpace(Title)
|
||||||
@@ -26,36 +70,37 @@ public sealed record SmartEmbedText : SmartText
|
|||||||
&& (!string.IsNullOrWhiteSpace(Footer.Text) || !string.IsNullOrWhiteSpace(Footer.IconUrl)))
|
&& (!string.IsNullOrWhiteSpace(Footer.Text) || !string.IsNullOrWhiteSpace(Footer.IconUrl)))
|
||||||
|| Fields is { Length: > 0 };
|
|| Fields is { Length: > 0 };
|
||||||
|
|
||||||
public static SmartEmbedText FromEmbed(IEmbed eb, string plainText = null)
|
protected SmartEmbedTextBase()
|
||||||
{
|
{
|
||||||
var set = new SmartEmbedText
|
|
||||||
{
|
}
|
||||||
PlainText = plainText,
|
|
||||||
Title = eb.Title,
|
protected SmartEmbedTextBase(IEmbed eb)
|
||||||
Description = eb.Description,
|
{
|
||||||
Url = eb.Url,
|
Title = eb.Title;
|
||||||
Thumbnail = eb.Thumbnail?.Url,
|
Description = eb.Description;
|
||||||
Image = eb.Image?.Url,
|
Url = eb.Url;
|
||||||
Author = eb.Author is { } ea
|
Thumbnail = eb.Thumbnail?.Url;
|
||||||
? new()
|
Image = eb.Image?.Url;
|
||||||
{
|
Author = eb.Author is { } ea
|
||||||
Name = ea.Name,
|
? new()
|
||||||
Url = ea.Url,
|
{
|
||||||
IconUrl = ea.IconUrl
|
Name = ea.Name,
|
||||||
}
|
Url = ea.Url,
|
||||||
: null,
|
IconUrl = ea.IconUrl
|
||||||
Footer = eb.Footer is { } ef
|
}
|
||||||
? new()
|
: null;
|
||||||
{
|
Footer = eb.Footer is { } ef
|
||||||
Text = ef.Text,
|
? new()
|
||||||
IconUrl = ef.IconUrl
|
{
|
||||||
}
|
Text = ef.Text,
|
||||||
: null
|
IconUrl = ef.IconUrl
|
||||||
};
|
}
|
||||||
|
: null;
|
||||||
|
|
||||||
if (eb.Fields.Length > 0)
|
if (eb.Fields.Length > 0)
|
||||||
{
|
{
|
||||||
set.Fields = eb.Fields.Select(field
|
Fields = eb.Fields.Select(field
|
||||||
=> new SmartTextEmbedField
|
=> new SmartTextEmbedField
|
||||||
{
|
{
|
||||||
Inline = field.Inline,
|
Inline = field.Inline,
|
||||||
@@ -64,14 +109,14 @@ public sealed record SmartEmbedText : SmartText
|
|||||||
})
|
})
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
set.Color = eb.Color?.RawValue ?? 0;
|
|
||||||
return set;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public EmbedBuilder GetEmbed()
|
public EmbedBuilder GetEmbed()
|
||||||
|
=> GetEmbedInternal();
|
||||||
|
|
||||||
|
protected virtual EmbedBuilder GetEmbedInternal()
|
||||||
{
|
{
|
||||||
var embed = new EmbedBuilder().WithColor(Color);
|
var embed = new EmbedBuilder();
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(Title))
|
if (!string.IsNullOrWhiteSpace(Title))
|
||||||
embed.WithTitle(Title);
|
embed.WithTitle(Title);
|
||||||
|
@@ -3,8 +3,8 @@ namespace NadekoBot;
|
|||||||
|
|
||||||
public sealed record SmartEmbedTextArray : SmartText
|
public sealed record SmartEmbedTextArray : SmartText
|
||||||
{
|
{
|
||||||
public string PlainText { get; set; }
|
public string Content { get; set; }
|
||||||
public SmartEmbedText[] Embeds { get; set; }
|
public SmartEmbedArrayElementText[] Embeds { get; set; }
|
||||||
|
|
||||||
public bool IsValid
|
public bool IsValid
|
||||||
=> Embeds?.All(x => x.IsValid) ?? false;
|
=> Embeds?.All(x => x.IsValid) ?? false;
|
||||||
|
@@ -30,7 +30,7 @@ public abstract record SmartText
|
|||||||
SmartPlainText spt => new SmartPlainText(spt.Text + input),
|
SmartPlainText spt => new SmartPlainText(spt.Text + input),
|
||||||
SmartEmbedTextArray arr => arr with
|
SmartEmbedTextArray arr => arr with
|
||||||
{
|
{
|
||||||
PlainText = arr.PlainText + input
|
Content = arr.Content + input
|
||||||
},
|
},
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
||||||
};
|
};
|
||||||
@@ -45,7 +45,7 @@ public abstract record SmartText
|
|||||||
SmartPlainText spt => new SmartPlainText(input + spt.Text),
|
SmartPlainText spt => new SmartPlainText(input + spt.Text),
|
||||||
SmartEmbedTextArray arr => arr with
|
SmartEmbedTextArray arr => arr with
|
||||||
{
|
{
|
||||||
PlainText = input + arr.PlainText
|
Content = input + arr.Content
|
||||||
},
|
},
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
||||||
};
|
};
|
||||||
|
@@ -256,15 +256,54 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
{
|
{
|
||||||
text = new SmartEmbedText()
|
text = new SmartEmbedText()
|
||||||
{
|
{
|
||||||
PlainText = pt.Text
|
Description = pt.Text
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
else if (text is SmartEmbedText set)
|
||||||
((SmartEmbedText)text).Footer = new()
|
|
||||||
{
|
{
|
||||||
Text = $"This message was sent from {user.Guild} server.",
|
text = set with
|
||||||
IconUrl = user.Guild.IconUrl
|
{
|
||||||
};
|
Footer = CreateFooterSource(user)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (text is SmartEmbedTextArray seta)
|
||||||
|
{
|
||||||
|
// if the greet dm message is a text array
|
||||||
|
var ebElem = seta.Embeds.LastOrDefault();
|
||||||
|
if (ebElem is null)
|
||||||
|
{
|
||||||
|
// if there are no embeds, add an embed with the footer
|
||||||
|
text = seta with
|
||||||
|
{
|
||||||
|
Embeds = new[]
|
||||||
|
{
|
||||||
|
new SmartEmbedArrayElementText()
|
||||||
|
{
|
||||||
|
Footer = CreateFooterSource(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if the maximum amount of embeds is reached, edit the last embed
|
||||||
|
if (seta.Embeds.Length >= 10)
|
||||||
|
{
|
||||||
|
seta.Embeds[^1] = seta.Embeds[^1] with
|
||||||
|
{
|
||||||
|
Footer = CreateFooterSource(user)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if there is less than 10 embeds, add an embed with footer only
|
||||||
|
seta.Embeds = seta.Embeds.Append(new SmartEmbedArrayElementText()
|
||||||
|
{
|
||||||
|
Footer = CreateFooterSource(user)
|
||||||
|
}).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await user.SendAsync(text);
|
await user.SendAsync(text);
|
||||||
}
|
}
|
||||||
@@ -276,6 +315,13 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static SmartTextEmbedFooter CreateFooterSource(IGuildUser user)
|
||||||
|
=> new()
|
||||||
|
{
|
||||||
|
Text = $"This message was sent from {user.Guild} server.",
|
||||||
|
IconUrl = user.Guild.IconUrl
|
||||||
|
};
|
||||||
|
|
||||||
private Task OnUserJoined(IGuildUser user)
|
private Task OnUserJoined(IGuildUser user)
|
||||||
{
|
{
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
|
@@ -84,13 +84,12 @@ public class PatreonRewardsService : INService, IReadyExecutor
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var http = _httpFactory.CreateClient();
|
using var http = _httpFactory.CreateClient();
|
||||||
using var content = new StringContent(string.Empty);
|
|
||||||
using var res = await http.PostAsync("https://www.patreon.com/api/oauth2/token"
|
using var res = await http.PostAsync("https://www.patreon.com/api/oauth2/token"
|
||||||
+ "?grant_type=refresh_token"
|
+ "?grant_type=refresh_token"
|
||||||
+ $"&refresh_token={creds.Patreon.RefreshToken}"
|
+ $"&refresh_token={creds.Patreon.RefreshToken}"
|
||||||
+ $"&client_id={creds.Patreon.ClientId}"
|
+ $"&client_id={creds.Patreon.ClientId}"
|
||||||
+ $"&client_secret={creds.Patreon.ClientSecret}",
|
+ $"&client_secret={creds.Patreon.ClientSecret}",
|
||||||
content);
|
null);
|
||||||
|
|
||||||
res.EnsureSuccessStatusCode();
|
res.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
@@ -149,7 +148,7 @@ public class PatreonRewardsService : INService, IReadyExecutor
|
|||||||
if (!success)
|
if (!success)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LastUpdate = DateTime.UtcNow;
|
LastUpdate = DateTime.UtcNow;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -8,6 +8,7 @@ public interface IWallet
|
|||||||
public Task<bool> Take(long amount, TxData txData);
|
public Task<bool> Take(long amount, TxData txData);
|
||||||
public Task Add(long amount, TxData txData);
|
public Task Add(long amount, TxData txData);
|
||||||
|
|
||||||
|
// todo message
|
||||||
public async Task<bool> Transfer(
|
public async Task<bool> Transfer(
|
||||||
long amount,
|
long amount,
|
||||||
IWallet to,
|
IWallet to,
|
||||||
|
@@ -53,9 +53,8 @@ public sealed class BotCredsProvider : IBotCredsProvider
|
|||||||
_config = new ConfigurationBuilder().AddYamlFile(CredsPath, false, true)
|
_config = new ConfigurationBuilder().AddYamlFile(CredsPath, false, true)
|
||||||
.AddEnvironmentVariables("NadekoBot_")
|
.AddEnvironmentVariables("NadekoBot_")
|
||||||
.Build();
|
.Build();
|
||||||
#if !GLOBAL_NADEKO
|
|
||||||
_changeToken = ChangeToken.OnChange(() => _config.GetReloadToken(), Reload);
|
_changeToken = ChangeToken.OnChange(() => _config.GetReloadToken(), Reload);
|
||||||
#endif
|
|
||||||
Reload();
|
Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,7 +26,7 @@ public static class Extensions
|
|||||||
SmartEmbedTextArray set => msg.ModifyAsync(x =>
|
SmartEmbedTextArray set => msg.ModifyAsync(x =>
|
||||||
{
|
{
|
||||||
x.Embeds = set.GetEmbedBuilders().Map(eb => eb.Build());
|
x.Embeds = set.GetEmbedBuilders().Map(eb => eb.Build());
|
||||||
x.Content = set.PlainText?.SanitizeMentions() ?? "";
|
x.Content = set.Content?.SanitizeMentions() ?? "";
|
||||||
}),
|
}),
|
||||||
SmartPlainText spt => msg.ModifyAsync(x =>
|
SmartPlainText spt => msg.ModifyAsync(x =>
|
||||||
{
|
{
|
||||||
|
@@ -30,7 +30,7 @@ public static class MessageChannelExtensions
|
|||||||
{
|
{
|
||||||
SmartEmbedText set => channel.SendAsync(set.PlainText, set.GetEmbed().Build(), sanitizeAll: sanitizeAll),
|
SmartEmbedText set => channel.SendAsync(set.PlainText, set.GetEmbed().Build(), sanitizeAll: sanitizeAll),
|
||||||
SmartPlainText st => channel.SendAsync(st.Text, null, sanitizeAll: sanitizeAll),
|
SmartPlainText st => channel.SendAsync(st.Text, null, sanitizeAll: sanitizeAll),
|
||||||
SmartEmbedTextArray arr => channel.SendAsync(arr.PlainText,
|
SmartEmbedTextArray arr => channel.SendAsync(arr.Content,
|
||||||
embeds: arr.GetEmbedBuilders().Map(e => e.Build())),
|
embeds: arr.GetEmbedBuilders().Map(e => e.Build())),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user