diff --git a/abogen/integrations/calibre_opds.py b/abogen/integrations/calibre_opds.py index 2d264d3..f2ea3f4 100644 --- a/abogen/integrations/calibre_opds.py +++ b/abogen/integrations/calibre_opds.py @@ -166,7 +166,12 @@ class CalibreOPDSClient: href = href.strip() if href.startswith("http://") or href.startswith("https://"): return href - return urljoin(self._base_url, href) + if href.startswith("/") or href.startswith("?") or href.startswith("#"): + return urljoin(self._base_url, href) + if href.startswith("./") or href.startswith("../"): + return urljoin(self._base_url, href) + # Ensure relative paths like "search" keep the catalog prefix + return urljoin(self._base_url, f"./{href}") def _open_client(self) -> httpx.Client: return httpx.Client( diff --git a/tests/test_calibre_opds.py b/tests/test_calibre_opds.py index 06d8e43..edd5975 100644 --- a/tests/test_calibre_opds.py +++ b/tests/test_calibre_opds.py @@ -95,3 +95,12 @@ This is the detailed summary text. assert entry.rating_max == 5.0 assert entry.summary == "This is the detailed summary text." assert entry.published == "2024-01-15T00:00:00+00:00" + + +def test_calibre_opds_relative_urls_keep_catalog_prefix() -> None: + client = CalibreOPDSClient("http://example.com/opds/") + + assert client._make_url("search") == "http://example.com/opds/search" + assert client._make_url("books/sample.epub") == "http://example.com/opds/books/sample.epub" + assert client._make_url("/cover/1") == "http://example.com/cover/1" + assert client._make_url("?page=2") == "http://example.com/opds/?page=2"