Compare commits

..

42 Commits

Author SHA1 Message Date
Tyrrrz e6f9a364e1 Update version 2023-11-23 00:25:27 +02:00
Tyrrrz 0f6841593f Simplify CLI docs 2023-11-23 00:16:36 +02:00
Tyrrrz 2262d0abfb Update readme 2023-11-21 20:09:22 +02:00
Tyrrrz ab535233dc Update readme 2023-11-21 19:38:47 +02:00
Tyrrrz dcaceaddaf Skip the whole test job on pull requests, not just one step 2023-11-21 16:33:02 +02:00
Tyrrrz 2a787d2749 Rename job for consistency 2023-11-20 16:03:02 +02:00
Tyrrrz 481ddc4cd5 Update usage guide in apps 2023-11-19 22:52:03 +02:00
Oleksii Holub c493518eaf Update token docs
Closes #1159
2023-11-19 22:50:46 +02:00
Tyrrrz 450866d1f5 Make formatting check a separate job 2023-11-19 01:53:44 +02:00
Tyrrrz 60c8703e78 Fix incorrect handling of unformatted timestamp markers 2023-11-19 00:52:19 +02:00
Tyrrrz 1c343b75f8 Update NuGet packages 2023-11-18 23:49:25 +02:00
Tyrrrz b2a22ab2a9 Ignore invalid timestamp formats
Closes #1156
2023-11-18 23:45:57 +02:00
Tyrrrz b2ac5d8b45 Fix formatting 2023-11-17 18:44:40 +02:00
Tyrrrz 008c2e64aa Clean up 2023-11-17 18:37:52 +02:00
Tyrrrz 576ee73bfc Update workflows 2023-11-16 21:45:30 +02:00
Tyrrrz db1da5545a Bypass CSharpier in tests 2023-11-16 21:17:10 +02:00
Tyrrrz 5397b0db7d Fix formatting 2023-11-16 21:12:41 +02:00
Tyrrrz e89701e3f9 Provide more context in exception messages 2023-11-16 21:10:24 +02:00
Tyrrrz a46bf9bf11 Update version 2023-11-16 00:43:07 +02:00
Tyrrrz 8dc024d244 Add more comments to the dockerfile 2023-11-16 00:38:18 +02:00
Tyrrrz 9a125db0ea Reformat docker commands 2023-11-15 17:03:36 +02:00
Tyrrrz d9c35f4405 Clean up dockerfile 2023-11-15 15:25:10 +02:00
Tyrrrz 5846129cc6 Use native OpenFolderDialog in GUI 2023-11-14 23:44:29 +02:00
Tyrrrz 6f5f747632 Standardize paths in docker 2023-11-14 23:31:12 +02:00
Tyrrrz 6a71c59b6d Don't need to create a user in Docker anymore with .NET 8 2023-11-14 23:24:28 +02:00
Tyrrrz 73574ade48 Convert some classes to use primary constructors 2023-11-14 22:57:02 +02:00
Tyrrrz 743db67f91 Update references to .NET Runtime 2023-11-14 20:20:35 +02:00
Tyrrrz 5d7a74eece Switch to .NET 8 2023-11-14 20:05:27 +02:00
Tyrrrz 129df42de4 Keep file:/// for absolute paths in HTML exports
Closes #1155
2023-11-13 18:09:09 +02:00
Tyrrrz 6508455f3a Move the tooltip to the correct place 2023-11-12 23:47:16 +02:00
Tyrrrz 50b26c557f Disable "Reuse assets" and "Assets path" options in GUI export setup if "Download assets" is disabled 2023-11-12 23:45:52 +02:00
Tyrrrz b709fc0f15 Update NuGet packages 2023-11-12 23:39:38 +02:00
Tyrrrz c118a0bb94 Fix broken links in docs 2023-11-11 17:49:43 +02:00
Oleksii Holub 1418bec0c7 Update dotnet installation instructions 2023-11-11 17:21:33 +02:00
Oleksii Holub 750fd69a50 Update Docker instructions 2023-11-11 17:10:43 +02:00
Tyrrrz b1297bb7df Set default locale in Docker 2023-11-11 16:56:49 +02:00
Tyrrrz 3189111a0e Install both the iclu-libs and icu-data-full in Docker 2023-11-11 16:52:55 +02:00
Tyrrrz 6ec2c04aa3 Use the full ICU in docker 2023-11-11 16:48:26 +02:00
Tyrrrz 7c014bf64d Add a note about interactivity in the CLI 2023-11-11 16:39:36 +02:00
Tyrrrz c875f8f4f0 Install ICU libs in Docker 2023-11-11 16:27:17 +02:00
Tyrrrz 69e2c337d8 Use alpine images again in Docker 2023-11-11 00:05:27 +02:00
Tyrrrz 77c770acdd Update gitignore file 2023-11-09 13:41:43 +02:00
48 changed files with 430 additions and 516 deletions
+8 -11
View File
@@ -2,7 +2,8 @@
Docker distribution of DiscordChatExporter provides a way to run the app in a virtualized and isolated environment. Due to the nature of Docker, you also don't need to install any prerequisites otherwise required by DCE.
Note that only the CLI flavor of DiscordChatExporter is available for use with Docker.
> **Note**:
> Only the CLI flavor of DiscordChatExporter is available for use with Docker.
## Pulling
@@ -14,9 +15,9 @@ docker pull tyrrrz/discordchatexporter:stable
Note the `:stable` tag. DiscordChatExporter images are tagged according to the following patterns:
- `stable`: Latest stable version release and maps to the latest GitHub release. This tag is updated with release of each new version. Recommended for personal use.
- `latest`: Built from the latest commit and maps to the latest CI build on GitHub. This tag is updated with each new commit to `master` branch. Not recommended for everyday use, but you can use it if you want to try out some features that haven't been officially released yet.
- `x.y.z` (e.g. `2.30.1`): Fixed version release and maps to the corresponding tag on GitHub. This tag is never updated once that version has been released. Recommended for use in automation scenarios.
- `stable` — latest stable version release. This tag is updated with each release of a new project version. Recommended for personal use.
- `x.y.z` (e.g. `2.30.1`) — specific stable version release. This tag is pushed when the corresponding version is released and never updated thereafter. Recommended for use in automation scenarios.
- `latest` — latest (potentially unstable) build. This tag is updated with each new commit to the `master` branch. Not recommended, unless you want to test a new feature that has not been released in a stable version yet.
You can see all available tags [here](https://hub.docker.com/r/tyrrrz/discordchatexporter/tags?ordering=name).
@@ -34,13 +35,13 @@ To export a channel:
docker run --rm -v /path/on/machine:/out tyrrrz/discordchatexporter:stable export -t TOKEN -c CHANNELID
```
If you want colored output and real-time progress reporting, pass the `-it` (interactive) option:
If you want colored output and real-time progress reporting, pass the `-it` (interactive + pseudo-terminal) option:
```console
docker run --rm -it -v /path/on/machine:/out tyrrrz/discordchatexporter:stable export -t TOKEN -c CHANNELID
```
Note the `-v /path/on/machine:/out` option, which instructs Docker to bind the `/out` directory inside the container to a path on your host machine. Replace `/path/on/machine` with the directory you want the files to be saved at.
The `-v /path/on/machine:/out` option instructs Docker to bind the `/out` directory inside the container to a path on your host machine. Replace `/path/on/machine` with the directory you want the files to be saved at.
> **Note**:
> If you are running SELinux, you will need to add the `:z` option after `/out`, e.g.:
@@ -58,14 +59,10 @@ You can also use the current working directory as the output directory by specif
For more information, please refer to the [Dockerfile](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/DiscordChatExporter.Cli.dockerfile) and [Docker documentation](https://docs.docker.com/engine/reference/run).
To get your Token and Channel IDs, please refer to [this page](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md).
To get your Token and Channel IDs, please refer to [this page](Token-and-IDs.md).
## Environment variables
DiscordChatExpoter CLI accepts the `DISCORD_TOKEN` environment variable as a fallback for the `--token` option. You can set this variable either with the `--env` Docker option or with a combination of the `--env-file` Docker option and a `.env` file.
Please refer to the [Docker documentation](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file) for more information.
## Permission issues with Linux hosts
When bounding volumes between the container and the host, files mirrored from the Docker container will be owned by the Docker user (in most setups this is `root`). Please refer to this [issue comment](https://github.com/Tyrrrz/DiscordChatExporter/issues/800#issuecomment-1030471970) for instructions on how to override this behavior.
+23 -39
View File
@@ -1,42 +1,36 @@
# Install .NET runtime
**.NET v7.0 Runtime** is required by **DiscordChatExporter v2.37 and newer**.
**.NET 8.0 Runtime** is required by **DiscordChatExporter**.
If you are using GUI flavor of DiscordChatExporter, the runtime will be installed automatically (since v2.27.1).
If you are using the CLI from Docker, installing the runtime on the host machine is not needed.
> **Note**:
> Installing the **.NET Runtime** is not required if you running **DiscordChatExporter** using [Docker](Docker.md).
- Install
- [Windows and macOS](#windows-and-macos)
- [Linux](#linux)
- [Docker](#docker)
- [Verify installation](#verify-installation-optional)
## Windows
## Windows and macOS
Both the GUI and the CLI flavors of **DiscordChatExporter** for Windows come with a bootstrapper that should automatically install all the required prerequisites. Simply run the application and follow the presented instructions.
**Download directly from one of the links:**
If, for some reason, you need to install the runtime manually, use one of the download links below:
- [.NET v7.0 Runtime for **Windows x64**](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-desktop-7.0.11-windows-x64-installer)
- [.NET v7.0 Runtime for **Windows x86**](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-desktop-7.0.11-windows-x86-installer)
- [.NET v7.0 Runtime for **Macs with Apple silicon**](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-7.0.11-macos-arm64-installer)
- [.NET v7.0 Runtime for **Macs with an Intel processor**](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-7.0.11-macos-x64-installer)
- [.NET 8.0 Runtime for **Windows x64**](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.0-windows-x86-installer)
- [.NET 8.0 Runtime for **Windows x86**](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.0-windows-x64-installer)
- [.NET 8.0 Runtime for **Windows arm64**](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.0-windows-arm64-installer)
> **Note**:
> [How can I tell if my computer is running a 32-bit (x86) or a 64-bit (x64) version of Windows?](https://support.microsoft.com/help/15056/windows-32-64-bit-faq)
## macOS
Use one of the download links below:
- [.NET 8.0 Runtime for **macOS x64**](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.0-macos-x64-installer)
- [.NET 8.0 Runtime for **macOS arm64**](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.0-macos-arm64-installer)
> **Note**:
> [Is my Mac using an Intel processor or Apple silicon?](https://support.apple.com/HT211814)
**Otherwise:**
[Check out the latest version on this page](https://dotnet.microsoft.com/download/dotnet/7.0).
Look for the download link in the '**.NET Runtime**' section, under **Installers**:
[![Screenshot from download page](https://i.imgur.com/t3PB3NC.png)](https://dotnet.microsoft.com/download/dotnet/7.0)
> [Is my Mac using an Intel processor (x64) or Apple Silicon (arm64)?](https://support.apple.com/HT211814)
## Linux
Installing the .NET Runtime works differently depending on which Linux distribution you use.
Check out the instructions for your distro:
Installing the .NET Runtime works differently depending on which Linux distribution you use. Check out the instructions for your distro:
- [Ubuntu](https://docs.microsoft.com/dotnet/core/install/linux-ubuntu)
- [Debian](https://docs.microsoft.com/dotnet/core/install/linux-debian)
@@ -44,25 +38,15 @@ Check out the instructions for your distro:
For other distros, please check the _'Install on Linux'_ menu on the left of [this page](https://docs.microsoft.com/dotnet/core/install/linux).
## Docker
Installing the .NET Runtime is not needed. Please refer to the [Docker usage instructions](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Docker.md) page for more information.
## Verify installation (optional)
You can check which version of **.NET Runtime** is installed by following these instructions:
You can check which version of **.NET Runtime** is installed by running the following command in a terminal:
### Step 1
```console
dotnet --info
```
**Windows:** Open Command Prompt (aka `cmd`)
**macOS and Linux:** Open `Terminal`
### Step 2
Run `dotnet --info`
If the **.NET Runtime** is correctly installed, the command will output the following:
If the **.NET Runtime** is correctly installed, the command will output something similar to the following:
```console
.NET runtimes installed:
+6 -5
View File
@@ -2,15 +2,16 @@
Welcome to the getting started page!
Here you'll learn how to use every **DiscordChatExporter** (DCE for short) feature.
For other things you can do with DCE, check out the [Guides](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Readme.md#Guides) section.
For other things you can do with DCE, check out the [Guides](Readme.md#guides) section.
If you still have unanswered questions after reading this page or if you have encountered a problem, please visit our [FAQ & Troubleshooting](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Troubleshooting.md) section.
If you still have unanswered questions after reading this page or if you have encountered a problem, please visit our [FAQ & Troubleshooting](Troubleshooting.md) section.
The information presented on this page is valid for **all** platforms.
## GUI or CLI?
![GUI vs CLI](https://i.imgur.com/j9OTxRB.png)
**DCE** has two different versions:
- **Graphical User Interface** (**GUI**) - it's the preferred version for newcomers as it is easy to use.
@@ -19,12 +20,12 @@ The information presented on this page is valid for **all** platforms.
You can get it by [downloading](https://github.com/Tyrrrz/DiscordChatExporter/releases/latest) the `DiscordChatExporter.CLI.zip` file.
If you're not comfortable with **Windows'** Command-line (cmd), please choose the GUI.
[**macOS**](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/MacOS.md), [**Linux**](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Linux.md) and [**Docker**](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Docker.md) users can only use the CLI version.
[**macOS**](MacOS.md), [**Linux**](Linux.md) and [**Docker**](Docker.md) users can only use the CLI version.
There are dedicated guides for each version:
- [Using the GUI](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-GUI.md)
- [Using the CLI](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md)
- [Using the GUI](Using-the-GUI.md)
- [Using the CLI](Using-the-CLI.md)
## File formats
+3 -3
View File
@@ -2,7 +2,7 @@
## Installing .NET Runtime
Please follow the [instructions provided here](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Dotnet.md).
Please follow the [instructions provided here](Dotnet.md).
## Downloading and using DiscordChatExporter.Cli
@@ -21,6 +21,6 @@ If the above command throws a "Permission denied" error, execute this command to
chmod 644 *.dll DiscordChatExporter.*
```
> [How to get Token and Channel IDs](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md).
> [How to get Token and Channel IDs](Token-and-IDs.md).
There's much more you can do with DCE.CLI! Read the [CLI explained](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#dcecli-commands-) page to get started.
There's much more you can do with DCE.CLI! Read the [CLI explained](Using-the-CLI.md) page to get started.
+3 -3
View File
@@ -4,7 +4,7 @@
## Installing .NET Runtime
Please follow the [instructions provided here](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Dotnet.md).
Please follow the [instructions provided here](Dotnet.md).
## Downloading and using DiscordChatExporter.Cli
@@ -17,6 +17,6 @@ Please follow the [instructions provided here](https://github.com/Tyrrrz/Discord
dotnet DiscordChatExporter.Cli.dll export -t TOKEN -c CHANNEL
```
> [How to get Token and Channel IDs](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md).
> [How to get Token and Channel IDs](Token-and-IDs.md).
There's much more you can do with DCE.CLI! Read the [CLI explained](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#dcecli-commands-) page to get started.
There's much more you can do with DCE.CLI! Read the [CLI explained](Using-the-CLI.md) page to get started.
+16 -16
View File
@@ -2,21 +2,21 @@
## Installation & Usage
- [Get .NET Core Runtime](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Dotnet.md) (Required for CLI; Installed automatically for GUI; Not required in Docker)
- [Windows](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#gui-or-cli) | [macOS](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/MacOS.md) | [Linux](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Linux.md) | [Docker](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Docker.md)
- [Get .NET Core Runtime](Dotnet.md) (Required for CLI; Installed automatically for GUI; Not required in Docker)
- [Windows](Getting-started.md#gui-or-cli) | [macOS](MacOS.md) | [Linux](Linux.md) | [Docker](Docker.md)
- Getting started:
- [Using the GUI](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#using-the-gui)
- [Using the CLI](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#using-the-cli)
- [File formats](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#file-formats)
- [Using the GUI](Using-the-CLI.md)
- [Using the CLI](Using-the-CLI.md)
- [File formats](Getting-started.md#file-formats)
## Guides
- [How to get Token and Channel IDs](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md)
- [How to use message filters](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Message-filters.md)
- [How to get Token and Channel IDs](Token-and-IDs.md)
- [How to use message filters](Message-filters.md)
- Export scheduling with CLI:
- [Windows](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Scheduling-Windows.md)
- [macOS](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Scheduling-MacOS.md)
- [Linux](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Scheduling-Linux.md)
- [Windows](Scheduling-Windows.md)
- [macOS](Scheduling-MacOS.md)
- [Linux](Scheduling-Linux.md)
## Video tutorial
@@ -26,9 +26,9 @@
## FAQ & Troubleshooting
- [General questions](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Troubleshooting.md#general)
- [First steps help](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Troubleshooting.md#first-steps)
- [It's crashing/failing](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Troubleshooting.md#DCE-is-crashingfailing)
- [.NET Core Runtime is required](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Troubleshooting.md#net-core-runtime-is-required)
- [Errors](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Troubleshooting.md#errors)
- [**More help**](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Troubleshooting.md)
- [General questions](Troubleshooting.md#general)
- [First steps help](Troubleshooting.md#first-steps)
- [It's crashing/failing](Troubleshooting.md#DCE-is-crashingfailing)
- [.NET Core Runtime is required](Troubleshooting.md#net-core-runtime-is-required)
- [Errors](Troubleshooting.md#errors)
- [**More help**](Troubleshooting.md)
+4 -6
View File
@@ -1,10 +1,8 @@
# Scheduling exports with Cron
Make sure you already have **DiscordChatExporter.CLI** and **.NET Core** properly installed ([instructions here](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Linux.md)).
Make sure you already have **DiscordChatExporter.CLI** and **.NET Core** properly installed ([instructions here](Linux.md)).
You can use Cron on macOS, but [this method](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/scheduling-MacOS.md) is preferred.
---
## Creating the script
1. Open Terminal and create a new text file with `nano /path/to/DiscordChatExporter/cron.sh`
@@ -66,8 +64,8 @@ exit 0
3. Replace:
- `tokenhere` with your [Token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md).
- `channelhere` with a [Channel ID](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md).
- `tokenhere` with your [Token](Token-and-IDs.md).
- `channelhere` with a [Channel ID](Token-and-IDs.md).
- `dceFOLDERpathhere` with DCE's **directory path** (e.g. `/path/to/folder`, NOT `/path/to/folder/DiscordChatExporter.dll`).
- `filenamehere` with the exported channel's filename, without spaces.
- `dirhere` with the export directory (e.g. /home/user/Documents/Discord\ Exports).
+4 -4
View File
@@ -2,7 +2,7 @@
Scheduling on macOS is a bit tricky, but it should work if you follow the instructions accordingly.
Make sure you already have **DiscordChatExporter.CLI** and **.NET Core** properly installed ([instructions here](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/macOS-usage-instructions.md)).
Make sure you already have **DiscordChatExporter.CLI** and **.NET Core** properly installed ([instructions here](MacOS.md)).
## Creating the script
@@ -70,8 +70,8 @@ exit 0
4. Replace:
- `tokenhere` with your [Token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md)
- `channelhere` with a [Channel ID](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md)
- `tokenhere` with your [Token](Token-and-IDs.md)
- `channelhere` with a [Channel ID](Token-and-IDs.md)
- `dceFOLDERpathhere` with DCE's **directory's path** (e.g. `/Users/user/Desktop/DiscordChatExporterFolder`, NOT `/Users/user/Desktop/DiscordChatExporterFolder/DiscordChatExporter.DLL`)
- `filenamehere` with the exported channel's filename, without spaces
- `dirhere` with the directory you want the files to be saved at (e.g. `/Users/user/Documents/Discord\ Exports`)
@@ -168,7 +168,7 @@ Omitted keys are interpreted as wildcards, for example, if you delete the Minute
Be aware that if you set the day to '31', the script will only run on months that have the 31st day.
**Check the examples below ([or skip to step 3 (loading the file)](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/scheduling-MacOS.md#3-loading-the-plist-into-launchctl)):**
**Check the examples below ([or skip to step 3 (loading the file)](#3-loading-the-plist-into-launchctl)):**
Export everyday at 5:15 PM:
+5 -3
View File
@@ -2,10 +2,12 @@
We'll be using [DiscordChatExporter CLI](https://github.com/Tyrrrz/DiscordChatExporter/releases/latest), PowerShell, and Task Scheduler.
## Creating the script
1. Open a text editor such as Notepad and paste:
```console
# Info: https://github.com/Tyrrrz/DiscordChatExporter/wiki
# Info: https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs
$TOKEN = "tokenhere"
$CHANNEL = "channelhere"
@@ -31,8 +33,8 @@ exit
2. Replace:
- `tokenhere` with your [Token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md)
- `channelhere` with a [Channel ID](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md)
- `tokenhere` with your [Token](Token-and-IDs.md)
- `channelhere` with a [Channel ID](Token-and-IDs.md)
- `exefolderhere` with the .exe **directory's path** (e.g. C:\Users\User\Desktop\DiscordChatExporter)
- `filenamehere` with a filename without spaces
- `dirhere` with the export directory (e.g. C:\Users\User\Documents\Exports)
+6 -6
View File
@@ -48,12 +48,12 @@ Prerequisite step: Navigate to [discord.com](https://discord.com) and login.
<br clear="right" />
<br />
4. <img width="500" align="right" src="https://i.imgur.com/rnZG8Id.png" />Click the text box labelled `Filter` and type `library`. The entries will filter down to a single entry named `library`.
4. <img width="500" align="right" src="https://i.imgur.com/rnZG8Id.png" />Click the text box labelled `Filter` and type `messages`. The entries will filter down to a single request named `messages`. If the request doesn't appear, switch to any other Discord channel to trigger it.
<br clear="right" />
<br />
5. <img width="500" align="right" src="https://i.imgur.com/29dE3fR.png" />Click the entry named `library`. A panel will open to the right and display details about the entry. Click the `Headers` tab if it isn't already active.
5. <img width="500" align="right" src="https://i.imgur.com/29dE3fR.png" />Click the entry named `messages`. A panel will open to the right and display details about the entry. Click the `Headers` tab if it isn't already active.
<br clear="right" />
<br />
@@ -136,12 +136,12 @@ Prerequisite step: Navigate to [discord.com](https://discord.com) and login.
<br clear="right" />
<br />
3. <img width="500" align="right" src="https://i.imgur.com/efUCfBO.png" />Type `library` into the filter. The network request list will filter out any entries not containing the string `library`.
3. <img width="500" align="right" src="https://i.imgur.com/efUCfBO.png" />Type `messages` into the filter. The network request list will filter out any entries not containing the string `messages`. If the request doesn't appear, switch to any other Discord channel to trigger it.
<br clear="right" />
<br />
4. <img width="500" align="right" src="https://i.imgur.com/cdJZ7Q1.png" />Click `library`. The [network request details pane](https://firefox-source-docs.mozilla.org/devtools-user/network_monitor/request_details/index.html) will display. The [headers tab](https://firefox-source-docs.mozilla.org/devtools-user/network_monitor/request_details/index.html#network-monitor-request-details-headers-tab) should be active by default. If it isnt, click it.
4. <img width="500" align="right" src="https://i.imgur.com/cdJZ7Q1.png" />Click `messages`. The [network request details pane](https://firefox-source-docs.mozilla.org/devtools-user/network_monitor/request_details/index.html) will display. The [headers tab](https://firefox-source-docs.mozilla.org/devtools-user/network_monitor/request_details/index.html#network-monitor-request-details-headers-tab) should be active by default. If it isnt, click it.
<br clear="right" />
<br />
@@ -232,7 +232,7 @@ Prerequisite step: Navigate to [discord.com](https://discord.com) and login.
4. Launch Discord.
5. To find your user token, continue [here](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#in-chrome).
5. To find your user token, continue [here](#in-chrome).
#### Via settings menu (BetterDiscord only)
@@ -252,7 +252,7 @@ Prerequisite step: Navigate to [discord.com](https://discord.com) and login.
<br />
4. Press <kbd>Esc</kbd>. The settings page will close.
5. To find your user token, continue [here](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#in-chrome).
5. To find your user token, continue [here](#in-chrome).
## How to get a Bot Token
+16 -21
View File
@@ -20,7 +20,7 @@ A token can be used to log into your account, so treat it like a password and ne
### How can I reset my token?
Follow the [instructions here](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md).
Follow the [instructions here](Token-and-IDs.md).
### Will I get banned if I use this?
@@ -66,31 +66,26 @@ No.
### How can I find my token?
Check the following page: [Obtaining token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md)
Check the following page: [Obtaining token](Token-and-IDs.md)
### When I open DCE a black window pops up quickly or nothing shows up
If you have [.NET Core Runtime correctly installed](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Dotnet.md), you might have downloaded the CLi flavor, try [downloading the GUI](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#gui-or-cli) instead.
### I can't open DCE, it sends me to a Visual Studio webpage
Check the following page:
[Installation and usage](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Readme.md#installation--usage)
If you have [.NET Core Runtime correctly installed](Dotnet.md), you might have downloaded the CLi flavor, try [downloading the GUI](Getting-started.md#gui-or-cli) instead.
### How do I run DCE on macOS or Linux?
Check the following pages:
- [macOS usage instructions](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/MacOS.md)
- [Linux usage instructions](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Linux.md)
- [macOS usage instructions](MacOS.md)
- [Linux usage instructions](Linux.md)
### How can I set DCE to export automatically at certain times?
Check the following pages to learn how to schedule **DiscordChatExporter.CLI** runs (advanced):
- [Windows scheduling](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/scheduling-windows.md)
- [macOS scheduling](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/scheduling-MacOS.md)
- [Linux scheduling](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/scheduling-Linux.md)
- [Windows scheduling](Scheduling-Windows.md)
- [macOS scheduling](Scheduling-MacOS.md)
- [Linux scheduling](Scheduling-Linux.md)
### The exported file is too large, I can't open it
@@ -98,13 +93,13 @@ Try opening it with a different program, try partitioning or use a different fil
### DCE is crashing/failing
Check the following page: [Installing .NET Core Runtime](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Dotnet.md)
Check the following page: [Installing .NET Core Runtime](Dotnet.md)
If you already have .NET Core installed, please check if your problem is a [known issue](https://github.com/Tyrrrz/DiscordChatExporter/issues?q=is%3Aissue) before [opening a bug report](https://github.com/Tyrrrz/DiscordChatExporter/issues/new).
### .NET Core Runtime is required
Check the following page: [Installing .NET Core Runtime](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Dotnet.md)
Check the following page: [Installing .NET Core Runtime](Dotnet.md)
### I see messages in the export, but they have no content
@@ -116,25 +111,25 @@ Your bot is missing the 'Message Content Intent'. Go to the [Discord Developer P
Check the following page:
- [Using the CLI](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#using-the-cli)
- [Using the CLI](Using-the-CLI.md)
If you're using **Docker**, please refer to the [Docker Usage Instructions](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Docker.md) instead.
If you're using **Docker**, please refer to the [Docker Usage Instructions](Docker.md) instead.
### Where can I find the 'Channel IDs'?
Check the following page:
- [Obtaining Channel IDs](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md)
- [Obtaining Channel IDs](Token-and-IDs.md)
### I can't find Docker exported chats
Check the following page:
- [Docker usage instructions](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/docker)
- [Docker usage instructions](Docker.md)
### I can't export Direct Messages
Make sure you're [copying the DM Channel ID](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-a-direct-message-channel-id), not the person's user ID.
Make sure you're [copying the DM Channel ID](Token-and-IDs.md#how-to-get-a-direct-message-channel-id), not the person's user ID.
## Errors
@@ -149,7 +144,7 @@ DiscordChatExporter.Domain.Exceptions.DiscordChatExporterException: Authenticati
DiscordChatExporter.Domain.Exceptions.DiscordChatExporterException: Requested resource does not exist.
```
↳ Check your channel ID, it might be invalid. [Read this if you need help](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md).
↳ Check your channel ID, it might be invalid. [Read this if you need help](Token-and-IDs.md).
```console
DiscordChatExporter.Domain.Exceptions.DiscordChatExporterException: Access is forbidden.
+70 -166
View File
@@ -3,8 +3,8 @@
## Guide
> **Note**:
> Make sure you have [.NET Core installed](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Dotnet.md) before attempting to run the commands below.
> **Docker** users, please refer to the [Docker usage instructions](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Docker.md).
> Make sure you have [.NET Core installed](Dotnet.md) before attempting to run the commands below.
> **Docker** users, please refer to the [Docker usage instructions](Docker.md).
## Step 1
@@ -25,7 +25,8 @@ You can also drag and drop the folder on **every platform**.
## Step 3
Now we're ready to run the commands. The examples on this page follow the Windows file path format, change the file paths according to your system.
Now we're ready to run the commands. The examples on this page follow the Windows file path format, change the file
paths according to your system.
Type the following in Command Prompt (Terminal), then press ENTER to run it. This will list DCE's options.
@@ -33,52 +34,36 @@ Type the following in Command Prompt (Terminal), then press ENTER to run it. Thi
dotnet DiscordChatExporter.Cli.dll
```
> **Docker** users, please refer to the [Docker usage instructions](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Docker.md).
> **Docker** users, please refer to the [Docker usage instructions](Docker.md).
## CLI commands
| Command | Description |
| ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
| [export](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#export) | Exports a channel |
| [exportdm](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#exportdm) | Exports all direct message channels |
| [exportguild](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#exportguild) | Exports all channels within the specified server |
| [exportall](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#exportall) | Exports all accessible channels |
| [channels](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#channels) | Outputs the list of channels in the given server |
| [dm](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#dm) | Outputs the list of direct message channels |
| [guilds](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#guilds) | Outputs the list of accessible servers |
| [guide](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#guide) | Explains how to obtain token, guild, and channel ID |
| Command | Description |
|-------------------------|-----------------------------------------------------|
| export | Exports a channel |
| exportdm | Exports all direct message channels |
| exportguild | Exports all channels within the specified server |
| exportall | Exports all accessible channels |
| channels | Outputs the list of channels in the given server |
| dm | Outputs the list of direct message channels |
| guilds | Outputs the list of accessible servers |
| guide | Explains how to obtain token, guild, and channel ID |
To use the commands, you'll need a token. For the instructions on how to get a token, please refer to [this page](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md), or run `dotnet DiscordChatExporter.Cli.dll guide`.
To get help with a specific command, please run:
To use the commands, you'll need a token. For the instructions on how to get a token, please refer to [this page](Token-and-IDs.md), or run `dotnet DiscordChatExporter.Cli.dll guide`.
To get help with a specific command, run:
```console
dotnet DiscordChatExporter.Cli.dll command -h
dotnet DiscordChatExporter.Cli.dll command --help
```
### `export`
For example, to figure out how to use the `export` command, run:
With this command, you can export **server channels** and **direct messages**.
```console
dotnet DiscordChatExporter.Cli.dll export --help
```
| | Option | Description |
| ------ | --------------------------------------------------------------------------------------------------------------------- | ----------- |
| **\*** | [-c](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#basic-usage) | [Channel ID(s)](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-guild-id-or-guild-channel-id) |
| **\*** | [-t](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#basic-usage) | [Authorization token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-user-token). Environment variable: `DISCORD_TOKEN` |
| | [-o](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#changing-the-output-filename) | Output file or directory path |
| | [-f](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#changing-the-format) | [Output file format](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#file-formats). Default: HtmlDark |
| | [--after](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#date-ranges) | Only include messages sent after this date |
| | [--before](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#date-ranges) | Only include messages sent before this date |
| | [-p](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#partitioning) | Split output into partitions, each limited to this number of messages (e.g. 100) or file size (e.g. 10mb) |
| | [--filter](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Message-filters.md) | Special notation for filtering the messages that get included in the export |
| | [--media](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#downloading-assets) | Download assets referenced by the export (user avatars, attached files, embedded images, etc.). Default: false |
| | [--reuse-media](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#reuse-assets) | Reuse previously downloaded assets to avoid redundant requests. Default: false |
| | [--media-dir](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#downloading-assets) | Directory to store assets from all exported channels in the same place |
| | [--locale](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#changing-the-date-format) | Format used when writing dates. Default: en-US |
| | -h | Shows help text |
> **Note**:
> Options with an asterisk (**\***) are required. The order of the options doesn't matter.
#### Basic usage
## Export a specific channel
You can quickly export with DCE's default settings by using just `-t token` and `-c channelid`.
@@ -88,7 +73,8 @@ dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555
#### Changing the format
You can change the export format to `HtmlDark`, `HtmlLight`, `PlainText` `Json` or `Csv` with `-f format`. The default format is `HtmlDark`.
You can change the export format to `HtmlDark`, `HtmlLight`, `PlainText` `Json` or `Csv` with `-f format`. The default
format is `HtmlDark`.
```console
dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 -f Json
@@ -104,7 +90,8 @@ dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 -o myserver.htm
#### Changing the output directory
You can change the export directory by using `-o` and providing a path that ends with a slash or does not have a file extension.
You can change the export directory by using `-o` and providing a path that ends with a slash or does not have a file
extension.
If any of the folders in the path have a space in its name, escape them with quotes (").
```console
@@ -129,7 +116,9 @@ You can use template tokens to generate the output file path based on the guild
dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 -o "C:\Discord Exports\%G\%T\%C.html"
```
Assuming you are exporting a channel named `"my-channel"` in the `"Text channels"` category from a server called `"My server"`, you will get the following output file path: `C:\Discord Exports\My server\Text channels\my-channel.html`
Assuming you are exporting a channel named `"my-channel"` in the `"Text channels"` category from a server
called `"My server"`, you will get the following output file
path: `C:\Discord Exports\My server\Text channels\my-channel.html`
Here is the full list of supported template tokens:
@@ -163,7 +152,8 @@ dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 -p 20mb
#### Downloading assets
If this option is set, the export will include additional files such as user avatars, attached files, images, etc.
Only files that are referenced by the export are downloaded, which means that, for example, user avatars will not be downloaded when using the plain text (TXT) export format.
Only files that are referenced by the export are downloaded, which means that, for example, user avatars will not be
downloaded when using the plain text (TXT) export format.
A folder containing the assets will be created along with the exported chat. They must be kept together.
```console
@@ -172,7 +162,8 @@ dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 --media
#### Reusing assets
Previously downloaded assets can be reused to skip redundant downloads as long as the chat is always exported to the same folder. Using this option can speed up future exports. This option requires the `--media` option.
Previously downloaded assets can be reused to skip redundant downloads as long as the chat is always exported to the
same folder. Using this option can speed up future exports. This option requires the `--media` option.
```console
dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 --media --reuse-media
@@ -180,7 +171,8 @@ dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 --media --reuse
#### Changing the media directory
By default, the media directory is created alongside the exported chat. You can change this by using `--media-dir` and providing a path that ends with a slash. All of the exported media will be stored in this directory.
By default, the media directory is created alongside the exported chat. You can change this by using `--media-dir` and
providing a path that ends with a slash. All of the exported media will be stored in this directory.
```console
dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 --media --media-dir "C:\Discord Media"
@@ -188,7 +180,8 @@ dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 --media --media
#### Changing the date format
You can customize how dates are formatted in the exported files by using `--locale` and inserting one of Discord's locales. The default locale is `en-US`.
You can customize how dates are formatted in the exported files by using `--locale` and inserting one of Discord's
locales. The default locale is `en-US`.
```console
dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 --locale "de-DE"
@@ -211,67 +204,32 @@ dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 --after "2019-0
```
**Messages sent in a date range**
Use `--before` and `--after` to export messages sent during the provided date range. E.g. messages sent between September 17th, 2019 11:34 PM and September 18th:
Use `--before` and `--after` to export messages sent during the provided date range. E.g. messages sent between
September 17th, 2019 11:34 PM and September 18th:
```console
dotnet DiscordChatExporter.Cli.dll export -t "mfa.Ifrn" -c 53555 --after "2019-09-17 23:34" --before "2019-09-18"
```
You can try different formats like `17-SEP-2019 11:34 PM` or even refine your ranges down to milliseconds `17-SEP-2019 23:45:30.6170`!
You can try different formats like `17-SEP-2019 11:34 PM` or even refine your ranges down to
milliseconds `17-SEP-2019 23:45:30.6170`!
Don't forget to quote (") the date if it has spaces!
More info about .NET date formats [here](https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).
More info about .NET date
formats [here](https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).
### `exportdm`
### Export channels from a specific guild (server)
This command exports all your **direct messages**.
To export all channels in a specific guild, use the `exportguild` command and provide the guild ID through the `-g|--guild` option:
| | Option | Description |
| ------ | --------------------------------------------------------------------------------------------------------------------- | ----------- |
| **\*** | [-c](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#basic-usage) | [Channel ID(s)](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-guild-id-or-guild-channel-id) |
| **\*** | [-t](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#basic-usage) | [Authorization token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-user-token). Environment variable: `DISCORD_TOKEN` |
| | [-o](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#changing-the-output-filename) | Output file or directory path |
| | [-f](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#changing-the-format) | [Output file format](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#file-formats). Default: HtmlDark |
| | [--after](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#date-ranges) | Only include messages sent after this date |
| | [--before](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#date-ranges) | Only include messages sent before this date |
| | [-p](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#partitioning) | Split output into partitions, each limited to this number of messages (e.g. 100) or file size (e.g. 10mb) |
| | [--filter](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Message-filters.md) | Special notation for filtering the messages that get included in the export |
| | [--media](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#downloading-assets) | Download assets referenced by the export (user avatars, attached files, embedded images, etc.). Default: false |
| | [--reuse-media](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#reuse-assets) | Reuse previously downloaded assets to avoid redundant requests. Default: false |
| | [--media-dir](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#downloading-assets) | Directory to store assets from all exported channels in the same place |
| | [--locale](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#changing-the-date-format) | Format used when writing dates. Default: en-US |
| | -h | Shows help text |
> **Note**:
> Options with an asterisk (**\***) are required. The order of the options doesn't matter.
### `exportguild`
This command exports all channels of a **server**.
| | Option | Description |
| ------ | ------------------------------------------------------------------------------------------------------------------------- | ----------- |
| **\*** | -g | [Server ID](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-guild-id-or-guild-channel-id) |
| **\*** | [-t](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#basic-usage) | [Authorization token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-user-token). Environment variable: `DISCORD_TOKEN` |
| | [-o](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#changing-the-output-filename) | Output file or directory path |
| | [-f](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#changing-the-format) | [Output file format](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#file-formats). Default: HtmlDark |
| | [--after](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#date-ranges) | Only include messages sent after this date |
| | [--before](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#date-ranges) | Only include messages sent before this date |
| | [-p](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#partitioning) | Split output into partitions, each limited to this number of messages (e.g. 100) or file size (e.g. 10mb) |
| | [--filter](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Message-filters.md) | Special notation for filtering the messages that get included in the export |
| | [--media](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#downloading-assets) | Download assets referenced by the export (user avatars, attached files, embedded images, etc.). Default: false |
| | [--reuse-media](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#reuse-assets) | Reuse previously downloaded assets to avoid redundant requests. Default: false |
| | [--media-dir](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#downloading-assets) | Directory to store assets from all exported channels in the same place |
| | [--locale](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#changing-the-date-format) | Format used when writing dates. Default: en-US |
| | [--include-threads](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#including-threads) | Specify whether to include threads (and which type) in the export. By default, threads are not included. It has possible values of `none`, `active`, or `all`, indicating which threads should be included. To include both active and archived threads, use `--include-threads all`. |
| | [--include-vc](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#including-voice-channels) | Include voice channels in the export. Default: true |
| | -h | Shows help text |
> **Note**:
> Options with an asterisk (**\***) are required. The order of the options doesn't matter.
```console
dotnet DiscordChatExporter.Cli.dll exportguild -t "mfa.Ifrn" -g 21814
```
#### Including threads
By default, threads are not included in the export. You can change this behavior by using `--include-threads` and specifying which threads should be included. It has possible values of `none`, `active`, or `all`, indicating which threads should be included. To include both active and archived threads, use `--include-threads all`.
By default, threads are not included in the export. You can change this behavior by using `--include-threads` and
specifying which threads should be included. It has possible values of `none`, `active`, or `all`, indicating which
threads should be included. To include both active and archived threads, use `--include-threads all`.
```console
dotnet DiscordChatExporter.Cli.dll exportguild -t "mfa.Ifrn" -g 21814 --include-threads all
@@ -279,36 +237,21 @@ dotnet DiscordChatExporter.Cli.dll exportguild -t "mfa.Ifrn" -g 21814 --include-
#### Including voice channels
By default, voice channels are included in the export. You can change this behavior by using `--include-vc` and specifying whether to include voice channels in the export. It has possible values of `true` or `false`, to exclude voice channels, use `--include-vc false`.
By default, voice channels are included in the export. You can change this behavior by using `--include-vc` and
specifying whether to include voice channels in the export. It has possible values of `true` or `false`, to exclude
voice channels, use `--include-vc false`.
```console
dotnet DiscordChatExporter.Cli.dll exportguild -t "mfa.Ifrn" -g 21814 --include-vc false
```
### `exportall`
### Export all channels
This command exports **all accessible channels**, including server channels and DMs.
To export all accessible channels, use the `exportall` command:
| | Option | Description |
| ------ | ------------------------------------------------------------------------------------------------------------------------- | ----------- |
| **\*** | [-t](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#basic-usage) | [Authorization token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-user-token). Environment variable: `DISCORD_TOKEN` |
| | [-o](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#changing-the-output-filename) | Output file or directory path |
| | [-f](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#changing-the-format) | [Output file format](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#file-formats). Default: HtmlDark |
| | [--after](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#date-ranges) | Only include messages sent after this date |
| | [--before](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#date-ranges) | Only include messages sent before this date |
| | [-p](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#partitioning) | Split output into partitions, each limited to this number of messages (e.g. 100) or file size (e.g. 10mb) |
| | [--filter](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Message-filters.md) | Special notation for filtering the messages that get included in the export |
| | [--media](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#downloading-assets) | Download assets referenced by the export (user avatars, attached files, embedded images, etc.). Default: false |
| | [--reuse-media](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#reuse-assets) | Reuse previously downloaded assets to avoid redundant requests. Default: false |
| | [--media-dir](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#downloading-assets) | Directory to store assets from all exported channels in the same place |
| | [--locale](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#changing-the-date-format) | Format used when writing dates. Default: en-US |
| | [--include-threads](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#including-threads) | Specify whether to include threads (and which type) in the export. By default, threads are not included. It has possible values of `none`, `active`, or `all`, indicating which threads should be included. To include both active and archived threads, use `--include-threads all`. |
| | [--include-vc](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#including-voice-channels) | Include voice channels in the export. Default: true |
| | [--include-dm](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#excluding-dms) | Include direct messages in the export. Default: true |
| | -h | Shows help text |
> **Note**:
> Options with an asterisk (**\***) are required. The order of the options doesn't matter.
```console
dotnet DiscordChatExporter.Cli.dll exportall -t "mfa.Ifrn"
```
#### Excluding DMs
@@ -318,65 +261,26 @@ To exclude DMs, add the `--include-dm false` option.
dotnet DiscordChatExporter.Cli.dll exportall -t "mfa.Ifrn" --include-dm false
```
### `channels`
### List channels in a guild (server)
This command outputs a **server's channels** in the following format:
`Channel ID | Channel Name`
To save the output to a file, run the command below. If the file already exists, it will be overwritten.
| | Option | Description |
| ------ | ---------------------------------------------------------------------------------------------------- | ----------- |
| **\*** | -g | [Server ID](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-guild-id-or-guild-channel-id) |
| **\*** | [-t](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#basic-usage) | [Authorization token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-user-token). Environment variable: `DISCORD_TOKEN` |
| | [--include-threads](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#including-threads) | Specify whether to include threads (and which type) in the output. By default, threads are not included. It has possible values of `none`, `active`, or `all`, indicating which threads should be included. To include both active and archived threads, use `--include-threads all`. |
| | [--include-vc](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Using-the-CLI.md#including-voice-channels) | Include voice channels in the output. Default: true |
| | -h | Shows help text |
> **Note**:
> Options with an asterisk (**\***) are required. The order of the options doesn't matter.
To save the output to a file, run the command with `> C:\path\…` like the example below. If the file already exists, it will be overwritten.
To list the channels available in a specific guild, use the `channels` command and provide the guild ID through the `-g|--guild` option:
```console
dotnet DiscordChatExporter.Cli.dll channels -t "mfa.Ifrn" -g 21814 > C:\path\to\output.txt
dotnet DiscordChatExporter.Cli.dll channels -t "mfa.Ifrn" -g 21814
```
### `dm`
### List direct message channels
This command outputs a list of your **direct messages**.
| | Option | Description |
| ------ | ---------------------------------------------------------------------------------------------------- | ----------- |
| **\*** | [-t](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#basic-usage) | [Authorization token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-user-token). Environment variable: `DISCORD_TOKEN` |
| | -h | Shows help text |
> **Note**:
> Options with an asterisk (**\***) are required. The order of the options doesn't matter.
To save the output to a file, run the command with `> C:\path\…` like the example below. If the file already exists, it will be overwritten.
To list all DM channels accessible to the current account, use the `dm` command:
```console
dotnet DiscordChatExporter.Cli.dll dm -t "mfa.Ifrn" > C:\path\to\output.txt
dotnet DiscordChatExporter.Cli.dll dm -t "mfa.Ifrn"
```
### `guilds`
### List guilds (servers)
This command outputs a list of your **servers**.
| | Option | Description |
| ------ | ---------------------------------------------------------------------------------------------------- | ----------- |
| **\*** | [-t](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Getting-started.md#basic-usage) | [Authorization token](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md#how-to-get-user-token). Environment variable: `DISCORD_TOKEN` |
| | -h | Shows help text |
> **Note**:
> Options with an asterisk (**\***) are required. The order of the options doesn't matter.
To save the output to a file, run the command with `> C:\path\…` like the example below. If the file already exists, it will be overwritten.
To list all guilds accessible by the current account, use the `guilds` command:
```console
dotnet DiscordChatExporter.Cli.dll guilds -t "mfa.Ifrn" > C:\path\to\output.txt
```
### `guide`
This command explains [how to get your token, guild, and channel IDs](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Token-and-IDs.md).
```
+1 -1
View File
@@ -46,7 +46,7 @@ In this screen you can customize the following:
- **Partition limit** (Optional) - Split output into partitions, each limited to this number of messages (e.g. 100) or file size (e.g. 10mb). For example, a channel with 36 messages set to be partitioned every 10 messages will output 4 files.
- **Message Filter** (Optional) - Special notation for filtering the messages that get included in the export. See [Message filters](https://github.com/Tyrrrz/DiscordChatExporter/blob/master/.docs/Message-filters.md) for more info.
- **Message Filter** (Optional) - Special notation for filtering the messages that get included in the export. See [Message filters](Message-filters.md) for more info.
- **Format markdown** (Optional) - Disable markdown processing when exporting. You can use this to produce JSON or plain text exports without unwrapping mentions, custom emoji, and certain other special tokens.
+5 -6
View File
@@ -1,13 +1,14 @@
name: docker
on:
workflow_dispatch:
push:
pull_request:
jobs:
# Outputs from this job aren't really used, but it's here to verify that
# the Dockerfile builds correctly on pull requests.
build:
pack:
runs-on: ubuntu-latest
permissions:
actions: write
@@ -22,11 +23,10 @@ jobs:
- name: Build image
run: >
docker buildx build
docker buildx build .
--file DiscordChatExporter.Cli.dockerfile
--platform linux/amd64,linux/arm64
--output type=tar,dest=DiscordChatExporter.Cli.Docker.tar
.
- name: Upload artifacts
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # 3.1.3
@@ -37,7 +37,7 @@ jobs:
deploy:
# Deploy to DockerHub only on tag push or master branch push
if: ${{ github.event_name == 'push' && (github.ref_type == 'tag' || github.ref_type == 'branch' && github.ref_name == 'master') }}
if: ${{ github.ref_type == 'tag' || github.ref_type == 'branch' && github.ref_name == 'master' }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -56,11 +56,10 @@ jobs:
- name: Build & push image
run: >
docker buildx build
docker buildx build .
--file DiscordChatExporter.Cli.dockerfile
--platform linux/amd64,linux/arm64
--push
--tag tyrrrz/discordchatexporter:latest
${{ github.ref_type == 'tag' && '--tag tyrrrz/discordchatexporter:$GITHUB_REF_NAME' || '' }}
${{ github.ref_type == 'tag' && '--tag tyrrrz/discordchatexporter:stable' || '' }}
.
+30 -6
View File
@@ -1,6 +1,7 @@
name: main
on:
workflow_dispatch:
push:
pull_request:
@@ -10,7 +11,7 @@ env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
test:
format:
runs-on: windows-latest
permissions:
contents: read
@@ -22,15 +23,36 @@ jobs:
- name: Install .NET
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # 3.2.0
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Verify formatting
run: >
dotnet build
-t:CSharpierFormat
--configuration Release
test:
# Tests need access to secrets, so we can't run them against PRs because of limited trust
if: ${{ github.event_name != 'pull_request' }}
runs-on: windows-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # 4.1.0
- name: Install .NET
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # 3.2.0
with:
dotnet-version: 8.0.x
- name: Run tests
# Tests need access to secrets, so we can't run them against PRs because of limited trust
if: ${{ github.event_name != 'pull_request' }}
env:
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
run: >
dotnet test
-p:CSharpier_Bypass=true
--configuration Release
--logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
--collect:"XPlat Code Coverage"
@@ -62,11 +84,12 @@ jobs:
- name: Install .NET
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # 3.2.0
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Publish app
run: >
dotnet publish ${{ matrix.app }}
-p:CSharpier_Bypass=true
--output ${{ matrix.app }}/bin/publish/
--configuration Release
@@ -78,9 +101,10 @@ jobs:
if-no-files-found: error
release:
if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }}
if: ${{ github.ref_type == 'tag' }}
needs:
- format
- test
- pack
+6 -17
View File
@@ -1,23 +1,12 @@
# User-specific files
.vs/
.idea/
*.suo
*.user
*.userosscache
*.sln.docstates
.idea/
.vs/
.vscode/
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/
bin/
obj/
# Coverage
*.opencover.xml
# Test results
TestResults/
+16
View File
@@ -1,5 +1,21 @@
# Changelog
## v2.42.5 (23-Nov-2023)
- General changes:
- Fixed an issue where the application crashed when trying to export a channel that contained a message with an invalid timestamp (e.g. `<t:0:x>`).
## v2.42.4 (16-Nov-2023)
- General changes:
- Switched from .NET 7.0 to .NET 8.0. If running on Windows, the application should update all required prerequisites automatically. Alternatively, you can download the latest version of the runtime for your system [here](https://dotnet.microsoft.com/download/dotnet/8.0).
- CLI changes:
- Added a message that is displayed when the application is running with the output stream redirected, informing the user that they will not get rich progress reporting in this mode.
- GUI changes:
- Changed the presentation of the "Reuse assets" and "Assets path" options, such that the corresponding controls are now disabled if the "Download assets" option is not enabled.
- HTML changes:
- Fixed an issue where exporting a channel with a custom assets path could result in an HTML output that did not render properly in Firefox.
## v2.42.3 (09-Nov-2023)
- JSON changes:
+2 -2
View File
@@ -1,8 +1,8 @@
<Project>
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Version>2.42.3</Version>
<TargetFramework>net8.0</TargetFramework>
<Version>2.42.5</Version>
<Company>Tyrrrz</Company>
<Copyright>Copyright (c) Oleksii Holub</Copyright>
<LangVersion>preview</LangVersion>
@@ -11,15 +11,15 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AngleSharp" Version="1.0.5" />
<PackageReference Include="AngleSharp" Version="1.0.7" />
<PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.1" PrivateAssets="all" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.2" PrivateAssets="all" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" PrivateAssets="all" />
<PackageReference Include="JsonExtensions" Version="1.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="ReflectionMagic" Version="5.0.0" />
<PackageReference Include="xunit" Version="2.6.1" />
@@ -105,7 +105,7 @@ public static class ExportWrapper
if (message is null)
{
throw new InvalidOperationException(
$"Message '{messageId}' does not exist in the export of channel '{channelId}'."
$"Message #{messageId} not found in the export of channel #{channelId}."
);
}
@@ -129,7 +129,7 @@ public static class ExportWrapper
if (message.ValueKind == JsonValueKind.Undefined)
{
throw new InvalidOperationException(
$"Message '{messageId}' does not exist in the export of channel '{channelId}'."
$"Message #{messageId} not found in the export of channel #{channelId}."
);
}
+16 -13
View File
@@ -1,18 +1,13 @@
# -- Build
# Specify the platform here so that we pull the SDK image matching the host platform,
# instead of the target platform specified during build by the `--platform` option.
# Use the .NET 8.0 preview because the `--arch` option is only available in that version.
# https://github.com/dotnet/dotnet-docker/issues/4388#issuecomment-1459038566
# TODO: switch images to Alpine once .NET 8.0 is released.
# Currently, the correct preview version is only available on Debian.
# https://github.com/dotnet/dotnet-docker/blob/main/samples/selecting-tags.md
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
# Expose the target architecture set by the `docker build --platform` option, so that
# we can build the assembly for the correct platform.
ARG TARGETARCH
WORKDIR /tmp/dce
WORKDIR /tmp/app
COPY favicon.ico .
COPY NuGet.config .
@@ -31,7 +26,7 @@ RUN dotnet publish DiscordChatExporter.Cli \
# -- Run
# Use `runtime-deps` instead of `runtime` because we have a self-contained assembly
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/runtime-deps:7.0 AS run
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/runtime-deps:8.0-alpine AS run
LABEL org.opencontainers.image.title="DiscordChatExporter.Cli"
LABEL org.opencontainers.image.description="DiscordChatExporter is an application that can be used to export message history from any Discord channel to a file."
@@ -40,14 +35,22 @@ LABEL org.opencontainers.image.url="https://github.com/Tyrrrz/DiscordChatExporte
LABEL org.opencontainers.image.source="https://github.com/Tyrrrz/DiscordChatExporter/blob/master/DiscordChatExporter.Cli.dockerfile"
LABEL org.opencontainers.image.licenses="MIT"
# Create a non-root user to run the app, so that the output files can be accessed by the host
# Alpine image doesn't come with the ICU libraries pre-installed, so we need to install them manually.
# We need the full ICU data because we allow the user to specify any locale for formatting purposes.
RUN apk add --no-cache icu-libs
RUN apk add --no-cache icu-data-full
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
ENV LC_ALL=en_US.UTF-8
ENV LANG=en_US.UTF-8
# Use a non-root user to ensure that the files shared with the host are accessible by the host user.
# We can use the default user provided by the base image for this purpose.
# https://github.com/Tyrrrz/DiscordChatExporter/issues/851
RUN adduser --disabled-password --no-create-home dce
USER dce
USER $APP_UID
# This directory is exposed to the user for mounting purposes, so it's important that it always
# stays the same for backwards compatibility.
WORKDIR /out
COPY --from=build /tmp/dce/DiscordChatExporter.Cli/bin/publish /opt/dce
ENTRYPOINT ["/opt/dce/DiscordChatExporter.Cli"]
COPY --from=build /tmp/app/DiscordChatExporter.Cli/bin/publish /opt/app
ENTRYPOINT ["/opt/app/DiscordChatExporter.Cli"]
@@ -48,6 +48,17 @@ public abstract class DiscordCommandBase : ICommand
}
#pragma warning restore CS0618
// Note about interactivity
if (console.IsOutputRedirected)
{
console
.Output
.WriteLine(
"Note: Output streams are redirected, rich console interactions are disabled. "
+ "If you are running this command in Docker, consider allocating a pseudo-terminal for better user experience (docker run -it ...)."
);
}
return default;
}
}
@@ -16,7 +16,6 @@ using DiscordChatExporter.Core.Exceptions;
using DiscordChatExporter.Core.Exporting;
using DiscordChatExporter.Core.Exporting.Filtering;
using DiscordChatExporter.Core.Exporting.Partitioning;
using DiscordChatExporter.Core.Utils;
using DiscordChatExporter.Core.Utils.Extensions;
using Gress;
using Spectre.Console;
@@ -163,13 +162,14 @@ public abstract class ExportCommandBase : DiscordCommandBase
|| OutputPath.Contains('%')
// Otherwise, require an existing directory or an unambiguous directory path
|| Directory.Exists(OutputPath)
|| PathEx.IsDirectoryPath(OutputPath);
|| Path.EndsInDirectorySeparator(OutputPath);
if (!isValidOutputPath)
{
throw new CommandException(
"Attempted to export multiple channels, but the output path is neither a directory nor a template. "
+ "If the provided output path is meant to be treated as a directory, make sure it ends with a slash."
+ "If the provided output path is meant to be treated as a directory, make sure it ends with a slash. "
+ $"Provided output path: '{OutputPath}'."
);
}
@@ -26,9 +26,7 @@ public class GuideCommand : ICommand
console.Output.WriteLine(" 4. Navigate to the Network tab");
console.Output.WriteLine(" 5. Press Ctrl+R to reload");
console.Output.WriteLine(" 6. Switch between random channels to trigger network requests");
console
.Output
.WriteLine(" 7. Search for a request containing \"messages?limit=50\" or similar");
console.Output.WriteLine(" 7. Search for a request that starts with \"messages\"");
console.Output.WriteLine(" 8. Select the Headers tab on the right");
console.Output.WriteLine(" 9. Scroll down to the Request Headers section");
console.Output.WriteLine(" 10. Copy the value of the \"authorization\" header");
@@ -6,8 +6,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CliFx" Version="2.3.4" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.1" PrivateAssets="all" />
<PackageReference Include="CliFx" Version="2.3.5" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.2" PrivateAssets="all" />
<PackageReference Include="Deorcify" Version="1.0.2" PrivateAssets="all" />
<PackageReference Include="DotnetRuntimeBootstrapper" Version="2.5.1" PrivateAssets="all" />
<PackageReference Include="Gress" Version="2.1.1" />
@@ -618,7 +618,7 @@ public class DiscordClient
if (!application.IsMessageContentIntentEnabled)
{
throw new DiscordChatExporterException(
"Bot account does not have the Message Content Intent enabled.",
"Provided bot account does not have the Message Content Intent enabled.",
true
);
}
@@ -22,26 +22,27 @@ public partial record struct Snowflake
public static Snowflake FromDate(DateTimeOffset instant) =>
new(((ulong)instant.ToUnixTimeMilliseconds() - 1420070400000UL) << 22);
public static Snowflake? TryParse(string? str, IFormatProvider? formatProvider = null)
public static Snowflake? TryParse(string? value, IFormatProvider? formatProvider = null)
{
if (string.IsNullOrWhiteSpace(str))
if (string.IsNullOrWhiteSpace(value))
return null;
// As number
if (ulong.TryParse(str, NumberStyles.None, formatProvider, out var value))
return new Snowflake(value);
if (ulong.TryParse(value, NumberStyles.None, formatProvider, out var number))
return new Snowflake(number);
// As date
if (DateTimeOffset.TryParse(str, formatProvider, DateTimeStyles.None, out var instant))
if (DateTimeOffset.TryParse(value, formatProvider, DateTimeStyles.None, out var instant))
return FromDate(instant);
return null;
}
public static Snowflake Parse(string str, IFormatProvider? formatProvider) =>
TryParse(str, formatProvider) ?? throw new FormatException($"Invalid snowflake '{str}'.");
public static Snowflake Parse(string value, IFormatProvider? formatProvider) =>
TryParse(value, formatProvider)
?? throw new FormatException($"Invalid snowflake '{value}'.");
public static Snowflake Parse(string str) => Parse(str, null);
public static Snowflake Parse(string value) => Parse(value, null);
}
public partial record struct Snowflake : IComparable<Snowflake>, IComparable
@@ -2,10 +2,10 @@
<ItemGroup>
<PackageReference Include="AsyncKeyedLock" Version="6.2.2" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.1" PrivateAssets="all" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.2" PrivateAssets="all" />
<PackageReference Include="Gress" Version="2.1.1" />
<PackageReference Include="JsonExtensions" Version="1.2.0" />
<PackageReference Include="Polly" Version="8.1.0" />
<PackageReference Include="Polly" Version="8.2.0" />
<PackageReference Include="RazorBlade" Version="0.4.4" />
<PackageReference Include="Superpower" Version="3.0.0" />
<PackageReference Include="WebMarkupMin.Core" Version="2.14.0" />
@@ -6,8 +6,12 @@ public class DiscordChatExporterException : Exception
{
public bool IsFatal { get; }
public DiscordChatExporterException(string message, bool isFatal = false)
: base(message)
public DiscordChatExporterException(
string message,
bool isFatal = false,
Exception? innerException = null
)
: base(message, innerException)
{
IsFatal = isFatal;
}
@@ -8,11 +8,9 @@ using Gress;
namespace DiscordChatExporter.Core.Exporting;
public class ChannelExporter
public class ChannelExporter(DiscordClient discord)
{
private readonly DiscordClient _discord;
public ChannelExporter(DiscordClient discord) => _discord = discord;
private readonly DiscordClient _discord = discord;
public async ValueTask ExportChannelAsync(
ExportRequest request,
@@ -24,7 +22,9 @@ public class ChannelExporter
if (request.Channel.Kind == ChannelKind.GuildForum)
{
throw new DiscordChatExporterException(
"Channel is a forum and cannot be exported directly. "
$"Channel '{request.Channel.Name}' (#{request.Channel.Id}) "
+ $"of guild '{request.Guild.Name}' (#{request.Guild.Id}) "
+ $"is a forum and cannot be exported directly. "
+ "You need to pull its threads and export them individually."
);
}
@@ -32,14 +32,20 @@ public class ChannelExporter
// Check if the channel is empty
if (request.Channel.IsEmpty)
{
throw new DiscordChatExporterException("Channel does not contain any messages.");
throw new DiscordChatExporterException(
$"Channel '{request.Channel.Name}' (#{request.Channel.Id}) "
+ $"of guild '{request.Guild.Name}' (#{request.Guild.Id}) "
+ $"does not contain any messages."
);
}
// Check if the 'after' boundary is valid
if (request.After is not null && !request.Channel.MayHaveMessagesAfter(request.After.Value))
{
throw new DiscordChatExporterException(
"Channel does not contain any messages within the specified period."
$"Channel '{request.Channel.Name}' (#{request.Channel.Id}) "
+ $"of guild '{request.Guild.Name}' (#{request.Guild.Id}) "
+ $"does not contain any messages within the specified period."
);
}
@@ -50,7 +56,9 @@ public class ChannelExporter
)
{
throw new DiscordChatExporterException(
"Channel does not contain any messages within the specified period."
$"Channel '{request.Channel.Name}' (#{request.Channel.Id}) "
+ $"of guild '{request.Guild.Name}' (#{request.Guild.Id}) "
+ $"does not contain any messages within the specified period."
);
}
@@ -70,20 +78,36 @@ public class ChannelExporter
)
)
{
// Resolve members for referenced users
foreach (var user in message.GetReferencedUsers())
await context.PopulateMemberAsync(user, cancellationToken);
try
{
// Resolve members for referenced users
foreach (var user in message.GetReferencedUsers())
await context.PopulateMemberAsync(user, cancellationToken);
// Export the message
if (request.MessageFilter.IsMatch(message))
await messageExporter.ExportMessageAsync(message, cancellationToken);
// Export the message
if (request.MessageFilter.IsMatch(message))
await messageExporter.ExportMessageAsync(message, cancellationToken);
}
catch (Exception ex)
{
// Provide more context to the exception, to simplify debugging based on error messages
throw new DiscordChatExporterException(
$"Failed to export message #{message.Id} "
+ $"in channel '{request.Channel.Name}' (#{request.Channel.Id}) "
+ $"of guild '{request.Guild.Name} (#{request.Guild.Id})'.",
ex is not DiscordChatExporterException dex || dex.IsFatal,
ex
);
}
}
// Throw if no messages were exported
if (messageExporter.MessagesExported <= 0)
{
throw new DiscordChatExporterException(
"Channel does not contain any matching messages within the specified period."
$"Channel '{request.Channel.Name}' (#{request.Channel.Id}) "
+ $"of guild '{request.Guild.Name}' (#{request.Guild.Id}) "
+ $"does not contain any matching messages within the specified period."
);
}
}
@@ -8,15 +8,10 @@ using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Core.Exporting;
internal partial class CsvMessageWriter : MessageWriter
internal partial class CsvMessageWriter(Stream stream, ExportContext context)
: MessageWriter(stream, context)
{
private readonly TextWriter _writer;
public CsvMessageWriter(Stream stream, ExportContext context)
: base(stream, context)
{
_writer = new StreamWriter(stream);
}
private readonly TextWriter _writer = new StreamWriter(stream);
private async ValueTask<string> FormatMarkdownAsync(
string markdown,
@@ -14,7 +14,7 @@ using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Core.Exporting;
internal partial class ExportAssetDownloader
internal partial class ExportAssetDownloader(string workingDirPath, bool reuse)
{
private static readonly AsyncKeyedLocker<string> Locker =
new(o =>
@@ -23,18 +23,12 @@ internal partial class ExportAssetDownloader
o.PoolInitialFill = 1;
});
private readonly string _workingDirPath;
private readonly bool _reuse;
private readonly string _workingDirPath = workingDirPath;
private readonly bool _reuse = reuse;
// File paths of the previously downloaded assets
private readonly Dictionary<string, string> _previousPathsByUrl = new(StringComparer.Ordinal);
public ExportAssetDownloader(string workingDirPath, bool reuse)
{
_workingDirPath = workingDirPath;
_reuse = reuse;
}
public async ValueTask<string> DownloadAsync(
string url,
CancellationToken cancellationToken = default
@@ -12,27 +12,18 @@ using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Core.Exporting;
internal class ExportContext
internal class ExportContext(DiscordClient discord, ExportRequest request)
{
private readonly Dictionary<Snowflake, Member?> _membersById = new();
private readonly Dictionary<Snowflake, Channel> _channelsById = new();
private readonly Dictionary<Snowflake, Role> _rolesById = new();
private readonly ExportAssetDownloader _assetDownloader;
public DiscordClient Discord { get; }
private readonly ExportAssetDownloader _assetDownloader =
new(request.AssetsDirPath, request.ShouldReuseAssets);
public ExportRequest Request { get; }
public DiscordClient Discord { get; } = discord;
public ExportContext(DiscordClient discord, ExportRequest request)
{
Discord = discord;
Request = request;
_assetDownloader = new ExportAssetDownloader(
request.AssetsDirPath,
request.ShouldReuseAssets
);
}
public ExportRequest Request { get; } = request;
public DateTimeOffset NormalizeDate(DateTimeOffset instant) =>
Request.IsUtcNormalizationEnabled ? instant.ToUniversalTime() : instant.ToLocalTime();
@@ -124,9 +115,9 @@ internal class ExportContext
var filePath = await _assetDownloader.DownloadAsync(url, cancellationToken);
var relativeFilePath = Path.GetRelativePath(Request.OutputDirPath, filePath);
// Prefer relative paths so that the output files can be copied around without breaking references.
// If the asset directory is outside of the export directory, use an absolute path instead.
var optimalFilePath =
// Prefer the relative path so that the export package can be copied around without breaking references.
// However, if the assets directory lies outside of the export directory, use the absolute path instead.
var shouldUseAbsoluteFilePath =
relativeFilePath.StartsWith(
".." + Path.DirectorySeparatorChar,
StringComparison.Ordinal
@@ -134,15 +125,19 @@ internal class ExportContext
|| relativeFilePath.StartsWith(
".." + Path.AltDirectorySeparatorChar,
StringComparison.Ordinal
)
? filePath
: relativeFilePath;
);
var optimalFilePath = shouldUseAbsoluteFilePath ? filePath : relativeFilePath;
// For HTML, the path needs to be properly formatted
if (Request.Format is ExportFormat.HtmlDark or ExportFormat.HtmlLight)
{
// Create a 'file:///' URI and then strip the 'file:///' prefix to allow for relative paths
return new Uri(new Uri("file:///"), optimalFilePath).ToString()[8..];
// Format the path into a valid file URI
var href = new Uri(new Uri("file:///"), optimalFilePath).ToString();
// File schema does not support relative paths, so strip it if that's the case
// https://github.com/Tyrrrz/DiscordChatExporter/issues/1155
return shouldUseAbsoluteFilePath ? href : href[8..];
}
return optimalFilePath;
@@ -12,18 +12,15 @@ using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Core.Exporting;
internal partial class HtmlMarkdownVisitor : MarkdownVisitor
internal partial class HtmlMarkdownVisitor(
ExportContext context,
StringBuilder buffer,
bool isJumbo
) : MarkdownVisitor
{
private readonly ExportContext _context;
private readonly StringBuilder _buffer;
private readonly bool _isJumbo;
public HtmlMarkdownVisitor(ExportContext context, StringBuilder buffer, bool isJumbo)
{
_context = context;
_buffer = buffer;
_isJumbo = isJumbo;
}
private readonly ExportContext _context = context;
private readonly StringBuilder _buffer = buffer;
private readonly bool _isJumbo = isJumbo;
protected override ValueTask VisitTextAsync(
TextNode text,
@@ -9,21 +9,15 @@ using WebMarkupMin.Core;
namespace DiscordChatExporter.Core.Exporting;
internal class HtmlMessageWriter : MessageWriter
internal class HtmlMessageWriter(Stream stream, ExportContext context, string themeName)
: MessageWriter(stream, context)
{
private readonly TextWriter _writer;
private readonly string _themeName;
private readonly TextWriter _writer = new StreamWriter(stream);
private readonly string _themeName = themeName;
private readonly HtmlMinifier _minifier = new();
private readonly List<Message> _messageGroup = new();
public HtmlMessageWriter(Stream stream, ExportContext context, string themeName)
: base(stream, context)
{
_writer = new StreamWriter(stream);
_themeName = themeName;
}
private bool CanJoinGroup(Message message)
{
// If the group is empty, any message can join it
@@ -12,26 +12,21 @@ using JsonExtensions.Writing;
namespace DiscordChatExporter.Core.Exporting;
internal class JsonMessageWriter : MessageWriter
internal class JsonMessageWriter(Stream stream, ExportContext context)
: MessageWriter(stream, context)
{
private readonly Utf8JsonWriter _writer;
public JsonMessageWriter(Stream stream, ExportContext context)
: base(stream, context)
{
_writer = new Utf8JsonWriter(
stream,
new JsonWriterOptions
{
// https://github.com/Tyrrrz/DiscordChatExporter/issues/450
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
Indented = true,
// Validation errors may mask actual failures
// https://github.com/Tyrrrz/DiscordChatExporter/issues/413
SkipValidation = true
}
);
}
private readonly Utf8JsonWriter _writer = new Utf8JsonWriter(
stream,
new JsonWriterOptions
{
// https://github.com/Tyrrrz/DiscordChatExporter/issues/450
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
Indented = true,
// Validation errors may mask actual failures
// https://github.com/Tyrrrz/DiscordChatExporter/issues/413
SkipValidation = true
}
);
private async ValueTask<string> FormatMarkdownAsync(
string markdown,
@@ -6,20 +6,15 @@ using DiscordChatExporter.Core.Discord.Data;
namespace DiscordChatExporter.Core.Exporting;
internal partial class MessageExporter : IAsyncDisposable
internal partial class MessageExporter(ExportContext context) : IAsyncDisposable
{
private readonly ExportContext _context;
private readonly ExportContext _context = context;
private int _partitionIndex;
private MessageWriter? _writer;
public long MessagesExported { get; private set; }
public MessageExporter(ExportContext context)
{
_context = context;
}
private async ValueTask ResetWriterAsync(CancellationToken cancellationToken = default)
{
if (_writer is not null)
@@ -6,22 +6,16 @@ using DiscordChatExporter.Core.Discord.Data;
namespace DiscordChatExporter.Core.Exporting;
internal abstract class MessageWriter : IAsyncDisposable
internal abstract class MessageWriter(Stream stream, ExportContext context) : IAsyncDisposable
{
protected Stream Stream { get; }
protected Stream Stream { get; } = stream;
protected ExportContext Context { get; }
protected ExportContext Context { get; } = context;
public long MessagesWritten { get; private set; }
public long BytesWritten => Stream.Length;
protected MessageWriter(Stream stream, ExportContext context)
{
Stream = stream;
Context = context;
}
public virtual ValueTask WritePreambleAsync(CancellationToken cancellationToken = default) =>
default;
@@ -8,16 +8,11 @@ using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Core.Exporting;
internal partial class PlainTextMarkdownVisitor : MarkdownVisitor
internal partial class PlainTextMarkdownVisitor(ExportContext context, StringBuilder buffer)
: MarkdownVisitor
{
private readonly ExportContext _context;
private readonly StringBuilder _buffer;
public PlainTextMarkdownVisitor(ExportContext context, StringBuilder buffer)
{
_context = context;
_buffer = buffer;
}
private readonly ExportContext _context = context;
private readonly StringBuilder _buffer = buffer;
protected override ValueTask VisitTextAsync(
TextNode text,
@@ -8,15 +8,10 @@ using DiscordChatExporter.Core.Discord.Data.Embeds;
namespace DiscordChatExporter.Core.Exporting;
internal class PlainTextMessageWriter : MessageWriter
internal class PlainTextMessageWriter(Stream stream, ExportContext context)
: MessageWriter(stream, context)
{
private readonly TextWriter _writer;
public PlainTextMessageWriter(Stream stream, ExportContext context)
: base(stream, context)
{
_writer = new StreamWriter(stream);
}
private readonly TextWriter _writer = new StreamWriter(stream);
private async ValueTask<string> FormatMarkdownAsync(
string markdown,
@@ -340,13 +340,27 @@ internal static partial class MarkdownParser
)
);
// https://discord.com/developers/docs/reference#message-formatting-timestamp-styles
var format = m.Groups[2].Value.NullIfWhiteSpace() switch
{
// Ignore the 'relative' format because it doesn't make sense in a static export
// Known formats
"t" => "t",
"T" => "T",
"d" => "d",
"D" => "D",
"f" => "f",
"F" => "F",
// Relative format: ignore because it doesn't make sense in a static export
"r" => null,
"R" => null,
// Discord's date formats are (mostly) compatible with .NET's date formats
var f => f
// Unspecified format: will be mapped to the default format
null => null,
// Unknown format: throw an exception to consider this timestamp invalid
// https://github.com/Tyrrrz/DiscordChatExporter/issues/1156
var f
=> throw new InvalidOperationException(
$"Unknown timestamp format '{f}'."
)
};
return new TimestampNode(instant, format);
@@ -354,7 +368,12 @@ internal static partial class MarkdownParser
// https://github.com/Tyrrrz/DiscordChatExporter/issues/681
// https://github.com/Tyrrrz/DiscordChatExporter/issues/766
catch (Exception ex)
when (ex is FormatException or ArgumentOutOfRangeException or OverflowException)
when (ex
is FormatException
or ArgumentOutOfRangeException
or OverflowException
or InvalidOperationException
)
{
// For invalid timestamps, Discord renders "Invalid Date" instead of ignoring the markdown
return TimestampNode.Invalid;
-3
View File
@@ -27,7 +27,4 @@ public static class PathEx
return buffer.ToString();
}
public static bool IsDirectoryPath(string path) =>
path.EndsWith(Path.DirectorySeparatorChar) || path.EndsWith(Path.AltDirectorySeparatorChar);
}
@@ -14,14 +14,13 @@
<ItemGroup>
<PackageReference Include="Cogwheel" Version="2.0.4" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.1" PrivateAssets="all" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.2" PrivateAssets="all" />
<PackageReference Include="Deorcify" Version="1.0.2" PrivateAssets="all" />
<PackageReference Include="DotnetRuntimeBootstrapper" Version="2.5.1" PrivateAssets="all" />
<PackageReference Include="Gress" Version="2.1.1" />
<PackageReference Include="MaterialDesignColors" Version="2.1.4" />
<PackageReference Include="MaterialDesignThemes" Version="4.9.0" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
<PackageReference Include="Onova" Version="2.6.10" />
<PackageReference Include="PropertyChanged.Fody" Version="4.1.0" PrivateAssets="all" />
<PackageReference Include="Stylet" Version="1.3.6" />
@@ -277,9 +277,7 @@ public class DashboardViewModel : PropertyChangedBase
}
catch (DiscordChatExporterException ex) when (!ex.IsFatal)
{
_eventAggregator.Publish(
new NotificationMessage(ex.Message.TrimEnd('.') + $" ({channel.Name})")
);
_eventAggregator.Publish(new NotificationMessage(ex.Message.TrimEnd('.')));
}
finally
{
@@ -4,7 +4,6 @@ using System.Threading;
using System.Threading.Tasks;
using MaterialDesignThemes.Wpf;
using Microsoft.Win32;
using Ookii.Dialogs.Wpf;
using Stylet;
namespace DiscordChatExporter.Gui.ViewModels.Framework;
@@ -68,9 +67,8 @@ public class DialogManager : IDisposable
public string? PromptDirectoryPath(string defaultDirPath = "")
{
var dialog = new VistaFolderBrowserDialog { SelectedPath = defaultDirPath };
return dialog.ShowDialog() == true ? dialog.SelectedPath : null;
var dialog = new OpenFolderDialog { InitialDirectory = defaultDirPath };
return dialog.ShowDialog() == true ? dialog.FolderName : null;
}
public void Dispose()
@@ -193,9 +193,8 @@
<LineBreak />
<Run Text="6. Switch between random channels to trigger network requests" />
<LineBreak />
<Run Text="7. Search for a request containing" />
<Run FontWeight="SemiBold" Text="messages?limit=50" />
<Run Text="or similar" />
<Run Text="7. Search for a request that starts with" />
<Run FontWeight="SemiBold" Text="messages" />
<LineBreak />
<Run Text="8. Select the" />
<Run FontWeight="SemiBold" Text="Headers" />
@@ -271,7 +271,10 @@
</Grid>
<!-- Reuse assets -->
<Grid Margin="16,8" ToolTip="Reuse previously downloaded assets to avoid redundant requests">
<Grid
Margin="16,8"
IsEnabled="{Binding ShouldDownloadAssets}"
ToolTip="Reuse previously downloaded assets to avoid redundant requests">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
@@ -289,14 +292,16 @@
</Grid>
<!-- Assets path -->
<Grid Margin="16,8">
<Grid
Margin="16,8"
IsEnabled="{Binding ShouldDownloadAssets}"
ToolTip="Download assets to this directory. If not specified, the asset directory path will be derived from the output path.">
<TextBox
Padding="16,16,42,16"
materialDesign:HintAssist.Hint="Assets directory path"
materialDesign:HintAssist.IsFloating="True"
Style="{DynamicResource MaterialDesignOutlinedTextBox}"
Text="{Binding AssetsDirPath}"
ToolTip="Download assets to this directory. If not specified, the asset directory path will be derived from the output path." />
Text="{Binding AssetsDirPath}" />
<Button
Width="24"
Height="24"
+10 -10
View File
@@ -89,21 +89,21 @@ The following table lists all available download options:
</tbody>
</table>
> **Note**:
> AUR and Nix packages linked above are maintained by the community.
> If you have any issues with them, please contact the corresponding maintainers.
> **Warning**:
> To run **DiscordChatExporter** on macOS and Linux, you need to make sure that **.NET 7.0 Runtime** is installed.
> **Important**:
> To run **DiscordChatExporter** on macOS and Linux, you need to make sure that **.NET 8.0 Runtime** is installed.
> You can download it here:
>
> - [.NET 7.0 Runtime for **macOS x64**](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-7.0.101-macos-x64-installer)
> - [.NET 7.0 Runtime for **macOS Arm64**](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-7.0.101-macos-arm64-installer)
> - [.NET 7.0 Runtime for **Linux**](https://docs.microsoft.com/en-us/dotnet/core/install/linux) (find the correct download for your distro)
> - [.NET 8.0 Runtime for **macOS x64**](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.0-macos-x64-installer)
> - [.NET 8.0 Runtime for **macOS arm64**](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.0-macos-arm64-installer)
> - [.NET 8.0 Runtime for **Linux**](https://learn.microsoft.com/dotnet/core/install/linux) (find the correct download for your distro)
>
> This should not be necessary if you install **DiscordChatExporter** using a package manager, as it should take care of the dependencies for you.
> This is also not necessary if you are running **DiscordChatExporter** via Docker, because the image already contains the runtime.
> **Note**:
> AUR and Nix packages linked above are maintained by the community.
> If you have any issues with them, please contact the corresponding maintainers.
## Features
- Graphical user interface (Windows)
@@ -119,7 +119,7 @@ The following table lists all available download options:
![channel list](.assets/list.png)
![rendered output](.assets/output.png)
## Related projects
## See also
- [**Chat Analytics**](https://github.com/mlomb/chat-analytics) — solution for analyzing chat patterns of Discord users, using exports produced by **DiscordChatExporter**.
- [**DiscordChatExporter-frontend**](https://github.com/slatinsky/DiscordChatExporter-frontend) — convenient viewer for exports produced by **DiscordChatExporter**.