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); }
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()); }
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); }
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); }
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); }
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"); }
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); }
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"); }
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); }
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"); }