mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-24 07:15:20 -07:00
Add multi-disc support for single file releases.
Add a cue sheet class. Enable track selection for single file releases. (cherry picked from commit 430807a3046f8bb4c36301278ff31fc9a1d3987d)
This commit is contained in:
parent
16a3fbe25b
commit
c87efacb6a
12 changed files with 154 additions and 120 deletions
|
@ -65,7 +65,6 @@ class InteractiveImportRow extends Component {
|
||||||
album,
|
album,
|
||||||
tracks,
|
tracks,
|
||||||
isSingleFileRelease,
|
isSingleFileRelease,
|
||||||
cuesheetPath,
|
|
||||||
quality,
|
quality,
|
||||||
isSelected,
|
isSelected,
|
||||||
onValidRowChange
|
onValidRowChange
|
||||||
|
@ -84,7 +83,7 @@ class InteractiveImportRow extends Component {
|
||||||
const isValid = !!(
|
const isValid = !!(
|
||||||
artist &&
|
artist &&
|
||||||
album &&
|
album &&
|
||||||
((isSingleFileRelease && cuesheetPath) || tracks.length) &&
|
(isSingleFileRelease || tracks.length) &&
|
||||||
quality
|
quality
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -261,7 +260,7 @@ class InteractiveImportRow extends Component {
|
||||||
</TableRowCellButton>
|
</TableRowCellButton>
|
||||||
|
|
||||||
<TableRowCellButton
|
<TableRowCellButton
|
||||||
isDisabled={!artist || !album || isSingleFileRelease}
|
isDisabled={!artist || !album}
|
||||||
title={artist && album ? translate('ArtistAlbumClickToChangeTrack') : undefined}
|
title={artist && album ? translate('ArtistAlbumClickToChangeTrack') : undefined}
|
||||||
onPress={this.onSelectTrackPress}
|
onPress={this.onSelectTrackPress}
|
||||||
>
|
>
|
||||||
|
@ -269,7 +268,7 @@ class InteractiveImportRow extends Component {
|
||||||
showTrackNumbersLoading && <LoadingIndicator size={20} className={styles.loading} />
|
showTrackNumbersLoading && <LoadingIndicator size={20} className={styles.loading} />
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
!isSingleFileRelease && showTrackNumbersPlaceholder ? <InteractiveImportRowCellPlaceholder /> : trackNumbers
|
showTrackNumbersPlaceholder ? <InteractiveImportRowCellPlaceholder /> : trackNumbers
|
||||||
}
|
}
|
||||||
|
|
||||||
</TableRowCellButton>
|
</TableRowCellButton>
|
||||||
|
|
80
src/NzbDrone.Core/MediaFiles/CueSheet.cs
Normal file
80
src/NzbDrone.Core/MediaFiles/CueSheet.cs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO.Abstractions;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles
|
||||||
|
{
|
||||||
|
public class CueSheet : ModelBase
|
||||||
|
{
|
||||||
|
public CueSheet(IFileInfo fileInfo)
|
||||||
|
{
|
||||||
|
using (var fs = fileInfo.OpenRead())
|
||||||
|
{
|
||||||
|
var bytes = new byte[fileInfo.Length];
|
||||||
|
var encoding = new UTF8Encoding(true);
|
||||||
|
string content;
|
||||||
|
while (fs.Read(bytes, 0, bytes.Length) > 0)
|
||||||
|
{
|
||||||
|
content = encoding.GetString(bytes);
|
||||||
|
var lines = content.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
|
||||||
|
|
||||||
|
// Single-file cue means it's an unsplit image
|
||||||
|
var fileNames = ReadFieldFromCuesheet(lines, "FILE");
|
||||||
|
IsSingleFileRelease = fileNames.Count == 1;
|
||||||
|
FileName = fileNames[0];
|
||||||
|
|
||||||
|
var performers = ReadFieldFromCuesheet(lines, "PERFORMER");
|
||||||
|
if (performers.Count > 0)
|
||||||
|
{
|
||||||
|
Performer = performers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var titles = ReadFieldFromCuesheet(lines, "TITLE");
|
||||||
|
if (titles.Count > 0)
|
||||||
|
{
|
||||||
|
Title = titles[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
Date = ReadOptionalFieldFromCuesheet(lines, "REM DATE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSingleFileRelease { get; set; }
|
||||||
|
public string FileName { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Performer { get; set; }
|
||||||
|
public string Date { get; set; }
|
||||||
|
|
||||||
|
private static List<string> ReadFieldFromCuesheet(string[] lines, string fieldName)
|
||||||
|
{
|
||||||
|
var results = new List<string>();
|
||||||
|
var candidates = lines.Where(l => l.StartsWith(fieldName)).ToList();
|
||||||
|
foreach (var candidate in candidates)
|
||||||
|
{
|
||||||
|
var matches = Regex.Matches(candidate, "\"(.*?)\"");
|
||||||
|
var result = matches.ToList()[0].Groups[1].Value;
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadOptionalFieldFromCuesheet(string[] lines, string fieldName)
|
||||||
|
{
|
||||||
|
var results = lines.Where(l => l.StartsWith(fieldName));
|
||||||
|
if (results.Any())
|
||||||
|
{
|
||||||
|
var matches = Regex.Matches(results.ToList()[0], fieldName + " (.+)");
|
||||||
|
var result = matches.ToList()[0].Groups[1].Value;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -65,13 +65,18 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Aggregation.Aggregators
|
||||||
|| tracks.Any(x => x.FileTrackInfo.DiscNumber == 0))
|
|| tracks.Any(x => x.FileTrackInfo.DiscNumber == 0))
|
||||||
{
|
{
|
||||||
_logger.Debug("Missing data in tags, trying filename augmentation");
|
_logger.Debug("Missing data in tags, trying filename augmentation");
|
||||||
if (tracks.Count == 1 && tracks[0].IsSingleFileRelease)
|
if (release.IsSingleFileRelease)
|
||||||
{
|
{
|
||||||
tracks[0].FileTrackInfo.ArtistTitle = tracks[0].Artist.Name;
|
for (var i = 0; i < tracks.Count; ++i)
|
||||||
tracks[0].FileTrackInfo.AlbumTitle = tracks[0].Album.Title;
|
{
|
||||||
|
tracks[i].FileTrackInfo.ArtistTitle = tracks[i].Artist.Name;
|
||||||
|
tracks[i].FileTrackInfo.AlbumTitle = tracks[i].Album.Title;
|
||||||
|
tracks[i].FileTrackInfo.DiscNumber = i + 1;
|
||||||
|
tracks[i].FileTrackInfo.DiscCount = tracks.Count;
|
||||||
|
|
||||||
// TODO this is too bold, the release year is not the one from the .cue file
|
// TODO this is too bold, the release year is not the one from the .cue file
|
||||||
tracks[0].FileTrackInfo.Year = (uint)tracks[0].Album.ReleaseDate.Value.Year;
|
tracks[i].FileTrackInfo.Year = (uint)tracks[i].Album.ReleaseDate.Value.Year;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -131,11 +131,11 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Identification
|
||||||
|
|
||||||
private List<CandidateAlbumRelease> GetDbCandidatesByAlbum(LocalAlbumRelease localAlbumRelease, Album album, bool includeExisting)
|
private List<CandidateAlbumRelease> GetDbCandidatesByAlbum(LocalAlbumRelease localAlbumRelease, Album album, bool includeExisting)
|
||||||
{
|
{
|
||||||
if (localAlbumRelease.LocalTracks.Count == 1 && localAlbumRelease.LocalTracks[0].IsSingleFileRelease)
|
if (localAlbumRelease.IsSingleFileRelease)
|
||||||
{
|
{
|
||||||
return GetDbCandidatesByRelease(_releaseService.GetReleasesByAlbum(album.Id)
|
return GetDbCandidatesByRelease(_releaseService.GetReleasesByAlbum(album.Id)
|
||||||
.OrderBy(x => x.ReleaseDate)
|
.OrderBy(x => x.ReleaseDate)
|
||||||
.ToList(), includeExisting);
|
.ToList(), includeExisting);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort candidate releases by closest track count so that we stand a chance of
|
// sort candidate releases by closest track count so that we stand a chance of
|
||||||
|
|
|
@ -120,7 +120,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Identification
|
||||||
var releaseYear = release.ReleaseDate?.Year ?? 0;
|
var releaseYear = release.ReleaseDate?.Year ?? 0;
|
||||||
|
|
||||||
// The single file version's year is from the album year already, to avoid false positives here we consider it's always different
|
// The single file version's year is from the album year already, to avoid false positives here we consider it's always different
|
||||||
var isSameWithAlbumYear = (localTracks.Count == 1 && localTracks[0].IsSingleFileRelease) ? false : localYear == albumYear;
|
var isSameWithAlbumYear = localTracks.All(x => x.IsSingleFileRelease == true) ? false : localYear == albumYear;
|
||||||
if (isSameWithAlbumYear || localYear == releaseYear)
|
if (isSameWithAlbumYear || localYear == releaseYear)
|
||||||
{
|
{
|
||||||
dist.Add("year", 0.0);
|
dist.Add("year", 0.0);
|
||||||
|
@ -179,7 +179,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Identification
|
||||||
}
|
}
|
||||||
|
|
||||||
// tracks
|
// tracks
|
||||||
if (localTracks.Count == 1 && localTracks[0].IsSingleFileRelease)
|
if (localTracks.All(x => x.IsSingleFileRelease == true))
|
||||||
{
|
{
|
||||||
dist.Add("tracks", 0);
|
dist.Add("tracks", 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Identification
|
||||||
|
|
||||||
private bool ShouldFingerprint(LocalAlbumRelease localAlbumRelease)
|
private bool ShouldFingerprint(LocalAlbumRelease localAlbumRelease)
|
||||||
{
|
{
|
||||||
if (localAlbumRelease.LocalTracks.Count == 1 && localAlbumRelease.LocalTracks[0].IsSingleFileRelease)
|
if (localAlbumRelease.IsSingleFileRelease)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -340,10 +340,18 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Identification
|
||||||
localAlbumRelease.AlbumRelease = release;
|
localAlbumRelease.AlbumRelease = release;
|
||||||
localAlbumRelease.ExistingTracks = extraTracks;
|
localAlbumRelease.ExistingTracks = extraTracks;
|
||||||
localAlbumRelease.TrackMapping = mapping;
|
localAlbumRelease.TrackMapping = mapping;
|
||||||
if (localAlbumRelease.LocalTracks.Count == 1 && localAlbumRelease.LocalTracks[0].IsSingleFileRelease)
|
if (localAlbumRelease.IsSingleFileRelease)
|
||||||
{
|
{
|
||||||
localAlbumRelease.LocalTracks[0].Tracks = release.Tracks;
|
localAlbumRelease.LocalTracks.ForEach(x => x.Tracks.Clear());
|
||||||
localAlbumRelease.LocalTracks[0].Tracks.ForEach(x => x.IsSingleFileRelease = true);
|
for (var i = 0; i < release.Tracks.Value.Count; i++)
|
||||||
|
{
|
||||||
|
var track = release.Tracks.Value[i];
|
||||||
|
var localTrackIndex = localAlbumRelease.LocalTracks.FindIndex(x => x.FileTrackInfo.DiscNumber == track.MediumNumber);
|
||||||
|
if (localTrackIndex != -1)
|
||||||
|
{
|
||||||
|
localAlbumRelease.LocalTracks[localTrackIndex].Tracks.Add(track);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currDistance == 0.0)
|
if (currDistance == 0.0)
|
||||||
|
@ -360,10 +368,9 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Identification
|
||||||
public TrackMapping MapReleaseTracks(List<LocalTrack> localTracks, List<Track> mbTracks)
|
public TrackMapping MapReleaseTracks(List<LocalTrack> localTracks, List<Track> mbTracks)
|
||||||
{
|
{
|
||||||
var result = new TrackMapping();
|
var result = new TrackMapping();
|
||||||
if (localTracks.Count == 1 && localTracks[0].IsSingleFileRelease)
|
result.IsSingleFileRelease = localTracks.All(x => x.IsSingleFileRelease == true);
|
||||||
|
if (result.IsSingleFileRelease)
|
||||||
{
|
{
|
||||||
result.IsSingleFileRelease = true;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Abstractions;
|
using System.IO.Abstractions;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Common.Crypto;
|
using NzbDrone.Common.Crypto;
|
||||||
|
@ -134,33 +132,6 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
||||||
return ProcessFolder(path, downloadId, artist, filter, replaceExistingFiles);
|
return ProcessFolder(path, downloadId, artist, filter, replaceExistingFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<string> ReadFieldFromCuesheet(string[] lines, string fieldName)
|
|
||||||
{
|
|
||||||
var results = new List<string>();
|
|
||||||
var candidates = lines.Where(l => l.StartsWith(fieldName)).ToList();
|
|
||||||
foreach (var candidate in candidates)
|
|
||||||
{
|
|
||||||
var matches = Regex.Matches(candidate, "\"(.*?)\"");
|
|
||||||
var result = matches.ToList()[0].Groups[1].Value;
|
|
||||||
results.Add(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReadOptionalFieldFromCuesheet(string[] lines, string fieldName)
|
|
||||||
{
|
|
||||||
var results = lines.Where(l => l.StartsWith(fieldName));
|
|
||||||
if (results.Any())
|
|
||||||
{
|
|
||||||
var matches = Regex.Matches(results.ToList()[0], fieldName + " (.+)");
|
|
||||||
var result = matches.ToList()[0].Groups[1].Value;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ManualImportItem> ProcessFolder(string folder, string downloadId, Artist artist, FilterFilesType filter, bool replaceExistingFiles)
|
private List<ManualImportItem> ProcessFolder(string folder, string downloadId, Artist artist, FilterFilesType filter, bool replaceExistingFiles)
|
||||||
{
|
{
|
||||||
DownloadClientItem downloadClientItem = null;
|
DownloadClientItem downloadClientItem = null;
|
||||||
|
@ -186,65 +157,31 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
||||||
audioFiles.RemoveAll(l => cueFiles.Contains(l));
|
audioFiles.RemoveAll(l => cueFiles.Contains(l));
|
||||||
foreach (var cueFile in cueFiles)
|
foreach (var cueFile in cueFiles)
|
||||||
{
|
{
|
||||||
// TODO move this to the disk service
|
var cueSheet = new CueSheet(cueFile);
|
||||||
using (var fs = cueFile.OpenRead())
|
|
||||||
|
Artist artistFromCue = null;
|
||||||
|
if (!cueSheet.Performer.Empty())
|
||||||
{
|
{
|
||||||
var bytes = new byte[cueFile.Length];
|
artistFromCue = _parsingService.GetArtist(cueSheet.Performer);
|
||||||
var encoding = new UTF8Encoding(true);
|
|
||||||
string content;
|
|
||||||
while (fs.Read(bytes, 0, bytes.Length) > 0)
|
|
||||||
{
|
|
||||||
content = encoding.GetString(bytes);
|
|
||||||
var lines = content.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
|
|
||||||
|
|
||||||
// Single-file cue means it's an unsplit image
|
|
||||||
var fileNames = ReadFieldFromCuesheet(lines, "FILE");
|
|
||||||
if (fileNames.Empty() || fileNames.Count > 1)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileName = fileNames[0];
|
|
||||||
if (!fileName.Empty())
|
|
||||||
{
|
|
||||||
Artist artistFromCue = null;
|
|
||||||
var artistNames = ReadFieldFromCuesheet(lines, "PERFORMER");
|
|
||||||
if (artistNames.Count > 0)
|
|
||||||
{
|
|
||||||
artistFromCue = _parsingService.GetArtist(artistNames[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
string albumTitle = null;
|
|
||||||
var albumTitles = ReadFieldFromCuesheet(lines, "TITLE");
|
|
||||||
if (artistNames.Count > 0)
|
|
||||||
{
|
|
||||||
albumTitle = albumTitles[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
var date = ReadOptionalFieldFromCuesheet(lines, "REM DATE");
|
|
||||||
var audioFile = audioFiles.Find(x => x.Name == fileName && x.DirectoryName == cueFile.DirectoryName);
|
|
||||||
var parsedAlbumInfo = new ParsedAlbumInfo
|
|
||||||
{
|
|
||||||
AlbumTitle = albumTitle,
|
|
||||||
ArtistName = artistFromCue.Name,
|
|
||||||
ReleaseDate = date,
|
|
||||||
};
|
|
||||||
var albumsFromCue = _parsingService.GetAlbums(parsedAlbumInfo, artistFromCue);
|
|
||||||
if (albumsFromCue == null || albumsFromCue.Count == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tempAudioFiles = new List<IFileInfo>
|
|
||||||
{
|
|
||||||
audioFile
|
|
||||||
};
|
|
||||||
|
|
||||||
results.AddRange(ProcessFolder(downloadId, artistFromCue, albumsFromCue[0], filter, replaceExistingFiles, downloadClientItem, albumTitle, tempAudioFiles, cueFile.FullName));
|
|
||||||
audioFiles.Remove(audioFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var audioFile = audioFiles.Find(x => x.Name == cueSheet.FileName && x.DirectoryName == cueFile.DirectoryName);
|
||||||
|
var parsedAlbumInfo = new ParsedAlbumInfo
|
||||||
|
{
|
||||||
|
AlbumTitle = cueSheet.Title,
|
||||||
|
ArtistName = artistFromCue.Name,
|
||||||
|
ReleaseDate = cueSheet.Date,
|
||||||
|
};
|
||||||
|
var albumsFromCue = _parsingService.GetAlbums(parsedAlbumInfo, artistFromCue);
|
||||||
|
if (albumsFromCue == null || albumsFromCue.Count == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tempAudioFiles = new List<IFileInfo> { audioFile };
|
||||||
|
|
||||||
|
results.AddRange(ProcessFolder(downloadId, artistFromCue, albumsFromCue[0], filter, replaceExistingFiles, downloadClientItem, cueSheet.Title, tempAudioFiles, cueFile.FullName));
|
||||||
|
audioFiles.Remove(audioFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
results.AddRange(ProcessFolder(downloadId, artist, null, filter, replaceExistingFiles, downloadClientItem, directoryInfo.Name, audioFiles, string.Empty));
|
results.AddRange(ProcessFolder(downloadId, artist, null, filter, replaceExistingFiles, downloadClientItem, directoryInfo.Name, audioFiles, string.Empty));
|
||||||
|
@ -322,7 +259,14 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
||||||
IncludeExisting = !replaceExistingFiles,
|
IncludeExisting = !replaceExistingFiles,
|
||||||
AddNewArtists = false
|
AddNewArtists = false
|
||||||
};
|
};
|
||||||
var decisions = _importDecisionMaker.GetImportDecisions(files, idOverride, null, config);
|
|
||||||
|
var itemInfo = new ImportDecisionMakerInfo
|
||||||
|
{
|
||||||
|
IsSingleFileRelease = group.All(x => x.IsSingleFileRelease == true)
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO support with the cuesheet
|
||||||
|
var decisions = _importDecisionMaker.GetImportDecisions(files, idOverride, itemInfo, config);
|
||||||
|
|
||||||
var existingItems = group.Join(decisions,
|
var existingItems = group.Join(decisions,
|
||||||
i => i.Path,
|
i => i.Path,
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Specifications
|
||||||
{
|
{
|
||||||
double dist;
|
double dist;
|
||||||
string reasons;
|
string reasons;
|
||||||
if (item.LocalTracks.Count == 1 && item.LocalTracks[0].IsSingleFileRelease)
|
if (item.IsSingleFileRelease)
|
||||||
{
|
{
|
||||||
_logger.Debug($"Accepting single file release {item}: {item.Distance.Reasons}");
|
_logger.Debug($"Accepting single file release {item}: {item.Distance.Reasons}");
|
||||||
return Decision.Accept();
|
return Decision.Accept();
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Specifications
|
||||||
|
|
||||||
public Decision IsSatisfiedBy(LocalAlbumRelease item, DownloadClientItem downloadClientItem)
|
public Decision IsSatisfiedBy(LocalAlbumRelease item, DownloadClientItem downloadClientItem)
|
||||||
{
|
{
|
||||||
if (item.LocalTracks.Count == 1 && item.LocalTracks[0].IsSingleFileRelease)
|
if (item.IsSingleFileRelease)
|
||||||
{
|
{
|
||||||
return Decision.Accept();
|
return Decision.Accept();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Specifications
|
||||||
|
|
||||||
public Decision IsSatisfiedBy(LocalAlbumRelease item, DownloadClientItem downloadClientItem)
|
public Decision IsSatisfiedBy(LocalAlbumRelease item, DownloadClientItem downloadClientItem)
|
||||||
{
|
{
|
||||||
if (item.LocalTracks.Count == 1 && item.LocalTracks[0].IsSingleFileRelease)
|
if (item.IsSingleFileRelease)
|
||||||
{
|
{
|
||||||
return Decision.Accept();
|
return Decision.Accept();
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,16 +105,13 @@ namespace NzbDrone.Core.Organizer
|
||||||
|
|
||||||
var pattern = namingConfig.StandardTrackFormat;
|
var pattern = namingConfig.StandardTrackFormat;
|
||||||
|
|
||||||
if (!trackFile.IsSingleFileRelease)
|
if (tracks.First().AlbumRelease.Value.Media.Count > 1)
|
||||||
{
|
{
|
||||||
if (tracks.First().AlbumRelease.Value.Media.Count > 1)
|
pattern = namingConfig.MultiDiscTrackFormat;
|
||||||
{
|
|
||||||
pattern = namingConfig.MultiDiscTrackFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
tracks = tracks.OrderBy(e => e.AlbumReleaseId).ThenBy(e => e.TrackNumber).ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracks = tracks.OrderBy(e => e.AlbumReleaseId).ThenBy(e => e.TrackNumber).ToList();
|
||||||
|
|
||||||
var splitPatterns = pattern.Split(new[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
|
var splitPatterns = pattern.Split(new[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
var components = new List<string>();
|
var components = new List<string>();
|
||||||
|
|
||||||
|
@ -126,14 +123,14 @@ namespace NzbDrone.Core.Organizer
|
||||||
if (!trackFile.IsSingleFileRelease)
|
if (!trackFile.IsSingleFileRelease)
|
||||||
{
|
{
|
||||||
splitPattern = FormatTrackNumberTokens(splitPattern, "", tracks);
|
splitPattern = FormatTrackNumberTokens(splitPattern, "", tracks);
|
||||||
splitPattern = FormatMediumNumberTokens(splitPattern, "", tracks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
splitPattern = FormatMediumNumberTokens(splitPattern, "", tracks);
|
||||||
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));
|
||||||
if (!trackFile.IsSingleFileRelease)
|
if (!trackFile.IsSingleFileRelease)
|
||||||
{
|
{
|
||||||
AddMediumTokens(tokenHandlers, tracks.First().AlbumRelease.Value.Media.SingleOrDefault(m => m.Number == tracks.First().MediumNumber));
|
|
||||||
AddTrackTokens(tokenHandlers, tracks, artist);
|
AddTrackTokens(tokenHandlers, tracks, artist);
|
||||||
AddTrackTitlePlaceholderTokens(tokenHandlers);
|
AddTrackTitlePlaceholderTokens(tokenHandlers);
|
||||||
AddTrackFileTokens(tokenHandlers, trackFile);
|
AddTrackFileTokens(tokenHandlers, trackFile);
|
||||||
|
|
|
@ -61,6 +61,8 @@ namespace NzbDrone.Core.Parser.Model
|
||||||
{
|
{
|
||||||
return "[" + string.Join(", ", LocalTracks.Select(x => Path.GetDirectoryName(x.Path)).Distinct()) + "]";
|
return "[" + string.Join(", ", LocalTracks.Select(x => Path.GetDirectoryName(x.Path)).Distinct()) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsSingleFileRelease => LocalTracks.All(x => x.IsSingleFileRelease == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TrackMapping
|
public class TrackMapping
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue