Migrate to Avalonia (#1220)

This commit is contained in:
Oleksii Holub
2024-04-27 04:17:46 +03:00
committed by GitHub
parent 74f99b4e59
commit b9c1c47474
89 changed files with 2467 additions and 2810 deletions

View File

@@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Linq;
namespace DiscordChatExporter.Core.Discord.Data;
public record ChannelNode(Channel Channel, IReadOnlyList<ChannelNode> Children)
{
public static IReadOnlyList<ChannelNode> BuildTree(IReadOnlyList<Channel> channels)
{
IReadOnlyList<ChannelNode> GetChildren(Channel parent) =>
channels
.Where(c => c.Parent?.Id == parent.Id)
.Select(c => new ChannelNode(c, GetChildren(c)))
.ToArray();
return channels
.Where(c => c.Parent is null)
.Select(c => new ChannelNode(c, GetChildren(c)))
.ToArray();
}
}

View File

@@ -83,16 +83,15 @@ public partial record Message
// Find embeds with the same URL that only contain a single image and nothing else
var trailingEmbeds = embeds
.Skip(i + 1)
.TakeWhile(
e =>
e.Url == embed.Url
&& e.Timestamp is null
&& e.Author is null
&& e.Color is null
&& string.IsNullOrWhiteSpace(e.Description)
&& !e.Fields.Any()
&& e.Images.Count == 1
&& e.Footer is null
.TakeWhile(e =>
e.Url == embed.Url
&& e.Timestamp is null
&& e.Author is null
&& e.Color is null
&& string.IsNullOrWhiteSpace(e.Description)
&& !e.Fields.Any()
&& e.Images.Count == 1
&& e.Footer is null
)
.ToArray();

View File

@@ -66,12 +66,12 @@ public class DiscordClient(string token)
if (remainingRequestCount <= 0 && resetAfterDelay is not null)
{
var delay =
// Adding a small buffer to the reset time reduces the chance of getting
// rate limited again, because it allows for more requests to be released.
(resetAfterDelay.Value + TimeSpan.FromSeconds(1))
// Sometimes Discord returns an absurdly high value for the reset time, which
// is not actually enforced by the server. So we cap it at a reasonable value.
.Clamp(TimeSpan.Zero, TimeSpan.FromSeconds(60));
// Adding a small buffer to the reset time reduces the chance of getting
// rate limited again, because it allows for more requests to be released.
(resetAfterDelay.Value + TimeSpan.FromSeconds(1))
// Sometimes Discord returns an absurdly high value for the reset time, which
// is not actually enforced by the server. So we cap it at a reasonable value.
.Clamp(TimeSpan.Zero, TimeSpan.FromSeconds(60));
await Task.Delay(delay, innerCancellationToken);
}
@@ -152,8 +152,13 @@ public class DiscordClient(string token)
_
=> throw new DiscordChatExporterException(
$"""
Request to '{url}' failed: {response.StatusCode.ToString().ToSpaceSeparatedWords().ToLowerInvariant()}.
Response content: {await response.Content.ReadAsStringAsync(cancellationToken)}
Request to '{url}' failed: {response
.StatusCode.ToString()
.ToSpaceSeparatedWords()
.ToLowerInvariant()}.
Response content: {await response.Content.ReadAsStringAsync(
cancellationToken
)}
""",
true
)

View File

@@ -2,14 +2,14 @@
<ItemGroup>
<PackageReference Include="AsyncKeyedLock" Version="6.3.4" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.7" PrivateAssets="all" />
<PackageReference Include="CSharpier.MsBuild" Version="0.28.0" PrivateAssets="all" />
<PackageReference Include="Gress" Version="2.1.1" />
<PackageReference Include="JsonExtensions" Version="1.2.0" />
<PackageReference Include="Polly" Version="8.2.0" />
<PackageReference Include="RazorBlade" Version="0.5.0" />
<PackageReference Include="Polly" Version="8.3.1" />
<PackageReference Include="RazorBlade" Version="0.6.0" />
<PackageReference Include="Superpower" Version="3.0.0" />
<PackageReference Include="WebMarkupMin.Core" Version="2.14.0" />
<PackageReference Include="YoutubeExplode" Version="6.3.10" />
<PackageReference Include="WebMarkupMin.Core" Version="2.16.0" />
<PackageReference Include="YoutubeExplode" Version="6.3.13" />
</ItemGroup>
</Project>
</Project>

View File

@@ -58,16 +58,15 @@ internal partial class ExportAssetDownloader(string workingDirPath, bool reuse)
{
var lastModified = response
.Content.Headers.TryGetValue("Last-Modified")
?.Pipe(
s =>
DateTimeOffset.TryParse(
s,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out var instant
)
? instant
: (DateTimeOffset?)null
?.Pipe(s =>
DateTimeOffset.TryParse(
s,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out var instant
)
? instant
: (DateTimeOffset?)null
);
if (lastModified is not null)

View File

@@ -93,8 +93,7 @@ internal class ExportContext(DiscordClient discord, ExportRequest request)
public IReadOnlyList<Role> GetUserRoles(Snowflake id) =>
TryGetMember(id)
?.RoleIds
.Select(TryGetRole)
?.RoleIds.Select(TryGetRole)
.WhereNotNull()
.OrderByDescending(r => r.Position)
.ToArray() ?? [];

View File

@@ -22,12 +22,11 @@ internal class ContainsMessageFilter(string text) : MessageFilter
public override bool IsMatch(Message message) =>
IsMatch(message.Content)
|| message.Embeds.Any(
e =>
IsMatch(e.Title)
|| IsMatch(e.Author?.Name)
|| IsMatch(e.Description)
|| IsMatch(e.Footer?.Text)
|| e.Fields.Any(f => IsMatch(f.Name) || IsMatch(f.Value))
|| message.Embeds.Any(e =>
IsMatch(e.Title)
|| IsMatch(e.Author?.Name)
|| IsMatch(e.Description)
|| IsMatch(e.Footer?.Text)
|| e.Fields.Any(f => IsMatch(f.Name) || IsMatch(f.Value))
);
}

View File

@@ -7,11 +7,10 @@ namespace DiscordChatExporter.Core.Exporting.Filtering;
internal class MentionsMessageFilter(string value) : MessageFilter
{
public override bool IsMatch(Message message) =>
message.MentionedUsers.Any(
user =>
string.Equals(value, user.Name, StringComparison.OrdinalIgnoreCase)
|| string.Equals(value, user.DisplayName, StringComparison.OrdinalIgnoreCase)
|| string.Equals(value, user.FullName, StringComparison.OrdinalIgnoreCase)
|| string.Equals(value, user.Id.ToString(), StringComparison.OrdinalIgnoreCase)
message.MentionedUsers.Any(user =>
string.Equals(value, user.Name, StringComparison.OrdinalIgnoreCase)
|| string.Equals(value, user.DisplayName, StringComparison.OrdinalIgnoreCase)
|| string.Equals(value, user.FullName, StringComparison.OrdinalIgnoreCase)
|| string.Equals(value, user.Id.ToString(), StringComparison.OrdinalIgnoreCase)
);
}

View File

@@ -30,8 +30,8 @@ internal static class FilterGrammar
.OneOf(QuotedString, UnquotedString)
.Named("text string");
private static readonly TextParser<MessageFilter> ContainsFilter = String.Select(
v => (MessageFilter)new ContainsMessageFilter(v)
private static readonly TextParser<MessageFilter> ContainsFilter = String.Select(v =>
(MessageFilter)new ContainsMessageFilter(v)
);
private static readonly TextParser<MessageFilter> FromFilter = Span.EqualToIgnoreCase("from:")

View File

@@ -7,10 +7,9 @@ namespace DiscordChatExporter.Core.Exporting.Filtering;
internal class ReactionMessageFilter(string value) : MessageFilter
{
public override bool IsMatch(Message message) =>
message.Reactions.Any(
r =>
string.Equals(value, r.Emoji.Id?.ToString(), StringComparison.OrdinalIgnoreCase)
|| string.Equals(value, r.Emoji.Name, StringComparison.OrdinalIgnoreCase)
|| string.Equals(value, r.Emoji.Code, StringComparison.OrdinalIgnoreCase)
message.Reactions.Any(r =>
string.Equals(value, r.Emoji.Id?.ToString(), StringComparison.OrdinalIgnoreCase)
|| string.Equals(value, r.Emoji.Name, StringComparison.OrdinalIgnoreCase)
|| string.Equals(value, r.Emoji.Code, StringComparison.OrdinalIgnoreCase)
);
}

View File

@@ -155,7 +155,9 @@ internal partial class HtmlMarkdownVisitor(
buffer.Append(
// lang=html
$"""
<code class="chatlog__markdown-pre chatlog__markdown-pre--inline">{HtmlEncode(inlineCodeBlock.Code)}</code>
<code class="chatlog__markdown-pre chatlog__markdown-pre--inline">{HtmlEncode(
inlineCodeBlock.Code
)}</code>
"""
);
@@ -174,7 +176,9 @@ internal partial class HtmlMarkdownVisitor(
buffer.Append(
// lang=html
$"""
<code class="chatlog__markdown-pre chatlog__markdown-pre--multiline {highlightClass}">{HtmlEncode(multiLineCodeBlock.Code)}</code>
<code class="chatlog__markdown-pre chatlog__markdown-pre--multiline {highlightClass}">{HtmlEncode(
multiLineCodeBlock.Code
)}</code>
"""
);
@@ -267,7 +271,9 @@ internal partial class HtmlMarkdownVisitor(
buffer.Append(
// lang=html
$"""
<span class="chatlog__markdown-mention" title="{HtmlEncode(fullName)}">@{HtmlEncode(displayName)}</span>
<span class="chatlog__markdown-mention" title="{HtmlEncode(fullName)}">@{HtmlEncode(
displayName
)}</span>
"""
);
}
@@ -292,8 +298,12 @@ internal partial class HtmlMarkdownVisitor(
var style = color is not null
? $"""
color: rgb({color.Value.R}, {color.Value.G}, {color.Value.B}); background-color: rgba({color.Value.R}, {color.Value.G}, {color.Value.B}, 0.1);
"""
color: rgb({color.Value.R}, {color.Value.G}, {color
.Value
.B}); background-color: rgba({color.Value.R}, {color.Value.G}, {color
.Value
.B}, 0.1);
"""
: null;
buffer.Append(
@@ -321,7 +331,9 @@ internal partial class HtmlMarkdownVisitor(
buffer.Append(
// lang=html
$"""
<span class="chatlog__markdown-timestamp" title="{HtmlEncode(formattedLong)}">{HtmlEncode(formatted)}</span>
<span class="chatlog__markdown-timestamp" title="{HtmlEncode(
formattedLong
)}">{HtmlEncode(formatted)}</span>
"""
);
@@ -344,10 +356,8 @@ internal partial class HtmlMarkdownVisitor
var isJumbo =
isJumboAllowed
&& nodes.All(
n =>
n is EmojiNode
|| n is TextNode textNode && string.IsNullOrWhiteSpace(textNode.Text)
&& nodes.All(n =>
n is EmojiNode || n is TextNode textNode && string.IsNullOrWhiteSpace(textNode.Text)
);
var buffer = new StringBuilder();

View File

@@ -25,11 +25,10 @@ public static class Http
private static bool IsRetryableException(Exception exception) =>
exception
.GetSelfAndChildren()
.Any(
ex =>
ex is TimeoutException or SocketException or AuthenticationException
|| ex is HttpRequestException hrex
&& IsRetryableStatusCode(hrex.StatusCode ?? HttpStatusCode.OK)
.Any(ex =>
ex is TimeoutException or SocketException or AuthenticationException
|| ex is HttpRequestException hrex
&& IsRetryableStatusCode(hrex.StatusCode ?? HttpStatusCode.OK)
);
public static ResiliencePipeline ResiliencePipeline { get; } =