|
4 | 4 | """ |
5 | 5 |
|
6 | 6 | from abc import ABC, abstractmethod |
| 7 | +from dataclasses import dataclass |
7 | 8 | from typing import List, Optional |
| 9 | +from urllib.parse import urlencode |
8 | 10 |
|
9 | 11 | from pydantic import BaseModel |
10 | 12 | from typing import Optional |
11 | 13 |
|
12 | | -from opds2.models import Metadata, Publication, Link |
| 14 | +from opds2.models import Metadata, Publication, Link, Catalog |
13 | 15 | from opds2.catalog import create_catalog |
14 | 16 |
|
15 | 17 |
|
@@ -79,15 +81,113 @@ def search( |
79 | 81 | query: str, |
80 | 82 | limit: int = 50, |
81 | 83 | offset: int = 0, |
| 84 | + sort: Optional[str] = None, |
82 | 85 | ) -> tuple[List[DataProviderRecord], int]: |
83 | 86 | """Search for publications matching the query. |
84 | 87 | |
85 | 88 | Args: |
86 | 89 | query: Search query string |
87 | 90 | limit: Maximum number of results to return (default: 50) |
88 | 91 | offset: Offset for pagination (default: 0) |
| 92 | + sort: Optional sorting parameter |
89 | 93 | |
90 | 94 | Returns: |
91 | 95 | List of Publication objects matching the search criteria |
92 | 96 | """ |
93 | 97 | 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