Skip to content

feat(search): add summary, country, collection, and rating search fields - #1801

Open
chrisbenincasa wants to merge 1 commit into
mainfrom
extra-search-fields
Open

chrisbenincasa wants to merge 1 commit into
mainfrom
extra-search-fields

Conversation

@chrisbenincasa

@chrisbenincasa chrisbenincasa commented Apr 12, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds five fields to the program search index, the search DSL, and the web search builder.

Field Type Indexed as
summary string summary
country faceted string countries.name
collection faceted string collections.name
audience_rating numeric, sortable audienceRating
critic_rating numeric, sortable criticRating

All five appear in the web search builder for movie and show libraries only.

Where the values come from

Source audience rating critic rating countries collections
Plex movie audienceRating rating Country Collection
Plex show audienceRating not available Country Collection
Jellyfin movie CommunityRating CriticRating ProductionLocations not available
Jellyfin series CommunityRating CriticRating ProductionLocations not available
Emby not wired not wired not wired not wired

The Jellyfin library request now asks for ProductionLocations, CommunityRating, and CriticRating. PlexMovieSchema gains an optional Collection array.

Database

Migration 0052_next_eternals.sql:

ALTER TABLE `program` ADD `audience_rating` real;
ALTER TABLE `program` ADD `critic_rating` real;

Movie ratings persist end to end. ProgramDaoMinter.mintMovie writes both columns, and ProgramConverter.programDaoToTerminalProgram plus ApiProgramConverters read them back, so a movie keeps its ratings across a database round trip and an index rebuilt from the database keeps them too.

What is not persisted

Search works for all five fields on freshly scanned items, because the scanner hands Meilisearch its in-memory media objects. The following only survive until the index is rebuilt, and are filed as follow-ups rather than fixed here.

  • Show ratings. program_grouping has no rating columns, so an episode inherits its show's ratings only when the show came from a deep scan. A shallow re-scan materializes the show from the database and the episode gets null.
  • Countries and collections. Not persisted for movies or shows. They are join-table shaped, like genres and studios, so they need new tables rather than new columns.
  • Emby. EmbyApiClient sets only the content rating and returns nothing for any of the five fields.

Notes for review

This branch was rebased from a 325-commit-old base. Two things changed during the rebase:

  • The original migration 0044_add_audience_critic_rating collided with 0044–0051 on main. It was regenerated as 0052 via pnpm resolve-migrations; the SQL is byte-identical to the original.
  • Two commented-out entries (// library_name, // media_source_name) and a redundant identity mapping (summary: 'summary') were dropped from virtualFieldToIndexField. Every read site does virtualFieldToIndexField[key] ?? key, so the identity entry was a no-op.

Test plan

  • pnpm turbo typecheck clean across all five packages
  • pnpm turbo test — server 1682 passed / 2 skipped, shared 97 passed
  • oxlint and prettier clean on every changed file
  • Generated 0052_next_eternals.sql is byte-identical to the 0044 this branch originally carried
  • Manual: scan a Plex library, filter on audience_rating > 7, re-scan and confirm the values survive
  • Manual: scan a Jellyfin library, filter on country and critic_rating

🤖 Generated with Claude Code

@chrisbenincasa
chrisbenincasa marked this pull request as ready for review April 20, 2026 16:42
Adds five fields to the program search index, the search DSL, and the web
search builder:

  summary          string
  country          faceted string
  collection       faceted string
  audience_rating  numeric, also sortable
  critic_rating    numeric, also sortable

Plex and Jellyfin populate them while scanning a library. Plex movies take the
audience score from `audienceRating` and the critic score from `rating`, and
take countries and collections from the `Country` and `Collection` join items.
Plex shows have no critic score, so it stays null. Jellyfin maps
`CommunityRating` and `CriticRating`, and takes countries from
`ProductionLocations`; its library request now asks for those three fields.
Jellyfin has no collection equivalent, so collections stay empty. Emby is not
wired up and returns nothing for any of the five.

The web search builder shows all five for movie and show libraries only.

Migration 0052 adds nullable `audience_rating` and `critic_rating` REAL columns
to `program`. `ProgramDaoMinter.mintMovie` writes them, and `ProgramConverter`
and `ApiProgramConverters` read them back, so a movie keeps its ratings across a
database round trip and an index rebuilt from the database keeps them too.

Ratings on shows are not persisted. `program_grouping` has no columns for them,
so an episode inherits its show's ratings only when the show came from a deep
scan. Countries and collections are not persisted either, for movies or shows,
since they need join tables rather than columns. Both reach Meilisearch from the
scanner's in-memory objects and survive until the index is rebuilt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chrisbenincasa

Copy link
Copy Markdown
Owner Author

Follow-ups filed for the gaps listed under What is not persisted:

Also #2147 for the resolve-migrations regex that blocked this rebase.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant