From 759187dcd4bf724254b4a158b51a15802e0c35be Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 5 Oct 2024 12:26:29 -0700 Subject: [PATCH] Fixed: Encoded unicode characters in Transmission torrent names Closes #7270 --- .../ReplaceEncodedUnicodeCharactersFixture.cs | 20 ++++++++++++++++++ src/NzbDrone.Common.Test/OsPathFixture.cs | 2 +- .../Extensions/StringExtensions.cs | 6 ++++++ .../TransmissionTests/TransmissionFixture.cs | 21 +++++++++++++++++++ .../Clients/Transmission/TransmissionBase.cs | 4 ++-- 5 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src/NzbDrone.Common.Test/ExtensionTests/StringExtensionTests/ReplaceEncodedUnicodeCharactersFixture.cs diff --git a/src/NzbDrone.Common.Test/ExtensionTests/StringExtensionTests/ReplaceEncodedUnicodeCharactersFixture.cs b/src/NzbDrone.Common.Test/ExtensionTests/StringExtensionTests/ReplaceEncodedUnicodeCharactersFixture.cs new file mode 100644 index 000000000..963454054 --- /dev/null +++ b/src/NzbDrone.Common.Test/ExtensionTests/StringExtensionTests/ReplaceEncodedUnicodeCharactersFixture.cs @@ -0,0 +1,20 @@ +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.Extensions; + +namespace NzbDrone.Common.Test.ExtensionTests.StringExtensionTests +{ + [TestFixture] + public class ReplaceEncodedUnicodeCharactersFixture + { + [TestCase("+\\u2b50", "\u2b50")] + [TestCase("\\u2b50", "\u2b50")] + [TestCase("+\\u00e9", "é")] + [TestCase("\\u00e9", "é")] + [TestCase("é", "é")] + public void should_replace_encoded_unicode_character(string input, string expected) + { + input.ReplaceEncodedUnicodeCharacters().Should().Be(expected); + } + } +} diff --git a/src/NzbDrone.Common.Test/OsPathFixture.cs b/src/NzbDrone.Common.Test/OsPathFixture.cs index c31abefc7..9f2a3c42c 100644 --- a/src/NzbDrone.Common.Test/OsPathFixture.cs +++ b/src/NzbDrone.Common.Test/OsPathFixture.cs @@ -1,4 +1,4 @@ -using FluentAssertions; +using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Disk; using NzbDrone.Test.Common; diff --git a/src/NzbDrone.Common/Extensions/StringExtensions.cs b/src/NzbDrone.Common/Extensions/StringExtensions.cs index 8a4d140f7..49742b033 100644 --- a/src/NzbDrone.Common/Extensions/StringExtensions.cs +++ b/src/NzbDrone.Common/Extensions/StringExtensions.cs @@ -12,6 +12,7 @@ namespace NzbDrone.Common.Extensions public static class StringExtensions { private static readonly Regex CamelCaseRegex = new Regex("(?[a-z0-9]{4})", RegexOptions.Compiled | RegexOptions.IgnoreCase); public static string NullSafe(this string target) { @@ -251,5 +252,10 @@ namespace NzbDrone.Common.Extensions return new string(array); } + + public static string ReplaceEncodedUnicodeCharacters(this string text) + { + return UnicodeEscapeRegex.Replace(text, m => ((char)int.Parse(m.Groups["Value"].Value, NumberStyles.HexNumber)).ToString()); + } } } diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/TransmissionTests/TransmissionFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/TransmissionTests/TransmissionFixture.cs index 3bbb417b9..8b9a597fe 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/TransmissionTests/TransmissionFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/TransmissionTests/TransmissionFixture.cs @@ -440,5 +440,26 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests item.CanBeRemoved.Should().BeTrue(); item.CanMoveFiles.Should().BeTrue(); } + + [TestCase(@"Pok\u00e9 Bowl Complete", "Poké Bowl Complete")] + [TestCase("Pok\u00e9 Bowl Complete", "Poké Bowl Complete")] + [TestCase(@"Series with a +\u2b50", "Series with a \u2b50")] + [TestCase("Series with a \u2b50", "Series with a \u2b50")] + + public void should_replace_unicode_characters(string input, string expected) + { + _completed.DownloadDir = @"/Downloads/Finished/transmission"; + _completed.Name = input; + + GivenTorrents(new List + { + _completed + }); + + var items = Subject.GetItems().ToList(); + + items.Should().HaveCount(1); + items.First().OutputPath.Should().Be(@"/Downloads/Finished/transmission/" + expected); + } } } diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs index 87810d016..8df7cbe11 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionBase.cs @@ -66,7 +66,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission var item = new DownloadClientItem(); item.DownloadId = torrent.HashString.ToUpper(); item.Category = Settings.TvCategory; - item.Title = torrent.Name; + item.Title = torrent.Name.ReplaceEncodedUnicodeCharacters(); item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this, false); @@ -242,7 +242,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission protected virtual OsPath GetOutputPath(OsPath outputPath, TransmissionTorrent torrent) { - return outputPath + torrent.Name.Replace(":", "_"); + return outputPath + torrent.Name.ReplaceEncodedUnicodeCharacters().Replace(":", "_"); } protected string GetDownloadDirectory()