Example #1
0
        private Artist GetArtist(ParsedAlbumInfo parsedAlbumInfo, SearchCriteriaBase searchCriteria)
        {
            Artist artist = null;

            if (searchCriteria != null)
            {
                if (searchCriteria.Artist.CleanName == parsedAlbumInfo.ArtistName.CleanArtistName())
                {
                    return(searchCriteria.Artist);
                }
            }

            artist = _artistService.FindByName(parsedAlbumInfo.ArtistName);

            if (artist == null)
            {
                _logger.Debug("Trying inexact artist match for {0}", parsedAlbumInfo.ArtistName);
                artist = _artistService.FindByNameInexact(parsedAlbumInfo.ArtistName);
            }

            if (artist == null)
            {
                _logger.Debug("No matching artist {0}", parsedAlbumInfo.ArtistName);
                return(null);
            }

            return(artist);
        }
Example #2
0
 public RemoteAlbum Map(ParsedAlbumInfo parsedAlbumInfo, int artistId, IEnumerable <int> albumIds)
 {
     return(new RemoteAlbum
     {
         ParsedAlbumInfo = parsedAlbumInfo,
         Artist = _artistService.GetArtist(artistId),
         Albums = _albumService.GetAlbums(albumIds)
     });
 }
Example #3
0
        private static ParsedAlbumInfo ParseAlbumMatchCollection(MatchCollection matchCollection)
        {
            var artistName     = matchCollection[0].Groups["artist"].Value.Replace('.', ' ').Replace('_', ' ');
            var albumTitle     = matchCollection[0].Groups["album"].Value.Replace('.', ' ').Replace('_', ' ');
            var releaseVersion = matchCollection[0].Groups["version"].Value.Replace('.', ' ').Replace('_', ' ');

            artistName     = RequestInfoRegex.Replace(artistName, "").Trim(' ');
            albumTitle     = RequestInfoRegex.Replace(albumTitle, "").Trim(' ');
            releaseVersion = RequestInfoRegex.Replace(releaseVersion, "").Trim(' ');

            int releaseYear;

            int.TryParse(matchCollection[0].Groups["releaseyear"].Value, out releaseYear);

            ParsedAlbumInfo result;

            result = new ParsedAlbumInfo();

            result.ArtistName      = artistName;
            result.AlbumTitle      = albumTitle;
            result.ArtistTitleInfo = GetArtistTitleInfo(result.ArtistName);
            result.ReleaseDate     = releaseYear.ToString();
            result.ReleaseVersion  = releaseVersion;

            if (matchCollection[0].Groups["discography"].Success)
            {
                int discStart;
                int discEnd;
                int.TryParse(matchCollection[0].Groups["startyear"].Value, out discStart);
                int.TryParse(matchCollection[0].Groups["endyear"].Value, out discEnd);
                result.Discography = true;

                if (discStart > 0 && discEnd > 0)
                {
                    result.DiscographyStart = discStart;
                    result.DiscographyEnd   = discEnd;
                }
                else if (discEnd > 0)
                {
                    result.DiscographyEnd = discEnd;
                }

                result.AlbumTitle = "Discography";
            }

            Logger.Debug("Album Parsed. {0}", result);

            return(result);
        }
Example #4
0
        public RemoteAlbum Map(ParsedAlbumInfo parsedAlbumInfo, SearchCriteriaBase searchCriteria = null)
        {
            var remoteAlbum = new RemoteAlbum
            {
                ParsedAlbumInfo = parsedAlbumInfo,
            };

            var artist = GetArtist(parsedAlbumInfo, searchCriteria);

            if (artist == null)
            {
                return(remoteAlbum);
            }

            remoteAlbum.Artist = artist;
            remoteAlbum.Albums = GetAlbums(parsedAlbumInfo, artist, searchCriteria);

            return(remoteAlbum);
        }
