mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
feat: Enhance search functionality in CalibreOPDSClient to support contextual search with start_href
This commit is contained in:
@@ -198,10 +198,10 @@ class CalibreOPDSClient:
|
|||||||
|
|
||||||
return self._parse_feed(response.text, base_url=target)
|
return self._parse_feed(response.text, base_url=target)
|
||||||
|
|
||||||
def search(self, query: str) -> OPDSFeed:
|
def search(self, query: str, start_href: Optional[str] = None) -> OPDSFeed:
|
||||||
cleaned = (query or "").strip()
|
cleaned = (query or "").strip()
|
||||||
if not cleaned:
|
if not cleaned:
|
||||||
return self.fetch_feed()
|
return self.fetch_feed(start_href) if start_href else self.fetch_feed()
|
||||||
|
|
||||||
base_feed: Optional[OPDSFeed] = None
|
base_feed: Optional[OPDSFeed] = None
|
||||||
try:
|
try:
|
||||||
@@ -223,51 +223,42 @@ class CalibreOPDSClient:
|
|||||||
|
|
||||||
last_error: Optional[Exception] = None
|
last_error: Optional[Exception] = None
|
||||||
base_combined: Optional[OPDSFeed] = None
|
base_combined: Optional[OPDSFeed] = None
|
||||||
|
|
||||||
|
# Try server-side search first (global search)
|
||||||
for path, params in candidates:
|
for path, params in candidates:
|
||||||
try:
|
try:
|
||||||
feed = self.fetch_feed(path, params=params)
|
feed = self.fetch_feed(path, params=params)
|
||||||
except CalibreOPDSError as exc:
|
except CalibreOPDSError as exc:
|
||||||
last_error = exc
|
last_error = exc
|
||||||
continue
|
continue
|
||||||
combined = self._merge_feed_entries(
|
|
||||||
self._collect_search_results(feed, cleaned),
|
# If we got results from server search, use them
|
||||||
self._local_search(cleaned, seed_feed=feed),
|
if feed.entries:
|
||||||
)
|
return feed
|
||||||
if combined.entries:
|
|
||||||
return combined
|
# Fallback to local search (crawling)
|
||||||
if base_feed is None:
|
# If start_href is provided, we search from there (contextual search)
|
||||||
try:
|
# Otherwise we search from root (which might be empty if root has no books)
|
||||||
base_feed = self.fetch_feed()
|
|
||||||
except CalibreOPDSError:
|
seed_feed: Optional[OPDSFeed] = None
|
||||||
base_feed = None
|
if start_href:
|
||||||
if base_feed is not None and base_combined is None:
|
|
||||||
base_combined = self._merge_feed_entries(
|
|
||||||
self._collect_search_results(base_feed, cleaned),
|
|
||||||
self._local_search(cleaned, seed_feed=base_feed),
|
|
||||||
)
|
|
||||||
if base_combined is not None and base_combined.entries:
|
|
||||||
return base_combined
|
|
||||||
if base_feed is None:
|
|
||||||
try:
|
try:
|
||||||
base_feed = self.fetch_feed()
|
seed_feed = self.fetch_feed(start_href)
|
||||||
except CalibreOPDSError as exc:
|
except CalibreOPDSError:
|
||||||
if last_error is not None:
|
pass
|
||||||
raise last_error
|
|
||||||
raise exc
|
if not seed_feed and base_feed:
|
||||||
if base_feed is None:
|
seed_feed = base_feed
|
||||||
if last_error is not None:
|
|
||||||
raise last_error
|
if not seed_feed:
|
||||||
raise CalibreOPDSError("Calibre OPDS base feed is unavailable")
|
try:
|
||||||
if base_combined is None:
|
seed_feed = self.fetch_feed()
|
||||||
base_combined = self._merge_feed_entries(
|
except CalibreOPDSError as exc:
|
||||||
self._collect_search_results(base_feed, cleaned),
|
if last_error:
|
||||||
self._local_search(cleaned, seed_feed=base_feed),
|
raise last_error
|
||||||
)
|
raise exc
|
||||||
if base_combined.entries:
|
|
||||||
return base_combined
|
return self._local_search(cleaned, seed_feed=seed_feed)
|
||||||
if last_error is not None:
|
|
||||||
raise last_error
|
|
||||||
return base_combined
|
|
||||||
|
|
||||||
def _collect_search_results(
|
def _collect_search_results(
|
||||||
self,
|
self,
|
||||||
@@ -803,6 +794,16 @@ class CalibreOPDSClient:
|
|||||||
absolute_href = urljoin(base_for_join, href)
|
absolute_href = urljoin(base_for_join, href)
|
||||||
entry = OPDSLink(href=absolute_href, rel=rel, type=link_type, title=title)
|
entry = OPDSLink(href=absolute_href, rel=rel, type=link_type, title=title)
|
||||||
key = rel or absolute_href
|
key = rel or absolute_href
|
||||||
|
|
||||||
|
# Prioritize search links with template parameters
|
||||||
|
if key == "search" and key in results:
|
||||||
|
existing = results[key]
|
||||||
|
if "{searchTerms}" in (existing.href or ""):
|
||||||
|
continue
|
||||||
|
if "{searchTerms}" in absolute_href:
|
||||||
|
results[key] = entry
|
||||||
|
continue
|
||||||
|
|
||||||
results[key] = entry
|
results[key] = entry
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ def api_calibre_opds_feed() -> ResponseReturnValue:
|
|||||||
if letter:
|
if letter:
|
||||||
feed = client.browse_letter(letter, start_href=href)
|
feed = client.browse_letter(letter, start_href=href)
|
||||||
elif query:
|
elif query:
|
||||||
feed = client.search(query)
|
feed = client.search(query, start_href=href)
|
||||||
else:
|
else:
|
||||||
feed = client.fetch_feed(href)
|
feed = client.fetch_feed(href)
|
||||||
except CalibreOPDSError as exc:
|
except CalibreOPDSError as exc:
|
||||||
|
|||||||
Reference in New Issue
Block a user