Merge pull request #4652 from crobibero/display-preferences
Add support for custom item display preferences
This commit is contained in:
commit
4e6584c345
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using Jellyfin.Api.Constants;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
@ -47,13 +48,19 @@ namespace Jellyfin.Api.Controllers
|
|||
[FromQuery, Required] Guid userId,
|
||||
[FromQuery, Required] string client)
|
||||
{
|
||||
var displayPreferences = _displayPreferencesManager.GetDisplayPreferences(userId, client);
|
||||
var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(displayPreferences.UserId, Guid.Empty, displayPreferences.Client);
|
||||
if (!Guid.TryParse(displayPreferencesId, out var itemId))
|
||||
{
|
||||
itemId = displayPreferencesId.GetMD5();
|
||||
}
|
||||
|
||||
var displayPreferences = _displayPreferencesManager.GetDisplayPreferences(userId, itemId, client);
|
||||
var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(displayPreferences.UserId, itemId, displayPreferences.Client);
|
||||
itemPreferences.ItemId = itemId;
|
||||
|
||||
var dto = new DisplayPreferencesDto
|
||||
{
|
||||
Client = displayPreferences.Client,
|
||||
Id = displayPreferences.UserId.ToString(),
|
||||
Id = displayPreferences.ItemId.ToString(),
|
||||
ViewType = itemPreferences.ViewType.ToString(),
|
||||
SortBy = itemPreferences.SortBy,
|
||||
SortOrder = itemPreferences.SortOrder,
|
||||
|
@ -81,6 +88,16 @@ namespace Jellyfin.Api.Controllers
|
|||
dto.CustomPrefs["enableNextVideoInfoOverlay"] = displayPreferences.EnableNextVideoInfoOverlay.ToString(CultureInfo.InvariantCulture);
|
||||
dto.CustomPrefs["tvhome"] = displayPreferences.TvHome;
|
||||
|
||||
// Load all custom display preferences
|
||||
var customDisplayPreferences = _displayPreferencesManager.ListCustomItemDisplayPreferences(displayPreferences.UserId, itemId, displayPreferences.Client);
|
||||
if (customDisplayPreferences != null)
|
||||
{
|
||||
foreach (var (key, value) in customDisplayPreferences)
|
||||
{
|
||||
dto.CustomPrefs.TryAdd(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// This will essentially be a noop if no changes have been made, but new prefs must be saved at least.
|
||||
_displayPreferencesManager.SaveChanges();
|
||||
|
||||
|
@ -115,7 +132,12 @@ namespace Jellyfin.Api.Controllers
|
|||
HomeSectionType.LatestMedia, HomeSectionType.None,
|
||||
};
|
||||
|
||||
var existingDisplayPreferences = _displayPreferencesManager.GetDisplayPreferences(userId, client);
|
||||
if (!Guid.TryParse(displayPreferencesId, out var itemId))
|
||||
{
|
||||
itemId = displayPreferencesId.GetMD5();
|
||||
}
|
||||
|
||||
var existingDisplayPreferences = _displayPreferencesManager.GetDisplayPreferences(userId, itemId, client);
|
||||
existingDisplayPreferences.IndexBy = Enum.TryParse<IndexingKind>(displayPreferences.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null;
|
||||
existingDisplayPreferences.ShowBackdrop = displayPreferences.ShowBackdrop;
|
||||
existingDisplayPreferences.ShowSidebar = displayPreferences.ShowSidebar;
|
||||
|
@ -124,21 +146,33 @@ namespace Jellyfin.Api.Controllers
|
|||
existingDisplayPreferences.ChromecastVersion = displayPreferences.CustomPrefs.TryGetValue("chromecastVersion", out var chromecastVersion)
|
||||
? Enum.Parse<ChromecastVersion>(chromecastVersion, true)
|
||||
: ChromecastVersion.Stable;
|
||||
displayPreferences.CustomPrefs.Remove("chromecastVersion");
|
||||
|
||||
existingDisplayPreferences.EnableNextVideoInfoOverlay = displayPreferences.CustomPrefs.TryGetValue("enableNextVideoInfoOverlay", out var enableNextVideoInfoOverlay)
|
||||
? bool.Parse(enableNextVideoInfoOverlay)
|
||||
: true;
|
||||
displayPreferences.CustomPrefs.Remove("enableNextVideoInfoOverlay");
|
||||
|
||||
existingDisplayPreferences.SkipBackwardLength = displayPreferences.CustomPrefs.TryGetValue("skipBackLength", out var skipBackLength)
|
||||
? int.Parse(skipBackLength, CultureInfo.InvariantCulture)
|
||||
: 10000;
|
||||
displayPreferences.CustomPrefs.Remove("skipBackLength");
|
||||
|
||||
existingDisplayPreferences.SkipForwardLength = displayPreferences.CustomPrefs.TryGetValue("skipForwardLength", out var skipForwardLength)
|
||||
? int.Parse(skipForwardLength, CultureInfo.InvariantCulture)
|
||||
: 30000;
|
||||
displayPreferences.CustomPrefs.Remove("skipForwardLength");
|
||||
|
||||
existingDisplayPreferences.DashboardTheme = displayPreferences.CustomPrefs.TryGetValue("dashboardTheme", out var theme)
|
||||
? theme
|
||||
: string.Empty;
|
||||
displayPreferences.CustomPrefs.Remove("dashboardTheme");
|
||||
|
||||
existingDisplayPreferences.TvHome = displayPreferences.CustomPrefs.TryGetValue("tvhome", out var home)
|
||||
? home
|
||||
: string.Empty;
|
||||
displayPreferences.CustomPrefs.Remove("tvhome");
|
||||
|
||||
existingDisplayPreferences.HomeSections.Clear();
|
||||
|
||||
foreach (var key in displayPreferences.CustomPrefs.Keys.Where(key => key.StartsWith("homesection", StringComparison.OrdinalIgnoreCase)))
|
||||
|
@ -149,26 +183,34 @@ namespace Jellyfin.Api.Controllers
|
|||
type = order < 7 ? defaults[order] : HomeSectionType.None;
|
||||
}
|
||||
|
||||
displayPreferences.CustomPrefs.Remove(key);
|
||||
existingDisplayPreferences.HomeSections.Add(new HomeSection { Order = order, Type = type });
|
||||
}
|
||||
|
||||
foreach (var key in displayPreferences.CustomPrefs.Keys.Where(key => key.StartsWith("landing-", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(existingDisplayPreferences.UserId, Guid.Parse(key.Substring("landing-".Length)), existingDisplayPreferences.Client);
|
||||
if (Guid.TryParse(key.AsSpan().Slice("landing-".Length), out var preferenceId))
|
||||
{
|
||||
var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(existingDisplayPreferences.UserId, preferenceId, existingDisplayPreferences.Client);
|
||||
itemPreferences.ViewType = Enum.Parse<ViewType>(displayPreferences.ViewType);
|
||||
displayPreferences.CustomPrefs.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
var itemPrefs = _displayPreferencesManager.GetItemDisplayPreferences(existingDisplayPreferences.UserId, Guid.Empty, existingDisplayPreferences.Client);
|
||||
var itemPrefs = _displayPreferencesManager.GetItemDisplayPreferences(existingDisplayPreferences.UserId, itemId, existingDisplayPreferences.Client);
|
||||
itemPrefs.SortBy = displayPreferences.SortBy;
|
||||
itemPrefs.SortOrder = displayPreferences.SortOrder;
|
||||
itemPrefs.RememberIndexing = displayPreferences.RememberIndexing;
|
||||
itemPrefs.RememberSorting = displayPreferences.RememberSorting;
|
||||
itemPrefs.ItemId = itemId;
|
||||
|
||||
if (Enum.TryParse<ViewType>(displayPreferences.ViewType, true, out var viewType))
|
||||
{
|
||||
itemPrefs.ViewType = viewType;
|
||||
}
|
||||
|
||||
// Set all remaining custom preferences.
|
||||
_displayPreferencesManager.SetCustomItemDisplayPreferences(userId, itemId, existingDisplayPreferences.Client, displayPreferences.CustomPrefs);
|
||||
_displayPreferencesManager.SaveChanges();
|
||||
|
||||
return NoContent();
|
||||
|
|
90
Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs
Normal file
90
Jellyfin.Data/Entities/CustomItemDisplayPreferences.cs
Normal file
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Jellyfin.Data.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity that represents a user's custom display preferences for a specific item.
|
||||
/// </summary>
|
||||
public class CustomItemDisplayPreferences
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CustomItemDisplayPreferences"/> class.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="preferenceKey">The preference key.</param>
|
||||
/// <param name="preferenceValue">The preference value.</param>
|
||||
public CustomItemDisplayPreferences(Guid userId, Guid itemId, string client, string preferenceKey, string preferenceValue)
|
||||
{
|
||||
UserId = userId;
|
||||
ItemId = itemId;
|
||||
Client = client;
|
||||
Key = preferenceKey;
|
||||
Value = preferenceValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CustomItemDisplayPreferences"/> class.
|
||||
/// </summary>
|
||||
protected CustomItemDisplayPreferences()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Id.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Required.
|
||||
/// </remarks>
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user Id.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Required.
|
||||
/// </remarks>
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id of the associated item.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Required.
|
||||
/// </remarks>
|
||||
public Guid ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the client string.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Required. Max Length = 32.
|
||||
/// </remarks>
|
||||
[Required]
|
||||
[MaxLength(32)]
|
||||
[StringLength(32)]
|
||||
public string Client { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the preference key.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Required.
|
||||
/// </remarks>
|
||||
[Required]
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the preference value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Required.
|
||||
/// </remarks>
|
||||
[Required]
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
|
@ -17,10 +17,12 @@ namespace Jellyfin.Data.Entities
|
|||
/// Initializes a new instance of the <see cref="DisplayPreferences"/> class.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id.</param>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <param name="client">The client string.</param>
|
||||
public DisplayPreferences(Guid userId, string client)
|
||||
public DisplayPreferences(Guid userId, Guid itemId, string client)
|
||||
{
|
||||
UserId = userId;
|
||||
ItemId = itemId;
|
||||
Client = client;
|
||||
ShowSidebar = false;
|
||||
ShowBackdrop = true;
|
||||
|
@ -58,6 +60,14 @@ namespace Jellyfin.Data.Entities
|
|||
/// </remarks>
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id of the associated item.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Required.
|
||||
/// </remarks>
|
||||
public Guid ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the client string.
|
||||
/// </summary>
|
||||
|
|
|
@ -34,6 +34,8 @@ namespace Jellyfin.Server.Implementations
|
|||
|
||||
public virtual DbSet<ItemDisplayPreferences> ItemDisplayPreferences { get; set; }
|
||||
|
||||
public virtual DbSet<CustomItemDisplayPreferences> CustomItemDisplayPreferences { get; set; }
|
||||
|
||||
public virtual DbSet<Permission> Permissions { get; set; }
|
||||
|
||||
public virtual DbSet<Preference> Preferences { get; set; }
|
||||
|
@ -151,7 +153,15 @@ namespace Jellyfin.Server.Implementations
|
|||
.IsUnique(false);
|
||||
|
||||
modelBuilder.Entity<DisplayPreferences>()
|
||||
.HasIndex(entity => new { entity.UserId, entity.Client })
|
||||
.HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client })
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<CustomItemDisplayPreferences>()
|
||||
.HasIndex(entity => entity.UserId)
|
||||
.IsUnique(false);
|
||||
|
||||
modelBuilder.Entity<CustomItemDisplayPreferences>()
|
||||
.HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client, entity.Key })
|
||||
.IsUnique();
|
||||
}
|
||||
}
|
||||
|
|
522
Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs
generated
Normal file
522
Jellyfin.Server.Implementations/Migrations/20201204223655_AddCustomDisplayPreferences.Designer.cs
generated
Normal file
|
@ -0,0 +1,522 @@
|
|||
#pragma warning disable CS1591
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Jellyfin.Server.Implementations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Migrations
|
||||
{
|
||||
[DbContext(typeof(JellyfinDb))]
|
||||
[Migration("20201204223655_AddCustomDisplayPreferences")]
|
||||
partial class AddCustomDisplayPreferences
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("jellyfin")
|
||||
.HasAnnotation("ProductVersion", "5.0.0");
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DayOfWeek")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("EndHour")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("StartHour")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AccessSchedules");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ItemId")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("LogSeverity")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Overview")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ShortOverview")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ActivityLogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Client")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("UserId", "ItemId", "Client", "Key")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("CustomItemDisplayPreferences");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ChromecastVersion")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Client")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DashboardTheme")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EnableNextVideoInfoOverlay")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("IndexBy")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ScrollDirection")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ShowBackdrop")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ShowSidebar")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SkipBackwardLength")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SkipForwardLength")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("TvHome")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("UserId", "ItemId", "Client")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DisplayPreferences");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DisplayPreferencesId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Order")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DisplayPreferencesId");
|
||||
|
||||
b.ToTable("HomeSection");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("LastModified")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Path")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("ImageInfos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Client")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("IndexBy")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("RememberIndexing")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("RememberSorting")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SortBy")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ViewType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("ItemDisplayPreferences");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Kind")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid?>("Permission_Permissions_Guid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Value")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Permission_Permissions_Guid");
|
||||
|
||||
b.ToTable("Permissions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Kind")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid?>("Preference_Preferences_Guid")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Preference_Preferences_Guid");
|
||||
|
||||
b.ToTable("Preferences");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AudioLanguagePreference")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AuthenticationProviderId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("DisplayCollectionsView")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("DisplayMissingEpisodes")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("EasyPassword")
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EnableAutoLogin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("EnableLocalPassword")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("EnableNextEpisodeAutoPlay")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("EnableUserPreferenceAccess")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("HidePlayedInLatest")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("InternalId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("InvalidLoginAttemptCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastActivityDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("LastLoginDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("LoginAttemptsBeforeLockout")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("MaxActiveSessions")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("MaxParentalAgeRating")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("MustUpdatePassword")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordResetProviderId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PlayDefaultAudioTrack")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("RememberAudioSelections")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("RememberSubtitleSelections")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("RemoteClientBitrateLimit")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SubtitleLanguagePreference")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SubtitleMode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SyncPlayAccess")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithMany("AccessSchedules")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithOne("DisplayPreferences")
|
||||
.HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null)
|
||||
.WithMany("HomeSections")
|
||||
.HasForeignKey("DisplayPreferencesId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithOne("ProfileImage")
|
||||
.HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithMany("ItemDisplayPreferences")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithMany("Permissions")
|
||||
.HasForeignKey("Permission_Permissions_Guid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
|
||||
{
|
||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||
.WithMany("Preferences")
|
||||
.HasForeignKey("Preference_Preferences_Guid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||
{
|
||||
b.Navigation("HomeSections");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
|
||||
{
|
||||
b.Navigation("AccessSchedules");
|
||||
|
||||
b.Navigation("DisplayPreferences")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ItemDisplayPreferences");
|
||||
|
||||
b.Navigation("Permissions");
|
||||
|
||||
b.Navigation("Preferences");
|
||||
|
||||
b.Navigation("ProfileImage");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
#pragma warning disable CS1591
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Migrations
|
||||
{
|
||||
public partial class AddCustomDisplayPreferences : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_DisplayPreferences_UserId_Client",
|
||||
schema: "jellyfin",
|
||||
table: "DisplayPreferences");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "MaxActiveSessions",
|
||||
schema: "jellyfin",
|
||||
table: "Users",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "INTEGER",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "ItemId",
|
||||
schema: "jellyfin",
|
||||
table: "DisplayPreferences",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CustomItemDisplayPreferences",
|
||||
schema: "jellyfin",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
UserId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ItemId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
Client = table.Column<string>(type: "TEXT", maxLength: 32, nullable: false),
|
||||
Key = table.Column<string>(type: "TEXT", nullable: false),
|
||||
Value = table.Column<string>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CustomItemDisplayPreferences", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DisplayPreferences_UserId_ItemId_Client",
|
||||
schema: "jellyfin",
|
||||
table: "DisplayPreferences",
|
||||
columns: new[] { "UserId", "ItemId", "Client" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CustomItemDisplayPreferences_UserId",
|
||||
schema: "jellyfin",
|
||||
table: "CustomItemDisplayPreferences",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CustomItemDisplayPreferences_UserId_ItemId_Client_Key",
|
||||
schema: "jellyfin",
|
||||
table: "CustomItemDisplayPreferences",
|
||||
columns: new[] { "UserId", "ItemId", "Client", "Key" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "CustomItemDisplayPreferences",
|
||||
schema: "jellyfin");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_DisplayPreferences_UserId_ItemId_Client",
|
||||
schema: "jellyfin",
|
||||
table: "DisplayPreferences");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ItemId",
|
||||
schema: "jellyfin",
|
||||
table: "DisplayPreferences");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "MaxActiveSessions",
|
||||
schema: "jellyfin",
|
||||
table: "Users",
|
||||
type: "INTEGER",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "INTEGER");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DisplayPreferences_UserId_Client",
|
||||
schema: "jellyfin",
|
||||
table: "DisplayPreferences",
|
||||
columns: new[] { "UserId", "Client" },
|
||||
unique: true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("jellyfin")
|
||||
.HasAnnotation("ProductVersion", "3.1.8");
|
||||
.HasAnnotation("ProductVersion", "5.0.0");
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
|
||||
{
|
||||
|
@ -52,33 +52,33 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ItemId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("LogSeverity")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(512);
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Overview")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(512);
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("RowVersion")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ShortOverview")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(512);
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(256);
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
@ -88,6 +88,41 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
b.ToTable("ActivityLogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Client")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("UserId", "ItemId", "Client", "Key")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("CustomItemDisplayPreferences");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -99,12 +134,12 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
|
||||
b.Property<string>("Client")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(32);
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DashboardTheme")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(32);
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EnableNextVideoInfoOverlay")
|
||||
.HasColumnType("INTEGER");
|
||||
|
@ -112,6 +147,9 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
b.Property<int?>("IndexBy")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ScrollDirection")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
@ -128,8 +166,8 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("TvHome")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(32);
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
@ -138,7 +176,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("UserId", "Client")
|
||||
b.HasIndex("UserId", "ItemId", "Client")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DisplayPreferences");
|
||||
|
@ -177,8 +215,8 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
|
||||
b.Property<string>("Path")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(512);
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
@ -199,8 +237,8 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
|
||||
b.Property<string>("Client")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(32);
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("IndexBy")
|
||||
.HasColumnType("INTEGER");
|
||||
|
@ -216,8 +254,8 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
|
||||
b.Property<string>("SortBy")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(64);
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
@ -279,8 +317,8 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(65535);
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
|
@ -296,13 +334,13 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AudioLanguagePreference")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(255);
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AuthenticationProviderId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(255);
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("DisplayCollectionsView")
|
||||
.HasColumnType("INTEGER");
|
||||
|
@ -311,8 +349,8 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("EasyPassword")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(65535);
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EnableAutoLogin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
@ -354,13 +392,13 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(65535);
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordResetProviderId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(255);
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PlayDefaultAudioTrack")
|
||||
.HasColumnType("INTEGER");
|
||||
|
@ -379,8 +417,8 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SubtitleLanguagePreference")
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(255);
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("SubtitleMode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
@ -390,8 +428,8 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasMaxLength(255);
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
|
@ -454,6 +492,27 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||
.WithMany("Preferences")
|
||||
.HasForeignKey("Preference_Preferences_Guid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||
{
|
||||
b.Navigation("HomeSections");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
|
||||
{
|
||||
b.Navigation("AccessSchedules");
|
||||
|
||||
b.Navigation("DisplayPreferences")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ItemDisplayPreferences");
|
||||
|
||||
b.Navigation("Permissions");
|
||||
|
||||
b.Navigation("Preferences");
|
||||
|
||||
b.Navigation("ProfileImage");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,16 +26,16 @@ namespace Jellyfin.Server.Implementations.Users
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public DisplayPreferences GetDisplayPreferences(Guid userId, string client)
|
||||
public DisplayPreferences GetDisplayPreferences(Guid userId, Guid itemId, string client)
|
||||
{
|
||||
var prefs = _dbContext.DisplayPreferences
|
||||
.Include(pref => pref.HomeSections)
|
||||
.FirstOrDefault(pref =>
|
||||
pref.UserId == userId && string.Equals(pref.Client, client));
|
||||
pref.UserId == userId && string.Equals(pref.Client, client) && pref.ItemId == itemId);
|
||||
|
||||
if (prefs == null)
|
||||
{
|
||||
prefs = new DisplayPreferences(userId, client);
|
||||
prefs = new DisplayPreferences(userId, itemId, client);
|
||||
_dbContext.DisplayPreferences.Add(prefs);
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,34 @@ namespace Jellyfin.Server.Implementations.Users
|
|||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IDictionary<string, string> ListCustomItemDisplayPreferences(Guid userId, Guid itemId, string client)
|
||||
{
|
||||
return _dbContext.CustomItemDisplayPreferences
|
||||
.AsQueryable()
|
||||
.Where(prefs => prefs.UserId == userId
|
||||
&& prefs.ItemId == itemId
|
||||
&& string.Equals(prefs.Client, client))
|
||||
.ToDictionary(prefs => prefs.Key, prefs => prefs.Value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetCustomItemDisplayPreferences(Guid userId, Guid itemId, string client, Dictionary<string, string> customPreferences)
|
||||
{
|
||||
var existingPrefs = _dbContext.CustomItemDisplayPreferences
|
||||
.AsQueryable()
|
||||
.Where(prefs => prefs.UserId == userId
|
||||
&& prefs.ItemId == itemId
|
||||
&& string.Equals(prefs.Client, client));
|
||||
_dbContext.CustomItemDisplayPreferences.RemoveRange(existingPrefs);
|
||||
|
||||
foreach (var (key, value) in customPreferences)
|
||||
{
|
||||
_dbContext.CustomItemDisplayPreferences
|
||||
.Add(new CustomItemDisplayPreferences(userId, itemId, client, key, value));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SaveChanges()
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Text.Json.Serialization;
|
|||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Server.Implementations;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -94,6 +95,7 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||
continue;
|
||||
}
|
||||
|
||||
var itemId = new Guid(result[1].ToBlob());
|
||||
var dtoUserId = new Guid(result[1].ToBlob());
|
||||
var existingUser = _userManager.GetUserById(dtoUserId);
|
||||
if (existingUser == null)
|
||||
|
@ -105,8 +107,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||
var chromecastVersion = dto.CustomPrefs.TryGetValue("chromecastVersion", out var version)
|
||||
? chromecastDict[version]
|
||||
: ChromecastVersion.Stable;
|
||||
dto.CustomPrefs.Remove("chromecastVersion");
|
||||
|
||||
var displayPreferences = new DisplayPreferences(dtoUserId, result[2].ToString())
|
||||
var displayPreferences = new DisplayPreferences(dtoUserId, itemId, result[2].ToString())
|
||||
{
|
||||
IndexBy = Enum.TryParse<IndexingKind>(dto.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null,
|
||||
ShowBackdrop = dto.ShowBackdrop,
|
||||
|
@ -126,15 +129,24 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||
TvHome = dto.CustomPrefs.TryGetValue("tvhome", out var home) ? home : string.Empty
|
||||
};
|
||||
|
||||
dto.CustomPrefs.Remove("skipForwardLength");
|
||||
dto.CustomPrefs.Remove("skipBackLength");
|
||||
dto.CustomPrefs.Remove("enableNextVideoInfoOverlay");
|
||||
dto.CustomPrefs.Remove("dashboardtheme");
|
||||
dto.CustomPrefs.Remove("tvhome");
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
dto.CustomPrefs.TryGetValue("homesection" + i, out var homeSection);
|
||||
var key = "homesection" + i;
|
||||
dto.CustomPrefs.TryGetValue(key, out var homeSection);
|
||||
|
||||
displayPreferences.HomeSections.Add(new HomeSection
|
||||
{
|
||||
Order = i,
|
||||
Type = Enum.TryParse<HomeSectionType>(homeSection, true, out var type) ? type : defaults[i]
|
||||
});
|
||||
|
||||
dto.CustomPrefs.Remove(key);
|
||||
}
|
||||
|
||||
var defaultLibraryPrefs = new ItemDisplayPreferences(displayPreferences.UserId, Guid.Empty, displayPreferences.Client)
|
||||
|
@ -149,12 +161,12 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||
|
||||
foreach (var key in dto.CustomPrefs.Keys.Where(key => key.StartsWith("landing-", StringComparison.Ordinal)))
|
||||
{
|
||||
if (!Guid.TryParse(key.AsSpan().Slice("landing-".Length), out var itemId))
|
||||
if (!Guid.TryParse(key.AsSpan().Slice("landing-".Length), out var landingItemId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var libraryDisplayPreferences = new ItemDisplayPreferences(displayPreferences.UserId, itemId, displayPreferences.Client)
|
||||
var libraryDisplayPreferences = new ItemDisplayPreferences(displayPreferences.UserId, landingItemId, displayPreferences.Client)
|
||||
{
|
||||
SortBy = dto.SortBy ?? "SortName",
|
||||
SortOrder = dto.SortOrder,
|
||||
|
@ -167,9 +179,15 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||
libraryDisplayPreferences.ViewType = viewType;
|
||||
}
|
||||
|
||||
dto.CustomPrefs.Remove(key);
|
||||
dbContext.ItemDisplayPreferences.Add(libraryDisplayPreferences);
|
||||
}
|
||||
|
||||
foreach (var (key, value) in dto.CustomPrefs)
|
||||
{
|
||||
dbContext.Add(new CustomItemDisplayPreferences(displayPreferences.UserId, itemId, displayPreferences.Client, key, value));
|
||||
}
|
||||
|
||||
dbContext.Add(displayPreferences);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,9 +16,10 @@ namespace MediaBrowser.Controller
|
|||
/// This will create the display preferences if it does not exist, but it will not save automatically.
|
||||
/// </remarks>
|
||||
/// <param name="userId">The user's id.</param>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <param name="client">The client string.</param>
|
||||
/// <returns>The associated display preferences.</returns>
|
||||
DisplayPreferences GetDisplayPreferences(Guid userId, string client);
|
||||
DisplayPreferences GetDisplayPreferences(Guid userId, Guid itemId, string client);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default item display preferences for the user and client.
|
||||
|
@ -40,6 +41,24 @@ namespace MediaBrowser.Controller
|
|||
/// <returns>A list of item display preferences.</returns>
|
||||
IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all of the custom item display preferences for the user and client.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <param name="client">The client string.</param>
|
||||
/// <returns>The dictionary of custom item display preferences.</returns>
|
||||
IDictionary<string, string> ListCustomItemDisplayPreferences(Guid userId, Guid itemId, string client);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the custom item display preference for the user and client.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="itemId">The item id.</param>
|
||||
/// <param name="client">The client id.</param>
|
||||
/// <param name="customPreferences">A dictionary of custom item display preferences.</param>
|
||||
void SetCustomItemDisplayPreferences(Guid userId, Guid itemId, string client, Dictionary<string, string> customPreferences);
|
||||
|
||||
/// <summary>
|
||||
/// Saves changes made to the database.
|
||||
/// </summary>
|
||||
|
|
Loading…
Reference in New Issue
Block a user