fix(e5): address code-review findings (TMDB guid media_type, search ingest guard, discover keying)
Follow-ups from the epic-end /code-review of the E5 branch: - tmdb.resolve_recs + people._resolve_known_for: match recommendations/ credits to the library bucketed by media_type. TMDB movie ids and tv ids are independent sequences, so a bare `tmdb:<id>` match could deep-link a movie rec to an unrelated show (or vice-versa) on a numeric collision. Regression test added (test_resolve_recs_matches_by_media_type_not_bare_id). - routes/search: wrap the _ingest_candidates call so a DB/enrich failure degrades to a 422 with a message instead of a bare 500 hidden behind the FE's generic "search failed" (extends the B-core-1 rationale); rollback on failure. Stamp enriched_at with its own timestamp taken after the enrich, not the stub-insert placeholder. - routes/plex/discover: key serialized cards back by rating_key (globally unique in Plex) instead of id(obj); fix the stale rows 3-tuple annotation.
This commit is contained in:
@@ -340,25 +340,37 @@ def run_enrich(db: Session) -> dict:
|
||||
|
||||
def resolve_recs(db: Session, recs: list[dict] | None) -> list[dict]:
|
||||
"""Tag each recommendation with whether it's in OUR library (matched by guid `tmdb:<id>`) and, if so,
|
||||
its rating_key — so the client can deep-link the ones we have and merely display the rest."""
|
||||
its rating_key — so the client can deep-link the ones we have and merely display the rest.
|
||||
|
||||
TMDB movie ids and tv ids are independent sequences (id 603 can be BOTH a movie and a show), so the
|
||||
match is bucketed by each rec's own media_type: a movie rec only matches a library movie, a tv rec
|
||||
only a library show — otherwise a numeric-id collision would deep-link a rec to an unrelated title."""
|
||||
if not recs:
|
||||
return []
|
||||
guids = [f"tmdb:{r['tmdb_id']}" for r in recs if r.get("tmdb_id")]
|
||||
in_lib: dict[str, str] = {}
|
||||
if guids:
|
||||
movie_guids = [
|
||||
f"tmdb:{r['tmdb_id']}" for r in recs if r.get("tmdb_id") and r.get("media_type") != "tv"
|
||||
]
|
||||
tv_guids = [
|
||||
f"tmdb:{r['tmdb_id']}" for r in recs if r.get("tmdb_id") and r.get("media_type") == "tv"
|
||||
]
|
||||
movie_lib: dict[str, str] = {}
|
||||
show_lib: dict[str, str] = {}
|
||||
if movie_guids:
|
||||
for guid, rk in db.execute(
|
||||
select(PlexItem.guid, PlexItem.rating_key).where(
|
||||
PlexItem.kind == "movie", PlexItem.guid.in_(guids)
|
||||
PlexItem.kind == "movie", PlexItem.guid.in_(movie_guids)
|
||||
)
|
||||
):
|
||||
in_lib[guid] = rk
|
||||
movie_lib.setdefault(guid, rk)
|
||||
if tv_guids:
|
||||
for guid, rk in db.execute(
|
||||
select(PlexShow.guid, PlexShow.rating_key).where(PlexShow.guid.in_(guids))
|
||||
select(PlexShow.guid, PlexShow.rating_key).where(PlexShow.guid.in_(tv_guids))
|
||||
):
|
||||
in_lib.setdefault(guid, rk)
|
||||
show_lib.setdefault(guid, rk)
|
||||
out: list[dict] = []
|
||||
for r in recs:
|
||||
rk = in_lib.get(f"tmdb:{r.get('tmdb_id')}")
|
||||
g = f"tmdb:{r.get('tmdb_id')}"
|
||||
rk = show_lib.get(g) if r.get("media_type") == "tv" else movie_lib.get(g)
|
||||
out.append({**r, "in_library": rk is not None, "rating_key": rk})
|
||||
return out
|
||||
|
||||
|
||||
Reference in New Issue
Block a user