Refactor message grouping out and add a limit setting

pull/17/head
Alexey Golub 7 years ago
parent 69184a74fe
commit 7b9de314ab

@ -14,6 +14,7 @@ namespace DiscordChatExporter
// Services
SimpleIoc.Default.Register<IDataService, DataService>();
SimpleIoc.Default.Register<IExportService, ExportService>();
SimpleIoc.Default.Register<IMessageGroupService, MessageGroupService>();
SimpleIoc.Default.Register<ISettingsService, SettingsService>();
// View models

@ -91,6 +91,8 @@
<Compile Include="Models\AttachmentType.cs" />
<Compile Include="Models\ChannelChatLog.cs" />
<Compile Include="Models\ChannelType.cs" />
<Compile Include="Services\IMessageGroupService.cs" />
<Compile Include="Services\MessageGroupService.cs" />
<Compile Include="ViewModels\ErrorViewModel.cs" />
<Compile Include="ViewModels\IErrorViewModel.cs" />
<Compile Include="ViewModels\ISettingsViewModel.cs" />

@ -9,13 +9,13 @@ namespace DiscordChatExporter.Models
public Channel Channel { get; }
public IReadOnlyList<Message> Messages { get; }
public IReadOnlyList<MessageGroup> MessageGroups { get; }
public ChannelChatLog(Guild guild, Channel channel, IEnumerable<Message> messages)
public ChannelChatLog(Guild guild, Channel channel, IEnumerable<MessageGroup> messageGroups)
{
Guild = guild;
Channel = channel;
Messages = messages.ToArray();
MessageGroups = messageGroups.ToArray();
}
}
}

@ -1,6 +1,4 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Text.RegularExpressions;
@ -19,7 +17,7 @@ namespace DiscordChatExporter.Services
_settingsService = settingsService;
}
public void Export(string filePath, ChannelChatLog channelChatLog, Theme theme)
public void Export(string filePath, ChannelChatLog log, Theme theme)
{
var doc = GetTemplate();
var style = GetStyle(theme);
@ -31,25 +29,24 @@ namespace DiscordChatExporter.Services
// Title
var titleHtml = doc.DocumentNode.Element("html").Element("head").Element("title");
titleHtml.InnerHtml = $"{channelChatLog.Guild.Name} - {channelChatLog.Channel.Name}";
titleHtml.InnerHtml = $"{log.Guild.Name} - {log.Channel.Name}";
// Info
var infoHtml = doc.GetElementbyId("info");
var infoLeftHtml = infoHtml.AppendChild(HtmlNode.CreateNode("<div class=\"info-left\"></div>"));
infoLeftHtml.AppendChild(HtmlNode.CreateNode(
$"<img class=\"guild-icon\" src=\"{channelChatLog.Guild.IconUrl}\" />"));
$"<img class=\"guild-icon\" src=\"{log.Guild.IconUrl}\" />"));
var infoRightHtml = infoHtml.AppendChild(HtmlNode.CreateNode("<div class=\"info-right\"></div>"));
infoRightHtml.AppendChild(HtmlNode.CreateNode(
$"<div class=\"guild-name\">{channelChatLog.Guild.Name}</div>"));
$"<div class=\"guild-name\">{log.Guild.Name}</div>"));
infoRightHtml.AppendChild(HtmlNode.CreateNode(
$"<div class=\"channel-name\">{channelChatLog.Channel.Name}</div>"));
$"<div class=\"channel-name\">{log.Channel.Name}</div>"));
infoRightHtml.AppendChild(HtmlNode.CreateNode(
$"<div class=\"misc\">{channelChatLog.Messages.Count:N0} messages</div>"));
$"<div class=\"misc\">{log.MessageGroups.Count:N0} messages</div>"));
// Log
var logHtml = doc.GetElementbyId("log");
var messageGroups = GroupMessages(channelChatLog.Messages);
foreach (var messageGroup in messageGroups)
foreach (var messageGroup in log.MessageGroups)
{
// Container
var messageHtml = logHtml.AppendChild(HtmlNode.CreateNode("<div class=\"msg\"></div>"));
@ -171,48 +168,6 @@ namespace DiscordChatExporter.Services
return $"{size:0.#} {units[unit]}";
}
private static IEnumerable<MessageGroup> GroupMessages(IEnumerable<Message> messages)
{
var result = new List<MessageGroup>();
// Group adjacent messages by timestamp and author
var groupBuffer = new List<Message>();
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
);
// If condition is true - flush buffer
if (breakCondition)
{
var group = new MessageGroup(groupFirst.Author, groupFirst.TimeStamp, groupBuffer);
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);
result.Add(group);
}
return result;
}
private static string FormatMessageContent(string content)
{
// Encode HTML

@ -4,6 +4,6 @@ namespace DiscordChatExporter.Services
{
public interface IExportService
{
void Export(string filePath, ChannelChatLog channelChatLog, Theme theme);
void Export(string filePath, ChannelChatLog log, Theme theme);
}
}

@ -0,0 +1,10 @@
using System.Collections.Generic;
using DiscordChatExporter.Models;
namespace DiscordChatExporter.Services
{
public interface IMessageGroupService
{
IEnumerable<MessageGroup> GroupMessages(IEnumerable<Message> messages);
}
}

@ -7,6 +7,7 @@ namespace DiscordChatExporter.Services
string Token { get; set; }
Theme Theme { get; set; }
string DateFormat { get; set; }
int MessageGroupLimit { get; set; }
void Load();
void Save();

@ -0,0 +1,60 @@
using System.Collections.Generic;
using System.Linq;
using DiscordChatExporter.Models;
namespace DiscordChatExporter.Services
{
public class MessageGroupService : IMessageGroupService
{
private readonly ISettingsService _settingsService;
public MessageGroupService(ISettingsService settingsService)
{
_settingsService = settingsService;
}
public IEnumerable<MessageGroup> GroupMessages(IEnumerable<Message> messages)
{
var groupLimit = _settingsService.MessageGroupLimit;
var result = new List<MessageGroup>();
// Group adjacent messages by timestamp and author
var groupBuffer = new List<Message>();
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 >= groupLimit
);
// If condition is true - flush buffer
if (breakCondition)
{
var group = new MessageGroup(groupFirst.Author, groupFirst.TimeStamp, groupBuffer);
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);
result.Add(group);
}
return result;
}
}
}

@ -8,6 +8,7 @@ namespace DiscordChatExporter.Services
public string Token { get; set; }
public Theme Theme { get; set; }
public string DateFormat { get; set; } = "dd-MMM-yy hh:mm";
public int MessageGroupLimit { get; set; } = 20;
public SettingsService()
{

@ -7,5 +7,7 @@ namespace DiscordChatExporter.ViewModels
{
IReadOnlyList<Theme> AvailableThemes { get; }
Theme Theme { get; set; }
string DateFormat { get; set; }
int MessageGroupLimit { get; set; }
}
}

@ -17,6 +17,7 @@ namespace DiscordChatExporter.ViewModels
{
private readonly ISettingsService _settingsService;
private readonly IDataService _dataService;
private readonly IMessageGroupService _messageGroupService;
private readonly IExportService _exportService;
private readonly Dictionary<Guild, IReadOnlyList<Channel>> _guildChannelsMap;
@ -85,10 +86,12 @@ namespace DiscordChatExporter.ViewModels
public RelayCommand ShowSettingsCommand { get; }
public RelayCommand ShowAboutCommand { get; }
public MainViewModel(ISettingsService settingsService, IDataService dataService, IExportService exportService)
public MainViewModel(ISettingsService settingsService, IDataService dataService,
IMessageGroupService messageGroupService, IExportService exportService)
{
_settingsService = settingsService;
_dataService = dataService;
_messageGroupService = messageGroupService;
_exportService = exportService;
_guildChannelsMap = new Dictionary<Guild, IReadOnlyList<Channel>>();
@ -166,8 +169,11 @@ namespace DiscordChatExporter.ViewModels
// Get messages
var messages = await _dataService.GetChannelMessagesAsync(_cachedToken, channel.Id);
// Group them
var messageGroups = _messageGroupService.GroupMessages(messages);
// Create log
var chatLog = new ChannelChatLog(SelectedGuild, channel, messages);
var chatLog = new ChannelChatLog(SelectedGuild, channel, messageGroups);
// Export
_exportService.Export(sfd.FileName, chatLog, _settingsService.Theme);

@ -4,6 +4,7 @@ using System.Linq;
using DiscordChatExporter.Models;
using DiscordChatExporter.Services;
using GalaSoft.MvvmLight;
using Tyrrrz.Extensions;
namespace DiscordChatExporter.ViewModels
{
@ -25,6 +26,12 @@ namespace DiscordChatExporter.ViewModels
set => _settingsService.DateFormat = value;
}
public int MessageGroupLimit
{
get => _settingsService.MessageGroupLimit;
set => _settingsService.MessageGroupLimit = value.ClampMin(0);
}
public SettingsViewModel(ISettingsService settingsService)
{
_settingsService = settingsService;

@ -23,6 +23,13 @@ UserControl "DiscordChatExporter.Views.SettingsDialog" {
Text: bind DateFormat
}
// Group limit
TextBox {
Margin: "16 8 16 8"
HintAssist.Hint: "Message group limit"
HintAssist.IsFloating: true
Text: bind MessageGroupLimit
}
// Save
Button {

Loading…
Cancel
Save