Skip to content

Enhance TPDB metadata hydration and Plex mapping fidelity - #2

Open
adeze wants to merge 16 commits into
mystrock:mainfrom
adeze:main
Open

Enhance TPDB metadata hydration and Plex mapping fidelity#2
adeze wants to merge 16 commits into
mystrock:mainfrom
adeze:main

Conversation

@adeze

@adeze adeze commented Jun 4, 2026

Copy link
Copy Markdown

No description provided.

Copilot AI and others added 7 commits June 4, 2026 06:21
Hydrate TPDB scene entities and expand Plex metadata mapping fidelity
…or identity, external GUIDs) (#2)

* Initial plan

* Add Plex metadata images endpoint support

* Fix legacy TPDB image field mapping

* Polish image dedupe and debug logging

* Add adult, Guid, and performer ID mappings

* Hardcode adult flag for TPDB content

* Add coverage for empty images and role ID priority

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Initial plan

* feat: include studio in plex collections mapping

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 4, 2026 10:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds richer TPDB→Plex enrichment (images, GUIDs, directors/collections), hydrates sparse TPDB payloads via cached lookups, and exposes a new /images metadata route.

Changes:

  • Introduces scene hydration with in-memory LRU-style caching for performers and sites (metadata + match flows).
  • Expands the TPDB→Plex mapper to normalize image extraction, roles, directors, collections, and Guid entries.
  • Adds a new metadata images endpoint and associated tests + manifest/README updates.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
tests/test_tpdb_enrichment.py Adds unit tests covering new mapper enrichment and hydration/caching behavior.
tests/test_metadata_routes.py Adds route tests for the new /library/metadata/{id}/images endpoint.
provider/services/metadata_service.py Adds hydration + caching and new get_images() API.
provider/services/match_service.py Adds hydration + caching during search results mapping.
provider/routes/metadata.py Adds /library/metadata/{rating_key}/images route.
provider/routes/manifest.py Advertises the new images feature in the manifest.
provider/mappers/tpdb_to_plex.py Implements robust image extraction, collections/directors/roles GUID mapping, and image entries mapping.
README.md Documents the new images endpoint.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +41 to +43
def _has_image(payload: dict) -> bool:
"""Check if payload already includes any image-like field."""
return any(payload.get(key) for key in ("image", "poster", "thumb", "photo", "avatar", "face"))
Comment thread provider/services/match_service.py Outdated
Comment on lines +41 to +43
def _has_image(payload: dict) -> bool:
"""Check if payload already includes any image-like field."""
return any(payload.get(key) for key in ("image", "poster", "thumb", "photo", "avatar", "face"))
Comment thread provider/services/metadata_service.py Outdated
Comment on lines +91 to +98
site = scene.get("site")
site_identifier = ""
if isinstance(site, dict):
site_identifier = self._first_identifier(site, ("id", "slug"))
if not site_identifier:
site_identifier = self._first_identifier(scene, ("site_id", "site_slug"))

hydrated_site = self._get_cached_site(site_identifier)
class MetadataService:
"""Service for fetching full metadata from TPDB."""

_CACHE_LIMIT = 512
Comment on lines +28 to +32
self._performer_cache: OrderedDict[str, dict | None] = OrderedDict()
self._site_cache: OrderedDict[str, dict | None] = OrderedDict()

@staticmethod
def _first_identifier(payload: dict, keys: tuple[str, ...]) -> str:
Comment thread provider/services/metadata_service.py Outdated
self._performer_cache[performer_identifier] = self.client.get_performer(performer_identifier)
return self._performer_cache[performer_identifier]

def _get_cached_site(self, site_identifier: str) -> Optional[dict]:
Comment thread provider/services/metadata_service.py Outdated
self._site_cache[site_identifier] = self.client.get_site(site_identifier)
return self._site_cache[site_identifier]

def _hydrate_scene(self, scene: dict) -> dict:
Comment on lines +148 to +152
try:
return map_scene_to_images(scene)
except Exception as e:
logger.error("Failed to map images for scene %s: %s", rating_key, e)
return []
Comment thread provider/mappers/tpdb_to_plex.py Outdated
Comment on lines +100 to +107
if poster:
images["poster"] = poster
images["thumb"] = poster

art = _get_scene_art(scene)
if art:
images["art"] = art
images["background"] = art
Comment thread provider/services/metadata_service.py Outdated
Comment on lines +45 to +54
def _get_cached_performer(self, performer_identifier: str) -> Optional[dict]:
"""Get performer details with lightweight in-memory cache."""
if not performer_identifier:
return None
if performer_identifier in self._performer_cache:
self._performer_cache.move_to_end(performer_identifier)
else:
if len(self._performer_cache) >= self._CACHE_LIMIT:
self._performer_cache.popitem(last=False)
self._performer_cache[performer_identifier] = self.client.get_performer(performer_identifier)
Copilot AI and others added 9 commits July 21, 2026 11:40
…r VR and other scenes (#5)

* Initial plan

* fix: prefer poster/background over screengrabs in image selection (especially for VR scenes)

- Add _POSTER_KIND_SCORES, _ART_KIND_SCORES, _SCREENGRAB_SCORE_THRESHOLD constants
- Add _image_kind_from_key() to classify field names/labels to image kinds
- Add _collect_image_candidates() that inspects all image fields with type hints,
  returning (poster_score, art_score, url) tuples
- Refactor _get_scene_poster() and _get_scene_art() to pick highest-scored candidate
  instead of blindly taking the first string found
- Update extract_scene_images() to return list[dict] with multiple candidates,
  enabling Plex to offer alternative image selections
- Update map_scene_to_images() for new list-based extract_scene_images() return
- Add 10 new tests covering: VR screengrab ordering, list type hints,
  deduplication, multiple candidates, screengrab fallback, legacy strings

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants