You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DiscordChatExporter/DiscordChatExporter.Core/Exporting/PlainTextMarkdownVisitor.cs

116 lines
3.5 KiB

using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DiscordChatExporter.Core.Markdown;
using DiscordChatExporter.Core.Markdown.Parsing;
using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Core.Exporting;
internal partial class PlainTextMarkdownVisitor : MarkdownVisitor
{
private readonly ExportContext _context;
private readonly StringBuilder _buffer;
public PlainTextMarkdownVisitor(ExportContext context, StringBuilder buffer)
{
_context = context;
_buffer = buffer;
}
protected override ValueTask VisitTextAsync(
TextNode text,
CancellationToken cancellationToken = default)
{
_buffer.Append(text.Text);
return default;
}
protected override ValueTask VisitEmojiAsync(
EmojiNode emoji,
CancellationToken cancellationToken = default)
{
_buffer.Append(
emoji.IsCustomEmoji
? $":{emoji.Name}:"
: emoji.Name
);
return default;
}
protected override async ValueTask VisitMentionAsync(MentionNode mention,
CancellationToken cancellationToken = default)
{
if (mention.Kind == MentionKind.Everyone)
{
_buffer.Append("@everyone");
}
else if (mention.Kind == MentionKind.Here)
{
_buffer.Append("@here");
}
else if (mention.Kind == MentionKind.User)
{
// User mentions are not always included in the message object,
// which means they need to be populated on demand.
// https://github.com/Tyrrrz/DiscordChatExporter/issues/304
if (mention.TargetId is not null)
await _context.PopulateMemberAsync(mention.TargetId.Value, cancellationToken);
var member = mention.TargetId?.Pipe(_context.TryGetMember);
var name = member?.User.Name ?? "Unknown";
_buffer.Append($"@{name}");
}
else if (mention.Kind == MentionKind.Channel)
{
var channel = mention.TargetId?.Pipe(_context.TryGetChannel);
var name = channel?.Name ?? "deleted-channel";
_buffer.Append($"#{name}");
// Voice channel marker
if (channel?.IsVoice == true)
_buffer.Append(" [voice]");
}
else if (mention.Kind == MentionKind.Role)
{
var role = mention.TargetId?.Pipe(_context.TryGetRole);
var name = role?.Name ?? "deleted-role";
_buffer.Append($"@{name}");
}
}
protected override ValueTask VisitTimestampAsync(
TimestampNode timestamp,
CancellationToken cancellationToken = default)
{
_buffer.Append(
timestamp.Instant is not null
? !string.IsNullOrWhiteSpace(timestamp.Format)
? timestamp.Instant.Value.ToLocalString(timestamp.Format)
: _context.FormatDate(timestamp.Instant.Value)
: "Invalid date"
);
return default;
}
}
internal partial class PlainTextMarkdownVisitor
{
public static async ValueTask<string> FormatAsync(
ExportContext context,
string markdown,
CancellationToken cancellationToken = default)
{
var nodes = MarkdownParser.ParseMinimal(markdown);
var buffer = new StringBuilder();
await new PlainTextMarkdownVisitor(context, buffer).VisitAsync(nodes, cancellationToken);
return buffer.ToString();
}
}