diff --git a/DiscordChatExporter.Core/DiscordChatExporter.Core.csproj b/DiscordChatExporter.Core/DiscordChatExporter.Core.csproj index ad97b73..517e1db 100644 --- a/DiscordChatExporter.Core/DiscordChatExporter.Core.csproj +++ b/DiscordChatExporter.Core/DiscordChatExporter.Core.csproj @@ -15,6 +15,7 @@ + diff --git a/DiscordChatExporter.Core/Models/ExportFormat.cs b/DiscordChatExporter.Core/Models/ExportFormat.cs index 726fd9d..aca8307 100644 --- a/DiscordChatExporter.Core/Models/ExportFormat.cs +++ b/DiscordChatExporter.Core/Models/ExportFormat.cs @@ -4,6 +4,7 @@ { PlainText, HtmlDark, - HtmlLight + HtmlLight, + Csv } } \ No newline at end of file diff --git a/DiscordChatExporter.Core/Models/Extensions.cs b/DiscordChatExporter.Core/Models/Extensions.cs index 0f021f2..90817b9 100644 --- a/DiscordChatExporter.Core/Models/Extensions.cs +++ b/DiscordChatExporter.Core/Models/Extensions.cs @@ -12,6 +12,8 @@ namespace DiscordChatExporter.Core.Models return "html"; if (format == ExportFormat.HtmlLight) return "html"; + if (format == ExportFormat.Csv) + return "csv"; throw new ArgumentOutOfRangeException(nameof(format)); } @@ -24,6 +26,8 @@ namespace DiscordChatExporter.Core.Models return "HTML (Dark)"; if (format == ExportFormat.HtmlLight) return "HTML (Light)"; + if (format == ExportFormat.Csv) + return "Comma Seperated Values (CSV)"; throw new ArgumentOutOfRangeException(nameof(format)); } diff --git a/DiscordChatExporter.Core/Services/ExportService.Csv.cs b/DiscordChatExporter.Core/Services/ExportService.Csv.cs new file mode 100644 index 0000000..d3c6a30 --- /dev/null +++ b/DiscordChatExporter.Core/Services/ExportService.Csv.cs @@ -0,0 +1,85 @@ +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using CsvHelper; +using DiscordChatExporter.Core.Models; +using Tyrrrz.Extensions; + +namespace DiscordChatExporter.Core.Services +{ + public partial class ExportService + { + private string FormatMessageContentCsv(Message message) + { + var content = message.Content; + + // New lines + content = content.Replace("\n", ", "); + + // User mentions (<@id> and <@!id>) + foreach (var mentionedUser in message.MentionedUsers) + content = Regex.Replace(content, $"<@!?{mentionedUser.Id}>", $"@{mentionedUser}"); + + // Role mentions (<@&id>) + foreach (var mentionedRole in message.MentionedRoles) + content = content.Replace($"<@&{mentionedRole.Id}>", $"@{mentionedRole.Name}"); + + // Channel mentions (<#id>) + foreach (var mentionedChannel in message.MentionedChannels) + content = content.Replace($"<#{mentionedChannel.Id}>", $"#{mentionedChannel.Name}"); + + // Custom emojis (<:name:id>) + content = Regex.Replace(content, "<(:.*?:)\\d*>", "$1"); + + return content; + } + + private async Task ExportAsCsvAsync(ChannelChatLog log, TextWriter output) + { + using (var writer = new CsvWriter(output)) + { + // Generation info + writer.WriteComment("https://github.com/Tyrrrz/DiscordChatExporter"); + + // Guild and channel info + writer.WriteComment($"Guild: {log.Guild.Name}"); + writer.WriteComment($"Channel: {log.Channel.Name}"); + writer.WriteComment($"Topic: {log.Channel.Topic}"); + writer.WriteComment($"Messages: {log.TotalMessageCount:N0}"); + + // Headers + writer.WriteField("Author"); + writer.WriteField("Date"); + writer.WriteField("Content"); + writer.WriteField("Attachments"); + await writer.NextRecordAsync(); + + // Chat log + foreach (var group in log.MessageGroups) + { + // Messages + foreach (var msg in group.Messages) + { + // Author + writer.WriteField(msg.Author.FullName, true); + + // Date + var timeStampFormatted = msg.TimeStamp.ToString(_settingsService.DateFormat); + writer.WriteField(timeStampFormatted); + + // Content + var contentFormatted = msg.Content.IsNotBlank() ? FormatMessageContentCsv(msg) : null; + writer.WriteField(contentFormatted, true); + + // Attachments + var attachmentsFormatted = msg.Attachments.Select(a => a.Url).JoinToString(","); + writer.WriteField(attachmentsFormatted, true); + + await writer.NextRecordAsync(); + } + } + } + } + } +} diff --git a/DiscordChatExporter.Core/Services/ExportService.cs b/DiscordChatExporter.Core/Services/ExportService.cs index da7dba1..fe6b4ae 100644 --- a/DiscordChatExporter.Core/Services/ExportService.cs +++ b/DiscordChatExporter.Core/Services/ExportService.cs @@ -41,6 +41,11 @@ namespace DiscordChatExporter.Core.Services await ExportAsHtmlAsync(log, output, css); } + else if (format == ExportFormat.Csv) + { + await ExportAsCsvAsync(log, output); + } + else throw new ArgumentOutOfRangeException(nameof(format)); } }