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:
Alexey Golub 2017-09-01 15:45:19 +03:00 committed by GitHub
parent 22d7dd43ec
commit 95d581797b
10 changed files with 288 additions and 135 deletions

View file

@ -9,7 +9,9 @@
</PropertyGroup>
<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>

View file

@ -6,10 +6,13 @@
public string ChannelId { get; }
public Options(string token, string channelId)
public Theme Theme { get; }
public Options(string token, string channelId, Theme theme)
{
Token = token;
ChannelId = channelId;
Theme = theme;
}
}
}

View file

@ -0,0 +1,8 @@
namespace DiscordChatExporter.Models
{
public enum Theme
{
Light,
Dark
}
}

View file

@ -11,7 +11,7 @@ namespace DiscordChatExporter
public static class Program
{
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)
{
@ -37,8 +37,11 @@ namespace DiscordChatExporter
if (token.IsBlank() || channelId.IsBlank())
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
return new Options(token, channelId);
return new Options(token, channelId, theme);
}
private static async Task MainAsync(string[] args)
@ -53,7 +56,7 @@ namespace DiscordChatExporter
// Export
Console.WriteLine("Exporting messages...");
ExportService.Export($"{options.ChannelId}.html", chatLog);
HtmlExportService.Export($"{options.ChannelId}.html", chatLog, options.Theme);
}
public static void Main(string[] args)

View 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;
}

View 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;
}

View file

@ -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>

View file

@ -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>

View file

@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Text.RegularExpressions;
using DiscordChatExporter.Models;
using HtmlAgilityPack;
@ -8,13 +10,18 @@ using Tyrrrz.Extensions;
namespace DiscordChatExporter.Services
{
public class ExportService
public class HtmlExportService
{
private HtmlDocument GetTemplate()
{
const string templateName = "DiscordChatExporter.Services.ExportTemplate.html";
string templateName = "DiscordChatExporter.Resources.HtmlExportService.Template.html";
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();
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)
{
var result = new List<MessageGroup>();
@ -99,9 +122,14 @@ namespace DiscordChatExporter.Services
return content;
}
public void Export(string filePath, ChatLog chatLog)
public void Export(string filePath, ChatLog chatLog, Theme theme)
{
var doc = GetTemplate();
string style = GetStyle(theme);
// Set theme
var themeHtml = doc.GetElementbyId("theme");
themeHtml.InnerHtml = style;
// Info
var infoHtml = doc.GetElementbyId("info");

View file

@ -12,7 +12,7 @@ Command line executable that can export [Discord](https://discordapp.com) channe
## Features
- Produces output styled similar to the Discord's light theme
- Supports both dark and light theme
- Displays user avatars
- Groups messages by author and time
- Handles Discord markdown characters
@ -23,18 +23,18 @@ Command line executable that can export [Discord](https://discordapp.com) channe
## 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`
#### Getting access token:
#### Getting access token
- Open Discord desktop or web client
- Press `Ctrl+Shift+I`
- Navigate to `Application > Storage > Local Storage > https://discordapp.com`
- Find the value for `token` and extract it
#### Getting channel ID:
#### Getting channel ID
- Open Discord desktop or web client
- 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:
`https://discordapp.com/channels/WHATEVER/CHANNEL_ID`
#### Optional arguments
- `/theme:[Dark/Light]` - sets the style of the output
## Libraries used
- [HtmlAgilityPack](https://github.com/zzzprojects/html-agility-pack)