Greatly simplify scrobbling books
This commit is contained in:
@ -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):
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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
|
|
||||||
Reference in New Issue
Block a user