fix(plex): gate the part-key re-probe to single-version items; drop dead i18n key; cover cross-facet narrowing

Deep-review round 2 on the round-1 fixes (all low):

- part_key churn (state): round 1's part-key reset re-probed EVERY sync for a
  multi-version item (an original + a Plex 'Optimized' copy), because
  _media_facts reads media[0]/part[0] whose order Plex doesn't guarantee stable,
  oscillating transcode_hw between the two versions. Gate the part-key signal on
  a single-version item (len(Media)<=1); codec-change reset still applies to all.
  A multi-version same-codec re-encode not self-healing is an acceptable rare
  edge; a per-sync re-probe loop is not.

- dead i18n key: this diff's playableClass() collapses to transcode_hw/sw, so the
  bare plex.playable.transcode key it orphaned is now unused (knip can't see
  dynamic keys). Dropped from both locales, parity kept.

- test: cross-facet narrowing by an active playable class (a co-facet's year
  range collapses to the selected subset) — the flip side of self-exclusion,
  previously unpinned.

The aria-label+title double-announcement on the card dot is a deliberate accepted
trade-off (reliable SR name + mouse tooltip). Backend + FE gates green.
This commit is contained in:
2026-08-30 17:58:38 +02:00
parent bf98b48517
commit c1a3b7b935
4 changed files with 56 additions and 11 deletions
+14 -9
View File
@@ -472,15 +472,20 @@ def _apply_item(row: PlexItem, lib_id: int, kind: str, meta: dict) -> None:
mf = _media_facts(meta)
new_vcodec = mf.get("codec_video")
new_part_key = mf.get("part_key")
# The physical file was replaced when its Plex Part key changes (a re-encode / quality upgrade gets a
# new part id) OR — a coarser signal — when the video codec changes. Either way any probed bit-depth is
# stale, so reset the probe watermark and re-derive transcode_hw from codec alone until the backfill
# re-probes. Codec alone is NOT enough: a same-codec bit-depth re-encode (8-bit→10-bit HEVC) keeps the
# codec `hevc` but flips the HW class, and only the part-key move catches it. A spurious reset (a rare
# part-id reassignment on an unchanged file) costs at most one extra bounded re-probe — safe direction.
if (row.codec_video or "").lower() != (
new_vcodec or ""
).lower() or row.part_key != new_part_key:
# The physical file was replaced when its video codec changes OR — for a SINGLE-version item — when its
# Plex Part key changes (a re-encode / quality upgrade gets a new part id). Either way any probed
# bit-depth is stale, so reset the probe watermark and re-derive transcode_hw from codec alone until the
# backfill re-probes. Codec alone is NOT enough: a same-codec bit-depth re-encode (8-bit→10-bit HEVC)
# keeps the codec `hevc` but flips the HW class, and only the part-key move catches it.
#
# The part-key check is gated on single-version because `_media_facts` reads media[0]/part[0], and for a
# MULTI-version item (an original + a Plex "Optimized" copy) that order isn't guaranteed stable across
# listings — an unguarded part-key compare would then reset+re-probe every sync and oscillate the
# transcode_hw bucket between the two versions. A multi-version same-codec re-encode not self-healing is
# an acceptable rare edge; a per-sync re-probe loop is not.
single_version = len(meta.get("Media") or []) <= 1
codec_changed = (row.codec_video or "").lower() != (new_vcodec or "").lower()
if codec_changed or (single_version and row.part_key != new_part_key):
row.video_bit_depth = None
row.media_probed_at = None
row.file_path = mf.get("file_path")