Example #5
0
        public void should_not_fail_if_search_criteria_contains_multiple_albums_with_the_same_name()
        {
            var artist = Builder <Artist> .CreateNew().Build();

            var albums = Builder <Album> .CreateListOfSize(2).All().With(x => x.Title = "IdenticalTitle").Build().ToList();

            var criteria = new AlbumSearchCriteria {
                Artist = artist,
                Albums = albums
            };

            var parsed = new ParsedAlbumInfo {
                AlbumTitle = "IdenticalTitle"
            };

            Subject.GetAlbums(parsed, artist, criteria).Should().BeEquivalentTo(new List <Album>());

            Mocker.GetMock <IAlbumService>()
            .Verify(s => s.FindByTitle(artist.ArtistMetadataId, "IdenticalTitle"), Times.Once());
        }
        public void Setup()
        {
            Mocker.Resolve <UpgradableSpecification>();

            _parsedAlbumInfo = Builder <ParsedAlbumInfo> .CreateNew()
                               .With(p => p.Quality = new QualityModel(Quality.FLAC,
                                                                       new Revision(2, 0, false)))
                               .With(p => p.ReleaseGroup = "Lidarr")
                               .Build();

            _albums = Builder <Album> .CreateListOfSize(1)
                      .All()
                      .BuildList();

            _trackFiles = Builder <TrackFile> .CreateListOfSize(3)
                          .All()
                          .With(t => t.AlbumId = _albums.First().Id)
                          .BuildList();

            Mocker.GetMock <IMediaFileService>()
            .Setup(c => c.GetFilesByAlbum(It.IsAny <int>()))
            .Returns(_trackFiles);
        }
Example #7
0
        public Tuple <List <LocalTrack>, List <ImportDecision <LocalTrack> > > GetLocalTracks(List <IFileInfo> musicFiles, DownloadClientItem downloadClientItem, ParsedTrackInfo folderInfo, FilterFilesType filter)
        {
            var watch = new System.Diagnostics.Stopwatch();

            watch.Start();

            var files = _mediaFileService.FilterUnchangedFiles(musicFiles, filter);

            var localTracks = new List <LocalTrack>();
            var decisions   = new List <ImportDecision <LocalTrack> >();

            _logger.Debug("Analyzing {0}/{1} files.", files.Count, musicFiles.Count);

            if (!files.Any())
            {
                return(Tuple.Create(localTracks, decisions));
            }

            ParsedAlbumInfo downloadClientItemInfo = null;

            if (downloadClientItem != null)
            {
                downloadClientItemInfo = Parser.Parser.ParseAlbumTitle(downloadClientItem.Title);
            }

            int i = 1;

            foreach (var file in files)
            {
                _logger.ProgressInfo($"Reading file {i++}/{files.Count}");

                var localTrack = new LocalTrack
                {
                    DownloadClientAlbumInfo = downloadClientItemInfo,
                    FolderTrackInfo         = folderInfo,
                    Path           = file.FullName,
                    Size           = file.Length,
                    Modified       = file.LastWriteTimeUtc,
                    FileTrackInfo  = _audioTagService.ReadTags(file.FullName),
                    AdditionalFile = false
                };

                try
                {
                    // TODO fix otherfiles?
                    _augmentingService.Augment(localTrack, true);
                    localTracks.Add(localTrack);
                }
                catch (AugmentingFailedException)
                {
                    decisions.Add(new ImportDecision <LocalTrack>(localTrack, new Rejection("Unable to parse file")));
                }
                catch (Exception e)
                {
                    _logger.Error(e, "Couldn't import file. {0}", localTrack.Path);

                    decisions.Add(new ImportDecision <LocalTrack>(localTrack, new Rejection("Unexpected error processing file")));
                }
            }

            _logger.Debug($"Tags parsed for {files.Count} files in {watch.ElapsedMilliseconds}ms");

            return(Tuple.Create(localTracks, decisions));
        }
