[BUG] Edge case in metadata.provider.plex.tv when including user state with episode order

I’m writing this post to share a bug I found with the metadata.provider.plex.tv metadata source. The bug involves a pretty bizarre and specific edge case where the user state gets returned incorrectly. I’ll try to break it down into its reproducing requirements below and provide an example offending request:

  1. Make a request to metadata.provider.plex.tv for the children of a show (/library/metadata/{ratingKey}/children)
  2. The request must use the includeUserState param
  3. The request must use the episodeOrder param

And below is an example request:

https://metadata.provider.plex.tv/library/metadata/5e1622d34f2292003e91314a/children?includeUserState=1&episodeOrder=tvdbAiring

The combination of includeUserState=1 and episodeOrder=tvdbAiring breaks the user state data. Without an episode order, the user state is returned correctly (e.g. in viewedLeafCount). However, with episodeOrder included, the user state always returns incorrectly (e.g.viewedLeafCount is always 0).

Here’s a side-by-side comparison of the same example request as above with and without the episodeOrder param:

With episodeOrder

<MediaContainer librarySectionID="home" librarySectionTitle="Metadata" offset="0" totalSize="3" identifier="tv.plex.provider.metadata" size="3">
    <Directory art="https://artworks.thetvdb.com/banners/v4/season/1971742/backgrounds/640194a576f32.jpg" banner="https://artworks.thetvdb.com/banners/v4/season/1971742/banners/64019535f16a9.jpg" guid="plex://season/61bc714e4fe00ccfae63bcf5" key="/library/metadata/61bc714e4fe00ccfae63bcf5/children" ratingKey="61bc714e4fe00ccfae63bcf5" type="season" thumb="https://artworks.thetvdb.com/banners/v4/season/1971742/posters/62113d7daa972.jpg" addedAt="1645142400" publicPagesURL="https://watch.plex.tv/show/severance/season/1" viewedLeafCount="0" title="Season 1" hasGenericTitle="1" parentSlug="severance" parentTitle="Severance" parentType="show" parentArt="https://image.tmdb.org/t/p/original/8MtMFngDWvIdRo34rz3ao0BGBAe.jpg" parentThumb="https://image.tmdb.org/t/p/original/pPHpeI2X1qEd1CS1SeyrdhZ4qnT.jpg" parentRatingKey="5e1622d34f2292003e91314a" parentGuid="plex://show/5e1622d34f2292003e91314a" parentKey="/library/metadata/5e1622d34f2292003e91314a" leafCount="9" index="1" contentRating="TV-MA" originallyAvailableAt="2022-02-18" year="2022">
        ...
    </Directory>
    ...
</MediaContainer>

Without episodeOrder

<MediaContainer librarySectionID="home" librarySectionTitle="Metadata" offset="0" totalSize="3" identifier="tv.plex.provider.metadata" size="3">
    <Directory art="http://assets.fanart.tv/fanart/tv/371980/seasonthumb/severance-640194737dcd7.jpg" banner="http://assets.fanart.tv/fanart/tv/371980/seasonbanner/severance-6401951cc0e73.jpg" guid="plex://season/5e1622d34f2292003e91314e" key="/library/metadata/5e1622d34f2292003e91314e/children" rating="9.7" ratingKey="5e1622d34f2292003e91314e" summary="At Lumon Industries, employees undergo "severance," a procedure dividing their work and personal memories. Mark, a grieving team leader, begins to uncover the dark secrets of the company, forcing him and his coworkers to confront questions of identity, free will, and corporate control." type="season" thumb="https://image.tmdb.org/t/p/original/lFf6LLrQjYldcZItzOkGmMMigP7.jpg" addedAt="1645056000" publicPagesURL="https://watch.plex.tv/show/severance/season/1" viewedLeafCount="9" title="Season 1" hasGenericTitle="1" parentSlug="severance" parentTitle="Severance" parentType="show" parentArt="https://image.tmdb.org/t/p/original/8MtMFngDWvIdRo34rz3ao0BGBAe.jpg" parentThumb="https://image.tmdb.org/t/p/original/pPHpeI2X1qEd1CS1SeyrdhZ4qnT.jpg" parentRatingKey="5e1622d34f2292003e91314a" parentGuid="plex://show/5e1622d34f2292003e91314a" parentKey="/library/metadata/5e1622d34f2292003e91314a" leafCount="9" index="1" contentRating="TV-MA" originallyAvailableAt="2022-02-17" year="2022" audienceRating="8.5" audienceRatingImage="rottentomatoes://image.rating.upright" ratingImage="rottentomatoes://image.rating.ripe">
        ...
    </Directory>
    ...
</MediaContainer>

The difference to note is in the viewedLeafCount attribute. When episodeOrder is included, the viewedLeafCount is 0 instead of 9 (the correct value).


The issue extends even further because when requesting the user state for a specific season (instead of the children of a show), the user state is always returned incorrectly with viewedLeafCount as 0, regardless of the episodeOrder param. Here’s an example request:

https://metadata.provider.plex.tv/library/metadata/61bc714e4fe00ccfae63bcf5?includeUserState=1&episodeOrder=tvdbAiring

I’ll also note that this problem is exclusive to seasons. When requesting the user state of a show, an episode, or the children of a season, the user state is always returned correctly with viewedLeafCount or viewCount as the correct value.

The /library/metadata/{ratingKey}/userState endpoint for seasons is also unaffected by this bug. The user state bug only occurs when:

  1. Requesting a season, or the children of show
  2. Using the includeUserState param
  3. Using the episodeOrder param

How often are you performing these call? Perhaps you could collect user state and episode order separately? If you won’t be destroying their servers :D.

How often are you performing these call?

This is for an open source app, so I guess it depends on the user but it shouldn’t be anything crazy.

Perhaps you could collect user state and episode order separately?

Good suggestion! This is actually what I’m already doing, I just thought I’d post this here in case a Plex Dev sees this and possibly reduces the number of requests I’d need to make.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.