mirror of
https://github.com/chylex/Discord-History-Tracker.git
synced 2025-04-19 13:15:44 +02:00
Compare commits
5 Commits
38f79dee7d
...
b2276600c7
Author | SHA1 | Date | |
---|---|---|---|
b2276600c7 | |||
40269f591b | |||
dea3b272c0 | |||
e66206b4a8 | |||
780d5ae421 |
@ -3,12 +3,12 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:main="clr-namespace:DHT.Desktop.Main"
|
xmlns:main="clr-namespace:DHT.Desktop.Main"
|
||||||
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="360"
|
mc:Ignorable="d" d:DesignWidth="510" d:DesignHeight="375"
|
||||||
x:Class="DHT.Desktop.Main.AboutWindow"
|
x:Class="DHT.Desktop.Main.AboutWindow"
|
||||||
x:DataType="main:AboutWindowModel"
|
x:DataType="main:AboutWindowModel"
|
||||||
Title="About Discord History Tracker"
|
Title="About Discord History Tracker"
|
||||||
Icon="avares://DiscordHistoryTracker/Resources/icon.ico"
|
Icon="avares://DiscordHistoryTracker/Resources/icon.ico"
|
||||||
Width="480" Height="360" CanResize="False"
|
Width="510" Height="375" CanResize="False"
|
||||||
WindowStartupLocation="CenterOwner">
|
WindowStartupLocation="CenterOwner">
|
||||||
|
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
@ -16,10 +16,6 @@
|
|||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
|
|
||||||
<Window.Styles>
|
<Window.Styles>
|
||||||
<Style Selector="StackPanel">
|
|
||||||
<Setter Property="Orientation" Value="Horizontal" />
|
|
||||||
<Setter Property="Spacing" Value="5" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="TextBlock">
|
<Style Selector="TextBlock">
|
||||||
<Setter Property="TextWrapping" Value="Wrap" />
|
<Setter Property="TextWrapping" Value="Wrap" />
|
||||||
<Setter Property="VerticalAlignment" Value="Center" />
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
@ -33,44 +29,45 @@
|
|||||||
|
|
||||||
<StackPanel Orientation="Vertical" Margin="20" Spacing="12">
|
<StackPanel Orientation="Vertical" Margin="20" Spacing="12">
|
||||||
|
|
||||||
<TextBlock VerticalAlignment="Center">
|
<StackPanel Orientation="Vertical" Spacing="3">
|
||||||
Discord History Tracker was created by chylex and released under the MIT license.
|
<TextBlock TextWrapping="Wrap">Discord History Tracker was created by chylex.</TextBlock>
|
||||||
</TextBlock>
|
<TextBlock>It is available under the MIT license.</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel>
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
<Button Command="{Binding ShowOfficialWebsite}">Official Website</Button>
|
<Button Command="{Binding ShowOfficialWebsite}">Official Website</Button>
|
||||||
<Button Command="{Binding ShowIssueTracker}">Issue Tracker</Button>
|
<Button Command="{Binding ShowIssueTracker}">Issue Tracker</Button>
|
||||||
<Button Command="{Binding ShowSourceCode}">Source Code</Button>
|
<Button Command="{Binding ShowSourceCode}">Source Code</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Grid RowDefinitions="Auto,5,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto" ColumnDefinitions="175,125,*" Margin="0 10 0 0">
|
<Grid RowDefinitions="Auto,5,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto" ColumnDefinitions="*,115,95" Margin="0 10 0 0">
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0" FontWeight="Bold">Third-Party Software</TextBlock>
|
<TextBlock Grid.Row="0" Grid.Column="0" FontWeight="Bold">Third-Party Software</TextBlock>
|
||||||
<TextBlock Grid.Row="0" Grid.Column="1" FontWeight="Bold">License</TextBlock>
|
<TextBlock Grid.Row="0" Grid.Column="1" FontWeight="Bold">License</TextBlock>
|
||||||
<TextBlock Grid.Row="0" Grid.Column="2" FontWeight="Bold">Link</TextBlock>
|
<TextBlock Grid.Row="0" Grid.Column="2" FontWeight="Bold">Link</TextBlock>
|
||||||
|
|
||||||
<TextBlock Grid.Row="2" Grid.Column="0">.NET 8</TextBlock>
|
<TextBlock Grid.Row="2" Grid.Column="0">.NET</TextBlock>
|
||||||
<TextBlock Grid.Row="2" Grid.Column="1">MIT</TextBlock>
|
<TextBlock Grid.Row="2" Grid.Column="1">MIT</TextBlock>
|
||||||
<Button Grid.Row="2" Grid.Column="2" Command="{Binding ShowLibraryNetCore}">GitHub</Button>
|
<Button Grid.Row="2" Grid.Column="2" Command="{Binding ShowLibraryNetCore}">GitHub</Button>
|
||||||
|
|
||||||
<TextBlock Grid.Row="3" Grid.Column="0">Avalonia</TextBlock>
|
<TextBlock Grid.Row="3" Grid.Column="0">Avalonia</TextBlock>
|
||||||
<TextBlock Grid.Row="3" Grid.Column="1">MIT</TextBlock>
|
<TextBlock Grid.Row="3" Grid.Column="1">MIT</TextBlock>
|
||||||
<Button Grid.Row="3" Grid.Column="2" Command="{Binding ShowLibraryAvalonia}">NuGet</Button>
|
<Button Grid.Row="3" Grid.Column="2" Command="{Binding ShowLibraryAvalonia}">GitHub</Button>
|
||||||
|
|
||||||
<TextBlock Grid.Row="4" Grid.Column="0">MVVM Toolkit</TextBlock>
|
<TextBlock Grid.Row="4" Grid.Column="0">Rx.NET</TextBlock>
|
||||||
<TextBlock Grid.Row="4" Grid.Column="1">MIT</TextBlock>
|
<TextBlock Grid.Row="4" Grid.Column="1">MIT</TextBlock>
|
||||||
<Button Grid.Row="4" Grid.Column="2" Command="{Binding ShowLibraryCommunityToolkit}">GitHub</Button>
|
<Button Grid.Row="4" Grid.Column="2" Command="{Binding ShowLibraryRxNet}">GitHub</Button>
|
||||||
|
|
||||||
<TextBlock Grid.Row="5" Grid.Column="0">SQLite</TextBlock>
|
<TextBlock Grid.Row="5" Grid.Column="0">SQLite</TextBlock>
|
||||||
<TextBlock Grid.Row="5" Grid.Column="1">Public Domain</TextBlock>
|
<TextBlock Grid.Row="5" Grid.Column="1">Public Domain</TextBlock>
|
||||||
<Button Grid.Row="5" Grid.Column="2" Command="{Binding ShowLibrarySqlite}">Official Website</Button>
|
<Button Grid.Row="5" Grid.Column="2" Command="{Binding ShowLibrarySqlite}">Website</Button>
|
||||||
|
|
||||||
<TextBlock Grid.Row="6" Grid.Column="0">Microsoft.Data.Sqlite</TextBlock>
|
<TextBlock Grid.Row="6" Grid.Column="0">Microsoft.Data.Sqlite</TextBlock>
|
||||||
<TextBlock Grid.Row="6" Grid.Column="1">Apache-2.0</TextBlock>
|
<TextBlock Grid.Row="6" Grid.Column="1">Apache-2.0</TextBlock>
|
||||||
<Button Grid.Row="6" Grid.Column="2" Command="{Binding ShowLibrarySqliteAdoNet}">NuGet</Button>
|
<Button Grid.Row="6" Grid.Column="2" Command="{Binding ShowLibrarySqliteAdoNet}">NuGet</Button>
|
||||||
|
|
||||||
<TextBlock Grid.Row="7" Grid.Column="0">Rx.NET</TextBlock>
|
<TextBlock Grid.Row="7" Grid.Column="0">PropertyChanged.SourceGenerator</TextBlock>
|
||||||
<TextBlock Grid.Row="7" Grid.Column="1">MIT</TextBlock>
|
<TextBlock Grid.Row="7" Grid.Column="1">MIT</TextBlock>
|
||||||
<Button Grid.Row="7" Grid.Column="2" Command="{Binding ShowLibraryRxNet}">GitHub</Button>
|
<Button Grid.Row="7" Grid.Column="2" Command="{Binding ShowLibraryPropertyChangedSourceGenerator}">GitHub</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -20,11 +20,11 @@ sealed class AboutWindowModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void ShowLibraryAvalonia() {
|
public void ShowLibraryAvalonia() {
|
||||||
SystemUtils.OpenUrl("https://www.nuget.org/packages/Avalonia");
|
SystemUtils.OpenUrl("https://github.com/AvaloniaUI/Avalonia");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowLibraryCommunityToolkit() {
|
public void ShowLibraryPropertyChangedSourceGenerator() {
|
||||||
SystemUtils.OpenUrl("https://github.com/CommunityToolkit/dotnet");
|
SystemUtils.OpenUrl("https://github.com/canton7/PropertyChanged.SourceGenerator");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowLibrarySqlite() {
|
public void ShowLibrarySqlite() {
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<Button Command="{Binding OnClickToggleDownload}" Content="{Binding ToggleDownloadButtonText}" IsEnabled="{Binding IsToggleDownloadButtonEnabled}" />
|
<Button Command="{Binding OnClickToggleDownload}" Content="{Binding ToggleDownloadButtonText}" IsEnabled="{Binding IsToggleDownloadButtonEnabled}" />
|
||||||
<Button Command="{Binding OnClickRetryFailed}" IsEnabled="{Binding IsRetryFailedOnDownloadsButtonEnabled}">Retry Failed</Button>
|
<Button Command="{Binding OnClickRetryFailed}" IsEnabled="{Binding IsRetryFailedOnDownloadsButtonEnabled}">Retry Failed</Button>
|
||||||
<Button Command="{Binding OnClickDeleteOrphaned}">Delete Orphaned</Button>
|
<Button Command="{Binding OnClickDeleteOrphaned}">Delete Orphaned</Button>
|
||||||
<Button Command="{Binding OnClickExportAll}" IsEnabled="{Binding HasSuccessfulDownloads}">Export All</Button>
|
<Button Command="{Binding OnClickExportAll}" IsEnabled="{Binding HasSuccessfulDownloads}">Export All...</Button>
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
<StackPanel Orientation="Vertical" Spacing="20" Margin="0 10 0 0">
|
<StackPanel Orientation="Vertical" Spacing="20" Margin="0 10 0 0">
|
||||||
<controls:DownloadItemFilterPanel DataContext="{Binding FilterModel}" IsEnabled="{Binding !$parent[UserControl].((pages:DownloadsPageModel)DataContext).IsDownloading}" />
|
<controls:DownloadItemFilterPanel DataContext="{Binding FilterModel}" IsEnabled="{Binding !$parent[UserControl].((pages:DownloadsPageModel)DataContext).IsDownloading}" />
|
||||||
|
@ -21,12 +21,13 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
|
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
|
||||||
<PublishTrimmed>true</PublishTrimmed>
|
<PublishTrimmed>true</PublishTrimmed>
|
||||||
<TrimMode>partial</TrimMode>
|
<TrimMode>full</TrimMode>
|
||||||
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
|
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
|
||||||
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
|
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
|
||||||
<EventSourceSupport>false</EventSourceSupport>
|
<EventSourceSupport>false</EventSourceSupport>
|
||||||
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
|
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
|
||||||
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
|
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
|
||||||
|
<XmlResolverIsNetworkingEnabledByDefault>false</XmlResolverIsNetworkingEnabledByDefault>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Buffers.Text;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace DHT.Server.Database.Export;
|
namespace DHT.Server.Database.Export;
|
||||||
|
|
||||||
sealed class SnowflakeJsonSerializer : JsonConverter<Snowflake> {
|
sealed class SnowflakeJsonSerializer : JsonConverter<Snowflake> {
|
||||||
|
private const int MaxUlongStringLength = 20;
|
||||||
|
|
||||||
public override Snowflake Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
public override Snowflake Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
||||||
return new Snowflake(ulong.Parse(reader.GetString()!));
|
return new Snowflake(ulong.Parse(reader.GetString()!));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(Utf8JsonWriter writer, Snowflake value, JsonSerializerOptions options) {
|
public override void Write(Utf8JsonWriter writer, Snowflake value, JsonSerializerOptions options) {
|
||||||
writer.WriteStringValue(value.Id.ToString());
|
writer.WriteStringValue(Format(value, stackalloc byte[MaxUlongStringLength]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Snowflake ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
public override Snowflake ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
||||||
@ -18,6 +22,14 @@ sealed class SnowflakeJsonSerializer : JsonConverter<Snowflake> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteAsPropertyName(Utf8JsonWriter writer, Snowflake value, JsonSerializerOptions options) {
|
public override void WriteAsPropertyName(Utf8JsonWriter writer, Snowflake value, JsonSerializerOptions options) {
|
||||||
writer.WritePropertyName(value.Id.ToString());
|
writer.WritePropertyName(Format(value, stackalloc byte[MaxUlongStringLength]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReadOnlySpan<byte> Format(Snowflake value, Span<byte> destination) {
|
||||||
|
if (!Utf8Formatter.TryFormat(value.Id, destination, out int bytesWritten)) {
|
||||||
|
Debug.Fail("Failed to format Snowflake value.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return destination[..bytesWritten];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ static class ViewerJson {
|
|||||||
public required string Name { get; init; }
|
public required string Name { get; init; }
|
||||||
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public string? Parent { get; init; }
|
public Snowflake? Parent { get; init; }
|
||||||
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public int? Position { get; init; }
|
public int? Position { get; init; }
|
||||||
@ -55,7 +55,7 @@ static class ViewerJson {
|
|||||||
public long? Te { get; init; }
|
public long? Te { get; init; }
|
||||||
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public string? R { get; init; }
|
public Snowflake? R { get; init; }
|
||||||
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public JsonMessageAttachment[]? A { get; init; }
|
public JsonMessageAttachment[]? A { get; init; }
|
||||||
@ -80,7 +80,7 @@ static class ViewerJson {
|
|||||||
|
|
||||||
public sealed class JsonMessageReaction {
|
public sealed class JsonMessageReaction {
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public string? Id { get; init; }
|
public Snowflake? Id { get; init; }
|
||||||
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public string? N { get; init; }
|
public string? N { get; init; }
|
||||||
|
@ -2,13 +2,15 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DHT.Server.Data;
|
using DHT.Server.Data;
|
||||||
using DHT.Server.Data.Filters;
|
using DHT.Server.Data.Filters;
|
||||||
using DHT.Utils.Logging;
|
using DHT.Utils.Logging;
|
||||||
|
using Channel = System.Threading.Channels.Channel;
|
||||||
|
using DiscordChannel = DHT.Server.Data.Channel;
|
||||||
|
|
||||||
namespace DHT.Server.Database.Export;
|
namespace DHT.Server.Database.Export;
|
||||||
|
|
||||||
@ -18,12 +20,12 @@ static class ViewerJsonExport {
|
|||||||
public static async Task GetMetadata(Stream stream, IDatabaseFile db, MessageFilter? filter = null, CancellationToken cancellationToken = default) {
|
public static async Task GetMetadata(Stream stream, IDatabaseFile db, MessageFilter? filter = null, CancellationToken cancellationToken = default) {
|
||||||
Perf perf = Log.Start();
|
Perf perf = Log.Start();
|
||||||
|
|
||||||
var includedChannels = new List<Channel>();
|
var includedChannels = new List<DiscordChannel>();
|
||||||
var includedServerIds = new HashSet<ulong>();
|
var includedServerIds = new HashSet<ulong>();
|
||||||
|
|
||||||
HashSet<ulong>? channelIdFilter = filter?.ChannelIds;
|
HashSet<ulong>? channelIdFilter = filter?.ChannelIds;
|
||||||
|
|
||||||
await foreach (Channel channel in db.Channels.Get(cancellationToken)) {
|
await foreach (DiscordChannel channel in db.Channels.Get(cancellationToken)) {
|
||||||
if (channelIdFilter == null || channelIdFilter.Contains(channel.Id)) {
|
if (channelIdFilter == null || channelIdFilter.Contains(channel.Id)) {
|
||||||
includedChannels.Add(channel);
|
includedChannels.Add(channel);
|
||||||
includedServerIds.Add(channel.Server);
|
includedServerIds.Add(channel.Server);
|
||||||
@ -53,11 +55,30 @@ static class ViewerJsonExport {
|
|||||||
|
|
||||||
ReadOnlyMemory<byte> newLine = "\n"u8.ToArray();
|
ReadOnlyMemory<byte> newLine = "\n"u8.ToArray();
|
||||||
|
|
||||||
await foreach (ViewerJson.JsonMessage message in GenerateMessageList(db, filter, cancellationToken)) {
|
Channel<Message> channel = Channel.CreateBounded<Message>(new BoundedChannelOptions(32) {
|
||||||
await JsonSerializer.SerializeAsync(stream, message, ViewerJsonMessageContext.Default.JsonMessage, cancellationToken);
|
SingleWriter = true,
|
||||||
|
SingleReader = true,
|
||||||
|
AllowSynchronousContinuations = true,
|
||||||
|
FullMode = BoundedChannelFullMode.Wait,
|
||||||
|
});
|
||||||
|
|
||||||
|
Task writerTask = Task.Run(async () => {
|
||||||
|
try {
|
||||||
|
await foreach (Message message in db.Messages.Get(filter, cancellationToken)) {
|
||||||
|
await channel.Writer.WriteAsync(message, cancellationToken);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
channel.Writer.Complete();
|
||||||
|
}
|
||||||
|
}, cancellationToken);
|
||||||
|
|
||||||
|
await foreach (Message message in channel.Reader.ReadAllAsync(cancellationToken)) {
|
||||||
|
await JsonSerializer.SerializeAsync(stream, ToJsonMessage(message), ViewerJsonMessageContext.Default.JsonMessage, cancellationToken);
|
||||||
await stream.WriteAsync(newLine, cancellationToken);
|
await stream.WriteAsync(newLine, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await writerTask;
|
||||||
|
|
||||||
perf.Step("Generate and serialize messages to JSON");
|
perf.Step("Generate and serialize messages to JSON");
|
||||||
perf.End();
|
perf.End();
|
||||||
}
|
}
|
||||||
@ -93,14 +114,14 @@ static class ViewerJsonExport {
|
|||||||
return servers;
|
return servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<Snowflake, ViewerJson.JsonChannel> GenerateChannelList(List<Channel> includedChannels) {
|
private static Dictionary<Snowflake, ViewerJson.JsonChannel> GenerateChannelList(List<DiscordChannel> includedChannels) {
|
||||||
var channels = new Dictionary<Snowflake, ViewerJson.JsonChannel>();
|
var channels = new Dictionary<Snowflake, ViewerJson.JsonChannel>();
|
||||||
|
|
||||||
foreach (Channel channel in includedChannels) {
|
foreach (DiscordChannel channel in includedChannels) {
|
||||||
channels[channel.Id] = new ViewerJson.JsonChannel {
|
channels[channel.Id] = new ViewerJson.JsonChannel {
|
||||||
Server = channel.Server,
|
Server = channel.Server,
|
||||||
Name = channel.Name,
|
Name = channel.Name,
|
||||||
Parent = channel.ParentId?.ToString(),
|
Parent = channel.ParentId,
|
||||||
Position = channel.Position,
|
Position = channel.Position,
|
||||||
Topic = channel.Topic,
|
Topic = channel.Topic,
|
||||||
Nsfw = channel.Nsfw,
|
Nsfw = channel.Nsfw,
|
||||||
@ -110,40 +131,38 @@ static class ViewerJsonExport {
|
|||||||
return channels;
|
return channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async IAsyncEnumerable<ViewerJson.JsonMessage> GenerateMessageList(IDatabaseFile db, MessageFilter? filter, [EnumeratorCancellation] CancellationToken cancellationToken) {
|
private static ViewerJson.JsonMessage ToJsonMessage(Message message) {
|
||||||
await foreach (Message message in db.Messages.Get(filter, cancellationToken)) {
|
return new ViewerJson.JsonMessage {
|
||||||
yield return new ViewerJson.JsonMessage {
|
Id = message.Id,
|
||||||
Id = message.Id,
|
C = message.Channel,
|
||||||
C = message.Channel,
|
U = message.Sender,
|
||||||
U = message.Sender,
|
T = message.Timestamp,
|
||||||
T = message.Timestamp,
|
M = string.IsNullOrEmpty(message.Text) ? null : message.Text,
|
||||||
M = string.IsNullOrEmpty(message.Text) ? null : message.Text,
|
Te = message.EditTimestamp,
|
||||||
Te = message.EditTimestamp,
|
R = message.RepliedToId,
|
||||||
R = message.RepliedToId?.ToString(),
|
|
||||||
|
A = message.Attachments.IsEmpty ? null : message.Attachments.Select(static attachment => {
|
||||||
|
var a = new ViewerJson.JsonMessageAttachment {
|
||||||
|
Url = attachment.DownloadUrl,
|
||||||
|
Name = Uri.TryCreate(attachment.NormalizedUrl, UriKind.Absolute, out Uri? uri) ? Path.GetFileName(uri.LocalPath) : attachment.NormalizedUrl,
|
||||||
|
};
|
||||||
|
|
||||||
A = message.Attachments.IsEmpty ? null : message.Attachments.Select(static attachment => {
|
if (attachment is { Width: not null, Height: not null }) {
|
||||||
var a = new ViewerJson.JsonMessageAttachment {
|
a.Width = attachment.Width;
|
||||||
Url = attachment.DownloadUrl,
|
a.Height = attachment.Height;
|
||||||
Name = Uri.TryCreate(attachment.NormalizedUrl, UriKind.Absolute, out Uri? uri) ? Path.GetFileName(uri.LocalPath) : attachment.NormalizedUrl,
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if (attachment is { Width: not null, Height: not null }) {
|
|
||||||
a.Width = attachment.Width;
|
|
||||||
a.Height = attachment.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
}).ToArray(),
|
|
||||||
|
|
||||||
E = message.Embeds.IsEmpty ? null : message.Embeds.Select(static embed => embed.Json).ToArray(),
|
return a;
|
||||||
|
}).ToArray(),
|
||||||
Re = message.Reactions.IsEmpty ? null : message.Reactions.Select(static reaction => new ViewerJson.JsonMessageReaction {
|
|
||||||
Id = reaction.EmojiId?.ToString(),
|
E = message.Embeds.IsEmpty ? null : message.Embeds.Select(static embed => embed.Json).ToArray(),
|
||||||
N = reaction.EmojiName,
|
|
||||||
A = reaction.EmojiFlags.HasFlag(EmojiFlags.Animated),
|
Re = message.Reactions.IsEmpty ? null : message.Reactions.Select(static reaction => new ViewerJson.JsonMessageReaction {
|
||||||
C = reaction.Count,
|
Id = reaction.EmojiId,
|
||||||
}).ToArray(),
|
N = reaction.EmojiName,
|
||||||
};
|
A = reaction.EmojiFlags.HasFlag(EmojiFlags.Animated),
|
||||||
}
|
C = reaction.Count,
|
||||||
|
}).ToArray(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,5 @@ using DHT.Utils;
|
|||||||
namespace DHT.Utils;
|
namespace DHT.Utils;
|
||||||
|
|
||||||
static class Version {
|
static class Version {
|
||||||
public const string Tag = "45.0.0.0";
|
public const string Tag = "46.0.0.0";
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user