Skip to content

Add first-class OPDS2 groups support to FeedData (PP-3675)#3100

Merged
jonathangreen merged 4 commits intomainfrom
feature/opds2-groups-feed
Mar 4, 2026
Merged

Add first-class OPDS2 groups support to FeedData (PP-3675)#3100
jonathangreen merged 4 commits intomainfrom
feature/opds2-groups-feed

Conversation

@jonathangreen
Copy link
Member

@jonathangreen jonathangreen commented Mar 3, 2026

Description

Add first-class group structure to FeedData so that the OPDS2 serializer can produce native groups output for grouped feeds (e.g., /groups).

Previously, group membership was encoded as rel="collection" links on individual work entries — an OPDS1 convention.

Key changes:

  • Add FeedEntryGroup dataclass and entry_groups field to FeedData
  • Build groups directly in OPDSAcquisitionFeed.groups() instead of populating annotator.lanes_by_work
  • OPDS1 serializer flattens entry_groups into entries with rel="collection" links (preserving existing behavior)
  • OPDS2 serializer builds native PublicationsGroup objects from entry_groups
  • Remove now-dead group_uri(), lanes_by_work, and _lanes_by_work from LibraryAnnotator
  • Remove collection link addition from annotate_work_entry()

Motivation and Context

The /groups endpoint should return works organized by sublanes using the OPDS2 groups structure, but was instead returning a flat publications array. This is because group information was only carried as per-entry collection links — a pattern that doesn't map to OPDS2. Making groups a first-class concept in FeedData allows each serializer to handle them idiomatically.

How Has This Been Tested?

  • All existing tests pass (136 tests across 4 test files)
  • Added new tests for OPDS2 group serialization (group structure, ordering, flat fallback, empty group skipping)
  • Added new tests for OPDS1 group flattening (collection links, coexistence with flat entries)
  • Updated test_exclude_by_work_ids and added test_groups_populates_entry_groups for the acquisition feed
  • Removed test_group_uri_with_flattened_lane (method deleted)
  • mypy passes with no issues

Checklist

  • I have updated the documentation accordingly.
  • All new and existing tests passed.

@jonathangreen jonathangreen added the feature New feature label Mar 3, 2026
@jonathangreen jonathangreen changed the base branch from main to bugfix/opds2-entry-content-type March 3, 2026 15:08
@codecov
Copy link

codecov bot commented Mar 3, 2026

Codecov Report

❌ Patch coverage is 93.33333% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.23%. Comparing base (40ccda3) to head (a1e4e2b).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
src/palace/manager/feed/acquisition.py 90.90% 0 Missing and 2 partials ⚠️
src/palace/manager/feed/serializer/opds2.py 90.47% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3100   +/-   ##
=======================================
  Coverage   93.22%   93.23%           
=======================================
  Files         491      491           
  Lines       45336    45350   +14     
  Branches     6239     6243    +4     
=======================================
+ Hits        42266    42282   +16     
+ Misses       1984     1982    -2     
  Partials     1086     1086           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jonathangreen jonathangreen force-pushed the bugfix/opds2-entry-content-type branch from f1261ae to a5adbf6 Compare March 4, 2026 15:04
Group membership in grouped feeds was previously encoded as per-entry
collection links, an OPDS1 convention that the OPDS2 serializer silently
dropped. This makes group structure a first-class concept in FeedData
by adding FeedEntryGroup, populated upstream in groups(). The OPDS1
serializer flattens groups into entries with collection links, while
the OPDS2 serializer builds native PublicationsGroup objects.
@jonathangreen jonathangreen force-pushed the feature/opds2-groups-feed branch from 2a5daad to 30583ff Compare March 4, 2026 15:15
@jonathangreen jonathangreen changed the base branch from bugfix/opds2-entry-content-type to main March 4, 2026 15:22
Use Work.id (database PK) instead of id() (memory address) for entry
lookup, coerce sublane display_name to str for consistency, make test
helper a staticmethod, and tighten empty-group assertion.
Validates that when the same work is returned by multiple sublanes,
it correctly appears in each corresponding FeedEntryGroup.
Feed._serialize now keeps all truthy collection fields and only falls
back to priority-based selection when none are truthy. This lets the
OPDS2 serializer pass all fields directly instead of conditionally
building kwargs.
@jonathangreen jonathangreen marked this pull request as ready for review March 4, 2026 16:24
@jonathangreen jonathangreen requested a review from a team March 4, 2026 17:28
Copy link
Contributor

@dbernstein dbernstein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥇

@jonathangreen jonathangreen merged commit 450a2d6 into main Mar 4, 2026
20 checks passed
@jonathangreen jonathangreen deleted the feature/opds2-groups-feed branch March 4, 2026 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants