From 47f0561c716345d762825f1778810a0f298bfe6a Mon Sep 17 00:00:00 2001 From: Oleksii Holub Date: Thu, 1 Nov 2018 18:16:23 +0200 Subject: [PATCH] Refactor message grouping from data layer to render layer --- DiscordChatExporter.Cli/Container.cs | 2 - .../Verbs/ExportChatVerb.cs | 4 +- DiscordChatExporter.Core/Models/ChatLog.cs | 10 +--- .../Models/MessageGroup.cs | 23 -------- .../Resources/ExportTemplates/Csv.csv | 14 ++--- .../Resources/ExportTemplates/Html/Core.html | 4 +- .../Resources/ExportTemplates/PlainText.txt | 4 +- .../Services/ChatLogService.cs | 51 ---------------- .../Services/DataService.cs | 27 +++++++++ .../Services/ExportService.MessageGroup.cs | 25 ++++++++ .../Services/ExportService.TemplateModel.cs | 47 ++++++++++++++- .../Services/ExportService.cs | 4 +- .../Services/IChatLogService.cs | 15 ----- .../Services/IDataService.cs | 6 ++ .../Services/IMessageGroupService.cs | 10 ---- .../Services/MessageGroupService.cs | 59 ------------------- DiscordChatExporter.Gui/Container.cs | 2 - .../ViewModels/MainViewModel.cs | 6 +- 18 files changed, 124 insertions(+), 189 deletions(-) delete mode 100644 DiscordChatExporter.Core/Models/MessageGroup.cs delete mode 100644 DiscordChatExporter.Core/Services/ChatLogService.cs create mode 100644 DiscordChatExporter.Core/Services/ExportService.MessageGroup.cs delete mode 100644 DiscordChatExporter.Core/Services/IChatLogService.cs delete mode 100644 DiscordChatExporter.Core/Services/IMessageGroupService.cs delete mode 100644 DiscordChatExporter.Core/Services/MessageGroupService.cs diff --git a/DiscordChatExporter.Cli/Container.cs b/DiscordChatExporter.Cli/Container.cs index f678354..dea3515 100644 --- a/DiscordChatExporter.Cli/Container.cs +++ b/DiscordChatExporter.Cli/Container.cs @@ -12,10 +12,8 @@ namespace DiscordChatExporter.Cli SimpleIoc.Default.Reset(); // Services - SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); } diff --git a/DiscordChatExporter.Cli/Verbs/ExportChatVerb.cs b/DiscordChatExporter.Cli/Verbs/ExportChatVerb.cs index 8761da2..4bbf0cd 100644 --- a/DiscordChatExporter.Cli/Verbs/ExportChatVerb.cs +++ b/DiscordChatExporter.Cli/Verbs/ExportChatVerb.cs @@ -20,7 +20,7 @@ namespace DiscordChatExporter.Cli.Verbs // Get services var container = new Container(); var settingsService = container.Resolve(); - var chatLogService = container.Resolve(); + var dataService = container.Resolve(); var exportService = container.Resolve(); // Configure settings @@ -30,7 +30,7 @@ namespace DiscordChatExporter.Cli.Verbs settingsService.MessageGroupLimit = Options.MessageGroupLimit; // Get chat log - var chatLog = await chatLogService.GetChatLogAsync(Options.GetToken(), Options.ChannelId, + var chatLog = await dataService.GetChatLogAsync(Options.GetToken(), Options.ChannelId, Options.After, Options.Before); // Generate file path if not set diff --git a/DiscordChatExporter.Core/Models/ChatLog.cs b/DiscordChatExporter.Core/Models/ChatLog.cs index aa8c476..d8dc2ca 100644 --- a/DiscordChatExporter.Core/Models/ChatLog.cs +++ b/DiscordChatExporter.Core/Models/ChatLog.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; namespace DiscordChatExporter.Core.Models { @@ -14,21 +13,18 @@ namespace DiscordChatExporter.Core.Models public DateTime? To { get; } - public IReadOnlyList MessageGroups { get; } - - public long TotalMessageCount { get; } + public IReadOnlyList Messages { get; } public Mentionables Mentionables { get; } public ChatLog(Guild guild, Channel channel, DateTime? from, DateTime? to, - IReadOnlyList messageGroups, long totalMessageCount, Mentionables mentionables) + IReadOnlyList messages, Mentionables mentionables) { Guild = guild; Channel = channel; From = from; To = to; - MessageGroups = messageGroups; - TotalMessageCount = totalMessageCount; + Messages = messages; Mentionables = mentionables; } diff --git a/DiscordChatExporter.Core/Models/MessageGroup.cs b/DiscordChatExporter.Core/Models/MessageGroup.cs deleted file mode 100644 index 4e9dce9..0000000 --- a/DiscordChatExporter.Core/Models/MessageGroup.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace DiscordChatExporter.Core.Models -{ - public class MessageGroup - { - public User Author { get; } - - public DateTime Timestamp { get; } - - public IReadOnlyList Messages { get; } - - public MessageGroup(User author, DateTime timestamp, IReadOnlyList messages) - { - Author = author; - Timestamp = timestamp; - Messages = messages; - } - - public override string ToString() => $"{Author.FullName} | {Timestamp} | {Messages.Count} messages"; - } -} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Resources/ExportTemplates/Csv.csv b/DiscordChatExporter.Core/Resources/ExportTemplates/Csv.csv index 5d8d9b6..7de5e5c 100644 --- a/DiscordChatExporter.Core/Resources/ExportTemplates/Csv.csv +++ b/DiscordChatExporter.Core/Resources/ExportTemplates/Csv.csv @@ -1,12 +1,10 @@ Author;Date;Content;Attachments; -{{~ for group in Model.MessageGroups -}} - {{- for message in group.Messages -}} - {{- message.Author.FullName }}; +{{~ for message in Model.Messages -}} + {{- message.Author.FullName }}; - {{- message.Timestamp | FormatDate }}; + {{- message.Timestamp | FormatDate }}; - {{- message.Content | FormatContent }}; + {{- message.Content | FormatContent }}; - {{- message.Attachments | array.map "Url" | array.join "," }}; - {{~ end -}} -{{- end -}} \ No newline at end of file + {{- message.Attachments | array.map "Url" | array.join "," }}; +{{~ end -}} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Resources/ExportTemplates/Html/Core.html b/DiscordChatExporter.Core/Resources/ExportTemplates/Html/Core.html index d9e8b1d..5b888ea 100644 --- a/DiscordChatExporter.Core/Resources/ExportTemplates/Html/Core.html +++ b/DiscordChatExporter.Core/Resources/ExportTemplates/Html/Core.html @@ -24,7 +24,7 @@
{{ Model.Channel.Topic | html.escape }}
{{~ end ~}} -
{{ Model.TotalMessageCount | Format "N0" }} messages
+
{{ Model.Messages | array.size | Format "N0" }} messages
{{~ if Model.From || Model.To ~}}
@@ -42,7 +42,7 @@ {{~ # Log ~}}
- {{~ for group in Model.MessageGroups ~}} + {{~ for group in Model.Messages | GroupMessages ~}}
{{~ # Avatar ~}}
diff --git a/DiscordChatExporter.Core/Resources/ExportTemplates/PlainText.txt b/DiscordChatExporter.Core/Resources/ExportTemplates/PlainText.txt index c215fb9..4410710 100644 --- a/DiscordChatExporter.Core/Resources/ExportTemplates/PlainText.txt +++ b/DiscordChatExporter.Core/Resources/ExportTemplates/PlainText.txt @@ -3,12 +3,12 @@ Guild: {{ Model.Guild.Name }} Channel: {{ Model.Channel.Name }} Topic: {{ Model.Channel.Topic }} -Messages: {{ Model.TotalMessageCount | Format "N0" }} +Messages: {{ Model.Messages | array.size | Format "N0" }} Range: {{ if Model.From }}{{ Model.From | FormatDate }} {{ end }}{{ if Model.From || Model.To }}->{{ end }}{{ if Model.To }} {{ Model.To | FormatDate }}{{ end }} ============================================================== {{~ # Log ~}} -{{~ for group in Model.MessageGroups ~}} +{{~ for group in Model.Messages | GroupMessages ~}} {{~ # Author name and timestamp ~}} {{~ }}[{{ group.Timestamp | FormatDate }}] {{ group.Author.FullName }} {{~ # Messages ~}} diff --git a/DiscordChatExporter.Core/Services/ChatLogService.cs b/DiscordChatExporter.Core/Services/ChatLogService.cs deleted file mode 100644 index 2bd4695..0000000 --- a/DiscordChatExporter.Core/Services/ChatLogService.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Threading.Tasks; -using DiscordChatExporter.Core.Models; - -namespace DiscordChatExporter.Core.Services -{ - public class ChatLogService : IChatLogService - { - private readonly IDataService _dataService; - private readonly IMessageGroupService _messageGroupService; - - public ChatLogService(IDataService dataService, IMessageGroupService messageGroupService) - { - _dataService = dataService; - _messageGroupService = messageGroupService; - } - - public async Task GetChatLogAsync(AuthToken token, Guild guild, Channel channel, - DateTime? from = null, DateTime? to = null, IProgress progress = null) - { - // Get messages - var messages = await _dataService.GetChannelMessagesAsync(token, channel.Id, from, to, progress); - - // Group messages - var messageGroups = _messageGroupService.GroupMessages(messages); - - // Get total message count - var totalMessageCount = messages.Count; - - // Get mentionables - var mentionables = await _dataService.GetMentionablesAsync(token, guild.Id, messages); - - return new ChatLog(guild, channel, from, to, messageGroups, totalMessageCount, mentionables); - } - - public async Task GetChatLogAsync(AuthToken token, string channelId, - DateTime? from = null, DateTime? to = null, IProgress progress = null) - { - // Get channel - var channel = await _dataService.GetChannelAsync(token, channelId); - - // Get guild - var guild = channel.GuildId == Guild.DirectMessages.Id - ? Guild.DirectMessages - : await _dataService.GetGuildAsync(token, channel.GuildId); - - // Get the chat log - return await GetChatLogAsync(token, guild, channel, from, to, progress); - } - } -} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Services/DataService.cs b/DiscordChatExporter.Core/Services/DataService.cs index 1fccc4c..452ca85 100644 --- a/DiscordChatExporter.Core/Services/DataService.cs +++ b/DiscordChatExporter.Core/Services/DataService.cs @@ -214,6 +214,33 @@ namespace DiscordChatExporter.Core.Services return new Mentionables(users, channels, roles); } + public async Task GetChatLogAsync(AuthToken token, Guild guild, Channel channel, + DateTime? from = null, DateTime? to = null, IProgress progress = null) + { + // Get messages + var messages = await GetChannelMessagesAsync(token, channel.Id, from, to, progress); + + // Get mentionables + var mentionables = await GetMentionablesAsync(token, guild.Id, messages); + + return new ChatLog(guild, channel, from, to, messages, mentionables); + } + + public async Task GetChatLogAsync(AuthToken token, string channelId, + DateTime? from = null, DateTime? to = null, IProgress progress = null) + { + // Get channel + var channel = await GetChannelAsync(token, channelId); + + // Get guild + var guild = channel.GuildId == Guild.DirectMessages.Id + ? Guild.DirectMessages + : await GetGuildAsync(token, channel.GuildId); + + // Get the chat log + return await GetChatLogAsync(token, guild, channel, from, to, progress); + } + public void Dispose() { _httpClient.Dispose(); diff --git a/DiscordChatExporter.Core/Services/ExportService.MessageGroup.cs b/DiscordChatExporter.Core/Services/ExportService.MessageGroup.cs new file mode 100644 index 0000000..0577540 --- /dev/null +++ b/DiscordChatExporter.Core/Services/ExportService.MessageGroup.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using DiscordChatExporter.Core.Models; + +namespace DiscordChatExporter.Core.Services +{ + public partial class ExportService + { + private class MessageGroup + { + public User Author { get; } + + public DateTime Timestamp { get; } + + public IReadOnlyList Messages { get; } + + public MessageGroup(User author, DateTime timestamp, IReadOnlyList messages) + { + Author = author; + Timestamp = timestamp; + Messages = messages; + } + } + } +} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Services/ExportService.TemplateModel.cs b/DiscordChatExporter.Core/Services/ExportService.TemplateModel.cs index 5a757c6..effe4fb 100644 --- a/DiscordChatExporter.Core/Services/ExportService.TemplateModel.cs +++ b/DiscordChatExporter.Core/Services/ExportService.TemplateModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.Linq; @@ -18,12 +19,55 @@ namespace DiscordChatExporter.Core.Services private readonly ExportFormat _format; private readonly ChatLog _log; private readonly string _dateFormat; + private readonly int _messageGroupLimit; - public TemplateModel(ExportFormat format, ChatLog log, string dateFormat) + public TemplateModel(ExportFormat format, ChatLog log, string dateFormat, int messageGroupLimit) { _format = format; _log = log; _dateFormat = dateFormat; + _messageGroupLimit = messageGroupLimit; + } + + private IEnumerable GroupMessages(IEnumerable messages) + { + // Group adjacent messages by timestamp and author + var groupBuffer = new List(); + foreach (var message in messages) + { + var groupFirst = groupBuffer.FirstOrDefault(); + + // Group break condition + var breakCondition = + groupFirst != null && + ( + message.Author.Id != groupFirst.Author.Id || + (message.Timestamp - groupFirst.Timestamp).TotalHours > 1 || + message.Timestamp.Hour != groupFirst.Timestamp.Hour || + groupBuffer.Count >= _messageGroupLimit + ); + + // If condition is true - flush buffer + if (breakCondition) + { + var group = new MessageGroup(groupFirst.Author, groupFirst.Timestamp, groupBuffer.ToArray()); + groupBuffer.Clear(); + + yield return group; + } + + // Add message to buffer + groupBuffer.Add(message); + } + + // Add what's remaining in buffer + if (groupBuffer.Any()) + { + var groupFirst = groupBuffer.First(); + var group = new MessageGroup(groupFirst.Author, groupFirst.Timestamp, groupBuffer.ToArray()); + + yield return group; + } } private string HtmlEncode(string str) => WebUtility.HtmlEncode(str); @@ -310,6 +354,7 @@ namespace DiscordChatExporter.Core.Services scriptObject.SetValue("Model", _log, true); // Import functions + scriptObject.Import(nameof(GroupMessages), new Func, IEnumerable>(GroupMessages)); scriptObject.Import(nameof(Format), new Func(Format)); scriptObject.Import(nameof(FormatDate), new Func(FormatDate)); scriptObject.Import(nameof(FormatFileSize), new Func(FormatFileSize)); diff --git a/DiscordChatExporter.Core/Services/ExportService.cs b/DiscordChatExporter.Core/Services/ExportService.cs index d0e85f7..69e9207 100644 --- a/DiscordChatExporter.Core/Services/ExportService.cs +++ b/DiscordChatExporter.Core/Services/ExportService.cs @@ -35,7 +35,9 @@ namespace DiscordChatExporter.Core.Services }; // Create template model - var templateModel = new TemplateModel(format, chatLog, _settingsService.DateFormat); + var templateModel = new TemplateModel(format, chatLog, + _settingsService.DateFormat, _settingsService.MessageGroupLimit); + context.PushGlobal(templateModel.GetScriptObject()); // Create directory diff --git a/DiscordChatExporter.Core/Services/IChatLogService.cs b/DiscordChatExporter.Core/Services/IChatLogService.cs deleted file mode 100644 index 1de69e3..0000000 --- a/DiscordChatExporter.Core/Services/IChatLogService.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Threading.Tasks; -using DiscordChatExporter.Core.Models; - -namespace DiscordChatExporter.Core.Services -{ - public interface IChatLogService - { - Task GetChatLogAsync(AuthToken token, Guild guild, Channel channel, - DateTime? from = null, DateTime? to = null, IProgress progress = null); - - Task GetChatLogAsync(AuthToken token, string channelId, - DateTime? from = null, DateTime? to = null, IProgress progress = null); - } -} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Services/IDataService.cs b/DiscordChatExporter.Core/Services/IDataService.cs index 9c5522c..0822d23 100644 --- a/DiscordChatExporter.Core/Services/IDataService.cs +++ b/DiscordChatExporter.Core/Services/IDataService.cs @@ -24,5 +24,11 @@ namespace DiscordChatExporter.Core.Services Task GetMentionablesAsync(AuthToken token, string guildId, IEnumerable messages); + + Task GetChatLogAsync(AuthToken token, Guild guild, Channel channel, + DateTime? from = null, DateTime? to = null, IProgress progress = null); + + Task GetChatLogAsync(AuthToken token, string channelId, + DateTime? from = null, DateTime? to = null, IProgress progress = null); } } \ No newline at end of file diff --git a/DiscordChatExporter.Core/Services/IMessageGroupService.cs b/DiscordChatExporter.Core/Services/IMessageGroupService.cs deleted file mode 100644 index b21f1fb..0000000 --- a/DiscordChatExporter.Core/Services/IMessageGroupService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using DiscordChatExporter.Core.Models; - -namespace DiscordChatExporter.Core.Services -{ - public interface IMessageGroupService - { - IReadOnlyList GroupMessages(IEnumerable messages); - } -} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Services/MessageGroupService.cs b/DiscordChatExporter.Core/Services/MessageGroupService.cs deleted file mode 100644 index b9882ae..0000000 --- a/DiscordChatExporter.Core/Services/MessageGroupService.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using DiscordChatExporter.Core.Models; - -namespace DiscordChatExporter.Core.Services -{ - public class MessageGroupService : IMessageGroupService - { - private readonly ISettingsService _settingsService; - - public MessageGroupService(ISettingsService settingsService) - { - _settingsService = settingsService; - } - - public IReadOnlyList GroupMessages(IEnumerable messages) - { - var result = new List(); - - // Group adjacent messages by timestamp and author - var groupBuffer = new List(); - foreach (var message in messages) - { - var groupFirst = groupBuffer.FirstOrDefault(); - - // Group break condition - var breakCondition = - groupFirst != null && - ( - message.Author.Id != groupFirst.Author.Id || - (message.Timestamp - groupFirst.Timestamp).TotalHours > 1 || - message.Timestamp.Hour != groupFirst.Timestamp.Hour || - groupBuffer.Count >= _settingsService.MessageGroupLimit - ); - - // If condition is true - flush buffer - if (breakCondition) - { - var group = new MessageGroup(groupFirst.Author, groupFirst.Timestamp, groupBuffer.ToArray()); - result.Add(group); - groupBuffer.Clear(); - } - - // Add message to buffer - groupBuffer.Add(message); - } - - // Add what's remaining in buffer - if (groupBuffer.Any()) - { - var groupFirst = groupBuffer.First(); - var group = new MessageGroup(groupFirst.Author, groupFirst.Timestamp, groupBuffer.ToArray()); - result.Add(group); - } - - return result; - } - } -} \ No newline at end of file diff --git a/DiscordChatExporter.Gui/Container.cs b/DiscordChatExporter.Gui/Container.cs index d2adc94..f47cc47 100644 --- a/DiscordChatExporter.Gui/Container.cs +++ b/DiscordChatExporter.Gui/Container.cs @@ -17,10 +17,8 @@ namespace DiscordChatExporter.Gui SimpleIoc.Default.Reset(); // Services - SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); SimpleIoc.Default.Register(); diff --git a/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs b/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs index 6aa8a73..e2299de 100644 --- a/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs @@ -19,7 +19,6 @@ namespace DiscordChatExporter.Gui.ViewModels private readonly ISettingsService _settingsService; private readonly IUpdateService _updateService; private readonly IDataService _dataService; - private readonly IChatLogService _chatLogService; private readonly IExportService _exportService; private readonly Dictionary> _guildChannelsMap; @@ -111,12 +110,11 @@ namespace DiscordChatExporter.Gui.ViewModels public RelayCommand ShowExportSetupCommand { get; } public MainViewModel(ISettingsService settingsService, IUpdateService updateService, IDataService dataService, - IChatLogService chatLogService, IExportService exportService) + IExportService exportService) { _settingsService = settingsService; _updateService = updateService; _dataService = dataService; - _chatLogService = chatLogService; _exportService = exportService; _guildChannelsMap = new Dictionary>(); @@ -257,7 +255,7 @@ namespace DiscordChatExporter.Gui.ViewModels try { // Get chat log - var chatLog = await _chatLogService.GetChatLogAsync(token, guild, channel, from, to, progressHandler); + var chatLog = await _dataService.GetChatLogAsync(token, guild, channel, from, to, progressHandler); // Export _exportService.ExportChatLog(chatLog, filePath, format);