mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2024-09-19 12:18:48 -04:00
Add dark theme and theme switch (#4)
* Add dark theme * Refactor a bit * Add back Light theme and add a switch * Update readme
This commit is contained in:
parent
22d7dd43ec
commit
95d581797b
10 changed files with 288 additions and 135 deletions
|
@ -9,7 +9,9 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Services\ExportTemplate.html" />
|
<EmbeddedResource Include="Resources\HtmlExportService\LightTheme.css" />
|
||||||
|
<EmbeddedResource Include="Resources\HtmlExportService\DarkTheme.css" />
|
||||||
|
<EmbeddedResource Include="Resources\HtmlExportService\Template.html" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -6,10 +6,13 @@
|
||||||
|
|
||||||
public string ChannelId { get; }
|
public string ChannelId { get; }
|
||||||
|
|
||||||
public Options(string token, string channelId)
|
public Theme Theme { get; }
|
||||||
|
|
||||||
|
public Options(string token, string channelId, Theme theme)
|
||||||
{
|
{
|
||||||
Token = token;
|
Token = token;
|
||||||
ChannelId = channelId;
|
ChannelId = channelId;
|
||||||
|
Theme = theme;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
8
DiscordChatExporter/Models/Theme.cs
Normal file
8
DiscordChatExporter/Models/Theme.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace DiscordChatExporter.Models
|
||||||
|
{
|
||||||
|
public enum Theme
|
||||||
|
{
|
||||||
|
Light,
|
||||||
|
Dark
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ namespace DiscordChatExporter
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
private static readonly DiscordApiService DiscordApiService = new DiscordApiService();
|
private static readonly DiscordApiService DiscordApiService = new DiscordApiService();
|
||||||
private static readonly ExportService ExportService = new ExportService();
|
private static readonly HtmlExportService HtmlExportService = new HtmlExportService();
|
||||||
|
|
||||||
private static Options GetOptions(string[] args)
|
private static Options GetOptions(string[] args)
|
||||||
{
|
{
|
||||||
|
@ -37,8 +37,11 @@ namespace DiscordChatExporter
|
||||||
if (token.IsBlank() || channelId.IsBlank())
|
if (token.IsBlank() || channelId.IsBlank())
|
||||||
throw new ArgumentException("Some or all required command line arguments are missing");
|
throw new ArgumentException("Some or all required command line arguments are missing");
|
||||||
|
|
||||||
|
// Exract optional arguments
|
||||||
|
var theme = argsDic.GetOrDefault("theme").ParseEnumOrDefault<Theme>();
|
||||||
|
|
||||||
// Create option set
|
// Create option set
|
||||||
return new Options(token, channelId);
|
return new Options(token, channelId, theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task MainAsync(string[] args)
|
private static async Task MainAsync(string[] args)
|
||||||
|
@ -53,7 +56,7 @@ namespace DiscordChatExporter
|
||||||
|
|
||||||
// Export
|
// Export
|
||||||
Console.WriteLine("Exporting messages...");
|
Console.WriteLine("Exporting messages...");
|
||||||
ExportService.Export($"{options.ChannelId}.html", chatLog);
|
HtmlExportService.Export($"{options.ChannelId}.html", chatLog, options.Theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
|
|
105
DiscordChatExporter/Resources/HtmlExportService/DarkTheme.css
Normal file
105
DiscordChatExporter/Resources/HtmlExportService/DarkTheme.css
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
body {
|
||||||
|
font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
background-color: #36393E;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
color: #0096CF;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.pre, span.pre {
|
||||||
|
font-family: Consolas, Courier New, Courier, Monospace;
|
||||||
|
|
||||||
|
padding-right: 2px;
|
||||||
|
padding-left: 2px;
|
||||||
|
|
||||||
|
background-color: #2F3136;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#info {
|
||||||
|
max-width: 100%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
div#log {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.msg {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.msg-avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.msg-avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.msg-body {
|
||||||
|
margin-left: 20px;
|
||||||
|
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.msg-user {
|
||||||
|
font-size: 1rem;
|
||||||
|
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.msg-date {
|
||||||
|
font-size: .75rem;
|
||||||
|
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
color: rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.msg-edited {
|
||||||
|
font-size: .8rem;
|
||||||
|
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
color: rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.msg-content {
|
||||||
|
font-size: .9375rem;
|
||||||
|
|
||||||
|
padding-top: 5px;
|
||||||
|
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.msg-attachment {
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.msg-attachment {
|
||||||
|
max-width: 50%;
|
||||||
|
max-height: 500px;
|
||||||
|
}
|
105
DiscordChatExporter/Resources/HtmlExportService/LightTheme.css
Normal file
105
DiscordChatExporter/Resources/HtmlExportService/LightTheme.css
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
body {
|
||||||
|
font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
color: #00B0F4;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.pre, span.pre {
|
||||||
|
font-family: Consolas, Courier New, Courier, Monospace;
|
||||||
|
|
||||||
|
padding-right: 2px;
|
||||||
|
padding-left: 2px;
|
||||||
|
|
||||||
|
background-color: #F9F9F9;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#info {
|
||||||
|
max-width: 100%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
color: #737F8D;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#log {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.msg {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
|
||||||
|
border-top: 1px solid #ECEEEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.msg-avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.msg-avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.msg-body {
|
||||||
|
margin-left: 20px;
|
||||||
|
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.msg-user {
|
||||||
|
font-size: 1rem;
|
||||||
|
|
||||||
|
color: #2F3136;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.msg-date {
|
||||||
|
font-size: .75rem;
|
||||||
|
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
color: #99AAB5;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.msg-edited {
|
||||||
|
font-size: .8rem;
|
||||||
|
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
color: #99AAB5;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.msg-content {
|
||||||
|
font-size: .9375rem;
|
||||||
|
|
||||||
|
padding-top: 5px;
|
||||||
|
|
||||||
|
color: #737F8D;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.msg-attachment {
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.msg-attachment {
|
||||||
|
max-width: 50%;
|
||||||
|
max-height: 500px;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<!-- This chat log was automatically generated by DiscordChatExporter (https://github.com/Tyrrrz/DiscordChatExporter) -->
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Discord Chat Log</title>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<style id="theme">
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="info"></div>
|
||||||
|
<div id="log"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,122 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>Discord Chat Log</title>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif;
|
|
||||||
font-size: 15px;
|
|
||||||
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
color: #37bcf7;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.pre, span.pre {
|
|
||||||
font-family: Consolas, Courier New, Courier, Monospace;
|
|
||||||
|
|
||||||
padding-right: 2px;
|
|
||||||
padding-left: 2px;
|
|
||||||
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#info {
|
|
||||||
max-width: 100%;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
color: #939799;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#log {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.msg {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-left: 10px;
|
|
||||||
padding-top: 15px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
|
|
||||||
border-top: 1px solid #eceeef;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.msg-avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.msg-avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.msg-body {
|
|
||||||
margin-left: 15px;
|
|
||||||
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.msg-user {
|
|
||||||
font-size: 1.15em;
|
|
||||||
|
|
||||||
color: #2f3136;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.msg-date {
|
|
||||||
font-size: .8em;
|
|
||||||
font-weight: 200;
|
|
||||||
|
|
||||||
margin-left: 5px;
|
|
||||||
|
|
||||||
color: #b7bcbf;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.msg-edited {
|
|
||||||
font-size: .8em;
|
|
||||||
font-weight: 200;
|
|
||||||
|
|
||||||
margin-left: 5px;
|
|
||||||
|
|
||||||
color: #b7bcbf;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.msg-content {
|
|
||||||
padding-top: 5px;
|
|
||||||
|
|
||||||
color: #939799;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.msg-attachment {
|
|
||||||
margin-top: 5px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.msg-attachment {
|
|
||||||
max-width: 50%;
|
|
||||||
max-height: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="info"></div>
|
|
||||||
<div id="log"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using DiscordChatExporter.Models;
|
using DiscordChatExporter.Models;
|
||||||
using HtmlAgilityPack;
|
using HtmlAgilityPack;
|
||||||
|
@ -8,13 +10,18 @@ using Tyrrrz.Extensions;
|
||||||
|
|
||||||
namespace DiscordChatExporter.Services
|
namespace DiscordChatExporter.Services
|
||||||
{
|
{
|
||||||
public class ExportService
|
public class HtmlExportService
|
||||||
{
|
{
|
||||||
private HtmlDocument GetTemplate()
|
private HtmlDocument GetTemplate()
|
||||||
{
|
{
|
||||||
const string templateName = "DiscordChatExporter.Services.ExportTemplate.html";
|
string templateName = "DiscordChatExporter.Resources.HtmlExportService.Template.html";
|
||||||
|
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
using (var stream = assembly.GetManifestResourceStream(templateName))
|
var stream = assembly.GetManifestResourceStream(templateName);
|
||||||
|
if (stream == null)
|
||||||
|
throw new MissingManifestResourceException("Could not find template resource");
|
||||||
|
|
||||||
|
using (stream)
|
||||||
{
|
{
|
||||||
var doc = new HtmlDocument();
|
var doc = new HtmlDocument();
|
||||||
doc.Load(stream);
|
doc.Load(stream);
|
||||||
|
@ -22,6 +29,22 @@ namespace DiscordChatExporter.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetStyle(Theme theme)
|
||||||
|
{
|
||||||
|
string styleName = $"DiscordChatExporter.Resources.HtmlExportService.{theme}Theme.css";
|
||||||
|
|
||||||
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
var stream = assembly.GetManifestResourceStream(styleName);
|
||||||
|
if (stream == null)
|
||||||
|
throw new MissingManifestResourceException("Could not find theme style resource");
|
||||||
|
|
||||||
|
using (stream)
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
return reader.ReadToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private IEnumerable<MessageGroup> GroupMessages(IEnumerable<Message> messages)
|
private IEnumerable<MessageGroup> GroupMessages(IEnumerable<Message> messages)
|
||||||
{
|
{
|
||||||
var result = new List<MessageGroup>();
|
var result = new List<MessageGroup>();
|
||||||
|
@ -99,9 +122,14 @@ namespace DiscordChatExporter.Services
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Export(string filePath, ChatLog chatLog)
|
public void Export(string filePath, ChatLog chatLog, Theme theme)
|
||||||
{
|
{
|
||||||
var doc = GetTemplate();
|
var doc = GetTemplate();
|
||||||
|
string style = GetStyle(theme);
|
||||||
|
|
||||||
|
// Set theme
|
||||||
|
var themeHtml = doc.GetElementbyId("theme");
|
||||||
|
themeHtml.InnerHtml = style;
|
||||||
|
|
||||||
// Info
|
// Info
|
||||||
var infoHtml = doc.GetElementbyId("info");
|
var infoHtml = doc.GetElementbyId("info");
|
12
Readme.md
12
Readme.md
|
@ -12,7 +12,7 @@ Command line executable that can export [Discord](https://discordapp.com) channe
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Produces output styled similar to the Discord's light theme
|
- Supports both dark and light theme
|
||||||
- Displays user avatars
|
- Displays user avatars
|
||||||
- Groups messages by author and time
|
- Groups messages by author and time
|
||||||
- Handles Discord markdown characters
|
- Handles Discord markdown characters
|
||||||
|
@ -23,18 +23,18 @@ Command line executable that can export [Discord](https://discordapp.com) channe
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
The program expects an access token and channel ID as parameters.
|
The program expects an access token and channel ID as parameters. At minimum, the execution should look like this:
|
||||||
|
|
||||||
`DiscordChatExporter.exe /token:REkOTVqm9RWOTNOLCdiuMpWd.QiglBz.Lub0E0TZ1xX4ZxCtnwtpBhWt3v1 /channelId:459360869055190534`
|
`DiscordChatExporter.exe /token:REkOTVqm9RWOTNOLCdiuMpWd.QiglBz.Lub0E0TZ1xX4ZxCtnwtpBhWt3v1 /channelId:459360869055190534`
|
||||||
|
|
||||||
#### Getting access token:
|
#### Getting access token
|
||||||
|
|
||||||
- Open Discord desktop or web client
|
- Open Discord desktop or web client
|
||||||
- Press `Ctrl+Shift+I`
|
- Press `Ctrl+Shift+I`
|
||||||
- Navigate to `Application > Storage > Local Storage > https://discordapp.com`
|
- Navigate to `Application > Storage > Local Storage > https://discordapp.com`
|
||||||
- Find the value for `token` and extract it
|
- Find the value for `token` and extract it
|
||||||
|
|
||||||
#### Getting channel ID:
|
#### Getting channel ID
|
||||||
|
|
||||||
- Open Discord desktop or web client
|
- Open Discord desktop or web client
|
||||||
- Navigate to any DM or server channel
|
- Navigate to any DM or server channel
|
||||||
|
@ -46,6 +46,10 @@ The program expects an access token and channel ID as parameters.
|
||||||
- If it's a server channel, the format looks like this:
|
- If it's a server channel, the format looks like this:
|
||||||
`https://discordapp.com/channels/WHATEVER/CHANNEL_ID`
|
`https://discordapp.com/channels/WHATEVER/CHANNEL_ID`
|
||||||
|
|
||||||
|
#### Optional arguments
|
||||||
|
|
||||||
|
- `/theme:[Dark/Light]` - sets the style of the output
|
||||||
|
|
||||||
## Libraries used
|
## Libraries used
|
||||||
|
|
||||||
- [HtmlAgilityPack](https://github.com/zzzprojects/html-agility-pack)
|
- [HtmlAgilityPack](https://github.com/zzzprojects/html-agility-pack)
|
||||||
|
|
Loading…
Reference in a new issue