Esempio n. 1
0
        public void should_match_tracks(string file)
        {
            var path     = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Identification", file);
            var testcase = JsonConvert.DeserializeObject <IdTestCase>(File.ReadAllText(path));

            var artists         = GivenArtists(testcase.LibraryAuthors);
            var specifiedArtist = artists.SingleOrDefault(x => x.Metadata.Value.ForeignAuthorId == testcase.Author);
            var idOverrides     = new IdentificationOverrides {
                Author = specifiedArtist
            };

            var tracks = testcase.Tracks.Select(x => new LocalBook
            {
                Path          = x.Path.AsOsAgnostic(),
                FileTrackInfo = x.FileTrackInfo
            }).ToList();

            if (testcase.Fingerprints != null)
            {
                GivenFingerprints(testcase.Fingerprints);
            }

            var config = new ImportDecisionMakerConfig
            {
                NewDownload     = testcase.NewDownload,
                SingleRelease   = testcase.SingleRelease,
                IncludeExisting = false
            };

            var result = _Subject.Identify(tracks, idOverrides, config);

            result.Should().HaveCount(testcase.ExpectedMusicBrainzReleaseIds.Count);
        }
Esempio n. 2
0
        private List <ManualImportItem> ProcessFolder(string folder, string downloadId, Author author, FilterFilesType filter, bool replaceExistingFiles)
        {
            DownloadClientItem downloadClientItem = null;
            var directoryInfo = new DirectoryInfo(folder);

            author = author ?? _parsingService.GetAuthor(directoryInfo.Name);

            if (downloadId.IsNotNullOrWhiteSpace())
            {
                var trackedDownload = _trackedDownloadService.Find(downloadId);
                downloadClientItem = trackedDownload?.DownloadItem;

                if (author == null)
                {
                    author = trackedDownload?.RemoteBook?.Author;
                }
            }

            var authorFiles = _diskScanService.GetBookFiles(folder).ToList();
            var idOverrides = new IdentificationOverrides
            {
                Author = author
            };
            var itemInfo = new ImportDecisionMakerInfo
            {
                DownloadClientItem = downloadClientItem,
                ParsedTrackInfo    = Parser.Parser.ParseTitle(directoryInfo.Name)
            };
            var config = new ImportDecisionMakerConfig
            {
                Filter          = filter,
                NewDownload     = true,
                SingleRelease   = false,
                IncludeExisting = !replaceExistingFiles,
                AddNewAuthors   = false,
                KeepAllEditions = true
            };

            var decisions = _importDecisionMaker.GetImportDecisions(authorFiles, idOverrides, itemInfo, config);

            // paths will be different for new and old files which is why we need to map separately
            var newFiles = authorFiles.Join(decisions,
                                            f => f.FullName,
                                            d => d.Item.Path,
                                            (f, d) => new { File = f, Decision = d },
                                            PathEqualityComparer.Instance);

            var newItems          = newFiles.Select(x => MapItem(x.Decision, downloadId, replaceExistingFiles, false));
            var existingDecisions = decisions.Except(newFiles.Select(x => x.Decision));
            var existingItems     = existingDecisions.Select(x => MapItem(x, null, replaceExistingFiles, false));

            return(newItems.Concat(existingItems).ToList());
        }
Esempio n. 3
0
        public List <ManualImportItem> GetMediaFiles(string path, string downloadId, Author author, FilterFilesType filter, bool replaceExistingFiles)
        {
            if (downloadId.IsNotNullOrWhiteSpace())
            {
                var trackedDownload = _trackedDownloadService.Find(downloadId);

                if (trackedDownload == null)
                {
                    return(new List <ManualImportItem>());
                }

                if (trackedDownload.ImportItem == null)
                {
                    trackedDownload.ImportItem = _provideImportItemService.ProvideImportItem(trackedDownload.DownloadItem, trackedDownload.ImportItem);
                }

                path = trackedDownload.ImportItem.OutputPath.FullPath;
            }

            if (!_diskProvider.FolderExists(path))
            {
                if (!_diskProvider.FileExists(path))
                {
                    return(new List <ManualImportItem>());
                }

                var files = new List <IFileInfo> {
                    _diskProvider.GetFileInfo(path)
                };

                var config = new ImportDecisionMakerConfig
                {
                    Filter          = FilterFilesType.None,
                    NewDownload     = true,
                    SingleRelease   = false,
                    IncludeExisting = !replaceExistingFiles,
                    AddNewAuthors   = false,
                    KeepAllEditions = true
                };

                var decision = _importDecisionMaker.GetImportDecisions(files, null, null, config);
                var result   = MapItem(decision.First(), downloadId, replaceExistingFiles, false);

                return(new List <ManualImportItem> {
                    result
                });
            }

            return(ProcessFolder(path, downloadId, author, filter, replaceExistingFiles));
        }
        private List <ImportResult> ProcessFile(IFileInfo fileInfo, ImportMode importMode, Author author, DownloadClientItem downloadClientItem)
        {
            if (Path.GetFileNameWithoutExtension(fileInfo.Name).StartsWith("._"))
            {
                _logger.Debug("[{0}] starts with '._', skipping", fileInfo.FullName);

                return(new List <ImportResult>
                {
                    new ImportResult(new ImportDecision <LocalBook>(new LocalBook {
                        Path = fileInfo.FullName
                    }, new Rejection("Invalid music file, filename starts with '._'")), "Invalid music file, filename starts with '._'")
                });
            }

            if (downloadClientItem == null)
            {
                if (_diskProvider.IsFileLocked(fileInfo.FullName))
                {
                    return(new List <ImportResult>
                    {
                        FileIsLockedResult(fileInfo.FullName)
                    });
                }
            }

            var idOverrides = new IdentificationOverrides
            {
                Author = author
            };
            var idInfo = new ImportDecisionMakerInfo
            {
                DownloadClientItem = downloadClientItem
            };
            var idConfig = new ImportDecisionMakerConfig
            {
                Filter          = FilterFilesType.None,
                NewDownload     = true,
                SingleRelease   = false,
                IncludeExisting = false,
                AddNewAuthors   = false
            };

            var decisions = _importDecisionMaker.GetImportDecisions(new List <IFileInfo>()
            {
                fileInfo
            }, idOverrides, idInfo, idConfig);

            return(_importApprovedTracks.Import(decisions, true, downloadClientItem, importMode));
        }
        private List <ImportResult> ProcessFolder(IDirectoryInfo directoryInfo, ImportMode importMode, Author author, DownloadClientItem downloadClientItem)
        {
            if (_authorService.AuthorPathExists(directoryInfo.FullName))
            {
                _logger.Warn("Unable to process folder that is mapped to an existing author");
                return(new List <ImportResult>());
            }

            var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
            var folderInfo    = Parser.Parser.ParseBookTitle(directoryInfo.Name);
            var trackInfo     = new ParsedTrackInfo {
            };

            if (folderInfo != null)
            {
                _logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality);

                trackInfo = new ParsedTrackInfo
                {
                    AlbumTitle   = folderInfo.BookTitle,
                    ArtistTitle  = folderInfo.AuthorName,
                    Quality      = folderInfo.Quality,
                    ReleaseGroup = folderInfo.ReleaseGroup,
                    ReleaseHash  = folderInfo.ReleaseHash,
                };
            }
            else
            {
                trackInfo = null;
            }

            var audioFiles = _diskScanService.FilterFiles(directoryInfo.FullName, _diskScanService.GetBookFiles(directoryInfo.FullName));

            if (downloadClientItem == null)
            {
                foreach (var audioFile in audioFiles)
                {
                    if (_diskProvider.IsFileLocked(audioFile.FullName))
                    {
                        return(new List <ImportResult>
                        {
                            FileIsLockedResult(audioFile.FullName)
                        });
                    }
                }
            }

            var idOverrides = new IdentificationOverrides
            {
                Author = author
            };
            var idInfo = new ImportDecisionMakerInfo
            {
                DownloadClientItem = downloadClientItem,
                ParsedTrackInfo    = trackInfo
            };
            var idConfig = new ImportDecisionMakerConfig
            {
                Filter          = FilterFilesType.None,
                NewDownload     = true,
                SingleRelease   = false,
                IncludeExisting = false,
                AddNewAuthors   = false
            };

            var decisions     = _importDecisionMaker.GetImportDecisions(audioFiles, idOverrides, idInfo, idConfig);
            var importResults = _importApprovedTracks.Import(decisions, true, downloadClientItem, importMode);

            if (importMode == ImportMode.Auto)
            {
                importMode = (downloadClientItem == null || downloadClientItem.CanMoveFiles) ? ImportMode.Move : ImportMode.Copy;
            }

            if (importMode == ImportMode.Move &&
                importResults.Any(i => i.Result == ImportResultType.Imported) &&
                ShouldDeleteFolder(directoryInfo, author))
            {
                _logger.Debug("Deleting folder after importing valid files");
                _diskProvider.DeleteFolder(directoryInfo.FullName, true);
            }

            return(importResults);
        }
