This commit is contained in:
Tyrrrz 2021-02-22 03:15:09 +02:00
parent bed0ade732
commit ebe4d58a42
101 changed files with 330 additions and 310 deletions

View file

@ -4,9 +4,9 @@ using CliFx;
using CliFx.Attributes; using CliFx.Attributes;
using CliFx.Exceptions; using CliFx.Exceptions;
using CliFx.Utilities; using CliFx.Utilities;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Exporting; using DiscordChatExporter.Core.Exporting;
namespace DiscordChatExporter.Cli.Commands.Base namespace DiscordChatExporter.Cli.Commands.Base
{ {
@ -36,11 +36,15 @@ namespace DiscordChatExporter.Cli.Commands.Base
[CommandOption("dateformat", Description = "Format used when writing dates.")] [CommandOption("dateformat", Description = "Format used when writing dates.")]
public string DateFormat { get; init; } = "dd-MMM-yy hh:mm tt"; public string DateFormat { get; init; } = "dd-MMM-yy hh:mm tt";
protected ChannelExporter GetChannelExporter() => new(GetDiscordClient()); private ChannelExporter? _channelExporter;
protected ChannelExporter Exporter => _channelExporter ??= new ChannelExporter(Discord);
protected async ValueTask ExportAsync(IConsole console, Guild guild, Channel channel) protected async ValueTask ExportAsync(IConsole console, Guild guild, Channel channel)
{ {
console.Output.Write($"Exporting channel '{channel.Category} / {channel.Name}'... "); await console.Output.WriteAsync(
$"Exporting channel '{channel.Category} / {channel.Name}'... "
);
var progress = console.CreateProgressTicker(); var progress = console.CreateProgressTicker();
var request = new ExportRequest( var request = new ExportRequest(
@ -56,21 +60,21 @@ namespace DiscordChatExporter.Cli.Commands.Base
DateFormat DateFormat
); );
await GetChannelExporter().ExportChannelAsync(request, progress); await Exporter.ExportChannelAsync(request, progress);
console.Output.WriteLine(); await console.Output.WriteLineAsync();
console.Output.WriteLine("Done."); await console.Output.WriteLineAsync("Done.");
} }
protected async ValueTask ExportAsync(IConsole console, Channel channel) protected async ValueTask ExportAsync(IConsole console, Channel channel)
{ {
var guild = await GetDiscordClient().GetGuildAsync(channel.GuildId); var guild = await Discord.GetGuildAsync(channel.GuildId);
await ExportAsync(console, guild, channel); await ExportAsync(console, guild, channel);
} }
protected async ValueTask ExportAsync(IConsole console, Snowflake channelId) protected async ValueTask ExportAsync(IConsole console, Snowflake channelId)
{ {
var channel = await GetDiscordClient().GetChannelAsync(channelId); var channel = await Discord.GetChannelAsync(channelId);
await ExportAsync(console, channel); await ExportAsync(console, channel);
} }

View file

@ -6,10 +6,10 @@ using System.Threading.Tasks;
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Attributes;
using CliFx.Utilities; using CliFx.Utilities;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Exceptions; using DiscordChatExporter.Core.Exceptions;
using DiscordChatExporter.Domain.Exporting; using DiscordChatExporter.Core.Exporting;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using Gress; using Gress;
using Tyrrrz.Extensions; using Tyrrrz.Extensions;
@ -25,7 +25,10 @@ namespace DiscordChatExporter.Cli.Commands.Base
// This uses a different route from ExportCommandBase.ExportAsync() because it runs // This uses a different route from ExportCommandBase.ExportAsync() because it runs
// in parallel and needs another way to report progress to console. // in parallel and needs another way to report progress to console.
console.Output.Write($"Exporting {channels.Count} channels... "); await console.Output.WriteAsync(
$"Exporting {channels.Count} channels... "
);
var progress = console.CreateProgressTicker(); var progress = console.CreateProgressTicker();
var operations = progress.Wrap().CreateOperations(channels.Count); var operations = progress.Wrap().CreateOperations(channels.Count);
@ -39,7 +42,7 @@ namespace DiscordChatExporter.Cli.Commands.Base
try try
{ {
var guild = await GetDiscordClient().GetGuildAsync(channel.GuildId); var guild = await Discord.GetGuildAsync(channel.GuildId);
var request = new ExportRequest( var request = new ExportRequest(
guild, guild,
@ -54,7 +57,7 @@ namespace DiscordChatExporter.Cli.Commands.Base
DateFormat DateFormat
); );
await GetChannelExporter().ExportChannelAsync(request, operation); await Exporter.ExportChannelAsync(request, operation);
Interlocked.Increment(ref successfulExportCount); Interlocked.Increment(ref successfulExportCount);
} }
@ -68,12 +71,12 @@ namespace DiscordChatExporter.Cli.Commands.Base
} }
}, ParallelLimit.ClampMin(1)); }, ParallelLimit.ClampMin(1));
console.Output.WriteLine(); await console.Output.WriteLineAsync();
foreach (var (channel, error) in errors) foreach (var (channel, error) in errors)
console.Error.WriteLine($"Channel '{channel}': {error}"); await console.Error.WriteLineAsync($"Channel '{channel}': {error}");
console.Output.WriteLine($"Successfully exported {successfulExportCount} channel(s)."); await console.Output.WriteLineAsync($"Successfully exported {successfulExportCount} channel(s).");
} }
} }
} }

View file

