diff --git a/DiscordChatExporter.Core/Exporting/ChannelExporter.cs b/DiscordChatExporter.Core/Exporting/ChannelExporter.cs index 4a434a97..9a8aa37c 100644 --- a/DiscordChatExporter.Core/Exporting/ChannelExporter.cs +++ b/DiscordChatExporter.Core/Exporting/ChannelExporter.cs @@ -55,24 +55,32 @@ public class ChannelExporter(DiscordClient discord) ); if (lastMessageSnowflake != null) { - request.LastPriorMessage = lastMessageSnowflake.Value; - - if (!request.Channel.MayHaveMessagesAfter(request.LastPriorMessage.Value)) + if (!request.Channel.MayHaveMessagesAfter(lastMessageSnowflake.Value)) { logger.IncrementCounter(ExportResult.UpdateExportSkip); logger.LogInfo(request, "Existing export already up to date"); return; } - + request.LastPriorMessage = lastMessageSnowflake.Value; logger.LogInfo( request, "Appending existing export starting at " + lastMessageSnowflake.Value.ToDate() ); - currentPartitionIndex = MessageExporter.GetPartitionCount( - request.OutputFilePath - ); } + else + { + if (request.Channel.IsEmpty) + { + logger.IncrementCounter(ExportResult.UpdateExportSkip); + logger.LogInfo(request, "Existing empty export already up to date"); + return; + } + logger.LogInfo(request, "Appending existing empty export."); + } + currentPartitionIndex = MessageExporter.GetPartitionCount( + request.OutputFilePath + ); break; default: throw new InvalidOperationException( diff --git a/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs b/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs index 9df2bba3..ede7052c 100644 --- a/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs +++ b/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs @@ -142,10 +142,12 @@ internal partial class CsvMessageWriter(Stream stream, ExportContext context) { try { - var fileLines = File.ReadAllLines(filePath) - .SkipWhile(string.IsNullOrWhiteSpace) - .ToArray(); - if (fileLines.Length <= HeaderSize) + var fileLines = File.ReadAllLines(filePath); + var fileContainsMessages = fileLines + .Where(line => !string.IsNullOrWhiteSpace(line)) + .Skip(HeaderSize) + .Any(); + if (!fileContainsMessages) return null; const string columnPattern = "(?:[^\"]?(?:\"\")?)*"; @@ -155,7 +157,9 @@ internal partial class CsvMessageWriter(Stream stream, ExportContext context) ); var messageDateRegex = new Regex(messageDatePattern); - var timestampMatch = messageDateRegex.Match(fileLines[^1]); + var timestampMatch = messageDateRegex.Match( + fileLines.Last(line => !string.IsNullOrWhiteSpace(line)) + ); var timestampString = timestampMatch.Groups[1].Value; var timestamp = DateTimeOffset.Parse(timestampString); return Snowflake.FromDate(timestamp, true); diff --git a/DiscordChatExporter.Core/Exporting/HtmlMessageWriter.cs b/DiscordChatExporter.Core/Exporting/HtmlMessageWriter.cs index e6916fd2..f8357a99 100644 --- a/DiscordChatExporter.Core/Exporting/HtmlMessageWriter.cs +++ b/DiscordChatExporter.Core/Exporting/HtmlMessageWriter.cs @@ -179,6 +179,8 @@ internal partial class HtmlMessageWriter(Stream stream, ExportContext context, s var messageDateRegex = MessageDateRegex(); var timestampMatches = messageDateRegex.Matches(fileContent); + if (timestampMatches.Count == 0) + return null; var timestampString = timestampMatches[^1].Groups[1].Value; var timestamp = DateTimeOffset.Parse(timestampString); return Snowflake.FromDate(timestamp, true); diff --git a/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml b/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml index e0730553..4a7d2558 100644 --- a/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml +++ b/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml @@ -240,6 +240,7 @@ } @* Timestamp *@ + @* Don't change this without changing the corresponding detection in the HtmlMessageWriter *@ @FormatDate(message.Timestamp) } diff --git a/DiscordChatExporter.Core/Exporting/PlainTextMessageWriter.cs b/DiscordChatExporter.Core/Exporting/PlainTextMessageWriter.cs index f96248ad..a2dc5976 100644 --- a/DiscordChatExporter.Core/Exporting/PlainTextMessageWriter.cs +++ b/DiscordChatExporter.Core/Exporting/PlainTextMessageWriter.cs @@ -16,6 +16,7 @@ internal partial class PlainTextMessageWriter(Stream stream, ExportContext conte : MessageWriter(stream, context) { private const int HeaderSize = 4; + private const int FooterSize = 3; private readonly TextWriter _writer = new StreamWriter(stream); @@ -306,13 +307,17 @@ internal partial class PlainTextMessageWriter(Stream stream, ExportContext conte public static Snowflake? GetLastMessageDate(string filePath) { var fileLines = File.ReadAllLines(filePath); - if (fileLines.SkipWhile(string.IsNullOrWhiteSpace).ToArray().Length <= HeaderSize) + var fileContainsMessages = fileLines + .Where(line => !string.IsNullOrWhiteSpace(line)) + .Skip(HeaderSize + FooterSize) + .Any(); + if (!fileContainsMessages) return null; var messageDateRegex = MessageDateRegex(); // Find the last line with a message timestamp - for (var i = fileLines.Length - 1; i >= HeaderSize; i--) + for (var i = fileLines.Length - 1 - FooterSize; i >= HeaderSize; i--) { var timestampMatch = messageDateRegex.Match(fileLines[i]); if (!timestampMatch.Success)