using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors; using DiscordChatExporter.Core.Utils.Extensions; namespace DiscordChatExporter.Core.Exporting.Writers { internal partial class CsvMessageWriter : MessageWriter { private readonly TextWriter _writer; public CsvMessageWriter(Stream stream, ExportContext context) : base(stream, context) { _writer = new StreamWriter(stream); } private string FormatMarkdown(string? markdown) => PlainTextMarkdownVisitor.Format(Context, markdown ?? ""); public override async ValueTask WritePreambleAsync() => await _writer.WriteLineAsync("AuthorID,Author,Date,Content,Attachments,Reactions"); private async ValueTask WriteAttachmentsAsync(IReadOnlyList attachments) { var buffer = new StringBuilder(); foreach (var attachment in attachments) { buffer .AppendIfNotEmpty(',') .Append(await Context.ResolveMediaUrlAsync(attachment.Url)); } await _writer.WriteAsync(CsvEncode(buffer.ToString())); } private async ValueTask WriteReactionsAsync(IReadOnlyList reactions) { var buffer = new StringBuilder(); foreach (var reaction in reactions) { buffer .AppendIfNotEmpty(',') .Append(reaction.Emoji.Name) .Append(' ') .Append('(') .Append(reaction.Count) .Append(')'); } await _writer.WriteAsync(CsvEncode(buffer.ToString())); } public override async ValueTask WriteMessageAsync(Message message) { await base.WriteMessageAsync(message); // Author ID await _writer.WriteAsync(CsvEncode(message.Author.Id.ToString())); await _writer.WriteAsync(','); // Author name await _writer.WriteAsync(CsvEncode(message.Author.FullName)); await _writer.WriteAsync(','); // Message timestamp await _writer.WriteAsync(CsvEncode(Context.FormatDate(message.Timestamp))); await _writer.WriteAsync(','); // Message content await _writer.WriteAsync(CsvEncode(FormatMarkdown(message.Content))); await _writer.WriteAsync(','); // Attachments await WriteAttachmentsAsync(message.Attachments); await _writer.WriteAsync(','); // Reactions await WriteReactionsAsync(message.Reactions); // Finish row await _writer.WriteLineAsync(); } public override async ValueTask DisposeAsync() { await _writer.DisposeAsync(); await base.DisposeAsync(); } } internal partial class CsvMessageWriter { private static string CsvEncode(string value) { value = value.Replace("\"", "\"\""); return $"\"{value}\""; } } }