Example #8
0
        public List <Album> GetAlbums(ParsedAlbumInfo parsedAlbumInfo, Artist artist, SearchCriteriaBase searchCriteria = null)
        {
            var albumTitle = parsedAlbumInfo.AlbumTitle;
            var result     = new List <Album>();

            if (parsedAlbumInfo.AlbumTitle == null)
            {
                return(new List <Album>());
            }

            Album albumInfo = null;

            if (parsedAlbumInfo.Discography)
            {
                if (parsedAlbumInfo.DiscographyStart > 0)
                {
                    return(_albumService.ArtistAlbumsBetweenDates(artist,
                                                                  new DateTime(parsedAlbumInfo.DiscographyStart, 1, 1),
                                                                  new DateTime(parsedAlbumInfo.DiscographyEnd, 12, 31), false));
                }

                if (parsedAlbumInfo.DiscographyEnd > 0)
                {
                    return(_albumService.ArtistAlbumsBetweenDates(artist,
                                                                  new DateTime(1800, 1, 1),
                                                                  new DateTime(parsedAlbumInfo.DiscographyEnd, 12, 31), false));
                }

                return(_albumService.GetAlbumsByArtist(artist.Id));
            }

            if (searchCriteria != null)
            {
                albumInfo = searchCriteria.Albums.ExclusiveOrDefault(e => e.Title == albumTitle);
            }

            if (albumInfo == null)
            {
                // TODO: Search by Title and Year instead of just Title when matching
                albumInfo = _albumService.FindByTitle(artist.ArtistMetadataId, parsedAlbumInfo.AlbumTitle);
            }

            if (albumInfo == null)
            {
                _logger.Debug("Trying inexact album match for {0}", parsedAlbumInfo.AlbumTitle);
                albumInfo = _albumService.FindByTitleInexact(artist.ArtistMetadataId, parsedAlbumInfo.AlbumTitle);
            }

            if (albumInfo != null)
            {
                result.Add(albumInfo);
            }

            else
            {
                _logger.Debug("Unable to find {0}", parsedAlbumInfo);
            }


            return(result);
        }
        public void Setup()
        {
            _artist = Builder <Artist> .CreateNew()
                      .Build();

            _album = Builder <Album> .CreateNew()
                     .Build();

            _profile = new QualityProfile
            {
                Name   = "Test",
                Cutoff = Quality.MP3_256.Id,
                Items  = new List <QualityProfileQualityItem>
                {
                    new QualityProfileQualityItem {
                        Allowed = true, Quality = Quality.MP3_256
                    },
                    new QualityProfileQualityItem {
                        Allowed = true, Quality = Quality.MP3_320
                    },
                    new QualityProfileQualityItem {
                        Allowed = true, Quality = Quality.FLAC
                    }
                },
            };

            _artist.QualityProfile = new LazyLoaded <QualityProfile>(_profile);

            _release = Builder <ReleaseInfo> .CreateNew().Build();

            _parsedAlbumInfo = Builder <ParsedAlbumInfo> .CreateNew().Build();

            _parsedAlbumInfo.Quality = new QualityModel(Quality.MP3_256);

            _remoteAlbum        = new RemoteAlbum();
            _remoteAlbum.Albums = new List <Album> {
                _album
            };
            _remoteAlbum.Artist          = _artist;
            _remoteAlbum.ParsedAlbumInfo = _parsedAlbumInfo;
            _remoteAlbum.Release         = _release;

            _temporarilyRejected = new DownloadDecision(_remoteAlbum, new Rejection("Temp Rejected", RejectionType.Temporary));

            _heldReleases = new List <PendingRelease>();

            Mocker.GetMock <IPendingReleaseRepository>()
            .Setup(s => s.All())
            .Returns(_heldReleases);

            Mocker.GetMock <IPendingReleaseRepository>()
            .Setup(s => s.AllByArtistId(It.IsAny <int>()))
            .Returns <int>(i => _heldReleases.Where(v => v.ArtistId == i).ToList());

            Mocker.GetMock <IArtistService>()
            .Setup(s => s.GetArtist(It.IsAny <int>()))
            .Returns(_artist);

            Mocker.GetMock <IArtistService>()
            .Setup(s => s.GetArtists(It.IsAny <IEnumerable <int> >()))
            .Returns(new List <Artist> {
                _artist
            });

            Mocker.GetMock <IParsingService>()
            .Setup(s => s.GetAlbums(It.IsAny <ParsedAlbumInfo>(), _artist, null))
            .Returns(new List <Album> {
                _album
            });

            Mocker.GetMock <IPrioritizeDownloadDecision>()
            .Setup(s => s.PrioritizeDecisions(It.IsAny <List <DownloadDecision> >()))
            .Returns((List <DownloadDecision> d) => d);
        }
Example #10
0
        public List <ImportDecision <LocalTrack> > GetImportDecisions(List <IFileInfo> musicFiles, Artist artist, Album album, AlbumRelease albumRelease, DownloadClientItem downloadClientItem, ParsedTrackInfo folderInfo, FilterFilesType filter, bool newDownload, bool singleRelease, bool includeExisting)
        {
            var watch = new System.Diagnostics.Stopwatch();

            watch.Start();

            var files = filter != FilterFilesType.None && (artist != null) ? _mediaFileService.FilterUnchangedFiles(musicFiles, artist, filter) : musicFiles;

            var localTracks = new List <LocalTrack>();
            var decisions   = new List <ImportDecision <LocalTrack> >();

            _logger.Debug("Analyzing {0}/{1} files.", files.Count, musicFiles.Count);

            if (!files.Any())
            {
                return(decisions);
            }

            ParsedAlbumInfo downloadClientItemInfo = null;

            if (downloadClientItem != null)
            {
                downloadClientItemInfo = Parser.Parser.ParseAlbumTitle(downloadClientItem.Title);
            }

            foreach (var file in files)
            {
                var localTrack = new LocalTrack
                {
                    Artist = artist,
                    Album  = album,
                    DownloadClientAlbumInfo = downloadClientItemInfo,
                    FolderTrackInfo         = folderInfo,
                    Path           = file.FullName,
                    Size           = file.Length,
                    Modified       = file.LastWriteTimeUtc,
                    FileTrackInfo  = _audioTagService.ReadTags(file.FullName),
                    ExistingFile   = !newDownload,
                    AdditionalFile = false
                };

                try
                {
                    // TODO fix otherfiles?
                    _augmentingService.Augment(localTrack, true);
                    localTracks.Add(localTrack);
                }
                catch (AugmentingFailedException)
                {
                    decisions.Add(new ImportDecision <LocalTrack>(localTrack, new Rejection("Unable to parse file")));
                }
                catch (Exception e)
                {
                    _logger.Error(e, "Couldn't import file. {0}", localTrack.Path);

                    decisions.Add(new ImportDecision <LocalTrack>(localTrack, new Rejection("Unexpected error processing file")));
                }
            }

            _logger.Debug($"Tags parsed for {files.Count} files in {watch.ElapsedMilliseconds}ms");

            var releases = _identificationService.Identify(localTracks, artist, album, albumRelease, newDownload, singleRelease, includeExisting);

            foreach (var release in releases)
            {
                release.NewDownload = newDownload;
                var releaseDecision = GetDecision(release);

                foreach (var localTrack in release.LocalTracks)
                {
                    if (releaseDecision.Approved)
                    {
                        decisions.AddIfNotNull(GetDecision(localTrack));
                    }
                    else
                    {
                        decisions.Add(new ImportDecision <LocalTrack>(localTrack, releaseDecision.Rejections.ToArray()));
                    }
                }
            }

            return(decisions);
        }
