From 102380a8ff17a1b334fe3de317049c33bfd95cde Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Tue, 1 Sep 2026 13:00:20 -0400 Subject: [PATCH] [books] Fix dead source icon links and gate ComicVine lookups --- PROJECT.org | 45 +++++++++- tests/books_tests/test_book_source_links.py | 84 ++++++++++++++++++ .../commands/cleanup_book_metadata.py | 13 ++- vrobbler/apps/books/models.py | 44 ++++++++- .../scrobbles/static/images/bookshop-logo.png | Bin 0 -> 25713 bytes .../static/images/openlibrary-logo.png | Bin 0 -> 16000 bytes vrobbler/settings.py | 2 + vrobbler/templates/books/book_detail.html | 4 +- .../templates/bricksets/brickset_detail.html | 4 - 9 files changed, 181 insertions(+), 15 deletions(-) create mode 100644 tests/books_tests/test_book_source_links.py create mode 100644 vrobbler/apps/scrobbles/static/images/bookshop-logo.png create mode 100644 vrobbler/apps/scrobbles/static/images/openlibrary-logo.png diff --git a/PROJECT.org b/PROJECT.org index 41b746e..9a605aa 100644 --- a/PROJECT.org +++ b/PROJECT.org @@ -616,6 +616,50 @@ author name (like Track does with =musicbrainz_id=). the author to the Google lookup and persists =google_books_id= on backfill. - Migration ~0040_book_google_books_id~ adds the field. +** DONE [#C] Fix dead source icon links on book and brick set pages :books:templates: +:PROPERTIES: +:ID: 35ce01a2-0dca-4bd3-83ea-ca826c734c36 +:END: + +*** Description + +The book detail page rendered OpenLibrary and Amazon source icons via +=object.openlibrary_link= and =object.amazon_link=, but neither property +existed on =Book= (the model has no Amazon ASIN field at all), so both icons +were dead links around broken images. The brick set detail page was a copy of +the book template and had the same broken icons for a type with no +OpenLibrary/Amazon presence. + +*** Implementation + +- ~vrobbler/apps/books/models.py~: added =Book.openlibrary_link= (builds + =https://openlibrary.org/works/{olid}= or =/books/{olid}= for edition IDs) + and =Book.bookshop_link= (uses the ISBN, in =/a/{affiliate_id}/{isbn}= + affiliate form when =BOOKSHOP_AFFILIATE_ID= is set, otherwise a + =/books?keywords={isbn}= search link). +- ~vrobbler/settings.py~: added =BOOKSHOP_AFFILIATE_ID= read from + =VROBBLER_BOOKSHOP_AFFILIATE_ID=. +- ~vrobbler/templates/books/book_detail.html~: source icons now render + conditionally (only when a link exists, like the music pages), link to + OpenLibrary and Bookshop, and the dead Amazon icon is gone. +- ~vrobbler/templates/bricksets/brickset_detail.html~: removed the dead + OpenLibrary/Amazon source icon row entirely. +- Added official OpenLibrary and Bookshop logos at + ~vrobbler/apps/scrobbles/static/images/~ + (=openlibrary-logo.png=, =bookshop-logo.png=). +- Tests in ~tests/books_tests/test_book_source_links.py= cover both link + properties (work vs edition OLIDs, ISBN-10/13, with/without affiliate ID). +- ~vrobbler/apps/books/management/commands/cleanup_book_metadata.py~: added a + =--missing-source_id= filter flag for books lacking any of + =openlibrary_id= / =google_books_id= / =comicvine_id=. +- ~vrobbler/apps/books/models.py~: added =Book.is_comic= so ComicVine is only + queried for books that already carry comic source data + (=comicvine_id=, =volume_comicvine_id=, =readcomics_url=, issue/volume + fields) or whose title contains "Issue "/"Volume ". The blanket ComicVine + fallback in =find_or_create()=, =fix_metadata()=, and + ~cleanup_book_metadata.py~ now respects this, so unrelated prose books no + longer get matched to comics. + ** DONE [#B] Books created via koreader do not get enriched :books:metadata:bug: :PROPERTIES: :ID: ddfed612-1f4e-b0bb-5310-19adf9cf9336 @@ -683,7 +727,6 @@ include their scrobbles in global aggregation. If that check box is not selected - Tests in ~vrobbler/apps/charts/tests/test_views.py~ and new global chart tests in ~vrobbler/apps/charts/tests/test_utils.py~. - ** DONE [#B] Make it possible for anonymous users to view media objects :media:templates: :PROPERTIES: :ID: f12fd0b4-b728-4fbc-adf7-d51695d8c155 diff --git a/tests/books_tests/test_book_source_links.py b/tests/books_tests/test_book_source_links.py new file mode 100644 index 0000000..f93c415 --- /dev/null +++ b/tests/books_tests/test_book_source_links.py @@ -0,0 +1,84 @@ +import pytest +from books.models import Book +from django.test import override_settings + + +@pytest.mark.django_db +def test_openlibrary_link_work_id(): + book = Book.objects.create(title="Test Book", openlibrary_id="OL1234567W") + assert book.openlibrary_link == "https://openlibrary.org/works/OL1234567W" + + +@pytest.mark.django_db +def test_openlibrary_link_edition_id(): + book = Book.objects.create(title="Test Book", openlibrary_id="OL1234567M") + assert book.openlibrary_link == "https://openlibrary.org/books/OL1234567M" + + +@pytest.mark.django_db +def test_openlibrary_link_empty(): + book = Book.objects.create(title="Test Book") + assert book.openlibrary_link == "" + + +@pytest.mark.django_db +def test_bookshop_link_isbn_13_without_affiliate(): + book = Book.objects.create(title="Test Book", isbn_13="9783161484100") + assert book.bookshop_link == "https://bookshop.org/books?keywords=9783161484100" + + +@pytest.mark.django_db +def test_bookshop_link_isbn_10_without_affiliate(): + book = Book.objects.create(title="Test Book", isbn_10="0805061762") + assert book.bookshop_link == "https://bookshop.org/books?keywords=0805061762" + + +@pytest.mark.django_db +@override_settings(BOOKSHOP_AFFILIATE_ID="abc123") +def test_bookshop_link_with_affiliate(): + book = Book.objects.create(title="Test Book", isbn_13="9783161484100") + assert book.bookshop_link == "https://bookshop.org/a/abc123/9783161484100" + + +@pytest.mark.django_db +def test_bookshop_link_empty(): + book = Book.objects.create(title="Test Book") + assert book.bookshop_link == "" + + +@pytest.mark.django_db +def test_is_comic_false_for_prose_book(): + book = Book.objects.create(title="A Gentle Madness") + assert book.is_comic is False + + +@pytest.mark.django_db +def test_is_comic_true_for_comicvine_id(): + book = Book.objects.create(title="Spider-Man", comicvine_id="538480") + assert book.is_comic is True + + +@pytest.mark.django_db +def test_is_comic_true_for_readcomics_url(): + book = Book.objects.create( + title="Saga", readcomics_url="https://readcomicsonline.ru/comic/saga/1" + ) + assert book.is_comic is True + + +@pytest.mark.django_db +def test_is_comic_true_for_issue_number(): + book = Book.objects.create(title="Watchmen", issue_number=1) + assert book.is_comic is True + + +@pytest.mark.django_db +def test_is_comic_true_for_issue_in_title(): + book = Book.objects.create(title="Star Wars Issue 42") + assert book.is_comic is True + + +@pytest.mark.django_db +def test_is_comic_true_for_volume_in_title(): + book = Book.objects.create(title="East of West Volume 2") + assert book.is_comic is True diff --git a/vrobbler/apps/books/management/commands/cleanup_book_metadata.py b/vrobbler/apps/books/management/commands/cleanup_book_metadata.py index 91d4222..e69a959 100644 --- a/vrobbler/apps/books/management/commands/cleanup_book_metadata.py +++ b/vrobbler/apps/books/management/commands/cleanup_book_metadata.py @@ -16,6 +16,7 @@ MISSING_ALL = [ "language", "publisher", "publish_year", + "source_id", ] @@ -36,6 +37,9 @@ MISSING_GROUPS = { "language": lambda b: not b.language, "publisher": lambda b: not b.publisher, "publish_year": lambda b: b.first_publish_year is None, + "source_id": lambda b: not ( + b.openlibrary_id or b.google_books_id or b.comicvine_id + ), } @@ -184,10 +188,11 @@ class Command(BaseCommand): book_dict = {} cv_data = None - if book.comicvine_id: - cv_data = lookup_issue_by_comicvine_id(str(book.comicvine_id)) - if not cv_data: - cv_data = lookup_comic_from_comicvine(title) + if book.is_comic: + if book.comicvine_id: + cv_data = lookup_issue_by_comicvine_id(str(book.comicvine_id)) + if not cv_data: + cv_data = lookup_comic_from_comicvine(title) if cv_data: book_dict.update(cv_data) diff --git a/vrobbler/apps/books/models.py b/vrobbler/apps/books/models.py index 08dfb15..066cca8 100644 --- a/vrobbler/apps/books/models.py +++ b/vrobbler/apps/books/models.py @@ -240,12 +240,48 @@ class Book(LongPlayScrobblableMixin): def get_absolute_url(self): return reverse("books:book_detail", kwargs={"slug": self.uuid}) + @property + def openlibrary_link(self) -> str: + if not self.openlibrary_id: + return "" + if self.openlibrary_id.endswith("M"): + return f"https://openlibrary.org/books/{self.openlibrary_id}" + return f"https://openlibrary.org/works/{self.openlibrary_id}" + + @property + def bookshop_link(self) -> str: + isbn = self.isbn_13 or self.isbn_10 + if not isbn: + return "" + affiliate_id = getattr(settings, "BOOKSHOP_AFFILIATE_ID", "") + if affiliate_id: + return f"https://bookshop.org/a/{affiliate_id}/{isbn}" + return f"https://bookshop.org/books?keywords={isbn}" + @property def resume_start_url(self): return ( reverse("scrobbles:start", kwargs={"media_uuid": self.uuid}) + "?resume=1" ) + @property + def is_comic(self) -> bool: + """True if this book looks like a comic rather than prose. + + We don't want to send every book title through ComicVine, since it + will happily return comic matches for unrelated titles. Only treat a + book as a comic when it already has comic source data, or its title + smells like an issue/volume. + """ + if self.comicvine_id or self.volume_comicvine_id: + return True + if self.readcomics_url or self.next_readcomics_url: + return True + if self.issue_number or self.volume_number or self.volume: + return True + title = self.original_title or self.title or "" + return "Issue " in title or "Volume " in title + @classmethod def get_from_comicvine( cls, title: str, overwrite: bool = False, force_new: bool = False @@ -333,9 +369,9 @@ class Book(LongPlayScrobblableMixin): if ol_data and ol_data.get("cover_url"): book_dict["cover_url"] = ol_data["cover_url"] - # Always try ComicVine as a fallback — it may recognize books that - # OL/Google don't flag as comics - if not tried_comicvine: + # Try ComicVine as a fallback, but only for titles that look like + # comics — otherwise it matches unrelated prose books to comics. + if not tried_comicvine and ("Issue " in title or "Volume " in title): cv_data = lookup_comic_from_comicvine(title) if cv_data: for k, v in cv_data.items(): @@ -443,7 +479,7 @@ class Book(LongPlayScrobblableMixin): logger.warn(f"Checking LOCG for {self.title}") data = lookup_comic_from_locg(str(self.title)) - if not data and COMICVINE_API_KEY: + if not data and COMICVINE_API_KEY and self.is_comic: if self.comicvine_id: logger.warn(f"Checking ComicVine by ID for {self.title}") data = lookup_issue_by_comicvine_id(str(self.comicvine_id)) diff --git a/vrobbler/apps/scrobbles/static/images/bookshop-logo.png b/vrobbler/apps/scrobbles/static/images/bookshop-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e17c04b64afccf42c666751ed7ad1556ccdd82 GIT binary patch literal 25713 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 literal 0 HcmV?d00001 diff --git a/vrobbler/apps/scrobbles/static/images/openlibrary-logo.png b/vrobbler/apps/scrobbles/static/images/openlibrary-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8ea28b554608e6ab52dba1331ace07a9e22d2be7 GIT binary patch literal 16000 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 literal 0 HcmV?d00001 diff --git a/vrobbler/settings.py b/vrobbler/settings.py index d7cc2a5..f90404f 100644 --- a/vrobbler/settings.py +++ b/vrobbler/settings.py @@ -143,6 +143,8 @@ AMAZON_PAAPI_SECRET_KEY = os.getenv("VROBBLER_AMAZON_PAAPI_SECRET_KEY", "") AMAZON_PAAPI_ASSOCIATE_TAG = os.getenv("VROBBLER_AMAZON_PAAPI_ASSOCIATE_TAG", "") AMAZON_PAAPI_COUNTRY = os.getenv("VROBBLER_AMAZON_PAAPI_COUNTRY", "US") +BOOKSHOP_AFFILIATE_ID = os.getenv("VROBBLER_BOOKSHOP_AFFILIATE_ID", "") + FASTCORK_API_KEY = os.getenv("VROBBLER_FASTCORK_API_KEY", "") DEFAULT_TASK_CONTEXT_TAGS = [ diff --git a/vrobbler/templates/books/book_detail.html b/vrobbler/templates/books/book_detail.html index 39b402b..db2dc22 100644 --- a/vrobbler/templates/books/book_detail.html +++ b/vrobbler/templates/books/book_detail.html @@ -20,8 +20,8 @@
{% endif %}

- - + {% if object.openlibrary_link %}{% endif %} + {% if object.bookshop_link %}{% endif %}

diff --git a/vrobbler/templates/bricksets/brickset_detail.html b/vrobbler/templates/bricksets/brickset_detail.html index f463439..ca4eaba 100644 --- a/vrobbler/templates/bricksets/brickset_detail.html +++ b/vrobbler/templates/bricksets/brickset_detail.html @@ -19,10 +19,6 @@

{{object.summary|safe|linebreaks|truncatewords:160}}


{% endif %} -

- - -