mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2026-07-19 20:16:18 +02:00
Compare commits
9 Commits
2.47.1
...
7ee2763d4b
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ee2763d4b | |||
| eb99ab29ed | |||
| 5c61306231 | |||
| 2e4601d378 | |||
| cc703cc860 | |||
| 661f82c478 | |||
| b9f19f7003 | |||
| e794d7c833 | |||
| 5a26ba0b5a |
@@ -26,7 +26,7 @@ jobs:
|
|||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
||||||
- name: Install Docker Buildx
|
- name: Install Docker Buildx
|
||||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||||
|
|
||||||
- name: Build image
|
- name: Build image
|
||||||
run: >
|
run: >
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
||||||
- name: Install Docker Buildx
|
- name: Install Docker Buildx
|
||||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
run: >
|
run: >
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
||||||
- name: Install .NET
|
- name: Install .NET
|
||||||
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
|
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
|
||||||
|
|
||||||
# Build the project separately to discern between build and format errors
|
# Build the project separately to discern between build and format errors
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -65,7 +65,7 @@ jobs:
|
|||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
||||||
- name: Install .NET
|
- name: Install .NET
|
||||||
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
|
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
env:
|
env:
|
||||||
@@ -81,7 +81,7 @@ jobs:
|
|||||||
DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover
|
DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover
|
||||||
|
|
||||||
- name: Upload coverage
|
- name: Upload coverage
|
||||||
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
|
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ jobs:
|
|||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
||||||
- name: Install .NET
|
- name: Install .NET
|
||||||
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
|
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
|
||||||
|
|
||||||
- name: Publish app
|
- name: Publish app
|
||||||
run: >
|
run: >
|
||||||
@@ -200,7 +200,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download app binaries
|
- name: Download app binaries
|
||||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.asset }}.${{ matrix.rid }}
|
name: ${{ matrix.asset }}.${{ matrix.rid }}
|
||||||
path: ${{ matrix.app }}/
|
path: ${{ matrix.app }}/
|
||||||
@@ -236,7 +236,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Notify Discord
|
- name: Notify Discord
|
||||||
uses: tyrrrz/action-http-request@1dd7ad841a34b9299f3741f7c7399f9feefdfb08 # 1.1.3
|
uses: tyrrrz/action-http-request@25f132e48dea89c0f6b7955398270b506e1d51cb # 1.1.4
|
||||||
with:
|
with:
|
||||||
url: ${{ secrets.DISCORD_WEBHOOK }}
|
url: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
method: POST
|
method: POST
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Version>999.9.9-dev</Version>
|
<Version>999.9.9-dev</Version>
|
||||||
@@ -7,8 +6,8 @@
|
|||||||
<Copyright>Copyright (c) Oleksii Holub</Copyright>
|
<Copyright>Copyright (c) Oleksii Holub</Copyright>
|
||||||
<LangVersion>preview</LangVersion>
|
<LangVersion>preview</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
<ILLinkTreatWarningsAsErrors>false</ILLinkTreatWarningsAsErrors>
|
<ILLinkTreatWarningsAsErrors>false</ILLinkTreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
</Project>
|
|
||||||
|
|||||||
+21
-18
@@ -5,37 +5,40 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="AngleSharp" Version="1.4.0" />
|
<PackageVersion Include="AngleSharp" Version="1.4.0" />
|
||||||
<PackageVersion Include="AsyncImageLoader.Avalonia" Version="3.6.0" />
|
<PackageVersion Include="AsyncImageLoader.Avalonia" Version="3.7.0" />
|
||||||
<PackageVersion Include="AsyncKeyedLock" Version="8.0.2" />
|
<PackageVersion Include="AsyncKeyedLock" Version="8.0.2" />
|
||||||
<PackageVersion Include="Avalonia" Version="11.3.12" />
|
<PackageVersion Include="Avalonia" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.12" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.12" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.13" />
|
||||||
<PackageVersion Include="CliFx" Version="2.3.6" />
|
<PackageVersion Include="CliFx" Version="3.0.0-alpha.2" />
|
||||||
<PackageVersion Include="Cogwheel" Version="2.1.0" />
|
<PackageVersion Include="Cogwheel" Version="2.1.1" />
|
||||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||||
<PackageVersion Include="coverlet.collector" Version="8.0.0" />
|
<PackageVersion Include="coverlet.collector" Version="8.0.1" />
|
||||||
<PackageVersion Include="CSharpier.MsBuild" Version="1.2.6" />
|
<PackageVersion Include="CSharpier.MsBuild" Version="1.2.6" />
|
||||||
<PackageVersion Include="Deorcify" Version="1.1.0" />
|
<PackageVersion Include="Deorcify" Version="1.1.0" />
|
||||||
<PackageVersion Include="ThisAssembly.Project" Version="2.1.2" />
|
<PackageVersion Include="ThisAssembly.Project" Version="2.1.2" />
|
||||||
<PackageVersion Include="DialogHost.Avalonia" Version="0.10.4" />
|
<PackageVersion Include="DialogHost.Avalonia" Version="0.11.0" />
|
||||||
<PackageVersion Include="FluentAssertions" Version="8.8.0" />
|
<PackageVersion Include="FluentAssertions" Version="8.9.0" />
|
||||||
<PackageVersion Include="GitHubActionsTestLogger" Version="3.0.1" />
|
<PackageVersion Include="GitHubActionsTestLogger" Version="3.0.3" />
|
||||||
<PackageVersion Include="Gress" Version="2.1.1" />
|
<PackageVersion Include="Gress" Version="2.1.1" />
|
||||||
<PackageVersion Include="JsonExtensions" Version="1.2.0" />
|
<PackageVersion Include="JsonExtensions" Version="1.2.0" />
|
||||||
<PackageVersion Include="Markdig" Version="1.0.1" />
|
<PackageVersion Include="Markdig" Version="1.1.2" />
|
||||||
<PackageVersion Include="Material.Avalonia" Version="3.9.2" />
|
<PackageVersion Include="Material.Avalonia" Version="3.9.2" />
|
||||||
<PackageVersion Include="Material.Icons.Avalonia" Version="2.2.0" />
|
<PackageVersion Include="Material.Icons.Avalonia" Version="2.2.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.3" />
|
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.5" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.3" />
|
<PackageVersion
|
||||||
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.3" />
|
Include="Microsoft.Extensions.Configuration.EnvironmentVariables"
|
||||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.3" />
|
Version="10.0.5"
|
||||||
|
/>
|
||||||
|
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.5" />
|
||||||
|
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.5" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
||||||
<PackageVersion Include="Onova" Version="2.6.13" />
|
<PackageVersion Include="Onova" Version="2.6.13" />
|
||||||
<PackageVersion Include="Polly" Version="8.6.5" />
|
<PackageVersion Include="Polly" Version="8.6.6" />
|
||||||
<PackageVersion Include="RazorBlade" Version="0.11.0" />
|
<PackageVersion Include="RazorBlade" Version="0.11.0" />
|
||||||
<PackageVersion Include="Spectre.Console" Version="0.54.0" />
|
<PackageVersion Include="Spectre.Console" Version="0.54.0" />
|
||||||
<PackageVersion Include="Superpower" Version="3.1.0" />
|
<PackageVersion Include="Superpower" Version="3.1.0" />
|
||||||
<PackageVersion Include="WebMarkupMin.Core" Version="2.20.2" />
|
<PackageVersion Include="WebMarkupMin.Core" Version="2.21.0" />
|
||||||
<PackageVersion Include="xunit" Version="2.9.3" />
|
<PackageVersion Include="xunit" Version="2.9.3" />
|
||||||
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
|
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||||
<PackageVersion Include="YoutubeExplode" Version="6.5.7" />
|
<PackageVersion Include="YoutubeExplode" Version="6.5.7" />
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx;
|
using CliFx;
|
||||||
using CliFx.Attributes;
|
using CliFx.Binding;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using DiscordChatExporter.Core.Discord;
|
using DiscordChatExporter.Core.Discord;
|
||||||
using DiscordChatExporter.Core.Utils;
|
using DiscordChatExporter.Core.Utils;
|
||||||
@@ -17,23 +17,22 @@ public abstract class DiscordCommandBase : ICommand
|
|||||||
EnvironmentVariable = "DISCORD_TOKEN",
|
EnvironmentVariable = "DISCORD_TOKEN",
|
||||||
Description = "Authentication token."
|
Description = "Authentication token."
|
||||||
)]
|
)]
|
||||||
public required string Token { get; init; }
|
public required string Token { get; set; }
|
||||||
|
|
||||||
[Obsolete("This option doesn't do anything. Kept for backwards compatibility.")]
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"bot",
|
"bot",
|
||||||
'b',
|
'b',
|
||||||
EnvironmentVariable = "DISCORD_TOKEN_BOT",
|
EnvironmentVariable = "DISCORD_TOKEN_BOT",
|
||||||
Description = "This option doesn't do anything. Kept for backwards compatibility."
|
Description = "This option doesn't do anything. Kept for backwards compatibility."
|
||||||
)]
|
)]
|
||||||
public bool IsBotToken { get; init; } = false;
|
public bool IsBotToken { get; set; } = false;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"respect-rate-limits",
|
"respect-rate-limits",
|
||||||
Description = "Whether to respect advisory rate limits. "
|
Description = "Whether to respect advisory rate limits. "
|
||||||
+ "If disabled, only hard rate limits (i.e. 429 responses) will be respected."
|
+ "If disabled, only hard rate limits (i.e. 429 responses) will be respected."
|
||||||
)]
|
)]
|
||||||
public bool ShouldRespectRateLimits { get; init; } = true;
|
public bool ShouldRespectRateLimits { get; set; } = true;
|
||||||
|
|
||||||
[field: AllowNull, MaybeNull]
|
[field: AllowNull, MaybeNull]
|
||||||
protected DiscordClient Discord =>
|
protected DiscordClient Discord =>
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx.Attributes;
|
using CliFx;
|
||||||
using CliFx.Exceptions;
|
using CliFx.Binding;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using DiscordChatExporter.Cli.Commands.Converters;
|
using DiscordChatExporter.Cli.Commands.Converters;
|
||||||
using DiscordChatExporter.Cli.Commands.Shared;
|
using DiscordChatExporter.Cli.Commands.Shared;
|
||||||
@@ -37,23 +37,23 @@ public abstract class ExportCommandBase : DiscordCommandBase
|
|||||||
get;
|
get;
|
||||||
// Handle ~/ in paths on Unix systems
|
// Handle ~/ in paths on Unix systems
|
||||||
// https://github.com/Tyrrrz/DiscordChatExporter/pull/903
|
// https://github.com/Tyrrrz/DiscordChatExporter/pull/903
|
||||||
init => field = Path.GetFullPath(value);
|
set => field = Path.GetFullPath(value);
|
||||||
} = Directory.GetCurrentDirectory();
|
} = Directory.GetCurrentDirectory();
|
||||||
|
|
||||||
[CommandOption("format", 'f', Description = "Export format.")]
|
[CommandOption("format", 'f', Description = "Export format.")]
|
||||||
public ExportFormat ExportFormat { get; init; } = ExportFormat.HtmlDark;
|
public ExportFormat ExportFormat { get; set; } = ExportFormat.HtmlDark;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"after",
|
"after",
|
||||||
Description = "Only include messages sent after this date or message ID."
|
Description = "Only include messages sent after this date or message ID."
|
||||||
)]
|
)]
|
||||||
public Snowflake? After { get; init; }
|
public Snowflake? After { get; set; }
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"before",
|
"before",
|
||||||
Description = "Only include messages sent before this date or message ID."
|
Description = "Only include messages sent before this date or message ID."
|
||||||
)]
|
)]
|
||||||
public Snowflake? Before { get; init; }
|
public Snowflake? Before { get; set; }
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"partition",
|
"partition",
|
||||||
@@ -61,51 +61,51 @@ public abstract class ExportCommandBase : DiscordCommandBase
|
|||||||
Description = "Split the output into partitions, each limited to the specified "
|
Description = "Split the output into partitions, each limited to the specified "
|
||||||
+ "number of messages (e.g. '100') or file size (e.g. '10mb')."
|
+ "number of messages (e.g. '100') or file size (e.g. '10mb')."
|
||||||
)]
|
)]
|
||||||
public PartitionLimit PartitionLimit { get; init; } = PartitionLimit.Null;
|
public PartitionLimit PartitionLimit { get; set; } = PartitionLimit.Null;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"include-threads",
|
"include-threads",
|
||||||
Description = "Which types of threads should be included.",
|
Description = "Which types of threads should be included.",
|
||||||
Converter = typeof(ThreadInclusionModeBindingConverter)
|
Converter = typeof(ThreadInclusionModeInputConverter)
|
||||||
)]
|
)]
|
||||||
public ThreadInclusionMode ThreadInclusionMode { get; init; } = ThreadInclusionMode.None;
|
public ThreadInclusionMode ThreadInclusionMode { get; set; } = ThreadInclusionMode.None;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"filter",
|
"filter",
|
||||||
Description = "Only include messages that satisfy this filter. "
|
Description = "Only include messages that satisfy this filter. "
|
||||||
+ "See the documentation for more info."
|
+ "See the documentation for more info."
|
||||||
)]
|
)]
|
||||||
public MessageFilter MessageFilter { get; init; } = MessageFilter.Null;
|
public MessageFilter MessageFilter { get; set; } = MessageFilter.Null;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"parallel",
|
"parallel",
|
||||||
Description = "Limits how many channels can be exported in parallel."
|
Description = "Limits how many channels can be exported in parallel."
|
||||||
)]
|
)]
|
||||||
public int ParallelLimit { get; init; } = 1;
|
public int ParallelLimit { get; set; } = 1;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"reverse",
|
"reverse",
|
||||||
Description = "Export messages in reverse chronological order (newest first)."
|
Description = "Export messages in reverse chronological order (newest first)."
|
||||||
)]
|
)]
|
||||||
public bool IsReverseMessageOrder { get; init; }
|
public bool IsReverseMessageOrder { get; set; }
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"markdown",
|
"markdown",
|
||||||
Description = "Process markdown, mentions, and other special tokens."
|
Description = "Process markdown, mentions, and other special tokens."
|
||||||
)]
|
)]
|
||||||
public bool ShouldFormatMarkdown { get; init; } = true;
|
public bool ShouldFormatMarkdown { get; set; } = true;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"media",
|
"media",
|
||||||
Description = "Download assets referenced by the export (user avatars, attached files, embedded images, etc.)."
|
Description = "Download assets referenced by the export (user avatars, attached files, embedded images, etc.)."
|
||||||
)]
|
)]
|
||||||
public bool ShouldDownloadAssets { get; init; }
|
public bool ShouldDownloadAssets { get; set; }
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"reuse-media",
|
"reuse-media",
|
||||||
Description = "Reuse previously downloaded assets to avoid redundant requests."
|
Description = "Reuse previously downloaded assets to avoid redundant requests."
|
||||||
)]
|
)]
|
||||||
public bool ShouldReuseAssets { get; init; } = false;
|
public bool ShouldReuseAssets { get; set; } = false;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"media-dir",
|
"media-dir",
|
||||||
@@ -117,34 +117,33 @@ public abstract class ExportCommandBase : DiscordCommandBase
|
|||||||
get;
|
get;
|
||||||
// Handle ~/ in paths on Unix systems
|
// Handle ~/ in paths on Unix systems
|
||||||
// https://github.com/Tyrrrz/DiscordChatExporter/pull/903
|
// https://github.com/Tyrrrz/DiscordChatExporter/pull/903
|
||||||
init => field = value is not null ? Path.GetFullPath(value) : null;
|
set => field = value is not null ? Path.GetFullPath(value) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This option doesn't do anything. Kept for backwards compatibility.")]
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"dateformat",
|
"dateformat",
|
||||||
Description = "This option doesn't do anything. Kept for backwards compatibility."
|
Description = "This option doesn't do anything. Kept for backwards compatibility."
|
||||||
)]
|
)]
|
||||||
public string DateFormat { get; init; } = "MM/dd/yyyy h:mm tt";
|
public string DateFormat { get; set; } = "MM/dd/yyyy h:mm tt";
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"locale",
|
"locale",
|
||||||
Description = "Locale to use when formatting dates and numbers. "
|
Description = "Locale to use when formatting dates and numbers. "
|
||||||
+ "If not specified, the default system locale will be used."
|
+ "If not specified, the default system locale will be used."
|
||||||
)]
|
)]
|
||||||
public string? Locale { get; init; }
|
public string? Locale { get; set; }
|
||||||
|
|
||||||
[CommandOption("utc", Description = "Normalize all timestamps to UTC+0.")]
|
[CommandOption("utc", Description = "Normalize all timestamps to UTC+0.")]
|
||||||
public bool IsUtcNormalizationEnabled { get; init; } = false;
|
public bool IsUtcNormalizationEnabled { get; set; } = false;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"fuck-russia",
|
"fuck-russia",
|
||||||
EnvironmentVariable = "FUCK_RUSSIA",
|
EnvironmentVariable = "FUCK_RUSSIA",
|
||||||
Description = "Don't print the Support Ukraine message to the console.",
|
Description = "Don't print the Support Ukraine message to the console.",
|
||||||
// Use a converter to accept '1' as 'true' to reuse the existing environment variable
|
// Use a converter to accept '1' as 'true' to reuse the existing environment variable
|
||||||
Converter = typeof(TruthyBooleanBindingConverter)
|
Converter = typeof(TruthyBooleanInputConverter)
|
||||||
)]
|
)]
|
||||||
public bool IsUkraineSupportMessageDisabled { get; init; } = false;
|
public bool IsUkraineSupportMessageDisabled { get; set; } = false;
|
||||||
|
|
||||||
[field: AllowNull, MaybeNull]
|
[field: AllowNull, MaybeNull]
|
||||||
protected ChannelExporter Exporter => field ??= new ChannelExporter(Discord);
|
protected ChannelExporter Exporter => field ??= new ChannelExporter(Discord);
|
||||||
|
|||||||
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using CliFx.Extensibility;
|
using CliFx.Activation;
|
||||||
using DiscordChatExporter.Cli.Commands.Shared;
|
using DiscordChatExporter.Cli.Commands.Shared;
|
||||||
|
|
||||||
namespace DiscordChatExporter.Cli.Commands.Converters;
|
namespace DiscordChatExporter.Cli.Commands.Converters;
|
||||||
|
|
||||||
internal class ThreadInclusionModeBindingConverter : BindingConverter<ThreadInclusionMode>
|
internal class ThreadInclusionModeInputConverter : ScalarInputConverter<ThreadInclusionMode>
|
||||||
{
|
{
|
||||||
public override ThreadInclusionMode Convert(string? rawValue)
|
public override ThreadInclusionMode Convert(string? rawValue)
|
||||||
{
|
{
|
||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using CliFx.Extensibility;
|
using CliFx.Activation;
|
||||||
|
|
||||||
namespace DiscordChatExporter.Cli.Commands.Converters;
|
namespace DiscordChatExporter.Cli.Commands.Converters;
|
||||||
|
|
||||||
internal class TruthyBooleanBindingConverter : BindingConverter<bool>
|
internal class TruthyBooleanInputConverter : ScalarInputConverter<bool>
|
||||||
{
|
{
|
||||||
public override bool Convert(string? rawValue)
|
public override bool Convert(string? rawValue)
|
||||||
{
|
{
|
||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx.Attributes;
|
using CliFx.Binding;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using DiscordChatExporter.Cli.Commands.Base;
|
using DiscordChatExporter.Cli.Commands.Base;
|
||||||
using DiscordChatExporter.Cli.Utils.Extensions;
|
using DiscordChatExporter.Cli.Utils.Extensions;
|
||||||
@@ -14,23 +14,23 @@ using Spectre.Console;
|
|||||||
namespace DiscordChatExporter.Cli.Commands;
|
namespace DiscordChatExporter.Cli.Commands;
|
||||||
|
|
||||||
[Command("exportall", Description = "Exports all accessible channels.")]
|
[Command("exportall", Description = "Exports all accessible channels.")]
|
||||||
public class ExportAllCommand : ExportCommandBase
|
public partial class ExportAllCommand : ExportCommandBase
|
||||||
{
|
{
|
||||||
[CommandOption("include-dm", Description = "Include direct message channels.")]
|
[CommandOption("include-dm", Description = "Include direct message channels.")]
|
||||||
public bool IncludeDirectChannels { get; init; } = true;
|
public bool IncludeDirectChannels { get; set; } = true;
|
||||||
|
|
||||||
[CommandOption("include-guilds", Description = "Include server channels.")]
|
[CommandOption("include-guilds", Description = "Include server channels.")]
|
||||||
public bool IncludeGuildChannels { get; init; } = true;
|
public bool IncludeGuildChannels { get; set; } = true;
|
||||||
|
|
||||||
[CommandOption("include-vc", Description = "Include voice channels.")]
|
[CommandOption("include-vc", Description = "Include voice channels.")]
|
||||||
public bool IncludeVoiceChannels { get; init; } = true;
|
public bool IncludeVoiceChannels { get; set; } = true;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"data-package",
|
"data-package",
|
||||||
Description = "Path to the personal data package (ZIP file) requested from Discord. "
|
Description = "Path to the personal data package (ZIP file) requested from Discord. "
|
||||||
+ "If provided, only channels referenced in the dump will be exported."
|
+ "If provided, only channels referenced in the dump will be exported."
|
||||||
)]
|
)]
|
||||||
public string? DataPackageFilePath { get; init; }
|
public string? DataPackageFilePath { get; set; }
|
||||||
|
|
||||||
public override async ValueTask ExecuteAsync(IConsole console)
|
public override async ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx.Attributes;
|
using CliFx.Binding;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using DiscordChatExporter.Cli.Commands.Base;
|
using DiscordChatExporter.Cli.Commands.Base;
|
||||||
using DiscordChatExporter.Core.Discord;
|
using DiscordChatExporter.Core.Discord;
|
||||||
@@ -10,7 +10,7 @@ using DiscordChatExporter.Core.Utils.Extensions;
|
|||||||
namespace DiscordChatExporter.Cli.Commands;
|
namespace DiscordChatExporter.Cli.Commands;
|
||||||
|
|
||||||
[Command("export", Description = "Exports one or multiple channels.")]
|
[Command("export", Description = "Exports one or multiple channels.")]
|
||||||
public class ExportChannelsCommand : ExportCommandBase
|
public partial class ExportChannelsCommand : ExportCommandBase
|
||||||
{
|
{
|
||||||
// TODO: change this to plural (breaking change)
|
// TODO: change this to plural (breaking change)
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
@@ -19,7 +19,7 @@ public class ExportChannelsCommand : ExportCommandBase
|
|||||||
Description = "Channel ID(s). "
|
Description = "Channel ID(s). "
|
||||||
+ "If provided with category ID(s), all channels inside those categories will be exported."
|
+ "If provided with category ID(s), all channels inside those categories will be exported."
|
||||||
)]
|
)]
|
||||||
public required IReadOnlyList<Snowflake> ChannelIds { get; init; }
|
public required IReadOnlyList<Snowflake> ChannelIds { get; set; }
|
||||||
|
|
||||||
public override async ValueTask ExecuteAsync(IConsole console)
|
public override async ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx.Attributes;
|
using CliFx.Binding;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using DiscordChatExporter.Cli.Commands.Base;
|
using DiscordChatExporter.Cli.Commands.Base;
|
||||||
using DiscordChatExporter.Core.Discord.Data;
|
using DiscordChatExporter.Core.Discord.Data;
|
||||||
@@ -8,7 +8,7 @@ using DiscordChatExporter.Core.Utils.Extensions;
|
|||||||
namespace DiscordChatExporter.Cli.Commands;
|
namespace DiscordChatExporter.Cli.Commands;
|
||||||
|
|
||||||
[Command("exportdm", Description = "Exports all direct message channels.")]
|
[Command("exportdm", Description = "Exports all direct message channels.")]
|
||||||
public class ExportDirectMessagesCommand : ExportCommandBase
|
public partial class ExportDirectMessagesCommand : ExportCommandBase
|
||||||
{
|
{
|
||||||
public override async ValueTask ExecuteAsync(IConsole console)
|
public override async ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx.Attributes;
|
using CliFx.Binding;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using DiscordChatExporter.Cli.Commands.Base;
|
using DiscordChatExporter.Cli.Commands.Base;
|
||||||
using DiscordChatExporter.Cli.Utils.Extensions;
|
using DiscordChatExporter.Cli.Utils.Extensions;
|
||||||
@@ -11,13 +11,13 @@ using Spectre.Console;
|
|||||||
namespace DiscordChatExporter.Cli.Commands;
|
namespace DiscordChatExporter.Cli.Commands;
|
||||||
|
|
||||||
[Command("exportguild", Description = "Exports all channels within the specified server.")]
|
[Command("exportguild", Description = "Exports all channels within the specified server.")]
|
||||||
public class ExportGuildCommand : ExportCommandBase
|
public partial class ExportGuildCommand : ExportCommandBase
|
||||||
{
|
{
|
||||||
[CommandOption("guild", 'g', Description = "Server ID.")]
|
[CommandOption("guild", 'g', Description = "Server ID.")]
|
||||||
public required Snowflake GuildId { get; init; }
|
public required Snowflake GuildId { get; set; }
|
||||||
|
|
||||||
[CommandOption("include-vc", Description = "Include voice channels.")]
|
[CommandOption("include-vc", Description = "Include voice channels.")]
|
||||||
public bool IncludeVoiceChannels { get; init; } = true;
|
public bool IncludeVoiceChannels { get; set; } = true;
|
||||||
|
|
||||||
public override async ValueTask ExecuteAsync(IConsole console)
|
public override async ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx.Attributes;
|
using CliFx.Binding;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using DiscordChatExporter.Cli.Commands.Base;
|
using DiscordChatExporter.Cli.Commands.Base;
|
||||||
using DiscordChatExporter.Cli.Commands.Converters;
|
using DiscordChatExporter.Cli.Commands.Converters;
|
||||||
@@ -12,20 +12,20 @@ using DiscordChatExporter.Core.Utils.Extensions;
|
|||||||
namespace DiscordChatExporter.Cli.Commands;
|
namespace DiscordChatExporter.Cli.Commands;
|
||||||
|
|
||||||
[Command("channels", Description = "Get the list of channels in a server.")]
|
[Command("channels", Description = "Get the list of channels in a server.")]
|
||||||
public class GetChannelsCommand : DiscordCommandBase
|
public partial class GetChannelsCommand : DiscordCommandBase
|
||||||
{
|
{
|
||||||
[CommandOption("guild", 'g', Description = "Server ID.")]
|
[CommandOption("guild", 'g', Description = "Server ID.")]
|
||||||
public required Snowflake GuildId { get; init; }
|
public required Snowflake GuildId { get; set; }
|
||||||
|
|
||||||
[CommandOption("include-vc", Description = "Include voice channels.")]
|
[CommandOption("include-vc", Description = "Include voice channels.")]
|
||||||
public bool IncludeVoiceChannels { get; init; } = true;
|
public bool IncludeVoiceChannels { get; set; } = true;
|
||||||
|
|
||||||
[CommandOption(
|
[CommandOption(
|
||||||
"include-threads",
|
"include-threads",
|
||||||
Description = "Which types of threads should be included.",
|
Description = "Which types of threads should be included.",
|
||||||
Converter = typeof(ThreadInclusionModeBindingConverter)
|
Converter = typeof(ThreadInclusionModeInputConverter)
|
||||||
)]
|
)]
|
||||||
public ThreadInclusionMode ThreadInclusionMode { get; init; } = ThreadInclusionMode.None;
|
public ThreadInclusionMode ThreadInclusionMode { get; set; } = ThreadInclusionMode.None;
|
||||||
|
|
||||||
public override async ValueTask ExecuteAsync(IConsole console)
|
public override async ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx.Attributes;
|
using CliFx.Binding;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using DiscordChatExporter.Cli.Commands.Base;
|
using DiscordChatExporter.Cli.Commands.Base;
|
||||||
using DiscordChatExporter.Core.Discord.Data;
|
using DiscordChatExporter.Core.Discord.Data;
|
||||||
@@ -10,7 +10,7 @@ using DiscordChatExporter.Core.Utils.Extensions;
|
|||||||
namespace DiscordChatExporter.Cli.Commands;
|
namespace DiscordChatExporter.Cli.Commands;
|
||||||
|
|
||||||
[Command("dm", Description = "Gets the list of all direct message channels.")]
|
[Command("dm", Description = "Gets the list of all direct message channels.")]
|
||||||
public class GetDirectChannelsCommand : DiscordCommandBase
|
public partial class GetDirectChannelsCommand : DiscordCommandBase
|
||||||
{
|
{
|
||||||
public override async ValueTask ExecuteAsync(IConsole console)
|
public override async ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx.Attributes;
|
using CliFx.Binding;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using DiscordChatExporter.Cli.Commands.Base;
|
using DiscordChatExporter.Cli.Commands.Base;
|
||||||
using DiscordChatExporter.Core.Discord.Data;
|
using DiscordChatExporter.Core.Discord.Data;
|
||||||
@@ -10,7 +10,7 @@ using DiscordChatExporter.Core.Utils.Extensions;
|
|||||||
namespace DiscordChatExporter.Cli.Commands;
|
namespace DiscordChatExporter.Cli.Commands;
|
||||||
|
|
||||||
[Command("guilds", Description = "Gets the list of accessible servers.")]
|
[Command("guilds", Description = "Gets the list of accessible servers.")]
|
||||||
public class GetGuildsCommand : DiscordCommandBase
|
public partial class GetGuildsCommand : DiscordCommandBase
|
||||||
{
|
{
|
||||||
public override async ValueTask ExecuteAsync(IConsole console)
|
public override async ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CliFx;
|
using CliFx;
|
||||||
using CliFx.Attributes;
|
using CliFx.Binding;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
namespace DiscordChatExporter.Cli.Commands;
|
namespace DiscordChatExporter.Cli.Commands;
|
||||||
|
|
||||||
[Command("guide", Description = "Explains how to obtain the token, server or channel ID.")]
|
[Command("guide", Description = "Explains how to obtain the token, server or channel ID.")]
|
||||||
public class GuideCommand : ICommand
|
public partial class GuideCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,12 +6,6 @@
|
|||||||
<CopyOutputSymbolsToPublishDirectory>false</CopyOutputSymbolsToPublishDirectory>
|
<CopyOutputSymbolsToPublishDirectory>false</CopyOutputSymbolsToPublishDirectory>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- HACK: Disable trim warnings because they seem to break when the code contains C# 14 extension blocks -->
|
|
||||||
<PropertyGroup>
|
|
||||||
<EnableTrimAnalyzer>false</EnableTrimAnalyzer>
|
|
||||||
<EnableAotAnalyzer>false</EnableAotAnalyzer>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CliFx" />
|
<PackageReference Include="CliFx" />
|
||||||
<PackageReference Include="CSharpier.MsBuild" PrivateAssets="all" />
|
<PackageReference Include="CSharpier.MsBuild" PrivateAssets="all" />
|
||||||
|
|||||||
@@ -1,41 +1,13 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Threading.Tasks;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using CliFx;
|
using CliFx;
|
||||||
using DiscordChatExporter.Cli.Commands;
|
|
||||||
using DiscordChatExporter.Cli.Commands.Converters;
|
|
||||||
using DiscordChatExporter.Core.Exporting.Filtering;
|
|
||||||
using DiscordChatExporter.Core.Exporting.Partitioning;
|
|
||||||
|
|
||||||
namespace DiscordChatExporter.Cli;
|
namespace DiscordChatExporter.Cli;
|
||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
// Explicit references because CliFx relies on reflection and we're publishing with trimming enabled
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportAllCommand))]
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportChannelsCommand))]
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportDirectMessagesCommand))]
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportGuildCommand))]
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GetChannelsCommand))]
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GetDirectChannelsCommand))]
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GetGuildsCommand))]
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GuideCommand))]
|
|
||||||
[DynamicDependency(
|
|
||||||
DynamicallyAccessedMemberTypes.All,
|
|
||||||
typeof(ThreadInclusionModeBindingConverter)
|
|
||||||
)]
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(TruthyBooleanBindingConverter))]
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(PartitionLimit))]
|
|
||||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(MessageFilter))]
|
|
||||||
public static async Task<int> Main(string[] args) =>
|
public static async Task<int> Main(string[] args) =>
|
||||||
await new CliApplicationBuilder()
|
await new CommandLineApplicationBuilder()
|
||||||
.AddCommand<ExportAllCommand>()
|
.AddCommandsFromThisAssembly()
|
||||||
.AddCommand<ExportChannelsCommand>()
|
|
||||||
.AddCommand<ExportDirectMessagesCommand>()
|
|
||||||
.AddCommand<ExportGuildCommand>()
|
|
||||||
.AddCommand<GetChannelsCommand>()
|
|
||||||
.AddCommand<GetDirectChannelsCommand>()
|
|
||||||
.AddCommand<GetGuildsCommand>()
|
|
||||||
.AddCommand<GuideCommand>()
|
|
||||||
.Build()
|
.Build()
|
||||||
.RunAsync(args);
|
.RunAsync(args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,6 @@
|
|||||||
<PublishMacOSBundle>false</PublishMacOSBundle>
|
<PublishMacOSBundle>false</PublishMacOSBundle>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- HACK: Disable trim warnings because they seem to break when the code contains C# 14 extension blocks -->
|
|
||||||
<PropertyGroup>
|
|
||||||
<EnableTrimAnalyzer>false</EnableTrimAnalyzer>
|
|
||||||
<EnableAotAnalyzer>false</EnableAotAnalyzer>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AvaloniaResource Include="..\favicon.ico" Link="favicon.ico" />
|
<AvaloniaResource Include="..\favicon.ico" Link="favicon.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -56,7 +50,7 @@
|
|||||||
|
|
||||||
<Target Name="PublishMacOSBundle" AfterTargets="Publish" Condition="$(PublishMacOSBundle)">
|
<Target Name="PublishMacOSBundle" AfterTargets="Publish" Condition="$(PublishMacOSBundle)">
|
||||||
<Exec
|
<Exec
|
||||||
Command="pwsh -ExecutionPolicy Bypass -File $(ProjectDir)/Publish-MacOSBundle.ps1 -PublishDirPath $(PublishDir) -IconsFilePath $(ProjectDir)/../favicon.icns -FullVersion $(Version) -ShortVersion $(AssemblyVersion)"
|
Command="dotnet run --file "$(ProjectDir)PublishMacOSBundle.csx" -- --publish-dir "$(PublishDir)" --icons-file "$(ProjectDir)../favicon.icns" --full-version $(Version) --short-version $(AssemblyVersion)"
|
||||||
LogStandardErrorAsError="true"
|
LogStandardErrorAsError="true"
|
||||||
/>
|
/>
|
||||||
</Target>
|
</Target>
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
param(
|
|
||||||
[Parameter(Mandatory=$true)]
|
|
||||||
[string]$PublishDirPath,
|
|
||||||
|
|
||||||
[Parameter(Mandatory=$true)]
|
|
||||||
[string]$IconsFilePath,
|
|
||||||
|
|
||||||
[Parameter(Mandatory=$true)]
|
|
||||||
[string]$FullVersion,
|
|
||||||
|
|
||||||
[Parameter(Mandatory=$true)]
|
|
||||||
[string]$ShortVersion
|
|
||||||
)
|
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
|
|
||||||
# Setup paths
|
|
||||||
$tempDirPath = Join-Path $PublishDirPath "../publish-macos-app-temp"
|
|
||||||
$bundleName = "DiscordChatExporter.app"
|
|
||||||
$bundleDirPath = Join-Path $tempDirPath $bundleName
|
|
||||||
$contentsDirPath = Join-Path $bundleDirPath "Contents"
|
|
||||||
$macosDirPath = Join-Path $contentsDirPath "MacOS"
|
|
||||||
$resourcesDirPath = Join-Path $contentsDirPath "Resources"
|
|
||||||
|
|
||||||
try {
|
|
||||||
# Initialize the bundle's directory structure
|
|
||||||
New-Item -Path $bundleDirPath -ItemType Directory -Force
|
|
||||||
New-Item -Path $contentsDirPath -ItemType Directory -Force
|
|
||||||
New-Item -Path $macosDirPath -ItemType Directory -Force
|
|
||||||
New-Item -Path $resourcesDirPath -ItemType Directory -Force
|
|
||||||
|
|
||||||
# Copy icons into the .app's Resources folder
|
|
||||||
Copy-Item -Path $IconsFilePath -Destination (Join-Path $resourcesDirPath "AppIcon.icns") -Force
|
|
||||||
|
|
||||||
# Generate the Info.plist metadata file with the app information
|
|
||||||
$plistContent = @"
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>DiscordChatExporter</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>DiscordChatExporter</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>DiscordChatExporter</string>
|
|
||||||
<key>NSHumanReadableCopyright</key>
|
|
||||||
<string>© Oleksii Holub</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>me.Tyrrrz.DiscordChatExporter</string>
|
|
||||||
<key>CFBundleSpokenName</key>
|
|
||||||
<string>Discord Chat Exporter</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>AppIcon</string>
|
|
||||||
<key>CFBundleIconName</key>
|
|
||||||
<string>AppIcon</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>$FullVersion</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>$ShortVersion</string>
|
|
||||||
<key>NSHighResolutionCapable</key>
|
|
||||||
<true />
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
"@
|
|
||||||
|
|
||||||
Set-Content -Path (Join-Path $contentsDirPath "Info.plist") -Value $plistContent
|
|
||||||
|
|
||||||
# Delete the previous bundle if it exists
|
|
||||||
if (Test-Path (Join-Path $PublishDirPath $bundleName)) {
|
|
||||||
Remove-Item -Path (Join-Path $PublishDirPath $bundleName) -Recurse -Force
|
|
||||||
}
|
|
||||||
|
|
||||||
# Move all files from the publish directory into the MacOS directory
|
|
||||||
Get-ChildItem -Path $PublishDirPath | ForEach-Object {
|
|
||||||
Move-Item -Path $_.FullName -Destination $macosDirPath -Force
|
|
||||||
}
|
|
||||||
|
|
||||||
# Move the final bundle into the publish directory for upload
|
|
||||||
Move-Item -Path $bundleDirPath -Destination $PublishDirPath -Force
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
# Clean up the temporary directory
|
|
||||||
Remove-Item -Path $tempDirPath -Recurse -Force
|
|
||||||
}
|
|
||||||
+128
@@ -0,0 +1,128 @@
|
|||||||
|
#!/usr/bin/dotnet --
|
||||||
|
#:package CliFx
|
||||||
|
|
||||||
|
using CliFx;
|
||||||
|
using CliFx.Binding;
|
||||||
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
|
return await new CommandLineApplicationBuilder()
|
||||||
|
.AddCommandsFromThisAssembly()
|
||||||
|
.Build()
|
||||||
|
.RunAsync(args);
|
||||||
|
|
||||||
|
[Command(Description = "Publishes the GUI app as a macOS .app bundle.")]
|
||||||
|
public partial class PublishMacOSBundleCommand : ICommand
|
||||||
|
{
|
||||||
|
private const string BundleName = "DiscordChatExporter.app";
|
||||||
|
private const string AppName = "DiscordChatExporter";
|
||||||
|
private const string AppCopyright = "© Oleksii Holub";
|
||||||
|
private const string AppIdentifier = "me.Tyrrrz.DiscordChatExporter";
|
||||||
|
private const string AppSpokenName = "Discord Chat Exporter";
|
||||||
|
private const string AppIconName = "AppIcon";
|
||||||
|
|
||||||
|
[CommandOption("publish-dir", Description = "Path to the publish output directory.")]
|
||||||
|
public required string PublishDirPath { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("icons-file", Description = "Path to the .icns icons file.")]
|
||||||
|
public required string IconsFilePath { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("full-version", Description = "Full version string (e.g. '1.2.3.4').")]
|
||||||
|
public required string FullVersion { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("short-version", Description = "Short version string (e.g. '1.2.3').")]
|
||||||
|
public required string ShortVersion { get; set; }
|
||||||
|
|
||||||
|
public async ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
// Set up paths
|
||||||
|
var publishDirPath = Path.GetFullPath(PublishDirPath);
|
||||||
|
var tempDirPath = Path.GetFullPath(
|
||||||
|
Path.Combine(publishDirPath, "../publish-macos-app-temp")
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure the temporary directory is clean before use in case a previous run crashed
|
||||||
|
if (Directory.Exists(tempDirPath))
|
||||||
|
Directory.Delete(tempDirPath, true);
|
||||||
|
|
||||||
|
var bundleDirPath = Path.Combine(tempDirPath, BundleName);
|
||||||
|
var contentsDirPath = Path.Combine(bundleDirPath, "Contents");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Copy icons into the .app's Resources folder
|
||||||
|
Directory.CreateDirectory(Path.Combine(contentsDirPath, "Resources"));
|
||||||
|
File.Copy(
|
||||||
|
IconsFilePath,
|
||||||
|
Path.Combine(contentsDirPath, "Resources", "AppIcon.icns"),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Generate the Info.plist metadata file with the app information
|
||||||
|
// lang=xml
|
||||||
|
var plistContent = $"""
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>{AppName}</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>{AppName}</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>{AppName}</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>{AppCopyright}</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>{AppIdentifier}</string>
|
||||||
|
<key>CFBundleSpokenName</key>
|
||||||
|
<string>{AppSpokenName}</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>{AppIconName}</string>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>{AppIconName}</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>{FullVersion}</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>{ShortVersion}</string>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<true />
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
""";
|
||||||
|
|
||||||
|
await File.WriteAllTextAsync(Path.Combine(contentsDirPath, "Info.plist"), plistContent);
|
||||||
|
|
||||||
|
// Delete the previous bundle if it exists
|
||||||
|
var existingBundlePath = Path.Combine(publishDirPath, BundleName);
|
||||||
|
if (Directory.Exists(existingBundlePath))
|
||||||
|
Directory.Delete(existingBundlePath, true);
|
||||||
|
|
||||||
|
// Move all files from the publish directory into the MacOS directory
|
||||||
|
Directory.CreateDirectory(Path.Combine(contentsDirPath, "MacOS"));
|
||||||
|
foreach (var entryPath in Directory.GetFileSystemEntries(publishDirPath))
|
||||||
|
{
|
||||||
|
var destinationPath = Path.Combine(
|
||||||
|
contentsDirPath,
|
||||||
|
"MacOS",
|
||||||
|
Path.GetFileName(entryPath)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (Directory.Exists(entryPath))
|
||||||
|
Directory.Move(entryPath, destinationPath);
|
||||||
|
else
|
||||||
|
File.Move(entryPath, destinationPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the final bundle into the publish directory for upload
|
||||||
|
Directory.Move(bundleDirPath, Path.Combine(publishDirPath, BundleName));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Clean up the temporary directory
|
||||||
|
if (Directory.Exists(tempDirPath))
|
||||||
|
Directory.Delete(tempDirPath, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,12 +44,14 @@ To learn more about the war and how you can help, [click here](https://tyrrrz.me
|
|||||||
- 🟢 **[Stable release](https://github.com/Tyrrrz/DiscordChatExporter/releases/latest)**: look for `DiscordChatExporter.*.zip`
|
- 🟢 **[Stable release](https://github.com/Tyrrrz/DiscordChatExporter/releases/latest)**: look for `DiscordChatExporter.*.zip`
|
||||||
- 🟠 [CI build](https://github.com/Tyrrrz/DiscordChatExporter/actions/workflows/main.yml): look for `DiscordChatExporter.*.zip`
|
- 🟠 [CI build](https://github.com/Tyrrrz/DiscordChatExporter/actions/workflows/main.yml): look for `DiscordChatExporter.*.zip`
|
||||||
- 📦 [Scoop](https://scoop.sh/#/apps?q=DiscordChatExporter&p=1&id=c71b7367623c560a2dc746b9739b9568b79b59ae): `scoop install extras/discordchatexporter` (community-maintained)
|
- 📦 [Scoop](https://scoop.sh/#/apps?q=DiscordChatExporter&p=1&id=c71b7367623c560a2dc746b9739b9568b79b59ae): `scoop install extras/discordchatexporter` (community-maintained)
|
||||||
- 📦 [WinGet](https://winget.run/pkg/Tyrrrz/DiscordChatExporter.GUI): `winget install Tyrrrz.DiscordChatExporter.GUI` (community-maintained)
|
- 📦 [WinGet](https://winstall.app/apps/Tyrrrz.DiscordChatExporter.GUI): `winget install Tyrrrz.DiscordChatExporter.GUI` (community-maintained)
|
||||||
- 📦 [AUR](https://aur.archlinux.org/packages/discord-chat-exporter-gui): `yay -S discord-chat-exporter-gui` (community-maintained)
|
- 📦 [AUR](https://aur.archlinux.org/packages/discord-chat-exporter-gui): `yay -S discord-chat-exporter-gui` (community-maintained)
|
||||||
|
- 📦 [Nix](https://search.nixos.org/packages?show=discordchatexporter-desktop): `nix-shell -p discordchatexporter-desktop` (community-maintained)
|
||||||
- **Command-line interface** (terminal app):
|
- **Command-line interface** (terminal app):
|
||||||
- 🟢 **[Stable release](https://github.com/Tyrrrz/DiscordChatExporter/releases/latest)**: look for `DiscordChatExporter.Cli.*.zip`
|
- 🟢 **[Stable release](https://github.com/Tyrrrz/DiscordChatExporter/releases/latest)**: look for `DiscordChatExporter.Cli.*.zip`
|
||||||
- 🟠 [CI build](https://github.com/Tyrrrz/DiscordChatExporter/actions/workflows/main.yml): look for `DiscordChatExporter.Cli.*.zip`
|
- 🟠 [CI build](https://github.com/Tyrrrz/DiscordChatExporter/actions/workflows/main.yml): look for `DiscordChatExporter.Cli.*.zip`
|
||||||
- 🐋 [Docker](https://hub.docker.com/r/tyrrrz/discordchatexporter): `docker pull tyrrrz/discordchatexporter`
|
- 🐋 [Docker](https://hub.docker.com/r/tyrrrz/discordchatexporter): `docker pull tyrrrz/discordchatexporter`
|
||||||
|
- 📦 [WinGet](https://winstall.app/apps/Tyrrrz.DiscordChatExporter.CLI): `winget install Tyrrrz.DiscordChatExporter.CLI` (community-maintained)
|
||||||
- 📦 [AUR](https://aur.archlinux.org/packages/discord-chat-exporter-cli): `yay -S discord-chat-exporter-cli` (community-maintained)
|
- 📦 [AUR](https://aur.archlinux.org/packages/discord-chat-exporter-cli): `yay -S discord-chat-exporter-cli` (community-maintained)
|
||||||
- 📦 [Nix](https://search.nixos.org/packages?show=discordchatexporter-cli): `nix-shell -p discordchatexporter-cli` (community-maintained)
|
- 📦 [Nix](https://search.nixos.org/packages?show=discordchatexporter-cli): `nix-shell -p discordchatexporter-cli` (community-maintained)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 36 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 26 KiB |
Reference in New Issue
Block a user