Use snowflakes in more places

This commit is contained in:
Oleksii Holub 2022-02-06 01:15:56 +02:00
parent 2467caac9f
commit d51d0d4872
7 changed files with 36 additions and 33 deletions

View file

@ -10,14 +10,14 @@ namespace DiscordChatExporter.Core.Discord.Data;
// https://discord.com/developers/docs/resources/emoji#emoji-object // https://discord.com/developers/docs/resources/emoji#emoji-object
public partial record Emoji( public partial record Emoji(
// Only present on custom emoji // Only present on custom emoji
string? Id, Snowflake? Id,
// Name of custom emoji (e.g. LUL) or actual representation of standard emoji (e.g. 🙂) // Name of custom emoji (e.g. LUL) or actual representation of standard emoji (e.g. 🙂)
string Name, string Name,
bool IsAnimated, bool IsAnimated,
string ImageUrl) string ImageUrl)
{ {
// Name of custom emoji (e.g. LUL) or name of standard emoji (e.g. slight_smile) // Name of custom emoji (e.g. LUL) or name of standard emoji (e.g. slight_smile)
public string Code => !string.IsNullOrWhiteSpace(Id) public string Code => Id is not null
? Name ? Name
: EmojiIndex.TryGetCode(Name) ?? Name; : EmojiIndex.TryGetCode(Name) ?? Name;
} }
@ -32,18 +32,18 @@ public partial record Emoji
.Select(r => r.Value.ToString("x")) .Select(r => r.Value.ToString("x"))
); );
private static string GetImageUrl(string id, bool isAnimated) => isAnimated private static string GetImageUrl(Snowflake id, bool isAnimated) => isAnimated
? $"https://cdn.discordapp.com/emojis/{id}.gif" ? $"https://cdn.discordapp.com/emojis/{id}.gif"
: $"https://cdn.discordapp.com/emojis/{id}.png"; : $"https://cdn.discordapp.com/emojis/{id}.png";
private static string GetImageUrl(string name) => private static string GetImageUrl(string name) =>
$"https://twemoji.maxcdn.com/2/svg/{GetTwemojiName(name)}.svg"; $"https://twemoji.maxcdn.com/2/svg/{GetTwemojiName(name)}.svg";
public static string GetImageUrl(string? id, string? name, bool isAnimated) public static string GetImageUrl(Snowflake? id, string? name, bool isAnimated)
{ {
// Custom emoji // Custom emoji
if (!string.IsNullOrWhiteSpace(id)) if (id is not null)
return GetImageUrl(id, isAnimated); return GetImageUrl(id.Value, isAnimated);
// Standard emoji // Standard emoji
if (!string.IsNullOrWhiteSpace(name)) if (!string.IsNullOrWhiteSpace(name))
@ -55,7 +55,7 @@ public partial record Emoji
public static Emoji Parse(JsonElement json) public static Emoji Parse(JsonElement json)
{ {
var id = json.GetPropertyOrNull("id")?.GetNonWhiteSpaceStringOrNull(); var id = json.GetPropertyOrNull("id")?.GetNonWhiteSpaceStringOrNull()?.Pipe(Snowflake.Parse);
var name = json.GetPropertyOrNull("name")?.GetNonWhiteSpaceStringOrNull(); var name = json.GetPropertyOrNull("name")?.GetNonWhiteSpaceStringOrNull();
var isAnimated = json.GetPropertyOrNull("animated")?.GetBooleanOrNull() ?? false; var isAnimated = json.GetPropertyOrNull("animated")?.GetBooleanOrNull() ?? false;

View file

@ -169,7 +169,7 @@ internal class JsonMessageWriter : MessageWriter
// Emoji // Emoji
_writer.WriteStartObject("emoji"); _writer.WriteStartObject("emoji");
_writer.WriteString("id", reaction.Emoji.Id); _writer.WriteString("id", reaction.Emoji.Id.ToString());
_writer.WriteString("name", reaction.Emoji.Name); _writer.WriteString("name", reaction.Emoji.Name);
_writer.WriteBoolean("isAnimated", reaction.Emoji.IsAnimated); _writer.WriteBoolean("isAnimated", reaction.Emoji.IsAnimated);
_writer.WriteString("imageUrl", await Context.ResolveMediaUrlAsync(reaction.Emoji.ImageUrl, cancellationToken)); _writer.WriteString("imageUrl", await Context.ResolveMediaUrlAsync(reaction.Emoji.ImageUrl, cancellationToken));

View file

@ -3,7 +3,6 @@ using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Core.Markdown; using DiscordChatExporter.Core.Markdown;
using DiscordChatExporter.Core.Markdown.Parsing; using DiscordChatExporter.Core.Markdown.Parsing;
@ -108,17 +107,16 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor
protected override MarkdownNode VisitMention(MentionNode mention) protected override MarkdownNode VisitMention(MentionNode mention)
{ {
var mentionId = Snowflake.TryParse(mention.Id);
if (mention.Kind == MentionKind.Meta) if (mention.Kind == MentionKind.Meta)
{ {
_buffer _buffer
.Append("<span class=\"mention\">") .Append("<span class=\"mention\">")
.Append("@").Append(HtmlEncode(mention.Id)) .Append("@").Append(HtmlEncode(mention.Id.ToString()))
.Append("</span>"); .Append("</span>");
} }
else if (mention.Kind == MentionKind.User) else if (mention.Kind == MentionKind.User)
{ {
var member = mentionId?.Pipe(_context.TryGetMember); var member = _context.TryGetMember(mention.Id);
var fullName = member?.User.FullName ?? "Unknown"; var fullName = member?.User.FullName ?? "Unknown";
var nick = member?.Nick ?? "Unknown"; var nick = member?.Nick ?? "Unknown";
@ -129,7 +127,7 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor
} }
else if (mention.Kind == MentionKind.Channel) else if (mention.Kind == MentionKind.Channel)
{ {
var channel = mentionId?.Pipe(_context.TryGetChannel); var channel = _context.TryGetChannel(mention.Id);
var symbol = channel?.IsVoiceChannel == true ? "🔊" : "#"; var symbol = channel?.IsVoiceChannel == true ? "🔊" : "#";
var name = channel?.Name ?? "deleted-channel"; var name = channel?.Name ?? "deleted-channel";
@ -140,7 +138,7 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor
} }
else if (mention.Kind == MentionKind.Role) else if (mention.Kind == MentionKind.Role)
{ {
var role = mentionId?.Pipe(_context.TryGetRole); var role = _context.TryGetRole(mention.Id);
var name = role?.Name ?? "deleted-role"; var name = role?.Name ?? "deleted-role";
var color = role?.Color; var color = role?.Color;

View file

@ -1,8 +1,6 @@
using System.Text; using System.Text;
using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Core.Markdown; using DiscordChatExporter.Core.Markdown;
using DiscordChatExporter.Core.Markdown.Parsing; using DiscordChatExporter.Core.Markdown.Parsing;
using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors; namespace DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors;
@ -36,21 +34,20 @@ internal partial class PlainTextMarkdownVisitor : MarkdownVisitor
protected override MarkdownNode VisitMention(MentionNode mention) protected override MarkdownNode VisitMention(MentionNode mention)
{ {
var mentionId = Snowflake.TryParse(mention.Id);
if (mention.Kind == MentionKind.Meta) if (mention.Kind == MentionKind.Meta)
{ {
_buffer.Append($"@{mention.Id}"); _buffer.Append($"@{mention.Id}");
} }
else if (mention.Kind == MentionKind.User) else if (mention.Kind == MentionKind.User)
{ {
var member = mentionId?.Pipe(_context.TryGetMember); var member = _context.TryGetMember(mention.Id);
var name = member?.User.Name ?? "Unknown"; var name = member?.User.Name ?? "Unknown";
_buffer.Append($"@{name}"); _buffer.Append($"@{name}");
} }
else if (mention.Kind == MentionKind.Channel) else if (mention.Kind == MentionKind.Channel)
{ {
var channel = mentionId?.Pipe(_context.TryGetChannel); var channel = _context.TryGetChannel(mention.Id);
var name = channel?.Name ?? "deleted-channel"; var name = channel?.Name ?? "deleted-channel";
_buffer.Append($"#{name}"); _buffer.Append($"#{name}");
@ -61,7 +58,7 @@ internal partial class PlainTextMarkdownVisitor : MarkdownVisitor
} }
else if (mention.Kind == MentionKind.Role) else if (mention.Kind == MentionKind.Role)
{ {
var role = mentionId?.Pipe(_context.TryGetRole); var role = _context.TryGetRole(mention.Id);
var name = role?.Name ?? "deleted-role"; var name = role?.Name ?? "deleted-role";
_buffer.Append($"@{name}"); _buffer.Append($"@{name}");

View file

@ -1,21 +1,22 @@
using DiscordChatExporter.Core.Utils; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Core.Utils;
namespace DiscordChatExporter.Core.Markdown; namespace DiscordChatExporter.Core.Markdown;
internal record EmojiNode( internal record EmojiNode(
// Only present on custom emoji // Only present on custom emoji
string? Id, Snowflake? Id,
// Name of custom emoji (e.g. LUL) or actual representation of standard emoji (e.g. 🙂) // Name of custom emoji (e.g. LUL) or actual representation of standard emoji (e.g. 🙂)
string Name, string Name,
bool IsAnimated) : MarkdownNode bool IsAnimated) : MarkdownNode
{ {
public bool IsCustomEmoji => Id is not null;
// Name of custom emoji (e.g. LUL) or name of standard emoji (e.g. slight_smile) // Name of custom emoji (e.g. LUL) or name of standard emoji (e.g. slight_smile)
public string Code => !string.IsNullOrWhiteSpace(Id) public string Code => IsCustomEmoji
? Name ? Name
: EmojiIndex.TryGetCode(Name) ?? Name; : EmojiIndex.TryGetCode(Name) ?? Name;
public bool IsCustomEmoji => !string.IsNullOrWhiteSpace(Id);
public EmojiNode(string name) public EmojiNode(string name)
: this(null, name, false) : this(null, name, false)
{ {

View file

@ -1,3 +1,5 @@
namespace DiscordChatExporter.Core.Markdown; using DiscordChatExporter.Core.Discord;
internal record MentionNode(string Id, MentionKind Kind) : MarkdownNode; namespace DiscordChatExporter.Core.Markdown;
internal record MentionNode(Snowflake Id, MentionKind Kind) : MarkdownNode;

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Core.Utils; using DiscordChatExporter.Core.Utils;
namespace DiscordChatExporter.Core.Markdown.Parsing; namespace DiscordChatExporter.Core.Markdown.Parsing;
@ -123,31 +124,31 @@ internal static partial class MarkdownParser
// Capture @everyone // Capture @everyone
private static readonly IMatcher<MarkdownNode> EveryoneMentionNodeMatcher = new StringMatcher<MarkdownNode>( private static readonly IMatcher<MarkdownNode> EveryoneMentionNodeMatcher = new StringMatcher<MarkdownNode>(
"@everyone", "@everyone",
_ => new MentionNode("everyone", MentionKind.Meta) _ => new MentionNode(Snowflake.Zero, MentionKind.Meta)
); );
// Capture @here // Capture @here
private static readonly IMatcher<MarkdownNode> HereMentionNodeMatcher = new StringMatcher<MarkdownNode>( private static readonly IMatcher<MarkdownNode> HereMentionNodeMatcher = new StringMatcher<MarkdownNode>(
"@here", "@here",
_ => new MentionNode("here", MentionKind.Meta) _ => new MentionNode(Snowflake.Zero, MentionKind.Meta)
); );
// Capture <@123456> or <@!123456> // Capture <@123456> or <@!123456>
private static readonly IMatcher<MarkdownNode> UserMentionNodeMatcher = new RegexMatcher<MarkdownNode>( private static readonly IMatcher<MarkdownNode> UserMentionNodeMatcher = new RegexMatcher<MarkdownNode>(
new Regex("<@!?(\\d+)>", DefaultRegexOptions), new Regex("<@!?(\\d+)>", DefaultRegexOptions),
(_, m) => new MentionNode(m.Groups[1].Value, MentionKind.User) (_, m) => new MentionNode(Snowflake.Parse(m.Groups[1].Value), MentionKind.User)
); );
// Capture <#123456> // Capture <#123456>
private static readonly IMatcher<MarkdownNode> ChannelMentionNodeMatcher = new RegexMatcher<MarkdownNode>( private static readonly IMatcher<MarkdownNode> ChannelMentionNodeMatcher = new RegexMatcher<MarkdownNode>(
new Regex("<#!?(\\d+)>", DefaultRegexOptions), new Regex("<#!?(\\d+)>", DefaultRegexOptions),
(_, m) => new MentionNode(m.Groups[1].Value, MentionKind.Channel) (_, m) => new MentionNode(Snowflake.Parse(m.Groups[1].Value), MentionKind.Channel)
); );
// Capture <@&123456> // Capture <@&123456>
private static readonly IMatcher<MarkdownNode> RoleMentionNodeMatcher = new RegexMatcher<MarkdownNode>( private static readonly IMatcher<MarkdownNode> RoleMentionNodeMatcher = new RegexMatcher<MarkdownNode>(
new Regex("<@&(\\d+)>", DefaultRegexOptions), new Regex("<@&(\\d+)>", DefaultRegexOptions),
(_, m) => new MentionNode(m.Groups[1].Value, MentionKind.Role) (_, m) => new MentionNode(Snowflake.Parse(m.Groups[1].Value), MentionKind.Role)
); );
/* Emoji */ /* Emoji */
@ -177,7 +178,11 @@ internal static partial class MarkdownParser
// Capture <:lul:123456> or <a:lul:123456> // Capture <:lul:123456> or <a:lul:123456>
private static readonly IMatcher<MarkdownNode> CustomEmojiNodeMatcher = new RegexMatcher<MarkdownNode>( private static readonly IMatcher<MarkdownNode> CustomEmojiNodeMatcher = new RegexMatcher<MarkdownNode>(
new Regex("<(a)?:(.+?):(\\d+?)>", DefaultRegexOptions), new Regex("<(a)?:(.+?):(\\d+?)>", DefaultRegexOptions),
(_, m) => new EmojiNode(m.Groups[3].Value, m.Groups[2].Value, !string.IsNullOrWhiteSpace(m.Groups[1].Value)) (_, m) => new EmojiNode(
Snowflake.Parse(m.Groups[3].Value),
m.Groups[2].Value,
!string.IsNullOrWhiteSpace(m.Groups[1].Value)
)
); );
/* Links */ /* Links */