diff --git a/frontend/src/Settings/MediaManagement/Naming/NamingModal.js b/frontend/src/Settings/MediaManagement/Naming/NamingModal.js index dec15893f..c006a5674 100644 --- a/frontend/src/Settings/MediaManagement/Naming/NamingModal.js +++ b/frontend/src/Settings/MediaManagement/Naming/NamingModal.js @@ -75,10 +75,13 @@ const fileNameTokens = [ const artistTokens = [ { token: '{Artist Name}', example: 'Artist Name' }, + { token: '{Artist SortName}', example: 'Artist LastName, Artist FirstName'}, { token: '{Artist CleanName}', example: 'Artist Name' }, + { token: '{Artist CleanSortName}', example: 'Artist LastName, Artist FirstName'}, { token: '{Artist NameThe}', example: 'Artist Name, The' }, { token: '{Artist CleanNameThe}', example: 'Artist Name, The' }, { token: '{Artist NameFirstCharacter}', example: 'A' }, + { token: '{Artist SortNameFirstCharacter}', example: 'A' }, { token: '{Artist Disambiguation}', example: 'Disambiguation' }, { token: '{Artist Genre}', example: 'Pop' }, { token: '{Artist MbId}', example: 'db92a151-1ac2-438b-bc43-b82e149ddd50' } diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/ArtistCleanSortNameFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/ArtistCleanSortNameFixture.cs new file mode 100644 index 000000000..483bdf80e --- /dev/null +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/ArtistCleanSortNameFixture.cs @@ -0,0 +1,56 @@ +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Music; +using NzbDrone.Core.Organizer; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests +{ + [TestFixture] + public class ArtistCleanSortNameFixture : CoreTest + { + private Artist _artist; + private NamingConfig _namingConfig; + + [SetUp] + public void Setup() + { + _artist = Builder + .CreateNew() + .Build(); + + _namingConfig = NamingConfig.Default; + _namingConfig.RenameTracks = true; + + Mocker.GetMock() + .Setup(c => c.GetConfig()).Returns(_namingConfig); + + Mocker.GetMock() + .Setup(v => v.Get(Moq.It.IsAny())) + .Returns(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v)); + } + + [TestCase("AC/DC", "AC DC")] + [TestCase("Guns N' Roses", "Guns N Roses")] + [TestCase("Twenty Øne Piløts", "Twenty One Pilots")] + public void should_get_expected_folder_name_back(string sortName, string cleanSortName) + { + _artist.SortName = sortName; + _namingConfig.ArtistFolderFormat = "{Artist CleanSortName}"; + + Subject.GetArtistFolder(_artist).Should().Be(cleanSortName); + } + + [Test] + public void should_be_able_to_use_lower_case_clean_sort_name() + { + _artist.SortName = "AC/DC"; + _namingConfig.ArtistFolderFormat = "{artist cleansortname}"; + + Subject.GetArtistFolder(_artist).Should().Be("ac dc"); + } + } +} diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/ArtistSortNameFirstCharacterFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/ArtistSortNameFirstCharacterFixture.cs new file mode 100644 index 000000000..1f1fbfc40 --- /dev/null +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/ArtistSortNameFirstCharacterFixture.cs @@ -0,0 +1,63 @@ +using System.IO; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Music; +using NzbDrone.Core.Organizer; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests +{ + [TestFixture] + public class ArtistSortNameFirstCharacterFixture : CoreTest + { + private Artist _artist; + private NamingConfig _namingConfig; + + [SetUp] + public void Setup() + { + _artist = Builder + .CreateNew() + .Build(); + + _namingConfig = NamingConfig.Default; + _namingConfig.RenameTracks = true; + + Mocker.GetMock() + .Setup(c => c.GetConfig()).Returns(_namingConfig); + + Mocker.GetMock() + .Setup(v => v.Get(Moq.It.IsAny())) + .Returns(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v)); + } + + [TestCase("Beatles, The", "B", "Beatles, The")] + [TestCase("1975, The", "1", "1975, The")] + [TestCase("Smith, Elliott", "S", "Smith, Elliott")] + [TestCase("Madonna", "M", "Madonna")] + [TestCase("Perfect Circle, A", "P", "Perfect Circle, A")] + [TestCase("Rolling Stones, The", "R", "Rolling Stones, The")] + [TestCase("50 Cent", "5", "50 Cent")] + [TestCase("¡Forward, Russia!", "F", "¡Forward, Russia!")] + [TestCase(".hack//SIGN", "H", "hack++SIGN")] + public void should_get_expected_folder_name_back(string sortName, string parent, string child) + { + _artist.SortName = sortName; + _namingConfig.ArtistFolderFormat = "{Artist SortNameFirstCharacter}\\{Artist SortName}"; + + Subject.GetArtistFolder(_artist).Should().Be(Path.Combine(parent, child)); + } + + [Test] + public void should_be_able_to_use_lower_case_first_character() + { + _artist.SortName = "Beatles, The"; + _namingConfig.ArtistFolderFormat = "{artist sortnamefirstcharacter}\\{artist sortname}"; + + Subject.GetArtistFolder(_artist).Should().Be(Path.Combine("b", "beatles, the")); + } + } +} diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/ArtistSortNameFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/ArtistSortNameFixture.cs new file mode 100644 index 000000000..36c275ea5 --- /dev/null +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/ArtistSortNameFixture.cs @@ -0,0 +1,60 @@ +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Music; +using NzbDrone.Core.Organizer; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests +{ + [TestFixture] + public class ArtistSortNameFixture : CoreTest + { + private Artist _artist; + private NamingConfig _namingConfig; + + [SetUp] + public void Setup() + { + _artist = Builder + .CreateNew() + .Build(); + + _namingConfig = NamingConfig.Default; + _namingConfig.RenameTracks = true; + + Mocker.GetMock() + .Setup(c => c.GetConfig()).Returns(_namingConfig); + + Mocker.GetMock() + .Setup(v => v.Get(Moq.It.IsAny())) + .Returns(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v)); + } + + [TestCase("The Beatles", "Beatles, The")] + [TestCase("Elliott Smith", "Smith, Elliott")] + [TestCase("Madonna", "Madonna")] + [TestCase("A Perfect Circle", "Perfect Circle, A")] + [TestCase("The Rolling Stones", "Rolling Stones, The")] + public void should_get_expected_folder_name_back(string name, string sortName) + { + _artist.Name = name; + _artist.SortName = sortName; + _namingConfig.ArtistFolderFormat = "{Artist SortName}"; + + Subject.GetArtistFolder(_artist).Should().Be(sortName); + } + + [Test] + public void should_be_able_to_use_lower_case_sort_name() + { + _artist.Name = "The Beatles"; + _artist.SortName = "Beatles, The"; + _namingConfig.ArtistFolderFormat = "{artist sortname}"; + + Subject.GetArtistFolder(_artist).Should().Be("beatles, the"); + } + } +} diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index a3342f5b3..eef439d15 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -310,10 +310,13 @@ private void AddArtistTokens(Dictionary> tokenH { tokenHandlers["{Artist Name}"] = m => Truncate(artist.Name, m.CustomFormat); tokenHandlers["{Artist CleanName}"] = m => Truncate(CleanTitle(artist.Name), m.CustomFormat); + tokenHandlers["{Artist SortName}"] = m => Truncate(artist.SortName, m.CustomFormat); + tokenHandlers["{Artist CleanSortName}"] = m => Truncate(CleanTitle(artist.SortName), m.CustomFormat); tokenHandlers["{Artist NameThe}"] = m => Truncate(TitleThe(artist.Name), m.CustomFormat); tokenHandlers["{Artist CleanNameThe}"] = m => Truncate(CleanTitleThe(artist.Name), m.CustomFormat); tokenHandlers["{Artist Genre}"] = m => artist.Metadata.Value.Genres?.FirstOrDefault() ?? string.Empty; tokenHandlers["{Artist NameFirstCharacter}"] = m => TitleFirstCharacter(TitleThe(artist.Name)); + tokenHandlers["{Artist SortNameFirstCharacter}"] = m => TitleFirstCharacter(artist.SortName); tokenHandlers["{Artist MbId}"] = m => artist.ForeignArtistId ?? string.Empty; if (artist.Metadata.Value.Disambiguation != null)