Esempio n. 6
0
        public void Scan(List <string> folders = null, FilterFilesType filter = FilterFilesType.Known, bool addNewAuthors = false, List <int> authorIds = null)
        {
            if (folders == null)
            {
                folders = _rootFolderService.All().Select(x => x.Path).ToList();
            }

            if (authorIds == null)
            {
                authorIds = new List <int>();
            }

            var mediaFileList = new List <IFileInfo>();

            var musicFilesStopwatch = Stopwatch.StartNew();

            foreach (var folder in folders)
            {
                // We could be scanning a root folder or a subset of a root folder.  If it's a subset,
                // check if the root folder exists before cleaning.
                var rootFolder = _rootFolderService.GetBestRootFolder(folder);

                if (rootFolder == null)
                {
                    _logger.Error("Not scanning {0}, it's not a subdirectory of a defined root folder", folder);
                    return;
                }

                var folderExists = _diskProvider.FolderExists(folder);

                if (!folderExists)
                {
                    if (!_diskProvider.FolderExists(rootFolder.Path))
                    {
                        _logger.Warn("Authors' root folder ({0}) doesn't exist.", rootFolder);
                        var skippedAuthors = _authorService.GetAuthors(authorIds);
                        skippedAuthors.ForEach(x => _eventAggregator.PublishEvent(new AuthorScanSkippedEvent(x, AuthorScanSkippedReason.RootFolderDoesNotExist)));
                        return;
                    }

                    if (_diskProvider.FolderEmpty(rootFolder.Path))
                    {
                        _logger.Warn("Authors' root folder ({0}) is empty.", rootFolder);
                        var skippedAuthors = _authorService.GetAuthors(authorIds);
                        skippedAuthors.ForEach(x => _eventAggregator.PublishEvent(new AuthorScanSkippedEvent(x, AuthorScanSkippedReason.RootFolderIsEmpty)));
                        return;
                    }
                }

                if (!folderExists)
                {
                    _logger.Debug("Specified scan folder ({0}) doesn't exist.", folder);

                    CleanMediaFiles(folder, new List <string>());
                    continue;
                }

                _logger.ProgressInfo("Scanning {0}", folder);

                var files = FilterFiles(folder, GetBookFiles(folder));

                if (!files.Any())
                {
                    _logger.Warn("Scan folder {0} is empty.", folder);
                    continue;
                }

                CleanMediaFiles(folder, files.Select(x => x.FullName).ToList());
                mediaFileList.AddRange(files);
            }

            musicFilesStopwatch.Stop();
            _logger.Trace("Finished getting track files for:\n{0} [{1}]", folders.ConcatToString("\n"), musicFilesStopwatch.Elapsed);

            var decisionsStopwatch = Stopwatch.StartNew();

            var config = new ImportDecisionMakerConfig
            {
                Filter          = filter,
                IncludeExisting = true,
                AddNewAuthors   = addNewAuthors
            };

            var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, null, null, config);

            decisionsStopwatch.Stop();
            _logger.Debug("Import decisions complete [{0}]", decisionsStopwatch.Elapsed);

            var importStopwatch = Stopwatch.StartNew();

            _importApprovedTracks.Import(decisions, false);

            // decisions may have been filtered to just new files.  Anything new and approved will have been inserted.
            // Now we need to make sure anything new but not approved gets inserted
            // Note that knownFiles will include anything imported just now
            var knownFiles = new List <BookFile>();

            folders.ForEach(x => knownFiles.AddRange(_mediaFileService.GetFilesWithBasePath(x)));

            var newFiles = decisions
                           .ExceptBy(x => x.Item.Path, knownFiles, x => x.Path, PathEqualityComparer.Instance)
                           .Select(decision => new BookFile
            {
                Path      = decision.Item.Path,
                CalibreId = decision.Item.Path.ParseCalibreId(),
                Size      = decision.Item.Size,
                Modified  = decision.Item.Modified,
                DateAdded = DateTime.UtcNow,
                Quality   = decision.Item.Quality,
                MediaInfo = decision.Item.FileTrackInfo.MediaInfo,
                Edition   = decision.Item.Edition
            })
                           .ToList();

            _mediaFileService.AddMany(newFiles);

            _logger.Debug($"Inserted {newFiles.Count} new unmatched trackfiles");

            // finally update info on size/modified for existing files
            var updatedFiles = knownFiles
                               .Join(decisions,
                                     x => x.Path,
                                     x => x.Item.Path,
                                     (file, decision) => new
            {
                File = file,
                Item = decision.Item
            },
                                     PathEqualityComparer.Instance)
                               .Where(x => x.File.Size != x.Item.Size ||
                                      Math.Abs((x.File.Modified - x.Item.Modified).TotalSeconds) > 1)
                               .Select(x =>
            {
                x.File.Size      = x.Item.Size;
                x.File.Modified  = x.Item.Modified;
                x.File.MediaInfo = x.Item.FileTrackInfo.MediaInfo;
                x.File.Quality   = x.Item.Quality;
                return(x.File);
            })
                               .ToList();

            _mediaFileService.Update(updatedFiles);

            _logger.Debug($"Updated info for {updatedFiles.Count} known files");

            var authors = _authorService.GetAuthors(authorIds);

            foreach (var author in authors)
            {
                CompletedScanning(author);
            }

            importStopwatch.Stop();
            _logger.Debug("Book import complete for:\n{0} [{1}]", folders.ConcatToString("\n"), importStopwatch.Elapsed);
        }
