diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 29bb6bf..c3a0dc9 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "xamlstyler.console": { - "version": "3.2003.9", + "version": "3.2008.4", "commands": [ "xstyler" ] diff --git a/DiscordChatExporter.Core/Discord/Data/Attachment.cs b/DiscordChatExporter.Core/Discord/Data/Attachment.cs index 74a70f7..2b52cc6 100644 --- a/DiscordChatExporter.Core/Discord/Data/Attachment.cs +++ b/DiscordChatExporter.Core/Discord/Data/Attachment.cs @@ -58,11 +58,11 @@ namespace DiscordChatExporter.Core.Discord.Data { public static Attachment Parse(JsonElement json) { - var id = json.GetProperty("id").GetString().Pipe(Snowflake.Parse); - var url = json.GetProperty("url").GetString(); + var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); + var url = json.GetProperty("url").GetNonWhiteSpaceString(); var width = json.GetPropertyOrNull("width")?.GetInt32(); var height = json.GetPropertyOrNull("height")?.GetInt32(); - var fileName = json.GetProperty("filename").GetString(); + var fileName = json.GetProperty("filename").GetNonWhiteSpaceString(); var fileSize = json.GetProperty("size").GetInt64().Pipe(FileSize.FromBytes); return new Attachment(id, url, fileName, width, height, fileSize); diff --git a/DiscordChatExporter.Core/Discord/Data/Channel.cs b/DiscordChatExporter.Core/Discord/Data/Channel.cs index 5978df2..a6288c3 100644 --- a/DiscordChatExporter.Core/Discord/Data/Channel.cs +++ b/DiscordChatExporter.Core/Discord/Data/Channel.cs @@ -74,14 +74,14 @@ namespace DiscordChatExporter.Core.Discord.Data public static Channel Parse(JsonElement json, ChannelCategory? category = null, int? position = null) { - var id = json.GetProperty("id").GetString().Pipe(Snowflake.Parse); - var guildId = json.GetPropertyOrNull("guild_id")?.GetString().Pipe(Snowflake.Parse); - var topic = json.GetPropertyOrNull("topic")?.GetString(); + var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); + var guildId = json.GetPropertyOrNull("guild_id")?.GetNonWhiteSpaceString().Pipe(Snowflake.Parse); + var topic = json.GetPropertyOrNull("topic")?.GetStringOrNull(); var kind = (ChannelKind) json.GetProperty("type").GetInt32(); var name = // Guild channel - json.GetPropertyOrNull("name")?.GetString() ?? + json.GetPropertyOrNull("name")?.GetStringOrNull() ?? // DM channel json.GetPropertyOrNull("recipients")?.EnumerateArray().Select(User.Parse).Select(u => u.Name).JoinToString(", ") ?? // Fallback diff --git a/DiscordChatExporter.Core/Discord/Data/ChannelCategory.cs b/DiscordChatExporter.Core/Discord/Data/ChannelCategory.cs index 159adc2..df1b08a 100644 --- a/DiscordChatExporter.Core/Discord/Data/ChannelCategory.cs +++ b/DiscordChatExporter.Core/Discord/Data/ChannelCategory.cs @@ -31,10 +31,10 @@ namespace DiscordChatExporter.Core.Discord.Data public static ChannelCategory Parse(JsonElement json, int? position = null) { - var id = json.GetProperty("id").GetString().Pipe(Snowflake.Parse); + var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); var name = - json.GetPropertyOrNull("name")?.GetString() ?? + json.GetPropertyOrNull("name")?.GetStringOrNull() ?? id.ToString(); return new ChannelCategory( diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs index 510d5c5..38189cb 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs @@ -70,11 +70,11 @@ namespace DiscordChatExporter.Core.Discord.Data.Embeds { public static Embed Parse(JsonElement json) { - var title = json.GetPropertyOrNull("title")?.GetString(); - var url = json.GetPropertyOrNull("url")?.GetString(); + var title = json.GetPropertyOrNull("title")?.GetStringOrNull(); + var url = json.GetPropertyOrNull("url")?.GetStringOrNull(); var timestamp = json.GetPropertyOrNull("timestamp")?.GetDateTimeOffset(); var color = json.GetPropertyOrNull("color")?.GetInt32().Pipe(System.Drawing.Color.FromArgb).ResetAlpha(); - var description = json.GetPropertyOrNull("description")?.GetString(); + var description = json.GetPropertyOrNull("description")?.GetStringOrNull(); var author = json.GetPropertyOrNull("author")?.Pipe(EmbedAuthor.Parse); var thumbnail = json.GetPropertyOrNull("thumbnail")?.Pipe(EmbedImage.Parse); diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs index c420a99..75f192c 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs @@ -31,10 +31,10 @@ namespace DiscordChatExporter.Core.Discord.Data.Embeds { public static EmbedAuthor Parse(JsonElement json) { - var name = json.GetPropertyOrNull("name")?.GetString(); - var url = json.GetPropertyOrNull("url")?.GetString(); - var iconUrl = json.GetPropertyOrNull("icon_url")?.GetString(); - var iconProxyUrl = json.GetPropertyOrNull("proxy_icon_url")?.GetString(); + var name = json.GetPropertyOrNull("name")?.GetStringOrNull(); + var url = json.GetPropertyOrNull("url")?.GetStringOrNull(); + var iconUrl = json.GetPropertyOrNull("icon_url")?.GetStringOrNull(); + var iconProxyUrl = json.GetPropertyOrNull("proxy_icon_url")?.GetStringOrNull(); return new EmbedAuthor(name, url, iconUrl, iconProxyUrl); } diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedField.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedField.cs index 1e21c64..acfe240 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedField.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedField.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; +using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; namespace DiscordChatExporter.Core.Discord.Data.Embeds @@ -28,8 +29,8 @@ namespace DiscordChatExporter.Core.Discord.Data.Embeds { public static EmbedField Parse(JsonElement json) { - var name = json.GetProperty("name").GetString(); - var value = json.GetProperty("value").GetString(); + var name = json.GetProperty("name").GetNonWhiteSpaceString(); + var value = json.GetProperty("value").GetNonWhiteSpaceString(); var isInline = json.GetPropertyOrNull("inline")?.GetBoolean() ?? false; return new EmbedField(name, value, isInline); diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedFooter.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedFooter.cs index 931f15e..5b2343d 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedFooter.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedFooter.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; +using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; namespace DiscordChatExporter.Core.Discord.Data.Embeds @@ -28,9 +29,9 @@ namespace DiscordChatExporter.Core.Discord.Data.Embeds { public static EmbedFooter Parse(JsonElement json) { - var text = json.GetProperty("text").GetString(); - var iconUrl = json.GetPropertyOrNull("icon_url")?.GetString(); - var iconProxyUrl = json.GetPropertyOrNull("proxy_icon_url")?.GetString(); + var text = json.GetProperty("text").GetNonWhiteSpaceString(); + var iconUrl = json.GetPropertyOrNull("icon_url")?.GetStringOrNull(); + var iconProxyUrl = json.GetPropertyOrNull("proxy_icon_url")?.GetStringOrNull(); return new EmbedFooter(text, iconUrl, iconProxyUrl); } diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedImage.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedImage.cs index 6f0569c..b1ebcff 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedImage.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedImage.cs @@ -27,8 +27,8 @@ namespace DiscordChatExporter.Core.Discord.Data.Embeds { public static EmbedImage Parse(JsonElement json) { - var url = json.GetPropertyOrNull("url")?.GetString(); - var proxyUrl = json.GetPropertyOrNull("proxy_url")?.GetString(); + var url = json.GetPropertyOrNull("url")?.GetStringOrNull(); + var proxyUrl = json.GetPropertyOrNull("proxy_url")?.GetStringOrNull(); var width = json.GetPropertyOrNull("width")?.GetInt32(); var height = json.GetPropertyOrNull("height")?.GetInt32(); diff --git a/DiscordChatExporter.Core/Discord/Data/Emoji.cs b/DiscordChatExporter.Core/Discord/Data/Emoji.cs index e42da43..15eaf4f 100644 --- a/DiscordChatExporter.Core/Discord/Data/Emoji.cs +++ b/DiscordChatExporter.Core/Discord/Data/Emoji.cs @@ -64,8 +64,8 @@ namespace DiscordChatExporter.Core.Discord.Data public static Emoji Parse(JsonElement json) { - var id = json.GetPropertyOrNull("id")?.GetString(); - var name = json.GetProperty("name").GetString(); + var id = json.GetPropertyOrNull("id")?.GetNonWhiteSpaceString(); + var name = json.GetProperty("name").GetNonWhiteSpaceString(); var isAnimated = json.GetPropertyOrNull("animated")?.GetBoolean() ?? false; var imageUrl = GetImageUrl(id, name, isAnimated); diff --git a/DiscordChatExporter.Core/Discord/Data/Guild.cs b/DiscordChatExporter.Core/Discord/Data/Guild.cs index 90538b7..840e8f3 100644 --- a/DiscordChatExporter.Core/Discord/Data/Guild.cs +++ b/DiscordChatExporter.Core/Discord/Data/Guild.cs @@ -2,6 +2,7 @@ using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; using DiscordChatExporter.Core.Utils.Extensions; +using JsonExtensions.Reading; namespace DiscordChatExporter.Core.Discord.Data { @@ -41,9 +42,9 @@ namespace DiscordChatExporter.Core.Discord.Data public static Guild Parse(JsonElement json) { - var id = json.GetProperty("id").GetString().Pipe(Snowflake.Parse); - var name = json.GetProperty("name").GetString(); - var iconHash = json.GetProperty("icon").GetString(); + var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); + var name = json.GetProperty("name").GetNonWhiteSpaceString(); + var iconHash = json.GetPropertyOrNull("icon")?.GetStringOrNull(); var iconUrl = !string.IsNullOrWhiteSpace(iconHash) ? GetIconUrl(id, iconHash) diff --git a/DiscordChatExporter.Core/Discord/Data/Member.cs b/DiscordChatExporter.Core/Discord/Data/Member.cs index d98b977..9711d62 100644 --- a/DiscordChatExporter.Core/Discord/Data/Member.cs +++ b/DiscordChatExporter.Core/Discord/Data/Member.cs @@ -42,10 +42,10 @@ namespace DiscordChatExporter.Core.Discord.Data public static Member Parse(JsonElement json) { var user = json.GetProperty("user").Pipe(User.Parse); - var nick = json.GetPropertyOrNull("nick")?.GetString(); + var nick = json.GetPropertyOrNull("nick")?.GetStringOrNull(); var roleIds = - json.GetPropertyOrNull("roles")?.EnumerateArray().Select(j => j.GetString()).Select(Snowflake.Parse).ToArray() ?? + json.GetPropertyOrNull("roles")?.EnumerateArray().Select(j => j.GetNonWhiteSpaceString()).Select(Snowflake.Parse).ToArray() ?? Array.Empty(); return new Member( diff --git a/DiscordChatExporter.Core/Discord/Data/Message.cs b/DiscordChatExporter.Core/Discord/Data/Message.cs index 10adbf7..f03ac3a 100644 --- a/DiscordChatExporter.Core/Discord/Data/Message.cs +++ b/DiscordChatExporter.Core/Discord/Data/Message.cs @@ -81,7 +81,7 @@ namespace DiscordChatExporter.Core.Discord.Data { public static Message Parse(JsonElement json) { - var id = json.GetProperty("id").GetString().Pipe(Snowflake.Parse); + var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); var author = json.GetProperty("author").Pipe(User.Parse); var timestamp = json.GetProperty("timestamp").GetDateTimeOffset(); var editedTimestamp = json.GetPropertyOrNull("edited_timestamp")?.GetDateTimeOffset(); @@ -101,7 +101,7 @@ namespace DiscordChatExporter.Core.Discord.Data MessageKind.ChannelIconChange => "Changed the channel icon.", MessageKind.ChannelPinnedMessage => "Pinned a message.", MessageKind.GuildMemberJoin => "Joined the server.", - _ => json.GetPropertyOrNull("content")?.GetString() ?? "" + _ => json.GetPropertyOrNull("content")?.GetStringOrNull() ?? "" }; var attachments = diff --git a/DiscordChatExporter.Core/Discord/Data/MessageReference.cs b/DiscordChatExporter.Core/Discord/Data/MessageReference.cs index a2160e4..419070d 100644 --- a/DiscordChatExporter.Core/Discord/Data/MessageReference.cs +++ b/DiscordChatExporter.Core/Discord/Data/MessageReference.cs @@ -29,9 +29,9 @@ namespace DiscordChatExporter.Core.Discord.Data { public static MessageReference Parse(JsonElement json) { - var messageId = json.GetPropertyOrNull("message_id")?.GetString().Pipe(Snowflake.Parse); - var channelId = json.GetPropertyOrNull("channel_id")?.GetString().Pipe(Snowflake.Parse); - var guildId = json.GetPropertyOrNull("guild_id")?.GetString().Pipe(Snowflake.Parse); + var messageId = json.GetPropertyOrNull("message_id")?.GetStringOrNull()?.Pipe(Snowflake.Parse); + var channelId = json.GetPropertyOrNull("channel_id")?.GetStringOrNull()?.Pipe(Snowflake.Parse); + var guildId = json.GetPropertyOrNull("guild_id")?.GetStringOrNull()?.Pipe(Snowflake.Parse); return new MessageReference(messageId, channelId, guildId); } diff --git a/DiscordChatExporter.Core/Discord/Data/Role.cs b/DiscordChatExporter.Core/Discord/Data/Role.cs index f9e2235..7b75554 100644 --- a/DiscordChatExporter.Core/Discord/Data/Role.cs +++ b/DiscordChatExporter.Core/Discord/Data/Role.cs @@ -38,8 +38,8 @@ namespace DiscordChatExporter.Core.Discord.Data { public static Role Parse(JsonElement json) { - var id = json.GetProperty("id").GetString().Pipe(Snowflake.Parse); - var name = json.GetProperty("name").GetString(); + var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); + var name = json.GetProperty("name").GetNonWhiteSpaceString(); var position = json.GetProperty("position").GetInt32(); var color = json diff --git a/DiscordChatExporter.Core/Discord/Data/User.cs b/DiscordChatExporter.Core/Discord/Data/User.cs index a446be9..2b1fc09 100644 --- a/DiscordChatExporter.Core/Discord/Data/User.cs +++ b/DiscordChatExporter.Core/Discord/Data/User.cs @@ -58,11 +58,11 @@ namespace DiscordChatExporter.Core.Discord.Data public static User Parse(JsonElement json) { - var id = json.GetProperty("id").GetString().Pipe(Snowflake.Parse); + var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); var isBot = json.GetPropertyOrNull("bot")?.GetBoolean() ?? false; - var discriminator = json.GetProperty("discriminator").GetString().Pipe(int.Parse); - var name = json.GetProperty("username").GetString(); - var avatarHash = json.GetProperty("avatar").GetString(); + var discriminator = json.GetProperty("discriminator").GetNonWhiteSpaceString().Pipe(int.Parse); + var name = json.GetProperty("username").GetNonWhiteSpaceString(); + var avatarHash = json.GetPropertyOrNull("avatar")?.GetStringOrNull(); var avatarUrl = !string.IsNullOrWhiteSpace(avatarHash) ? GetAvatarUrl(id, avatarHash) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index a0fa38c..87e3c1e 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -130,7 +130,7 @@ namespace DiscordChatExporter.Core.Discord var responseOrdered = response .EnumerateArray() .OrderBy(j => j.GetProperty("position").GetInt32()) - .ThenBy(j => Snowflake.Parse(j.GetProperty("id").GetString())) + .ThenBy(j => j.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse)) .ToArray(); var categories = responseOrdered @@ -142,7 +142,7 @@ namespace DiscordChatExporter.Core.Discord foreach (var channelJson in responseOrdered) { - var parentId = channelJson.GetPropertyOrNull("parent_id")?.GetString(); + var parentId = channelJson.GetPropertyOrNull("parent_id")?.GetStringOrNull(); var category = !string.IsNullOrWhiteSpace(parentId) ? categories.GetValueOrDefault(parentId) @@ -205,7 +205,7 @@ namespace DiscordChatExporter.Core.Discord { var response = await GetJsonResponseAsync($"channels/{channelId}", cancellationToken); - var parentId = response.GetPropertyOrNull("parent_id")?.GetString().Pipe(Snowflake.Parse); + var parentId = response.GetPropertyOrNull("parent_id")?.GetStringOrNull()?.Pipe(Snowflake.Parse); var category = parentId is not null ? await GetChannelCategoryAsync(parentId.Value, cancellationToken) diff --git a/DiscordChatExporter.Core/Utils/Extensions/JsonExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/JsonExtensions.cs new file mode 100644 index 0000000..61fcfff --- /dev/null +++ b/DiscordChatExporter.Core/Utils/Extensions/JsonExtensions.cs @@ -0,0 +1,20 @@ +using System; +using System.Text.Json; + +namespace DiscordChatExporter.Core.Utils.Extensions +{ + public static class JsonExtensions + { + public static string GetNonWhiteSpaceString(this JsonElement json) + { + if (json.ValueKind != JsonValueKind.String) + throw new FormatException(); + + var value = json.GetString(); + if (string.IsNullOrWhiteSpace(value)) + throw new FormatException(); + + return value; + } + } +} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Utils/Http.cs b/DiscordChatExporter.Core/Utils/Http.cs index fec0cbf..f505fe1 100644 --- a/DiscordChatExporter.Core/Utils/Http.cs +++ b/DiscordChatExporter.Core/Utils/Http.cs @@ -33,7 +33,7 @@ namespace DiscordChatExporter.Core.Utils // on the very first request. if (i > 3) { - var retryAfterDelay = result.Result.Headers.RetryAfter.Delta; + var retryAfterDelay = result.Result.Headers.RetryAfter?.Delta; if (retryAfterDelay is not null) return retryAfterDelay.Value + TimeSpan.FromSeconds(1); // margin just in case } diff --git a/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj b/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj index f8094c6..c5e05d4 100644 --- a/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj +++ b/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj @@ -1,6 +1,7 @@ - + + $(TargetFramework)-windows WinExe DiscordChatExporter true @@ -34,7 +35,7 @@ - + \ No newline at end of file