Format stuff

This commit is contained in:
Tyrrrz
2024-10-26 21:41:16 +03:00
parent e8192b2b53
commit 09e0b3f133
45 changed files with 156 additions and 174 deletions
@@ -56,7 +56,7 @@ public static class ExportWrapper
ExportFormat = format, ExportFormat = format,
OutputPath = filePath, OutputPath = filePath,
Locale = "en-US", Locale = "en-US",
IsUtcNormalizationEnabled = true IsUtcNormalizationEnabled = true,
}.ExecuteAsync(console); }.ExecuteAsync(console);
} }
@@ -30,7 +30,7 @@ public class DateRangeSpecs
ChannelIds = [ChannelIds.DateRangeTestCases], ChannelIds = [ChannelIds.DateRangeTestCases],
ExportFormat = ExportFormat.Json, ExportFormat = ExportFormat.Json,
OutputPath = file.Path, OutputPath = file.Path,
After = Snowflake.FromDate(after) After = Snowflake.FromDate(after),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -50,7 +50,7 @@ public class DateRangeSpecs
new DateTimeOffset(2021, 07, 24, 14, 52, 38, TimeSpan.Zero), new DateTimeOffset(2021, 07, 24, 14, 52, 38, TimeSpan.Zero),
new DateTimeOffset(2021, 07, 24, 14, 52, 39, TimeSpan.Zero), new DateTimeOffset(2021, 07, 24, 14, 52, 39, TimeSpan.Zero),
new DateTimeOffset(2021, 07, 24, 14, 52, 40, TimeSpan.Zero), new DateTimeOffset(2021, 07, 24, 14, 52, 40, TimeSpan.Zero),
new DateTimeOffset(2021, 09, 08, 14, 26, 35, TimeSpan.Zero) new DateTimeOffset(2021, 09, 08, 14, 26, 35, TimeSpan.Zero),
], ],
o => o =>
o.Using<DateTimeOffset>(ctx => o.Using<DateTimeOffset>(ctx =>
@@ -74,7 +74,7 @@ public class DateRangeSpecs
ChannelIds = [ChannelIds.DateRangeTestCases], ChannelIds = [ChannelIds.DateRangeTestCases],
ExportFormat = ExportFormat.Json, ExportFormat = ExportFormat.Json,
OutputPath = file.Path, OutputPath = file.Path,
Before = Snowflake.FromDate(before) Before = Snowflake.FromDate(before),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -92,7 +92,7 @@ public class DateRangeSpecs
[ [
new DateTimeOffset(2021, 07, 19, 13, 34, 18, TimeSpan.Zero), new DateTimeOffset(2021, 07, 19, 13, 34, 18, TimeSpan.Zero),
new DateTimeOffset(2021, 07, 19, 15, 58, 48, TimeSpan.Zero), new DateTimeOffset(2021, 07, 19, 15, 58, 48, TimeSpan.Zero),
new DateTimeOffset(2021, 07, 19, 17, 23, 58, TimeSpan.Zero) new DateTimeOffset(2021, 07, 19, 17, 23, 58, TimeSpan.Zero),
], ],
o => o =>
o.Using<DateTimeOffset>(ctx => o.Using<DateTimeOffset>(ctx =>
@@ -118,7 +118,7 @@ public class DateRangeSpecs
ExportFormat = ExportFormat.Json, ExportFormat = ExportFormat.Json,
OutputPath = file.Path, OutputPath = file.Path,
Before = Snowflake.FromDate(before), Before = Snowflake.FromDate(before),
After = Snowflake.FromDate(after) After = Snowflake.FromDate(after),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -137,7 +137,7 @@ public class DateRangeSpecs
new DateTimeOffset(2021, 07, 24, 13, 49, 13, TimeSpan.Zero), new DateTimeOffset(2021, 07, 24, 13, 49, 13, TimeSpan.Zero),
new DateTimeOffset(2021, 07, 24, 14, 52, 38, TimeSpan.Zero), new DateTimeOffset(2021, 07, 24, 14, 52, 38, TimeSpan.Zero),
new DateTimeOffset(2021, 07, 24, 14, 52, 39, TimeSpan.Zero), new DateTimeOffset(2021, 07, 24, 14, 52, 39, TimeSpan.Zero),
new DateTimeOffset(2021, 07, 24, 14, 52, 40, TimeSpan.Zero) new DateTimeOffset(2021, 07, 24, 14, 52, 40, TimeSpan.Zero),
], ],
o => o =>
o.Using<DateTimeOffset>(ctx => o.Using<DateTimeOffset>(ctx =>
@@ -29,7 +29,7 @@ public class FilterSpecs
ChannelIds = [ChannelIds.FilterTestCases], ChannelIds = [ChannelIds.FilterTestCases],
ExportFormat = ExportFormat.Json, ExportFormat = ExportFormat.Json,
OutputPath = file.Path, OutputPath = file.Path,
MessageFilter = MessageFilter.Parse("some text") MessageFilter = MessageFilter.Parse("some text"),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -54,7 +54,7 @@ public class FilterSpecs
ChannelIds = [ChannelIds.FilterTestCases], ChannelIds = [ChannelIds.FilterTestCases],
ExportFormat = ExportFormat.Json, ExportFormat = ExportFormat.Json,
OutputPath = file.Path, OutputPath = file.Path,
MessageFilter = MessageFilter.Parse("from:Tyrrrz") MessageFilter = MessageFilter.Parse("from:Tyrrrz"),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -79,7 +79,7 @@ public class FilterSpecs
ChannelIds = [ChannelIds.FilterTestCases], ChannelIds = [ChannelIds.FilterTestCases],
ExportFormat = ExportFormat.Json, ExportFormat = ExportFormat.Json,
OutputPath = file.Path, OutputPath = file.Path,
MessageFilter = MessageFilter.Parse("has:image") MessageFilter = MessageFilter.Parse("has:image"),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -104,7 +104,7 @@ public class FilterSpecs
ChannelIds = [ChannelIds.FilterTestCases], ChannelIds = [ChannelIds.FilterTestCases],
ExportFormat = ExportFormat.Json, ExportFormat = ExportFormat.Json,
OutputPath = file.Path, OutputPath = file.Path,
MessageFilter = MessageFilter.Parse("has:pin") MessageFilter = MessageFilter.Parse("has:pin"),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -129,7 +129,7 @@ public class FilterSpecs
ChannelIds = [ChannelIds.FilterTestCases], ChannelIds = [ChannelIds.FilterTestCases],
ExportFormat = ExportFormat.Json, ExportFormat = ExportFormat.Json,
OutputPath = file.Path, OutputPath = file.Path,
MessageFilter = MessageFilter.Parse("has:invite") MessageFilter = MessageFilter.Parse("has:invite"),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -154,7 +154,7 @@ public class FilterSpecs
ChannelIds = [ChannelIds.FilterTestCases], ChannelIds = [ChannelIds.FilterTestCases],
ExportFormat = ExportFormat.Json, ExportFormat = ExportFormat.Json,
OutputPath = file.Path, OutputPath = file.Path,
MessageFilter = MessageFilter.Parse("mentions:Tyrrrz") MessageFilter = MessageFilter.Parse("mentions:Tyrrrz"),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -28,7 +28,7 @@ public class HtmlGroupingSpecs
Token = Secrets.DiscordToken, Token = Secrets.DiscordToken,
ChannelIds = [ChannelIds.GroupingTestCases], ChannelIds = [ChannelIds.GroupingTestCases],
ExportFormat = ExportFormat.HtmlDark, ExportFormat = ExportFormat.HtmlDark,
OutputPath = file.Path OutputPath = file.Path,
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -27,7 +27,7 @@ public class PartitioningSpecs
ChannelIds = [ChannelIds.DateRangeTestCases], ChannelIds = [ChannelIds.DateRangeTestCases],
ExportFormat = ExportFormat.HtmlDark, ExportFormat = ExportFormat.HtmlDark,
OutputPath = filePath, OutputPath = filePath,
PartitionLimit = PartitionLimit.Parse("3") PartitionLimit = PartitionLimit.Parse("3"),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -48,7 +48,7 @@ public class PartitioningSpecs
ChannelIds = [ChannelIds.DateRangeTestCases], ChannelIds = [ChannelIds.DateRangeTestCases],
ExportFormat = ExportFormat.HtmlDark, ExportFormat = ExportFormat.HtmlDark,
OutputPath = filePath, OutputPath = filePath,
PartitionLimit = PartitionLimit.Parse("1kb") PartitionLimit = PartitionLimit.Parse("1kb"),
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -27,7 +27,7 @@ public class SelfContainedSpecs
ChannelIds = [ChannelIds.SelfContainedTestCases], ChannelIds = [ChannelIds.SelfContainedTestCases],
ExportFormat = ExportFormat.HtmlDark, ExportFormat = ExportFormat.HtmlDark,
OutputPath = filePath, OutputPath = filePath,
ShouldDownloadAssets = true ShouldDownloadAssets = true,
}.ExecuteAsync(new FakeConsole()); }.ExecuteAsync(new FakeConsole());
// Assert // Assert
@@ -196,7 +196,7 @@ public abstract class ExportCommandBase : DiscordCommandBase
new ParallelOptions new ParallelOptions
{ {
MaxDegreeOfParallelism = Math.Max(1, ParallelLimit), MaxDegreeOfParallelism = Math.Max(1, ParallelLimit),
CancellationToken = cancellationToken CancellationToken = cancellationToken,
}, },
async (channel, innerCancellationToken) => async (channel, innerCancellationToken) =>
{ {
@@ -4,5 +4,5 @@ public enum ThreadInclusionMode
{ {
None, None,
Active, Active,
All All,
} }
@@ -13,7 +13,7 @@ internal static class ConsoleExtensions
{ {
Ansi = AnsiSupport.Detect, Ansi = AnsiSupport.Detect,
ColorSystem = ColorSystemSupport.Detect, ColorSystem = ColorSystemSupport.Detect,
Out = new AnsiConsoleOutput(console.Output) Out = new AnsiConsoleOutput(console.Output),
} }
); );
@@ -16,5 +16,5 @@ public enum ApplicationFlags
Embedded = 131072, Embedded = 131072,
GatewayMessageContent = 262144, GatewayMessageContent = 262144,
GatewayMessageContentLimited = 524288, GatewayMessageContentLimited = 524288,
ApplicationCommandBadge = 8388608 ApplicationCommandBadge = 8388608,
} }
@@ -14,5 +14,5 @@ public enum ChannelKind
GuildPrivateThread = 12, GuildPrivateThread = 12,
GuildStageVoice = 13, GuildStageVoice = 13,
GuildDirectory = 14, GuildDirectory = 14,
GuildForum = 15 GuildForum = 15,
} }
@@ -7,5 +7,5 @@ public enum EmbedKind
Image, Image,
Video, Video,
Gifv, Gifv,
Link Link,
} }
@@ -3548,7 +3548,7 @@ internal static class EmojiIndex
["🇸🇯"] = "flag_sj", ["🇸🇯"] = "flag_sj",
["🇹🇦"] = "flag_ta", ["🇹🇦"] = "flag_ta",
["🇺🇲"] = "flag_um", ["🇺🇲"] = "flag_um",
["🇺🇳"] = "united_nations" ["🇺🇳"] = "united_nations",
}; };
private static Dictionary<string, string> _fromCodes = private static Dictionary<string, string> _fromCodes =
@@ -8880,7 +8880,7 @@ internal static class EmojiIndex
["flag_sj"] = "🇸🇯", ["flag_sj"] = "🇸🇯",
["flag_ta"] = "🇹🇦", ["flag_ta"] = "🇹🇦",
["flag_um"] = "🇺🇲", ["flag_um"] = "🇺🇲",
["united_nations"] = "🇺🇳" ["united_nations"] = "🇺🇳",
}; };
public static string? TryGetCode(string name) => _toCodes.GetValueOrDefault(name); public static string? TryGetCode(string name) => _toCodes.GetValueOrDefault(name);
@@ -14,5 +14,5 @@ public enum MessageFlags
Urgent = 16, Urgent = 16,
HasThread = 32, HasThread = 32,
Ephemeral = 64, Ephemeral = 64,
Loading = 128 Loading = 128,
} }
@@ -12,5 +12,5 @@ public enum MessageKind
ChannelPinnedMessage = 6, ChannelPinnedMessage = 6,
GuildMemberJoin = 7, GuildMemberJoin = 7,
ThreadCreated = 18, ThreadCreated = 18,
Reply = 19 Reply = 19,
} }
@@ -28,7 +28,7 @@ public partial record Sticker
StickerFormat.Apng => "png", StickerFormat.Apng => "png",
StickerFormat.Lottie => "json", StickerFormat.Lottie => "json",
StickerFormat.Gif => "gif", StickerFormat.Gif => "gif",
_ => throw new InvalidOperationException($"Unknown sticker format '{format}'.") _ => throw new InvalidOperationException($"Unknown sticker format '{format}'."),
} }
); );
@@ -5,5 +5,5 @@ public enum StickerFormat
Png = 1, Png = 1,
Apng = 2, Apng = 2,
Lottie = 3, Lottie = 3,
Gif = 4 Gif = 4,
} }
@@ -133,25 +133,21 @@ public class DiscordClient(string token)
{ {
throw response.StatusCode switch throw response.StatusCode switch
{ {
HttpStatusCode.Unauthorized HttpStatusCode.Unauthorized => throw new DiscordChatExporterException(
=> throw new DiscordChatExporterException( "Authentication token is invalid.",
"Authentication token is invalid.", true
true ),
),
HttpStatusCode.Forbidden HttpStatusCode.Forbidden => throw new DiscordChatExporterException(
=> throw new DiscordChatExporterException( $"Request to '{url}' failed: forbidden."
$"Request to '{url}' failed: forbidden." ),
),
HttpStatusCode.NotFound HttpStatusCode.NotFound => throw new DiscordChatExporterException(
=> throw new DiscordChatExporterException( $"Request to '{url}' failed: not found."
$"Request to '{url}' failed: not found." ),
),
_ _ => throw new DiscordChatExporterException(
=> throw new DiscordChatExporterException( $"""
$"""
Request to '{url}' failed: {response Request to '{url}' failed: {response
.StatusCode.ToString() .StatusCode.ToString()
.ToSpaceSeparatedWords() .ToSpaceSeparatedWords()
@@ -160,8 +156,8 @@ public class DiscordClient(string token)
cancellationToken cancellationToken
)} )}
""", """,
true true
) ),
}; };
} }
@@ -3,5 +3,5 @@
public enum TokenKind public enum TokenKind
{ {
User, User,
Bot Bot,
} }
@@ -8,7 +8,7 @@ public enum ExportFormat
HtmlDark, HtmlDark,
HtmlLight, HtmlLight,
Csv, Csv,
Json Json,
} }
public static class ExportFormatExtensions public static class ExportFormatExtensions
@@ -21,7 +21,7 @@ public static class ExportFormatExtensions
ExportFormat.HtmlLight => "html", ExportFormat.HtmlLight => "html",
ExportFormat.Csv => "csv", ExportFormat.Csv => "csv",
ExportFormat.Json => "json", ExportFormat.Json => "json",
_ => throw new ArgumentOutOfRangeException(nameof(format)) _ => throw new ArgumentOutOfRangeException(nameof(format)),
}; };
public static string GetDisplayName(this ExportFormat format) => public static string GetDisplayName(this ExportFormat format) =>
@@ -32,6 +32,6 @@ public static class ExportFormatExtensions
ExportFormat.HtmlLight => "HTML (Light)", ExportFormat.HtmlLight => "HTML (Light)",
ExportFormat.Csv => "CSV", ExportFormat.Csv => "CSV",
ExportFormat.Json => "JSON", ExportFormat.Json => "JSON",
_ => throw new ArgumentOutOfRangeException(nameof(format)) _ => throw new ArgumentOutOfRangeException(nameof(format)),
}; };
} }
@@ -172,24 +172,21 @@ public partial class ExportRequest
"%C" => channel.Name, "%C" => channel.Name,
"%p" => channel.Position?.ToString(CultureInfo.InvariantCulture) ?? "0", "%p" => channel.Position?.ToString(CultureInfo.InvariantCulture) ?? "0",
"%P" "%P" => channel.Parent?.Position?.ToString(CultureInfo.InvariantCulture)
=> channel.Parent?.Position?.ToString(CultureInfo.InvariantCulture) ?? "0",
?? "0",
"%a" "%a" => after?.ToDate().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)
=> after?.ToDate().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) ?? "",
?? "", "%b" => before
"%b" ?.ToDate()
=> before?.ToDate().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) .ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) ?? "",
?? "", "%d" => DateTimeOffset.Now.ToString(
"%d" "yyyy-MM-dd",
=> DateTimeOffset.Now.ToString( CultureInfo.InvariantCulture
"yyyy-MM-dd", ),
CultureInfo.InvariantCulture
),
"%%" => "%", "%%" => "%",
_ => m.Value _ => m.Value,
} }
) )
); );
@@ -3,5 +3,5 @@
internal enum BinaryExpressionKind internal enum BinaryExpressionKind
{ {
Or, Or,
And And,
} }
@@ -14,6 +14,6 @@ internal class BinaryExpressionMessageFilter(
{ {
BinaryExpressionKind.Or => first.IsMatch(message) || second.IsMatch(message), BinaryExpressionKind.Or => first.IsMatch(message) || second.IsMatch(message),
BinaryExpressionKind.And => first.IsMatch(message) && second.IsMatch(message), BinaryExpressionKind.And => first.IsMatch(message) && second.IsMatch(message),
_ => throw new InvalidOperationException($"Unknown binary expression kind '{kind}'.") _ => throw new InvalidOperationException($"Unknown binary expression kind '{kind}'."),
}; };
} }
@@ -17,15 +17,13 @@ internal class HasMessageFilter(MessageContentMatchKind kind) : MessageFilter
MessageContentMatchKind.Image => message.Attachments.Any(file => file.IsImage), MessageContentMatchKind.Image => message.Attachments.Any(file => file.IsImage),
MessageContentMatchKind.Sound => message.Attachments.Any(file => file.IsAudio), MessageContentMatchKind.Sound => message.Attachments.Any(file => file.IsAudio),
MessageContentMatchKind.Pin => message.IsPinned, MessageContentMatchKind.Pin => message.IsPinned,
MessageContentMatchKind.Invite MessageContentMatchKind.Invite => MarkdownParser
=> MarkdownParser .ExtractLinks(message.Content)
.ExtractLinks(message.Content) .Select(l => l.Url)
.Select(l => l.Url) .Select(Invite.TryGetCodeFromUrl)
.Select(Invite.TryGetCodeFromUrl) .Any(c => !string.IsNullOrWhiteSpace(c)),
.Any(c => !string.IsNullOrWhiteSpace(c)), _ => throw new InvalidOperationException(
_ $"Unknown message content match kind '{kind}'."
=> throw new InvalidOperationException( ),
$"Unknown message content match kind '{kind}'."
)
}; };
} }
@@ -9,5 +9,5 @@ internal enum MessageContentMatchKind
Image, Image,
Sound, Sound,
Pin, Pin,
Invite Invite,
} }
@@ -125,7 +125,7 @@ internal static class FilterGrammar
op switch op switch
{ {
'|' => new BinaryExpressionMessageFilter(left, right, BinaryExpressionKind.Or), '|' => new BinaryExpressionMessageFilter(left, right, BinaryExpressionKind.Or),
_ => new BinaryExpressionMessageFilter(left, right, BinaryExpressionKind.And) _ => new BinaryExpressionMessageFilter(left, right, BinaryExpressionKind.And),
} }
); );
@@ -34,58 +34,51 @@ internal partial class HtmlMarkdownVisitor(
{ {
var (openingTag, closingTag) = formatting.Kind switch var (openingTag, closingTag) = formatting.Kind switch
{ {
FormattingKind.Bold FormattingKind.Bold => (
=> ( // lang=html
// lang=html "<strong>",
"<strong>", // lang=html
// lang=html "</strong>"
"</strong>" ),
),
FormattingKind.Italic FormattingKind.Italic => (
=> ( // lang=html
// lang=html "<em>",
"<em>", // lang=html
// lang=html "</em>"
"</em>" ),
),
FormattingKind.Underline FormattingKind.Underline => (
=> ( // lang=html
// lang=html "<u>",
"<u>", // lang=html
// lang=html "</u>"
"</u>" ),
),
FormattingKind.Strikethrough FormattingKind.Strikethrough => (
=> ( // lang=html
// lang=html "<s>",
"<s>", // lang=html
// lang=html "</s>"
"</s>" ),
),
FormattingKind.Spoiler FormattingKind.Spoiler => (
=> ( // lang=html
// lang=html """<span class="chatlog__markdown-spoiler chatlog__markdown-spoiler--hidden" onclick="showSpoiler(event, this)">""",
"""<span class="chatlog__markdown-spoiler chatlog__markdown-spoiler--hidden" onclick="showSpoiler(event, this)">""", // lang=html
// lang=html """</span>"""
"""</span>""" ),
),
FormattingKind.Quote FormattingKind.Quote => (
=> ( // lang=html
// lang=html """<div class="chatlog__markdown-quote"><div class="chatlog__markdown-quote-border"></div><div class="chatlog__markdown-quote-content">""",
"""<div class="chatlog__markdown-quote"><div class="chatlog__markdown-quote-border"></div><div class="chatlog__markdown-quote-content">""", // lang=html
// lang=html """</div></div>"""
"""</div></div>""" ),
),
_ _ => throw new InvalidOperationException(
=> throw new InvalidOperationException( $"Unknown formatting kind '{formatting.Kind}'."
$"Unknown formatting kind '{formatting.Kind}'." ),
)
}; };
buffer.Append(openingTag); buffer.Append(openingTag);
@@ -90,7 +90,7 @@ internal class HtmlMessageWriter(Stream stream, ExportContext context, string th
await new MessageGroupTemplate await new MessageGroupTemplate
{ {
Context = Context, Context = Context,
Messages = messages Messages = messages,
}.RenderAsync(cancellationToken) }.RenderAsync(cancellationToken)
) )
); );
@@ -131,7 +131,7 @@ internal class HtmlMessageWriter(Stream stream, ExportContext context, string th
await new PostambleTemplate await new PostambleTemplate
{ {
Context = Context, Context = Context,
MessagesWritten = MessagesWritten MessagesWritten = MessagesWritten,
}.RenderAsync(cancellationToken) }.RenderAsync(cancellationToken)
) )
); );
@@ -25,7 +25,7 @@ internal class JsonMessageWriter(Stream stream, ExportContext context)
Indented = true, Indented = true,
// Validation errors may mask actual failures // Validation errors may mask actual failures
// https://github.com/Tyrrrz/DiscordChatExporter/issues/413 // https://github.com/Tyrrrz/DiscordChatExporter/issues/413
SkipValidation = true SkipValidation = true,
} }
); );
@@ -100,13 +100,15 @@ internal partial class MessageExporter
ExportFormat.PlainText => new PlainTextMessageWriter(File.Create(filePath), context), ExportFormat.PlainText => new PlainTextMessageWriter(File.Create(filePath), context),
ExportFormat.Csv => new CsvMessageWriter(File.Create(filePath), context), ExportFormat.Csv => new CsvMessageWriter(File.Create(filePath), context),
ExportFormat.HtmlDark => new HtmlMessageWriter(File.Create(filePath), context, "Dark"), ExportFormat.HtmlDark => new HtmlMessageWriter(File.Create(filePath), context, "Dark"),
ExportFormat.HtmlLight ExportFormat.HtmlLight => new HtmlMessageWriter(
=> new HtmlMessageWriter(File.Create(filePath), context, "Light"), File.Create(filePath),
context,
"Light"
),
ExportFormat.Json => new JsonMessageWriter(File.Create(filePath), context), ExportFormat.Json => new JsonMessageWriter(File.Create(filePath), context),
_ _ => throw new ArgumentOutOfRangeException(
=> throw new ArgumentOutOfRangeException( nameof(format),
nameof(format), $"Unknown export format '{format}'."
$"Unknown export format '{format}'." ),
)
}; };
} }
@@ -37,7 +37,7 @@ public partial class PartitionLimit
"M" => 1_000_000, "M" => 1_000_000,
"K" => 1_000, "K" => 1_000,
"" => 1, "" => 1,
_ => -1 _ => -1,
}; };
if (magnitude < 0) if (magnitude < 0)
@@ -10,20 +10,18 @@ internal static class PlainTextMessageExtensions
public static string GetFallbackContent(this Message message) => public static string GetFallbackContent(this Message message) =>
message.Kind switch message.Kind switch
{ {
MessageKind.RecipientAdd MessageKind.RecipientAdd => message.MentionedUsers.Any()
=> message.MentionedUsers.Any() ? $"Added {message.MentionedUsers.First().DisplayName} to the group."
? $"Added {message.MentionedUsers.First().DisplayName} to the group." : "Added a recipient.",
: "Added a recipient.",
MessageKind.RecipientRemove MessageKind.RecipientRemove => message.MentionedUsers.Any()
=> message.MentionedUsers.Any() ? message.Author.Id == message.MentionedUsers.First().Id
? message.Author.Id == message.MentionedUsers.First().Id ? "Left the group."
? "Left the group." : $"Removed {message.MentionedUsers.First().DisplayName} from the group."
: $"Removed {message.MentionedUsers.First().DisplayName} from the group." : "Removed a recipient.",
: "Removed a recipient.",
MessageKind.Call MessageKind.Call =>
=> $"Started a call that lasted { $"Started a call that lasted {
message message
.CallEndedTimestamp? .CallEndedTimestamp?
.Pipe(t => t - message.Timestamp) .Pipe(t => t - message.Timestamp)
@@ -31,16 +29,15 @@ internal static class PlainTextMessageExtensions
.ToString("n0", CultureInfo.InvariantCulture) ?? "0" .ToString("n0", CultureInfo.InvariantCulture) ?? "0"
} minutes.", } minutes.",
MessageKind.ChannelNameChange MessageKind.ChannelNameChange => !string.IsNullOrWhiteSpace(message.Content)
=> !string.IsNullOrWhiteSpace(message.Content) ? $"Changed the channel name: {message.Content}"
? $"Changed the channel name: {message.Content}" : "Changed the channel name.",
: "Changed the channel name.",
MessageKind.ChannelIconChange => "Changed the channel icon.", MessageKind.ChannelIconChange => "Changed the channel icon.",
MessageKind.ChannelPinnedMessage => "Pinned a message.", MessageKind.ChannelPinnedMessage => "Pinned a message.",
MessageKind.ThreadCreated => "Started a thread.", MessageKind.ThreadCreated => "Started a thread.",
MessageKind.GuildMemberJoin => "Joined the server.", MessageKind.GuildMemberJoin => "Joined the server.",
_ => message.Content _ => message.Content,
}; };
} }
@@ -7,5 +7,5 @@ internal enum FormattingKind
Underline, Underline,
Strikethrough, Strikethrough,
Spoiler, Spoiler,
Quote Quote,
} }
@@ -6,5 +6,5 @@ internal enum MentionKind
Here, Here,
User, User,
Channel, Channel,
Role Role,
} }
@@ -377,10 +377,9 @@ internal static partial class MarkdownParser
null => null, null => null,
// Unknown format: throw an exception to consider this timestamp invalid // Unknown format: throw an exception to consider this timestamp invalid
// https://github.com/Tyrrrz/DiscordChatExporter/issues/1156 // https://github.com/Tyrrrz/DiscordChatExporter/issues/1156
var f var f => throw new InvalidOperationException(
=> throw new InvalidOperationException( $"Unknown timestamp format '{f}'."
$"Unknown timestamp format '{f}'." ),
)
}; };
return new TimestampNode(instant, format); return new TimestampNode(instant, format);
+2 -2
View File
@@ -39,7 +39,7 @@ public static class Http
ShouldHandle = new PredicateBuilder().Handle<Exception>(IsRetryableException), ShouldHandle = new PredicateBuilder().Handle<Exception>(IsRetryableException),
MaxRetryAttempts = 4, MaxRetryAttempts = 4,
BackoffType = DelayBackoffType.Exponential, BackoffType = DelayBackoffType.Exponential,
Delay = TimeSpan.FromSeconds(1) Delay = TimeSpan.FromSeconds(1),
} }
) )
.Build(); .Build();
@@ -68,7 +68,7 @@ public static class Http
return ValueTask.FromResult<TimeSpan?>( return ValueTask.FromResult<TimeSpan?>(
TimeSpan.FromSeconds(Math.Pow(2, args.AttemptNumber) + 1) TimeSpan.FromSeconds(Math.Pow(2, args.AttemptNumber) + 1)
); );
} },
} }
) )
.Build(); .Build();
+1 -1
View File
@@ -9,7 +9,7 @@ public static class PathEx
{ {
private static readonly HashSet<char> InvalidFileNameChars = private static readonly HashSet<char> InvalidFileNameChars =
[ [
.. Path.GetInvalidFileNameChars() .. Path.GetInvalidFileNameChars(),
]; ];
public static string EscapeFileName(string path) public static string EscapeFileName(string path)
+2 -2
View File
@@ -61,7 +61,7 @@ public class App : Application, IDisposable
{ {
ThemeVariant.Light => Avalonia.Styling.ThemeVariant.Light, ThemeVariant.Light => Avalonia.Styling.ThemeVariant.Light,
ThemeVariant.Dark => Avalonia.Styling.ThemeVariant.Dark, ThemeVariant.Dark => Avalonia.Styling.ThemeVariant.Dark,
_ => Avalonia.Styling.ThemeVariant.Default _ => Avalonia.Styling.ThemeVariant.Default,
}; };
InitializeTheme(); InitializeTheme();
@@ -86,7 +86,7 @@ public class App : Application, IDisposable
{ {
"Light" => PlatformThemeVariant.Light, "Light" => PlatformThemeVariant.Light,
"Dark" => PlatformThemeVariant.Dark, "Dark" => PlatformThemeVariant.Dark,
_ => PlatformSettings?.GetColorValues().ThemeVariant ?? PlatformThemeVariant.Light _ => PlatformSettings?.GetColorValues().ThemeVariant ?? PlatformThemeVariant.Light,
}; };
this.LocateMaterialTheme<MaterialThemeBase>().CurrentTheme = this.LocateMaterialTheme<MaterialThemeBase>().CurrentTheme =
@@ -56,7 +56,7 @@ public class DialogManager : IDisposable
{ {
FileTypeChoices = fileTypes, FileTypeChoices = fileTypes,
SuggestedFileName = defaultFilePath, SuggestedFileName = defaultFilePath,
DefaultExtension = Path.GetExtension(defaultFilePath).TrimStart('.') DefaultExtension = Path.GetExtension(defaultFilePath).TrimStart('.'),
} }
); );
@@ -77,7 +77,7 @@ public class DialogManager : IDisposable
new FolderPickerOpenOptions new FolderPickerOpenOptions
{ {
AllowMultiple = false, AllowMultiple = false,
SuggestedStartLocation = startLocation SuggestedStartLocation = startLocation,
} }
); );
@@ -4,5 +4,5 @@ public enum ThemeVariant
{ {
System, System,
Light, Light,
Dark Dark,
} }
@@ -19,7 +19,7 @@ public partial class ViewManager
ExportSetupViewModel => new ExportSetupView(), ExportSetupViewModel => new ExportSetupView(),
MessageBoxViewModel => new MessageBoxView(), MessageBoxViewModel => new MessageBoxView(),
SettingsViewModel => new SettingsView(), SettingsViewModel => new SettingsView(),
_ => null _ => null,
}; };
public Control? TryBindView(ViewModelBase viewModel) public Control? TryBindView(ViewModelBase viewModel)
@@ -4,5 +4,5 @@ public enum ThreadInclusionMode
{ {
None, None,
Active, Active,
All All,
} }
@@ -253,7 +253,7 @@ public partial class DashboardViewModel : ViewModelBase
channelProgressPairs, channelProgressPairs,
new ParallelOptions new ParallelOptions
{ {
MaxDegreeOfParallelism = Math.Max(1, _settingsService.ParallelLimit) MaxDegreeOfParallelism = Math.Max(1, _settingsService.ParallelLimit),
}, },
async (pair, cancellationToken) => async (pair, cancellationToken) =>
{ {
@@ -138,8 +138,8 @@ public partial class ExportSetupViewModel(
[ [
new FilePickerFileType($"{extension.ToUpperInvariant()} file") new FilePickerFileType($"{extension.ToUpperInvariant()} file")
{ {
Patterns = [$"*.{extension}"] Patterns = [$"*.{extension}"],
} },
], ],
defaultFileName defaultFileName
); );
@@ -85,7 +85,7 @@ public class SettingsViewModel : DialogViewModelBase
"zh-CN", "zh-CN",
"ja-JP", "ja-JP",
"zh-TW", "zh-TW",
"ko-KR" "ko-KR",
]; ];
// This has to be non-nullable because Avalonia ComboBox doesn't allow a null value to be selected // This has to be non-nullable because Avalonia ComboBox doesn't allow a null value to be selected