fix(opds): parse an empty OPDS 2.0 feed as a feed, not a publication - #7
Open
raphi011 wants to merge 1 commit into
Open
fix(opds): parse an empty OPDS 2.0 feed as a feed, not a publication#7raphi011 wants to merge 1 commit into
raphi011 wants to merge 1 commit into
Conversation
OPDS2Parser classified any JSON document lacking navigation/groups/ publications/facets collections as an OPDS Publication. But a zero-result feed legitimately omits every collection array — Komga's `@JsonInclude(NON_EMPTY)` drops empty arrays entirely, leaving just `metadata` + `links` on an empty search. Such a document was misread as a publication; `Publication(json:)` then throws, so `parse` returned neither a feed nor a publication and clients surfaced "not a feed" on every empty search. Per the OPDS 2.0 spec the media type is the authoritative feed-vs- publication signal (`application/opds+json` vs `application/opds-publication+json`). Treat a document as a Publication only when it neither carries a feed collection nor declares the feed media type, so an empty `application/opds+json` document parses as the empty feed it is. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
OPDS2Parser.parse(jsonData:url:response:)decides whether a JSON document is a feed or a publication by the absence of collection arrays:But an empty OPDS 2.0 feed (zero results — e.g. an empty search) legitimately omits every collection array. Real servers emit exactly this shape: Komga serializes its feeds with
@JsonInclude(NON_EMPTY), which drops empty arrays entirely, so an empty search returns justmetadata+links:{ "metadata": { "title": "Search: nomatch" }, "links": [ { "rel": "self", "href": "/opds/search?q=nomatch", "type": "application/opds+json" } ] }with
Content-Type: application/opds+json.That collection-less document is misread as a Publication.
Publication(json:)then throws (it isn't a publication), the error is swallowed bycatch { log(.warning, error) }, andparsereturns aParseDatawith neither.feednor.publication. DownstreamReadiumOPDSconsumers surface this as a generic "not a feed" error on every zero-result search — the user sees an error instead of an empty result list.Root cause
The disambiguation ignores the response media type, which the OPDS 2.0 spec designates as the authoritative feed-vs-publication signal:
application/opds+json(§1.1)application/opds-publication+json(§5.1)Zero-result feeds are a genuine spec gap (
"publications": []would violate the feed schema'sminItems: 1too), so servers omit the arrays — clients must tolerate collection-less feeds. Deciding "publication" from the absence of collections is the defect.Fix
Follow the spec's media-type signal. Treat a document as a Publication only when it neither carries a feed collection nor declares the feed media type (
application/opds+json, read fromresponse.mimeType). An emptyapplication/opds+jsondocument then parses as the empty feed it is:This is a minimal, behavior-preserving change: the only documents whose classification changes are collection-less ones that declare
application/opds+json— i.e. exactly the empty feeds that previously failed. A real publication document (declaredapplication/opds-publication+json, or any doc carrying an acquisition-only shape without the feed media type) still parses as a publication.Test
Adds
readium_opds2_0_test.testEmptyFeedWithOPDSMediaTypeParsesAsFeedandTests/OPDSTests/Samples/opds_2_0_empty_feed.json(the Komga-style empty-feed shape), asserting the document parses as a feed with zero publications/navigation rather than being misread as a publication.Reproduction server
https://mayberry.pub/opds(OPDS 2.0) — any search that returns no matches, e.g./opds/search?q=zzznoresultsquery, reproduces the empty-feed shape.