Greatly simplify scrobbling books

This commit is contained in:
2023-04-15 09:03:06 -04:00
parent f9dcc0d341
commit fb107c083f
3 changed files with 54 additions and 68 deletions

View File

@ -96,30 +96,42 @@ class Book(LongPlayScrobblableMixin):
def get_absolute_url(self): def get_absolute_url(self):
return reverse("books:book_detail", kwargs={"slug": self.uuid}) 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: if not self.openlibrary_id or force_update:
author_name = "" author_name = ""
if self.author: if self.author:
author_name = self.author.name 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}") logger.warn(f"Book not found in OL {self.title}")
return return
cover_url = book_dict.pop("cover_url", "") # We can discard the author name from OL for now, we'll lookup details below
ol_author_id = book_dict.pop("ol_author_id", "") data.pop("ol_author_name", "")
ol_author_name = book_dict.pop("ol_author_name", "") self.fix_authors_metadata(data.pop("ol_author_id", ""))
if book_dict.get("pages") == None:
book_dict.pop("pages")
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( logger.warn(
f"OL and KoReader disagree on this book title {self.title} != {ol_title}" 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() self.refresh_from_db()
if cover_url: if cover_url:
@ -129,12 +141,31 @@ class Book(LongPlayScrobblableMixin):
self.cover.save(fname, ContentFile(r.content), save=True) self.cover.save(fname, ContentFile(r.content), save=True)
if self.pages: if self.pages:
self.run_time_seconds = self.pages * int( self.run_time_seconds = int(self.pages) * int(
self.AVG_PAGE_READING_SECONDS self.AVG_PAGE_READING_SECONDS
) )
self.save() 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 @property
def author(self): def author(self):
return self.authors.first() return self.authors.first()
@ -161,10 +192,14 @@ class Book(LongPlayScrobblableMixin):
return progress return progress
@classmethod @classmethod
def find_or_create(cls, lookup_id: str, author: str = "") -> "Game": def find_or_create(cls, lookup_id: str, author: str = "") -> "Book":
from books.utils import update_or_create_book data = lookup_book_from_openlibrary(lookup_id, author)
return update_or_create_book(lookup_id, author) book, book_created = cls.objects.get_or_create(isbn=data["isbn"])
if book_created:
book.fix_metadata(data=data)
return book
class Page(TimeStampedModel): class Page(TimeStampedModel):

View File

@ -1,5 +1,6 @@
import json import json
import logging import logging
from typing import Optional
import urllib import urllib
import requests 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) title_quoted = urllib.parse.quote(title)
author_quoted = "" author_quoted = ""
if author: if author:

View File

@ -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