Esempio n. 7
0
        public List <LocalEdition> Identify(List <LocalBook> localTracks, IdentificationOverrides idOverrides, ImportDecisionMakerConfig config)
        {
            // 1 group localTracks so that we think they represent a single release
            // 2 get candidates given specified author, book and release.  Candidates can include extra files already on disk.
            // 3 find best candidate
            var watch = System.Diagnostics.Stopwatch.StartNew();

            _logger.Debug("Starting track identification");

            var releases = GetLocalBookReleases(localTracks, config.SingleRelease);

            int i = 0;

            foreach (var localRelease in releases)
            {
                i++;
                _logger.ProgressInfo($"Identifying book {i}/{releases.Count}");
                IdentifyRelease(localRelease, idOverrides, config);
            }

            watch.Stop();

            _logger.Debug($"Track identification for {localTracks.Count} tracks took {watch.ElapsedMilliseconds}ms");

            return(releases);
        }
Esempio n. 8
0
        private void IdentifyRelease(LocalEdition localBookRelease, IdentificationOverrides idOverrides, ImportDecisionMakerConfig config)
        {
            var  watch      = System.Diagnostics.Stopwatch.StartNew();
            bool usedRemote = false;

            IEnumerable <CandidateEdition> candidateReleases = _candidateService.GetDbCandidatesFromTags(localBookRelease, idOverrides, config.IncludeExisting);

            // convert all the TrackFiles that represent extra files to List<LocalTrack>
            // local candidates are actually a list so this is fine to enumerate
            var allLocalTracks = ToLocalTrack(candidateReleases
                                              .SelectMany(x => x.ExistingFiles)
                                              .DistinctBy(x => x.Path), localBookRelease);

            _logger.Debug($"Retrieved {allLocalTracks.Count} possible tracks in {watch.ElapsedMilliseconds}ms");

            if (!candidateReleases.Any())
            {
                candidateReleases = _candidateService.GetRemoteCandidates(localBookRelease, idOverrides);
                if (!config.AddNewAuthors)
                {
                    candidateReleases = candidateReleases.Where(x => x.Edition.Book.Value.Id > 0);
                }

                usedRemote = true;
            }

            if (!candidateReleases.Any())
            {
                // can't find any candidates even after using remote search
                // populate the overrides and return
                foreach (var localTrack in localBookRelease.LocalBooks)
                {
                    localTrack.Edition = idOverrides.Edition;
                    localTrack.Book    = idOverrides.Book;
                    localTrack.Author  = idOverrides.Author;
                }

                return;
            }

            GetBestRelease(localBookRelease, candidateReleases, allLocalTracks);

            // If the result isn't great and we haven't tried remote candidates, try looking for remote candidates
            // Goodreads may have a better edition of a local book
            if (localBookRelease.Distance.NormalizedDistance() > 0.15 && !usedRemote)
            {
                _logger.Debug("Match not good enough, trying remote candidates");
                candidateReleases = _candidateService.GetRemoteCandidates(localBookRelease, idOverrides);

                if (!config.AddNewAuthors)
                {
                    candidateReleases = candidateReleases.Where(x => x.Edition.Book.Value.Id > 0);
                }

                GetBestRelease(localBookRelease, candidateReleases, allLocalTracks);
            }

            _logger.Debug($"Best release found in {watch.ElapsedMilliseconds}ms");

            localBookRelease.PopulateMatch();

            _logger.Debug($"IdentifyRelease done in {watch.ElapsedMilliseconds}ms");
        }
