using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Xml.Linq; namespace NzbDrone.Core.MetadataSource.Goodreads { /// /// This class models a single book as defined by the Goodreads API. /// [DebuggerDisplay("{DebuggerDisplay,nq}")] public sealed class BookResource : GoodreadsResource { public override string ElementName => "book"; /// /// The Goodreads Id for this book. /// public long Id { get; private set; } /// /// The title of this book. /// public string Title { get; private set; } public string TitleWithoutSeries { get; private set; } /// /// The description of this book. /// public string Description { get; private set; } /// /// The ISBN of this book. /// public string Isbn { get; private set; } /// /// The ISBN13 of this book. /// public string Isbn13 { get; private set; } /// /// The ASIN of this book. /// public string Asin { get; private set; } /// /// The Kindle ASIN of this book. /// public string KindleAsin { get; private set; } /// /// The marketplace Id of this book. /// public string MarketplaceId { get; private set; } /// /// The country code of this book. /// public string CountryCode { get; private set; } /// /// The cover image for this book. /// public string ImageUrl { get; private set; } /// /// The date this book was published. /// public DateTime? PublicationDate { get; private set; } /// /// The publisher of this book. /// public string Publisher { get; private set; } /// /// The language code of this book. /// public string LanguageCode { get; private set; } /// /// Signifies if this is an eBook or not. /// public bool IsEbook { get; private set; } /// /// The average rating of this book by Goodreads users. /// public decimal AverageRating { get; private set; } /// /// The number of pages in this book. /// public int Pages { get; private set; } /// /// The format of this book. /// public string Format { get; private set; } /// /// Brief information about this edition of the book. /// public string EditionInformation { get; private set; } /// /// The count of all Goodreads ratings for this book. /// public int RatingsCount { get; private set; } /// /// The count of all reviews that contain text for this book. /// public int TextReviewsCount { get; private set; } /// /// The Goodreads Url for this book. /// public string Url { get; private set; } public string EditionsUrl { get; private set; } /// /// The aggregate information for this work across all editions of the book. /// public WorkResource Work { get; private set; } /// /// The list of authors that worked on this book. /// public IReadOnlyList Authors { get; private set; } /// /// HTML and CSS for the Goodreads iFrame. Used to display the reviews for this book. /// public string ReviewsWidget { get; private set; } /// /// The most popular shelf names this book appears on. This is a /// dictionary of shelf name -> count. /// public IReadOnlyDictionary PopularShelves { get; private set; } /// /// The list of book links tracked by Goodreads. /// This is usually a list of libraries that the user can borrow the book from. /// public IReadOnlyList BookLinks { get; private set; } /// /// The list of buy links tracked by Goodreads. /// This is usually a list of third-party sites that the /// user can purchase the book from. /// public IReadOnlyList BuyLinks { get; private set; } /// /// Summary information about similar books to this one. /// public IReadOnlyList SimilarBooks { get; private set; } // TODO: parse series information once I get a better sense // of what series are from the other API calls. //// public List Series { get; private set; } public override void Parse(XElement element) { Id = element.ElementAsLong("id"); Title = element.ElementAsString("title"); TitleWithoutSeries = element.ElementAsString("title_without_series"); Isbn = element.ElementAsString("isbn"); Isbn13 = element.ElementAsString("isbn13"); Asin = element.ElementAsString("asin"); KindleAsin = element.ElementAsString("kindle_asin"); MarketplaceId = element.ElementAsString("marketplace_id"); CountryCode = element.ElementAsString("country_code"); ImageUrl = element.ElementAsString("large_image_url") ?? element.ElementAsString("image_url") ?? element.ElementAsString("small_image_url"); PublicationDate = element.ElementAsMultiDateField("publication"); Publisher = element.ElementAsString("publisher"); LanguageCode = element.ElementAsString("language_code"); IsEbook = element.ElementAsBool("is_ebook"); Description = element.ElementAsString("description"); AverageRating = element.ElementAsDecimal("average_rating"); Pages = element.ElementAsInt("num_pages"); Format = element.ElementAsString("format"); EditionInformation = element.ElementAsString("edition_information"); RatingsCount = element.ElementAsInt("ratings_count"); TextReviewsCount = element.ElementAsInt("text_reviews_count"); Url = element.ElementAsString("link"); EditionsUrl = element.ElementAsString("editions_url"); ReviewsWidget = element.ElementAsString("reviews_widget"); var workElement = element.Element("work"); if (workElement != null) { Work = new WorkResource(); Work.Parse(workElement); } Authors = element.ParseChildren("authors", "author"); SimilarBooks = element.ParseChildren("similar_books", "book"); var bookLinks = element.ParseChildren("book_links", "book_link"); if (bookLinks != null) { bookLinks.ForEach(x => x.FixBookLink(Id)); BookLinks = bookLinks; } var buyLinks = element.ParseChildren("buy_links", "buy_link"); if (buyLinks != null) { buyLinks.ForEach(x => x.FixBookLink(Id)); BuyLinks = buyLinks; } var shelves = element.ParseChildren( "popular_shelves", "shelf", (shelfElement) => { var shelfName = shelfElement?.Attribute("name")?.Value; var shelfCountValue = shelfElement?.Attribute("count")?.Value; int.TryParse(shelfCountValue, out var shelfCount); return new KeyValuePair(shelfName, shelfCount); }); if (shelves != null) { PopularShelves = shelves.GroupBy(obj => obj.Key).ToDictionary(shelf => shelf.Key, shelf => shelf.Sum(x => x.Value)); } } } }