Skip to content

Commit 18e5c9a

Browse files
authored
Merge pull request #6 from cdrini/feature/search-catalog
Implement search catalog support with all the common fields
2 parents a3ccba0 + ca1b551 commit 18e5c9a

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-2
lines changed

opds2/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class Catalog(BaseModel):
101101
None,
102102
description="Navigation links for browsing"
103103
)
104-
groups: Optional[List[Dict[str, Any]]] = Field(
104+
groups: Optional[List['Catalog']] = Field(
105105
None,
106106
description="Grouped collections of publications"
107107
)

opds2/provider.py

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
"""
55

66
from abc import ABC, abstractmethod
7+
from dataclasses import dataclass
78
from typing import List, Optional
9+
from urllib.parse import urlencode
810

911
from pydantic import BaseModel
1012
from typing import Optional
1113

12-
from opds2.models import Metadata, Publication, Link
14+
from opds2.models import Metadata, Publication, Link, Catalog
1315
from opds2.catalog import create_catalog
1416

1517

@@ -79,15 +81,113 @@ def search(
7981
query: str,
8082
limit: int = 50,
8183
offset: int = 0,
84+
sort: Optional[str] = None,
8285
) -> tuple[List[DataProviderRecord], int]:
8386
"""Search for publications matching the query.
8487
8588
Args:
8689
query: Search query string
8790
limit: Maximum number of results to return (default: 50)
8891
offset: Offset for pagination (default: 0)
92+
sort: Optional sorting parameter
8993
9094
Returns:
9195
List of Publication objects matching the search criteria
9296
"""
9397
pass
98+
99+
def search_catalog(
100+
self,
101+
title: Optional[str] = None,
102+
query: str = "",
103+
limit: int = 50,
104+
offset: int = 0,
105+
sort: Optional[str] = None,
106+
) -> Catalog:
107+
"""
108+
Search for publications and return an OPDS Catalog.
109+
110+
Args:
111+
title: Optional title for the catalog
112+
query: Search query string
113+
limit: Maximum number of results to return (default: 50)
114+
offset: Offset for pagination (default: 0)
115+
sort: Optional sorting parameter
116+
"""
117+
118+
if not title:
119+
title = f"Search results for '{query}'"
120+
results, total = self.search(
121+
query=query,
122+
limit=limit,
123+
offset=offset,
124+
sort=sort,
125+
)
126+
page = (offset // limit) + 1 if limit else 1
127+
publications = [record.to_publication() for record in results]
128+
params: dict[str, str] = {}
129+
if query:
130+
params["query"] = query
131+
if limit:
132+
params["limit"] = str(limit)
133+
if page > 1:
134+
params["page"] = str(page)
135+
if sort:
136+
params["sort"] = sort
137+
138+
links: list[Link] = []
139+
base_url = self.SEARCH_URL.replace("{?query}", "")
140+
141+
self_url = base_url + ("?" + urlencode(params) if params else "")
142+
links.append(
143+
Link(
144+
rel="self",
145+
href=self_url,
146+
type="application/opds+json",
147+
)
148+
)
149+
links.append(
150+
Link(
151+
rel="first",
152+
href=base_url + "?" + urlencode(params | {"page": "1"}),
153+
type="application/opds+json",
154+
)
155+
)
156+
157+
if page > 1:
158+
links.append(
159+
Link(
160+
rel="previous",
161+
href=base_url + "?" + urlencode(params | {"page": str(page - 1)}),
162+
type="application/opds+json",
163+
)
164+
)
165+
166+
has_more = (offset + limit) < total
167+
if has_more:
168+
links.append(
169+
Link(
170+
rel="next",
171+
href=base_url + "?" + urlencode(params | {"page": str(page + 1)}),
172+
type="application/opds+json",
173+
)
174+
)
175+
last_page = (total + limit - 1) // limit
176+
links.append(
177+
Link(
178+
rel="last",
179+
href=base_url + "?" + urlencode(params | {"page": str(last_page)}),
180+
type="application/opds+json",
181+
)
182+
)
183+
184+
return Catalog(
185+
metadata=Metadata(
186+
title=title,
187+
numberOfItems=total,
188+
itemsPerPage=limit,
189+
currentPage=page,
190+
),
191+
publications=publications,
192+
links=links,
193+
)

0 commit comments

Comments
 (0)