Example #11
0
        private IEnumerable <DownloadDecision> GetAlbumDecisions(List <ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
        {
            if (reports.Any())
            {
                _logger.ProgressInfo("Processing {0} releases", reports.Count);
            }
            else
            {
                _logger.ProgressInfo("No results found");
            }

            var reportNumber = 1;

            foreach (var report in reports)
            {
                DownloadDecision decision = null;
                _logger.ProgressTrace("Processing release {0}/{1}", reportNumber, reports.Count);
                _logger.Debug("Processing release '{0}' from '{1}'", report.Title, report.Indexer);

                try
                {
                    var parsedAlbumInfo = Parser.Parser.ParseAlbumTitle(report.Title);

                    if (parsedAlbumInfo == null && searchCriteria != null)
                    {
                        parsedAlbumInfo = Parser.Parser.ParseAlbumTitleWithSearchCriteria(report.Title,
                                                                                          searchCriteria.Artist,
                                                                                          searchCriteria.Albums);
                    }

                    if (parsedAlbumInfo != null)
                    {
                        // TODO: Artist Data Augment without calling to parse title again
                        //if (!report.Artist.IsNullOrWhiteSpace())
                        //{
                        //    if (parsedAlbumInfo.ArtistName.IsNullOrWhiteSpace() || _parsingService.GetArtist(parsedAlbumInfo.ArtistName) == null)
                        //    {
                        //        parsedAlbumInfo.ArtistName = report.Artist;
                        //    }
                        //}

                        // TODO: Replace Parsed AlbumTitle with metadata Title if Parsed AlbumTitle not a valid match
                        //if (!report.Album.IsNullOrWhiteSpace())
                        //{
                        //    parsedAlbumInfo.AlbumTitle = report.Album;
                        //}
                        if (!parsedAlbumInfo.ArtistName.IsNullOrWhiteSpace())
                        {
                            var remoteAlbum = _parsingService.Map(parsedAlbumInfo, searchCriteria);

                            // try parsing again using the search criteria, in case it parsed but parsed incorrectly
                            if ((remoteAlbum.Artist == null || remoteAlbum.Albums.Empty()) && searchCriteria != null)
                            {
                                _logger.Debug("Artist/Album null for {0}, reparsing with search criteria", report.Title);
                                var parsedAlbumInfoWithCriteria = Parser.Parser.ParseAlbumTitleWithSearchCriteria(report.Title,
                                                                                                                  searchCriteria.Artist,
                                                                                                                  searchCriteria.Albums);

                                if (parsedAlbumInfoWithCriteria != null && parsedAlbumInfoWithCriteria.ArtistName.IsNotNullOrWhiteSpace())
                                {
                                    remoteAlbum = _parsingService.Map(parsedAlbumInfoWithCriteria, searchCriteria);
                                }
                            }

                            remoteAlbum.Release = report;

                            if (remoteAlbum.Artist == null)
                            {
                                decision = new DownloadDecision(remoteAlbum, new Rejection("Unknown Artist"));

                                // shove in the searched artist in case of forced download in interactive search
                                if (searchCriteria != null)
                                {
                                    remoteAlbum.Artist = searchCriteria.Artist;
                                    remoteAlbum.Albums = searchCriteria.Albums;
                                }
                            }
                            else if (remoteAlbum.Albums.Empty())
                            {
                                decision = new DownloadDecision(remoteAlbum, new Rejection("Unable to parse albums from release name"));
                                if (searchCriteria != null)
                                {
                                    remoteAlbum.Albums = searchCriteria.Albums;
                                }
                            }
                            else
                            {
                                _aggregationService.Augment(remoteAlbum);
                                remoteAlbum.DownloadAllowed = remoteAlbum.Albums.Any();
                                decision = GetDecisionForReport(remoteAlbum, searchCriteria);
                            }
                        }
                    }

                    if (searchCriteria != null)
                    {
                        if (parsedAlbumInfo == null)
                        {
                            parsedAlbumInfo = new ParsedAlbumInfo
                            {
                                Quality = QualityParser.ParseQuality(report.Title, null, 0)
                            };
                        }

                        if (parsedAlbumInfo.ArtistName.IsNullOrWhiteSpace())
                        {
                            var remoteAlbum = new RemoteAlbum
                            {
                                Release         = report,
                                ParsedAlbumInfo = parsedAlbumInfo
                            };

                            decision = new DownloadDecision(remoteAlbum, new Rejection("Unable to parse release"));
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.Error(e, "Couldn't process release.");

                    var remoteAlbum = new RemoteAlbum {
                        Release = report
                    };
                    decision = new DownloadDecision(remoteAlbum, new Rejection("Unexpected error processing release"));
                }

                reportNumber++;

                if (decision != null)
                {
                    if (decision.Rejections.Any())
                    {
                        _logger.Debug("Release rejected for the following reasons: {0}", string.Join(", ", decision.Rejections));
                    }
                    else
                    {
                        _logger.Debug("Release accepted");
                    }

                    yield return(decision);
                }
            }
        }