From 6231678c289570d81ca947d5081041d2da69b883 Mon Sep 17 00:00:00 2001 From: bullitt168 Date: Mon, 15 Jun 2026 04:45:36 +0200 Subject: [PATCH] fix: "No files found." check produces false positives when AA returns results alongside that string (#1067) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem Searching Anna's Archive with multiple format filters (e.g. `epub`, `mobi`, `pdf`, …) combined with a language filter (`lang=de`) and a specific title produces a response that **contains both a full results table and a `\"No files found.\"` span** in a separate section of the page. The previous code performed a naïve substring check on the raw HTML before parsing: ```python if "No files found." in html: logger.info("No books found for query: %s", query) return [] ``` When Anna's Archive renders a page that has, e.g., results for one content type but no results for another sub-filter, it emits a `No files found.` in the empty sub-section while the main results table is fully populated (650+ entries in the tested case). The early return discards all those results, making Shelfmark appear unable to find anything on Anna's Archive. Reported upstream as: https://github.com/calibrain/shelfmark/issues/1042 ## Root cause The string `"No files found."` appears in multiple places on an AA search results page. It is not a reliable signal that the entire query returned zero results — only that *some* filtered sub-section is empty. ## Fix Parse the HTML into BeautifulSoup first and look for the results ``. Only if no table is present does it make sense to fall back to the string check: ```python soup = BeautifulSoup(_html_response_text(html), "html.parser") tbody = soup.find("table") if tbody is None: if "No files found." in html: logger.info("No books found for query: %s", query) return [] logger.warning("No results table found for query: %s", query) msg = "No books found. Please try another query." raise RuntimeError(msg) ``` This preserves both existing behaviours: - Genuine empty results (no table + "No files found." present) → return `[]` - Unexpected response structure (no table, no "No files found." either) → raise `RuntimeError` And fixes the false-positive case (table present + "No files found." in another section) → proceed normally and parse the table. ## Testing Verified on a self-hosted Shelfmark v1.3.0 instance against `annas-archive.gl`: - Query: `"Reise zum Mittelpunkt der Erde"` + `lang=de` + all supported ebook formats - Before fix: `search_books()` returned `[]` immediately - After fix: `search_books()` returned 6 matching German epub/mobi results The fix is a pure restructuring — no logic is added or removed, only the order of operations changes. --- shelfmark/release_sources/direct_download.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/shelfmark/release_sources/direct_download.py b/shelfmark/release_sources/direct_download.py index c919cbdf..306e064d 100644 --- a/shelfmark/release_sources/direct_download.py +++ b/shelfmark/release_sources/direct_download.py @@ -397,14 +397,13 @@ def search_books(query: str, filters: SearchFilters) -> list[BrowseRecord]: msg = "Unable to reach download source. Network restricted or mirrors are blocked." raise SearchUnavailableError(msg) - if "No files found." in html: - logger.info("No books found for query: %s", query) - return [] - soup = BeautifulSoup(_html_response_text(html), "html.parser") tbody = soup.find("table") if tbody is None: + if "No files found." in html: + logger.info("No books found for query: %s", query) + return [] logger.warning("No results table found for query: %s", query) msg = "No books found. Please try another query." raise RuntimeError(msg)