mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-05-24 02:02:29 -04:00
Migrate Display Preferences to EF Core
This commit is contained in:
parent
175e7b45e5
commit
ab396225ea
@ -11,6 +11,7 @@ using System.Xml;
|
|||||||
using Emby.Dlna.Didl;
|
using Emby.Dlna.Didl;
|
||||||
using Emby.Dlna.Service;
|
using Emby.Dlna.Service;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
|
@ -554,8 +554,6 @@ namespace Emby.Server.Implementations
|
|||||||
serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
|
serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
|
||||||
serviceCollection.AddSingleton<IUserDataManager, UserDataManager>();
|
serviceCollection.AddSingleton<IUserDataManager, UserDataManager>();
|
||||||
|
|
||||||
serviceCollection.AddSingleton<IDisplayPreferencesRepository, SqliteDisplayPreferencesRepository>();
|
|
||||||
|
|
||||||
serviceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
|
serviceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
|
||||||
|
|
||||||
serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
|
serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
|
||||||
@ -650,7 +648,6 @@ namespace Emby.Server.Implementations
|
|||||||
_httpServer = Resolve<IHttpServer>();
|
_httpServer = Resolve<IHttpServer>();
|
||||||
_httpClient = Resolve<IHttpClient>();
|
_httpClient = Resolve<IHttpClient>();
|
||||||
|
|
||||||
((SqliteDisplayPreferencesRepository)Resolve<IDisplayPreferencesRepository>()).Initialize();
|
|
||||||
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
|
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
|
||||||
|
|
||||||
SetStaticProperties();
|
SetStaticProperties();
|
||||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Progress;
|
using MediaBrowser.Common.Progress;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
|
@ -1,225 +0,0 @@
|
|||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading;
|
|
||||||
using MediaBrowser.Common.Configuration;
|
|
||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Common.Json;
|
|
||||||
using MediaBrowser.Controller.Persistence;
|
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using SQLitePCL.pretty;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Data
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class SQLiteDisplayPreferencesRepository.
|
|
||||||
/// </summary>
|
|
||||||
public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository
|
|
||||||
{
|
|
||||||
private readonly IFileSystem _fileSystem;
|
|
||||||
|
|
||||||
private readonly JsonSerializerOptions _jsonOptions;
|
|
||||||
|
|
||||||
public SqliteDisplayPreferencesRepository(ILogger<SqliteDisplayPreferencesRepository> logger, IApplicationPaths appPaths, IFileSystem fileSystem)
|
|
||||||
: base(logger)
|
|
||||||
{
|
|
||||||
_fileSystem = fileSystem;
|
|
||||||
|
|
||||||
_jsonOptions = JsonDefaults.GetOptions();
|
|
||||||
|
|
||||||
DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the repository.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The name.</value>
|
|
||||||
public string Name => "SQLite";
|
|
||||||
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
InitializeInternal();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogError(ex, "Error loading database file. Will reset and retry.");
|
|
||||||
|
|
||||||
_fileSystem.DeleteFile(DbFilePath);
|
|
||||||
|
|
||||||
InitializeInternal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Opens the connection to the database.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Task.</returns>
|
|
||||||
private void InitializeInternal()
|
|
||||||
{
|
|
||||||
string[] queries =
|
|
||||||
{
|
|
||||||
"create table if not exists userdisplaypreferences (id GUID NOT NULL, userId GUID NOT NULL, client text NOT NULL, data BLOB NOT NULL)",
|
|
||||||
"create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)"
|
|
||||||
};
|
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
|
||||||
{
|
|
||||||
connection.RunQueries(queries);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Save the display preferences associated with an item in the repo.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="displayPreferences">The display preferences.</param>
|
|
||||||
/// <param name="userId">The user id.</param>
|
|
||||||
/// <param name="client">The client.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <exception cref="ArgumentNullException">item</exception>
|
|
||||||
public void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (displayPreferences == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(displayPreferences));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(displayPreferences.Id))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Display preferences has an invalid Id", nameof(displayPreferences));
|
|
||||||
}
|
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
|
||||||
{
|
|
||||||
connection.RunInTransaction(
|
|
||||||
db => SaveDisplayPreferences(displayPreferences, userId, client, db),
|
|
||||||
TransactionMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, IDatabaseConnection connection)
|
|
||||||
{
|
|
||||||
var serialized = JsonSerializer.SerializeToUtf8Bytes(displayPreferences, _jsonOptions);
|
|
||||||
|
|
||||||
using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)"))
|
|
||||||
{
|
|
||||||
statement.TryBind("@id", new Guid(displayPreferences.Id).ToByteArray());
|
|
||||||
statement.TryBind("@userId", userId.ToByteArray());
|
|
||||||
statement.TryBind("@client", client);
|
|
||||||
statement.TryBind("@data", serialized);
|
|
||||||
|
|
||||||
statement.MoveNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Save all display preferences associated with a user in the repo.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="displayPreferences">The display preferences.</param>
|
|
||||||
/// <param name="userId">The user id.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <exception cref="ArgumentNullException">item</exception>
|
|
||||||
public void SaveAllDisplayPreferences(IEnumerable<DisplayPreferences> displayPreferences, Guid userId, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (displayPreferences == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(displayPreferences));
|
|
||||||
}
|
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
|
||||||
|
|
||||||
using (var connection = GetConnection())
|
|
||||||
{
|
|
||||||
connection.RunInTransaction(
|
|
||||||
db =>
|
|
||||||
{
|
|
||||||
foreach (var displayPreference in displayPreferences)
|
|
||||||
{
|
|
||||||
SaveDisplayPreferences(displayPreference, userId, displayPreference.Client, db);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TransactionMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the display preferences.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="displayPreferencesId">The display preferences id.</param>
|
|
||||||
/// <param name="userId">The user id.</param>
|
|
||||||
/// <param name="client">The client.</param>
|
|
||||||
/// <returns>Task{DisplayPreferences}.</returns>
|
|
||||||
/// <exception cref="ArgumentNullException">item</exception>
|
|
||||||
public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, Guid userId, string client)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(displayPreferencesId))
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(displayPreferencesId));
|
|
||||||
}
|
|
||||||
|
|
||||||
var guidId = displayPreferencesId.GetMD5();
|
|
||||||
|
|
||||||
using (var connection = GetConnection(true))
|
|
||||||
{
|
|
||||||
using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client"))
|
|
||||||
{
|
|
||||||
statement.TryBind("@id", guidId.ToByteArray());
|
|
||||||
statement.TryBind("@userId", userId.ToByteArray());
|
|
||||||
statement.TryBind("@client", client);
|
|
||||||
|
|
||||||
foreach (var row in statement.ExecuteQuery())
|
|
||||||
{
|
|
||||||
return Get(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DisplayPreferences
|
|
||||||
{
|
|
||||||
Id = guidId.ToString("N", CultureInfo.InvariantCulture)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all display preferences for the given user.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userId">The user id.</param>
|
|
||||||
/// <returns>Task{DisplayPreferences}.</returns>
|
|
||||||
/// <exception cref="ArgumentNullException">item</exception>
|
|
||||||
public IEnumerable<DisplayPreferences> GetAllDisplayPreferences(Guid userId)
|
|
||||||
{
|
|
||||||
var list = new List<DisplayPreferences>();
|
|
||||||
|
|
||||||
using (var connection = GetConnection(true))
|
|
||||||
using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId"))
|
|
||||||
{
|
|
||||||
statement.TryBind("@userId", userId.ToByteArray());
|
|
||||||
|
|
||||||
foreach (var row in statement.ExecuteQuery())
|
|
||||||
{
|
|
||||||
list.Add(Get(row));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DisplayPreferences Get(IReadOnlyList<IResultSetValue> row)
|
|
||||||
=> JsonSerializer.Deserialize<DisplayPreferences>(row[0].ToBlob(), _jsonOptions);
|
|
||||||
|
|
||||||
public void SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken)
|
|
||||||
=> SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken);
|
|
||||||
|
|
||||||
public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client)
|
|
||||||
=> GetDisplayPreferences(displayPreferencesId, new Guid(userId), client);
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ using System.Text;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Emby.Server.Implementations.Playlists;
|
using Emby.Server.Implementations.Playlists;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Json;
|
using MediaBrowser.Common.Json;
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'" >true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'">true</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Code Analyzers-->
|
<!-- Code Analyzers-->
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Emby.Server.Implementations.Images;
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Emby.Server.Implementations.Images;
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -50,7 +50,6 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||||
using Genre = MediaBrowser.Controller.Entities.Genre;
|
using Genre = MediaBrowser.Controller.Entities.Genre;
|
||||||
using Person = MediaBrowser.Controller.Entities.Person;
|
using Person = MediaBrowser.Controller.Entities.Person;
|
||||||
using SortOrder = MediaBrowser.Model.Entities.SortOrder;
|
|
||||||
using VideoResolver = Emby.Naming.Video.VideoResolver;
|
using VideoResolver = Emby.Naming.Video.VideoResolver;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.Library
|
namespace Emby.Server.Implementations.Library
|
||||||
|
@ -4,12 +4,12 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Playlists;
|
using MediaBrowser.Controller.Playlists;
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
|
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
|
||||||
|
|
||||||
|
@ -4,12 +4,12 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Extensions;
|
using MediaBrowser.Controller.Extensions;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Search;
|
using MediaBrowser.Model.Search;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -12,6 +12,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Emby.Server.Implementations.Library;
|
using Emby.Server.Implementations.Library;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
|
72
Jellyfin.Data/Entities/DisplayPreferences.cs
Normal file
72
Jellyfin.Data/Entities/DisplayPreferences.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
|
namespace Jellyfin.Data.Entities
|
||||||
|
{
|
||||||
|
public class DisplayPreferences
|
||||||
|
{
|
||||||
|
public DisplayPreferences(string client, Guid userId)
|
||||||
|
{
|
||||||
|
RememberIndexing = false;
|
||||||
|
ShowBackdrop = true;
|
||||||
|
Client = client;
|
||||||
|
UserId = userId;
|
||||||
|
|
||||||
|
HomeSections = new HashSet<HomeSection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DisplayPreferences()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
public int Id { get; protected set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the id of the associated item.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is currently unused. In the future, this will allow us to have users set
|
||||||
|
/// display preferences per item.
|
||||||
|
/// </remarks>
|
||||||
|
public Guid? ItemId { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[MaxLength(64)]
|
||||||
|
[StringLength(64)]
|
||||||
|
public string Client { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool RememberIndexing { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool RememberSorting { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public SortOrder SortOrder { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool ShowSidebar { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool ShowBackdrop { get; set; }
|
||||||
|
|
||||||
|
public string SortBy { get; set; }
|
||||||
|
|
||||||
|
public ViewType? ViewType { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ScrollDirection ScrollDirection { get; set; }
|
||||||
|
|
||||||
|
public IndexingKind? IndexBy { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<HomeSection> HomeSections { get; protected set; }
|
||||||
|
}
|
||||||
|
}
|
21
Jellyfin.Data/Entities/HomeSection.cs
Normal file
21
Jellyfin.Data/Entities/HomeSection.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
|
namespace Jellyfin.Data.Entities
|
||||||
|
{
|
||||||
|
public class HomeSection
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[Required]
|
||||||
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
public int Id { get; protected set; }
|
||||||
|
|
||||||
|
public int DisplayPreferencesId { get; set; }
|
||||||
|
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
public HomeSectionType Type { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -349,6 +349,11 @@ namespace Jellyfin.Data.Entities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual ICollection<AccessSchedule> AccessSchedules { get; protected set; }
|
public virtual ICollection<AccessSchedule> AccessSchedules { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the list of item display preferences.
|
||||||
|
/// </summary>
|
||||||
|
public virtual ICollection<DisplayPreferences> DisplayPreferences { get; protected set; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the list of groups this user is a member of.
|
/// Gets or sets the list of groups this user is a member of.
|
||||||
|
53
Jellyfin.Data/Enums/HomeSectionType.cs
Normal file
53
Jellyfin.Data/Enums/HomeSectionType.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
namespace Jellyfin.Data.Enums
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An enum representing the different options for the home screen sections.
|
||||||
|
/// </summary>
|
||||||
|
public enum HomeSectionType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// My Media.
|
||||||
|
/// </summary>
|
||||||
|
SmallLibraryTiles = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// My Media Small.
|
||||||
|
/// </summary>
|
||||||
|
LibraryButtons = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Active Recordings.
|
||||||
|
/// </summary>
|
||||||
|
ActiveRecordings = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Continue Watching.
|
||||||
|
/// </summary>
|
||||||
|
Resume = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Continue Listening.
|
||||||
|
/// </summary>
|
||||||
|
ResumeAudio = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Latest Media.
|
||||||
|
/// </summary>
|
||||||
|
LatestMedia = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Next Up.
|
||||||
|
/// </summary>
|
||||||
|
NextUp = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Live TV.
|
||||||
|
/// </summary>
|
||||||
|
LiveTv = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// None.
|
||||||
|
/// </summary>
|
||||||
|
None = 8
|
||||||
|
}
|
||||||
|
}
|
20
Jellyfin.Data/Enums/IndexingKind.cs
Normal file
20
Jellyfin.Data/Enums/IndexingKind.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace Jellyfin.Data.Enums
|
||||||
|
{
|
||||||
|
public enum IndexingKind
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Index by the premiere date.
|
||||||
|
/// </summary>
|
||||||
|
PremiereDate,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Index by the production year.
|
||||||
|
/// </summary>
|
||||||
|
ProductionYear,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Index by the community rating.
|
||||||
|
/// </summary>
|
||||||
|
CommunityRating
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,17 @@
|
|||||||
namespace MediaBrowser.Model.Entities
|
namespace Jellyfin.Data.Enums
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enum ScrollDirection.
|
/// An enum representing the axis that should be scrolled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ScrollDirection
|
public enum ScrollDirection
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The horizontal.
|
/// Horizontal scrolling direction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Horizontal,
|
Horizontal,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The vertical.
|
/// Vertical scrolling direction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Vertical
|
Vertical
|
||||||
}
|
}
|
@ -1,17 +1,17 @@
|
|||||||
namespace MediaBrowser.Model.Entities
|
namespace Jellyfin.Data.Enums
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enum SortOrder.
|
/// An enum representing the sorting order.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum SortOrder
|
public enum SortOrder
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ascending.
|
/// Sort in increasing order.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Ascending,
|
Ascending,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The descending.
|
/// Sort in decreasing order.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Descending
|
Descending
|
||||||
}
|
}
|
38
Jellyfin.Data/Enums/ViewType.cs
Normal file
38
Jellyfin.Data/Enums/ViewType.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
namespace Jellyfin.Data.Enums
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An enum representing the type of view for a library or collection.
|
||||||
|
/// </summary>
|
||||||
|
public enum ViewType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shows banners.
|
||||||
|
/// </summary>
|
||||||
|
Banner = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows a list of content.
|
||||||
|
/// </summary>
|
||||||
|
List = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows poster artwork.
|
||||||
|
/// </summary>
|
||||||
|
Poster = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows poster artwork with a card containing the name and year.
|
||||||
|
/// </summary>
|
||||||
|
PosterCard = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows a thumbnail.
|
||||||
|
/// </summary>
|
||||||
|
Thumb = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows a thumbnail with a card containing the name and year.
|
||||||
|
/// </summary>
|
||||||
|
ThumbCard = 5
|
||||||
|
}
|
||||||
|
}
|
49
Jellyfin.Server.Implementations/DisplayPreferencesManager.cs
Normal file
49
Jellyfin.Server.Implementations/DisplayPreferencesManager.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Jellyfin.Data.Entities;
|
||||||
|
using MediaBrowser.Controller;
|
||||||
|
|
||||||
|
namespace Jellyfin.Server.Implementations
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manages the storage and retrieval of display preferences through Entity Framework.
|
||||||
|
/// </summary>
|
||||||
|
public class DisplayPreferencesManager : IDisplayPreferencesManager
|
||||||
|
{
|
||||||
|
private readonly JellyfinDbProvider _dbProvider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DisplayPreferencesManager"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dbProvider">The Jellyfin db provider.</param>
|
||||||
|
public DisplayPreferencesManager(JellyfinDbProvider dbProvider)
|
||||||
|
{
|
||||||
|
_dbProvider = dbProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public DisplayPreferences GetDisplayPreferences(Guid userId, string client)
|
||||||
|
{
|
||||||
|
var dbContext = _dbProvider.CreateContext();
|
||||||
|
var user = dbContext.Users.Find(userId);
|
||||||
|
#pragma warning disable CA1307
|
||||||
|
var prefs = user.DisplayPreferences.FirstOrDefault(pref => string.Equals(pref.Client, client));
|
||||||
|
|
||||||
|
if (prefs == null)
|
||||||
|
{
|
||||||
|
prefs = new DisplayPreferences(client, userId);
|
||||||
|
user.DisplayPreferences.Add(prefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void SaveChanges(DisplayPreferences preferences)
|
||||||
|
{
|
||||||
|
var dbContext = _dbProvider.CreateContext();
|
||||||
|
dbContext.Update(preferences);
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,8 @@ namespace Jellyfin.Server.Implementations
|
|||||||
|
|
||||||
public virtual DbSet<ActivityLog> ActivityLogs { get; set; }
|
public virtual DbSet<ActivityLog> ActivityLogs { get; set; }
|
||||||
|
|
||||||
|
public virtual DbSet<DisplayPreferences> DisplayPreferences { get; set; }
|
||||||
|
|
||||||
public virtual DbSet<ImageInfo> ImageInfos { get; set; }
|
public virtual DbSet<ImageInfo> ImageInfos { get; set; }
|
||||||
|
|
||||||
public virtual DbSet<Permission> Permissions { get; set; }
|
public virtual DbSet<Permission> Permissions { get; set; }
|
||||||
|
403
Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs
generated
Normal file
403
Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs
generated
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
#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("20200630170339_AddDisplayPreferences")]
|
||||||
|
partial class AddDisplayPreferences
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasDefaultSchema("jellyfin")
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.5");
|
||||||
|
|
||||||
|
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")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.Property<int>("LogSeverity")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(512);
|
||||||
|
|
||||||
|
b.Property<string>("Overview")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(512);
|
||||||
|
|
||||||
|
b.Property<uint>("RowVersion")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ShortOverview")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(512);
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ActivityLogs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Client")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(64);
|
||||||
|
|
||||||
|
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<int>("ScrollDirection")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ShowBackdrop")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ShowSidebar")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("SortBy")
|
||||||
|
.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("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()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(512);
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("ImageInfos");
|
||||||
|
});
|
||||||
|
|
||||||
|
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()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(65535);
|
||||||
|
|
||||||
|
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")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(255);
|
||||||
|
|
||||||
|
b.Property<string>("AuthenticationProviderId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(255);
|
||||||
|
|
||||||
|
b.Property<bool>("DisplayCollectionsView")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("DisplayMissingEpisodes")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("EasyPassword")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(65535);
|
||||||
|
|
||||||
|
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?>("MaxParentalAgeRating")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("MustUpdatePassword")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(65535);
|
||||||
|
|
||||||
|
b.Property<string>("PasswordResetProviderId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(255);
|
||||||
|
|
||||||
|
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")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(255);
|
||||||
|
|
||||||
|
b.Property<int>("SubtitleMode")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SyncPlayAccess")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(255);
|
||||||
|
|
||||||
|
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)
|
||||||
|
.WithMany("DisplayPreferences")
|
||||||
|
.HasForeignKey("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.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");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
#pragma warning disable CS1591
|
||||||
|
#pragma warning disable SA1601
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Jellyfin.Server.Implementations.Migrations
|
||||||
|
{
|
||||||
|
public partial class AddDisplayPreferences : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "DisplayPreferences",
|
||||||
|
schema: "jellyfin",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
UserId = table.Column<Guid>(nullable: false),
|
||||||
|
ItemId = table.Column<Guid>(nullable: true),
|
||||||
|
Client = table.Column<string>(maxLength: 64, nullable: false),
|
||||||
|
RememberIndexing = table.Column<bool>(nullable: false),
|
||||||
|
RememberSorting = table.Column<bool>(nullable: false),
|
||||||
|
SortOrder = table.Column<int>(nullable: false),
|
||||||
|
ShowSidebar = table.Column<bool>(nullable: false),
|
||||||
|
ShowBackdrop = table.Column<bool>(nullable: false),
|
||||||
|
SortBy = table.Column<string>(nullable: true),
|
||||||
|
ViewType = table.Column<int>(nullable: true),
|
||||||
|
ScrollDirection = table.Column<int>(nullable: false),
|
||||||
|
IndexBy = table.Column<int>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_DisplayPreferences", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_DisplayPreferences_Users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalSchema: "jellyfin",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "HomeSection",
|
||||||
|
schema: "jellyfin",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
DisplayPreferencesId = table.Column<int>(nullable: false),
|
||||||
|
Order = table.Column<int>(nullable: false),
|
||||||
|
Type = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_HomeSection", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId",
|
||||||
|
column: x => x.DisplayPreferencesId,
|
||||||
|
principalSchema: "jellyfin",
|
||||||
|
principalTable: "DisplayPreferences",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_DisplayPreferences_UserId",
|
||||||
|
schema: "jellyfin",
|
||||||
|
table: "DisplayPreferences",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_HomeSection_DisplayPreferencesId",
|
||||||
|
schema: "jellyfin",
|
||||||
|
table: "HomeSection",
|
||||||
|
column: "DisplayPreferencesId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "HomeSection",
|
||||||
|
schema: "jellyfin");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "DisplayPreferences",
|
||||||
|
schema: "jellyfin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasDefaultSchema("jellyfin")
|
.HasDefaultSchema("jellyfin")
|
||||||
.HasAnnotation("ProductVersion", "3.1.4");
|
.HasAnnotation("ProductVersion", "3.1.5");
|
||||||
|
|
||||||
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
|
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
|
||||||
{
|
{
|
||||||
@ -88,6 +88,79 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||||||
b.ToTable("ActivityLogs");
|
b.ToTable("ActivityLogs");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Client")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(64);
|
||||||
|
|
||||||
|
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<int>("ScrollDirection")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ShowBackdrop")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("ShowSidebar")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("SortBy")
|
||||||
|
.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("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 =>
|
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@ -282,6 +355,24 @@ namespace Jellyfin.Server.Implementations.Migrations
|
|||||||
.IsRequired();
|
.IsRequired();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||||
|
.WithMany("DisplayPreferences")
|
||||||
|
.HasForeignKey("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 =>
|
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Jellyfin.Data.Entities.User", null)
|
b.HasOne("Jellyfin.Data.Entities.User", null)
|
||||||
|
@ -9,6 +9,7 @@ using Jellyfin.Server.Implementations;
|
|||||||
using Jellyfin.Server.Implementations.Activity;
|
using Jellyfin.Server.Implementations.Activity;
|
||||||
using Jellyfin.Server.Implementations.Users;
|
using Jellyfin.Server.Implementations.Users;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Activity;
|
using MediaBrowser.Model.Activity;
|
||||||
@ -73,6 +74,7 @@ namespace Jellyfin.Server
|
|||||||
|
|
||||||
serviceCollection.AddSingleton<IActivityManager, ActivityManager>();
|
serviceCollection.AddSingleton<IActivityManager, ActivityManager>();
|
||||||
serviceCollection.AddSingleton<IUserManager, UserManager>();
|
serviceCollection.AddSingleton<IUserManager, UserManager>();
|
||||||
|
serviceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>();
|
||||||
|
|
||||||
base.RegisterServices(serviceCollection);
|
base.RegisterServices(serviceCollection);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,8 @@ namespace Jellyfin.Server.Migrations
|
|||||||
typeof(Routines.MigrateActivityLogDb),
|
typeof(Routines.MigrateActivityLogDb),
|
||||||
typeof(Routines.RemoveDuplicateExtras),
|
typeof(Routines.RemoveDuplicateExtras),
|
||||||
typeof(Routines.AddDefaultPluginRepository),
|
typeof(Routines.AddDefaultPluginRepository),
|
||||||
typeof(Routines.MigrateUserDb)
|
typeof(Routines.MigrateUserDb),
|
||||||
|
typeof(Routines.MigrateDisplayPreferencesDb)
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -0,0 +1,118 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
using Jellyfin.Server.Implementations;
|
||||||
|
using MediaBrowser.Controller;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using SQLitePCL.pretty;
|
||||||
|
|
||||||
|
namespace Jellyfin.Server.Migrations.Routines
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The migration routine for migrating the display preferences database to EF Core.
|
||||||
|
/// </summary>
|
||||||
|
public class MigrateDisplayPreferencesDb : IMigrationRoutine
|
||||||
|
{
|
||||||
|
private const string DbFilename = "displaypreferences.db";
|
||||||
|
|
||||||
|
private readonly ILogger<MigrateDisplayPreferencesDb> _logger;
|
||||||
|
private readonly IServerApplicationPaths _paths;
|
||||||
|
private readonly JellyfinDbProvider _provider;
|
||||||
|
private readonly JsonSerializerOptions _jsonOptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MigrateDisplayPreferencesDb"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger">The logger.</param>
|
||||||
|
/// <param name="paths">The server application paths.</param>
|
||||||
|
/// <param name="provider">The database provider.</param>
|
||||||
|
public MigrateDisplayPreferencesDb(ILogger<MigrateDisplayPreferencesDb> logger, IServerApplicationPaths paths, JellyfinDbProvider provider)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_paths = paths;
|
||||||
|
_provider = provider;
|
||||||
|
_jsonOptions = new JsonSerializerOptions();
|
||||||
|
_jsonOptions.Converters.Add(new JsonStringEnumConverter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Guid Id => Guid.Parse("06387815-C3CC-421F-A888-FB5F9992BEA8");
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "MigrateDisplayPreferencesDatabase";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Perform()
|
||||||
|
{
|
||||||
|
HomeSectionType[] defaults =
|
||||||
|
{
|
||||||
|
HomeSectionType.SmallLibraryTiles,
|
||||||
|
HomeSectionType.Resume,
|
||||||
|
HomeSectionType.ResumeAudio,
|
||||||
|
HomeSectionType.LiveTv,
|
||||||
|
HomeSectionType.NextUp,
|
||||||
|
HomeSectionType.LatestMedia,
|
||||||
|
HomeSectionType.None,
|
||||||
|
};
|
||||||
|
|
||||||
|
var dbFilePath = Path.Combine(_paths.DataPath, DbFilename);
|
||||||
|
using (var connection = SQLite3.Open(dbFilePath, ConnectionFlags.ReadOnly, null))
|
||||||
|
{
|
||||||
|
var dbContext = _provider.CreateContext();
|
||||||
|
|
||||||
|
var results = connection.Query("SELECT * FROM userdisplaypreferences");
|
||||||
|
foreach (var result in results)
|
||||||
|
{
|
||||||
|
var dto = JsonSerializer.Deserialize<DisplayPreferencesDto>(result[3].ToString(), _jsonOptions);
|
||||||
|
|
||||||
|
var displayPreferences = new DisplayPreferences(result[2].ToString(), new Guid(result[1].ToBlob()))
|
||||||
|
{
|
||||||
|
ViewType = Enum.TryParse<ViewType>(dto.ViewType, true, out var viewType) ? viewType : (ViewType?)null,
|
||||||
|
IndexBy = Enum.TryParse<IndexingKind>(dto.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null,
|
||||||
|
ShowBackdrop = dto.ShowBackdrop,
|
||||||
|
ShowSidebar = dto.ShowSidebar,
|
||||||
|
SortBy = dto.SortBy,
|
||||||
|
SortOrder = dto.SortOrder,
|
||||||
|
RememberIndexing = dto.RememberIndexing,
|
||||||
|
RememberSorting = dto.RememberSorting,
|
||||||
|
ScrollDirection = dto.ScrollDirection
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
dto.CustomPrefs.TryGetValue("homesection" + i, out var homeSection);
|
||||||
|
|
||||||
|
displayPreferences.HomeSections.Add(new HomeSection
|
||||||
|
{
|
||||||
|
Order = i,
|
||||||
|
Type = Enum.TryParse<HomeSectionType>(homeSection, true, out var type) ? type : defaults[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dbContext.Add(displayPreferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Move(dbFilePath, dbFilePath + ".old");
|
||||||
|
|
||||||
|
var journalPath = dbFilePath + "-journal";
|
||||||
|
if (File.Exists(journalPath))
|
||||||
|
{
|
||||||
|
File.Move(journalPath, dbFilePath + ".old-journal");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Error renaming legacy display preferences database to 'displaypreferences.db.old'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Api.UserLibrary;
|
using MediaBrowser.Api.UserLibrary;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
@ -11,7 +12,6 @@ using MediaBrowser.Controller.Library;
|
|||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.Channels;
|
using MediaBrowser.Model.Channels;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Services;
|
using MediaBrowser.Model.Services;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
using System.Threading;
|
using System;
|
||||||
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Controller.Persistence;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Serialization;
|
|
||||||
using MediaBrowser.Model.Services;
|
using MediaBrowser.Model.Services;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ namespace MediaBrowser.Api
|
|||||||
/// Class UpdateDisplayPreferences.
|
/// Class UpdateDisplayPreferences.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/DisplayPreferences/{DisplayPreferencesId}", "POST", Summary = "Updates a user's display preferences for an item")]
|
[Route("/DisplayPreferences/{DisplayPreferencesId}", "POST", Summary = "Updates a user's display preferences for an item")]
|
||||||
public class UpdateDisplayPreferences : DisplayPreferences, IReturnVoid
|
public class UpdateDisplayPreferences : DisplayPreferencesDto, IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
@ -27,7 +28,7 @@ namespace MediaBrowser.Api
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Route("/DisplayPreferences/{Id}", "GET", Summary = "Gets a user's display preferences for an item")]
|
[Route("/DisplayPreferences/{Id}", "GET", Summary = "Gets a user's display preferences for an item")]
|
||||||
public class GetDisplayPreferences : IReturn<DisplayPreferences>
|
public class GetDisplayPreferences : IReturn<DisplayPreferencesDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
@ -50,28 +51,21 @@ namespace MediaBrowser.Api
|
|||||||
public class DisplayPreferencesService : BaseApiService
|
public class DisplayPreferencesService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _display preferences manager.
|
/// The user manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IDisplayPreferencesRepository _displayPreferencesManager;
|
private readonly IDisplayPreferencesManager _displayPreferencesManager;
|
||||||
/// <summary>
|
|
||||||
/// The _json serializer.
|
|
||||||
/// </summary>
|
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="DisplayPreferencesService" /> class.
|
/// Initializes a new instance of the <see cref="DisplayPreferencesService" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="jsonSerializer">The json serializer.</param>
|
|
||||||
/// <param name="displayPreferencesManager">The display preferences manager.</param>
|
/// <param name="displayPreferencesManager">The display preferences manager.</param>
|
||||||
public DisplayPreferencesService(
|
public DisplayPreferencesService(
|
||||||
ILogger<DisplayPreferencesService> logger,
|
ILogger<DisplayPreferencesService> logger,
|
||||||
IServerConfigurationManager serverConfigurationManager,
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
IHttpResultFactory httpResultFactory,
|
IHttpResultFactory httpResultFactory,
|
||||||
IJsonSerializer jsonSerializer,
|
IDisplayPreferencesManager displayPreferencesManager)
|
||||||
IDisplayPreferencesRepository displayPreferencesManager)
|
|
||||||
: base(logger, serverConfigurationManager, httpResultFactory)
|
: base(logger, serverConfigurationManager, httpResultFactory)
|
||||||
{
|
{
|
||||||
_jsonSerializer = jsonSerializer;
|
|
||||||
_displayPreferencesManager = displayPreferencesManager;
|
_displayPreferencesManager = displayPreferencesManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,9 +75,34 @@ namespace MediaBrowser.Api
|
|||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
public object Get(GetDisplayPreferences request)
|
public object Get(GetDisplayPreferences request)
|
||||||
{
|
{
|
||||||
var result = _displayPreferencesManager.GetDisplayPreferences(request.Id, request.UserId, request.Client);
|
var result = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client);
|
||||||
|
|
||||||
return ToOptimizedResult(result);
|
if (result == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dto = new DisplayPreferencesDto
|
||||||
|
{
|
||||||
|
Client = result.Client,
|
||||||
|
Id = result.UserId.ToString(),
|
||||||
|
ViewType = result.ViewType?.ToString(),
|
||||||
|
SortBy = result.SortBy,
|
||||||
|
SortOrder = result.SortOrder,
|
||||||
|
IndexBy = result.IndexBy?.ToString(),
|
||||||
|
RememberIndexing = result.RememberIndexing,
|
||||||
|
RememberSorting = result.RememberSorting,
|
||||||
|
ScrollDirection = result.ScrollDirection,
|
||||||
|
ShowBackdrop = result.ShowBackdrop,
|
||||||
|
ShowSidebar = result.ShowSidebar
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var homeSection in result.HomeSections)
|
||||||
|
{
|
||||||
|
dto.CustomPrefs["homesection" + homeSection.Order] = homeSection.Type.ToString().ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToOptimizedResult(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -92,10 +111,43 @@ namespace MediaBrowser.Api
|
|||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
public void Post(UpdateDisplayPreferences request)
|
public void Post(UpdateDisplayPreferences request)
|
||||||
{
|
{
|
||||||
// Serialize to json and then back so that the core doesn't see the request dto type
|
HomeSectionType[] defaults =
|
||||||
var displayPreferences = _jsonSerializer.DeserializeFromString<DisplayPreferences>(_jsonSerializer.SerializeToString(request));
|
{
|
||||||
|
HomeSectionType.SmallLibraryTiles,
|
||||||
|
HomeSectionType.Resume,
|
||||||
|
HomeSectionType.ResumeAudio,
|
||||||
|
HomeSectionType.LiveTv,
|
||||||
|
HomeSectionType.NextUp,
|
||||||
|
HomeSectionType.LatestMedia,
|
||||||
|
HomeSectionType.None,
|
||||||
|
};
|
||||||
|
|
||||||
_displayPreferencesManager.SaveDisplayPreferences(displayPreferences, request.UserId, request.Client, CancellationToken.None);
|
var prefs = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client);
|
||||||
|
|
||||||
|
prefs.ViewType = Enum.TryParse<ViewType>(request.ViewType, true, out var viewType) ? viewType : (ViewType?)null;
|
||||||
|
prefs.IndexBy = Enum.TryParse<IndexingKind>(request.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null;
|
||||||
|
prefs.ShowBackdrop = request.ShowBackdrop;
|
||||||
|
prefs.ShowSidebar = request.ShowSidebar;
|
||||||
|
prefs.SortBy = request.SortBy;
|
||||||
|
prefs.SortOrder = request.SortOrder;
|
||||||
|
prefs.RememberIndexing = request.RememberIndexing;
|
||||||
|
prefs.RememberSorting = request.RememberSorting;
|
||||||
|
prefs.ScrollDirection = request.ScrollDirection;
|
||||||
|
prefs.HomeSections.Clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
if (request.CustomPrefs.TryGetValue("homesection" + i, out var homeSection))
|
||||||
|
{
|
||||||
|
prefs.HomeSections.Add(new HomeSection
|
||||||
|
{
|
||||||
|
Order = i,
|
||||||
|
Type = Enum.TryParse<HomeSectionType>(homeSection, true, out var type) ? type : defaults[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_displayPreferencesManager.SaveChanges(prefs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Services;
|
using MediaBrowser.Model.Services;
|
||||||
@ -466,8 +467,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
var sortOrderValue = sortOrders.Length > sortOrderIndex ? sortOrders[sortOrderIndex] : null;
|
var sortOrderValue = sortOrders.Length > sortOrderIndex ? sortOrders[sortOrderIndex] : null;
|
||||||
var sortOrder = string.Equals(sortOrderValue, "Descending", StringComparison.OrdinalIgnoreCase)
|
var sortOrder = string.Equals(sortOrderValue, "Descending", StringComparison.OrdinalIgnoreCase)
|
||||||
? MediaBrowser.Model.Entities.SortOrder.Descending
|
? Jellyfin.Data.Enums.SortOrder.Descending
|
||||||
: MediaBrowser.Model.Entities.SortOrder.Ascending;
|
: Jellyfin.Data.Enums.SortOrder.Ascending;
|
||||||
|
|
||||||
result[i] = new ValueTuple<string, SortOrder>(vals[i], sortOrder);
|
result[i] = new ValueTuple<string, SortOrder>(vals[i], sortOrder);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
25
MediaBrowser.Controller/IDisplayPreferencesManager.cs
Normal file
25
MediaBrowser.Controller/IDisplayPreferencesManager.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using Jellyfin.Data.Entities;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manages the storage and retrieval of display preferences.
|
||||||
|
/// </summary>
|
||||||
|
public interface IDisplayPreferencesManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display preferences for the user and client.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The user's id.</param>
|
||||||
|
/// <param name="client">The client string.</param>
|
||||||
|
/// <returns>The associated display preferences.</returns>
|
||||||
|
DisplayPreferences GetDisplayPreferences(Guid userId, string client);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves changes to the provided display preferences.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="preferences">The display preferences to save.</param>
|
||||||
|
void SaveChanges(DisplayPreferences preferences);
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Persistence
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interface IDisplayPreferencesRepository.
|
|
||||||
/// </summary>
|
|
||||||
public interface IDisplayPreferencesRepository : IRepository
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Saves display preferences for an item.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="displayPreferences">The display preferences.</param>
|
|
||||||
/// <param name="userId">The user id.</param>
|
|
||||||
/// <param name="client">The client.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
void SaveDisplayPreferences(
|
|
||||||
DisplayPreferences displayPreferences,
|
|
||||||
string userId,
|
|
||||||
string client,
|
|
||||||
CancellationToken cancellationToken);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Saves all display preferences for a user.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="displayPreferences">The display preferences.</param>
|
|
||||||
/// <param name="userId">The user id.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
void SaveAllDisplayPreferences(
|
|
||||||
IEnumerable<DisplayPreferences> displayPreferences,
|
|
||||||
Guid userId,
|
|
||||||
CancellationToken cancellationToken);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the display preferences.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="displayPreferencesId">The display preferences id.</param>
|
|
||||||
/// <param name="userId">The user id.</param>
|
|
||||||
/// <param name="client">The client.</param>
|
|
||||||
/// <returns>Task{DisplayPreferences}.</returns>
|
|
||||||
DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all display preferences for the given user.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userId">The user id.</param>
|
|
||||||
/// <returns>Task{DisplayPreferences}.</returns>
|
|
||||||
IEnumerable<DisplayPreferences> GetAllDisplayPreferences(Guid userId);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ using System.Text.Json.Serialization;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using MediaBrowser.Model.Entities;
|
using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Entities
|
namespace MediaBrowser.Model.Entities
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the display preferences for any item that supports them (usually Folders).
|
/// Defines the display preferences for any item that supports them (usually Folders).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DisplayPreferences
|
public class DisplayPreferencesDto
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The image scale.
|
/// Initializes a new instance of the <see cref="DisplayPreferencesDto" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const double ImageScale = .9;
|
public DisplayPreferencesDto()
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="DisplayPreferences" /> class.
|
|
||||||
/// </summary>
|
|
||||||
public DisplayPreferences()
|
|
||||||
{
|
{
|
||||||
RememberIndexing = false;
|
RememberIndexing = false;
|
||||||
PrimaryImageHeight = 250;
|
PrimaryImageHeight = 250;
|
@ -2,7 +2,7 @@
|
|||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using MediaBrowser.Model.Entities;
|
using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.LiveTv
|
namespace MediaBrowser.Model.LiveTv
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using MediaBrowser.Model.Entities;
|
using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.LiveTv
|
namespace MediaBrowser.Model.LiveTv
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user