tests/fixtures/pms_watched_shows.xml.txt
Rama dev · réplica de lectura del repositorio original.
<!--
PMS 1.43.3 GET /library/sections/{key}/all?type=2&unwatched=0 against a SHOW library. Recorded
2026-08-05 from a real server (plex-safety rule 11). Titles and ids are sanitized; attribute NAMES,
ordering and the container shape are verbatim.
NOTE THE QUERY. This is NO LONGER the read Shortlist makes: the show read now sends
`?type=2&viewedLeafCount!=0`, because `unwatched=0` omits a series whose show-level watch-state row
was never established (issue #108 — see the correction below and
`pms_watched_episodes_rollup.xml.txt`). The recording is kept because it is the evidence for that
change, and because the ROW shapes it captures — viewed/total pairs, a missing `lastViewedAt` — are
what `_watched_item` must parse either way.
WHY THIS FIXTURE EXISTS.
`pms_watched_incremental.xml.txt` records the same endpoint against a MOVIE library, and until now
it was the only recording we had. The show case was assumed rather than measured, and the whole
already-watched rule turns on it — so the assumption was load-bearing and unverified.
WHAT WAS MEASURED, on a show section, as the admin account:
?type=2&unwatched=0 -> every show with viewedLeafCount > 0, INCLUDING barely-started ones.
The ten rows below are the real viewed/total pairs observed, unchanged:
2/23 4/142 47/47 14/67 42/122 2/176 4/138 100/100 12/17 4/38
THE POINT. `unwatched=0` on a show library does NOT mean "fully watched". It returns a series from
its FIRST episode — 2 of 176 is 1.1% and still comes back. Plex has no show-level `viewCount`; a
`<Directory>` carries only `viewedLeafCount` and `leafCount`, so every yes/no answer about a show
is somebody's threshold over those two numbers, and Plex's own threshold is "more than zero".
This is what settled the 1.2 change to the already-watched rule. Shortlist used to apply its own
bar on top (>=80% of episodes, or a length-scaled floor of ~3), which meant five of the ten shows
above — everything under its floor — were still eligible to be recommended back to the person
watching them. A 0% row now treats started as watched, matching the server. See
`RowPolicy.zero_pct_exclusions`.
Note also the mark-as-watched case (ratingKey 5006): a bulk "mark as played" sets the leaf counts
equal with no per-episode play history, which the playback-history API would never have shown.
CORRECTION, 2026-09-01 (issue #108), in two parts — the second corrects the first.
**The column was never recorded.** This fixture's `lastViewedAt` values are invented: the first
three are copied from `pms_watched_incremental.xml.txt` (a MOVIE library) and the rest are round
numbers. Only the viewed/total pairs listed above were ever measured. Treat every other value here
as illustrative.
**The row that had no `lastViewedAt` was RIGHT, and was wrongly "corrected" away.** A first pass at
#108 removed it after probing the live server for shows missing that attribute and finding zero of
534. That probe asked `?type=2&unwatched=0` — the very query that EXCLUDES such shows — so the
answer could only ever be zero, and it read like proof they do not exist. It is a selection effect,
not evidence, and it cost a wrong diagnosis. The row is restored below.
What the same server actually shows when asked properly (`?type=2` unfiltered, plus the episode
read; see `pms_watched_episodes_rollup.xml.txt`):
?type=2&unwatched=0 -> 533 shows
?type=2 -> 4880 shows, of which 491 have viewedLeafCount > 0
?type=4&unwatched=0 -> 9563 episodes, rolling up to exactly those same 491 shows
**20 of those 491 never came back from `?type=2&unwatched=0`.** Every one has correct episode
counts and NO `lastViewedAt` on the show row. So this endpoint filters on the show's own watch-state
row, not on `viewedLeafCount`, and a show whose row was never established is invisible to it — which
is what happens when a series or a season is marked watched rather than an episode played. That is
issue #108, and it is why `watched_titles` now supplements this read with the episode-level one.
Row 5006 therefore records a show this endpoint would NOT return, and is kept for a narrower reason
than "the supplement handles it" — it does not: `_shows_from_episodes` builds recovered shows
directly from a plexapi object and never parses a `<Directory>`. It is here so `_watched_item` is
proven tolerant of a missing `lastViewedAt`, which the unfiltered `?type=2` genuinely returns.
-->
<MediaContainer size="10" totalSize="10" allowSync="1" identifier="com.plexapp.plugins.library"
librarySectionID="2" librarySectionTitle="TV Shows" librarySectionUUID="REDACTED-UUID"
mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1700000000"
offset="0" thumb="/:/resources/show.png" title1="TV Shows" title2="All Shows"
viewGroup="show" viewMode="65592">
<!-- Barely started: two episodes of twenty-three. Under every fraction, still returned. -->
<Directory ratingKey="5001" key="/library/metadata/5001/children" guid="plex://show/REDACTED"
type="show" title="Sanitised Show A" year="2024" leafCount="23" viewedLeafCount="2"
childCount="2" addedAt="1700000001" updatedAt="1700000002" lastViewedAt="1779572385">
<Guid id="imdb://tt1000001"/>
<Guid id="tmdb://300001"/>
<Guid id="tvdb://400001"/>
</Directory>
<!-- 4 of 142 — 2.8%. The case that makes a percentage-based rule wrong. -->
<Directory ratingKey="5002" key="/library/metadata/5002/children" guid="plex://show/REDACTED"
type="show" title="Sanitised Show B" year="2019" leafCount="142" viewedLeafCount="4"
childCount="8" addedAt="1700000003" updatedAt="1700000004" lastViewedAt="1774305861">
<Guid id="tmdb://300002"/>
</Directory>
<!-- Genuinely finished. -->
<Directory ratingKey="5003" key="/library/metadata/5003/children" guid="plex://show/REDACTED"
type="show" title="Sanitised Show C" year="2021" leafCount="47" viewedLeafCount="47"
childCount="4" addedAt="1700000005" updatedAt="1700000006" lastViewedAt="1765677185">
<Guid id="tmdb://300003"/>
</Directory>
<!-- Part-way through a long run: 14 of 67. -->
<Directory ratingKey="5004" key="/library/metadata/5004/children" guid="plex://show/REDACTED"
type="show" title="Sanitised Show D" year="2016" leafCount="67" viewedLeafCount="14"
childCount="5" addedAt="1700000007" updatedAt="1700000008" lastViewedAt="1760000000">
<Guid id="tmdb://300004"/>
</Directory>
<!-- 42 of 122. -->
<Directory ratingKey="5005" key="/library/metadata/5005/children" guid="plex://show/REDACTED"
type="show" title="Sanitised Show E" year="2013" leafCount="122" viewedLeafCount="42"
childCount="7" addedAt="1700000009" updatedAt="1700000010" lastViewedAt="1755000000">
<Guid id="tmdb://300005"/>
</Directory>
<!-- Finished, and carrying NO `lastViewedAt` at all — the issue #108 shape, measured 20 times on a
real server. Its episode counts are correct and complete; only the show's own watch-state row
is missing, and `?type=2&unwatched=0` filters on exactly that, so this row would NOT appear in
a real response to that query. Recovered instead from `?type=4&unwatched=0`. -->
<Directory ratingKey="5006" key="/library/metadata/5006/children" guid="plex://show/REDACTED"
type="show" title="Sanitised Show F" year="2011" leafCount="100" viewedLeafCount="100"
childCount="6" addedAt="1700000011" updatedAt="1700000012">
<Guid id="tmdb://300006"/>
</Directory>
<!-- 2 of 176 — 1.1%, the thinnest observed, and the single clearest proof of the point. -->
<Directory ratingKey="5007" key="/library/metadata/5007/children" guid="plex://show/REDACTED"
type="show" title="Sanitised Show G" year="2005" leafCount="176" viewedLeafCount="2"
childCount="12" addedAt="1700000013" updatedAt="1700000014" lastViewedAt="1750000000">
<Guid id="tmdb://300007"/>
</Directory>
<!-- 4 of 138. -->
<Directory ratingKey="5008" key="/library/metadata/5008/children" guid="plex://show/REDACTED"
type="show" title="Sanitised Show H" year="2008" leafCount="138" viewedLeafCount="4"
childCount="9" addedAt="1700000015" updatedAt="1700000016" lastViewedAt="1745000000">
<Guid id="tmdb://300008"/>
</Directory>
<!-- 12 of 17: over the old bar, and watched under the new one too. -->
<Directory ratingKey="5009" key="/library/metadata/5009/children" guid="plex://show/REDACTED"
type="show" title="Sanitised Show I" year="2022" leafCount="17" viewedLeafCount="12"
childCount="2" addedAt="1700000017" updatedAt="1700000018" lastViewedAt="1740000000">
<Guid id="tmdb://300009"/>
</Directory>
<!-- 4 of 38. A show with no tmdb:// guid would be DROPPED by `_watched_item`; every row here has
one, which matched the live server (all ten carried an inline TMDB guid). -->
<Directory ratingKey="5010" key="/library/metadata/5010/children" guid="plex://show/REDACTED"
type="show" title="Sanitised Show J" year="2018" leafCount="38" viewedLeafCount="4"
childCount="3" addedAt="1700000019" updatedAt="1700000020" lastViewedAt="1735000000">
<Guid id="tmdb://300010"/>
</Directory>
</MediaContainer>