From bfa5d107615ebbf9c8d57c6a57904e5dec27105c Mon Sep 17 00:00:00 2001 From: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> Date: Wed, 15 Dec 2021 02:05:19 +0200 Subject: [PATCH] Handle null `name` in `Emoji.Parse(...)` --- .../Discord/Data/Attachment.cs | 4 +- .../Discord/Data/Channel.cs | 10 +++-- .../Discord/Data/ChannelCategory.cs | 11 ++---- .../Discord/Data/Embeds/Embed.cs | 4 +- .../Discord/Data/Embeds/EmbedAuthor.cs | 6 +-- .../Discord/Data/Embeds/EmbedField.cs | 3 +- .../Discord/Data/Embeds/EmbedFooter.cs | 7 ++-- .../Discord/Data/Embeds/EmbedImage.cs | 8 ++-- .../Discord/Data/Emoji.cs | 39 ++++++++++++------- .../Discord/Data/Guild.cs | 2 +- .../Discord/Data/Member.cs | 2 +- .../Discord/Data/Message.cs | 2 +- .../Discord/Data/MessageReference.cs | 6 +-- DiscordChatExporter.Core/Discord/Data/User.cs | 4 +- .../Discord/DiscordClient.cs | 4 +- DiscordChatExporter.Core/Utils/FileFormat.cs | 12 +++--- 16 files changed, 67 insertions(+), 57 deletions(-) diff --git a/DiscordChatExporter.Core/Discord/Data/Attachment.cs b/DiscordChatExporter.Core/Discord/Data/Attachment.cs index 82d3456..f8ca229 100644 --- a/DiscordChatExporter.Core/Discord/Data/Attachment.cs +++ b/DiscordChatExporter.Core/Discord/Data/Attachment.cs @@ -34,8 +34,8 @@ public partial record Attachment { 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 width = json.GetPropertyOrNull("width")?.GetInt32OrNull(); + var height = json.GetPropertyOrNull("height")?.GetInt32OrNull(); var fileName = json.GetProperty("filename").GetNonWhiteSpaceString(); var fileSize = json.GetProperty("size").GetInt64().Pipe(FileSize.FromBytes); diff --git a/DiscordChatExporter.Core/Discord/Data/Channel.cs b/DiscordChatExporter.Core/Discord/Data/Channel.cs index 3268175..218341a 100644 --- a/DiscordChatExporter.Core/Discord/Data/Channel.cs +++ b/DiscordChatExporter.Core/Discord/Data/Channel.cs @@ -42,16 +42,16 @@ public partial record Channel null ); - public static Channel Parse(JsonElement json, ChannelCategory? category = null, int? position = null) + public static Channel Parse(JsonElement json, ChannelCategory? category = null, int? positionHint = null) { var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); - var guildId = json.GetPropertyOrNull("guild_id")?.GetStringOrNull()?.Pipe(Snowflake.Parse); + var guildId = json.GetPropertyOrNull("guild_id")?.GetNonWhiteSpaceStringOrNull()?.Pipe(Snowflake.Parse); var topic = json.GetPropertyOrNull("topic")?.GetStringOrNull(); var kind = (ChannelKind)json.GetProperty("type").GetInt32(); var name = // Guild channel - json.GetPropertyOrNull("name")?.GetStringOrNull() ?? + json.GetPropertyOrNull("name")?.GetNonWhiteSpaceStringOrNull() ?? // DM channel json.GetPropertyOrNull("recipients")? @@ -63,13 +63,15 @@ public partial record Channel // Fallback id.ToString(); + var position = positionHint ?? json.GetPropertyOrNull("position")?.GetInt32OrNull(); + return new Channel( id, kind, guildId ?? Guild.DirectMessages.Id, category ?? GetFallbackCategory(kind), name, - position ?? json.GetPropertyOrNull("position")?.GetInt32(), + position, topic ); } diff --git a/DiscordChatExporter.Core/Discord/Data/ChannelCategory.cs b/DiscordChatExporter.Core/Discord/Data/ChannelCategory.cs index a76a561..15e9744 100644 --- a/DiscordChatExporter.Core/Discord/Data/ChannelCategory.cs +++ b/DiscordChatExporter.Core/Discord/Data/ChannelCategory.cs @@ -9,18 +9,15 @@ public record ChannelCategory(Snowflake Id, string Name, int? Position) : IHasId { public static ChannelCategory Unknown { get; } = new(Snowflake.Zero, "", 0); - public static ChannelCategory Parse(JsonElement json, int? position = null) + public static ChannelCategory Parse(JsonElement json, int? positionHint = null) { var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); + var position = positionHint ?? json.GetPropertyOrNull("position")?.GetInt32OrNull(); var name = - json.GetPropertyOrNull("name")?.GetStringOrNull() ?? + json.GetPropertyOrNull("name")?.GetNonWhiteSpaceStringOrNull() ?? id.ToString(); - return new ChannelCategory( - id, - name, - position ?? json.GetPropertyOrNull("position")?.GetInt32() - ); + return new ChannelCategory(id, name, position); } } \ No newline at end of file diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs index 653f8e0..9d3c4eb 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs @@ -36,9 +36,9 @@ public partial record Embed public static Embed Parse(JsonElement json) { var title = json.GetPropertyOrNull("title")?.GetStringOrNull(); - var url = json.GetPropertyOrNull("url")?.GetStringOrNull(); + var url = json.GetPropertyOrNull("url")?.GetNonWhiteSpaceStringOrNull(); var timestamp = json.GetPropertyOrNull("timestamp")?.GetDateTimeOffset(); - var color = json.GetPropertyOrNull("color")?.GetInt32().Pipe(System.Drawing.Color.FromArgb).ResetAlpha(); + var color = json.GetPropertyOrNull("color")?.GetInt32OrNull()?.Pipe(System.Drawing.Color.FromArgb).ResetAlpha(); var description = json.GetPropertyOrNull("description")?.GetStringOrNull(); var author = json.GetPropertyOrNull("author")?.Pipe(EmbedAuthor.Parse); diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs index 9a8ddc2..7bdba77 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedAuthor.cs @@ -13,9 +13,9 @@ public record EmbedAuthor( public static EmbedAuthor Parse(JsonElement json) { 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(); + var url = json.GetPropertyOrNull("url")?.GetNonWhiteSpaceStringOrNull(); + var iconUrl = json.GetPropertyOrNull("icon_url")?.GetNonWhiteSpaceStringOrNull(); + var iconProxyUrl = json.GetPropertyOrNull("proxy_icon_url")?.GetNonWhiteSpaceStringOrNull(); 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 0dac0cf..3076829 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedField.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedField.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; namespace DiscordChatExporter.Core.Discord.Data.Embeds; @@ -14,7 +13,7 @@ public record EmbedField( { var name = json.GetProperty("name").GetNonWhiteSpaceString(); var value = json.GetProperty("value").GetNonWhiteSpaceString(); - var isInline = json.GetPropertyOrNull("inline")?.GetBoolean() ?? false; + var isInline = json.GetPropertyOrNull("inline")?.GetBooleanOrNull() ?? 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 5cdd094..df3549c 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedFooter.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedFooter.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; namespace DiscordChatExporter.Core.Discord.Data.Embeds; @@ -12,9 +11,9 @@ public record EmbedFooter( { public static EmbedFooter Parse(JsonElement json) { - var text = json.GetProperty("text").GetNonWhiteSpaceString(); - var iconUrl = json.GetPropertyOrNull("icon_url")?.GetStringOrNull(); - var iconProxyUrl = json.GetPropertyOrNull("proxy_icon_url")?.GetStringOrNull(); + var text = json.GetProperty("text").GetNonNullString(); + var iconUrl = json.GetPropertyOrNull("icon_url")?.GetNonWhiteSpaceStringOrNull(); + var iconProxyUrl = json.GetPropertyOrNull("proxy_icon_url")?.GetNonWhiteSpaceStringOrNull(); 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 2aae835..5d24ce3 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedImage.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/EmbedImage.cs @@ -12,10 +12,10 @@ public record EmbedImage( { public static EmbedImage Parse(JsonElement json) { - 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(); + var url = json.GetPropertyOrNull("url")?.GetNonWhiteSpaceStringOrNull(); + var proxyUrl = json.GetPropertyOrNull("proxy_url")?.GetNonWhiteSpaceStringOrNull(); + var width = json.GetPropertyOrNull("width")?.GetInt32OrNull(); + var height = json.GetPropertyOrNull("height")?.GetInt32OrNull(); return new EmbedImage(url, proxyUrl, width, height); } diff --git a/DiscordChatExporter.Core/Discord/Data/Emoji.cs b/DiscordChatExporter.Core/Discord/Data/Emoji.cs index fd20513..64bcbe6 100644 --- a/DiscordChatExporter.Core/Discord/Data/Emoji.cs +++ b/DiscordChatExporter.Core/Discord/Data/Emoji.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Text.Json; using DiscordChatExporter.Core.Utils; using DiscordChatExporter.Core.Utils.Extensions; @@ -31,29 +32,41 @@ public partial record Emoji .Select(r => r.Value.ToString("x")) ); - public static string GetImageUrl(string? id, string name, bool isAnimated) + private static string GetImageUrl(string id, bool isAnimated) => isAnimated + ? $"https://cdn.discordapp.com/emojis/{id}.gif" + : $"https://cdn.discordapp.com/emojis/{id}.png"; + + private static string GetImageUrl(string name) => + $"https://twemoji.maxcdn.com/2/svg/{GetTwemojiName(name)}.svg"; + + public static string GetImageUrl(string? id, string? name, bool isAnimated) { // Custom emoji if (!string.IsNullOrWhiteSpace(id)) - { - return isAnimated - ? $"https://cdn.discordapp.com/emojis/{id}.gif" - : $"https://cdn.discordapp.com/emojis/{id}.png"; - } + return GetImageUrl(id, isAnimated); // Standard emoji - var twemojiName = GetTwemojiName(name); - return $"https://twemoji.maxcdn.com/2/svg/{twemojiName}.svg"; + if (!string.IsNullOrWhiteSpace(name)) + return GetImageUrl(name); + + // Either ID or name should be set + throw new ApplicationException("Emoji has neither ID nor name set."); } public static Emoji Parse(JsonElement json) { - var id = json.GetPropertyOrNull("id")?.GetStringOrNull(); - var name = json.GetProperty("name").GetNonWhiteSpaceString(); - var isAnimated = json.GetPropertyOrNull("animated")?.GetBoolean() ?? false; + var id = json.GetPropertyOrNull("id")?.GetNonWhiteSpaceStringOrNull(); + var name = json.GetPropertyOrNull("name")?.GetNonWhiteSpaceStringOrNull(); + var isAnimated = json.GetPropertyOrNull("animated")?.GetBooleanOrNull() ?? false; var imageUrl = GetImageUrl(id, name, isAnimated); - return new Emoji(id, name, isAnimated, imageUrl); + return new Emoji( + id, + // Name may be missing if it's an emoji inside a reaction + name ?? "", + isAnimated, + imageUrl + ); } } \ No newline at end of file diff --git a/DiscordChatExporter.Core/Discord/Data/Guild.cs b/DiscordChatExporter.Core/Discord/Data/Guild.cs index 1b4faf9..aca97c7 100644 --- a/DiscordChatExporter.Core/Discord/Data/Guild.cs +++ b/DiscordChatExporter.Core/Discord/Data/Guild.cs @@ -24,7 +24,7 @@ public record Guild(Snowflake Id, string Name, string IconUrl) : IHasId { var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); var name = json.GetProperty("name").GetNonWhiteSpaceString(); - var iconHash = json.GetPropertyOrNull("icon")?.GetStringOrNull(); + var iconHash = json.GetPropertyOrNull("icon")?.GetNonWhiteSpaceStringOrNull(); 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 e36f341..aadfd70 100644 --- a/DiscordChatExporter.Core/Discord/Data/Member.cs +++ b/DiscordChatExporter.Core/Discord/Data/Member.cs @@ -28,7 +28,7 @@ public partial record Member public static Member Parse(JsonElement json) { var user = json.GetProperty("user").Pipe(User.Parse); - var nick = json.GetPropertyOrNull("nick")?.GetStringOrNull(); + var nick = json.GetPropertyOrNull("nick")?.GetNonWhiteSpaceStringOrNull(); var roleIds = json .GetPropertyOrNull("roles")? diff --git a/DiscordChatExporter.Core/Discord/Data/Message.cs b/DiscordChatExporter.Core/Discord/Data/Message.cs index 55c9807..4d38e7b 100644 --- a/DiscordChatExporter.Core/Discord/Data/Message.cs +++ b/DiscordChatExporter.Core/Discord/Data/Message.cs @@ -35,7 +35,7 @@ public record Message( var callEndedTimestamp = json.GetPropertyOrNull("call")?.GetPropertyOrNull("ended_timestamp") ?.GetDateTimeOffset(); var kind = (MessageKind)json.GetProperty("type").GetInt32(); - var isPinned = json.GetPropertyOrNull("pinned")?.GetBoolean() ?? false; + var isPinned = json.GetPropertyOrNull("pinned")?.GetBooleanOrNull() ?? false; var messageReference = json.GetPropertyOrNull("message_reference")?.Pipe(MessageReference.Parse); var referencedMessage = json.GetPropertyOrNull("referenced_message")?.Pipe(Parse); diff --git a/DiscordChatExporter.Core/Discord/Data/MessageReference.cs b/DiscordChatExporter.Core/Discord/Data/MessageReference.cs index f392050..54ff65c 100644 --- a/DiscordChatExporter.Core/Discord/Data/MessageReference.cs +++ b/DiscordChatExporter.Core/Discord/Data/MessageReference.cs @@ -9,9 +9,9 @@ public record MessageReference(Snowflake? MessageId, Snowflake? ChannelId, Snowf { public static MessageReference Parse(JsonElement json) { - 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); + var messageId = json.GetPropertyOrNull("message_id")?.GetNonWhiteSpaceStringOrNull()?.Pipe(Snowflake.Parse); + var channelId = json.GetPropertyOrNull("channel_id")?.GetNonWhiteSpaceStringOrNull()?.Pipe(Snowflake.Parse); + var guildId = json.GetPropertyOrNull("guild_id")?.GetNonWhiteSpaceStringOrNull()?.Pipe(Snowflake.Parse); return new MessageReference(messageId, channelId, guildId); } diff --git a/DiscordChatExporter.Core/Discord/Data/User.cs b/DiscordChatExporter.Core/Discord/Data/User.cs index 32b8aa2..a967523 100644 --- a/DiscordChatExporter.Core/Discord/Data/User.cs +++ b/DiscordChatExporter.Core/Discord/Data/User.cs @@ -36,10 +36,10 @@ public partial record User public static User Parse(JsonElement json) { var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse); - var isBot = json.GetPropertyOrNull("bot")?.GetBoolean() ?? false; + var isBot = json.GetPropertyOrNull("bot")?.GetBooleanOrNull() ?? false; var discriminator = json.GetProperty("discriminator").GetNonWhiteSpaceString().Pipe(int.Parse); var name = json.GetProperty("username").GetNonWhiteSpaceString(); - var avatarHash = json.GetPropertyOrNull("avatar")?.GetStringOrNull(); + var avatarHash = json.GetPropertyOrNull("avatar")?.GetNonWhiteSpaceStringOrNull(); var avatarUrl = !string.IsNullOrWhiteSpace(avatarHash) ? GetAvatarUrl(id, avatarHash) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index 1f4bd15..9319d83 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -142,7 +142,7 @@ public class DiscordClient foreach (var channelJson in responseOrdered) { - var parentId = channelJson.GetPropertyOrNull("parent_id")?.GetStringOrNull(); + var parentId = channelJson.GetPropertyOrNull("parent_id")?.GetNonWhiteSpaceStringOrNull(); var category = !string.IsNullOrWhiteSpace(parentId) ? categories.GetValueOrDefault(parentId) @@ -205,7 +205,7 @@ public class DiscordClient { var response = await GetJsonResponseAsync($"channels/{channelId}", cancellationToken); - var parentId = response.GetPropertyOrNull("parent_id")?.GetStringOrNull()?.Pipe(Snowflake.Parse); + var parentId = response.GetPropertyOrNull("parent_id")?.GetNonWhiteSpaceStringOrNull()?.Pipe(Snowflake.Parse); var category = parentId is not null ? await GetChannelCategoryAsync(parentId.Value, cancellationToken) diff --git a/DiscordChatExporter.Core/Utils/FileFormat.cs b/DiscordChatExporter.Core/Utils/FileFormat.cs index 3306902..a19ec8b 100644 --- a/DiscordChatExporter.Core/Utils/FileFormat.cs +++ b/DiscordChatExporter.Core/Utils/FileFormat.cs @@ -5,7 +5,7 @@ namespace DiscordChatExporter.Core.Utils; public static class FileFormat { - private static readonly HashSet ImageFormats = new(StringComparer.OrdinalIgnoreCase) + private static readonly HashSet ImageExtensions = new(StringComparer.OrdinalIgnoreCase) { ".jpg", ".jpeg", @@ -16,18 +16,18 @@ public static class FileFormat ".webp" }; - public static bool IsImage(string format) => ImageFormats.Contains(format); + public static bool IsImage(string format) => ImageExtensions.Contains(format); - private static readonly HashSet VideoFormats = new(StringComparer.OrdinalIgnoreCase) + private static readonly HashSet VideoExtensions = new(StringComparer.OrdinalIgnoreCase) { ".mp4", ".webm", ".mov" }; - public static bool IsVideo(string format) => VideoFormats.Contains(format); + public static bool IsVideo(string format) => VideoExtensions.Contains(format); - private static readonly HashSet AudioFormats = new(StringComparer.OrdinalIgnoreCase) + private static readonly HashSet AudioExtensions = new(StringComparer.OrdinalIgnoreCase) { ".mp3", ".wav", @@ -36,5 +36,5 @@ public static class FileFormat ".m4a" }; - public static bool IsAudio(string format) => AudioFormats.Contains(format); + public static bool IsAudio(string format) => AudioExtensions.Contains(format); } \ No newline at end of file