Browse Source

Greatly simplify scrobbling books

Colin Powell 2 years ago
parent
commit
fb107c083f
3 changed files with 54 additions and 68 deletions
  1. 50 15
      vrobbler/apps/books/models.py
  2. 4 1
      vrobbler/apps/books/openlibrary.py
  3. 0 52
      vrobbler/apps/books/utils.py

+ 50 - 15
vrobbler/apps/books/models.py

@@ -96,30 +96,42 @@ class Book(LongPlayScrobblableMixin):
     def get_absolute_url(self):
         return reverse("books:book_detail", kwargs={"slug": self.uuid})
 
-    def fix_metadata(self, force_update=False):
+    def fix_metadata(self, data: dict = {}, force_update=False):
         if not self.openlibrary_id or force_update:
             author_name = ""
             if self.author:
                 author_name = self.author.name
-            book_dict = lookup_book_from_openlibrary(self.title, author_name)
-            if not book_dict:
+
+            if not data:
+                data = lookup_book_from_openlibrary(
+                    str(self.title), author_name
+                )
+
+            if not data:
                 logger.warn(f"Book not found in OL {self.title}")
                 return
 
-            cover_url = book_dict.pop("cover_url", "")
-            ol_author_id = book_dict.pop("ol_author_id", "")
-            ol_author_name = book_dict.pop("ol_author_name", "")
-            if book_dict.get("pages") == None:
-                book_dict.pop("pages")
+            # We can discard the author name from OL for now, we'll lookup details below
+            data.pop("ol_author_name", "")
+            self.fix_authors_metadata(data.pop("ol_author_id", ""))
 
-            ol_title = book_dict.get("title", "")
+            ol_title = data.get("title", "")
 
-            if ol_title.lower() != self.title.lower():
+            # Kick out a little warning if we're about to change KoReader's title
+            if ol_title.lower() != str(self.title).lower():
                 logger.warn(
                     f"OL and KoReader disagree on this book title {self.title} != {ol_title}"
                 )
 
-            Book.objects.filter(pk=self.id).update(**book_dict)
+            # If we don't know pages, don't overwrite existing with None
+            if data.get("pages") == None:
+                data.pop("pages")
+
+            # Pop this, so we can look it up later
+            cover_url = data.pop("cover_url", "")
+
+            # Fun trick for updating all fields at once
+            Book.objects.filter(pk=self.id).update(**data)
             self.refresh_from_db()
 
             if cover_url:
@@ -129,12 +141,31 @@ class Book(LongPlayScrobblableMixin):
                     self.cover.save(fname, ContentFile(r.content), save=True)
 
             if self.pages:
-                self.run_time_seconds = self.pages * int(
+                self.run_time_seconds = int(self.pages) * int(
                     self.AVG_PAGE_READING_SECONDS
                 )
 
             self.save()
 
+    def fix_authors_metadata(self, openlibrary_author_id):
+        author = Author.objects.filter(
+            openlibrary_id=openlibrary_author_id
+        ).first()
+        if not author:
+            data = lookup_author_from_openlibrary(openlibrary_author_id)
+            author_image_url = data.pop("author_headshot_url", None)
+
+            author = Author.objects.create(**data)
+
+            if author_image_url:
+                r = requests.get(author_image_url)
+                if r.status_code == 200:
+                    fname = f"{author.name}_{author.uuid}.jpg"
+                    author.headshot.save(
+                        fname, ContentFile(r.content), save=True
+                    )
+        self.authors.add(author)
+
     @property
     def author(self):
         return self.authors.first()
@@ -161,10 +192,14 @@ class Book(LongPlayScrobblableMixin):
         return progress
 
     @classmethod
-    def find_or_create(cls, lookup_id: str, author: str = "") -> "Game":
-        from books.utils import update_or_create_book
+    def find_or_create(cls, lookup_id: str, author: str = "") -> "Book":
+        data = lookup_book_from_openlibrary(lookup_id, author)
+
+        book, book_created = cls.objects.get_or_create(isbn=data["isbn"])
+        if book_created:
+            book.fix_metadata(data=data)
 
-        return update_or_create_book(lookup_id, author)
+        return book
 
 
 class Page(TimeStampedModel):

+ 4 - 1
vrobbler/apps/books/openlibrary.py

@@ -1,5 +1,6 @@
 import json
 import logging
+from typing import Optional
 import urllib
 
 import requests
@@ -74,7 +75,9 @@ def lookup_author_from_openlibrary(olid: str) -> dict:
     }
 
 
-def lookup_book_from_openlibrary(title: str, author: str = None) -> dict:
+def lookup_book_from_openlibrary(
+    title: str, author: Optional[str] = None
+) -> dict:
     title_quoted = urllib.parse.quote(title)
     author_quoted = ""
     if author:

+ 0 - 52
vrobbler/apps/books/utils.py

@@ -1,52 +0,0 @@
-from django.core.files.base import ContentFile
-import requests
-from typing import Optional
-from books.openlibrary import (
-    lookup_author_from_openlibrary,
-    lookup_book_from_openlibrary,
-)
-from books.models import Author, Book
-
-
-def update_or_create_book(
-    title: str, author: Optional[str] = None, force_update=False
-) -> Book:
-    book_dict = lookup_book_from_openlibrary(title, author)
-
-    book, book_created = Book.objects.get_or_create(
-        isbn=book_dict.get("isbn"),
-    )
-
-    if book_created or force_update:
-        cover_url = book_dict.pop("cover_url")
-        ol_author_id = book_dict.pop("ol_author_id")
-
-        Book.objects.filter(pk=book.id).update(**book_dict)
-        book.refresh_from_db()
-
-        # Process authors
-        author_dict = lookup_author_from_openlibrary(ol_author_id)
-        author = Author.objects.filter(openlibrary_id=ol_author_id).first()
-        if not author:
-            author_image_url = author_dict.pop("author_headshot_url", None)
-
-            author = Author.objects.create(**author_dict)
-
-            if author_image_url:
-                r = requests.get(author_image_url)
-                if r.status_code == 200:
-                    fname = f"{author.name}_{author.uuid}.jpg"
-                    author.headshot.save(
-                        fname, ContentFile(r.content), save=True
-                    )
-        book.authors.add(author)
-
-        # Process cover URL
-        r = requests.get(cover_url)
-        if r.status_code == 200:
-            fname = f"{book.title}_{book.uuid}.jpg"
-            book.cover.save(fname, ContentFile(r.content), save=True)
-
-        book.fix_metadata()
-
-    return book