Esempio n. 9
0
        public List <ManualImportItem> UpdateItems(List <ManualImportItem> items)
        {
            var replaceExistingFiles = items.All(x => x.ReplaceExistingFiles);
            var groupedItems         = items.Where(x => !x.AdditionalFile).GroupBy(x => x.Album?.Id);

            _logger.Debug($"UpdateItems, {groupedItems.Count()} groups, replaceExisting {replaceExistingFiles}");

            var result = new List <ManualImportItem>();

            foreach (var group in groupedItems)
            {
                _logger.Debug("UpdateItems, group key: {0}", group.Key);

                var disableReleaseSwitching = group.First().DisableReleaseSwitching;

                var files      = group.Select(x => _diskProvider.GetFileInfo(x.Path)).ToList();
                var idOverride = new IdentificationOverrides
                {
                    Artist       = group.First().Artist,
                    Album        = group.First().Album,
                    AlbumRelease = group.First().Release
                };
                var config = new ImportDecisionMakerConfig
                {
                    Filter          = FilterFilesType.None,
                    NewDownload     = true,
                    SingleRelease   = true,
                    IncludeExisting = !replaceExistingFiles,
                    AddNewArtists   = false
                };
                var decisions = _importDecisionMaker.GetImportDecisions(files, idOverride, null, config);

                var existingItems = group.Join(decisions,
                                               i => i.Path,
                                               d => d.Item.Path,
                                               (i, d) => new { Item = i, Decision = d },
                                               PathEqualityComparer.Instance);

                foreach (var pair in existingItems)
                {
                    var item     = pair.Item;
                    var decision = pair.Decision;

                    if (decision.Item.Artist != null)
                    {
                        item.Artist = decision.Item.Artist;
                    }

                    if (decision.Item.Album != null)
                    {
                        item.Album   = decision.Item.Album;
                        item.Release = decision.Item.Release;
                    }

                    if (decision.Item.Tracks.Any())
                    {
                        item.Tracks = decision.Item.Tracks;
                    }

                    item.Rejections = decision.Rejections;

                    result.Add(item);
                }

                var newDecisions = decisions.Except(existingItems.Select(x => x.Decision));
                result.AddRange(newDecisions.Select(x => MapItem(x, null, replaceExistingFiles, disableReleaseSwitching)));
            }

            return(result);
        }
