Ctrl K
ComunidadGuías…

tests/fixtures/pms_watched_shows.xml.txt

Rama dev · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<!--
  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>