New: Token for track artist (as opposed to album artist) (#1910)

* New: Token for track artist (as opposed to album artist)

* - Move logic to AddTrackTokens instead of separate AddTrackArtistTokens method
- Just use the first artist name

* Update FIleNameSampleService to handle this token properly

* Fall back to album artist if there's no track artist

* Show tokens in naming modal
pull/2176/head
Daniel Lo Nigro 4 years ago committed by GitHub
parent f50556d4d5
commit 187672b183
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -82,6 +82,12 @@ const trackTitleTokens = [
{ token: '{Track CleanTitle}', example: 'Track Title' } { token: '{Track CleanTitle}', example: 'Track Title' }
]; ];
const trackArtistTokens = [
{ token: '{Track ArtistName}', example: 'Artist Name' },
{ token: '{Track ArtistNameThe}', example: 'Artist Name, The' },
{ token: '{Track ArtistCleanName}', example: 'Artist Name' }
];
const qualityTokens = [ const qualityTokens = [
{ token: '{Quality Full}', example: 'FLAC Proper' }, { token: '{Quality Full}', example: 'FLAC Proper' },
{ token: '{Quality Title}', example: 'FLAC' } { token: '{Quality Title}', example: 'FLAC' }
@ -411,6 +417,28 @@ class NamingModal extends Component {
</div> </div>
</FieldSet> </FieldSet>
<FieldSet legend="Track Artist">
<div className={styles.groups}>
{
trackArtistTokens.map(({ token, example }) => {
return (
<NamingOption
key={token}
name={name}
value={value}
token={token}
example={example}
tokenSeparator={tokenSeparator}
tokenCase={tokenCase}
onPress={this.onOptionPress}
/>
);
}
)
}
</div>
</FieldSet>
<FieldSet legend="Quality"> <FieldSet legend="Quality">
<div className={styles.groups}> <div className={styles.groups}>
{ {

@ -4,6 +4,7 @@ using System.Linq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Music; using NzbDrone.Core.Music;
using NzbDrone.Core.Organizer; using NzbDrone.Core.Organizer;
@ -17,10 +18,13 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
public class FileNameBuilderFixture : CoreTest<FileNameBuilder> public class FileNameBuilderFixture : CoreTest<FileNameBuilder>
{ {
private Artist _artist; private Artist _artist;
private Artist _variousArtists;
private Album _album; private Album _album;
private Album _mixAlbum;
private Medium _medium; private Medium _medium;
private AlbumRelease _release; private AlbumRelease _release;
private Track _track1; private Track _track1;
private Track _mixTrack1;
private TrackFile _trackFile; private TrackFile _trackFile;
private NamingConfig _namingConfig; private NamingConfig _namingConfig;
@ -37,6 +41,15 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
}) })
.Build(); .Build();
_variousArtists = Builder<Artist>
.CreateNew()
.With(s => s.Name = "Various Artists")
.With(s => s.Metadata = new ArtistMetadata
{
Name = "Various Artists"
})
.Build();
_medium = Builder<Medium> _medium = Builder<Medium>
.CreateNew() .CreateNew()
.With(m => m.Number = 3) .With(m => m.Number = 3)
@ -55,6 +68,12 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
.With(s => s.Disambiguation = "The Best Album") .With(s => s.Disambiguation = "The Best Album")
.Build(); .Build();
_mixAlbum = Builder<Album>
.CreateNew()
.With(s => s.Title = "Cool Music")
.With(s => s.AlbumType = "Album")
.Build();
_namingConfig = NamingConfig.Default; _namingConfig = NamingConfig.Default;
_namingConfig.RenameTracks = true; _namingConfig.RenameTracks = true;
@ -66,6 +85,15 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
.With(e => e.AbsoluteTrackNumber = 6) .With(e => e.AbsoluteTrackNumber = 6)
.With(e => e.AlbumRelease = _release) .With(e => e.AlbumRelease = _release)
.With(e => e.MediumNumber = _medium.Number) .With(e => e.MediumNumber = _medium.Number)
.With(e => e.ArtistMetadata = _artist.Metadata)
.Build();
_mixTrack1 = Builder<Track>.CreateNew()
.With(e => e.Title = "City Sushi")
.With(e => e.AbsoluteTrackNumber = 1)
.With(e => e.AlbumRelease = _release)
.With(e => e.MediumNumber = _medium.Number)
.With(e => e.ArtistMetadata = _artist.Metadata)
.Build(); .Build();
_trackFile = Builder<TrackFile>.CreateNew() _trackFile = Builder<TrackFile>.CreateNew()
@ -461,6 +489,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
.With(e => e.Title = "Part 1") .With(e => e.Title = "Part 1")
.With(e => e.AbsoluteTrackNumber = 6) .With(e => e.AbsoluteTrackNumber = 6)
.With(e => e.AlbumRelease = _release) .With(e => e.AlbumRelease = _release)
.With(e => e.ArtistMetadata = new ArtistMetadata { Name = "In The Woods." })
.Build(); .Build();
Subject.BuildTrackFileName(new List<Track> { track }, new Artist { Name = "In The Woods." }, new Album { Title = "30 Rock" }, _trackFile) Subject.BuildTrackFileName(new List<Track> { track }, new Artist { Name = "In The Woods." }, new Album { Title = "30 Rock" }, _trackFile)
@ -476,6 +505,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
.With(e => e.Title = "Part 1") .With(e => e.Title = "Part 1")
.With(e => e.AbsoluteTrackNumber = 6) .With(e => e.AbsoluteTrackNumber = 6)
.With(e => e.AlbumRelease = _release) .With(e => e.AlbumRelease = _release)
.With(e => e.ArtistMetadata = new ArtistMetadata { Name = "In The Woods..." })
.Build(); .Build();
Subject.BuildTrackFileName(new List<Track> { track }, new Artist { Name = "In The Woods..." }, new Album { Title = "30 Rock" }, _trackFile) Subject.BuildTrackFileName(new List<Track> { track }, new Artist { Name = "In The Woods..." }, new Album { Title = "30 Rock" }, _trackFile)
@ -648,5 +678,21 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile) Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
.Should().Be(releaseGroup); .Should().Be(releaseGroup);
} }
[Test]
public void should_replace_artist_name_for_Various_Artists_album()
{
_namingConfig.StandardTrackFormat = "{Artist Name}";
Subject.BuildTrackFileName(new List<Track> { _mixTrack1 }, _variousArtists, _mixAlbum, _trackFile)
.Should().Be("Various Artists");
}
[Test]
public void should_replace_track_artist_name_for_Various_Artists_album()
{
_namingConfig.StandardTrackFormat = "{Track ArtistName}";
Subject.BuildTrackFileName(new List<Track> { _mixTrack1 }, _variousArtists, _mixAlbum, _trackFile)
.Should().Be("Linkin Park");
}
} }
} }

@ -113,7 +113,7 @@ namespace NzbDrone.Core.Organizer
AddArtistTokens(tokenHandlers, artist); AddArtistTokens(tokenHandlers, artist);
AddAlbumTokens(tokenHandlers, album); AddAlbumTokens(tokenHandlers, album);
AddMediumTokens(tokenHandlers, tracks.First().AlbumRelease.Value.Media.SingleOrDefault(m => m.Number == tracks.First().MediumNumber)); AddMediumTokens(tokenHandlers, tracks.First().AlbumRelease.Value.Media.SingleOrDefault(m => m.Number == tracks.First().MediumNumber));
AddTrackTokens(tokenHandlers, tracks); AddTrackTokens(tokenHandlers, tracks, artist);
AddTrackFileTokens(tokenHandlers, trackFile); AddTrackFileTokens(tokenHandlers, trackFile);
AddQualityTokens(tokenHandlers, artist, trackFile); AddQualityTokens(tokenHandlers, artist, trackFile);
AddMediaInfoTokens(tokenHandlers, trackFile); AddMediaInfoTokens(tokenHandlers, trackFile);
@ -301,10 +301,21 @@ namespace NzbDrone.Core.Organizer
tokenHandlers["{Medium Format}"] = m => medium.Format; tokenHandlers["{Medium Format}"] = m => medium.Format;
} }
private void AddTrackTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, List<Track> tracks) private void AddTrackTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, List<Track> tracks, Artist artist)
{ {
tokenHandlers["{Track Title}"] = m => GetTrackTitle(tracks, "+"); tokenHandlers["{Track Title}"] = m => GetTrackTitle(tracks, "+");
tokenHandlers["{Track CleanTitle}"] = m => CleanTitle(GetTrackTitle(tracks, "and")); tokenHandlers["{Track CleanTitle}"] = m => CleanTitle(GetTrackTitle(tracks, "and"));
// Use the track's ArtistMetadata by default, as it will handle the "Various Artists" case
// (where the album artist is "Various Artists" but each track has its own artist). Fall back
// to the album artist if we don't have any track ArtistMetadata for whatever reason.
var firstArtist = tracks.Select(t => t.ArtistMetadata?.Value).FirstOrDefault() ?? artist.Metadata;
if (firstArtist != null)
{
tokenHandlers["{Track ArtistName}"] = m => firstArtist.Name;
tokenHandlers["{Track ArtistCleanName}"] = m => CleanTitle(firstArtist.Name);
tokenHandlers["{Track ArtistNameThe}"] = m => TitleThe(firstArtist.Name);
}
} }
private void AddTrackFileTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, TrackFile trackFile) private void AddTrackFileTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, TrackFile trackFile)

@ -29,14 +29,15 @@ namespace NzbDrone.Core.Organizer
public FileNameSampleService(IBuildFileNames buildFileNames) public FileNameSampleService(IBuildFileNames buildFileNames)
{ {
_buildFileNames = buildFileNames; _buildFileNames = buildFileNames;
var artistMetadata = new ArtistMetadata
_standardArtist = new Artist
{
Metadata = new ArtistMetadata
{ {
Name = "The Artist Name", Name = "The Artist Name",
Disambiguation = "US Rock Band" Disambiguation = "US Rock Band"
} };
_standardArtist = new Artist
{
Metadata = artistMetadata
}; };
_standardAlbum = new Album _standardAlbum = new Album
@ -86,8 +87,10 @@ namespace NzbDrone.Core.Organizer
_track1 = new Track _track1 = new Track
{ {
AlbumRelease = _singleRelease, AlbumRelease = _singleRelease,
Artist = _standardArtist,
AbsoluteTrackNumber = 3, AbsoluteTrackNumber = 3,
MediumNumber = 1, MediumNumber = 1,
ArtistMetadata = artistMetadata,
Title = "Track Title (1)", Title = "Track Title (1)",
}; };

Loading…
Cancel
Save