mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-11-15 12:58:31 +00:00
fix(direct_download): Anna's Archive search 404 on ISBN queries (#1456)
When ISBN filters are present, the search query is now the deduplicated bare ISBN strings, with the free-text query appended only if it is not already one of those tokens. Searches with no ISBN still send the quoted free-text query alone. An Anna's Archive lookup that includes an ISBN comes back as 404 Not Found, so the direct-download release search fails and the book cannot be retrieved. The failing request puts an isbn13:/isbn10: boolean expression in the q parameter. The direct-download search query tests passed. Closes #1444 Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
This commit is contained in:
1 parent
84d1d7196c
commit
d3bcf0674d
2 files changed
+90
-4
No files matched your search
@@ -722,11 +722,17 @@ def search_books(query: str, filters: SearchFilters) -> tuple[list[BrowseRecord]
|
||||
Exception: If parsing fails
|
||||
|
||||
"""
|
||||
query_html = quote(query)
|
||||
|
||||
# isbn13:/isbn10: boolean syntax 404s; search the bare ISBN strings instead.
|
||||
if filters.isbn:
|
||||
isbns = " || ".join([f"('isbn13:{isbn}' || 'isbn10:{isbn}')" for isbn in filters.isbn])
|
||||
query_html = quote(f"({isbns}) {query}")
|
||||
tokens: list[str] = []
|
||||
for isbn in filters.isbn:
|
||||
if isbn not in tokens:
|
||||
tokens.append(isbn)
|
||||
if query not in tokens:
|
||||
tokens.append(query)
|
||||
query_html = quote(" ".join(tokens))
|
||||
else:
|
||||
query_html = quote(query)
|
||||
|
||||
filters_query = ""
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
import pytest
|
||||
|
||||
from shelfmark.core.config import config
|
||||
from shelfmark.core.models import SearchFilters
|
||||
from shelfmark.core.search_plan import build_release_search_plan
|
||||
@@ -5,6 +9,7 @@ from shelfmark.metadata_providers import BookMetadata
|
||||
from shelfmark.release_sources import BrowseRecord
|
||||
from shelfmark.release_sources.direct_download import DirectDownloadSource
|
||||
from shelfmark.release_sources.direct_download import annas_archive as aa
|
||||
from shelfmark.release_sources.direct_download.common import get_supported_formats
|
||||
|
||||
|
||||
def _browse_record(record_id: str, title: str) -> BrowseRecord:
|
||||
@@ -186,6 +191,81 @@ class TestDirectDownloadSearchQueries:
|
||||
]
|
||||
|
||||
|
||||
def _record_search_pages(monkeypatch, body: str) -> list[str]:
|
||||
urls: list[str] = []
|
||||
|
||||
def _fake_html_get_page(url: str, selector, **_kwargs):
|
||||
del selector
|
||||
urls.append(url)
|
||||
return body
|
||||
|
||||
monkeypatch.setattr(aa.network, "get_aa_base_url", lambda: "https://mirror.example")
|
||||
monkeypatch.setattr(aa.network, "AAMirrorSelector", lambda: object())
|
||||
monkeypatch.setattr(
|
||||
aa.network, "get_available_aa_urls", lambda: ["https://a.example", "https://b.example"]
|
||||
)
|
||||
monkeypatch.setattr(aa, "_enrich_search_results_with_downloads", lambda _books: None)
|
||||
monkeypatch.setattr(aa.downloader, "html_get_page", _fake_html_get_page)
|
||||
return urls
|
||||
|
||||
|
||||
def _decoded_search_query(url: str) -> str:
|
||||
return parse_qs(urlparse(url).query)["q"][0]
|
||||
|
||||
|
||||
def test_isbn_search_requests_the_bare_isbn(monkeypatch):
|
||||
urls = _record_search_pages(monkeypatch, "No files found.")
|
||||
|
||||
aa.search_books("9788845269837", SearchFilters(isbn=["9788845269837"]))
|
||||
|
||||
url = urls[0]
|
||||
assert _decoded_search_query(url) == "9788845269837"
|
||||
assert "display=table" in url
|
||||
assert f"&ext={'&ext='.join(get_supported_formats())}" in url
|
||||
assert "isbn13" not in url
|
||||
assert "isbn10" not in url
|
||||
assert "||" not in url
|
||||
assert "%7C" not in url
|
||||
|
||||
|
||||
def test_isbn_search_includes_a_distinct_free_text_query(monkeypatch):
|
||||
urls = _record_search_pages(monkeypatch, "No files found.")
|
||||
|
||||
aa.search_books("Dune", SearchFilters(isbn=["9780441172719"]))
|
||||
|
||||
query = _decoded_search_query(urls[0])
|
||||
assert query == "9780441172719 Dune"
|
||||
assert "isbn13" not in query
|
||||
assert "isbn10" not in query
|
||||
assert "||" not in query
|
||||
|
||||
|
||||
def test_search_without_isbn_keeps_the_free_text_query(monkeypatch):
|
||||
urls = _record_search_pages(monkeypatch, "No files found.")
|
||||
|
||||
aa.search_books("Dune Messiah", SearchFilters())
|
||||
|
||||
assert _decoded_search_query(urls[0]) == "Dune Messiah"
|
||||
assert "q=Dune%20Messiah" in urls[0]
|
||||
|
||||
|
||||
def test_duplicate_isbn_filters_are_sent_once(monkeypatch):
|
||||
urls = _record_search_pages(monkeypatch, "No files found.")
|
||||
|
||||
aa.search_books("Dune", SearchFilters(isbn=["9780441172719", "9780441172719"]))
|
||||
|
||||
assert _decoded_search_query(urls[0]) == "9780441172719 Dune"
|
||||
|
||||
|
||||
def test_empty_isbn_search_page_is_terminal(monkeypatch):
|
||||
urls = _record_search_pages(monkeypatch, "")
|
||||
|
||||
with pytest.raises(aa.SearchUnavailableError):
|
||||
aa.search_books("9788845269837", SearchFilters(isbn=["9788845269837"]))
|
||||
|
||||
assert len(urls) == 1
|
||||
|
||||
|
||||
# --- Distant-path language detection tests ---
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user