From 1644b701ba4cbdc227c575b266533bce24de1292 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sun, 27 Aug 2023 21:23:46 +0100 Subject: [PATCH 1/5] refactor: remove optional default for format --- VPLink.Common/Data/PlainTextMessageBuilder.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/VPLink.Common/Data/PlainTextMessageBuilder.cs b/VPLink.Common/Data/PlainTextMessageBuilder.cs index a1f5ff0..dd68b97 100644 --- a/VPLink.Common/Data/PlainTextMessageBuilder.cs +++ b/VPLink.Common/Data/PlainTextMessageBuilder.cs @@ -35,8 +35,7 @@ public struct PlainTextMessageBuilder : IDisposable /// The timestamp. /// The format. /// The trailing whitespace trivia. - public void AddTimestamp(DateTimeOffset timestamp, TimestampFormat format = TimestampFormat.None, - char whitespace = ' ') + public void AddTimestamp(DateTimeOffset timestamp, TimestampFormat format, char whitespace = ' ') { switch (format) { From 67a5f9777ab8e80a8aa8c8c7dd97644f7a041bb9 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sun, 27 Aug 2023 21:24:28 +0100 Subject: [PATCH 2/5] fix: add support for unicode emojis --- VPLink/Services/DiscordMessageService.cs | 26 ++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/VPLink/Services/DiscordMessageService.cs b/VPLink/Services/DiscordMessageService.cs index 8611e36..2230eaf 100644 --- a/VPLink/Services/DiscordMessageService.cs +++ b/VPLink/Services/DiscordMessageService.cs @@ -96,6 +96,9 @@ internal sealed class DiscordMessageService : BackgroundService, IDiscordMessage SanitizeContent(guild, message.Content, ref builder); var content = builder.ToString(); + Span testSpan = stackalloc byte[Utf8Encoding.GetByteCount(content)]; + Utf8Encoding.GetBytes(content, testSpan); + _logger.LogInformation("Message by {Author}: {Content}", author, content); var messages = new List(); @@ -141,14 +144,16 @@ internal sealed class DiscordMessageService : BackgroundService, IDiscordMessage private static void AddMessage(ICollection messages, string displayName, string content) { - Span buffer = stackalloc byte[255]; // VP message length limit int byteCount = Utf8Encoding.GetByteCount(content); + Span buffer = stackalloc byte[byteCount]; + Utf8Encoding.GetBytes(content, buffer); + var offset = 0; while (offset < byteCount) { - int length = Math.Min(byteCount - offset, 255); - Utf8Encoding.GetBytes(content.AsSpan(offset, length), buffer); - messages.Add(new RelayedMessage(displayName, Utf8Encoding.GetString(buffer), false)); + int length = Math.Min(byteCount - offset, 255); // VP message length limit + Span slice = buffer.Slice(offset, length); + messages.Add(new RelayedMessage(displayName, Utf8Encoding.GetString(slice), false)); offset += length; } } @@ -199,6 +204,8 @@ internal sealed class DiscordMessageService : BackgroundService, IDiscordMessage { Utf8ValueStringBuilder wordBuffer = ZString.CreateUtf8StringBuilder(); + Span chars = stackalloc char[2]; + Span bytes = stackalloc byte[4]; for (var index = 0; index < content.Length; index++) { char current = content[index]; @@ -207,6 +214,13 @@ internal sealed class DiscordMessageService : BackgroundService, IDiscordMessage AddWord(guild, ref builder, ref wordBuffer, current); wordBuffer.Clear(); } + else if (char.IsSurrogate(current)) + { + content.Slice(index++, 2).CopyTo(chars); + int byteCount = Utf8Encoding.GetByteCount(chars); + Utf8Encoding.GetBytes(chars, bytes); + wordBuffer.AppendLiteral(bytes[..byteCount]); + } else { wordBuffer.Append(current); @@ -256,6 +270,10 @@ internal sealed class DiscordMessageService : BackgroundService, IDiscordMessage MentionUtility.ParseTag(guild, temp[..tagLength], ref builder, whitespace); break; + case var _ when char.IsSurrogate(current): + buffer.Append(chars.Slice(index++, 2)); + break; + default: buffer.Append(current); break; From f3d035d67b5fb247c84a7acc0b0674e95f5a1a86 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sun, 27 Aug 2023 21:27:41 +0100 Subject: [PATCH 3/5] feat: add support for custom discord emotes --- VPLink.Common/MentionUtility.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/VPLink.Common/MentionUtility.cs b/VPLink.Common/MentionUtility.cs index 5bc355d..08826b2 100644 --- a/VPLink.Common/MentionUtility.cs +++ b/VPLink.Common/MentionUtility.cs @@ -24,6 +24,11 @@ public static class MentionUtility else switch (contents[0]) { + // custom emote + case ':': + ParseCustomEmote(contents, ref builder, whitespaceTrivia); + break; + // user mention case '@': ParseUserMention(guild, contents, ref builder, whitespaceTrivia); @@ -71,6 +76,15 @@ public static class MentionUtility whitespaceTrivia); } + private static void ParseCustomEmote(ReadOnlySpan contents, + ref PlainTextMessageBuilder builder, + char whitespaceTrivia) + { + contents = contents[1..]; + ReadOnlySpan name = contents[..contents.IndexOf(':')]; + builder.AddWord($":{name.ToString()}:", whitespaceTrivia); + } + private static void ParseTimestamp(ReadOnlySpan contents, ref PlainTextMessageBuilder builder, char whitespaceTrivia) From 2cb98e85c731033489ff494507b5f7dbd437adcf Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sun, 27 Aug 2023 21:44:56 +0100 Subject: [PATCH 4/5] feat: render relative timestamps the way Discord does it --- VPLink.Common/Data/PlainTextMessageBuilder.cs | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/VPLink.Common/Data/PlainTextMessageBuilder.cs b/VPLink.Common/Data/PlainTextMessageBuilder.cs index dd68b97..b749a3c 100644 --- a/VPLink.Common/Data/PlainTextMessageBuilder.cs +++ b/VPLink.Common/Data/PlainTextMessageBuilder.cs @@ -1,5 +1,4 @@ using Cysharp.Text; -using Humanizer; namespace VPLink.Common.Data; @@ -40,7 +39,7 @@ public struct PlainTextMessageBuilder : IDisposable switch (format) { case TimestampFormat.Relative: - AddWord(timestamp.Humanize(), whitespace); + AddWord(FormatRelativeTime(timestamp), whitespace); break; case TimestampFormat.None: @@ -103,4 +102,53 @@ public struct PlainTextMessageBuilder : IDisposable { return _builder.ToString().Trim(); } + + private static string FormatRelativeTime(DateTimeOffset targetTime) + { + TimeSpan timeDifference = DateTimeOffset.Now - targetTime; + bool isFuture = timeDifference.TotalMilliseconds < 0; + int value; + string unit; + + timeDifference = TimeSpan.FromMilliseconds(Math.Abs(timeDifference.TotalMilliseconds)); + switch (timeDifference.TotalDays) + { + case >= 365: + unit = "year"; + value = (int)(timeDifference.TotalDays / 365); + break; + + case >= 30: + unit = "month"; + value = (int)(timeDifference.TotalDays / 30); + break; + + case >= 1: + unit = "day"; + value = (int)timeDifference.TotalDays; + break; + + default: + if (timeDifference.TotalHours >= 1) + { + unit = "hour"; + value = (int)timeDifference.TotalHours; + } + else if (timeDifference.TotalMinutes >= 1) + { + unit = "minute"; + value = (int)timeDifference.TotalMinutes; + } + else + { + unit = "second"; + value = (int)timeDifference.TotalSeconds; + } + + break; + } + + string suffix = value > 1 ? "s" : ""; + return isFuture ? $"in {value} {unit}{suffix}" : $"{value} {unit}{suffix} ago"; + } } From 80cb8e8cfbaea8f2413ccbca289e5081979a3351 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sun, 27 Aug 2023 21:45:12 +0100 Subject: [PATCH 5/5] chore: bump to 1.3.1 --- VPLink/VPLink.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VPLink/VPLink.csproj b/VPLink/VPLink.csproj index 4d33764..5d383f9 100644 --- a/VPLink/VPLink.csproj +++ b/VPLink/VPLink.csproj @@ -9,7 +9,7 @@ Oliver Booth https://github.com/oliverbooth/VpBridge git - 1.3.0 + 1.3.1