Fixed: Include extension when calculating maximum episode title length when renaming files

Fixed: Option to override max filename length with MAX_NAME environment variable

(cherry picked from commit 6efee036a826027391433b7d0c954ebc1a75c679)
pull/3864/head
Taloth Saldono 4 years ago committed by Bogdan
parent f4292be588
commit c86d5980d3

@ -7,6 +7,7 @@ using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
@ -43,12 +44,8 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackFileMovingServiceTests
.Build();
Mocker.GetMock<IBuildFileNames>()
.Setup(s => s.BuildTrackFileName(It.IsAny<List<Track>>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.IsAny<TrackFile>(), null, null))
.Returns("Album\\File Name");
Mocker.GetMock<IBuildFileNames>()
.Setup(s => s.BuildTrackFilePath(It.IsAny<Artist>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(@"C:\Test\Music\Artist\Album\File Name.mp3".AsOsAgnostic());
.Setup(s => s.BuildTrackFilePath(It.IsAny<List<Track>>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.IsAny<TrackFile>(), It.IsAny<string>(), It.IsAny<NamingConfig>(), It.IsAny<List<CustomFormat>>()))
.Returns(@"C:\Test\Music\Artist\Album\File Name.mp3".AsOsAgnostic());
var rootFolder = @"C:\Test\Music\".AsOsAgnostic();
Mocker.GetMock<IDiskProvider>()

@ -1,6 +1,8 @@
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Music;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Test.Framework;
@ -9,7 +11,6 @@ using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.OrganizerTests
{
[TestFixture]
public class BuildFilePathFixture : CoreTest<FileNameBuilder>
{
private NamingConfig _namingConfig;
@ -29,12 +30,24 @@ namespace NzbDrone.Core.Test.OrganizerTests
var filename = @"02 - Track Title";
var expectedPath = @"C:\Test\Fake- The Artist\02 - Track Title.flac";
var fakeTracks = Builder<Track>.CreateListOfSize(1)
.All()
.With(s => s.Title = "Episode Title")
.With(s => s.AbsoluteTrackNumber = 5)
.Build().ToList();
var fakeArtist = Builder<Artist>.CreateNew()
.With(s => s.Name = "Fake: The Artist")
.With(s => s.Path = @"C:\Test\Fake- The Artist".AsOsAgnostic())
.Build();
var fakeAlbum = Builder<Album>.CreateNew()
.With(e => e.ArtistId = fakeArtist.Id)
.Build();
var fakeTrackFile = Builder<TrackFile>.CreateNew()
.With(s => s.SceneName = filename)
.With(f => f.Artist = fakeArtist)
.Build();
Subject.BuildTrackFilePath(fakeArtist, filename, ".flac").Should().Be(expectedPath.AsOsAgnostic());
Subject.BuildTrackFilePath(fakeTracks, fakeArtist, fakeAlbum, fakeTrackFile, ".flac").Should().Be(expectedPath.AsOsAgnostic());
}
}
}

@ -15,7 +15,6 @@ using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
{
[TestFixture]
public class FileNameBuilderFixture : CoreTest<FileNameBuilder>
{
private Artist _artist;
@ -511,6 +510,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
{
_namingConfig.RenameTracks = false;
_trackFile.Path = "Linkin Park - 06 - Test";
_trackFile.SceneName = null;
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
.Should().Be(Path.GetFileNameWithoutExtension(_trackFile.Path));
@ -520,11 +520,11 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
public void use_file_name_when_sceneName_is_not_null()
{
_namingConfig.RenameTracks = false;
_trackFile.SceneName = "Linkin.Park.06.FLAC-LOL";
_trackFile.Path = "Linkin Park - 06 - Test";
_trackFile.SceneName = "SceneName";
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
.Should().Be(Path.GetFileNameWithoutExtension(_trackFile.Path));
.Should().Be("Linkin.Park.06.FLAC-LOL");
}
[Test]
@ -532,6 +532,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
{
_namingConfig.RenameTracks = false;
_trackFile.Path = @"C:\Test\Unsorted\Artist - 01 - Test";
_trackFile.SceneName = null;
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
.Should().Be(Path.GetFileNameWithoutExtension(_trackFile.Path));

@ -109,6 +109,22 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
_trackFile.Quality.Revision.Version = 2;
}
[Test]
public void should_truncate_with_extension()
{
_artist.Name = "The Fantastic Life of Mr. Sisko";
_tracks[0].AbsoluteTrackNumber = 18;
_tracks[0].Title = "This title has to be 197 characters in length, combined with the series title, quality and episode number it becomes 254ish and the extension puts it above the 255 limit and triggers the truncation";
_trackFile.Quality.Quality = Quality.FLAC;
_tracks = _tracks.Take(1).ToList();
_namingConfig.StandardTrackFormat = "{Artist Name} - {Album Title} - {track:00} - {Track Title} [{Quality Title}]";
var result = Subject.BuildTrackFileName(_tracks, _artist, _album, _trackFile, ".flac");
result.Length.Should().BeLessOrEqualTo(255);
result.Should().Be("The Fantastic Life of Mr. Sisko - Hail to the King - 18 - This title has to be 197 characters in length, combined with the series title, quality and episode number it becomes 254ish and the extension puts it above the 255 limit and triggers... [FLAC].flac");
}
[Test]
public void should_truncate_with_ellipsis_between_first_and_last_episode_titles()
{

@ -91,9 +91,7 @@ namespace NzbDrone.Core.MediaFiles
}
var album = _albumService.GetAlbum(tracksInFile.First().AlbumId);
var newName = _filenameBuilder.BuildTrackFileName(tracksInFile, artist, album, file);
var newPath = _filenameBuilder.BuildTrackFilePath(artist, newName, Path.GetExtension(trackFilePath));
var newPath = _filenameBuilder.BuildTrackFilePath(tracksInFile, artist, album, file, Path.GetExtension(trackFilePath));
if (!trackFilePath.PathEquals(newPath, StringComparison.Ordinal))
{

@ -64,8 +64,7 @@ namespace NzbDrone.Core.MediaFiles
{
var tracks = _trackService.GetTracksByFileId(trackFile.Id);
var album = _albumService.GetAlbum(trackFile.AlbumId);
var newFileName = _buildFileNames.BuildTrackFileName(tracks, artist, album, trackFile);
var filePath = _buildFileNames.BuildTrackFilePath(artist, newFileName, Path.GetExtension(trackFile.Path));
var filePath = _buildFileNames.BuildTrackFilePath(tracks, artist, album, trackFile, Path.GetExtension(trackFile.Path));
EnsureTrackFolder(trackFile, artist, album, filePath);
@ -76,8 +75,7 @@ namespace NzbDrone.Core.MediaFiles
public TrackFile MoveTrackFile(TrackFile trackFile, LocalTrack localTrack)
{
var newFileName = _buildFileNames.BuildTrackFileName(localTrack.Tracks, localTrack.Artist, localTrack.Album, trackFile);
var filePath = _buildFileNames.BuildTrackFilePath(localTrack.Artist, newFileName, Path.GetExtension(localTrack.Path));
var filePath = _buildFileNames.BuildTrackFilePath(localTrack.Tracks, localTrack.Artist, localTrack.Album, trackFile, Path.GetExtension(trackFile.Path));
EnsureTrackFolder(trackFile, localTrack, filePath);
@ -88,8 +86,7 @@ namespace NzbDrone.Core.MediaFiles
public TrackFile CopyTrackFile(TrackFile trackFile, LocalTrack localTrack)
{
var newFileName = _buildFileNames.BuildTrackFileName(localTrack.Tracks, localTrack.Artist, localTrack.Album, trackFile);
var filePath = _buildFileNames.BuildTrackFilePath(localTrack.Artist, newFileName, Path.GetExtension(localTrack.Path));
var filePath = _buildFileNames.BuildTrackFilePath(localTrack.Tracks, localTrack.Artist, localTrack.Album, trackFile, Path.GetExtension(trackFile.Path));
EnsureTrackFolder(trackFile, localTrack, filePath);

@ -18,8 +18,8 @@ namespace NzbDrone.Core.Organizer
{
public interface IBuildFileNames
{
string BuildTrackFileName(List<Track> tracks, Artist artist, Album album, TrackFile trackFile, NamingConfig namingConfig = null, List<CustomFormat> customFormats = null);
string BuildTrackFilePath(Artist artist, string fileName, string extension);
string BuildTrackFileName(List<Track> tracks, Artist artist, Album album, TrackFile trackFile, string extension = "", NamingConfig namingConfig = null, List<CustomFormat> customFormats = null);
string BuildTrackFilePath(List<Track> tracks, Artist artist, Album album, TrackFile trackFile, string extension, NamingConfig namingConfig = null, List<CustomFormat> customFormats = null);
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
string GetArtistFolder(Artist artist, NamingConfig namingConfig = null);
}
@ -83,7 +83,7 @@ namespace NzbDrone.Core.Organizer
_logger = logger;
}
private string BuildTrackFileName(List<Track> tracks, Artist artist, Album album, TrackFile trackFile, int maxPath, NamingConfig namingConfig = null, List<CustomFormat> customFormats = null)
private string BuildTrackFileName(List<Track> tracks, Artist artist, Album album, TrackFile trackFile, string extension, int maxPath, NamingConfig namingConfig = null, List<CustomFormat> customFormats = null)
{
if (namingConfig == null)
{
@ -92,7 +92,7 @@ namespace NzbDrone.Core.Organizer
if (!namingConfig.RenameTracks)
{
return GetOriginalFileName(trackFile);
return GetOriginalTitle(trackFile) + extension;
}
if (namingConfig.StandardTrackFormat.IsNullOrWhiteSpace() || namingConfig.MultiDiscTrackFormat.IsNullOrWhiteSpace())
@ -112,9 +112,9 @@ namespace NzbDrone.Core.Organizer
var splitPatterns = pattern.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
var components = new List<string>();
foreach (var s in splitPatterns)
for (var i = 0; i < splitPatterns.Length; i++)
{
var splitPattern = s;
var splitPattern = splitPatterns[i];
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
splitPattern = FormatTrackNumberTokens(splitPattern, "", tracks);
splitPattern = FormatMediumNumberTokens(splitPattern, "", tracks);
@ -131,6 +131,10 @@ namespace NzbDrone.Core.Organizer
var component = ReplaceTokens(splitPattern, tokenHandlers, namingConfig, true).Trim();
var maxPathSegmentLength = Math.Min(LongPathSupport.MaxFileNameLength, maxPath);
if (i == splitPatterns.Length - 1)
{
maxPathSegmentLength -= extension.GetByteCount();
}
var maxTrackTitleLength = maxPathSegmentLength - GetLengthWithoutTrackTitle(component, namingConfig);
@ -147,21 +151,23 @@ namespace NzbDrone.Core.Organizer
}
}
return Path.Combine(components.ToArray());
return string.Join(Path.DirectorySeparatorChar.ToString(), components) + extension;
}
public string BuildTrackFileName(List<Track> tracks, Artist artist, Album album, TrackFile trackFile, NamingConfig namingConfig = null, List<CustomFormat> customFormats = null)
public string BuildTrackFileName(List<Track> tracks, Artist artist, Album album, TrackFile trackFile, string extension = "", NamingConfig namingConfig = null, List<CustomFormat> customFormats = null)
{
return BuildTrackFileName(tracks, artist, album, trackFile, LongPathSupport.MaxFilePathLength, namingConfig, customFormats);
return BuildTrackFileName(tracks, artist, album, trackFile, extension, LongPathSupport.MaxFilePathLength, namingConfig, customFormats);
}
public string BuildTrackFilePath(Artist artist, string fileName, string extension)
public string BuildTrackFilePath(List<Track> tracks, Artist artist, Album album, TrackFile trackFile, string extension, NamingConfig namingConfig = null, List<CustomFormat> customFormats = null)
{
Ensure.That(extension, () => extension).IsNotNullOrWhiteSpace();
var path = artist.Path;
var artistPath = artist.Path;
var remainingPathLength = LongPathSupport.MaxFilePathLength - artistPath.GetByteCount() - 1;
var fileName = BuildTrackFileName(tracks, artist, album, trackFile, extension, remainingPathLength, namingConfig, customFormats);
return Path.Combine(path, fileName + extension);
return Path.Combine(artistPath, fileName);
}
public BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec)

@ -177,7 +177,7 @@ namespace NzbDrone.Core.Organizer
{
try
{
return _buildFileNames.BuildTrackFileName(tracks, artist, album, trackFile, nameSpec, _customFormats);
return _buildFileNames.BuildTrackFileName(tracks, artist, album, trackFile, "", nameSpec, _customFormats);
}
catch (NamingFormatException)
{

Loading…
Cancel
Save