Skip to content

Jellyfin watch status sync writes 0 rows when the library's videos are in Collections #794

Description

@philipsteingruber

Youtarr v1.81.0, Jellyfin 10.11.11, one (admin) user, jellyfinWatchStatusAllUsers = true.

What happens

I have 219 videos in a Movies-type Jellyfin library, organised into 49 Collections, one per channel. The watch status sync reports success on every run and never writes a row:

Starting watch status sync {"trigger":"scheduled","videoCount":219,"serverCount":1}
Watch status sync completed for server {"serverType":"jellyfin","updated":0,"rowsWritten":0,"entries":124,"users":1}

video_watch_status stayed empty, so watched auto-removal never had a candidate to work with:

[Auto-Removal] Found watched videos eligible for removal {"count":0,"minDaysSinceWatched":0,"minVideoAgeDays":0}

Nothing logs an error. The only clue is rowsWritten: 0, and that looks identical to a run which genuinely had nothing to do.

The 124 entries in that log line aren't videos at all. In my case they were 50 BoxSets plus 74 Episodes from unrelated libraries. None of the 219 videos came back in the response.

Why

fetchWatchStates in server/modules/mediaServers/adapters/jellyfinAdapter.js doesn't pass collapseBoxSetItems:

const params = {
  userId: user.id,
  includeItemTypes: 'Video,Movie,Episode',
  recursive: true,
  fields: 'Path',
  enableUserData: true,
};

Jellyfin's ItemsController takes that parameter as a nullable bool and hands it to the query without supplying a default. When it arrives null, Folder.cs decides for itself:

var param = query.CollapseBoxSetItems;
if (param.HasValue) { return param.Value && AllowBoxSetCollapsing(query); }

var config = configurationManager.Configuration;
bool queryHasMovies = query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(BaseItemKind.Movie);
bool queryHasSeries = query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(BaseItemKind.Series);
bool collapseMovies = config.EnableGroupingMoviesIntoCollections;
bool collapseSeries = config.EnableGroupingShowsIntoCollections;
if (user is not null)
{
    bool canCollapse = (queryHasMovies && collapseMovies) || (queryHasSeries && collapseSeries);
    return canCollapse && AllowBoxSetCollapsing(query);
}

So on a user-scoped query that includes Movie, Jellyfin swaps out every movie belonging to a Collection and returns the Collection instead. EnableGroupingMoviesIntoCollections is a server-wide setting (Dashboard, Libraries, Display, "Group movies into collections") and it ships enabled, so this should hit anyone who has grouped their library into Collections.

Reproducing it

  1. Point Youtarr at a Movies-type Jellyfin library.
  2. Put the videos into one or more Collections.
  3. Leave "Group movies into collections" checked, which is the default.
  4. Run a watch status sync.

Here's the same query with and without the parameter, against my library:

Query Result
/Items?UserId=…&ParentId=<lib>&IncludeItemTypes=Movie&Recursive=true 49 items, all BoxSet, Path is …/collections/<name> [boxset]
same, plus &CollapseBoxSetItems=false 219 items, all Movie, real file paths, 12 with UserData.Played = true

Suggested fix

Add the parameter in fetchWatchStates:

const params = {
  userId: user.id,
  includeItemTypes: 'Video,Movie,Episode',
  recursive: true,
  fields: 'Path',
  enableUserData: true,
  collapseBoxSetItems: false,
};

Collapsing is a browse-view convenience and there's no case where you'd want it on a data query, so I think the same applies to the /Items call used for file resolution further up the adapter.

Separately: it might be worth logging a warning when a sync matches none of N videos and N is greater than zero. That case currently looks exactly like a healthy no-op, which is why it took me a couple of days to spot.

Workaround

Unchecking "Group movies into collections" fixes it right away. My next sync wrote all 219 rows. It's a server-wide setting though, so it also changes how ordinary movie libraries display.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions