using System; using System.Collections.Generic; using System.IO; using System.Linq; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Core.Blocklisting; using NzbDrone.Core.History; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Music; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.CustomFormats { public interface ICustomFormatCalculationService { List ParseCustomFormat(RemoteAlbum remoteAlbum, long size); List ParseCustomFormat(TrackFile trackFile, Artist artist); List ParseCustomFormat(TrackFile trackFile); List ParseCustomFormat(Blocklist blocklist, Artist artist); List ParseCustomFormat(EntityHistory history, Artist artist); List ParseCustomFormat(LocalTrack localTrack); } public class CustomFormatCalculationService : ICustomFormatCalculationService { private readonly ICustomFormatService _formatService; private readonly Logger _logger; public CustomFormatCalculationService(ICustomFormatService formatService, Logger logger) { _formatService = formatService; _logger = logger; } public List ParseCustomFormat(RemoteAlbum remoteAlbum, long size) { var input = new CustomFormatInput { AlbumInfo = remoteAlbum.ParsedAlbumInfo, Artist = remoteAlbum.Artist, Size = size, IndexerFlags = remoteAlbum.Release?.IndexerFlags ?? 0 }; return ParseCustomFormat(input); } public List ParseCustomFormat(TrackFile trackFile, Artist artist) { return ParseCustomFormat(trackFile, artist, _formatService.All()); } public List ParseCustomFormat(TrackFile trackFile) { return ParseCustomFormat(trackFile, trackFile.Artist.Value, _formatService.All()); } public List ParseCustomFormat(Blocklist blocklist, Artist artist) { var parsed = Parser.Parser.ParseAlbumTitle(blocklist.SourceTitle); var albumInfo = new ParsedAlbumInfo { ArtistName = artist.Name, ReleaseTitle = parsed?.ReleaseTitle ?? blocklist.SourceTitle, Quality = blocklist.Quality, ReleaseGroup = parsed?.ReleaseGroup }; var input = new CustomFormatInput { AlbumInfo = albumInfo, Artist = artist, Size = blocklist.Size ?? 0, IndexerFlags = blocklist.IndexerFlags }; return ParseCustomFormat(input); } public List ParseCustomFormat(EntityHistory history, Artist artist) { var parsed = Parser.Parser.ParseAlbumTitle(history.SourceTitle); long.TryParse(history.Data.GetValueOrDefault("size"), out var size); Enum.TryParse(history.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags indexerFlags); var albumInfo = new ParsedAlbumInfo { ArtistName = artist.Name, ReleaseTitle = parsed?.ReleaseTitle ?? history.SourceTitle, Quality = history.Quality, ReleaseGroup = parsed?.ReleaseGroup, }; var input = new CustomFormatInput { AlbumInfo = albumInfo, Artist = artist, Size = size, IndexerFlags = indexerFlags }; return ParseCustomFormat(input); } public List ParseCustomFormat(LocalTrack localTrack) { var albumInfo = new ParsedAlbumInfo { ArtistName = localTrack.Artist.Name, ReleaseTitle = localTrack.SceneName.IsNotNullOrWhiteSpace() ? localTrack.SceneName : Path.GetFileName(localTrack.Path), Quality = localTrack.Quality, ReleaseGroup = localTrack.ReleaseGroup }; var input = new CustomFormatInput { AlbumInfo = albumInfo, Artist = localTrack.Artist, Size = localTrack.Size, Filename = Path.GetFileName(localTrack.Path), IndexerFlags = localTrack.IndexerFlags, }; return ParseCustomFormat(input); } private List ParseCustomFormat(CustomFormatInput input) { return ParseCustomFormat(input, _formatService.All()); } private static List ParseCustomFormat(CustomFormatInput input, List allCustomFormats) { var matches = new List(); foreach (var customFormat in allCustomFormats) { var specificationMatches = customFormat.Specifications .GroupBy(t => t.GetType()) .Select(g => new SpecificationMatchesGroup { Matches = g.ToDictionary(t => t, t => t.IsSatisfiedBy(input)) }) .ToList(); if (specificationMatches.All(x => x.DidMatch)) { matches.Add(customFormat); } } return matches.OrderBy(x => x.Name).ToList(); } private List ParseCustomFormat(TrackFile trackFile, Artist artist, List allCustomFormats) { var releaseTitle = string.Empty; if (trackFile.SceneName.IsNotNullOrWhiteSpace()) { _logger.Trace("Using scene name for release title: {0}", trackFile.SceneName); releaseTitle = trackFile.SceneName; } else if (trackFile.OriginalFilePath.IsNotNullOrWhiteSpace()) { _logger.Trace("Using original file path for release title: {0}", Path.GetFileName(trackFile.OriginalFilePath)); releaseTitle = Path.GetFileName(trackFile.OriginalFilePath); } else if (trackFile.Path.IsNotNullOrWhiteSpace()) { _logger.Trace("Using path for release title: {0}", Path.GetFileName(trackFile.Path)); releaseTitle = Path.GetFileName(trackFile.Path); } var albumInfo = new ParsedAlbumInfo { ArtistName = artist.Name, ReleaseTitle = releaseTitle, Quality = trackFile.Quality, ReleaseGroup = trackFile.ReleaseGroup }; var input = new CustomFormatInput { AlbumInfo = albumInfo, Artist = artist, Size = trackFile.Size, IndexerFlags = trackFile.IndexerFlags, Filename = Path.GetFileName(trackFile.Path) }; return ParseCustomFormat(input, allCustomFormats); } } }