mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2025-05-25 04:04:22 -04:00
Refactor message grouping out and add a limit setting
This commit is contained in:
parent
69184a74fe
commit
7b9de314ab
13 changed files with 111 additions and 59 deletions
|
@ -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);
|
||||
}
|
||||
}
|
10
DiscordChatExporter/Services/IMessageGroupService.cs
Normal file
10
DiscordChatExporter/Services/IMessageGroupService.cs
Normal file
|
@ -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();
|
||||
|
|
60
DiscordChatExporter/Services/MessageGroupService.cs
Normal file
60
DiscordChatExporter/Services/MessageGroupService.cs
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue