private static Book MapBook(WorkResource resource) { var book = new Book { ForeignBookId = resource.ForeignId.ToString(), Title = resource.Title, TitleSlug = resource.ForeignId.ToString(), CleanTitle = Parser.Parser.CleanAuthorName(resource.Title), ReleaseDate = resource.ReleaseDate, Genres = resource.Genres, RelatedBooks = resource.RelatedWorks }; book.Links.Add(new Links { Url = resource.Url, Name = "Goodreads Editions" }); if (resource.Books != null) { book.Editions = resource.Books.Select(x => MapEdition(x)).ToList(); // monitor the most popular release var mostPopular = book.Editions.Value.OrderByDescending(x => x.Ratings.Popularity).FirstOrDefault(); if (mostPopular != null) { mostPopular.Monitored = true; // fix work title if missing if (book.Title.IsNullOrWhiteSpace()) { book.Title = mostPopular.Title; } } } else { book.Editions = new List <Edition>(); } // If we are missing the book release date, set as the earliest edition release date if (!book.ReleaseDate.HasValue) { var editionReleases = book.Editions.Value .Where(x => x.ReleaseDate.HasValue && x.ReleaseDate.Value.Month != 1 && x.ReleaseDate.Value.Day != 1) .ToList(); if (editionReleases.Any()) { book.ReleaseDate = editionReleases.Min(x => x.ReleaseDate.Value); } else { editionReleases = book.Editions.Value.Where(x => x.ReleaseDate.HasValue).ToList(); if (editionReleases.Any()) { book.ReleaseDate = editionReleases.Min(x => x.ReleaseDate.Value); } } } Debug.Assert(!book.Editions.Value.Any() || book.Editions.Value.Count(x => x.Monitored) == 1, "one edition monitored"); book.AnyEditionOk = true; var ratingCount = book.Editions.Value.Sum(x => x.Ratings.Votes); if (ratingCount > 0) { book.Ratings = new Ratings { Votes = ratingCount, Value = book.Editions.Value.Sum(x => x.Ratings.Votes * x.Ratings.Value) / ratingCount }; } else { book.Ratings = new Ratings { Votes = 0, Value = 0 }; } return(book); }
private static int GetAuthorId(WorkResource b) { return(b.Books.OrderByDescending(x => x.RatingCount * x.AverageRating).FirstOrDefault(x => x.Contributors.Any())?.Contributors.First().ForeignId ?? 0); }
private Tuple <string, Book, List <AuthorMetadata> > PollBook(string foreignBookId) { WorkResource resource = null; for (var i = 0; i < 60; i++) { var httpRequest = _requestBuilder.GetRequestBuilder().Create() .SetSegment("route", $"work/{foreignBookId}") .Build(); httpRequest.SuppressHttpError = true; // this may redirect to an author var httpResponse = _httpClient.Get(httpRequest); if (httpResponse.StatusCode == HttpStatusCode.NotFound) { throw new BookNotFoundException(foreignBookId); } if (httpResponse.HasHttpRedirect) { var location = httpResponse.Headers.GetSingleValue("Location"); var split = location.Split('/'); var type = split[0]; var newId = split[1]; if (type == "author") { var author = PollAuthor(newId); var authorBook = author.Books.Value.SingleOrDefault(x => x.ForeignBookId == foreignBookId); if (authorBook == null) { throw new BookNotFoundException(foreignBookId); } var authorMetadata = new List <AuthorMetadata> { author.Metadata.Value }; return(Tuple.Create(author.ForeignAuthorId, authorBook, authorMetadata)); } else { throw new NotImplementedException($"Unexpected response from {httpResponse.Request.Url}"); } } if (httpResponse.HasHttpError) { if (httpResponse.StatusCode == HttpStatusCode.BadRequest) { throw new BadRequestException(foreignBookId); } else { throw new BookInfoException("Unexpected response fetching book data"); } } resource = JsonSerializer.Deserialize <WorkResource>(httpResponse.Content, SerializerSettings); if (resource.Books != null) { break; } Thread.Sleep(2000); } if (resource?.Books == null || resource?.Authors == null || (!resource?.Authors?.Any() ?? false)) { throw new BookInfoException($"Failed to get books for {foreignBookId}"); } var book = MapBook(resource); var authorId = GetAuthorId(resource).ToString(); var metadata = resource.Authors.Select(MapAuthorMetadata).ToList(); var series = resource.Series.Select(MapSeries).ToList(); MapSeriesLinks(series, new List <Book> { book }, resource.Series); return(Tuple.Create(authorId, book, metadata)); }