@ -1,26 +1,27 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Attributes;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
namespace DiscordChatExporter.Cli.Commands.Base namespace DiscordChatExporter.Cli.Commands.Base
{ {
public abstract class TokenCommandBase : ICommand public abstract class TokenCommandBase : ICommand
{ {
[CommandOption("token", 't', IsRequired = true, EnvironmentVariableName = "DISCORD_TOKEN", Description = "Authorization token.")] [CommandOption("token", 't', IsRequired = true, EnvironmentVariableName = "DISCORD_TOKEN", Description = "Authentication token.")]
public string TokenValue { get; init; } = ""; public string TokenValue { get; init; } = "";
[CommandOption("bot", 'b', EnvironmentVariableName = "DISCORD_TOKEN_BOT", Description = "Authorize as a bot.")] [CommandOption("bot", 'b', EnvironmentVariableName = "DISCORD_TOKEN_BOT", Description = "Authenticate as a bot.")]
public bool IsBotToken { get; init; } public bool IsBotToken { get; init; }
protected AuthToken GetAuthToken() => new( private AuthToken GetAuthToken() => new(
IsBotToken IsBotToken
? AuthTokenType.Bot ? AuthTokenType.Bot
: AuthTokenType.User, : AuthTokenType.User,
TokenValue TokenValue
); );
protected DiscordClient GetDiscordClient() => new(GetAuthToken()); private DiscordClient? _discordClient;
protected DiscordClient Discord => _discordClient ??= new DiscordClient(GetAuthToken());
public abstract ValueTask ExecuteAsync(IConsole console); public abstract ValueTask ExecuteAsync(IConsole console);
} }

View file

@ -3,7 +3,7 @@ using System.Threading.Tasks;
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Attributes;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
namespace DiscordChatExporter.Cli.Commands namespace DiscordChatExporter.Cli.Commands
{ {
@ -15,16 +15,18 @@ namespace DiscordChatExporter.Cli.Commands
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {
await base.ExecuteAsync(console);
var channels = new List<Channel>(); var channels = new List<Channel>();
// Aggregate channels from all guilds // Aggregate channels from all guilds
await foreach (var guild in GetDiscordClient().GetUserGuildsAsync()) await foreach (var guild in Discord.GetUserGuildsAsync())
{ {
// Skip DMs if instructed to // Skip DMs if instructed to
if (!IncludeDirectMessages && guild.Id == Guild.DirectMessages.Id) if (!IncludeDirectMessages && guild.Id == Guild.DirectMessages.Id)
continue; continue;
await foreach (var channel in GetDiscordClient().GetGuildChannelsAsync(guild.Id)) await foreach (var channel in Discord.GetGuildChannelsAsync(guild.Id))
{ {
channels.Add(channel); channels.Add(channel);
} }

View file

@ -2,7 +2,7 @@
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Attributes;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
namespace DiscordChatExporter.Cli.Commands namespace DiscordChatExporter.Cli.Commands
{ {

View file

@ -2,8 +2,8 @@
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Attributes;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Cli.Commands namespace DiscordChatExporter.Cli.Commands
{ {
@ -12,7 +12,9 @@ namespace DiscordChatExporter.Cli.Commands
{ {
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {
var channels = await GetDiscordClient().GetGuildChannelsAsync(Guild.DirectMessages.Id); await base.ExecuteAsync(console);
var channels = await Discord.GetGuildChannelsAsync(Guild.DirectMessages.Id);
await ExportMultipleAsync(console, channels); await ExportMultipleAsync(console, channels);
} }
} }

View file

@ -2,8 +2,8 @@
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Attributes;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Cli.Commands namespace DiscordChatExporter.Cli.Commands
{ {
@ -15,7 +15,9 @@ namespace DiscordChatExporter.Cli.Commands
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {
var channels = await GetDiscordClient().GetGuildChannelsAsync(GuildId); await base.ExecuteAsync(console);
var channels = await Discord.GetGuildChannelsAsync(GuildId);
await ExportMultipleAsync(console, channels); await ExportMultipleAsync(console, channels);
} }
} }

View file

@ -3,9 +3,9 @@ using System.Threading.Tasks;
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Attributes;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Cli.Commands namespace DiscordChatExporter.Cli.Commands
{ {
@ -17,10 +17,14 @@ namespace DiscordChatExporter.Cli.Commands
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {
var channels = await GetDiscordClient().GetGuildChannelsAsync(GuildId); var channels = await Discord.GetGuildChannelsAsync(GuildId);
foreach (var channel in channels.OrderBy(c => c.Category, PositionBasedComparer.Instance).ThenBy(c => c.Name)) foreach (var channel in channels.OrderBy(c => c.Category.Position).ThenBy(c => c.Name))
console.Output.WriteLine($"{channel.Id} | {channel.Category} / {channel.Name}"); {
await console.Output.WriteLineAsync(
$"{channel.Id} | {channel.Category} / {channel.Name}"
);
}
} }
} }
} }

View file

@ -3,9 +3,8 @@ using System.Threading.Tasks;
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Attributes;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Utils.Extensions;
using DiscordChatExporter.Domain.Utilities;
namespace DiscordChatExporter.Cli.Commands namespace DiscordChatExporter.Cli.Commands
{ {
@ -14,10 +13,14 @@ namespace DiscordChatExporter.Cli.Commands
{ {
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {
var channels = await GetDiscordClient().GetGuildChannelsAsync(Guild.DirectMessages.Id); var channels = await Discord.GetGuildChannelsAsync(Guild.DirectMessages.Id);
foreach (var channel in channels.OrderBy(c => c.Name)) foreach (var channel in channels.OrderBy(c => c.Name))
console.Output.WriteLine($"{channel.Id} | {channel.Category} / {channel.Name}"); {
await console.Output.WriteLineAsync(
$"{channel.Id} | {channel.Category} / {channel.Name}"
);
}
} }
} }
} }

View file

@ -3,7 +3,7 @@ using System.Threading.Tasks;
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Attributes;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Cli.Commands namespace DiscordChatExporter.Cli.Commands
{ {
@ -12,10 +12,14 @@ namespace DiscordChatExporter.Cli.Commands
{ {
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {
var guilds = await GetDiscordClient().GetUserGuildsAsync(); var guilds = await Discord.GetUserGuildsAsync();
foreach (var guild in guilds.OrderBy(g => g.Name)) foreach (var guild in guilds.OrderBy(g => g.Name))
console.Output.WriteLine($"{guild.Id} | {guild.Name}"); {
await console.Output.WriteLineAsync(
$"{guild.Id} | {guild.Name}"
);
}
} }
} }
} }

View file

@ -12,7 +12,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\DiscordChatExporter.Domain\DiscordChatExporter.Domain.csproj" /> <ProjectReference Include="..\DiscordChatExporter.Core\DiscordChatExporter.Core.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -1,6 +1,6 @@
using System.Net.Http.Headers; using System.Net.Http.Headers;
namespace DiscordChatExporter.Domain.Discord namespace DiscordChatExporter.Core.Discord
{ {
public enum AuthTokenType { User, Bot } public enum AuthTokenType { User, Bot }
@ -16,7 +16,7 @@ namespace DiscordChatExporter.Domain.Discord
Value = value; Value = value;
} }
public AuthenticationHeaderValue GetAuthorizationHeader() => Type switch public AuthenticationHeaderValue GetAuthenticationHeader() => Type switch
{ {
AuthTokenType.Bot => new AuthenticationHeaderValue("Bot", Value), AuthTokenType.Bot => new AuthenticationHeaderValue("Bot", Value),
_ => new AuthenticationHeaderValue(Value) _ => new AuthenticationHeaderValue(Value)

View file

@ -2,11 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/channel#attachment-object // https://discord.com/developers/docs/resources/channel#attachment-object
public partial class Attachment : IHasId public partial class Attachment : IHasId
@ -32,7 +32,13 @@ namespace DiscordChatExporter.Domain.Discord.Models
public FileSize FileSize { get; } public FileSize FileSize { get; }
public Attachment(Snowflake id, string url, string fileName, int? width, int? height, FileSize fileSize) public Attachment(
Snowflake id,
string url,
string fileName,
int? width,
int? height,
FileSize fileSize)
{ {
Id = id; Id = id;
Url = url; Url = url;

View file

@ -1,12 +1,11 @@
using System; using System.Linq;
using System.Linq;
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using JsonExtensions.Reading; using JsonExtensions.Reading;
using Tyrrrz.Extensions; using Tyrrrz.Extensions;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/channel#channel-object-channel-types // https://discord.com/developers/docs/resources/channel#channel-object-channel-types
// Order of enum fields needs to match the order in the docs. // Order of enum fields needs to match the order in the docs.
@ -22,7 +21,7 @@ namespace DiscordChatExporter.Domain.Discord.Models
} }
// https://discord.com/developers/docs/resources/channel#channel-object // https://discord.com/developers/docs/resources/channel#channel-object
public partial class Channel : IHasIdAndPosition public partial class Channel : IHasId, IHasPosition
{ {
public Snowflake Id { get; } public Snowflake Id { get; }
@ -45,12 +44,19 @@ namespace DiscordChatExporter.Domain.Discord.Models
public string? Topic { get; } public string? Topic { get; }
public Channel(Snowflake id, ChannelType type, Snowflake guildId, ChannelCategory? category, string name, int? position, string? topic) public Channel(
Snowflake id,
ChannelType type,
Snowflake guildId,
ChannelCategory? category,
string name,
int? position,
string? topic)
{ {
Id = id; Id = id;
Type = type; Type = type;
GuildId = guildId; GuildId = guildId;
Category = category ?? GetDefaultCategory(type); Category = category ?? GetFallbackCategory(type);
Name = name; Name = name;
Position = position; Position = position;
Topic = topic; Topic = topic;
@ -62,19 +68,19 @@ namespace DiscordChatExporter.Domain.Discord.Models
public partial class Channel public partial class Channel
{ {
private static ChannelCategory GetDefaultCategory(ChannelType channelType) => new( private static ChannelCategory GetFallbackCategory(ChannelType channelType) => new(
Snowflake.Zero, Snowflake.Zero,
channelType switch channelType switch
{ {
ChannelType.GuildTextChat => "Text", ChannelType.GuildTextChat => "Text",
ChannelType.DirectTextChat => "Private", ChannelType.DirectTextChat => "Private",
ChannelType.DirectGroupTextChat => "Group", ChannelType.DirectGroupTextChat => "Group",
ChannelType.GuildNews => "News", ChannelType.GuildNews => "News",
ChannelType.GuildStore => "Store", ChannelType.GuildStore => "Store",
_ => "Default" _ => "Default"
}, },
0 0
); );
public static Channel Parse(JsonElement json, ChannelCategory? category = null, int? position = null) public static Channel Parse(JsonElement json, ChannelCategory? category = null, int? position = null)
{ {
@ -82,7 +88,7 @@ namespace DiscordChatExporter.Domain.Discord.Models
var guildId = json.GetPropertyOrNull("guild_id")?.GetString().Pipe(Snowflake.Parse); var guildId = json.GetPropertyOrNull("guild_id")?.GetString().Pipe(Snowflake.Parse);
var topic = json.GetPropertyOrNull("topic")?.GetString(); var topic = json.GetPropertyOrNull("topic")?.GetString();
var type = (ChannelType)json.GetProperty("type").GetInt32(); var type = (ChannelType) json.GetProperty("type").GetInt32();
var name = var name =
json.GetPropertyOrNull("name")?.GetString() ?? json.GetPropertyOrNull("name")?.GetString() ??
@ -95,7 +101,7 @@ namespace DiscordChatExporter.Domain.Discord.Models
id, id,
type, type,
guildId ?? Guild.DirectMessages.Id, guildId ?? Guild.DirectMessages.Id,
category ?? GetDefaultCategory(type), category ?? GetFallbackCategory(type),
name, name,
position, position,
topic topic

View file

@ -1,14 +1,13 @@
using System; using System.Linq;
using System.Linq;
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using JsonExtensions.Reading; using JsonExtensions.Reading;
using Tyrrrz.Extensions; using Tyrrrz.Extensions;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
public partial class ChannelCategory : IHasIdAndPosition public partial class ChannelCategory : IHasId, IHasPosition
{ {
public Snowflake Id { get; } public Snowflake Id { get; }
@ -45,6 +44,6 @@ namespace DiscordChatExporter.Domain.Discord.Models
); );
} }
public static ChannelCategory Empty { get; } = new(Snowflake.Zero, "Missing", 0); public static ChannelCategory Empty { get; } = new(Snowflake.Zero, "<unknown category>", 0);
} }
} }

View file

@ -1,6 +1,6 @@
using System; using System;
namespace DiscordChatExporter.Domain.Discord.Models.Common namespace DiscordChatExporter.Core.Discord.Data.Common
{ {
// Loosely based on https://github.com/omar/ByteSize (MIT license) // Loosely based on https://github.com/omar/ByteSize (MIT license)
public readonly partial struct FileSize public readonly partial struct FileSize

View file

@ -1,4 +1,4 @@
namespace DiscordChatExporter.Domain.Discord.Models.Common namespace DiscordChatExporter.Core.Discord.Data.Common
{ {
public interface IHasId public interface IHasId
{ {

View file

@ -0,0 +1,7 @@
namespace DiscordChatExporter.Core.Discord.Data.Common
{
public interface IHasPosition
{
int? Position { get; }
}
}

View file

@ -1,7 +1,6 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
namespace DiscordChatExporter.Domain.Discord.Models.Common namespace DiscordChatExporter.Core.Discord.Data.Common
{ {
public partial class IdBasedEqualityComparer : IEqualityComparer<IHasId> public partial class IdBasedEqualityComparer : IEqualityComparer<IHasId>
{ {

View file

@ -3,11 +3,10 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Internal.Extensions; using DiscordChatExporter.Core.Utils.Extensions;
using DiscordChatExporter.Domain.Utilities;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/channel#embed-object // https://discord.com/developers/docs/resources/channel#embed-object
public partial class Embed public partial class Embed

View file

@ -1,7 +1,7 @@
using System.Text.Json; using System.Text.Json;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/channel#embed-object-embed-author-structure // https://discord.com/developers/docs/resources/channel#embed-object-embed-author-structure
public partial class EmbedAuthor public partial class EmbedAuthor

View file

@ -1,7 +1,7 @@
using System.Text.Json; using System.Text.Json;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure // https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure
public partial class EmbedField public partial class EmbedField

View file

@ -1,7 +1,7 @@
using System.Text.Json; using System.Text.Json;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure // https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure
public partial class EmbedFooter public partial class EmbedFooter

View file

@ -1,7 +1,7 @@
using System.Text.Json; using System.Text.Json;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure // https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure
public partial class EmbedImage public partial class EmbedImage

View file

@ -5,7 +5,7 @@ using System.Text.Json;
using JsonExtensions.Reading; using JsonExtensions.Reading;
using Tyrrrz.Extensions; using Tyrrrz.Extensions;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/emoji#emoji-object // https://discord.com/developers/docs/resources/emoji#emoji-object
public partial class Emoji public partial class Emoji

View file

@ -1,8 +1,8 @@
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/guild#guild-object // https://discord.com/developers/docs/resources/guild#guild-object
public partial class Guild : IHasId public partial class Guild : IHasId
@ -25,7 +25,11 @@ namespace DiscordChatExporter.Domain.Discord.Models
public partial class Guild public partial class Guild
{ {
public static Guild DirectMessages { get; } = new(Snowflake.Zero, "Direct Messages", GetDefaultIconUrl()); public static Guild DirectMessages { get; } = new(
Snowflake.Zero,
"Direct Messages",
GetDefaultIconUrl()
);
private static string GetDefaultIconUrl() => private static string GetDefaultIconUrl() =>
"https://cdn.discordapp.com/embed/avatars/0.png"; "https://cdn.discordapp.com/embed/avatars/0.png";

View file

@ -2,11 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/guild#guild-member-object // https://discord.com/developers/docs/resources/guild#guild-member-object
public partial class Member : IHasId public partial class Member : IHasId
@ -31,7 +31,11 @@ namespace DiscordChatExporter.Domain.Discord.Models
public partial class Member public partial class Member
{ {
public static Member CreateForUser(User user) => new(user, null, Array.Empty<Snowflake>()); public static Member CreateForUser(User user) => new(
user,
null,
Array.Empty<Snowflake>()
);
public static Member Parse(JsonElement json) public static Member Parse(JsonElement json)
{ {

View file

@ -2,11 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/channel#message-object-message-types // https://discord.com/developers/docs/resources/channel#message-object-message-types
public enum MessageType public enum MessageType

View file

@ -1,8 +1,8 @@
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/channel#message-object-message-reference-structure // https://discord.com/developers/docs/resources/channel#message-object-message-reference-structure
public partial class MessageReference public partial class MessageReference

View file

@ -1,7 +1,7 @@
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/channel#reaction-object // https://discord.com/developers/docs/resources/channel#reaction-object
public partial class Reaction public partial class Reaction

View file

@ -1,11 +1,10 @@
using System.Drawing; using System.Drawing;
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Domain.Internal.Extensions; using DiscordChatExporter.Core.Utils.Extensions;
using DiscordChatExporter.Domain.Utilities;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/topics/permissions#role-object // https://discord.com/developers/docs/topics/permissions#role-object
public partial class Role : IHasId public partial class Role : IHasId
@ -18,7 +17,11 @@ namespace DiscordChatExporter.Domain.Discord.Models
public Color? Color { get; } public Color? Color { get; }
public Role(Snowflake id, string name, int position, Color? color) public Role(
Snowflake id,
string name,
int position,
Color? color)
{ {
Id = id; Id = id;
Name = name; Name = name;

View file

@ -1,10 +1,10 @@
using System; using System;
using System.Text.Json; using System.Text.Json;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord.Models namespace DiscordChatExporter.Core.Discord.Data
{ {
// https://discord.com/developers/docs/resources/user#user-object // https://discord.com/developers/docs/resources/user#user-object
public partial class User : IHasId public partial class User : IHasId
@ -21,7 +21,12 @@ namespace DiscordChatExporter.Domain.Discord.Models
public string AvatarUrl { get; } public string AvatarUrl { get; }
public User(Snowflake id, bool isBot, int discriminator, string name, string avatarUrl) public User(
Snowflake id,
bool isBot,
int discriminator,
string name,
string avatarUrl)
{ {
Id = id; Id = id;
IsBot = isBot; IsBot = isBot;

View file

@ -5,14 +5,14 @@ using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Exceptions; using DiscordChatExporter.Core.Exceptions;
using DiscordChatExporter.Domain.Internal; using DiscordChatExporter.Core.Utils;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using JsonExtensions.Http; using JsonExtensions.Http;
using JsonExtensions.Reading; using JsonExtensions.Reading;
namespace DiscordChatExporter.Domain.Discord namespace DiscordChatExporter.Core.Discord
{ {
public class DiscordClient public class DiscordClient
{ {
@ -34,7 +34,7 @@ namespace DiscordChatExporter.Domain.Discord
await Http.ResponsePolicy.ExecuteAsync(async () => await Http.ResponsePolicy.ExecuteAsync(async () =>
{ {
using var request = new HttpRequestMessage(HttpMethod.Get, new Uri(_baseUri, url)); using var request = new HttpRequestMessage(HttpMethod.Get, new Uri(_baseUri, url));
request.Headers.Authorization = _token.GetAuthorizationHeader(); request.Headers.Authorization = _token.GetAuthenticationHeader();
return await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); return await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
}); });
@ -120,7 +120,8 @@ namespace DiscordChatExporter.Domain.Discord
var orderedResponse = response var orderedResponse = response
.EnumerateArray() .EnumerateArray()
.OrderBy(j => j.GetProperty("position").GetInt32()) .OrderBy(j => j.GetProperty("position").GetInt32())
.ThenBy(j => ulong.Parse(j.GetProperty("id").GetString())); .ThenBy(j => ulong.Parse(j.GetProperty("id").GetString()))
.ToArray();
var categories = orderedResponse var categories = orderedResponse
.Where(j => j.GetProperty("type").GetInt32() == (int)ChannelType.GuildCategory) .Where(j => j.GetProperty("type").GetInt32() == (int)ChannelType.GuildCategory)
@ -135,7 +136,7 @@ namespace DiscordChatExporter.Domain.Discord
var category = !string.IsNullOrWhiteSpace(parentId) var category = !string.IsNullOrWhiteSpace(parentId)
? categories.GetValueOrDefault(parentId) ? categories.GetValueOrDefault(parentId)
: null; : null;
var channel = Channel.Parse(channelJson, category, position); var channel = Channel.Parse(channelJson, category, position);
// Skip non-text channels // Skip non-text channels

View file

@ -2,7 +2,7 @@
using System.Globalization; using System.Globalization;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace DiscordChatExporter.Domain.Discord namespace DiscordChatExporter.Core.Discord
{ {
public readonly partial struct Snowflake public readonly partial struct Snowflake
{ {
@ -32,7 +32,7 @@ namespace DiscordChatExporter.Domain.Discord
return null; return null;
// As number // As number
if (Regex.IsMatch(str, @"^\d{15,}$") && if (Regex.IsMatch(str, @"^\d+$") &&
ulong.TryParse(str, NumberStyles.Number, formatProvider, out var value)) ulong.TryParse(str, NumberStyles.Number, formatProvider, out var value))
{ {
return new Snowflake(value); return new Snowflake(value);

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Net.Http; using System.Net.Http;
namespace DiscordChatExporter.Domain.Exceptions namespace DiscordChatExporter.Core.Exceptions
{ {
public partial class DiscordChatExporterException : Exception public partial class DiscordChatExporterException : Exception
{ {

View file

@ -2,13 +2,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Discord.Models.Common; using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Domain.Exceptions; using DiscordChatExporter.Core.Exceptions;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Domain.Exporting namespace DiscordChatExporter.Core.Exporting
{ {
public class ChannelExporter public class ChannelExporter
{ {

View file

@ -5,12 +5,12 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Internal.Extensions; using DiscordChatExporter.Core.Utils.Extensions;
using Tyrrrz.Extensions; using Tyrrrz.Extensions;
namespace DiscordChatExporter.Domain.Exporting namespace DiscordChatExporter.Core.Exporting
{ {
internal class ExportContext internal class ExportContext
{ {

View file

@ -1,6 +1,6 @@
using System; using System;
namespace DiscordChatExporter.Domain.Exporting namespace DiscordChatExporter.Core.Exporting
{ {
public enum ExportFormat public enum ExportFormat
{ {

View file

@ -2,11 +2,11 @@
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Internal; using DiscordChatExporter.Core.Utils;
namespace DiscordChatExporter.Domain.Exporting namespace DiscordChatExporter.Core.Exporting
{ {
public partial class ExportRequest public partial class ExportRequest
{ {

View file

@ -7,11 +7,10 @@ using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordChatExporter.Domain.Internal; using DiscordChatExporter.Core.Utils;
using DiscordChatExporter.Domain.Internal.Extensions; using DiscordChatExporter.Core.Utils.Extensions;
using DiscordChatExporter.Domain.Utilities;
namespace DiscordChatExporter.Domain.Exporting namespace DiscordChatExporter.Core.Exporting
{ {
internal partial class MediaDownloader internal partial class MediaDownloader
{ {

View file

@ -1,10 +1,10 @@
using System; using System;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Exporting.Writers; using DiscordChatExporter.Core.Exporting.Writers;
namespace DiscordChatExporter.Domain.Exporting namespace DiscordChatExporter.Core.Exporting
{ {
internal partial class MessageExporter : IAsyncDisposable internal partial class MessageExporter : IAsyncDisposable
{ {

View file

@ -2,11 +2,11 @@
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Exporting.Writers.MarkdownVisitors; using DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors;
using DiscordChatExporter.Domain.Internal.Extensions; using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Domain.Exporting.Writers namespace DiscordChatExporter.Core.Exporting.Writers
{ {
internal partial class CsvMessageWriter : MessageWriter internal partial class CsvMessageWriter : MessageWriter
{ {

View file

@ -1,4 +1,4 @@
namespace DiscordChatExporter.Domain.Exporting.Writers.Html namespace DiscordChatExporter.Core.Exporting.Writers.Html
{ {
internal class LayoutTemplateContext internal class LayoutTemplateContext
{ {

View file

@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
namespace DiscordChatExporter.Domain.Exporting.Writers.Html namespace DiscordChatExporter.Core.Exporting.Writers.Html
{ {
// Used for grouping contiguous messages in HTML export // Used for grouping contiguous messages in HTML export
internal partial class MessageGroup internal partial class MessageGroup

View file

@ -1,8 +1,8 @@
@using System @using System
@using System.Linq @using System.Linq
@using System.Threading.Tasks @using System.Threading.Tasks
@namespace DiscordChatExporter.Domain.Exporting.Writers.Html @namespace DiscordChatExporter.Core.Exporting.Writers.Html
@inherits MiniRazor.TemplateBase<DiscordChatExporter.Domain.Exporting.Writers.Html.MessageGroupTemplateContext> @inherits MiniRazor.TemplateBase<DiscordChatExporter.Core.Exporting.Writers.Html.MessageGroupTemplateContext>
@{ @{
string FormatDate(DateTimeOffset date) => Model.ExportContext.FormatDate(date); string FormatDate(DateTimeOffset date) => Model.ExportContext.FormatDate(date);

View file

@ -1,6 +1,6 @@
using DiscordChatExporter.Domain.Exporting.Writers.MarkdownVisitors; using DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors;
namespace DiscordChatExporter.Domain.Exporting.Writers.Html namespace DiscordChatExporter.Core.Exporting.Writers.Html
{ {
internal class MessageGroupTemplateContext internal class MessageGroupTemplateContext
{ {

View file

@ -0,0 +1,12 @@
@namespace DiscordChatExporter.Core.Exporting.Writers.Html
@inherits MiniRazor.TemplateBase<DiscordChatExporter.Core.Exporting.Writers.Html.LayoutTemplateContext>
</div>
<div class="postamble">
<div class="postamble__entry">Exported @Model.MessageCount.ToString("N0") message(s)</div>
</div>
</body>
</html>

View file

@ -1,15 +1,15 @@
@using System @using System
@using System.Threading.Tasks @using System.Threading.Tasks
@using Tyrrrz.Extensions @using Tyrrrz.Extensions
@namespace DiscordChatExporter.Domain.Exporting.Writers.Html @namespace DiscordChatExporter.Core.Exporting.Writers.Html
@inherits MiniRazor.TemplateBase<DiscordChatExporter.Domain.Exporting.Writers.Html.LayoutTemplateContext> @inherits MiniRazor.TemplateBase<DiscordChatExporter.Core.Exporting.Writers.Html.LayoutTemplateContext>
@{ @{
string FormatDate(DateTimeOffset date) => Model.ExportContext.FormatDate(date); string FormatDate(DateTimeOffset date) => Model.ExportContext.FormatDate(date);
ValueTask<string> ResolveUrlAsync(string url) => Model.ExportContext.ResolveMediaUrlAsync(url); ValueTask<string> ResolveUrlAsync(string url) => Model.ExportContext.ResolveMediaUrlAsync(url);
string GetStyleSheet(string name) => Model.GetType().Assembly.GetManifestResourceString($"DiscordChatExporter.Domain.Exporting.Writers.Html.{name}.css"); string GetStyleSheet(string name) => Model.GetType().Assembly.GetManifestResourceString($"DiscordChatExporter.Core.Exporting.Writers.Html.{name}.css");
} }
<!DOCTYPE html> <!DOCTYPE html>

View file

@ -2,10 +2,10 @@
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Exporting.Writers.Html; using DiscordChatExporter.Core.Exporting.Writers.Html;
namespace DiscordChatExporter.Domain.Exporting.Writers namespace DiscordChatExporter.Core.Exporting.Writers
{ {
internal class HtmlMessageWriter : MessageWriter internal class HtmlMessageWriter : MessageWriter
{ {

View file

@ -1,13 +1,13 @@
using System.IO; using System.IO;
using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Text.Encodings.Web; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors;
using DiscordChatExporter.Domain.Exporting.Writers.MarkdownVisitors; using DiscordChatExporter.Core.Utils.Extensions;
using DiscordChatExporter.Domain.Internal.Extensions;
using JsonExtensions.Writing; using JsonExtensions.Writing;
namespace DiscordChatExporter.Domain.Exporting.Writers namespace DiscordChatExporter.Core.Exporting.Writers
{ {
internal class JsonMessageWriter : MessageWriter internal class JsonMessageWriter : MessageWriter
{ {

View file

@ -3,13 +3,13 @@ using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Markdown; using DiscordChatExporter.Core.Markdown;
using DiscordChatExporter.Domain.Markdown.Ast; using DiscordChatExporter.Core.Markdown.Ast;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Domain.Exporting.Writers.MarkdownVisitors namespace DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors
{ {
internal partial class HtmlMarkdownVisitor : MarkdownVisitor internal partial class HtmlMarkdownVisitor : MarkdownVisitor
{ {

View file

@ -1,10 +1,10 @@
using System.Text; using System.Text;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Markdown; using DiscordChatExporter.Core.Markdown;
using DiscordChatExporter.Domain.Markdown.Ast; using DiscordChatExporter.Core.Markdown.Ast;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Domain.Exporting.Writers.MarkdownVisitors namespace DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors
{ {
internal partial class PlainTextMarkdownVisitor : MarkdownVisitor internal partial class PlainTextMarkdownVisitor : MarkdownVisitor
{ {

View file

@ -1,9 +1,9 @@
using System; using System;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
namespace DiscordChatExporter.Domain.Exporting.Writers namespace DiscordChatExporter.Core.Exporting.Writers
{ {
internal abstract class MessageWriter : IAsyncDisposable internal abstract class MessageWriter : IAsyncDisposable
{ {

View file

@ -2,11 +2,11 @@
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Exporting.Writers.MarkdownVisitors; using DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors;
using Tyrrrz.Extensions; using Tyrrrz.Extensions;
namespace DiscordChatExporter.Domain.Exporting.Writers namespace DiscordChatExporter.Core.Exporting.Writers
{ {
internal class PlainTextMessageWriter : MessageWriter internal class PlainTextMessageWriter : MessageWriter
{ {

View file

@ -1,4 +1,4 @@
namespace DiscordChatExporter.Domain.Markdown.Ast namespace DiscordChatExporter.Core.Markdown.Ast
{ {
internal class EmojiNode : MarkdownNode internal class EmojiNode : MarkdownNode
{ {

View file

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace DiscordChatExporter.Domain.Markdown.Ast namespace DiscordChatExporter.Core.Markdown.Ast
{ {
internal enum TextFormatting internal enum TextFormatting
{ {

View file

@ -1,4 +1,4 @@
namespace DiscordChatExporter.Domain.Markdown.Ast namespace DiscordChatExporter.Core.Markdown.Ast
{ {
internal class InlineCodeBlockNode : MarkdownNode internal class InlineCodeBlockNode : MarkdownNode
{ {

View file

@ -1,4 +1,4 @@
namespace DiscordChatExporter.Domain.Markdown.Ast namespace DiscordChatExporter.Core.Markdown.Ast
{ {
internal class LinkNode : MarkdownNode internal class LinkNode : MarkdownNode
{ {

View file

@ -1,4 +1,4 @@
namespace DiscordChatExporter.Domain.Markdown.Ast namespace DiscordChatExporter.Core.Markdown.Ast
{ {
internal abstract class MarkdownNode internal abstract class MarkdownNode
{ {

View file

@ -1,4 +1,4 @@
namespace DiscordChatExporter.Domain.Markdown.Ast namespace DiscordChatExporter.Core.Markdown.Ast
{ {
internal enum MentionType internal enum MentionType
{ {

View file

@ -1,4 +1,4 @@
namespace DiscordChatExporter.Domain.Markdown.Ast namespace DiscordChatExporter.Core.Markdown.Ast
{ {
internal class MultiLineCodeBlockNode : MarkdownNode internal class MultiLineCodeBlockNode : MarkdownNode
{ {

View file

@ -1,4 +1,4 @@
namespace DiscordChatExporter.Domain.Markdown.Ast namespace DiscordChatExporter.Core.Markdown.Ast
{ {
internal class TextNode : MarkdownNode internal class TextNode : MarkdownNode
{ {

View file

@ -1,10 +1,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using DiscordChatExporter.Domain.Markdown.Ast; using DiscordChatExporter.Core.Markdown.Ast;
using DiscordChatExporter.Domain.Markdown.Matching; using DiscordChatExporter.Core.Markdown.Matching;
namespace DiscordChatExporter.Domain.Markdown namespace DiscordChatExporter.Core.Markdown
{ {
// The following parsing logic is meant to replicate Discord's markdown grammar as close as possible // The following parsing logic is meant to replicate Discord's markdown grammar as close as possible
internal static partial class MarkdownParser internal static partial class MarkdownParser

View file

@ -1,8 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using DiscordChatExporter.Domain.Markdown.Ast; using DiscordChatExporter.Core.Markdown.Ast;
namespace DiscordChatExporter.Domain.Markdown namespace DiscordChatExporter.Core.Markdown
{ {
internal abstract class MarkdownVisitor internal abstract class MarkdownVisitor
{ {

View file

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace DiscordChatExporter.Domain.Markdown.Matching namespace DiscordChatExporter.Core.Markdown.Matching
{ {
internal class AggregateMatcher<T> : IMatcher<T> internal class AggregateMatcher<T> : IMatcher<T>
{ {

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace DiscordChatExporter.Domain.Markdown.Matching namespace DiscordChatExporter.Core.Markdown.Matching
{ {
internal interface IMatcher<T> internal interface IMatcher<T>
{ {

View file

@ -1,4 +1,4 @@
namespace DiscordChatExporter.Domain.Markdown.Matching namespace DiscordChatExporter.Core.Markdown.Matching
{ {
internal class ParsedMatch<T> internal class ParsedMatch<T>
{ {

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace DiscordChatExporter.Domain.Markdown.Matching namespace DiscordChatExporter.Core.Markdown.Matching
{ {
internal class RegexMatcher<T> : IMatcher<T> internal class RegexMatcher<T> : IMatcher<T>
{ {

View file

@ -1,6 +1,6 @@
using System; using System;
namespace DiscordChatExporter.Domain.Markdown.Matching namespace DiscordChatExporter.Core.Markdown.Matching
{ {
internal class StringMatcher<T> : IMatcher<T> internal class StringMatcher<T> : IMatcher<T>
{ {

View file

@ -1,6 +1,6 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace DiscordChatExporter.Domain.Markdown.Matching namespace DiscordChatExporter.Core.Markdown.Matching
{ {
internal readonly struct StringPart internal readonly struct StringPart
{ {

View file

@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace DiscordChatExporter.Domain.Utilities namespace DiscordChatExporter.Core.Utils.Extensions
{ {
public static class AsyncExtensions public static class AsyncExtensions
{ {

View file

@ -1,8 +1,8 @@
using System.Text; using System.Text;
namespace DiscordChatExporter.Domain.Internal.Extensions namespace DiscordChatExporter.Core.Utils.Extensions
{ {
internal static class BinaryExtensions public static class BinaryExtensions
{ {
public static string ToHex(this byte[] data) public static string ToHex(this byte[] data)
{ {

View file

@ -1,8 +1,8 @@
using System.Drawing; using System.Drawing;
namespace DiscordChatExporter.Domain.Internal.Extensions namespace DiscordChatExporter.Core.Utils.Extensions
{ {
internal static class ColorExtensions public static class ColorExtensions
{ {
public static Color WithAlpha(this Color color, int alpha) => Color.FromArgb(alpha, color); public static Color WithAlpha(this Color color, int alpha) => Color.FromArgb(alpha, color);

View file

@ -1,9 +1,9 @@
using System; using System;
using System.Globalization; using System.Globalization;
namespace DiscordChatExporter.Domain.Internal.Extensions namespace DiscordChatExporter.Core.Utils.Extensions
{ {
internal static class DateExtensions public static class DateExtensions
{ {
public static string ToLocalString(this DateTimeOffset dateTime, string format) => public static string ToLocalString(this DateTimeOffset dateTime, string format) =>
dateTime.ToLocalTime().ToString(format, CultureInfo.InvariantCulture); dateTime.ToLocalTime().ToString(format, CultureInfo.InvariantCulture);

View file

@ -1,9 +1,11 @@
using System; using System;
namespace DiscordChatExporter.Domain.Internal.Extensions namespace DiscordChatExporter.Core.Utils.Extensions
{ {
internal static class GenericExtensions public static class GenericExtensions
{ {
public static TOut Pipe<TIn, TOut>(this TIn input, Func<TIn, TOut> transform) => transform(input);
public static T? NullIf<T>(this T value, Func<T, bool> predicate) where T : struct => public static T? NullIf<T>(this T value, Func<T, bool> predicate) where T : struct =>
!predicate(value) !predicate(value)
? value ? value

View file

@ -1,8 +1,8 @@
using System.Net.Http.Headers; using System.Net.Http.Headers;
namespace DiscordChatExporter.Domain.Internal.Extensions namespace DiscordChatExporter.Core.Utils.Extensions
{ {
internal static class HttpExtensions public static class HttpExtensions
{ {
public static string? TryGetValue(this HttpContentHeaders headers, string name) => public static string? TryGetValue(this HttpContentHeaders headers, string name) =>
headers.TryGetValues(name, out var values) headers.TryGetValues(name, out var values)

View file

@ -1,8 +1,8 @@
using System.Text; using System.Text;
namespace DiscordChatExporter.Domain.Internal.Extensions namespace DiscordChatExporter.Core.Utils.Extensions
{ {
internal static class StringExtensions public static class StringExtensions
{ {
public static string Truncate(this string str, int charCount) => public static string Truncate(this string str, int charCount) =>
str.Length > charCount str.Length > charCount

View file

@ -7,9 +7,9 @@ using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Polly; using Polly;
namespace DiscordChatExporter.Domain.Internal namespace DiscordChatExporter.Core.Utils
{ {
internal static class Http public static class Http
{ {
public static HttpClient Client { get; } = new(); public static HttpClient Client { get; } = new();

View file

@ -1,9 +1,9 @@
using System.IO; using System.IO;
using System.Text; using System.Text;
namespace DiscordChatExporter.Domain.Internal namespace DiscordChatExporter.Core.Utils
{ {
internal static class PathEx public static class PathEx
{ {
public static StringBuilder EscapePath(StringBuilder pathBuffer) public static StringBuilder EscapePath(StringBuilder pathBuffer)
{ {

View file

@ -4,9 +4,9 @@ using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
namespace DiscordChatExporter.Domain.Internal namespace DiscordChatExporter.Core.Utils
{ {
internal class UrlBuilder public class UrlBuilder
{ {
private string _path = ""; private string _path = "";

View file

@ -1,7 +0,0 @@
namespace DiscordChatExporter.Domain.Discord.Models.Common
{
public interface IHasIdAndPosition : IHasId
{
int? Position { get; }
}
}

View file

@ -1,22 +0,0 @@
using System.Collections.Generic;
namespace DiscordChatExporter.Domain.Discord.Models.Common
{
public partial class PositionBasedComparer : IComparer<IHasIdAndPosition>
{
public int Compare(IHasIdAndPosition? x, IHasIdAndPosition? y)
{
int result = Comparer<int?>.Default.Compare(x?.Position, y?.Position);
if (result == 0)
{
result = Comparer<ulong?>.Default.Compare(x?.Id.Value, y?.Id.Value);
}
return result;
}
}
public partial class PositionBasedComparer
{
public static PositionBasedComparer Instance { get; } = new();
}
}

View file

@ -1,12 +0,0 @@
@namespace DiscordChatExporter.Domain.Exporting.Writers.Html
@inherits MiniRazor.TemplateBase<DiscordChatExporter.Domain.Exporting.Writers.Html.LayoutTemplateContext>
</div>
<div class="postamble">
<div class="postamble__entry">Exported @Model.MessageCount.ToString("N0") message(s)</div>
</div>
</body>
</html>

View file

@ -1,9 +0,0 @@
using System;
namespace DiscordChatExporter.Domain.Utilities
{
public static class GeneralExtensions
{
public static TOut Pipe<TIn, TOut>(this TIn input, Func<TIn, TOut> transform) => transform(input);
}
}

View file

@ -1,6 +1,6 @@
using System; using System;
using System.Reflection; using System.Reflection;
using DiscordChatExporter.Gui.Internal; using DiscordChatExporter.Gui.Utils;
using MaterialDesignThemes.Wpf; using MaterialDesignThemes.Wpf;
namespace DiscordChatExporter.Gui namespace DiscordChatExporter.Gui

View file

@ -1,4 +1,4 @@
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
namespace DiscordChatExporter.Gui.Behaviors namespace DiscordChatExporter.Gui.Behaviors
{ {

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
using System.Windows.Data; using System.Windows.Data;
using DiscordChatExporter.Domain.Exporting; using DiscordChatExporter.Core.Exporting;
namespace DiscordChatExporter.Gui.Converters namespace DiscordChatExporter.Gui.Converters
{ {

View file

@ -25,7 +25,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\DiscordChatExporter.Domain\DiscordChatExporter.Domain.csproj" /> <ProjectReference Include="..\DiscordChatExporter.Core\DiscordChatExporter.Core.csproj" />
</ItemGroup> </ItemGroup>
<Target Name="Format XAML" AfterTargets="BeforeBuild"> <Target Name="Format XAML" AfterTargets="BeforeBuild">

View file

@ -1,5 +1,5 @@
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Exporting; using DiscordChatExporter.Core.Exporting;
using Tyrrrz.Settings; using Tyrrrz.Settings;
namespace DiscordChatExporter.Gui.Services namespace DiscordChatExporter.Gui.Services

View file

@ -1,6 +1,6 @@
using System.Windows.Media; using System.Windows.Media;
namespace DiscordChatExporter.Gui.Internal namespace DiscordChatExporter.Gui.Utils
{ {
internal static class MediaColor internal static class MediaColor
{ {

View file

@ -1,6 +1,6 @@
using System.Diagnostics; using System.Diagnostics;
namespace DiscordChatExporter.Gui.Internal namespace DiscordChatExporter.Gui.Utils
{ {
internal static class ProcessEx internal static class ProcessEx
{ {

View file

@ -1,10 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Exporting; using DiscordChatExporter.Core.Exporting;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using DiscordChatExporter.Gui.Services; using DiscordChatExporter.Gui.Services;
using DiscordChatExporter.Gui.ViewModels.Framework; using DiscordChatExporter.Gui.ViewModels.Framework;

View file

@ -3,13 +3,13 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordChatExporter.Domain.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Domain.Discord.Models; using DiscordChatExporter.Core.Discord.Data;
using DiscordChatExporter.Domain.Exceptions; using DiscordChatExporter.Core.Exceptions;
using DiscordChatExporter.Domain.Exporting; using DiscordChatExporter.Core.Exporting;
using DiscordChatExporter.Domain.Utilities; using DiscordChatExporter.Core.Utils.Extensions;
using DiscordChatExporter.Gui.Internal;
using DiscordChatExporter.Gui.Services; using DiscordChatExporter.Gui.Services;
using DiscordChatExporter.Gui.Utils;
using DiscordChatExporter.Gui.ViewModels.Dialogs; using DiscordChatExporter.Gui.ViewModels.Dialogs;
using DiscordChatExporter.Gui.ViewModels.Framework; using DiscordChatExporter.Gui.ViewModels.Framework;
using Gress; using Gress;

View file

@ -16,7 +16,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordChatExporter.Gui", "
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscordChatExporter.Cli", "DiscordChatExporter.Cli\DiscordChatExporter.Cli.csproj", "{D08624B6-3081-4BCB-91F8-E9832FACC6CE}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscordChatExporter.Cli", "DiscordChatExporter.Cli\DiscordChatExporter.Cli.csproj", "{D08624B6-3081-4BCB-91F8-E9832FACC6CE}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordChatExporter.Domain", "DiscordChatExporter.Domain\DiscordChatExporter.Domain.csproj", "{E19980B9-2B84-4257-A517-540FF1E3FCDD}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordChatExporter.Core", "DiscordChatExporter.Core\DiscordChatExporter.Core.csproj", "{E19980B9-2B84-4257-A517-540FF1E3FCDD}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

View file

@ -4,7 +4,7 @@ WORKDIR /src
COPY favicon.ico ./ COPY favicon.ico ./
COPY Directory.Build.props ./ COPY Directory.Build.props ./
COPY DiscordChatExporter.Domain DiscordChatExporter.Domain COPY DiscordChatExporter.Core DiscordChatExporter.Core
COPY DiscordChatExporter.Cli DiscordChatExporter.Cli COPY DiscordChatExporter.Cli DiscordChatExporter.Cli
RUN dotnet publish DiscordChatExporter.Cli -o DiscordChatExporter.Cli/publish -c Release RUN dotnet publish DiscordChatExporter.Cli -o DiscordChatExporter.Cli/publish -c Release

Some files were not shown because too many files have changed in this diff Show more