diff --git a/src/NzbDrone.Core/Exceptions/EditionNotFoundException.cs b/src/NzbDrone.Core/Exceptions/EditionNotFoundException.cs new file mode 100644 index 000000000..98f399fc7 --- /dev/null +++ b/src/NzbDrone.Core/Exceptions/EditionNotFoundException.cs @@ -0,0 +1,27 @@ +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Exceptions +{ + public class EditionNotFoundException : NzbDroneException + { + public string MusicBrainzId { get; set; } + + public EditionNotFoundException(string musicbrainzId) + : base(string.Format("Edition with id {0} was not found, it may have been removed from metadata server.", musicbrainzId)) + { + MusicBrainzId = musicbrainzId; + } + + public EditionNotFoundException(string musicbrainzId, string message, params object[] args) + : base(message, args) + { + MusicBrainzId = musicbrainzId; + } + + public EditionNotFoundException(string musicbrainzId, string message) + : base(message) + { + MusicBrainzId = musicbrainzId; + } + } +} diff --git a/src/NzbDrone.Core/MetadataSource/BookInfo/BookInfoProxy.cs b/src/NzbDrone.Core/MetadataSource/BookInfo/BookInfoProxy.cs index 1c7f6b38c..9c72099a1 100644 --- a/src/NzbDrone.Core/MetadataSource/BookInfo/BookInfoProxy.cs +++ b/src/NzbDrone.Core/MetadataSource/BookInfo/BookInfoProxy.cs @@ -82,12 +82,20 @@ namespace NzbDrone.Core.MetadataSource.BookInfo { _logger.Debug("Getting Author details GoodreadsId of {0}", foreignAuthorId); - if (useCache) + try { - return PollAuthor(foreignAuthorId); - } + if (useCache) + { + return PollAuthor(foreignAuthorId); + } - return PollAuthorUncached(foreignAuthorId); + return PollAuthorUncached(foreignAuthorId); + } + catch (BookInfoException e) + { + _logger.Warn(e, "Unexpected error getting author info"); + throw new AuthorNotFoundException(foreignAuthorId); + } } public HashSet GetChangedBooks(DateTime startTime) @@ -102,7 +110,15 @@ namespace NzbDrone.Core.MetadataSource.BookInfo public Tuple> GetBookInfo(string foreignBookId) { - return PollBook(foreignBookId); + try + { + return PollBook(foreignBookId); + } + catch (BookInfoException e) + { + _logger.Warn(e, "Unexpected error getting book info"); + throw new AuthorNotFoundException(foreignBookId); + } } public List SearchForNewEntity(string title) @@ -211,7 +227,17 @@ namespace NzbDrone.Core.MetadataSource.BookInfo private List Search(string query, bool getAllEditions) { - var result = _goodreadsSearchProxy.Search(query); + List result; + try + { + result = _goodreadsSearchProxy.Search(query); + } + catch (Exception e) + { + _logger.Warn(e, "Error searching for {0}", query); + return new List(); + } + var books = new List(); if (getAllEditions) @@ -250,18 +276,19 @@ namespace NzbDrone.Core.MetadataSource.BookInfo if (ids.Count == 1) { - try - { - return SearchByGoodreadsBookId(ids[0], false); - } - catch (BookNotFoundException) - { - _logger.Debug($"Couldn't fetch book info for {ids[0]}"); - return new List(); - } + return SearchByGoodreadsBookId(ids[0], false); + } + + try + { + return MapSearchResult(ids); } + catch (Exception e) + { + _logger.Warn(e, "Error mapping search results"); - return MapSearchResult(ids); + return new List(); + } } } @@ -285,6 +312,11 @@ namespace NzbDrone.Core.MetadataSource.BookInfo { return new List(); } + catch (BookInfoException e) + { + _logger.Warn(e, "Error searching by author id"); + return new List(); + } } public List SearchByGoodreadsWorkId(int id) @@ -299,9 +331,41 @@ namespace NzbDrone.Core.MetadataSource.BookInfo { return new List(); } + catch (BookInfoException e) + { + _logger.Warn(e, "Error searching by work id"); + return new List(); + } } public List SearchByGoodreadsBookId(int id, bool getAllEditions) + { + try + { + var book = GetEditionInfo(id, getAllEditions); + + return new List { book }; + } + catch (AuthorNotFoundException) + { + return new List(); + } + catch (BookNotFoundException) + { + return new List(); + } + catch (EditionNotFoundException) + { + return new List(); + } + catch (BookInfoException e) + { + _logger.Warn(e, "Error searching by book id"); + return new List(); + } + } + + private Book GetEditionInfo(int id, bool getAllEditions) { var httpRequest = _requestBuilder.GetRequestBuilder().Create() .SetSegment("route", $"book/{id}") @@ -314,7 +378,7 @@ namespace NzbDrone.Core.MetadataSource.BookInfo if (httpResponse.StatusCode == HttpStatusCode.NotFound) { - return new List(); + throw new EditionNotFoundException(id.ToString()); } if (!httpResponse.HasHttpRedirect) @@ -349,9 +413,9 @@ namespace NzbDrone.Core.MetadataSource.BookInfo throw new NotImplementedException($"Unexpected response from {httpResponse.Request.Url}"); } - if (book == null) + if (book == null || book.Editions.Value.All(e => e.ForeignEditionId != id.ToString())) { - return new List(); + throw new EditionNotFoundException(id.ToString()); } if (!getAllEditions) @@ -362,20 +426,15 @@ namespace NzbDrone.Core.MetadataSource.BookInfo trimmed.AuthorMetadata = book.AuthorMetadata.Value; trimmed.SeriesLinks = book.SeriesLinks; var edition = book.Editions.Value.SingleOrDefault(e => e.ForeignEditionId == id.ToString()); - if (edition == null) - { - return new List(); - } trimmed.Editions = new List { edition }; - - return new List { trimmed }; + return trimmed; } var authorDict = authors.ToDictionary(x => x.ForeignAuthorId); AddDbIds(book.AuthorMetadata.Value.ForeignAuthorId, book, authorDict); - return new List { book }; + return book; } private List MapSearchResult(List ids) @@ -454,7 +513,10 @@ namespace NzbDrone.Core.MetadataSource.BookInfo if (author == null) { - var metadata = authors[authorId]; + if (!authors.TryGetValue(authorId, out var metadata)) + { + throw new BookInfoException(string.Format("Expected author metadata for id [{0}] in book data {1}", authorId, book)); + } author = new Author { @@ -502,7 +564,7 @@ namespace NzbDrone.Core.MetadataSource.BookInfo } else { - throw new HttpException(httpRequest, httpResponse); + throw new BookInfoException("Unexpected error fetching author data"); } } @@ -582,7 +644,7 @@ namespace NzbDrone.Core.MetadataSource.BookInfo } else { - throw new HttpException(httpRequest, httpResponse); + throw new BookInfoException("Unexpected response fetching book data"); } } @@ -596,7 +658,7 @@ namespace NzbDrone.Core.MetadataSource.BookInfo Thread.Sleep(2000); } - if (resource?.Books == null) + if (resource?.Books == null || resource?.Authors == null || (!resource?.Authors?.Any() ?? false)) { throw new BookInfoException($"Failed to get books for {foreignBookId}"); }