< Summary - Jellyfin

Information
Class: Jellyfin.Server.Implementations.Users.DisplayPreferencesManager
Assembly: Jellyfin.Server.Implementations
File(s): /srv/git/jellyfin/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
Line coverage
74%
Covered lines: 50
Uncovered lines: 17
Coverable lines: 67
Total lines: 153
Line coverage: 74.6%
Branch coverage
75%
Covered branches: 6
Total branches: 8
Branch coverage: 75%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 5/16/2026 - 12:15:55 AM Line coverage: 0% (0/52) Branch coverage: 0% (0/6) Total lines: 11610/29/2026 - 12:17:11 AM Line coverage: 74.6% (50/67) Branch coverage: 75% (6/8) Total lines: 153 5/16/2026 - 12:15:55 AM Line coverage: 0% (0/52) Branch coverage: 0% (0/6) Total lines: 11610/29/2026 - 12:17:11 AM Line coverage: 74.6% (50/67) Branch coverage: 75% (6/8) Total lines: 153

Coverage delta

Coverage delta 75 -75

Metrics

File(s)

/srv/git/jellyfin/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using Jellyfin.Database.Implementations;
 5using Jellyfin.Database.Implementations.Entities;
 6using MediaBrowser.Controller;
 7using Microsoft.EntityFrameworkCore;
 8
 9namespace Jellyfin.Server.Implementations.Users;
 10
 11/// <summary>
 12/// Manages the storage and retrieval of display preferences through Entity Framework.
 13/// </summary>
 14public sealed class DisplayPreferencesManager : IDisplayPreferencesManager
 15{
 16    private const int MaxSaveAttempts = 3;
 17
 18    private readonly IDbContextFactory<JellyfinDbContext> _dbContextFactory;
 19
 20    /// <summary>
 21    /// Initializes a new instance of the <see cref="DisplayPreferencesManager"/> class.
 22    /// </summary>
 23    /// <param name="dbContextFactory">The database context factory.</param>
 24    public DisplayPreferencesManager(IDbContextFactory<JellyfinDbContext> dbContextFactory)
 25    {
 526        _dbContextFactory = dbContextFactory;
 527    }
 28
 29    /// <inheritdoc />
 30    public DisplayPreferences GetDisplayPreferences(Guid userId, Guid itemId, string client)
 31    {
 132        using var dbContext = _dbContextFactory.CreateDbContext();
 133        var prefs = FindDisplayPreferences(dbContext, userId, itemId, client);
 134        if (prefs is not null)
 35        {
 036            return prefs;
 37        }
 38
 139        prefs = new DisplayPreferences(userId, itemId, client);
 140        dbContext.DisplayPreferences.Add(prefs);
 41        try
 42        {
 143            dbContext.SaveChanges();
 044        }
 145        catch (DbUpdateException)
 46        {
 47            // Another request may have stored the preferences between the lookup and the insert, and the unique index
 48            // rejected this one. Return the stored preferences; if there are none, the insert failed for another reason
 149            using var retryContext = _dbContextFactory.CreateDbContext();
 150            var stored = FindDisplayPreferences(retryContext, userId, itemId, client);
 151            if (stored is null)
 52            {
 053                throw;
 54            }
 55
 156            return stored;
 57        }
 58
 059        return prefs;
 160    }
 61
 62    /// <inheritdoc />
 63    public ItemDisplayPreferences GetItemDisplayPreferences(Guid userId, Guid itemId, string client)
 64    {
 365        using var dbContext = _dbContextFactory.CreateDbContext();
 366        var prefs = dbContext.ItemDisplayPreferences
 367            .FirstOrDefault(pref => pref.UserId.Equals(userId) && pref.ItemId.Equals(itemId) && pref.Client == client);
 68
 369        if (prefs is null)
 70        {
 271            prefs = new ItemDisplayPreferences(userId, itemId, client);
 272            dbContext.ItemDisplayPreferences.Add(prefs);
 273            dbContext.SaveChanges();
 74        }
 75
 376        return prefs;
 377    }
 78
 79    /// <inheritdoc />
 80    public IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client)
 81    {
 082        using var dbContext = _dbContextFactory.CreateDbContext();
 083        return dbContext.ItemDisplayPreferences
 084            .Where(prefs => prefs.UserId.Equals(userId) && !prefs.ItemId.Equals(default) && prefs.Client == client)
 085            .ToList();
 086    }
 87
 88    /// <inheritdoc />
 89    public Dictionary<string, string?> ListCustomItemDisplayPreferences(Guid userId, Guid itemId, string client)
 90    {
 291        using var dbContext = _dbContextFactory.CreateDbContext();
 292        return dbContext.CustomItemDisplayPreferences
 293            .Where(prefs => prefs.UserId.Equals(userId)
 294                            && prefs.ItemId.Equals(itemId)
 295                            && prefs.Client == client)
 296            .ToDictionary(prefs => prefs.Key, prefs => prefs.Value);
 297    }
 98
 99    /// <inheritdoc />
 100    public void SetCustomItemDisplayPreferences(Guid userId, Guid itemId, string client, Dictionary<string, string?> cus
 101    {
 102        // Another request can store one of these keys after this one's delete, and the unique index then rejects the
 103        // insert. Replacing the set again gives the same result, so the replace is repeated.
 7104        for (var attempt = 1; ; attempt++)
 105        {
 7106            using var dbContext = _dbContextFactory.CreateDbContext();
 7107            using var transaction = dbContext.Database.BeginTransaction();
 7108            dbContext.CustomItemDisplayPreferences.Where(prefs => prefs.UserId.Equals(userId)
 7109                                && prefs.ItemId.Equals(itemId)
 7110                                && prefs.Client == client)
 7111                                .ExecuteDelete();
 112
 28113            foreach (var (key, value) in customPreferences)
 114            {
 7115                dbContext.CustomItemDisplayPreferences
 7116                    .Add(new CustomItemDisplayPreferences(userId, itemId, client, key, value));
 117            }
 118
 119            try
 120            {
 7121                dbContext.SaveChanges();
 3122            }
 4123            catch (DbUpdateException) when (attempt < MaxSaveAttempts)
 124            {
 3125                continue;
 126            }
 127
 3128            transaction.Commit();
 3129            return;
 130        }
 3131    }
 132
 133    /// <inheritdoc/>
 134    public void UpdateDisplayPreferences(DisplayPreferences displayPreferences)
 135    {
 0136        using var dbContext = _dbContextFactory.CreateDbContext();
 0137        dbContext.DisplayPreferences.Attach(displayPreferences).State = EntityState.Modified;
 0138        dbContext.SaveChanges();
 0139    }
 140
 141    /// <inheritdoc/>
 142    public void UpdateItemDisplayPreferences(ItemDisplayPreferences itemDisplayPreferences)
 143    {
 0144        using var dbContext = _dbContextFactory.CreateDbContext();
 0145        dbContext.ItemDisplayPreferences.Attach(itemDisplayPreferences).State = EntityState.Modified;
 0146        dbContext.SaveChanges();
 0147    }
 148
 149    private static DisplayPreferences? FindDisplayPreferences(JellyfinDbContext dbContext, Guid userId, Guid itemId, str
 2150        => dbContext.DisplayPreferences
 2151            .Include(pref => pref.HomeSections)
 2152            .FirstOrDefault(pref => pref.UserId.Equals(userId) && pref.Client == client && pref.ItemId.Equals(itemId));
 153}