diff --git a/openlibrary/plugins/openlibrary/api.py b/openlibrary/plugins/openlibrary/api.py index acdace2dd17..ddb038efd37 100644 --- a/openlibrary/plugins/openlibrary/api.py +++ b/openlibrary/plugins/openlibrary/api.py @@ -827,18 +827,8 @@ def GET(self): href=f"{provider.BASE_URL}/opds/search{{?query}}", type="application/opds+json", templated=True, - ), - Link( - rel="http://opds-spec.org/shelf", - href="https://archive.org/services/loans/loan/?action=user_bookshelf", - type="application/opds+json", - ), - Link( - rel="profile", - href="https://archive.org/services/loans/loan/?action=user_profile", - type="application/opds-profile+json", - ), - ], + ) + ] + [provider.bookshelf_link(), provider.profile_link], ) web.header('Content-Type', 'application/opds+json') return delegate.RawText(json.dumps(catalog.model_dump())) @@ -860,20 +850,38 @@ def GET(self, edition_olid: str): ) pub = resp.records[0].to_publication() - pub.links += [ - Link( - rel="http://opds-spec.org/shelf", - href="https://archive.org/services/loans/loan/?action=user_bookshelf", - type="application/opds+json", - ), - Link( - rel="profile", - href="https://archive.org/services/loans/loan/?action=user_profile", - type="application/opds-profile+json", - ), - ] + pub.links += [provider.bookshelf_link(), provider.profile_link] return delegate.RawText(json.dumps(pub.model_dump())) +class opds_subjects(delegate.page): + path = r"/opds/subjects/(.*)" + + def GET(self, subject_key): + from pyopds2 import Catalog, Link, Metadata + from pyopds2.helpers import build_url + i = web.input(limit=25, page=1) + provider = get_opds_data_provider() + readable = 'ebook_access:[borrowable TO *]' + sfw = '-subject:"content_warning:cover"' + params = { + 'sort': 'trending', + 'query': f"subject_key:{subject_key} {readable} {sfw}', + } + self_url = build_url(f"{provider.BASE_URL}/opds/subjects/{subject_key}", params) + title = subject_key.replace("_", " ").title() + catalog = Catalog.create( + self_url=self_url, + metadata=Metadata(title=_(title)), + response=provider.search( + query=params.query, + sort=params.sort, + limit=int(i.limit), + offset=(int(i.page) - 1) * int(i.limit), + ), + ) + web.header('Content-Type', 'application/opds+json') + return delegate.RawText(json.dumps(catalog.model_dump())) + class opds_home(delegate.page): path = r"/opds" @@ -884,65 +892,21 @@ def build_homepage(): provider = get_opds_data_provider() catalog = Catalog( - metadata=Metadata(title=_("Welcome to Open Library")), + metadata=Metadata(title=_("Browsing the Open Library")), publications=[], navigation=[ Navigation( type="application/opds+json", title=subject['presentable_name'], - href=f'{provider.BASE_URL}{provider.SEARCH_URL}?sort=trending&query=subject_key:{subject['key'].split('/')[-1]} -subject:"content_warning:cover" ebook_access:[borrowable TO *]', # noqa: E501 + href=f"{provider.BASE_URL}/subjects/{subject['key'].split('/')[-1]}" ) for subject in get_cached_featured_subjects() ], groups=[ Catalog.create( - metadata=Metadata(title=_("Trending Books")), - response=provider.search( - query='trending_score_hourly_sum:[1 TO *] -subject:"content_warning:cover" ebook_access:[borrowable TO *]', - sort='trending', - limit=25, - ), - ), - Catalog.create( - metadata=Metadata(title=_("Classic Books")), - response=provider.search( - query='ddc:8* first_publish_year:[* TO 1950] publish_year:[2000 TO *] NOT public_scan_b:false -subject:"content_warning:cover"', - sort='trending', - limit=25, - ), - ), - Catalog.create( - metadata=Metadata(title=_("Romance")), - response=provider.search( - query='subject:romance ebook_access:[borrowable TO *] first_publish_year:[1930 TO *] trending_score_hourly_sum:[1 TO *] -subject:"content_warning:cover"', # noqa: E501 - sort='trending,trending_score_hourly_sum', - limit=25, - ), - ), - Catalog.create( - metadata=Metadata(title=_("Kids")), - response=provider.search( - query='ebook_access:[borrowable TO *] trending_score_hourly_sum:[1 TO *] (subject_key:(juvenile_audience OR children\'s_fiction OR juvenile_nonfiction OR juvenile_encyclopedias OR juvenile_riddles OR juvenile_poetry OR juvenile_wit_and_humor OR juvenile_limericks OR juvenile_dictionaries OR juvenile_non-fiction) OR subject:("Juvenile literature" OR "Juvenile fiction" OR "pour la jeunesse" OR "pour enfants"))', # noqa: E501 - sort='random.hourly', - limit=25, - ), - ), - Catalog.create( - metadata=Metadata(title=_("Thrillers")), - response=provider.search( - query='subject:thrillers ebook_access:[borrowable TO *] trending_score_hourly_sum:[1 TO *] -subject:"content_warning:cover"', - sort='trending,trending_score_hourly_sum', - limit=25, - ), - ), - Catalog.create( - metadata=Metadata(title=_("Textbooks")), - response=provider.search( - query='subject_key:textbooks publish_year:[1990 TO *] ebook_access:[borrowable TO *]', - sort='trending', - limit=25, - ), - ), + metadata=Metadata(title=_(title)), + response=provider.search(**search) + ) for (title, search) in provider.STORED_SEARCHES ], facets=None, links=[