Mark watched not working for media mis-identified and then corrected #7916

Open
opened 2025-12-22 06:31:02 +01:00 by backuprepo · 2 comments
Owner

Originally created by @poweredbyporkers on GitHub (Dec 14, 2025).

Description of the bug

If I issue an API command to mark a media item (that was initially mismatched) as watched (in this case) it returns a 200 OK but doesn't mark them as watched. This also happens via UI and tried marking as watched, and the same thing, they just never stick at being watched it just immediately goes from watched back to unwatched (in terms of the tick changing colour)

Monitoring the network tab in chrome dev tools shows the same issue as the API call a 200 response but with {"PlaybackPositionTicks": 0, "PlayCount": 0, "IsFavorite": false, "Played": false, "Key": "503901", "ItemId": "978b227d683dbf824d134ba62f60db32"}

Reproduction steps

I'm not sure it's easy to supply replication steps as it has to match an incorrect item but for me the example is

The Bodyguard (1992) (tt0103855) for some reason matched to a Russian movie called Телохранитель (1992) (tt0197013) which has an aka of The Bodyguard

So the item was stored with 2 new rows with keys tt0197013 and 503901
Correcting the match created 3 new rows with keys tt0103855, 619 and the item id

What is the current bug behavior?

When changing watched status via the API or UI it returns all 5 rows in the query and the proper 3 keys via var keys = item.GetUserDataKeys();

It then updates these 3 correct codes to watched, for example, but the older codes which happen to be the first two results are ignored

Image

Then is returns the first row of the result set which is Played=False as the old keys aren't updated, which is correct, but this leads to the database thinking it's watched and the API/UI thinking it's unwatched

What is the expected correct behavior?

I suspect that given UserDataManager.SaveUserData is the lowest point of many paths there should be a method added to clear out any keys for this ItemId/UserId combo that weren't returned as part of the item.GetUserDataKeys() call something like. This would lessen the chance of the issue being seen as old keys would be automatically removed and the correct item would be selected and returned to the API/UI

private static void RemoveUserDataNoLongerAssociatedViaKey(JellyfinDbContext dbContext, User user, BaseItem item, List<string> keys)
{
    var noLongerAssociated = dbContext.UserData
           .Where(f => f.ItemId == item.Id && f.UserId == user.Id && !keys.Contains(f.CustomDataKey));

    if (noLongerAssociated.Any())
    {
        dbContext.UserData.RemoveRange(noLongerAssociated);
    }
 }

Jellyfin Server version

10.11.4

Specify commit id

No response

Specify unstable release number

No response

Specify version number

No response

Specify the build version

10.11.4

Environment

- OS: Unraid 7.2.0
- Linux Kernel: Linux 6.12.54-Unraid x86_64
- Virtualization: Docker
- Clients: Web
- Browser: Chrome
- FFmpeg Version:
- Playback Method:
- Hardware Acceleration: QSV
- CPU Model:
- GPU Model:
- Plugins:
- Reverse Proxy: nginx
- Base URL:
- Networking:
- Jellyfin Data Storage & Filesystem:
- Media Storage & Filesystem:
- External Integrations:

Jellyfin logs

Logs not required

FFmpeg logs


Client / Browser logs

No response

Relevant screenshots or videos

No response

Additional information

No response

Originally created by @poweredbyporkers on GitHub (Dec 14, 2025). ### Description of the bug If I issue an API command to mark a media item (that was initially mismatched) as watched (in this case) it returns a 200 OK but doesn't mark them as watched. This also happens via UI and tried marking as watched, and the same thing, they just never stick at being watched it just immediately goes from watched back to unwatched (in terms of the tick changing colour) Monitoring the network tab in chrome dev tools shows the same issue as the API call a 200 response but with {"PlaybackPositionTicks": 0, "PlayCount": 0, "IsFavorite": false, "Played": false, "Key": "503901", "ItemId": "978b227d683dbf824d134ba62f60db32"} ### Reproduction steps I'm not sure it's easy to supply replication steps as it has to match an incorrect item but for me the example is The Bodyguard (1992) (tt0103855) for some reason matched to a Russian movie called Телохранитель (1992) (tt0197013) which has an aka of The Bodyguard So the item was stored with 2 new rows with keys tt0197013 and 503901 Correcting the match created 3 new rows with keys tt0103855, 619 and the item id ### What is the current _bug_ behavior? When changing watched status via the API or UI it returns all 5 rows in the query and the proper 3 keys via `var keys = item.GetUserDataKeys();` It then updates these 3 correct codes to watched, for example, but the older codes which happen to be the first two results are ignored <img width="2418" height="1123" alt="Image" src="https://github.com/user-attachments/assets/6324632b-9f38-444c-8ee3-1771320443a0" /> Then is returns the first row of the result set which is Played=False as the old keys aren't updated, which is correct, but this leads to the database thinking it's watched and the API/UI thinking it's unwatched ### What is the expected _correct_ behavior? I suspect that given UserDataManager.SaveUserData is the lowest point of many paths there should be a method added to clear out any keys for this ItemId/UserId combo that weren't returned as part of the item.GetUserDataKeys() call something like. This would lessen the chance of the issue being seen as old keys would be automatically removed and the correct item would be selected and returned to the API/UI ``` private static void RemoveUserDataNoLongerAssociatedViaKey(JellyfinDbContext dbContext, User user, BaseItem item, List<string> keys) { var noLongerAssociated = dbContext.UserData .Where(f => f.ItemId == item.Id && f.UserId == user.Id && !keys.Contains(f.CustomDataKey)); if (noLongerAssociated.Any()) { dbContext.UserData.RemoveRange(noLongerAssociated); } } ``` ### Jellyfin Server version 10.11.4 ### Specify commit id _No response_ ### Specify unstable release number _No response_ ### Specify version number _No response_ ### Specify the build version 10.11.4 ### Environment ```markdown - OS: Unraid 7.2.0 - Linux Kernel: Linux 6.12.54-Unraid x86_64 - Virtualization: Docker - Clients: Web - Browser: Chrome - FFmpeg Version: - Playback Method: - Hardware Acceleration: QSV - CPU Model: - GPU Model: - Plugins: - Reverse Proxy: nginx - Base URL: - Networking: - Jellyfin Data Storage & Filesystem: - Media Storage & Filesystem: - External Integrations: ``` ### Jellyfin logs ```shell Logs not required ``` ### FFmpeg logs ```shell ``` ### Client / Browser logs _No response_ ### Relevant screenshots or videos _No response_ ### Additional information _No response_
backuprepo added the
bug
label 2025-12-22 06:31:02 +01:00
Author
Owner

@poweredbyporkers commented on GitHub (Dec 15, 2025):

Apologies, I think this is the same as https://github.com/jellyfin/jellyfin/issues/15615. I did search but was using the wrong terminology

@poweredbyporkers commented on GitHub (Dec 15, 2025): Apologies, I think this is the same as https://github.com/jellyfin/jellyfin/issues/15615. I did search but was using the wrong terminology
Author
Owner

@Smeagolworms4 commented on GitHub (Dec 15, 2025):

+1 These are old folders I used to use as collections, now seen as TV shows. And it's impossible to force them to be used as collections. No NFO files or anything...

@Smeagolworms4 commented on GitHub (Dec 15, 2025): +1 These are old folders I used to use as collections, now seen as TV shows. And it's impossible to force them to be used as collections. No NFO files or anything...
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: starred/jellyfin#7916
No description provided.