();
+ foreach (var message in messages)
+ {
+ var bufferFirst = buffer.FirstOrDefault();
+
+ // Group break condition
+ bool breakCondition =
+ bufferFirst != null &&
+ (
+ message.Author.Id != bufferFirst.Author.Id ||
+ (message.TimeStamp - bufferFirst.TimeStamp).TotalHours > 1 ||
+ message.TimeStamp.Hour != bufferFirst.TimeStamp.Hour
+ );
+
+ // If condition is true - flush buffer
+ if (breakCondition)
+ {
+ var group = new MessageGroup(bufferFirst.Author, bufferFirst.TimeStamp, buffer);
+ result.Add(group);
+ buffer.Clear();
+ }
+
+ // Add message to buffer
+ buffer.Add(message);
+ }
+
+ // Add what's remaining in buffer
+ if (buffer.Any())
+ {
+ var bufferFirst = buffer.First();
+ var group = new MessageGroup(bufferFirst.Author, bufferFirst.TimeStamp, buffer);
+ result.Add(group);
+ }
+
+ return result;
+ }
+
+ private string FormatMessageContent(string content)
+ {
+ // Encode HTML
+ content = HtmlDocument.HtmlEncode(content);
+
+ // Links from URLs
+ content = Regex.Replace(content, "((^|\\s)(https?|ftp)://[^\\s/$.?#].[^\\s]*($|\\s))",
+ "$1");
+
+ // Preformatted multiline
+ content = Regex.Replace(content, "```([^`]*?)```", e => "" + e.Groups[1].Value + "
");
+
+ // Preformatted
+ content = Regex.Replace(content, "`([^`]*?)`", e => "" + e.Groups[1].Value + "
");
+
+ // Bold
+ content = Regex.Replace(content, "\\*\\*([^\\*]*?)\\*\\*", "$1");
+
+ // Italic
+ content = Regex.Replace(content, "\\*([^\\*]*?)\\*", "$1");
+
+ // Underline
+ content = Regex.Replace(content, "__([^_]*?)__", "$1");
+
+ // Strike through
+ content = Regex.Replace(content, "~~([^~]*?)~~", "$1");
+
+ // New lines
+ content = content.Replace("\n", "");
+
+ return content;
+ }
+
+ public void Export(string filePath, ChatLog chatLog)
+ {
+ var doc = GetTemplate();
+
+ // Info
+ var infoHtml = doc.GetElementbyId("info");
+ infoHtml.AppendChild(HtmlNode.CreateNode($"Channel ID: {chatLog.ChannelId}
"));
+ string participants = HtmlDocument.HtmlEncode(chatLog.Participants.Select(u => u.Name).JoinToString(", "));
+ infoHtml.AppendChild(HtmlNode.CreateNode($"Participants: {participants}
"));
+ infoHtml.AppendChild(HtmlNode.CreateNode($"Messages: {chatLog.Messages.Count:N0}
"));
+
+ // Messages
+ var logHtml = doc.GetElementbyId("log");
+ var messageGroups = GroupMessages(chatLog.Messages);
+ foreach (var messageGroup in messageGroups)
+ {
+ // Container
+ var messageHtml = logHtml.AppendChild(HtmlNode.CreateNode(""));
+
+ // Avatar
+ messageHtml.AppendChild(HtmlNode.CreateNode(""));
+
+ // Body
+ var messageBodyHtml = messageHtml.AppendChild(HtmlNode.CreateNode(""));
+
+ // Author
+ string authorName = HtmlDocument.HtmlEncode(messageGroup.Author.Name);
+ messageBodyHtml.AppendChild(HtmlNode.CreateNode($"{authorName}"));
+
+ // Date
+ string timeStamp = HtmlDocument.HtmlEncode(messageGroup.FirstTimeStamp.ToString("g"));
+ messageBodyHtml.AppendChild(HtmlNode.CreateNode($"{timeStamp}"));
+
+ // Separate messages
+ foreach (var message in messageGroup.Messages)
+ {
+ // Content
+ if (message.Content.IsNotBlank())
+ {
+ string content = FormatMessageContent(message.Content);
+ messageBodyHtml.AppendChild(HtmlNode.CreateNode($"{content}
"));
+ }
+
+ // Attachments
+ if (message.Attachments.Any())
+ {
+ // Attachments
+ foreach (var attachment in message.Attachments)
+ {
+ messageBodyHtml.AppendChild(
+ HtmlNode.CreateNode(""));
+ }
+ }
+ }
+ }
+
+ doc.Save(filePath);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscordChatExporter/Services/ExportTemplate.html b/DiscordChatExporter/Services/ExportTemplate.html
new file mode 100644
index 0000000..3befc29
--- /dev/null
+++ b/DiscordChatExporter/Services/ExportTemplate.html
@@ -0,0 +1,84 @@
+
+
+
+ Discord Chat Log
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file