mirror of https://github.com/jellyfin/jellyfin.git
Merge branch 'master' into userdb-efcore
# Conflicts: # Emby.Server.Implementations/Data/SqliteUserDataRepository.cs # Emby.Server.Implementations/Library/UserManager.cs # Jellyfin.Data/Entities/User.cs # Jellyfin.Data/ISavingChanges.cs # Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj # Jellyfin.Server.Implementations/JellyfinDb.cs # Jellyfin.Server/Migrations/MigrationRunner.cs # MediaBrowser.Model/Notifications/NotificationOptions.cs # MediaBrowser.sln
This commit is contained in:
commit
c1360a1dc3
|
@ -13,7 +13,7 @@ charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
max_line_length = null
|
max_line_length = off
|
||||||
|
|
||||||
# YAML indentation
|
# YAML indentation
|
||||||
[*.{yml,yaml}]
|
[*.{yml,yaml}]
|
||||||
|
@ -22,6 +22,7 @@ indent_size = 2
|
||||||
# XML indentation
|
# XML indentation
|
||||||
[*.{csproj,xml}]
|
[*.{csproj,xml}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
# .NET Coding Conventions #
|
# .NET Coding Conventions #
|
||||||
###############################
|
###############################
|
||||||
|
@ -51,11 +52,12 @@ dotnet_style_explicit_tuple_names = true:suggestion
|
||||||
dotnet_style_null_propagation = true:suggestion
|
dotnet_style_null_propagation = true:suggestion
|
||||||
dotnet_style_coalesce_expression = true:suggestion
|
dotnet_style_coalesce_expression = true:suggestion
|
||||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
|
||||||
dotnet_prefer_inferred_tuple_names = true:suggestion
|
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||||
dotnet_prefer_inferred_anonymous_type_member_names = true:suggestion
|
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||||
dotnet_style_prefer_auto_properties = true:silent
|
dotnet_style_prefer_auto_properties = true:silent
|
||||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
# Naming Conventions #
|
# Naming Conventions #
|
||||||
###############################
|
###############################
|
||||||
|
@ -67,7 +69,7 @@ dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non
|
||||||
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
|
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
|
||||||
|
|
||||||
dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
|
dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
|
||||||
dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected internal, private protected
|
dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
|
||||||
dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
|
dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
|
||||||
|
|
||||||
dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
|
dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
|
||||||
|
@ -159,6 +161,7 @@ csharp_style_deconstructed_variable_declaration = true:suggestion
|
||||||
csharp_prefer_simple_default_expression = true:suggestion
|
csharp_prefer_simple_default_expression = true:suggestion
|
||||||
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
||||||
csharp_style_inlined_variable_declaration = true:suggestion
|
csharp_style_inlined_variable_declaration = true:suggestion
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
# C# Formatting Rules #
|
# C# Formatting Rules #
|
||||||
###############################
|
###############################
|
||||||
|
@ -189,9 +192,3 @@ csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||||
# Wrapping preferences
|
# Wrapping preferences
|
||||||
csharp_preserve_single_line_statements = true
|
csharp_preserve_single_line_statements = true
|
||||||
csharp_preserve_single_line_blocks = true
|
csharp_preserve_single_line_blocks = true
|
||||||
###############################
|
|
||||||
# VB Coding Conventions #
|
|
||||||
###############################
|
|
||||||
[*.vb]
|
|
||||||
# Modifier preferences
|
|
||||||
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
{
|
{
|
||||||
public class Chapter
|
public class Chapter
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace DvdLib.Ifo
|
namespace DvdLib.Ifo
|
||||||
|
|
|
@ -89,14 +89,14 @@ namespace Emby.Naming.Video
|
||||||
if (parseName)
|
if (parseName)
|
||||||
{
|
{
|
||||||
var cleanDateTimeResult = CleanDateTime(name);
|
var cleanDateTimeResult = CleanDateTime(name);
|
||||||
|
name = cleanDateTimeResult.Name;
|
||||||
|
year = cleanDateTimeResult.Year;
|
||||||
|
|
||||||
if (extraResult.ExtraType == null
|
if (extraResult.ExtraType == null
|
||||||
&& TryCleanString(cleanDateTimeResult.Name, out ReadOnlySpan<char> newName))
|
&& TryCleanString(name, out ReadOnlySpan<char> newName))
|
||||||
{
|
{
|
||||||
name = newName.ToString();
|
name = newName.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
year = cleanDateTimeResult.Year;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new VideoFileInfo
|
return new VideoFileInfo
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Emby.Server.Implementations.HttpServer;
|
using Emby.Server.Implementations.HttpServer;
|
||||||
using Emby.Server.Implementations.Updates;
|
using Emby.Server.Implementations.Updates;
|
||||||
using MediaBrowser.Providers.Music;
|
|
||||||
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
|
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations
|
namespace Emby.Server.Implementations
|
||||||
|
|
|
@ -0,0 +1,389 @@
|
||||||
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using SQLitePCL.pretty;
|
||||||
|
|
||||||
|
namespace Emby.Server.Implementations.Data
|
||||||
|
{
|
||||||
|
public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
|
||||||
|
{
|
||||||
|
public SqliteUserDataRepository(
|
||||||
|
ILogger<SqliteUserDataRepository> logger,
|
||||||
|
IApplicationPaths appPaths)
|
||||||
|
: base(logger)
|
||||||
|
{
|
||||||
|
DbFilePath = Path.Combine(appPaths.DataPath, "library.db");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "SQLite";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the connection to the database.
|
||||||
|
/// </summary>
|
||||||
|
public void Initialize(IUserManager userManager, SemaphoreSlim dbLock, SQLiteDatabaseConnection dbConnection)
|
||||||
|
{
|
||||||
|
WriteLock.Dispose();
|
||||||
|
WriteLock = dbLock;
|
||||||
|
WriteConnection?.Dispose();
|
||||||
|
WriteConnection = dbConnection;
|
||||||
|
|
||||||
|
using (var connection = GetConnection())
|
||||||
|
{
|
||||||
|
var userDatasTableExists = TableExists(connection, "UserDatas");
|
||||||
|
var userDataTableExists = TableExists(connection, "userdata");
|
||||||
|
|
||||||
|
var users = userDatasTableExists ? null : userManager.Users;
|
||||||
|
|
||||||
|
connection.RunInTransaction(db =>
|
||||||
|
{
|
||||||
|
db.ExecuteAll(string.Join(";", new[] {
|
||||||
|
|
||||||
|
"create table if not exists UserDatas (key nvarchar not null, userId INT not null, rating float null, played bit not null, playCount int not null, isFavorite bit not null, playbackPositionTicks bigint not null, lastPlayedDate datetime null, AudioStreamIndex INT, SubtitleStreamIndex INT)",
|
||||||
|
|
||||||
|
"drop index if exists idx_userdata",
|
||||||
|
"drop index if exists idx_userdata1",
|
||||||
|
"drop index if exists idx_userdata2",
|
||||||
|
"drop index if exists userdataindex1",
|
||||||
|
"drop index if exists userdataindex",
|
||||||
|
"drop index if exists userdataindex3",
|
||||||
|
"drop index if exists userdataindex4",
|
||||||
|
"create unique index if not exists UserDatasIndex1 on UserDatas (key, userId)",
|
||||||
|
"create index if not exists UserDatasIndex2 on UserDatas (key, userId, played)",
|
||||||
|
"create index if not exists UserDatasIndex3 on UserDatas (key, userId, playbackPositionTicks)",
|
||||||
|
"create index if not exists UserDatasIndex4 on UserDatas (key, userId, isFavorite)"
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (userDataTableExists)
|
||||||
|
{
|
||||||
|
var existingColumnNames = GetColumnNames(db, "userdata");
|
||||||
|
|
||||||
|
AddColumn(db, "userdata", "InternalUserId", "int", existingColumnNames);
|
||||||
|
AddColumn(db, "userdata", "AudioStreamIndex", "int", existingColumnNames);
|
||||||
|
AddColumn(db, "userdata", "SubtitleStreamIndex", "int", existingColumnNames);
|
||||||
|
|
||||||
|
if (!userDatasTableExists)
|
||||||
|
{
|
||||||
|
ImportUserIds(db, users);
|
||||||
|
|
||||||
|
db.ExecuteAll("INSERT INTO UserDatas (key, userId, rating, played, playCount, isFavorite, playbackPositionTicks, lastPlayedDate, AudioStreamIndex, SubtitleStreamIndex) SELECT key, InternalUserId, rating, played, playCount, isFavorite, playbackPositionTicks, lastPlayedDate, AudioStreamIndex, SubtitleStreamIndex from userdata where InternalUserId not null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, TransactionMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ImportUserIds(IDatabaseConnection db, IEnumerable<User> users)
|
||||||
|
{
|
||||||
|
var userIdsWithUserData = GetAllUserIdsWithUserData(db);
|
||||||
|
|
||||||
|
using (var statement = db.PrepareStatement("update userdata set InternalUserId=@InternalUserId where UserId=@UserId"))
|
||||||
|
{
|
||||||
|
foreach (var user in users)
|
||||||
|
{
|
||||||
|
if (!userIdsWithUserData.Contains(user.Id))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
statement.TryBind("@UserId", user.Id.ToByteArray());
|
||||||
|
statement.TryBind("@InternalUserId", user.InternalId);
|
||||||
|
|
||||||
|
statement.MoveNext();
|
||||||
|
statement.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Guid> GetAllUserIdsWithUserData(IDatabaseConnection db)
|
||||||
|
{
|
||||||
|
var list = new List<Guid>();
|
||||||
|
|
||||||
|
using (var statement = PrepareStatement(db, "select DISTINCT UserId from UserData where UserId not null"))
|
||||||
|
{
|
||||||
|
foreach (var row in statement.ExecuteQuery())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
list.Add(row[0].ReadGuidFromBlob());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError(ex, "Error while getting user");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the user data.
|
||||||
|
/// </summary>
|
||||||
|
public void SaveUserData(long internalUserId, string key, UserItemData userData, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (userData == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(userData));
|
||||||
|
}
|
||||||
|
if (internalUserId <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(internalUserId));
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(key))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistUserData(internalUserId, key, userData, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveAllUserData(long internalUserId, UserItemData[] userData, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (userData == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(userData));
|
||||||
|
}
|
||||||
|
if (internalUserId <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(internalUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistAllUserData(internalUserId, userData, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Persists the user data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="internalUserId">The user id.</param>
|
||||||
|
/// <param name="key">The key.</param>
|
||||||
|
/// <param name="userData">The user data.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
public void PersistUserData(long internalUserId, string key, UserItemData userData, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
using (var connection = GetConnection())
|
||||||
|
{
|
||||||
|
connection.RunInTransaction(db =>
|
||||||
|
{
|
||||||
|
SaveUserData(db, internalUserId, key, userData);
|
||||||
|
}, TransactionMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SaveUserData(IDatabaseConnection db, long internalUserId, string key, UserItemData userData)
|
||||||
|
{
|
||||||
|
using (var statement = db.PrepareStatement("replace into UserDatas (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"))
|
||||||
|
{
|
||||||
|
statement.TryBind("@userId", internalUserId);
|
||||||
|
statement.TryBind("@key", key);
|
||||||
|
|
||||||
|
if (userData.Rating.HasValue)
|
||||||
|
{
|
||||||
|
statement.TryBind("@rating", userData.Rating.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statement.TryBindNull("@rating");
|
||||||
|
}
|
||||||
|
|
||||||
|
statement.TryBind("@played", userData.Played);
|
||||||
|
statement.TryBind("@playCount", userData.PlayCount);
|
||||||
|
statement.TryBind("@isFavorite", userData.IsFavorite);
|
||||||
|
statement.TryBind("@playbackPositionTicks", userData.PlaybackPositionTicks);
|
||||||
|
|
||||||
|
if (userData.LastPlayedDate.HasValue)
|
||||||
|
{
|
||||||
|
statement.TryBind("@lastPlayedDate", userData.LastPlayedDate.Value.ToDateTimeParamValue());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statement.TryBindNull("@lastPlayedDate");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userData.AudioStreamIndex.HasValue)
|
||||||
|
{
|
||||||
|
statement.TryBind("@AudioStreamIndex", userData.AudioStreamIndex.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statement.TryBindNull("@AudioStreamIndex");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userData.SubtitleStreamIndex.HasValue)
|
||||||
|
{
|
||||||
|
statement.TryBind("@SubtitleStreamIndex", userData.SubtitleStreamIndex.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statement.TryBindNull("@SubtitleStreamIndex");
|
||||||
|
}
|
||||||
|
|
||||||
|
statement.MoveNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Persist all user data for the specified user
|
||||||
|
/// </summary>
|
||||||
|
private void PersistAllUserData(long internalUserId, UserItemData[] userDataList, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
using (var connection = GetConnection())
|
||||||
|
{
|
||||||
|
connection.RunInTransaction(db =>
|
||||||
|
{
|
||||||
|
foreach (var userItemData in userDataList)
|
||||||
|
{
|
||||||
|
SaveUserData(db, internalUserId, userItemData.Key, userItemData);
|
||||||
|
}
|
||||||
|
}, TransactionMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the user data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="internalUserId">The user id.</param>
|
||||||
|
/// <param name="key">The key.</param>
|
||||||
|
/// <returns>Task{UserItemData}.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">
|
||||||
|
/// userId
|
||||||
|
/// or
|
||||||
|
/// key
|
||||||
|
/// </exception>
|
||||||
|
public UserItemData GetUserData(long internalUserId, string key)
|
||||||
|
{
|
||||||
|
if (internalUserId <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(internalUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(key))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var connection = GetConnection(true))
|
||||||
|
{
|
||||||
|
using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where key =@Key and userId=@UserId"))
|
||||||
|
{
|
||||||
|
statement.TryBind("@UserId", internalUserId);
|
||||||
|
statement.TryBind("@Key", key);
|
||||||
|
|
||||||
|
foreach (var row in statement.ExecuteQuery())
|
||||||
|
{
|
||||||
|
return ReadRow(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserItemData GetUserData(long internalUserId, List<string> keys)
|
||||||
|
{
|
||||||
|
if (keys == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(keys));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetUserData(internalUserId, keys[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return all user-data associated with the given user
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="internalUserId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<UserItemData> GetAllUserData(long internalUserId)
|
||||||
|
{
|
||||||
|
if (internalUserId <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(internalUserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = new List<UserItemData>();
|
||||||
|
|
||||||
|
using (var connection = GetConnection())
|
||||||
|
{
|
||||||
|
using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where userId=@UserId"))
|
||||||
|
{
|
||||||
|
statement.TryBind("@UserId", internalUserId);
|
||||||
|
|
||||||
|
foreach (var row in statement.ExecuteQuery())
|
||||||
|
{
|
||||||
|
list.Add(ReadRow(row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read a row from the specified reader into the provided userData object
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader"></param>
|
||||||
|
private UserItemData ReadRow(IReadOnlyList<IResultSetValue> reader)
|
||||||
|
{
|
||||||
|
var userData = new UserItemData();
|
||||||
|
|
||||||
|
userData.Key = reader[0].ToString();
|
||||||
|
//userData.UserId = reader[1].ReadGuidFromBlob();
|
||||||
|
|
||||||
|
if (reader[2].SQLiteType != SQLiteType.Null)
|
||||||
|
{
|
||||||
|
userData.Rating = reader[2].ToDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
userData.Played = reader[3].ToBool();
|
||||||
|
userData.PlayCount = reader[4].ToInt();
|
||||||
|
userData.IsFavorite = reader[5].ToBool();
|
||||||
|
userData.PlaybackPositionTicks = reader[6].ToInt64();
|
||||||
|
|
||||||
|
if (reader[7].SQLiteType != SQLiteType.Null)
|
||||||
|
{
|
||||||
|
userData.LastPlayedDate = reader[7].TryReadDateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader[8].SQLiteType != SQLiteType.Null)
|
||||||
|
{
|
||||||
|
userData.AudioStreamIndex = reader[8].ToInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader[9].SQLiteType != SQLiteType.Null)
|
||||||
|
{
|
||||||
|
userData.SubtitleStreamIndex = reader[9].ToInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
return userData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
/// <remarks>
|
||||||
|
/// There is nothing to dispose here since <see cref="BaseSqliteRepository.WriteLock"/> and
|
||||||
|
/// <see cref="BaseSqliteRepository.WriteConnection"/> are managed by <see cref="SqliteItemRepository"/>.
|
||||||
|
/// See <see cref="Initialize(IUserManager, SemaphoreSlim, SQLiteDatabaseConnection)"/>.
|
||||||
|
/// </remarks>
|
||||||
|
protected override void Dispose(bool dispose)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
"Folders": "Fouers",
|
"Folders": "Fouers",
|
||||||
"Favorites": "Gunstelinge",
|
"Favorites": "Gunstelinge",
|
||||||
"HeaderFavoriteShows": "Gunsteling Vertonings",
|
"HeaderFavoriteShows": "Gunsteling Vertonings",
|
||||||
"ValueSpecialEpisodeName": "Spesiaal - {0}",
|
"ValueSpecialEpisodeName": "Spesiale - {0}",
|
||||||
"HeaderAlbumArtists": "Album Kunstenaars",
|
"HeaderAlbumArtists": "Album Kunstenaars",
|
||||||
"Books": "Boeke",
|
"Books": "Boeke",
|
||||||
"HeaderNextUp": "Volgende",
|
"HeaderNextUp": "Volgende",
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"Collections": "Colecciones",
|
"Collections": "Colecciones",
|
||||||
"DeviceOfflineWithName": "{0} se ha desconectado",
|
"DeviceOfflineWithName": "{0} se ha desconectado",
|
||||||
"DeviceOnlineWithName": "{0} está conectado",
|
"DeviceOnlineWithName": "{0} está conectado",
|
||||||
"FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión de {0}",
|
"FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión desde {0}",
|
||||||
"Favorites": "Favoritos",
|
"Favorites": "Favoritos",
|
||||||
"Folders": "Carpetas",
|
"Folders": "Carpetas",
|
||||||
"Genres": "Géneros",
|
"Genres": "Géneros",
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
"ScheduledTaskFailedWithName": "{0} falló",
|
"ScheduledTaskFailedWithName": "{0} falló",
|
||||||
"ScheduledTaskStartedWithName": "{0} iniciada",
|
"ScheduledTaskStartedWithName": "{0} iniciada",
|
||||||
"ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado",
|
"ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado",
|
||||||
"Shows": "Series",
|
"Shows": "Mostrar",
|
||||||
"Songs": "Canciones",
|
"Songs": "Canciones",
|
||||||
"StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
|
"StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
|
||||||
"SubtitleDownloadFailureForItem": "Error al descargar subtítulos para {0}",
|
"SubtitleDownloadFailureForItem": "Error al descargar subtítulos para {0}",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"HeaderLiveTV": "Suorat lähetykset",
|
"HeaderLiveTV": "Live-TV",
|
||||||
"NewVersionIsAvailable": "Uusi versio Jellyfin palvelimesta on ladattavissa.",
|
"NewVersionIsAvailable": "Uusi versio Jellyfin palvelimesta on ladattavissa.",
|
||||||
"NameSeasonUnknown": "Tuntematon Kausi",
|
"NameSeasonUnknown": "Tuntematon Kausi",
|
||||||
"NameSeasonNumber": "Kausi {0}",
|
"NameSeasonNumber": "Kausi {0}",
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
"MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen asetusryhmä {0} on päivitetty",
|
"MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen asetusryhmä {0} on päivitetty",
|
||||||
"MessageApplicationUpdatedTo": "Jellyfin palvelin on päivitetty versioon {0}",
|
"MessageApplicationUpdatedTo": "Jellyfin palvelin on päivitetty versioon {0}",
|
||||||
"MessageApplicationUpdated": "Jellyfin palvelin on päivitetty",
|
"MessageApplicationUpdated": "Jellyfin palvelin on päivitetty",
|
||||||
"Latest": "Viimeisin",
|
"Latest": "Uusimmat",
|
||||||
"LabelRunningTimeValue": "Toiston kesto: {0}",
|
"LabelRunningTimeValue": "Toiston kesto: {0}",
|
||||||
"LabelIpAddressValue": "IP-osoite: {0}",
|
"LabelIpAddressValue": "IP-osoite: {0}",
|
||||||
"ItemRemovedWithName": "{0} poistettiin kirjastosta",
|
"ItemRemovedWithName": "{0} poistettiin kirjastosta",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"CameraImageUploadedFrom": "Uusi kamerakuva on ladattu {0}",
|
"CameraImageUploadedFrom": "Uusi kamerakuva on ladattu {0}",
|
||||||
"Books": "Kirjat",
|
"Books": "Kirjat",
|
||||||
"AuthenticationSucceededWithUserName": "{0} todennus onnistui",
|
"AuthenticationSucceededWithUserName": "{0} todennus onnistui",
|
||||||
"Artists": "Esiintyjät",
|
"Artists": "Artistit",
|
||||||
"Application": "Sovellus",
|
"Application": "Sovellus",
|
||||||
"AppDeviceValues": "Sovellus: {0}, Laite: {1}",
|
"AppDeviceValues": "Sovellus: {0}, Laite: {1}",
|
||||||
"Albums": "Albumit",
|
"Albums": "Albumit",
|
||||||
|
@ -67,21 +67,21 @@
|
||||||
"UserDownloadingItemWithValues": "{0} lataa {1}",
|
"UserDownloadingItemWithValues": "{0} lataa {1}",
|
||||||
"UserDeletedWithName": "Käyttäjä {0} poistettu",
|
"UserDeletedWithName": "Käyttäjä {0} poistettu",
|
||||||
"UserCreatedWithName": "Käyttäjä {0} luotu",
|
"UserCreatedWithName": "Käyttäjä {0} luotu",
|
||||||
"TvShows": "TV-Ohjelmat",
|
"TvShows": "TV-sarjat",
|
||||||
"Sync": "Synkronoi",
|
"Sync": "Synkronoi",
|
||||||
"SubtitleDownloadFailureFromForItem": "Tekstityksen lataaminen epäonnistui {0} - {1}",
|
"SubtitleDownloadFailureFromForItem": "Tekstitysten lataus ({0} -> {1}) epäonnistui //this string would have to be generated for each provider and movie because of finnish cases, sorry",
|
||||||
"StartupEmbyServerIsLoading": "Jellyfin palvelin latautuu. Kokeile hetken kuluttua uudelleen.",
|
"StartupEmbyServerIsLoading": "Jellyfin palvelin latautuu. Kokeile hetken kuluttua uudelleen.",
|
||||||
"Songs": "Kappaleet",
|
"Songs": "Kappaleet",
|
||||||
"Shows": "Ohjelmat",
|
"Shows": "Sarjat",
|
||||||
"ServerNameNeedsToBeRestarted": "{0} vaatii uudelleenkäynnistyksen",
|
"ServerNameNeedsToBeRestarted": "{0} täytyy käynnistää uudelleen",
|
||||||
"ProviderValue": "Tarjoaja: {0}",
|
"ProviderValue": "Tarjoaja: {0}",
|
||||||
"Plugin": "Liitännäinen",
|
"Plugin": "Liitännäinen",
|
||||||
"NotificationOptionVideoPlaybackStopped": "Videon toisto pysäytetty",
|
"NotificationOptionVideoPlaybackStopped": "Videon toisto pysäytetty",
|
||||||
"NotificationOptionVideoPlayback": "Videon toisto aloitettu",
|
"NotificationOptionVideoPlayback": "Videota toistetaan",
|
||||||
"NotificationOptionUserLockedOut": "Käyttäjä lukittu",
|
"NotificationOptionUserLockedOut": "Käyttäjä kirjautui ulos",
|
||||||
"NotificationOptionTaskFailed": "Ajastettu tehtävä epäonnistui",
|
"NotificationOptionTaskFailed": "Ajastettu tehtävä epäonnistui",
|
||||||
"NotificationOptionServerRestartRequired": "Palvelimen uudelleenkäynnistys vaaditaan",
|
"NotificationOptionServerRestartRequired": "Palvelin pitää käynnistää uudelleen",
|
||||||
"NotificationOptionPluginUpdateInstalled": "Lisäosan päivitys asennettu",
|
"NotificationOptionPluginUpdateInstalled": "Liitännäinen päivitetty",
|
||||||
"NotificationOptionPluginUninstalled": "Liitännäinen poistettu",
|
"NotificationOptionPluginUninstalled": "Liitännäinen poistettu",
|
||||||
"NotificationOptionPluginInstalled": "Liitännäinen asennettu",
|
"NotificationOptionPluginInstalled": "Liitännäinen asennettu",
|
||||||
"NotificationOptionPluginError": "Ongelma liitännäisessä",
|
"NotificationOptionPluginError": "Ongelma liitännäisessä",
|
||||||
|
@ -90,8 +90,8 @@
|
||||||
"NotificationOptionCameraImageUploaded": "Kameran kuva ladattu",
|
"NotificationOptionCameraImageUploaded": "Kameran kuva ladattu",
|
||||||
"NotificationOptionAudioPlaybackStopped": "Äänen toisto lopetettu",
|
"NotificationOptionAudioPlaybackStopped": "Äänen toisto lopetettu",
|
||||||
"NotificationOptionAudioPlayback": "Toistetaan ääntä",
|
"NotificationOptionAudioPlayback": "Toistetaan ääntä",
|
||||||
"NotificationOptionApplicationUpdateInstalled": "Uusi sovellusversio asennettu",
|
"NotificationOptionApplicationUpdateInstalled": "Sovelluspäivitys asennettu",
|
||||||
"NotificationOptionApplicationUpdateAvailable": "Sovelluksesta on uusi versio saatavilla",
|
"NotificationOptionApplicationUpdateAvailable": "Ohjelmistopäivitys saatavilla",
|
||||||
"TasksMaintenanceCategory": "Ylläpito",
|
"TasksMaintenanceCategory": "Ylläpito",
|
||||||
"TaskDownloadMissingSubtitlesDescription": "Etsii puuttuvia tekstityksiä videon metadatatietojen pohjalta.",
|
"TaskDownloadMissingSubtitlesDescription": "Etsii puuttuvia tekstityksiä videon metadatatietojen pohjalta.",
|
||||||
"TaskDownloadMissingSubtitles": "Lataa puuttuvat tekstitykset",
|
"TaskDownloadMissingSubtitles": "Lataa puuttuvat tekstitykset",
|
||||||
|
|
|
@ -94,5 +94,23 @@
|
||||||
"ValueSpecialEpisodeName": "Spécial - {0}",
|
"ValueSpecialEpisodeName": "Spécial - {0}",
|
||||||
"VersionNumber": "Version {0}",
|
"VersionNumber": "Version {0}",
|
||||||
"TasksLibraryCategory": "Bibliothèque",
|
"TasksLibraryCategory": "Bibliothèque",
|
||||||
"TasksMaintenanceCategory": "Entretien"
|
"TasksMaintenanceCategory": "Entretien",
|
||||||
|
"TaskDownloadMissingSubtitlesDescription": "Recherche l'internet pour des sous-titres manquants à base de métadonnées configurées.",
|
||||||
|
"TaskDownloadMissingSubtitles": "Télécharger des sous-titres manquants",
|
||||||
|
"TaskRefreshChannelsDescription": "Rafraîchit des informations des chaines d'internet.",
|
||||||
|
"TaskRefreshChannels": "Rafraîchir des chaines",
|
||||||
|
"TaskCleanTranscodeDescription": "Retirer des fichiers de transcodage de plus qu'un jour.",
|
||||||
|
"TaskCleanTranscode": "Nettoyer le directoire de transcodage",
|
||||||
|
"TaskUpdatePluginsDescription": "Télécharger et installer des mises à jours des plugins qui sont configurés m.à.j. automisés.",
|
||||||
|
"TaskUpdatePlugins": "Mise à jour des plugins",
|
||||||
|
"TaskRefreshPeopleDescription": "Met à jour les métadonnées pour les acteurs et réalisateurs dans votre bibliothèque.",
|
||||||
|
"TaskRefreshPeople": "Rafraîchir les acteurs",
|
||||||
|
"TaskCleanLogsDescription": "Retire les données qui ont plus que {0} jours.",
|
||||||
|
"TaskCleanLogs": "Nettoyer les données de directoire",
|
||||||
|
"TaskRefreshLibraryDescription": "Analyse votre bibliothèque média pour des nouveaux fichiers et rafraîchit les métadonnées.",
|
||||||
|
"TaskRefreshChapterImages": "Extraire des images du chapitre",
|
||||||
|
"TaskRefreshChapterImagesDescription": "Créer des vignettes pour des vidéos qui ont des chapitres",
|
||||||
|
"TaskRefreshLibrary": "Analyser la bibliothèque de média",
|
||||||
|
"TaskCleanCache": "Nettoyer le cache de directoire",
|
||||||
|
"TasksApplicationCategory": "Application"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,41 @@
|
||||||
{
|
{
|
||||||
"Albums": "Albom",
|
"Albums": "Alben",
|
||||||
"AppDeviceValues": "App: {0}, Grät: {1}",
|
"AppDeviceValues": "App: {0}, Gerät: {1}",
|
||||||
"Application": "Aawändig",
|
"Application": "Anwendung",
|
||||||
"Artists": "Könstler",
|
"Artists": "Künstler",
|
||||||
"AuthenticationSucceededWithUserName": "{0} het sech aagmäudet",
|
"AuthenticationSucceededWithUserName": "{0} hat sich angemeldet",
|
||||||
"Books": "Büecher",
|
"Books": "Bücher",
|
||||||
"CameraImageUploadedFrom": "Es nöis Foti esch ufeglade worde vo {0}",
|
"CameraImageUploadedFrom": "Ein neues Foto wurde von {0} hochgeladen",
|
||||||
"Channels": "Kanäu",
|
"Channels": "Kanäle",
|
||||||
"ChapterNameValue": "Kapitu {0}",
|
"ChapterNameValue": "Kapitel {0}",
|
||||||
"Collections": "Sammlige",
|
"Collections": "Sammlungen",
|
||||||
"DeviceOfflineWithName": "{0} esch offline gange",
|
"DeviceOfflineWithName": "{0} wurde getrennt",
|
||||||
"DeviceOnlineWithName": "{0} esch online cho",
|
"DeviceOnlineWithName": "{0} ist verbunden",
|
||||||
"FailedLoginAttemptWithUserName": "Fäugschlagne Aamäudeversuech vo {0}",
|
"FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
|
||||||
"Favorites": "Favorite",
|
"Favorites": "Favoriten",
|
||||||
"Folders": "Ordner",
|
"Folders": "Ordner",
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"HeaderAlbumArtists": "Albom-Könstler",
|
"HeaderAlbumArtists": "Album-Künstler",
|
||||||
"HeaderCameraUploads": "Kamera-Uploads",
|
"HeaderCameraUploads": "Kamera-Uploads",
|
||||||
"HeaderContinueWatching": "Wiiterluege",
|
"HeaderContinueWatching": "weiter schauen",
|
||||||
"HeaderFavoriteAlbums": "Lieblingsalbe",
|
"HeaderFavoriteAlbums": "Lieblingsalben",
|
||||||
"HeaderFavoriteArtists": "Lieblings-Interprete",
|
"HeaderFavoriteArtists": "Lieblings-Künstler",
|
||||||
"HeaderFavoriteEpisodes": "Lieblingsepisode",
|
"HeaderFavoriteEpisodes": "Lieblingsepisoden",
|
||||||
"HeaderFavoriteShows": "Lieblingsserie",
|
"HeaderFavoriteShows": "Lieblingsserien",
|
||||||
"HeaderFavoriteSongs": "Lieblingslieder",
|
"HeaderFavoriteSongs": "Lieblingslieder",
|
||||||
"HeaderLiveTV": "Live-Färnseh",
|
"HeaderLiveTV": "Live-Fernseh",
|
||||||
"HeaderNextUp": "Als nächts",
|
"HeaderNextUp": "Als Nächstes",
|
||||||
"HeaderRecordingGroups": "Ufnahmegruppe",
|
"HeaderRecordingGroups": "Aufnahme-Gruppen",
|
||||||
"HomeVideos": "Heimfilmli",
|
"HomeVideos": "Heimvideos",
|
||||||
"Inherit": "Hinzuefüege",
|
"Inherit": "Vererben",
|
||||||
"ItemAddedWithName": "{0} esch de Bibliothek dezuegfüegt worde",
|
"ItemAddedWithName": "{0} wurde der Bibliothek hinzugefügt",
|
||||||
"ItemRemovedWithName": "{0} esch vo de Bibliothek entfärnt worde",
|
"ItemRemovedWithName": "{0} wurde aus der Bibliothek entfernt",
|
||||||
"LabelIpAddressValue": "IP-Adrässe: {0}",
|
"LabelIpAddressValue": "IP-Adresse: {0}",
|
||||||
"LabelRunningTimeValue": "Loufziit: {0}",
|
"LabelRunningTimeValue": "Laufzeit: {0}",
|
||||||
"Latest": "Nöischti",
|
"Latest": "Neueste",
|
||||||
"MessageApplicationUpdated": "Jellyfin Server esch aktualisiert worde",
|
"MessageApplicationUpdated": "Jellyfin-Server wurde aktualisiert",
|
||||||
"MessageApplicationUpdatedTo": "Jellyfin Server esch of Version {0} aktualisiert worde",
|
"MessageApplicationUpdatedTo": "Jellyfin-Server wurde auf Version {0} aktualisiert",
|
||||||
"MessageNamedServerConfigurationUpdatedWithValue": "De Serveriistöuigsberiich {0} esch aktualisiert worde",
|
"MessageNamedServerConfigurationUpdatedWithValue": "Der Server-Einstellungsbereich {0} wurde aktualisiert",
|
||||||
"MessageServerConfigurationUpdated": "Serveriistöuige send aktualisiert worde",
|
"MessageServerConfigurationUpdated": "Serveriistöuige send aktualisiert worde",
|
||||||
"MixedContent": "Gmeschti Inhäut",
|
"MixedContent": "Gmeschti Inhäut",
|
||||||
"Movies": "Film",
|
"Movies": "Film",
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
"NotificationOptionAudioPlayback": "Audiowedergab gstartet",
|
"NotificationOptionAudioPlayback": "Audiowedergab gstartet",
|
||||||
"NotificationOptionAudioPlaybackStopped": "Audiwedergab gstoppt",
|
"NotificationOptionAudioPlaybackStopped": "Audiwedergab gstoppt",
|
||||||
"NotificationOptionCameraImageUploaded": "Foti ueglade",
|
"NotificationOptionCameraImageUploaded": "Foti ueglade",
|
||||||
"NotificationOptionInstallationFailed": "Installationsfäuer",
|
"NotificationOptionInstallationFailed": "Installationsfehler",
|
||||||
"NotificationOptionNewLibraryContent": "Nöie Inhaut hinzuegfüegt",
|
"NotificationOptionNewLibraryContent": "Nöie Inhaut hinzuegfüegt",
|
||||||
"NotificationOptionPluginError": "Plugin-Fäuer",
|
"NotificationOptionPluginError": "Plugin-Fäuer",
|
||||||
"NotificationOptionPluginInstalled": "Plugin installiert",
|
"NotificationOptionPluginInstalled": "Plugin installiert",
|
||||||
|
@ -92,5 +92,27 @@
|
||||||
"UserStoppedPlayingItemWithValues": "{0} het d'Wedergab vo {1} of {2} gstoppt",
|
"UserStoppedPlayingItemWithValues": "{0} het d'Wedergab vo {1} of {2} gstoppt",
|
||||||
"ValueHasBeenAddedToLibrary": "{0} esch dinnere Biblithek hinzuegfüegt worde",
|
"ValueHasBeenAddedToLibrary": "{0} esch dinnere Biblithek hinzuegfüegt worde",
|
||||||
"ValueSpecialEpisodeName": "Extra - {0}",
|
"ValueSpecialEpisodeName": "Extra - {0}",
|
||||||
"VersionNumber": "Version {0}"
|
"VersionNumber": "Version {0}",
|
||||||
|
"TaskCleanLogs": "Lösche Log Pfad",
|
||||||
|
"TaskRefreshLibraryDescription": "Scanne alle Bibliotheken für hinzugefügte Datein und erneuere Metadaten.",
|
||||||
|
"TaskRefreshLibrary": "Scanne alle Bibliotheken",
|
||||||
|
"TaskRefreshChapterImagesDescription": "Kreiert Vorschaubilder für Videos welche Kapitel haben.",
|
||||||
|
"TaskRefreshChapterImages": "Extrahiere Kapitel-Bilder",
|
||||||
|
"TaskCleanCacheDescription": "Löscht Zwischenspeicherdatein die nicht länger von System gebraucht werden.",
|
||||||
|
"TaskCleanCache": "Leere Cache Pfad",
|
||||||
|
"TasksChannelsCategory": "Internet Kanäle",
|
||||||
|
"TasksApplicationCategory": "Applikation",
|
||||||
|
"TasksLibraryCategory": "Bibliothek",
|
||||||
|
"TasksMaintenanceCategory": "Verwaltung",
|
||||||
|
"TaskDownloadMissingSubtitlesDescription": "Durchsucht das Internet nach fehlenden Untertiteln, basierend auf den Metadaten Einstellungen.",
|
||||||
|
"TaskDownloadMissingSubtitles": "Lade fehlende Untertitel herunter",
|
||||||
|
"TaskRefreshChannelsDescription": "Aktualisiert Internet Kanal Informationen.",
|
||||||
|
"TaskRefreshChannels": "Aktualisiere Kanäle",
|
||||||
|
"TaskCleanTranscodeDescription": "Löscht Transkodierdateien welche älter als ein Tag sind.",
|
||||||
|
"TaskCleanTranscode": "Räume Transcodier Verzeichnis auf",
|
||||||
|
"TaskUpdatePluginsDescription": "Lädt Aktualisierungen für Erweiterungen herunter und installiert diese, für welche automatische Aktualisierungen konfiguriert sind.",
|
||||||
|
"TaskUpdatePlugins": "Aktualisiere Erweiterungen",
|
||||||
|
"TaskRefreshPeopleDescription": "Aktualisiert Metadaten für Schausteller und Regisseure in deiner Bibliothek.",
|
||||||
|
"TaskRefreshPeople": "Aktualisiere Schauspieler",
|
||||||
|
"TaskCleanLogsDescription": "Löscht Log Dateien die älter als {0} Tage sind."
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
"NotificationOptionVideoPlayback": "Video playback started",
|
"NotificationOptionVideoPlayback": "Video playback started",
|
||||||
"NotificationOptionVideoPlaybackStopped": "Video playback stopped",
|
"NotificationOptionVideoPlaybackStopped": "Video playback stopped",
|
||||||
"Photos": "תמונות",
|
"Photos": "תמונות",
|
||||||
"Playlists": "רשימות ניגון",
|
"Playlists": "רשימות הפעלה",
|
||||||
"Plugin": "Plugin",
|
"Plugin": "Plugin",
|
||||||
"PluginInstalledWithName": "{0} was installed",
|
"PluginInstalledWithName": "{0} was installed",
|
||||||
"PluginUninstalledWithName": "{0} was uninstalled",
|
"PluginUninstalledWithName": "{0} was uninstalled",
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
"Inherit": "Naslijedi",
|
"Inherit": "Naslijedi",
|
||||||
"ItemAddedWithName": "{0} je dodano u biblioteku",
|
"ItemAddedWithName": "{0} je dodano u biblioteku",
|
||||||
"ItemRemovedWithName": "{0} je uklonjen iz biblioteke",
|
"ItemRemovedWithName": "{0} je uklonjen iz biblioteke",
|
||||||
"LabelIpAddressValue": "Ip adresa: {0}",
|
"LabelIpAddressValue": "IP adresa: {0}",
|
||||||
"LabelRunningTimeValue": "Vrijeme rada: {0}",
|
"LabelRunningTimeValue": "Vrijeme rada: {0}",
|
||||||
"Latest": "Najnovije",
|
"Latest": "Najnovije",
|
||||||
"MessageApplicationUpdated": "Jellyfin Server je ažuriran",
|
"MessageApplicationUpdated": "Jellyfin Server je ažuriran",
|
||||||
|
@ -92,5 +92,13 @@
|
||||||
"UserStoppedPlayingItemWithValues": "{0} je zaustavio {1}",
|
"UserStoppedPlayingItemWithValues": "{0} je zaustavio {1}",
|
||||||
"ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
|
"ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
|
||||||
"ValueSpecialEpisodeName": "Specijal - {0}",
|
"ValueSpecialEpisodeName": "Specijal - {0}",
|
||||||
"VersionNumber": "Verzija {0}"
|
"VersionNumber": "Verzija {0}",
|
||||||
|
"TaskRefreshLibraryDescription": "Skenira vašu medijsku knjižnicu sa novim datotekama i osvježuje metapodatke.",
|
||||||
|
"TaskRefreshLibrary": "Skeniraj medijsku knjižnicu",
|
||||||
|
"TaskRefreshChapterImagesDescription": "Stvara sličice za videozapise koji imaju poglavlja.",
|
||||||
|
"TaskRefreshChapterImages": "Raspakiraj slike poglavlja",
|
||||||
|
"TaskCleanCacheDescription": "Briše priručne datoteke nepotrebne za sistem.",
|
||||||
|
"TaskCleanCache": "Očisti priručnu memoriju",
|
||||||
|
"TasksApplicationCategory": "Aplikacija",
|
||||||
|
"TasksMaintenanceCategory": "Održavanje"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"Artists": "Artisti",
|
"Artists": "Artisti",
|
||||||
"AuthenticationSucceededWithUserName": "{0} autenticato con successo",
|
"AuthenticationSucceededWithUserName": "{0} autenticato con successo",
|
||||||
"Books": "Libri",
|
"Books": "Libri",
|
||||||
"CameraImageUploadedFrom": "È stata caricata una nuova immagine della fotocamera dal device {0}",
|
"CameraImageUploadedFrom": "È stata caricata una nuova fotografia da {0}",
|
||||||
"Channels": "Canali",
|
"Channels": "Canali",
|
||||||
"ChapterNameValue": "Capitolo {0}",
|
"ChapterNameValue": "Capitolo {0}",
|
||||||
"Collections": "Collezioni",
|
"Collections": "Collezioni",
|
||||||
|
|
|
@ -91,5 +91,12 @@
|
||||||
"Songs": "Песни",
|
"Songs": "Песни",
|
||||||
"Shows": "Серии",
|
"Shows": "Серии",
|
||||||
"ServerNameNeedsToBeRestarted": "{0} треба да се рестартира",
|
"ServerNameNeedsToBeRestarted": "{0} треба да се рестартира",
|
||||||
"ScheduledTaskStartedWithName": "{0} започна"
|
"ScheduledTaskStartedWithName": "{0} започна",
|
||||||
|
"TaskRefreshChapterImages": "Извези Слики од Поглавје",
|
||||||
|
"TaskCleanCacheDescription": "Ги брише кешираните фајлови што не се повеќе потребни од системот.",
|
||||||
|
"TaskCleanCache": "Исчисти Го Кешот",
|
||||||
|
"TasksChannelsCategory": "Интернет Канали",
|
||||||
|
"TasksApplicationCategory": "Апликација",
|
||||||
|
"TasksLibraryCategory": "Библиотека",
|
||||||
|
"TasksMaintenanceCategory": "Одржување"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"Artists": "Artiesten",
|
"Artists": "Artiesten",
|
||||||
"AuthenticationSucceededWithUserName": "{0} is succesvol geverifieerd",
|
"AuthenticationSucceededWithUserName": "{0} is succesvol geverifieerd",
|
||||||
"Books": "Boeken",
|
"Books": "Boeken",
|
||||||
"CameraImageUploadedFrom": "Er is een nieuwe afbeelding toegevoegd via {0}",
|
"CameraImageUploadedFrom": "Er is een nieuwe camera afbeelding toegevoegd via {0}",
|
||||||
"Channels": "Kanalen",
|
"Channels": "Kanalen",
|
||||||
"ChapterNameValue": "Hoofdstuk {0}",
|
"ChapterNameValue": "Hoofdstuk {0}",
|
||||||
"Collections": "Verzamelingen",
|
"Collections": "Verzamelingen",
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
"HeaderLiveTV": "Live TV",
|
"HeaderLiveTV": "Live TV",
|
||||||
"HeaderNextUp": "Volgende",
|
"HeaderNextUp": "Volgende",
|
||||||
"HeaderRecordingGroups": "Opnamegroepen",
|
"HeaderRecordingGroups": "Opnamegroepen",
|
||||||
"HomeVideos": "Start video's",
|
"HomeVideos": "Home video's",
|
||||||
"Inherit": "Overerven",
|
"Inherit": "Overerven",
|
||||||
"ItemAddedWithName": "{0} is toegevoegd aan de bibliotheek",
|
"ItemAddedWithName": "{0} is toegevoegd aan de bibliotheek",
|
||||||
"ItemRemovedWithName": "{0} is verwijderd uit de bibliotheek",
|
"ItemRemovedWithName": "{0} is verwijderd uit de bibliotheek",
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
"NotificationOptionAudioPlayback": "Muziek gestart",
|
"NotificationOptionAudioPlayback": "Muziek gestart",
|
||||||
"NotificationOptionAudioPlaybackStopped": "Muziek gestopt",
|
"NotificationOptionAudioPlaybackStopped": "Muziek gestopt",
|
||||||
"NotificationOptionCameraImageUploaded": "Camera-afbeelding geüpload",
|
"NotificationOptionCameraImageUploaded": "Camera-afbeelding geüpload",
|
||||||
"NotificationOptionInstallationFailed": "Installatie mislukking",
|
"NotificationOptionInstallationFailed": "Installatie mislukt",
|
||||||
"NotificationOptionNewLibraryContent": "Nieuwe content toegevoegd",
|
"NotificationOptionNewLibraryContent": "Nieuwe content toegevoegd",
|
||||||
"NotificationOptionPluginError": "Plug-in fout",
|
"NotificationOptionPluginError": "Plug-in fout",
|
||||||
"NotificationOptionPluginInstalled": "Plug-in geïnstalleerd",
|
"NotificationOptionPluginInstalled": "Plug-in geïnstalleerd",
|
||||||
|
|
|
@ -92,5 +92,26 @@
|
||||||
"UserStoppedPlayingItemWithValues": "{0} je nehal predvajati {1} na {2}",
|
"UserStoppedPlayingItemWithValues": "{0} je nehal predvajati {1} na {2}",
|
||||||
"ValueHasBeenAddedToLibrary": "{0} je bil dodan vaši knjižnici",
|
"ValueHasBeenAddedToLibrary": "{0} je bil dodan vaši knjižnici",
|
||||||
"ValueSpecialEpisodeName": "Poseben - {0}",
|
"ValueSpecialEpisodeName": "Poseben - {0}",
|
||||||
"VersionNumber": "Različica {0}"
|
"VersionNumber": "Različica {0}",
|
||||||
|
"TaskDownloadMissingSubtitles": "Prenesi manjkajoče podnapise",
|
||||||
|
"TaskRefreshChannelsDescription": "Osveži podatke spletnih kanalov.",
|
||||||
|
"TaskRefreshChannels": "Osveži kanale",
|
||||||
|
"TaskCleanTranscodeDescription": "Izbriše več kot dan stare datoteke prekodiranja.",
|
||||||
|
"TaskCleanTranscode": "Počisti mapo prekodiranja",
|
||||||
|
"TaskUpdatePluginsDescription": "Prenese in namesti posodobitve za dodatke, ki imajo omogočene samodejne posodobitve.",
|
||||||
|
"TaskUpdatePlugins": "Posodobi dodatke",
|
||||||
|
"TaskRefreshPeopleDescription": "Osveži metapodatke za igralce in režiserje v vaši knjižnici.",
|
||||||
|
"TaskRefreshPeople": "Osveži osebe",
|
||||||
|
"TaskCleanLogsDescription": "Izbriše dnevniške datoteke starejše od {0} dni.",
|
||||||
|
"TaskCleanLogs": "Počisti mapo dnevnika",
|
||||||
|
"TaskRefreshLibraryDescription": "Preišče vašo knjižnico za nove datoteke in osveži metapodatke.",
|
||||||
|
"TaskRefreshLibrary": "Preišči knjižnico predstavnosti",
|
||||||
|
"TaskRefreshChapterImagesDescription": "Ustvari sličice za poglavja videoposnetkov.",
|
||||||
|
"TaskRefreshChapterImages": "Izvleči slike poglavij",
|
||||||
|
"TaskCleanCacheDescription": "Izbriše predpomnjene datoteke, ki niso več potrebne.",
|
||||||
|
"TaskCleanCache": "Počisti mapo predpomnilnika",
|
||||||
|
"TasksChannelsCategory": "Spletni kanali",
|
||||||
|
"TasksApplicationCategory": "Aplikacija",
|
||||||
|
"TasksLibraryCategory": "Knjižnica",
|
||||||
|
"TasksMaintenanceCategory": "Vzdrževanje"
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
"Channels": "Kanaler",
|
"Channels": "Kanaler",
|
||||||
"ChapterNameValue": "Kapitel {0}",
|
"ChapterNameValue": "Kapitel {0}",
|
||||||
"Collections": "Samlingar",
|
"Collections": "Samlingar",
|
||||||
"DeviceOfflineWithName": "{0} har tappat anslutningen",
|
"DeviceOfflineWithName": "{0} har kopplat från",
|
||||||
"DeviceOnlineWithName": "{0} är ansluten",
|
"DeviceOnlineWithName": "{0} är ansluten",
|
||||||
"FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}",
|
"FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}",
|
||||||
"Favorites": "Favoriter",
|
"Favorites": "Favoriter",
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
"NotificationOptionAudioPlayback": "Ljuduppspelning har påbörjats",
|
"NotificationOptionAudioPlayback": "Ljuduppspelning har påbörjats",
|
||||||
"NotificationOptionAudioPlaybackStopped": "Ljuduppspelning stoppades",
|
"NotificationOptionAudioPlaybackStopped": "Ljuduppspelning stoppades",
|
||||||
"NotificationOptionCameraImageUploaded": "Kamerabild har laddats upp",
|
"NotificationOptionCameraImageUploaded": "Kamerabild har laddats upp",
|
||||||
"NotificationOptionInstallationFailed": "Fel vid installation",
|
"NotificationOptionInstallationFailed": "Installationen misslyckades",
|
||||||
"NotificationOptionNewLibraryContent": "Nytt innehåll har lagts till",
|
"NotificationOptionNewLibraryContent": "Nytt innehåll har lagts till",
|
||||||
"NotificationOptionPluginError": "Fel uppstod med tillägget",
|
"NotificationOptionPluginError": "Fel uppstod med tillägget",
|
||||||
"NotificationOptionPluginInstalled": "Tillägg har installerats",
|
"NotificationOptionPluginInstalled": "Tillägg har installerats",
|
||||||
|
@ -113,5 +113,6 @@
|
||||||
"TasksChannelsCategory": "Internetkanaler",
|
"TasksChannelsCategory": "Internetkanaler",
|
||||||
"TasksApplicationCategory": "Applikation",
|
"TasksApplicationCategory": "Applikation",
|
||||||
"TasksLibraryCategory": "Bibliotek",
|
"TasksLibraryCategory": "Bibliotek",
|
||||||
"TasksMaintenanceCategory": "Underhåll"
|
"TasksMaintenanceCategory": "Underhåll",
|
||||||
|
"TaskRefreshPeople": "Uppdatera Personer"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"MusicVideos": "Музичні відео",
|
||||||
|
"Music": "Музика",
|
||||||
|
"Movies": "Фільми",
|
||||||
|
"MessageApplicationUpdatedTo": "Jellyfin Server був оновлений до версії {0}",
|
||||||
|
"MessageApplicationUpdated": "Jellyfin Server був оновлений",
|
||||||
|
"Latest": "Останні",
|
||||||
|
"LabelIpAddressValue": "IP-адреси: {0}",
|
||||||
|
"ItemRemovedWithName": "{0} видалено з бібліотеки",
|
||||||
|
"ItemAddedWithName": "{0} додано до бібліотеки",
|
||||||
|
"HeaderNextUp": "Наступний",
|
||||||
|
"HeaderLiveTV": "Ефірне ТБ",
|
||||||
|
"HeaderFavoriteSongs": "Улюблені пісні",
|
||||||
|
"HeaderFavoriteShows": "Улюблені шоу",
|
||||||
|
"HeaderFavoriteEpisodes": "Улюблені серії",
|
||||||
|
"HeaderFavoriteArtists": "Улюблені виконавці",
|
||||||
|
"HeaderFavoriteAlbums": "Улюблені альбоми",
|
||||||
|
"HeaderContinueWatching": "Продовжити перегляд",
|
||||||
|
"HeaderCameraUploads": "Завантажено з камери",
|
||||||
|
"HeaderAlbumArtists": "Виконавці альбомів",
|
||||||
|
"Genres": "Жанри",
|
||||||
|
"Folders": "Директорії",
|
||||||
|
"Favorites": "Улюблені",
|
||||||
|
"DeviceOnlineWithName": "{0} під'єднано",
|
||||||
|
"DeviceOfflineWithName": "{0} від'єднано",
|
||||||
|
"Collections": "Колекції",
|
||||||
|
"ChapterNameValue": "Глава {0}",
|
||||||
|
"Channels": "Канали",
|
||||||
|
"CameraImageUploadedFrom": "Нова фотографія завантажена з {0}",
|
||||||
|
"Books": "Книги",
|
||||||
|
"AuthenticationSucceededWithUserName": "{0} успішно авторизовані",
|
||||||
|
"Artists": "Виконавці",
|
||||||
|
"Application": "Додаток",
|
||||||
|
"AppDeviceValues": "Додаток: {0}, Пристрій: {1}",
|
||||||
|
"Albums": "Альбоми"
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"Albums": "專輯",
|
"Albums": "專輯",
|
||||||
"AppDeviceValues": "軟體: {0}, 設備: {1}",
|
"AppDeviceValues": "軟件: {0}, 設備: {1}",
|
||||||
"Application": "應用程式",
|
"Application": "應用程式",
|
||||||
"Artists": "藝人",
|
"Artists": "藝人",
|
||||||
"AuthenticationSucceededWithUserName": "{0} 授權成功",
|
"AuthenticationSucceededWithUserName": "{0} 授權成功",
|
||||||
|
@ -92,5 +92,8 @@
|
||||||
"UserStoppedPlayingItemWithValues": "{0} 已在 {2} 上停止播放 {1}",
|
"UserStoppedPlayingItemWithValues": "{0} 已在 {2} 上停止播放 {1}",
|
||||||
"ValueHasBeenAddedToLibrary": "{0} 已添加到你的媒體庫",
|
"ValueHasBeenAddedToLibrary": "{0} 已添加到你的媒體庫",
|
||||||
"ValueSpecialEpisodeName": "特典 - {0}",
|
"ValueSpecialEpisodeName": "特典 - {0}",
|
||||||
"VersionNumber": "版本{0}"
|
"VersionNumber": "版本{0}",
|
||||||
|
"TaskDownloadMissingSubtitles": "下載遺失的字幕",
|
||||||
|
"TaskUpdatePlugins": "更新插件",
|
||||||
|
"TasksApplicationCategory": "應用程式"
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,9 @@ namespace Emby.Server.Implementations.SocketSharp
|
||||||
if (!IPAddress.TryParse(GetHeader(CustomHeaderNames.XRealIP), out ip))
|
if (!IPAddress.TryParse(GetHeader(CustomHeaderNames.XRealIP), out ip))
|
||||||
{
|
{
|
||||||
ip = Request.HttpContext.Connection.RemoteIpAddress;
|
ip = Request.HttpContext.Connection.RemoteIpAddress;
|
||||||
|
|
||||||
|
// Default to the loopback address if no RemoteIpAddress is specified (i.e. during integration tests)
|
||||||
|
ip ??= IPAddress.Loopback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +93,10 @@ namespace Emby.Server.Implementations.SocketSharp
|
||||||
|
|
||||||
public IQueryCollection QueryString => Request.Query;
|
public IQueryCollection QueryString => Request.Query;
|
||||||
|
|
||||||
public bool IsLocal => Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress);
|
public bool IsLocal =>
|
||||||
|
(Request.HttpContext.Connection.LocalIpAddress == null
|
||||||
|
&& Request.HttpContext.Connection.RemoteIpAddress == null)
|
||||||
|
|| Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress);
|
||||||
|
|
||||||
public string HttpMethod => Request.Method;
|
public string HttpMethod => Request.Method;
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Artwork")]
|
|
||||||
public partial class Artwork
|
public partial class Artwork
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Book")]
|
|
||||||
public partial class Book : LibraryItem
|
public partial class Book : LibraryItem
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Book() : base()
|
protected Book()
|
||||||
{
|
{
|
||||||
BookMetadata = new HashSet<BookMetadata>();
|
BookMetadata = new HashSet<BookMetadata>();
|
||||||
Releases = new HashSet<Release>();
|
Releases = new HashSet<Release>();
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
|
@ -16,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected BookMetadata() : base()
|
protected BookMetadata()
|
||||||
{
|
{
|
||||||
Publishers = new HashSet<Company>();
|
Publishers = new HashSet<Company>();
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Chapter")]
|
|
||||||
public partial class Chapter
|
public partial class Chapter
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Collection")]
|
|
||||||
public partial class Collection
|
public partial class Collection
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("CollectionItem")]
|
|
||||||
public partial class CollectionItem
|
public partial class CollectionItem
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Company")]
|
|
||||||
public partial class Company
|
public partial class Company
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("CompanyMetadata")]
|
|
||||||
public partial class CompanyMetadata : Metadata
|
public partial class CompanyMetadata : Metadata
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +10,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected CompanyMetadata() : base()
|
protected CompanyMetadata()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
|
@ -16,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected CustomItem() : base()
|
protected CustomItem()
|
||||||
{
|
{
|
||||||
CustomItemMetadata = new HashSet<CustomItemMetadata>();
|
CustomItemMetadata = new HashSet<CustomItemMetadata>();
|
||||||
Releases = new HashSet<Release>();
|
Releases = new HashSet<Release>();
|
||||||
|
|
|
@ -1,15 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("CustomItemMetadata")]
|
|
||||||
public partial class CustomItemMetadata : Metadata
|
public partial class CustomItemMetadata : Metadata
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +9,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected CustomItemMetadata() : base()
|
protected CustomItemMetadata()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Episode")]
|
|
||||||
public partial class Episode : LibraryItem
|
public partial class Episode : LibraryItem
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Episode() : base()
|
protected Episode()
|
||||||
{
|
{
|
||||||
// NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem.
|
// NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem.
|
||||||
// One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other.
|
// One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other.
|
||||||
|
|
|
@ -1,15 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("EpisodeMetadata")]
|
|
||||||
public partial class EpisodeMetadata : Metadata
|
public partial class EpisodeMetadata : Metadata
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +10,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected EpisodeMetadata() : base()
|
protected EpisodeMetadata()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Genre")]
|
|
||||||
public partial class Genre
|
public partial class Genre
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Group")]
|
|
||||||
public partial class Group
|
public partial class Group
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Library")]
|
|
||||||
public partial class Library
|
public partial class Library
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("LibraryItem")]
|
|
||||||
public abstract partial class LibraryItem
|
public abstract partial class LibraryItem
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("LibraryRoot")]
|
|
||||||
public partial class LibraryRoot
|
public partial class LibraryRoot
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("MediaFile")]
|
|
||||||
public partial class MediaFile
|
public partial class MediaFile
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("MediaFileStream")]
|
|
||||||
public partial class MediaFileStream
|
public partial class MediaFileStream
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Metadata")]
|
|
||||||
public abstract partial class Metadata
|
public abstract partial class Metadata
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("MetadataProvider")]
|
|
||||||
public partial class MetadataProvider
|
public partial class MetadataProvider
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("MetadataProviderId")]
|
|
||||||
public partial class MetadataProviderId
|
public partial class MetadataProviderId
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Movie")]
|
|
||||||
public partial class Movie : LibraryItem
|
public partial class Movie : LibraryItem
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Movie() : base()
|
protected Movie()
|
||||||
{
|
{
|
||||||
Releases = new HashSet<Release>();
|
Releases = new HashSet<Release>();
|
||||||
MovieMetadata = new HashSet<MovieMetadata>();
|
MovieMetadata = new HashSet<MovieMetadata>();
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("MovieMetadata")]
|
|
||||||
public partial class MovieMetadata : Metadata
|
public partial class MovieMetadata : Metadata
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +12,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected MovieMetadata() : base()
|
protected MovieMetadata()
|
||||||
{
|
{
|
||||||
Studios = new HashSet<Company>();
|
Studios = new HashSet<Company>();
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("MusicAlbum")]
|
|
||||||
public partial class MusicAlbum : LibraryItem
|
public partial class MusicAlbum : LibraryItem
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected MusicAlbum() : base()
|
protected MusicAlbum()
|
||||||
{
|
{
|
||||||
MusicAlbumMetadata = new HashSet<MusicAlbumMetadata>();
|
MusicAlbumMetadata = new HashSet<MusicAlbumMetadata>();
|
||||||
Tracks = new HashSet<Track>();
|
Tracks = new HashSet<Track>();
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("MusicAlbumMetadata")]
|
|
||||||
public partial class MusicAlbumMetadata : Metadata
|
public partial class MusicAlbumMetadata : Metadata
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +12,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected MusicAlbumMetadata() : base()
|
protected MusicAlbumMetadata()
|
||||||
{
|
{
|
||||||
Labels = new HashSet<Company>();
|
Labels = new HashSet<Company>();
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Permission")]
|
|
||||||
public partial class Permission
|
public partial class Permission
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Person")]
|
|
||||||
public partial class Person
|
public partial class Person
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("PersonRole")]
|
|
||||||
public partial class PersonRole
|
public partial class PersonRole
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Photo")]
|
|
||||||
public partial class Photo : LibraryItem
|
public partial class Photo : LibraryItem
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Photo() : base()
|
protected Photo()
|
||||||
{
|
{
|
||||||
PhotoMetadata = new HashSet<PhotoMetadata>();
|
PhotoMetadata = new HashSet<PhotoMetadata>();
|
||||||
Releases = new HashSet<Release>();
|
Releases = new HashSet<Release>();
|
||||||
|
|
|
@ -1,15 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("PhotoMetadata")]
|
|
||||||
public partial class PhotoMetadata : Metadata
|
public partial class PhotoMetadata : Metadata
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +10,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected PhotoMetadata() : base()
|
protected PhotoMetadata()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Preference")]
|
|
||||||
public partial class Preference
|
public partial class Preference
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("ProviderMapping")]
|
|
||||||
public partial class ProviderMapping
|
public partial class ProviderMapping
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Rating")]
|
|
||||||
public partial class Rating
|
public partial class Rating
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is the entity to store review ratings, not age ratings
|
/// This is the entity to store review ratings, not age ratings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Table("RatingSource")]
|
|
||||||
public partial class RatingSource
|
public partial class RatingSource
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Release")]
|
|
||||||
public partial class Release
|
public partial class Release
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Season")]
|
|
||||||
public partial class Season : LibraryItem
|
public partial class Season : LibraryItem
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Season() : base()
|
protected Season()
|
||||||
{
|
{
|
||||||
// NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem.
|
// NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem.
|
||||||
// One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other.
|
// One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other.
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("SeasonMetadata")]
|
|
||||||
public partial class SeasonMetadata : Metadata
|
public partial class SeasonMetadata : Metadata
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected SeasonMetadata() : base()
|
protected SeasonMetadata()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Series")]
|
|
||||||
public partial class Series : LibraryItem
|
public partial class Series : LibraryItem
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Series() : base()
|
protected Series()
|
||||||
{
|
{
|
||||||
SeriesMetadata = new HashSet<SeriesMetadata>();
|
SeriesMetadata = new HashSet<SeriesMetadata>();
|
||||||
Seasons = new HashSet<Season>();
|
Seasons = new HashSet<Season>();
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("SeriesMetadata")]
|
|
||||||
public partial class SeriesMetadata : Metadata
|
public partial class SeriesMetadata : Metadata
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +12,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected SeriesMetadata() : base()
|
protected SeriesMetadata()
|
||||||
{
|
{
|
||||||
Networks = new HashSet<Company>();
|
Networks = new HashSet<Company>();
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("Track")]
|
|
||||||
public partial class Track : LibraryItem
|
public partial class Track : LibraryItem
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +11,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Track() : base()
|
protected Track()
|
||||||
{
|
{
|
||||||
// NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem.
|
// NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem.
|
||||||
// One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other.
|
// One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other.
|
||||||
|
|
|
@ -1,15 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("TrackMetadata")]
|
|
||||||
public partial class TrackMetadata : Metadata
|
public partial class TrackMetadata : Metadata
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
|
@ -17,7 +10,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected TrackMetadata() : base()
|
protected TrackMetadata()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,15 @@ using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("User")]
|
public partial class User
|
||||||
public class User
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The values being delimited here are Guids, so commas work as they do not appear in Guids.
|
/// The values being delimited here are Guids, so commas work as they do not appear in Guids.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const char Delimiter = ',';
|
private const char Delimiter = ',';
|
||||||
|
|
||||||
|
partial void Init();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -26,6 +27,8 @@ namespace Jellyfin.Data.Entities
|
||||||
ProviderMappings = new HashSet<ProviderMapping>();
|
ProviderMappings = new HashSet<ProviderMapping>();
|
||||||
Preferences = new HashSet<Preference>();
|
Preferences = new HashSet<Preference>();
|
||||||
AccessSchedules = new HashSet<AccessSchedule>();
|
AccessSchedules = new HashSet<AccessSchedule>();
|
||||||
|
|
||||||
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -77,6 +80,8 @@ namespace Jellyfin.Data.Entities
|
||||||
RememberSubtitleSelections = true;
|
RememberSubtitleSelections = true;
|
||||||
EnableNextEpisodeAutoPlay = true;
|
EnableNextEpisodeAutoPlay = true;
|
||||||
EnableAutoLogin = false;
|
EnableAutoLogin = false;
|
||||||
|
|
||||||
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Enums
|
namespace Jellyfin.Data.Enums
|
||||||
{
|
{
|
||||||
public enum ArtKind : Int32
|
public enum ArtKind
|
||||||
{
|
{
|
||||||
Other,
|
Other,
|
||||||
Poster,
|
Poster,
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Enums
|
namespace Jellyfin.Data.Enums
|
||||||
{
|
{
|
||||||
public enum MediaFileKind : Int32
|
public enum MediaFileKind
|
||||||
{
|
{
|
||||||
Main,
|
Main,
|
||||||
Sidecar,
|
Sidecar,
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Enums
|
namespace Jellyfin.Data.Enums
|
||||||
{
|
{
|
||||||
public enum PersonRoleType : Int32
|
public enum PersonRoleType
|
||||||
{
|
{
|
||||||
Other,
|
Other,
|
||||||
Director,
|
Director,
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Enums
|
namespace Jellyfin.Data.Enums
|
||||||
{
|
{
|
||||||
public enum PreferenceKind
|
public enum PreferenceKind
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Enums
|
namespace Jellyfin.Data.Enums
|
||||||
{
|
{
|
||||||
public enum Weekday : Int32
|
public enum Weekday
|
||||||
{
|
{
|
||||||
Sunday,
|
Sunday,
|
||||||
Monday,
|
Monday,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
namespace Jellyfin.Data
|
namespace Jellyfin.Data
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,8 +21,6 @@ namespace Jellyfin.Server.Migrations
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Execute the migration routine.
|
/// Execute the migration routine.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="host">Host that hosts current version.</param>
|
public void Perform();
|
||||||
/// <param name="logger">Host logger.</param>
|
|
||||||
public void Perform(CoreAppHost host, ILogger logger);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Jellyfin.Server.Migrations
|
namespace Jellyfin.Server.Migrations
|
||||||
|
@ -13,11 +14,10 @@ namespace Jellyfin.Server.Migrations
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of known migrations, in order of applicability.
|
/// The list of known migrations, in order of applicability.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static readonly IMigrationRoutine[] Migrations =
|
private static readonly Type[] _migrationTypes =
|
||||||
{
|
{
|
||||||
new Routines.DisableTranscodingThrottling(),
|
typeof(Routines.DisableTranscodingThrottling),
|
||||||
new Routines.CreateUserLoggingConfigFile(),
|
typeof(Routines.CreateUserLoggingConfigFile)
|
||||||
new Routines.MigrateActivityLogDb()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -28,6 +28,10 @@ namespace Jellyfin.Server.Migrations
|
||||||
public static void Run(CoreAppHost host, ILoggerFactory loggerFactory)
|
public static void Run(CoreAppHost host, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
var logger = loggerFactory.CreateLogger<MigrationRunner>();
|
var logger = loggerFactory.CreateLogger<MigrationRunner>();
|
||||||
|
var migrations = _migrationTypes
|
||||||
|
.Select(m => ActivatorUtilities.CreateInstance(host.ServiceProvider, m))
|
||||||
|
.OfType<IMigrationRoutine>()
|
||||||
|
.ToArray();
|
||||||
var migrationOptions = ((IConfigurationManager)host.ServerConfigurationManager).GetConfiguration<MigrationOptions>(MigrationsListStore.StoreKey);
|
var migrationOptions = ((IConfigurationManager)host.ServerConfigurationManager).GetConfiguration<MigrationOptions>(MigrationsListStore.StoreKey);
|
||||||
|
|
||||||
if (!host.ServerConfigurationManager.Configuration.IsStartupWizardCompleted && migrationOptions.Applied.Count == 0)
|
if (!host.ServerConfigurationManager.Configuration.IsStartupWizardCompleted && migrationOptions.Applied.Count == 0)
|
||||||
|
@ -35,16 +39,16 @@ namespace Jellyfin.Server.Migrations
|
||||||
// If startup wizard is not finished, this is a fresh install.
|
// If startup wizard is not finished, this is a fresh install.
|
||||||
// Don't run any migrations, just mark all of them as applied.
|
// Don't run any migrations, just mark all of them as applied.
|
||||||
logger.LogInformation("Marking all known migrations as applied because this is a fresh install");
|
logger.LogInformation("Marking all known migrations as applied because this is a fresh install");
|
||||||
migrationOptions.Applied.AddRange(Migrations.Select(m => (m.Id, m.Name)));
|
migrationOptions.Applied.AddRange(migrations.Select(m => (m.Id, m.Name)));
|
||||||
host.ServerConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions);
|
host.ServerConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var appliedMigrationIds = migrationOptions.Applied.Select(m => m.Id).ToHashSet();
|
var appliedMigrationIds = migrationOptions.Applied.Select(m => m.Id).ToHashSet();
|
||||||
|
|
||||||
for (var i = 0; i < Migrations.Length; i++)
|
for (var i = 0; i < migrations.Length; i++)
|
||||||
{
|
{
|
||||||
var migrationRoutine = Migrations[i];
|
var migrationRoutine = migrations[i];
|
||||||
if (appliedMigrationIds.Contains(migrationRoutine.Id))
|
if (appliedMigrationIds.Contains(migrationRoutine.Id))
|
||||||
{
|
{
|
||||||
logger.LogDebug("Skipping migration '{Name}' since it is already applied", migrationRoutine.Name);
|
logger.LogDebug("Skipping migration '{Name}' since it is already applied", migrationRoutine.Name);
|
||||||
|
@ -55,7 +59,7 @@ namespace Jellyfin.Server.Migrations
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
migrationRoutine.Perform(host, logger);
|
migrationRoutine.Perform();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,6 +36,13 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||||
@"{""Serilog"":{""MinimumLevel"":""Information"",""WriteTo"":[{""Name"":""Console"",""Args"":{""outputTemplate"":""[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}""}},{""Name"":""Async"",""Args"":{""configure"":[{""Name"":""File"",""Args"":{""path"":""%JELLYFIN_LOG_DIR%//log_.log"",""rollingInterval"":""Day"",""retainedFileCountLimit"":3,""rollOnFileSizeLimit"":true,""fileSizeLimitBytes"":100000000,""outputTemplate"":""[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] [{ThreadId}] {SourceContext}:{Message}{NewLine}{Exception}""}}]}}],""Enrich"":[""FromLogContext"",""WithThreadId""]}}",
|
@"{""Serilog"":{""MinimumLevel"":""Information"",""WriteTo"":[{""Name"":""Console"",""Args"":{""outputTemplate"":""[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}""}},{""Name"":""Async"",""Args"":{""configure"":[{""Name"":""File"",""Args"":{""path"":""%JELLYFIN_LOG_DIR%//log_.log"",""rollingInterval"":""Day"",""retainedFileCountLimit"":3,""rollOnFileSizeLimit"":true,""fileSizeLimitBytes"":100000000,""outputTemplate"":""[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] [{ThreadId}] {SourceContext}:{Message}{NewLine}{Exception}""}}]}}],""Enrich"":[""FromLogContext"",""WithThreadId""]}}",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private readonly IApplicationPaths _appPaths;
|
||||||
|
|
||||||
|
public CreateUserLoggingConfigFile(IApplicationPaths appPaths)
|
||||||
|
{
|
||||||
|
_appPaths = appPaths;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Guid Id => Guid.Parse("{EF103419-8451-40D8-9F34-D1A8E93A1679}");
|
public Guid Id => Guid.Parse("{EF103419-8451-40D8-9F34-D1A8E93A1679}");
|
||||||
|
|
||||||
|
@ -43,9 +50,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||||
public string Name => "CreateLoggingConfigHeirarchy";
|
public string Name => "CreateLoggingConfigHeirarchy";
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Perform(CoreAppHost host, ILogger logger)
|
public void Perform()
|
||||||
{
|
{
|
||||||
var logDirectory = host.Resolve<IApplicationPaths>().ConfigurationDirectoryPath;
|
var logDirectory = _appPaths.ConfigurationDirectoryPath;
|
||||||
var existingConfigPath = Path.Combine(logDirectory, "logging.json");
|
var existingConfigPath = Path.Combine(logDirectory, "logging.json");
|
||||||
|
|
||||||
// If the existing logging.json config file is unmodified, then 'reset' it by moving it to 'logging.old.json'
|
// If the existing logging.json config file is unmodified, then 'reset' it by moving it to 'logging.old.json'
|
||||||
|
|
|
@ -10,6 +10,15 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class DisableTranscodingThrottling : IMigrationRoutine
|
internal class DisableTranscodingThrottling : IMigrationRoutine
|
||||||
{
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly IConfigurationManager _configManager;
|
||||||
|
|
||||||
|
public DisableTranscodingThrottling(ILogger<DisableTranscodingThrottling> logger, IConfigurationManager configManager)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_configManager = configManager;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Guid Id => Guid.Parse("{4124C2CD-E939-4FFB-9BE9-9B311C413638}");
|
public Guid Id => Guid.Parse("{4124C2CD-E939-4FFB-9BE9-9B311C413638}");
|
||||||
|
|
||||||
|
@ -17,16 +26,16 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||||
public string Name => "DisableTranscodingThrottling";
|
public string Name => "DisableTranscodingThrottling";
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Perform(CoreAppHost host, ILogger logger)
|
public void Perform()
|
||||||
{
|
{
|
||||||
// Set EnableThrottling to false since it wasn't used before and may introduce issues
|
// Set EnableThrottling to false since it wasn't used before and may introduce issues
|
||||||
var encoding = ((IConfigurationManager)host.ServerConfigurationManager).GetConfiguration<EncodingOptions>("encoding");
|
var encoding = _configManager.GetConfiguration<EncodingOptions>("encoding");
|
||||||
if (encoding.EnableThrottling)
|
if (encoding.EnableThrottling)
|
||||||
{
|
{
|
||||||
logger.LogInformation("Disabling transcoding throttling during migration");
|
_logger.LogInformation("Disabling transcoding throttling during migration");
|
||||||
encoding.EnableThrottling = false;
|
encoding.EnableThrottling = false;
|
||||||
|
|
||||||
host.ServerConfigurationManager.SaveConfiguration("encoding", encoding);
|
_configManager.SaveConfiguration("encoding", encoding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,23 +161,7 @@ namespace Jellyfin.Server
|
||||||
|
|
||||||
ApplicationHost.LogEnvironmentInfo(_logger, appPaths);
|
ApplicationHost.LogEnvironmentInfo(_logger, appPaths);
|
||||||
|
|
||||||
// Make sure we have all the code pages we can get
|
PerformStaticInitialization();
|
||||||
// Ref: https://docs.microsoft.com/en-us/dotnet/api/system.text.codepagesencodingprovider.instance?view=netcore-3.0#remarks
|
|
||||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
|
||||||
|
|
||||||
// Increase the max http request limit
|
|
||||||
// The default connection limit is 10 for ASP.NET hosted applications and 2 for all others.
|
|
||||||
ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
|
|
||||||
|
|
||||||
// Disable the "Expect: 100-Continue" header by default
|
|
||||||
// http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
|
|
||||||
ServicePointManager.Expect100Continue = false;
|
|
||||||
|
|
||||||
Batteries_V2.Init();
|
|
||||||
if (raw.sqlite3_enable_shared_cache(1) != raw.SQLITE_OK)
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Failed to enable shared cache for SQLite");
|
|
||||||
}
|
|
||||||
|
|
||||||
var appHost = new CoreAppHost(
|
var appHost = new CoreAppHost(
|
||||||
appPaths,
|
appPaths,
|
||||||
|
@ -205,7 +189,7 @@ namespace Jellyfin.Server
|
||||||
ServiceCollection serviceCollection = new ServiceCollection();
|
ServiceCollection serviceCollection = new ServiceCollection();
|
||||||
appHost.Init(serviceCollection);
|
appHost.Init(serviceCollection);
|
||||||
|
|
||||||
var webHost = CreateWebHostBuilder(appHost, serviceCollection, options, startupConfig, appPaths).Build();
|
var webHost = new WebHostBuilder().ConfigureWebHostBuilder(appHost, serviceCollection, options, startupConfig, appPaths).Build();
|
||||||
|
|
||||||
// Re-use the web host service provider in the app host since ASP.NET doesn't allow a custom service collection.
|
// Re-use the web host service provider in the app host since ASP.NET doesn't allow a custom service collection.
|
||||||
appHost.ServiceProvider = webHost.Services;
|
appHost.ServiceProvider = webHost.Services;
|
||||||
|
@ -250,14 +234,49 @@ namespace Jellyfin.Server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IWebHostBuilder CreateWebHostBuilder(
|
/// <summary>
|
||||||
|
/// Call static initialization methods for the application.
|
||||||
|
/// </summary>
|
||||||
|
public static void PerformStaticInitialization()
|
||||||
|
{
|
||||||
|
// Make sure we have all the code pages we can get
|
||||||
|
// Ref: https://docs.microsoft.com/en-us/dotnet/api/system.text.codepagesencodingprovider.instance?view=netcore-3.0#remarks
|
||||||
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
|
|
||||||
|
// Increase the max http request limit
|
||||||
|
// The default connection limit is 10 for ASP.NET hosted applications and 2 for all others.
|
||||||
|
ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
|
||||||
|
|
||||||
|
// Disable the "Expect: 100-Continue" header by default
|
||||||
|
// http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
|
||||||
|
ServicePointManager.Expect100Continue = false;
|
||||||
|
|
||||||
|
Batteries_V2.Init();
|
||||||
|
if (raw.sqlite3_enable_shared_cache(1) != raw.SQLITE_OK)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Failed to enable shared cache for SQLite");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configure the web host builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder to configure.</param>
|
||||||
|
/// <param name="appHost">The application host.</param>
|
||||||
|
/// <param name="serviceCollection">The application service collection.</param>
|
||||||
|
/// <param name="commandLineOpts">The command line options passed to the application.</param>
|
||||||
|
/// <param name="startupConfig">The application configuration.</param>
|
||||||
|
/// <param name="appPaths">The application paths.</param>
|
||||||
|
/// <returns>The configured web host builder.</returns>
|
||||||
|
public static IWebHostBuilder ConfigureWebHostBuilder(
|
||||||
|
this IWebHostBuilder builder,
|
||||||
ApplicationHost appHost,
|
ApplicationHost appHost,
|
||||||
IServiceCollection serviceCollection,
|
IServiceCollection serviceCollection,
|
||||||
StartupOptions commandLineOpts,
|
StartupOptions commandLineOpts,
|
||||||
IConfiguration startupConfig,
|
IConfiguration startupConfig,
|
||||||
IApplicationPaths appPaths)
|
IApplicationPaths appPaths)
|
||||||
{
|
{
|
||||||
return new WebHostBuilder()
|
return builder
|
||||||
.UseKestrel((builderContext, options) =>
|
.UseKestrel((builderContext, options) =>
|
||||||
{
|
{
|
||||||
var addresses = appHost.ServerConfigurationManager
|
var addresses = appHost.ServerConfigurationManager
|
||||||
|
@ -278,7 +297,6 @@ namespace Jellyfin.Server
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Kestrel listening on {IpAddress}", address);
|
_logger.LogInformation("Kestrel listening on {IpAddress}", address);
|
||||||
options.Listen(address, appHost.HttpPort);
|
options.Listen(address, appHost.HttpPort);
|
||||||
|
|
||||||
if (appHost.EnableHttps && appHost.Certificate != null)
|
if (appHost.EnableHttps && appHost.Certificate != null)
|
||||||
{
|
{
|
||||||
options.Listen(address, appHost.HttpsPort, listenOptions =>
|
options.Listen(address, appHost.HttpsPort, listenOptions =>
|
||||||
|
@ -288,6 +306,8 @@ namespace Jellyfin.Server
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (builderContext.HostingEnvironment.IsDevelopment())
|
else if (builderContext.HostingEnvironment.IsDevelopment())
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
options.Listen(address, appHost.HttpsPort, listenOptions =>
|
options.Listen(address, appHost.HttpsPort, listenOptions =>
|
||||||
{
|
{
|
||||||
|
@ -295,6 +315,11 @@ namespace Jellyfin.Server
|
||||||
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
|
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Failed to listen to HTTPS using the ASP.NET Core HTTPS development certificate. Please ensure it has been installed and set as trusted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -311,6 +336,8 @@ namespace Jellyfin.Server
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (builderContext.HostingEnvironment.IsDevelopment())
|
else if (builderContext.HostingEnvironment.IsDevelopment())
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
options.ListenAnyIP(appHost.HttpsPort, listenOptions =>
|
options.ListenAnyIP(appHost.HttpsPort, listenOptions =>
|
||||||
{
|
{
|
||||||
|
@ -318,6 +345,11 @@ namespace Jellyfin.Server
|
||||||
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
|
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Failed to listen to HTTPS using the ASP.NET Core HTTPS development certificate. Please ensure it has been installed and set as trusted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.ConfigureAppConfiguration(config => config.ConfigureAppConfiguration(commandLineOpts, appPaths, startupConfig))
|
.ConfigureAppConfiguration(config => config.ConfigureAppConfiguration(commandLineOpts, appPaths, startupConfig))
|
||||||
|
@ -496,7 +528,9 @@ namespace Jellyfin.Server
|
||||||
/// Initialize the logging configuration file using the bundled resource file as a default if it doesn't exist
|
/// Initialize the logging configuration file using the bundled resource file as a default if it doesn't exist
|
||||||
/// already.
|
/// already.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static async Task InitLoggingConfigFile(IApplicationPaths appPaths)
|
/// <param name="appPaths">The application paths.</param>
|
||||||
|
/// <returns>A task representing the creation of the configuration file, or a completed task if the file already exists.</returns>
|
||||||
|
public static async Task InitLoggingConfigFile(IApplicationPaths appPaths)
|
||||||
{
|
{
|
||||||
// Do nothing if the config file already exists
|
// Do nothing if the config file already exists
|
||||||
string configPath = Path.Combine(appPaths.ConfigurationDirectoryPath, LoggingConfigFileDefault);
|
string configPath = Path.Combine(appPaths.ConfigurationDirectoryPath, LoggingConfigFileDefault);
|
||||||
|
@ -516,7 +550,13 @@ namespace Jellyfin.Server
|
||||||
await resource.CopyToAsync(dst).ConfigureAwait(false);
|
await resource.CopyToAsync(dst).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IConfiguration CreateAppConfiguration(StartupOptions commandLineOpts, IApplicationPaths appPaths)
|
/// <summary>
|
||||||
|
/// Create the application configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="commandLineOpts">The command line options passed to the program.</param>
|
||||||
|
/// <param name="appPaths">The application paths.</param>
|
||||||
|
/// <returns>The application configuration.</returns>
|
||||||
|
public static IConfiguration CreateAppConfiguration(StartupOptions commandLineOpts, IApplicationPaths appPaths)
|
||||||
{
|
{
|
||||||
return new ConfigurationBuilder()
|
return new ConfigurationBuilder()
|
||||||
.ConfigureAppConfiguration(commandLineOpts, appPaths)
|
.ConfigureAppConfiguration(commandLineOpts, appPaths)
|
||||||
|
|
|
@ -265,18 +265,21 @@ namespace MediaBrowser.Api.Images
|
||||||
{
|
{
|
||||||
Url = url,
|
Url = url,
|
||||||
BufferContent = false
|
BufferContent = false
|
||||||
|
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
var ext = result.ContentType.Split('/').Last();
|
var ext = result.ContentType.Split('/')[^1];
|
||||||
|
|
||||||
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
|
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
|
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
|
||||||
using (var stream = result.Content)
|
var stream = result.Content;
|
||||||
|
await using (stream.ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
var filestream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true);
|
||||||
|
await using (filestream.ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
using var filestream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true);
|
|
||||||
await stream.CopyToAsync(filestream).ConfigureAwait(false);
|
await stream.CopyToAsync(filestream).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
|
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
|
||||||
File.WriteAllText(pointerCachePath, fullCachePath);
|
File.WriteAllText(pointerCachePath, fullCachePath);
|
||||||
|
|
|
@ -299,23 +299,27 @@ namespace MediaBrowser.Api
|
||||||
{
|
{
|
||||||
var result = await _providerManager.GetSearchImage(providerName, url, CancellationToken.None).ConfigureAwait(false);
|
var result = await _providerManager.GetSearchImage(providerName, url, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
var ext = result.ContentType.Split('/').Last();
|
var ext = result.ContentType.Split('/')[^1];
|
||||||
|
|
||||||
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
|
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
|
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
|
||||||
using (var stream = result.Content)
|
var stream = result.Content;
|
||||||
|
|
||||||
|
await using (stream.ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
using var fileStream = new FileStream(
|
var fileStream = new FileStream(
|
||||||
fullCachePath,
|
fullCachePath,
|
||||||
FileMode.Create,
|
FileMode.Create,
|
||||||
FileAccess.Write,
|
FileAccess.Write,
|
||||||
FileShare.Read,
|
FileShare.Read,
|
||||||
IODefaults.FileStreamBufferSize,
|
IODefaults.FileStreamBufferSize,
|
||||||
true);
|
true);
|
||||||
|
await using (fileStream.ConfigureAwait(false))
|
||||||
|
{
|
||||||
await stream.CopyToAsync(fileStream).ConfigureAwait(false);
|
await stream.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
|
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
|
||||||
File.WriteAllText(pointerCachePath, fullCachePath);
|
File.WriteAllText(pointerCachePath, fullCachePath);
|
||||||
|
|
|
@ -209,13 +209,15 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written
|
// Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written
|
||||||
using var fileStream = GetPlaylistFileStream(playlist);
|
var fileStream = GetPlaylistFileStream(playlist);
|
||||||
|
await using (fileStream.ConfigureAwait(false))
|
||||||
|
{
|
||||||
using var reader = new StreamReader(fileStream);
|
using var reader = new StreamReader(fileStream);
|
||||||
var count = 0;
|
var count = 0;
|
||||||
|
|
||||||
while (!reader.EndOfStream)
|
while (!reader.EndOfStream)
|
||||||
{
|
{
|
||||||
var line = reader.ReadLine();
|
var line = await reader.ReadLineAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
|
if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
|
||||||
{
|
{
|
||||||
|
@ -227,6 +229,8 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
|
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (IOException)
|
catch (IOException)
|
||||||
|
|
|
@ -720,22 +720,203 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
//return state.VideoRequest.VideoBitRate.HasValue;
|
//return state.VideoRequest.VideoBitRate.HasValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the H.26X level of the output video stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">StreamState of the current stream.</param>
|
||||||
|
/// <returns>H.26X level of the output video stream.</returns>
|
||||||
|
private int? GetOutputVideoCodecLevel(StreamState state)
|
||||||
|
{
|
||||||
|
string levelString;
|
||||||
|
if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& state.VideoStream.Level.HasValue)
|
||||||
|
{
|
||||||
|
levelString = state.VideoStream?.Level.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
levelString = state.GetRequestedLevel(state.ActualOutputVideoCodec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (int.TryParse(levelString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedLevel))
|
||||||
|
{
|
||||||
|
return parsedLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a formatted string of the output audio codec, for use in the CODECS field.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="AppendPlaylistCodecsField(StringBuilder, StreamState)"/>
|
||||||
|
/// <seealso cref="GetPlaylistVideoCodecs(StreamState, string, int)"/>
|
||||||
|
/// <param name="state">StreamState of the current stream.</param>
|
||||||
|
/// <returns>Formatted audio codec string.</returns>
|
||||||
|
private string GetPlaylistAudioCodecs(StreamState state)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (string.Equals(state.ActualOutputAudioCodec, "aac", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string profile = state.GetRequestedProfiles("aac").FirstOrDefault();
|
||||||
|
|
||||||
|
return HlsCodecStringFactory.GetAACString(profile);
|
||||||
|
}
|
||||||
|
else if (string.Equals(state.ActualOutputAudioCodec, "mp3", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return HlsCodecStringFactory.GetMP3String();
|
||||||
|
}
|
||||||
|
else if (string.Equals(state.ActualOutputAudioCodec, "ac3", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return HlsCodecStringFactory.GetAC3String();
|
||||||
|
}
|
||||||
|
else if (string.Equals(state.ActualOutputAudioCodec, "eac3", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return HlsCodecStringFactory.GetEAC3String();
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a formatted string of the output video codec, for use in the CODECS field.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="AppendPlaylistCodecsField(StringBuilder, StreamState)"/>
|
||||||
|
/// <seealso cref="GetPlaylistAudioCodecs(StreamState)"/>
|
||||||
|
/// <param name="state">StreamState of the current stream.</param>
|
||||||
|
/// <returns>Formatted video codec string.</returns>
|
||||||
|
private string GetPlaylistVideoCodecs(StreamState state, string codec, int level)
|
||||||
|
{
|
||||||
|
if (level == 0)
|
||||||
|
{
|
||||||
|
// This is 0 when there's no requested H.26X level in the device profile
|
||||||
|
// and the source is not encoded in H.26X
|
||||||
|
Logger.LogError("Got invalid H.26X level when building CODECS field for HLS master playlist");
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string profile = state.GetRequestedProfiles("h264").FirstOrDefault();
|
||||||
|
|
||||||
|
return HlsCodecStringFactory.GetH264String(profile, level);
|
||||||
|
}
|
||||||
|
else if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string profile = state.GetRequestedProfiles("h265").FirstOrDefault();
|
||||||
|
|
||||||
|
return HlsCodecStringFactory.GetH265String(profile, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends a CODECS field containing formatted strings of
|
||||||
|
/// the active streams output video and audio codecs.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="AppendPlaylist(StringBuilder, StreamState, string, int, string)"/>
|
||||||
|
/// <seealso cref="GetPlaylistVideoCodecs(StreamState, string, int)"/>
|
||||||
|
/// <seealso cref="GetPlaylistAudioCodecs(StreamState)"/>
|
||||||
|
/// <param name="builder">StringBuilder to append the field to.</param>
|
||||||
|
/// <param name="state">StreamState of the current stream.</param>
|
||||||
|
private void AppendPlaylistCodecsField(StringBuilder builder, StreamState state)
|
||||||
|
{
|
||||||
|
// Video
|
||||||
|
string videoCodecs = string.Empty;
|
||||||
|
int? videoCodecLevel = GetOutputVideoCodecLevel(state);
|
||||||
|
if (!string.IsNullOrEmpty(state.ActualOutputVideoCodec) && videoCodecLevel.HasValue)
|
||||||
|
{
|
||||||
|
videoCodecs = GetPlaylistVideoCodecs(state, state.ActualOutputVideoCodec, videoCodecLevel.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Audio
|
||||||
|
string audioCodecs = string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(state.ActualOutputAudioCodec))
|
||||||
|
{
|
||||||
|
audioCodecs = GetPlaylistAudioCodecs(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder codecs = new StringBuilder();
|
||||||
|
|
||||||
|
codecs.Append(videoCodecs)
|
||||||
|
.Append(',')
|
||||||
|
.Append(audioCodecs);
|
||||||
|
|
||||||
|
if (codecs.Length > 1)
|
||||||
|
{
|
||||||
|
builder.Append(",CODECS=\"")
|
||||||
|
.Append(codecs)
|
||||||
|
.Append('"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends a FRAME-RATE field containing the framerate of the output stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="AppendPlaylist(StringBuilder, StreamState, string, int, string)"/>
|
||||||
|
/// <param name="builder">StringBuilder to append the field to.</param>
|
||||||
|
/// <param name="state">StreamState of the current stream.</param>
|
||||||
|
private void AppendPlaylistFramerateField(StringBuilder builder, StreamState state)
|
||||||
|
{
|
||||||
|
double? framerate = null;
|
||||||
|
if (state.TargetFramerate.HasValue)
|
||||||
|
{
|
||||||
|
framerate = Math.Round(state.TargetFramerate.GetValueOrDefault(), 3);
|
||||||
|
}
|
||||||
|
else if (state.VideoStream.RealFrameRate.HasValue)
|
||||||
|
{
|
||||||
|
framerate = Math.Round(state.VideoStream.RealFrameRate.GetValueOrDefault(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (framerate.HasValue)
|
||||||
|
{
|
||||||
|
builder.Append(",FRAME-RATE=\"")
|
||||||
|
.Append(framerate.Value)
|
||||||
|
.Append('"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends a RESOLUTION field containing the resolution of the output stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="AppendPlaylist(StringBuilder, StreamState, string, int, string)"/>
|
||||||
|
/// <param name="builder">StringBuilder to append the field to.</param>
|
||||||
|
/// <param name="state">StreamState of the current stream.</param>
|
||||||
|
private void AppendPlaylistResolutionField(StringBuilder builder, StreamState state)
|
||||||
|
{
|
||||||
|
if (state.OutputWidth.HasValue && state.OutputHeight.HasValue)
|
||||||
|
{
|
||||||
|
builder.Append(",RESOLUTION=\"")
|
||||||
|
.Append(state.OutputWidth.GetValueOrDefault())
|
||||||
|
.Append('x')
|
||||||
|
.Append(state.OutputHeight.GetValueOrDefault())
|
||||||
|
.Append('"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void AppendPlaylist(StringBuilder builder, StreamState state, string url, int bitrate, string subtitleGroup)
|
private void AppendPlaylist(StringBuilder builder, StreamState state, string url, int bitrate, string subtitleGroup)
|
||||||
{
|
{
|
||||||
var header = "#EXT-X-STREAM-INF:BANDWIDTH=" + bitrate.ToString(CultureInfo.InvariantCulture) + ",AVERAGE-BANDWIDTH=" + bitrate.ToString(CultureInfo.InvariantCulture);
|
builder.Append("#EXT-X-STREAM-INF:BANDWIDTH=")
|
||||||
|
.Append(bitrate.ToString(CultureInfo.InvariantCulture))
|
||||||
|
.Append(",AVERAGE-BANDWIDTH=")
|
||||||
|
.Append(bitrate.ToString(CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
// tvos wants resolution, codecs, framerate
|
AppendPlaylistCodecsField(builder, state);
|
||||||
//if (state.TargetFramerate.HasValue)
|
|
||||||
//{
|
AppendPlaylistResolutionField(builder, state);
|
||||||
// header += string.Format(",FRAME-RATE=\"{0}\"", state.TargetFramerate.Value.ToString(CultureInfo.InvariantCulture));
|
|
||||||
//}
|
AppendPlaylistFramerateField(builder, state);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(subtitleGroup))
|
if (!string.IsNullOrWhiteSpace(subtitleGroup))
|
||||||
{
|
{
|
||||||
header += string.Format(",SUBTITLES=\"{0}\"", subtitleGroup);
|
builder.Append(",SUBTITLES=\"")
|
||||||
|
.Append(subtitleGroup)
|
||||||
|
.Append('"');
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AppendLine(header);
|
builder.Append(Environment.NewLine);
|
||||||
builder.AppendLine(url);
|
builder.AppendLine(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Playback
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get various codec strings for use in HLS playlists.
|
||||||
|
/// </summary>
|
||||||
|
static class HlsCodecStringFactory
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a MP3 codec string.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>MP3 codec string.</returns>
|
||||||
|
public static string GetMP3String()
|
||||||
|
{
|
||||||
|
return "mp4a.40.34";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an AAC codec string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="profile">AAC profile.</param>
|
||||||
|
/// <returns>AAC codec string.</returns>
|
||||||
|
public static string GetAACString(string profile)
|
||||||
|
{
|
||||||
|
StringBuilder result = new StringBuilder("mp4a", 9);
|
||||||
|
|
||||||
|
if (string.Equals(profile, "HE", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
result.Append(".40.5");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default to LC if profile is invalid
|
||||||
|
result.Append(".40.2");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a H.264 codec string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="profile">H.264 profile.</param>
|
||||||
|
/// <param name="level">H.264 level.</param>
|
||||||
|
/// <returns>H.264 string.</returns>
|
||||||
|
public static string GetH264String(string profile, int level)
|
||||||
|
{
|
||||||
|
StringBuilder result = new StringBuilder("avc1", 11);
|
||||||
|
|
||||||
|
if (string.Equals(profile, "high", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
result.Append(".6400");
|
||||||
|
}
|
||||||
|
else if (string.Equals(profile, "main", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
result.Append(".4D40");
|
||||||
|
}
|
||||||
|
else if (string.Equals(profile, "baseline", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
result.Append(".42E0");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default to constrained baseline if profile is invalid
|
||||||
|
result.Append(".4240");
|
||||||
|
}
|
||||||
|
|
||||||
|
string levelHex = level.ToString("X2");
|
||||||
|
result.Append(levelHex);
|
||||||
|
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a H.265 codec string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="profile">H.265 profile.</param>
|
||||||
|
/// <param name="level">H.265 level.</param>
|
||||||
|
/// <returns>H.265 string.</returns>
|
||||||
|
public static string GetH265String(string profile, int level)
|
||||||
|
{
|
||||||
|
// The h265 syntax is a bit of a mystery at the time this comment was written.
|
||||||
|
// This is what I've found through various sources:
|
||||||
|
// FORMAT: [codecTag].[profile].[constraint?].L[level * 30].[UNKNOWN]
|
||||||
|
StringBuilder result = new StringBuilder("hev1", 16);
|
||||||
|
|
||||||
|
if (string.Equals(profile, "main10", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
result.Append(".2.6");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default to main if profile is invalid
|
||||||
|
result.Append(".1.6");
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Append(".L")
|
||||||
|
.Append(level * 3)
|
||||||
|
.Append(".B0");
|
||||||
|
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an AC-3 codec string.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>AC-3 codec string.</returns>
|
||||||
|
public static string GetAC3String()
|
||||||
|
{
|
||||||
|
return "mp4a.a5";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an E-AC-3 codec string.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>E-AC-3 codec string.</returns>
|
||||||
|
public static string GetEAC3String()
|
||||||
|
{
|
||||||
|
return "mp4a.a6";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ namespace MediaBrowser.Api
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Users/Public", "GET", Summary = "Gets a list of publicly visible users for display on a login screen.")]
|
[Route("/Users/Public", "GET", Summary = "Gets a list of publicly visible users for display on a login screen.")]
|
||||||
public class GetPublicUsers : IReturn<UserDto[]>
|
public class GetPublicUsers : IReturn<PublicUserDto[]>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,22 +267,38 @@ namespace MediaBrowser.Api
|
||||||
_authContext = authContext;
|
_authContext = authContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the public available Users information
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The request.</param>
|
||||||
|
/// <returns>System.Object.</returns>
|
||||||
public object Get(GetPublicUsers request)
|
public object Get(GetPublicUsers request)
|
||||||
{
|
{
|
||||||
// If the startup wizard hasn't been completed then just return all users
|
var result = _userManager
|
||||||
if (!ServerConfigurationManager.Configuration.IsStartupWizardCompleted)
|
.Users
|
||||||
|
.Where(item => !item.Policy.IsDisabled);
|
||||||
|
|
||||||
|
if (ServerConfigurationManager.Configuration.IsStartupWizardCompleted)
|
||||||
{
|
{
|
||||||
return Get(new GetUsers
|
var deviceId = _authContext.GetAuthorizationInfo(Request).DeviceId;
|
||||||
|
result = result.Where(item => !item.Policy.IsHidden);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(deviceId))
|
||||||
{
|
{
|
||||||
IsDisabled = false
|
result = result.Where(i => _deviceManager.CanAccessDevice(i, deviceId));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Get(new GetUsers
|
if (!_networkManager.IsInLocalNetwork(Request.RemoteIp))
|
||||||
{
|
{
|
||||||
IsHidden = false,
|
result = result.Where(i => i.Policy.EnableRemoteAccess);
|
||||||
IsDisabled = false
|
}
|
||||||
}, true, true);
|
}
|
||||||
|
|
||||||
|
return ToOptimizedResult(result
|
||||||
|
.OrderBy(u => u.Name)
|
||||||
|
.Select(i => _userManager.GetPublicUserDto(i, Request.RemoteIp))
|
||||||
|
.ToArray()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -141,6 +141,14 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <returns>UserDto.</returns>
|
/// <returns>UserDto.</returns>
|
||||||
UserDto GetUserDto(User user, string remoteEndPoint = null);
|
UserDto GetUserDto(User user, string remoteEndPoint = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the user public dto.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">Ther user.</param>\
|
||||||
|
/// <param name="remoteEndPoint">The remote end point.</param>
|
||||||
|
/// <returns>A public UserDto, aka a UserDto stripped of personal data.</returns>
|
||||||
|
PublicUserDto GetPublicUserDto(User user, string remoteEndPoint = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Authenticates the user.
|
/// Authenticates the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
|
@ -57,7 +57,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
foreach (var val in codec)
|
foreach (var val in codec)
|
||||||
{
|
{
|
||||||
if (ListHelper.ContainsIgnoreCase(codecs, val))
|
if (codecs.Contains(val, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
|
@ -167,9 +167,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
switch (condition.Condition)
|
switch (condition.Condition)
|
||||||
{
|
{
|
||||||
case ProfileConditionType.EqualsAny:
|
case ProfileConditionType.EqualsAny:
|
||||||
{
|
return expected.Split('|').Contains(currentValue, StringComparer.OrdinalIgnoreCase);
|
||||||
return ListHelper.ContainsIgnoreCase(expected.Split('|'), currentValue);
|
|
||||||
}
|
|
||||||
case ProfileConditionType.Equals:
|
case ProfileConditionType.Equals:
|
||||||
return string.Equals(currentValue, expected, StringComparison.OrdinalIgnoreCase);
|
return string.Equals(currentValue, expected, StringComparison.OrdinalIgnoreCase);
|
||||||
case ProfileConditionType.NotEquals:
|
case ProfileConditionType.NotEquals:
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
|
@ -45,7 +45,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
public static bool ContainsContainer(string profileContainers, string inputContainer)
|
public static bool ContainsContainer(string profileContainers, string inputContainer)
|
||||||
{
|
{
|
||||||
var isNegativeList = false;
|
var isNegativeList = false;
|
||||||
if (profileContainers != null && profileContainers.StartsWith("-"))
|
if (profileContainers != null && profileContainers.StartsWith("-", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
isNegativeList = true;
|
isNegativeList = true;
|
||||||
profileContainers = profileContainers.Substring(1);
|
profileContainers = profileContainers.Substring(1);
|
||||||
|
@ -72,7 +72,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
foreach (var container in allInputContainers)
|
foreach (var container in allInputContainers)
|
||||||
{
|
{
|
||||||
if (ListHelper.ContainsIgnoreCase(profileContainers, container))
|
if (profileContainers.Contains(container, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
foreach (var container in allInputContainers)
|
foreach (var container in allInputContainers)
|
||||||
{
|
{
|
||||||
if (ListHelper.ContainsIgnoreCase(profileContainers, container))
|
if (profileContainers.Contains(container, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
|
@ -93,14 +93,14 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
public DeviceProfile()
|
public DeviceProfile()
|
||||||
{
|
{
|
||||||
DirectPlayProfiles = new DirectPlayProfile[] { };
|
DirectPlayProfiles = Array.Empty<DirectPlayProfile>();
|
||||||
TranscodingProfiles = new TranscodingProfile[] { };
|
TranscodingProfiles = Array.Empty<TranscodingProfile>();
|
||||||
ResponseProfiles = new ResponseProfile[] { };
|
ResponseProfiles = Array.Empty<ResponseProfile>();
|
||||||
CodecProfiles = new CodecProfile[] { };
|
CodecProfiles = Array.Empty<CodecProfile>();
|
||||||
ContainerProfiles = new ContainerProfile[] { };
|
ContainerProfiles = Array.Empty<ContainerProfile>();
|
||||||
SubtitleProfiles = Array.Empty<SubtitleProfile>();
|
SubtitleProfiles = Array.Empty<SubtitleProfile>();
|
||||||
|
|
||||||
XmlRootAttributes = new XmlAttribute[] { };
|
XmlRootAttributes = Array.Empty<XmlAttribute>();
|
||||||
|
|
||||||
SupportedMediaTypes = "Audio,Photo,Video";
|
SupportedMediaTypes = "Audio,Photo,Video";
|
||||||
MaxStreamingBitrate = 8000000;
|
MaxStreamingBitrate = 8000000;
|
||||||
|
@ -129,13 +129,14 @@ namespace MediaBrowser.Model.Dlna
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ListHelper.ContainsIgnoreCase(i.GetAudioCodecs(), audioCodec ?? string.Empty))
|
if (!i.GetAudioCodecs().Contains(audioCodec ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +156,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ListHelper.ContainsIgnoreCase(i.GetAudioCodecs(), audioCodec ?? string.Empty))
|
if (!i.GetAudioCodecs().Contains(audioCodec ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +186,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
|
|
||||||
var audioCodecs = i.GetAudioCodecs();
|
var audioCodecs = i.GetAudioCodecs();
|
||||||
if (audioCodecs.Length > 0 && !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec ?? string.Empty))
|
if (audioCodecs.Length > 0 && !audioCodecs.Contains(audioCodec ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -288,13 +289,13 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
|
|
||||||
var audioCodecs = i.GetAudioCodecs();
|
var audioCodecs = i.GetAudioCodecs();
|
||||||
if (audioCodecs.Length > 0 && !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec ?? string.Empty))
|
if (audioCodecs.Length > 0 && !audioCodecs.Contains(audioCodec ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var videoCodecs = i.GetVideoCodecs();
|
var videoCodecs = i.GetVideoCodecs();
|
||||||
if (videoCodecs.Length > 0 && !ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec ?? string.Empty))
|
if (videoCodecs.Length > 0 && !videoCodecs.Contains(videoCodec ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
|
@ -40,7 +41,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
|
|
||||||
var languages = GetLanguages();
|
var languages = GetLanguages();
|
||||||
return languages.Length == 0 || ListHelper.ContainsIgnoreCase(languages, subLanguage);
|
return languages.Length == 0 || languages.Contains(subLanguage, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Model.Dto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class PublicUserDto. Its goal is to show only public information about a user
|
||||||
|
/// </summary>
|
||||||
|
public class PublicUserDto : IItemDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the primary image tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The primary image tag.</value>
|
||||||
|
public string PrimaryImageTag { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this instance has password.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance has password; otherwise, <c>false</c>.</value>
|
||||||
|
public bool HasPassword { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this instance has configured password.
|
||||||
|
/// Note that in this case this method should not be here, but it is necessary when changing password at the
|
||||||
|
/// first login.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance has configured password; otherwise, <c>false</c>.</value>
|
||||||
|
public bool HasConfiguredPassword { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the primary image aspect ratio.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The primary image aspect ratio.</value>
|
||||||
|
public double? PrimaryImageAspectRatio { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Name ?? base.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,27 +0,0 @@
|
||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Extensions
|
|
||||||
{
|
|
||||||
// TODO: @bond remove
|
|
||||||
public static class ListHelper
|
|
||||||
{
|
|
||||||
public static bool ContainsIgnoreCase(string[] list, string value)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
if (string.Equals(item, value, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue