New: Seperate Naming for Multi-Disc Albums

pull/954/head
Qstick 5 years ago
parent 4edad5f563
commit 1425bc8bd9

@ -40,6 +40,18 @@ class Naming extends Component {
});
}
onMultiDiscNamingModalOpenClick = () => {
this.setState({
isNamingModalOpen: true,
namingModalOptions: {
name: 'multiDiscTrackFormat',
album: true,
track: true,
additional: true
}
});
}
onArtistFolderNamingModalOpenClick = () => {
this.setState({
isNamingModalOpen: true,
@ -87,6 +99,8 @@ class Naming extends Component {
const standardTrackFormatHelpTexts = [];
const standardTrackFormatErrors = [];
const multiDiscTrackFormatHelpTexts = [];
const multiDiscTrackFormatErrors = [];
const artistFolderFormatHelpTexts = [];
const artistFolderFormatErrors = [];
const albumFolderFormatHelpTexts = [];
@ -99,6 +113,12 @@ class Naming extends Component {
standardTrackFormatErrors.push({ message: 'Single Track: Invalid Format' });
}
if (examples.multiDiscTrackExample) {
multiDiscTrackFormatHelpTexts.push(`Multi Disc Track: ${examples.multiDiscTrackExample}`);
} else {
multiDiscTrackFormatErrors.push({ message: 'Single Track: Invalid Format' });
}
if (examples.artistFolderExample) {
artistFolderFormatHelpTexts.push(`Example: ${examples.artistFolderExample}`);
} else {
@ -169,6 +189,21 @@ class Naming extends Component {
/>
</FormGroup>
<FormGroup size={sizes.LARGE}>
<FormLabel>Multi Disc Track Format</FormLabel>
<FormInputGroup
inputClassName={styles.namingInput}
type={inputTypes.TEXT}
name="multiDiscTrackFormat"
buttons={<FormInputButton onPress={this.onMultiDiscNamingModalOpenClick}>?</FormInputButton>}
onChange={onInputChange}
{...settings.multiDiscTrackFormat}
helpTexts={multiDiscTrackFormatHelpTexts}
errors={[...multiDiscTrackFormatErrors, ...settings.multiDiscTrackFormat.errors]}
/>
</FormGroup>
</div>
}

@ -37,6 +37,7 @@ namespace Lidarr.Api.V1.Config
SharedValidator.RuleFor(c => c.StandardTrackFormat).ValidTrackFormat();
SharedValidator.RuleFor(c => c.MultiDiscTrackFormat).ValidTrackFormat();
SharedValidator.RuleFor(c => c.ArtistFolderFormat).ValidArtistFolderFormat();
SharedValidator.RuleFor(c => c.AlbumFolderFormat).ValidAlbumFolderFormat();
}
@ -60,6 +61,12 @@ namespace Lidarr.Api.V1.Config
basicConfig.AddToResource(resource);
}
if (resource.MultiDiscTrackFormat.IsNotNullOrWhiteSpace())
{
var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
basicConfig.AddToResource(resource);
}
return resource;
}
@ -79,11 +86,16 @@ namespace Lidarr.Api.V1.Config
var sampleResource = new NamingExampleResource();
var singleTrackSampleResult = _filenameSampleService.GetStandardTrackSample(nameSpec);
var multiDiscTrackSampleResult = _filenameSampleService.GetMultiDiscTrackSample(nameSpec);
sampleResource.SingleTrackExample = _filenameValidationService.ValidateTrackFilename(singleTrackSampleResult) != null
? null
: singleTrackSampleResult.FileName;
sampleResource.MultiDiscTrackExample = _filenameValidationService.ValidateTrackFilename(multiDiscTrackSampleResult) != null
? null
: multiDiscTrackSampleResult.FileName;
sampleResource.ArtistFolderExample = nameSpec.ArtistFolderFormat.IsNullOrWhiteSpace()
? null
: _filenameSampleService.GetArtistFolderSample(nameSpec);

@ -7,6 +7,7 @@ namespace Lidarr.Api.V1.Config
public bool RenameTracks { get; set; }
public bool ReplaceIllegalCharacters { get; set; }
public string StandardTrackFormat { get; set; }
public string MultiDiscTrackFormat { get; set; }
public string ArtistFolderFormat { get; set; }
public string AlbumFolderFormat { get; set; }
public bool IncludeArtistName { get; set; }

@ -5,6 +5,7 @@ namespace Lidarr.Api.V1.Config
public class NamingExampleResource
{
public string SingleTrackExample { get; set; }
public string MultiDiscTrackExample { get; set; }
public string ArtistFolderExample { get; set; }
public string AlbumFolderExample { get; set; }
}
@ -20,6 +21,7 @@ namespace Lidarr.Api.V1.Config
RenameTracks = model.RenameTracks,
ReplaceIllegalCharacters = model.ReplaceIllegalCharacters,
StandardTrackFormat = model.StandardTrackFormat,
MultiDiscTrackFormat = model.MultiDiscTrackFormat,
ArtistFolderFormat = model.ArtistFolderFormat,
AlbumFolderFormat = model.AlbumFolderFormat
};
@ -44,6 +46,7 @@ namespace Lidarr.Api.V1.Config
RenameTracks = resource.RenameTracks,
ReplaceIllegalCharacters = resource.ReplaceIllegalCharacters,
StandardTrackFormat = resource.StandardTrackFormat,
MultiDiscTrackFormat = resource.MultiDiscTrackFormat,
ArtistFolderFormat = resource.ArtistFolderFormat,
AlbumFolderFormat = resource.AlbumFolderFormat

@ -0,0 +1,17 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
using System.Data;
using System.IO;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(35)]
public class multi_disc_naming_format : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("NamingConfig").AddColumn("MultiDiscTrackFormat").AsString().Nullable();
Execute.Sql("UPDATE NamingConfig SET MultiDiscTrackFormat = '{Medium Format} {medium:00}/{Artist Name} - {Album Title} - {track:00} - {Track Title}'");
}
}
}

@ -1,10 +0,0 @@
namespace NzbDrone.Core.Organizer
{
public class EpisodeSortingType
{
public int Id { get; set; }
public string Name { get; set; }
public string Pattern { get; set; }
public string EpisodeSeparator { get; set; }
}
}

@ -66,7 +66,7 @@ namespace NzbDrone.Core.Organizer
//TODO: Support Written numbers (One, Two, etc) and Roman Numerals (I, II, III etc)
private static readonly Regex MultiPartCleanupRegex = new Regex(@"(?:\(\d+\)|(Part|Pt\.?)\s?\d+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly char[] EpisodeTitleTrimCharacters = new[] { ' ', '.', '?' };
private static readonly char[] TrackTitleTrimCharacters = new[] { ' ', '.', '?' };
private static readonly Regex TitlePrefixRegex = new Regex(@"^(The|An|A) (.*?)((?: *\([^)]+\))*)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
@ -96,18 +96,27 @@ namespace NzbDrone.Core.Organizer
return GetOriginalFileName(trackFile);
}
if (namingConfig.StandardTrackFormat.IsNullOrWhiteSpace())
if (namingConfig.StandardTrackFormat.IsNullOrWhiteSpace() || namingConfig.MultiDiscTrackFormat.IsNullOrWhiteSpace())
{
throw new NamingFormatException("Standard track format cannot be empty");
throw new NamingFormatException("Standard and Multi track formats cannot be empty");
}
var pattern = namingConfig.StandardTrackFormat;
if (tracks.First().AlbumRelease.Value.Media.Count() > 1)
{
pattern = namingConfig.MultiDiscTrackFormat;
}
var subFolders = pattern.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
var safePattern = subFolders.Aggregate("", (current, folderLevel) => Path.Combine(current, (folderLevel)));
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
tracks = tracks.OrderBy(e => e.AlbumReleaseId).ThenBy(e => e.TrackNumber).ToList();
pattern = FormatTrackNumberTokens(pattern, "", tracks);
pattern = FormatMediumNumberTokens(pattern, "", tracks);
safePattern = FormatTrackNumberTokens(safePattern, "", tracks);
safePattern = FormatMediumNumberTokens(safePattern, "", tracks);
AddArtistTokens(tokenHandlers, artist);
AddAlbumTokens(tokenHandlers, album);
@ -118,7 +127,7 @@ namespace NzbDrone.Core.Organizer
AddMediaInfoTokens(tokenHandlers, trackFile);
AddPreferredWords(tokenHandlers, artist, trackFile, preferredWords);
var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim();
var fileName = ReplaceTokens(safePattern, tokenHandlers, namingConfig).Trim();
fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString());
fileName = TrimSeparatorsRegex.Replace(fileName, string.Empty);
@ -315,12 +324,12 @@ namespace NzbDrone.Core.Organizer
private void AddQualityTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Artist artist, TrackFile trackFile)
{
var qualityTitle = _qualityDefinitionService.Get(trackFile.Quality.Quality).Title;
//var qualityProper = GetQualityProper(artist, trackFile.Quality);
var qualityProper = GetQualityProper(trackFile.Quality);
//var qualityReal = GetQualityReal(artist, trackFile.Quality);
tokenHandlers["{Quality Full}"] = m => String.Format("{0}", qualityTitle);
tokenHandlers["{Quality Title}"] = m => qualityTitle;
//tokenHandlers["{Quality Proper}"] = m => qualityProper;
tokenHandlers["{Quality Proper}"] = m => qualityProper;
//tokenHandlers["{Quality Real}"] = m => qualityReal;
}
@ -459,17 +468,17 @@ namespace NzbDrone.Core.Organizer
if (tracks.Count == 1)
{
return tracks.First().Title.TrimEnd(EpisodeTitleTrimCharacters);
return tracks.First().Title.TrimEnd(TrackTitleTrimCharacters);
}
var titles = tracks.Select(c => c.Title.TrimEnd(EpisodeTitleTrimCharacters))
var titles = tracks.Select(c => c.Title.TrimEnd(TrackTitleTrimCharacters))
.Select(CleanupTrackTitle)
.Distinct()
.ToList();
if (titles.All(t => t.IsNullOrWhiteSpace()))
{
titles = tracks.Select(c => c.Title.TrimEnd(EpisodeTitleTrimCharacters))
titles = tracks.Select(c => c.Title.TrimEnd(TrackTitleTrimCharacters))
.Distinct()
.ToList();
}
@ -483,21 +492,20 @@ namespace NzbDrone.Core.Organizer
return MultiPartCleanupRegex.Replace(title, string.Empty).Trim();
}
// TODO: DO WE NEED FOR MUSIC?
//private string GetQualityProper(Series series, QualityModel quality)
//{
// if (quality.Revision.Version > 1)
// {
// if (series.SeriesType == SeriesTypes.Anime)
// {
// return "v" + quality.Revision.Version;
// }
private string GetQualityProper(QualityModel quality)
{
if (quality.Revision.Version > 1)
{
if (quality.Revision.IsRepack)
{
return "Repack";
}
// return "Proper";
// }
return "Proper";
}
// return String.Empty;
//}
return String.Empty;
}
//private string GetQualityReal(Series series, QualityModel quality)
//{

@ -9,7 +9,7 @@ namespace NzbDrone.Core.Organizer
public interface IFilenameSampleService
{
SampleResult GetStandardTrackSample(NamingConfig nameSpec);
SampleResult GetMultiDiscTrackSample(NamingConfig nameSpec);
string GetArtistFolderSample(NamingConfig nameSpec);
string GetAlbumFolderSample(NamingConfig nameSpec);
}
@ -20,6 +20,8 @@ namespace NzbDrone.Core.Organizer
private static Artist _standardArtist;
private static Album _standardAlbum;
private static AlbumRelease _singleRelease;
private static AlbumRelease _multiRelease;
private static Track _track1;
private static List<Track> _singleTrack;
private static TrackFile _singleTrackFile;
@ -47,7 +49,7 @@ namespace NzbDrone.Core.Organizer
Disambiguation = "The Best Album",
};
var _release = new AlbumRelease
_singleRelease = new AlbumRelease
{
Album = _standardAlbum,
Media = new List<Medium>
@ -62,9 +64,30 @@ namespace NzbDrone.Core.Organizer
Monitored = true
};
_multiRelease = new AlbumRelease
{
Album = _standardAlbum,
Media = new List<Medium>
{
new Medium
{
Name = "CD 1: First Years",
Format = "CD",
Number = 1
},
new Medium
{
Name = "CD 2: Second Best",
Format = "CD",
Number = 2
}
},
Monitored = true
};
_track1 = new Track
{
AlbumRelease = _release,
AlbumRelease = _singleRelease,
AbsoluteTrackNumber = 3,
MediumNumber = 1,
@ -102,6 +125,24 @@ namespace NzbDrone.Core.Organizer
public SampleResult GetStandardTrackSample(NamingConfig nameSpec)
{
_track1.AlbumRelease = _singleRelease;
var result = new SampleResult
{
FileName = BuildTrackSample(_singleTrack, _standardArtist, _standardAlbum, _singleTrackFile, nameSpec),
Artist = _standardArtist,
Album = _standardAlbum,
Tracks = _singleTrack,
TrackFile = _singleTrackFile
};
return result;
}
public SampleResult GetMultiDiscTrackSample(NamingConfig nameSpec)
{
_track1.AlbumRelease = _multiRelease;
var result = new SampleResult
{
FileName = BuildTrackSample(_singleTrack, _standardArtist, _standardAlbum, _singleTrackFile, nameSpec),

@ -9,6 +9,7 @@ namespace NzbDrone.Core.Organizer
RenameTracks = false,
ReplaceIllegalCharacters = true,
StandardTrackFormat = "{Artist Name} - {Album Title} - {track:00} - {Track Title}",
MultiDiscTrackFormat = "{Medium Format} {medium:00}/{Artist Name} - {Album Title} - {track:00} - {Track Title}",
ArtistFolderFormat = "{Artist Name}",
AlbumFolderFormat = "{Album Title} ({Release Year})"
};
@ -16,6 +17,7 @@ namespace NzbDrone.Core.Organizer
public bool RenameTracks { get; set; }
public bool ReplaceIllegalCharacters { get; set; }
public string StandardTrackFormat { get; set; }
public string MultiDiscTrackFormat { get; set; }
public string ArtistFolderFormat { get; set; }
public string AlbumFolderFormat { get; set; }
}

Loading…
Cancel
Save