Esempio n. 10
0
        private void IdentifyRelease(LocalAlbumRelease localAlbumRelease, IdentificationOverrides idOverrides, ImportDecisionMakerConfig config)
        {
            var  watch         = System.Diagnostics.Stopwatch.StartNew();
            bool fingerprinted = false;

            var candidateReleases = _candidateService.GetDbCandidatesFromTags(localAlbumRelease, idOverrides, config.IncludeExisting);

            if (candidateReleases.Count == 0 && config.AddNewArtists)
            {
                candidateReleases = _candidateService.GetRemoteCandidates(localAlbumRelease);
            }

            if (candidateReleases.Count == 0 && FingerprintingAllowed(config.NewDownload))
            {
                _logger.Debug("No candidates found, fingerprinting");
                _fingerprintingService.Lookup(localAlbumRelease.LocalTracks, 0.5);
                fingerprinted     = true;
                candidateReleases = _candidateService.GetDbCandidatesFromFingerprint(localAlbumRelease, idOverrides, config.IncludeExisting);

                if (candidateReleases.Count == 0 && config.AddNewArtists)
                {
                    // Now fingerprints are populated this will return a different answer
                    candidateReleases = _candidateService.GetRemoteCandidates(localAlbumRelease);
                }
            }

            if (candidateReleases.Count == 0)
            {
                // can't find any candidates even after fingerprinting
                // populate the overrides and return
                foreach (var localTrack in localAlbumRelease.LocalTracks)
                {
                    localTrack.Release = idOverrides.AlbumRelease;
                    localTrack.Album   = idOverrides.Album;
                    localTrack.Artist  = idOverrides.Artist;
                }

                return;
            }

            _logger.Debug($"Got {candidateReleases.Count} candidates for {localAlbumRelease.LocalTracks.Count} tracks in {watch.ElapsedMilliseconds}ms");

            PopulateTracks(candidateReleases);

            // convert all the TrackFiles that represent extra files to List<LocalTrack>
            var allLocalTracks = ToLocalTrack(candidateReleases
                                              .SelectMany(x => x.ExistingTracks)
                                              .DistinctBy(x => x.Path), localAlbumRelease);

            _logger.Debug($"Retrieved {allLocalTracks.Count} possible tracks in {watch.ElapsedMilliseconds}ms");

            GetBestRelease(localAlbumRelease, candidateReleases, allLocalTracks);

            // If result isn't great and we haven't fingerprinted, try that
            // Note that this can improve the match even if we try the same candidates
            if (!fingerprinted && FingerprintingAllowed(config.NewDownload) && ShouldFingerprint(localAlbumRelease))
            {
                _logger.Debug($"Match not good enough, fingerprinting");
                _fingerprintingService.Lookup(localAlbumRelease.LocalTracks, 0.5);

                // Only include extra possible candidates if neither album nor release are specified
                // Will generally be specified as part of manual import
                if (idOverrides?.Album == null && idOverrides?.AlbumRelease == null)
                {
                    var dbCandidates     = _candidateService.GetDbCandidatesFromFingerprint(localAlbumRelease, idOverrides, config.IncludeExisting);
                    var remoteCandidates = config.AddNewArtists ? _candidateService.GetRemoteCandidates(localAlbumRelease) : new List <CandidateAlbumRelease>();
                    var extraCandidates  = dbCandidates.Concat(remoteCandidates);
                    var newCandidates    = extraCandidates.ExceptBy(x => x.AlbumRelease.Id, candidateReleases, y => y.AlbumRelease.Id, EqualityComparer <int> .Default);
                    candidateReleases.AddRange(newCandidates);

                    PopulateTracks(candidateReleases);

                    allLocalTracks.AddRange(ToLocalTrack(newCandidates
                                                         .SelectMany(x => x.ExistingTracks)
                                                         .DistinctBy(x => x.Path)
                                                         .ExceptBy(x => x.Path, allLocalTracks, x => x.Path, PathEqualityComparer.Instance),
                                                         localAlbumRelease));
                }

                // fingerprint all the local files in candidates we might be matching against
                _fingerprintingService.Lookup(allLocalTracks, 0.5);

                GetBestRelease(localAlbumRelease, candidateReleases, allLocalTracks);
            }

            _logger.Debug($"Best release found in {watch.ElapsedMilliseconds}ms");

            localAlbumRelease.PopulateMatch();

            _logger.Debug($"IdentifyRelease done in {watch.ElapsedMilliseconds}ms");
        }
