private List <CandidateEdition> GetDbCandidates(LocalEdition localEdition, bool includeExisting) { // most general version, nothing has been specified. // get all plausible artists, then all plausible albums, then get releases for each of these. var candidateReleases = new List <CandidateEdition>(); // check if it looks like VA. if (TrackGroupingService.IsVariousArtists(localEdition.LocalBooks)) { var va = _authorService.FindById(DistanceCalculator.VariousAuthorIds[0]); if (va != null) { candidateReleases.AddRange(GetDbCandidatesByAuthor(localEdition, va, includeExisting)); } } var artistTag = localEdition.LocalBooks.MostCommon(x => x.FileTrackInfo.ArtistTitle) ?? ""; if (artistTag.IsNotNullOrWhiteSpace()) { var possibleArtists = _authorService.GetCandidates(artistTag); foreach (var author in possibleArtists) { candidateReleases.AddRange(GetDbCandidatesByAuthor(localEdition, author, includeExisting)); } } return(candidateReleases); }
public List <CandidateEdition> GetRemoteCandidates(LocalEdition localEdition) { // Gets candidate book releases from the metadata server. // Will eventually need adding locally if we find a match var watch = System.Diagnostics.Stopwatch.StartNew(); List <Book> remoteBooks = null; var candidates = new List <CandidateEdition>(); var goodreads = localEdition.LocalBooks.Select(x => x.FileTrackInfo.GoodreadsId).Distinct().ToList(); var isbns = localEdition.LocalBooks.Select(x => x.FileTrackInfo.Isbn).Distinct().ToList(); var asins = localEdition.LocalBooks.Select(x => x.FileTrackInfo.Asin).Distinct().ToList(); try { if (goodreads.Count == 1 && goodreads[0].IsNotNullOrWhiteSpace()) { if (int.TryParse(goodreads[0], out var id)) { _logger.Trace($"Searching by goodreads id {id}"); remoteBooks = _bookSearchService.SearchByGoodreadsId(id); } } if ((remoteBooks == null || !remoteBooks.Any()) && isbns.Count == 1 && isbns[0].IsNotNullOrWhiteSpace()) { _logger.Trace($"Searching by isbn {isbns[0]}"); remoteBooks = _bookSearchService.SearchByIsbn(isbns[0]); } // Calibre puts junk asins into books it creates so check for sensible length if ((remoteBooks == null || !remoteBooks.Any()) && asins.Count == 1 && asins[0].IsNotNullOrWhiteSpace() && asins[0].Length == 10) { _logger.Trace($"Searching by asin {asins[0]}"); remoteBooks = _bookSearchService.SearchByAsin(asins[0]); } // if no asin/isbn or no result, fall back to text search if (remoteBooks == null || !remoteBooks.Any()) { // fall back to author / book name search string artistTag; if (TrackGroupingService.IsVariousArtists(localEdition.LocalBooks)) { artistTag = "Various Artists"; } else { artistTag = localEdition.LocalBooks.MostCommon(x => x.FileTrackInfo.ArtistTitle) ?? ""; } var albumTag = localEdition.LocalBooks.MostCommon(x => x.FileTrackInfo.AlbumTitle) ?? ""; if (artistTag.IsNullOrWhiteSpace() || albumTag.IsNullOrWhiteSpace()) { return(candidates); } remoteBooks = _bookSearchService.SearchForNewBook(albumTag, artistTag); if (!remoteBooks.Any()) { var albumSearch = _bookSearchService.SearchForNewBook(albumTag, null); var artistSearch = _bookSearchService.SearchForNewBook(artistTag, null); remoteBooks = albumSearch.Concat(artistSearch).DistinctBy(x => x.ForeignBookId).ToList(); } } } catch (SkyHookException e) { _logger.Info(e, "Skipping book due to SkyHook error"); remoteBooks = new List <Book>(); } foreach (var book in remoteBooks) { // We have to make sure various bits and pieces are populated that are normally handled // by a database lazy load foreach (var edition in book.Editions.Value) { edition.Book = book; candidates.Add(new CandidateEdition { Edition = edition, ExistingFiles = new List <BookFile>() }); } } watch.Stop(); _logger.Debug($"Getting {candidates.Count} remote candidates from tags for {localEdition.LocalBooks.Count} tracks took {watch.ElapsedMilliseconds}ms"); return(candidates); }