Esempio n. 11
0
        public void Setup()
        {
            _albumpass1 = new Mock <IImportDecisionEngineSpecification <LocalEdition> >();
            _albumpass2 = new Mock <IImportDecisionEngineSpecification <LocalEdition> >();
            _albumpass3 = new Mock <IImportDecisionEngineSpecification <LocalEdition> >();

            _albumfail1 = new Mock <IImportDecisionEngineSpecification <LocalEdition> >();
            _albumfail2 = new Mock <IImportDecisionEngineSpecification <LocalEdition> >();
            _albumfail3 = new Mock <IImportDecisionEngineSpecification <LocalEdition> >();

            _pass1 = new Mock <IImportDecisionEngineSpecification <LocalBook> >();
            _pass2 = new Mock <IImportDecisionEngineSpecification <LocalBook> >();
            _pass3 = new Mock <IImportDecisionEngineSpecification <LocalBook> >();

            _fail1 = new Mock <IImportDecisionEngineSpecification <LocalBook> >();
            _fail2 = new Mock <IImportDecisionEngineSpecification <LocalBook> >();
            _fail3 = new Mock <IImportDecisionEngineSpecification <LocalBook> >();

            _albumpass1.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalEdition>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Accept());
            _albumpass2.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalEdition>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Accept());
            _albumpass3.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalEdition>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Accept());

            _albumfail1.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalEdition>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Reject("_albumfail1"));
            _albumfail2.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalEdition>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Reject("_albumfail2"));
            _albumfail3.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalEdition>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Reject("_albumfail3"));

            _pass1.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalBook>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Accept());
            _pass2.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalBook>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Accept());
            _pass3.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalBook>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Accept());

            _fail1.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalBook>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Reject("_fail1"));
            _fail2.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalBook>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Reject("_fail2"));
            _fail3.Setup(c => c.IsSatisfiedBy(It.IsAny <LocalBook>(), It.IsAny <DownloadClientItem>())).Returns(Decision.Reject("_fail3"));

            _artist = Builder <Author> .CreateNew()
                      .With(e => e.QualityProfileId = 1)
                      .With(e => e.QualityProfile   = new QualityProfile {
                Items = Qualities.QualityFixture.GetDefaultQualities()
            })
                      .Build();

            _album = Builder <Book> .CreateNew()
                     .With(x => x.Author = _artist)
                     .Build();

            _edition = Builder <Edition> .CreateNew()
                       .With(x => x.Book = _album)
                       .Build();

            _quality = new QualityModel(Quality.MP3_320);

            _localTrack = new LocalBook
            {
                Author  = _artist,
                Quality = _quality,
                Book    = new Book(),
                Path    = @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi".AsOsAgnostic()
            };

            _idOverrides = new IdentificationOverrides
            {
                Author = _artist
            };

            _idConfig = new ImportDecisionMakerConfig();

            GivenAudioFiles(new List <string> {
                @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi".AsOsAgnostic()
            });

            Mocker.GetMock <IIdentificationService>()
            .Setup(s => s.Identify(It.IsAny <List <LocalBook> >(), It.IsAny <IdentificationOverrides>(), It.IsAny <ImportDecisionMakerConfig>()))
            .Returns((List <LocalBook> tracks, IdentificationOverrides idOverrides, ImportDecisionMakerConfig config) =>
            {
                var ret     = new LocalEdition(tracks);
                ret.Edition = _edition;
                return(new List <LocalEdition> {
                    ret
                });
            });

            Mocker.GetMock <IMediaFileService>()
            .Setup(c => c.FilterUnchangedFiles(It.IsAny <List <IFileInfo> >(), It.IsAny <FilterFilesType>()))
            .Returns((List <IFileInfo> files, FilterFilesType filter) => files);

            GivenSpecifications(_albumpass1);
        }
Esempio n. 12
0
        private void IdentifyRelease(LocalEdition localBookRelease, IdentificationOverrides idOverrides, ImportDecisionMakerConfig config)
        {
            var watch = System.Diagnostics.Stopwatch.StartNew();

            var candidateReleases = _candidateService.GetDbCandidatesFromTags(localBookRelease, idOverrides, config.IncludeExisting);

            if (candidateReleases.Count == 0 && config.AddNewAuthors)
            {
                candidateReleases = _candidateService.GetRemoteCandidates(localBookRelease);
            }

            if (candidateReleases.Count == 0)
            {
                // can't find any candidates even after fingerprinting
                // populate the overrides and return
                foreach (var localTrack in localBookRelease.LocalBooks)
                {
                    localTrack.Edition = idOverrides.Edition;
                    localTrack.Book    = idOverrides.Book;
                    localTrack.Author  = idOverrides.Author;
                }

                return;
            }

            _logger.Debug($"Got {candidateReleases.Count} candidates for {localBookRelease.LocalBooks.Count} tracks in {watch.ElapsedMilliseconds}ms");

            // convert all the TrackFiles that represent extra files to List<LocalTrack>
            var allLocalTracks = ToLocalTrack(candidateReleases
                                              .SelectMany(x => x.ExistingFiles)
                                              .DistinctBy(x => x.Path), localBookRelease);

            _logger.Debug($"Retrieved {allLocalTracks.Count} possible tracks in {watch.ElapsedMilliseconds}ms");

            GetBestRelease(localBookRelease, candidateReleases, allLocalTracks);

            _logger.Debug($"Best release found in {watch.ElapsedMilliseconds}ms");

            localBookRelease.PopulateMatch();

            _logger.Debug($"IdentifyRelease done in {watch.ElapsedMilliseconds}ms");
        }