Merge branch 'master' into RemoteAccessFix
This commit is contained in:
commit
5d16d1f66d
|
@ -160,7 +160,6 @@ jobs:
|
||||||
dependsOn:
|
dependsOn:
|
||||||
- BuildPackage
|
- BuildPackage
|
||||||
- BuildDocker
|
- BuildDocker
|
||||||
condition: and(succeeded('BuildPackage'), succeeded('BuildDocker'))
|
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-latest'
|
vmImage: 'ubuntu-latest'
|
||||||
|
@ -186,9 +185,6 @@ jobs:
|
||||||
|
|
||||||
- job: PublishNuget
|
- job: PublishNuget
|
||||||
displayName: 'Publish NuGet packages'
|
displayName: 'Publish NuGet packages'
|
||||||
dependsOn:
|
|
||||||
- BuildPackage
|
|
||||||
condition: succeeded('BuildPackage')
|
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-latest'
|
vmImage: 'ubuntu-latest'
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Emby.Dlna
|
||||||
private readonly ILogger<DlnaManager> _logger;
|
private readonly ILogger<DlnaManager> _logger;
|
||||||
private readonly IServerApplicationHost _appHost;
|
private readonly IServerApplicationHost _appHost;
|
||||||
private static readonly Assembly _assembly = typeof(DlnaManager).Assembly;
|
private static readonly Assembly _assembly = typeof(DlnaManager).Assembly;
|
||||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
|
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||||
|
|
||||||
private readonly Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>> _profiles = new Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>>(StringComparer.Ordinal);
|
private readonly Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>> _profiles = new Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>>(StringComparer.Ordinal);
|
||||||
|
|
||||||
|
@ -333,7 +333,12 @@ namespace Emby.Dlna
|
||||||
throw new ArgumentNullException(nameof(id));
|
throw new ArgumentNullException(nameof(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
var info = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, id, StringComparison.OrdinalIgnoreCase));
|
var info = GetProfileInfosInternal().FirstOrDefault(i => string.Equals(i.Info.Id, id, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (info == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return ParseProfileFile(info.Path, info.Info.Type);
|
return ParseProfileFile(info.Path, info.Info.Type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,8 @@ namespace Emby.Dlna.Main
|
||||||
|
|
||||||
_netConfig = config.GetConfiguration<NetworkConfiguration>("network");
|
_netConfig = config.GetConfiguration<NetworkConfiguration>("network");
|
||||||
_disabled = appHost.ListenWithHttps && _netConfig.RequireHttps;
|
_disabled = appHost.ListenWithHttps && _netConfig.RequireHttps;
|
||||||
if (_disabled)
|
|
||||||
|
if (_disabled && _config.GetDlnaConfiguration().EnableServer)
|
||||||
{
|
{
|
||||||
_logger.LogError("The DLNA specification does not support HTTPS.");
|
_logger.LogError("The DLNA specification does not support HTTPS.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace Emby.Dlna.Ssdp
|
||||||
{
|
{
|
||||||
lock (_syncLock)
|
lock (_syncLock)
|
||||||
{
|
{
|
||||||
if (_listenerCount > 0 && _deviceLocator == null)
|
if (_listenerCount > 0 && _deviceLocator == null && _commsServer != null)
|
||||||
{
|
{
|
||||||
_deviceLocator = new SsdpDeviceLocator(_commsServer);
|
_deviceLocator = new SsdpDeviceLocator(_commsServer);
|
||||||
|
|
||||||
|
|
|
@ -352,8 +352,13 @@ namespace Emby.Drawing
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetImageCacheTag(User user)
|
public string? GetImageCacheTag(User user)
|
||||||
{
|
{
|
||||||
|
if (user.ProfileImage == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (user.ProfileImage.Path + user.ProfileImage.LastModified.Ticks).GetMD5()
|
return (user.ProfileImage.Path + user.ProfileImage.LastModified.Ticks).GetMD5()
|
||||||
.ToString("N", CultureInfo.InvariantCulture);
|
.ToString("N", CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace Emby.Naming.Video
|
namespace Emby.Naming.Video
|
||||||
|
@ -16,8 +17,14 @@ namespace Emby.Naming.Video
|
||||||
/// <param name="expressions">List of regex to parse name and year from.</param>
|
/// <param name="expressions">List of regex to parse name and year from.</param>
|
||||||
/// <param name="newName">Parsing result string.</param>
|
/// <param name="newName">Parsing result string.</param>
|
||||||
/// <returns>True if parsing was successful.</returns>
|
/// <returns>True if parsing was successful.</returns>
|
||||||
public static bool TryClean(string name, IReadOnlyList<Regex> expressions, out ReadOnlySpan<char> newName)
|
public static bool TryClean([NotNullWhen(true)] string? name, IReadOnlyList<Regex> expressions, out ReadOnlySpan<char> newName)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
newName = ReadOnlySpan<char>.Empty;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var len = expressions.Count;
|
var len = expressions.Count;
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
|
@ -33,12 +40,6 @@ namespace Emby.Naming.Video
|
||||||
|
|
||||||
private static bool TryClean(string name, Regex expression, out ReadOnlySpan<char> newName)
|
private static bool TryClean(string name, Regex expression, out ReadOnlySpan<char> newName)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name))
|
|
||||||
{
|
|
||||||
newName = ReadOnlySpan<char>.Empty;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var match = expression.Match(name);
|
var match = expression.Match(name);
|
||||||
int index = match.Index;
|
int index = match.Index;
|
||||||
if (match.Success && index != 0)
|
if (match.Success && index != 0)
|
||||||
|
|
|
@ -221,20 +221,21 @@ namespace Emby.Naming.Video
|
||||||
string testFilename = Path.GetFileNameWithoutExtension(testFilePath);
|
string testFilename = Path.GetFileNameWithoutExtension(testFilePath);
|
||||||
if (testFilename.StartsWith(folderName, StringComparison.OrdinalIgnoreCase))
|
if (testFilename.StartsWith(folderName, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (CleanStringParser.TryClean(testFilename, _options.CleanStringRegexes, out var cleanName))
|
// Remove the folder name before cleaning as we don't care about cleaning that part
|
||||||
{
|
|
||||||
testFilename = cleanName.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (folderName.Length <= testFilename.Length)
|
if (folderName.Length <= testFilename.Length)
|
||||||
{
|
{
|
||||||
testFilename = testFilename.Substring(folderName.Length).Trim();
|
testFilename = testFilename.Substring(folderName.Length).Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CleanStringParser.TryClean(testFilename, _options.CleanStringRegexes, out var cleanName))
|
||||||
|
{
|
||||||
|
testFilename = cleanName.Trim().ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The CleanStringParser should have removed common keywords etc.
|
||||||
return string.IsNullOrEmpty(testFilename)
|
return string.IsNullOrEmpty(testFilename)
|
||||||
|| testFilename[0] == '-'
|
|| testFilename[0] == '-'
|
||||||
|| testFilename[0] == '_'
|
|| Regex.IsMatch(testFilename, @"^\[([^]]*)\]");
|
||||||
|| string.IsNullOrWhiteSpace(Regex.Replace(testFilename, @"\[([^]]*)\]", string.Empty));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Emby.Naming.Common;
|
using Emby.Naming.Common;
|
||||||
|
@ -146,7 +147,7 @@ namespace Emby.Naming.Video
|
||||||
/// <param name="name">Raw name.</param>
|
/// <param name="name">Raw name.</param>
|
||||||
/// <param name="newName">Clean name.</param>
|
/// <param name="newName">Clean name.</param>
|
||||||
/// <returns>True if cleaning of name was successful.</returns>
|
/// <returns>True if cleaning of name was successful.</returns>
|
||||||
public bool TryCleanString(string name, out ReadOnlySpan<char> newName)
|
public bool TryCleanString([NotNullWhen(true)] string? name, out ReadOnlySpan<char> newName)
|
||||||
{
|
{
|
||||||
return CleanStringParser.TryClean(name, _options.CleanStringRegexes, out newName);
|
return CleanStringParser.TryClean(name, _options.CleanStringRegexes, out newName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,6 @@ using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Emby.Dlna;
|
using Emby.Dlna;
|
||||||
|
@ -51,7 +49,6 @@ using Jellyfin.Networking.Manager;
|
||||||
using MediaBrowser.Common;
|
using MediaBrowser.Common;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Events;
|
using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Common.Json;
|
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Common.Plugins;
|
using MediaBrowser.Common.Plugins;
|
||||||
using MediaBrowser.Common.Updates;
|
using MediaBrowser.Common.Updates;
|
||||||
|
@ -470,7 +467,7 @@ namespace Emby.Server.Implementations
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IReadOnlyCollection<T> GetExports<T>(CreationDelegate defaultFunc, bool manageLifetime = true)
|
public IReadOnlyCollection<T> GetExports<T>(CreationDelegateFactory defaultFunc, bool manageLifetime = true)
|
||||||
{
|
{
|
||||||
// Convert to list so this isn't executed for each iteration
|
// Convert to list so this isn't executed for each iteration
|
||||||
var parts = GetExportTypes<T>()
|
var parts = GetExportTypes<T>()
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace Emby.Server.Implementations.Channels
|
||||||
private readonly IProviderManager _providerManager;
|
private readonly IProviderManager _providerManager;
|
||||||
private readonly IMemoryCache _memoryCache;
|
private readonly IMemoryCache _memoryCache;
|
||||||
private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1);
|
||||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
|
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ChannelManager"/> class.
|
/// Initializes a new instance of the <see cref="ChannelManager"/> class.
|
||||||
|
|
|
@ -344,7 +344,20 @@ namespace Emby.Server.Implementations.Collections
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
results[item.Id] = item;
|
var alreadyInResults = false;
|
||||||
|
foreach (var child in item.GetMediaSources(true))
|
||||||
|
{
|
||||||
|
if (Guid.TryParse(child.Id, out var id) && results.ContainsKey(id))
|
||||||
|
{
|
||||||
|
alreadyInResults = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alreadyInResults)
|
||||||
|
{
|
||||||
|
results[item.Id] = item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
_imageProcessor = imageProcessor;
|
_imageProcessor = imageProcessor;
|
||||||
|
|
||||||
_typeMapper = new TypeMapper();
|
_typeMapper = new TypeMapper();
|
||||||
_jsonOptions = JsonDefaults.GetOptions();
|
_jsonOptions = JsonDefaults.Options;
|
||||||
|
|
||||||
DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
|
DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
|
||||||
<PackageReference Include="Mono.Nat" Version="3.0.1" />
|
<PackageReference Include="Mono.Nat" Version="3.0.1" />
|
||||||
<PackageReference Include="prometheus-net.DotNetRuntime" Version="3.4.1" />
|
<PackageReference Include="prometheus-net.DotNetRuntime" Version="3.4.1" />
|
||||||
<PackageReference Include="sharpcompress" Version="0.28.1" />
|
<PackageReference Include="sharpcompress" Version="0.28.1" />
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
RemoteEndPoint = remoteEndPoint;
|
RemoteEndPoint = remoteEndPoint;
|
||||||
QueryString = query;
|
QueryString = query;
|
||||||
|
|
||||||
_jsonOptions = JsonDefaults.GetOptions();
|
_jsonOptions = JsonDefaults.Options;
|
||||||
LastActivityDate = DateTime.Now;
|
LastActivityDate = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IApplicationPaths _appPaths;
|
private readonly IApplicationPaths _appPaths;
|
||||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
|
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||||
|
|
||||||
public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger, IApplicationPaths appPaths)
|
public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger, IApplicationPaths appPaths)
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, ILiveStream> _openStreams = new ConcurrentDictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase);
|
private readonly ConcurrentDictionary<string, ILiveStream> _openStreams = new ConcurrentDictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase);
|
||||||
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
|
||||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
|
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||||
|
|
||||||
private IMediaSourceProvider[] _providers;
|
private IMediaSourceProvider[] _providers;
|
||||||
|
|
||||||
|
|
|
@ -59,11 +59,18 @@ namespace Emby.Server.Implementations.Library
|
||||||
/// <param name="newPath">The result of the sub path replacement</param>
|
/// <param name="newPath">The result of the sub path replacement</param>
|
||||||
/// <returns>The path after replacing the sub path.</returns>
|
/// <returns>The path after replacing the sub path.</returns>
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="path" />, <paramref name="newSubPath" /> or <paramref name="newSubPath" /> is empty.</exception>
|
/// <exception cref="ArgumentNullException"><paramref name="path" />, <paramref name="newSubPath" /> or <paramref name="newSubPath" /> is empty.</exception>
|
||||||
public static bool TryReplaceSubPath(this string path, string subPath, string newSubPath, [NotNullWhen(true)] out string? newPath)
|
public static bool TryReplaceSubPath(
|
||||||
|
[NotNullWhen(true)] this string? path,
|
||||||
|
[NotNullWhen(true)] string? subPath,
|
||||||
|
[NotNullWhen(true)] string? newSubPath,
|
||||||
|
[NotNullWhen(true)] out string? newPath)
|
||||||
{
|
{
|
||||||
newPath = null;
|
newPath = null;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(path) || string.IsNullOrEmpty(subPath) || string.IsNullOrEmpty(newSubPath) || subPath.Length > path.Length)
|
if (string.IsNullOrEmpty(path)
|
||||||
|
|| string.IsNullOrEmpty(subPath)
|
||||||
|
|| string.IsNullOrEmpty(newSubPath)
|
||||||
|
|| subPath.Length > path.Length)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="args">The args.</param>
|
/// <param name="args">The args.</param>
|
||||||
/// <returns>`0.</returns>
|
/// <returns>`0.</returns>
|
||||||
protected override T Resolve(ItemResolveArgs args)
|
public override T Resolve(ItemResolveArgs args)
|
||||||
{
|
{
|
||||||
return ResolveVideo<T>(args, false);
|
return ResolveVideo<T>(args, false);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||||
/// <param name="args">The args.</param>
|
/// <param name="args">The args.</param>
|
||||||
/// <param name="parseName">if set to <c>true</c> [parse name].</param>
|
/// <param name="parseName">if set to <c>true</c> [parse name].</param>
|
||||||
/// <returns>``0.</returns>
|
/// <returns>``0.</returns>
|
||||||
protected TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName)
|
protected virtual TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName)
|
||||||
where TVideoType : Video, new()
|
where TVideoType : Video, new()
|
||||||
{
|
{
|
||||||
var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
|
var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
|
||||||
{
|
{
|
||||||
private readonly string[] _validExtensions = { ".azw", ".azw3", ".cb7", ".cbr", ".cbt", ".cbz", ".epub", ".mobi", ".pdf" };
|
private readonly string[] _validExtensions = { ".azw", ".azw3", ".cb7", ".cbr", ".cbt", ".cbz", ".epub", ".mobi", ".pdf" };
|
||||||
|
|
||||||
protected override Book Resolve(ItemResolveArgs args)
|
public override Book Resolve(ItemResolveArgs args)
|
||||||
{
|
{
|
||||||
var collectionType = args.GetCollectionType();
|
var collectionType = args.GetCollectionType();
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,110 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resolves the specified args.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The args.</param>
|
||||||
|
/// <returns>Video.</returns>
|
||||||
|
public override Video Resolve(ItemResolveArgs args)
|
||||||
|
{
|
||||||
|
var collectionType = args.GetCollectionType();
|
||||||
|
|
||||||
|
// Find movies with their own folders
|
||||||
|
if (args.IsDirectory)
|
||||||
|
{
|
||||||
|
if (IsInvalid(args.Parent, collectionType))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var files = args.FileSystemChildren
|
||||||
|
.Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return FindMovie<MusicVideo>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return FindMovie<Video>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(collectionType))
|
||||||
|
{
|
||||||
|
// Owned items will be caught by the plain video resolver
|
||||||
|
if (args.Parent == null)
|
||||||
|
{
|
||||||
|
// return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.HasParent<Series>())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
return FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle owned items
|
||||||
|
if (args.Parent == null)
|
||||||
|
{
|
||||||
|
return base.Resolve(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsInvalid(args.Parent, collectionType))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Video item = null;
|
||||||
|
|
||||||
|
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
item = ResolveVideo<MusicVideo>(args, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// To find a movie file, the collection type must be movies or boxsets
|
||||||
|
else if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
item = ResolveVideo<Movie>(args, true);
|
||||||
|
}
|
||||||
|
else if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
item = ResolveVideo<Video>(args, false);
|
||||||
|
}
|
||||||
|
else if (string.IsNullOrEmpty(collectionType))
|
||||||
|
{
|
||||||
|
if (args.HasParent<Series>())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = ResolveVideo<Video>(args, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
item.IsInMixedFolder = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
private MultiItemResolverResult ResolveMultipleInternal(
|
private MultiItemResolverResult ResolveMultipleInternal(
|
||||||
Folder parent,
|
Folder parent,
|
||||||
List<FileSystemMetadata> files,
|
List<FileSystemMetadata> files,
|
||||||
|
@ -216,110 +320,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
||||||
return string.Equals(result.Path, file.FullName, StringComparison.OrdinalIgnoreCase);
|
return string.Equals(result.Path, file.FullName, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resolves the specified args.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">The args.</param>
|
|
||||||
/// <returns>Video.</returns>
|
|
||||||
protected override Video Resolve(ItemResolveArgs args)
|
|
||||||
{
|
|
||||||
var collectionType = args.GetCollectionType();
|
|
||||||
|
|
||||||
// Find movies with their own folders
|
|
||||||
if (args.IsDirectory)
|
|
||||||
{
|
|
||||||
if (IsInvalid(args.Parent, collectionType))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var files = args.FileSystemChildren
|
|
||||||
.Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return FindMovie<MusicVideo>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return FindMovie<Video>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(collectionType))
|
|
||||||
{
|
|
||||||
// Owned items will be caught by the plain video resolver
|
|
||||||
if (args.Parent == null)
|
|
||||||
{
|
|
||||||
// return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.HasParent<Series>())
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
return FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle owned items
|
|
||||||
if (args.Parent == null)
|
|
||||||
{
|
|
||||||
return base.Resolve(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsInvalid(args.Parent, collectionType))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Video item = null;
|
|
||||||
|
|
||||||
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
item = ResolveVideo<MusicVideo>(args, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// To find a movie file, the collection type must be movies or boxsets
|
|
||||||
else if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
item = ResolveVideo<Movie>(args, true);
|
|
||||||
}
|
|
||||||
else if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
item = ResolveVideo<Video>(args, false);
|
|
||||||
}
|
|
||||||
else if (string.IsNullOrEmpty(collectionType))
|
|
||||||
{
|
|
||||||
if (args.HasParent<Series>())
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = ResolveVideo<Video>(args, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
item.IsInMixedFolder = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the initial item values.
|
/// Sets the initial item values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
@ -11,12 +12,21 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EpisodeResolver : BaseVideoResolver<Episode>
|
public class EpisodeResolver : BaseVideoResolver<Episode>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EpisodeResolver"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
|
public EpisodeResolver(ILibraryManager libraryManager)
|
||||||
|
: base(libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resolves the specified args.
|
/// Resolves the specified args.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="args">The args.</param>
|
/// <param name="args">The args.</param>
|
||||||
/// <returns>Episode.</returns>
|
/// <returns>Episode.</returns>
|
||||||
protected override Episode Resolve(ItemResolveArgs args)
|
public override Episode Resolve(ItemResolveArgs args)
|
||||||
{
|
{
|
||||||
var parent = args.Parent;
|
var parent = args.Parent;
|
||||||
|
|
||||||
|
@ -34,11 +44,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
||||||
season = parent.GetParents().OfType<Season>().FirstOrDefault();
|
season = parent.GetParents().OfType<Season>().FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something
|
// If the parent is a Season or Series and the parent is not an extras folder, then this is an Episode if the VideoResolver returns something
|
||||||
// Also handle flat tv folders
|
// Also handle flat tv folders
|
||||||
if (season != null ||
|
if ((season != null ||
|
||||||
string.Equals(args.GetCollectionType(), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) ||
|
string.Equals(args.GetCollectionType(), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) ||
|
||||||
args.HasParent<Series>())
|
args.HasParent<Series>())
|
||||||
|
&& (parent is Series || !BaseItem.AllExtrasTypesFolderNames.Contains(parent.Name, StringComparer.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
var episode = ResolveVideo<Episode>(args, false);
|
var episode = ResolveVideo<Episode>(args, false);
|
||||||
|
|
||||||
|
@ -74,14 +85,5 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="EpisodeResolver"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="libraryManager">The library manager.</param>
|
|
||||||
public EpisodeResolver(ILibraryManager libraryManager)
|
|
||||||
: base(libraryManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
private readonly IServerApplicationPaths _appPaths;
|
private readonly IServerApplicationPaths _appPaths;
|
||||||
private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>();
|
private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>();
|
||||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
|
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||||
private bool _hasExited;
|
private bool _hasExited;
|
||||||
private Stream _logFileStream;
|
private Stream _logFileStream;
|
||||||
private string _targetPath;
|
private string _targetPath;
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
{
|
{
|
||||||
private readonly string _dataPath;
|
private readonly string _dataPath;
|
||||||
private readonly object _fileDataLock = new object();
|
private readonly object _fileDataLock = new object();
|
||||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
|
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||||
private T[] _items;
|
private T[] _items;
|
||||||
|
|
||||||
public ItemDataProvider(
|
public ItemDataProvider(
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||||
private readonly ICryptoProvider _cryptoProvider;
|
private readonly ICryptoProvider _cryptoProvider;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>();
|
private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>();
|
||||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
|
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||||
private DateTime _lastErrorResponse;
|
private DateTime _lastErrorResponse;
|
||||||
|
|
||||||
public SchedulesDirect(
|
public SchedulesDirect(
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
_streamHelper = streamHelper;
|
_streamHelper = streamHelper;
|
||||||
|
|
||||||
_jsonOptions = JsonDefaults.GetOptions();
|
_jsonOptions = JsonDefaults.Options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name => "HD Homerun";
|
public string Name => "HD Homerun";
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Buffers.Binary;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
@ -10,6 +11,7 @@ using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Common;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
|
@ -120,13 +122,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
|
|
||||||
private static async Task<bool> CheckTunerAvailability(NetworkStream stream, int tuner, CancellationToken cancellationToken)
|
private static async Task<bool> CheckTunerAvailability(NetworkStream stream, int tuner, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var lockkeyMsg = CreateGetMessage(tuner, "lockkey");
|
|
||||||
await stream.WriteAsync(lockkeyMsg, 0, lockkeyMsg.Length, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(8192);
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(8192);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int receivedBytes = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
|
var msgLen = WriteGetMessage(buffer, tuner, "lockkey");
|
||||||
|
await stream.WriteAsync(buffer.AsMemory(0, msgLen), cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
int receivedBytes = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
ParseReturnMessage(buffer, receivedBytes, out string returnVal);
|
ParseReturnMessage(buffer, receivedBytes, out string returnVal);
|
||||||
|
|
||||||
|
@ -166,9 +168,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
|
|
||||||
_activeTuner = i;
|
_activeTuner = i;
|
||||||
var lockKeyString = string.Format(CultureInfo.InvariantCulture, "{0:d}", lockKeyValue);
|
var lockKeyString = string.Format(CultureInfo.InvariantCulture, "{0:d}", lockKeyValue);
|
||||||
var lockkeyMsg = CreateSetMessage(i, "lockkey", lockKeyString, null);
|
var lockkeyMsgLen = WriteSetMessage(buffer, i, "lockkey", lockKeyString, null);
|
||||||
await stream.WriteAsync(lockkeyMsg, 0, lockkeyMsg.Length, cancellationToken).ConfigureAwait(false);
|
await stream.WriteAsync(buffer.AsMemory(0, lockkeyMsgLen), cancellationToken).ConfigureAwait(false);
|
||||||
int receivedBytes = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
|
int receivedBytes = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// parse response to make sure it worked
|
// parse response to make sure it worked
|
||||||
if (!ParseReturnMessage(buffer, receivedBytes, out _))
|
if (!ParseReturnMessage(buffer, receivedBytes, out _))
|
||||||
|
@ -178,9 +180,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
|
|
||||||
foreach (var command in commands.GetCommands())
|
foreach (var command in commands.GetCommands())
|
||||||
{
|
{
|
||||||
var channelMsg = CreateSetMessage(i, command.Item1, command.Item2, lockKeyValue);
|
var channelMsgLen = WriteSetMessage(buffer, i, command.Item1, command.Item2, lockKeyValue);
|
||||||
await stream.WriteAsync(channelMsg, 0, channelMsg.Length, cancellationToken).ConfigureAwait(false);
|
await stream.WriteAsync(buffer.AsMemory(0, channelMsgLen), cancellationToken).ConfigureAwait(false);
|
||||||
receivedBytes = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
|
receivedBytes = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// parse response to make sure it worked
|
// parse response to make sure it worked
|
||||||
if (!ParseReturnMessage(buffer, receivedBytes, out _))
|
if (!ParseReturnMessage(buffer, receivedBytes, out _))
|
||||||
|
@ -191,10 +193,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetValue = string.Format(CultureInfo.InvariantCulture, "rtp://{0}:{1}", localIp, localPort);
|
var targetValue = string.Format(CultureInfo.InvariantCulture, "rtp://{0}:{1}", localIp, localPort);
|
||||||
var targetMsg = CreateSetMessage(i, "target", targetValue, lockKeyValue);
|
var targetMsgLen = WriteSetMessage(buffer, i, "target", targetValue, lockKeyValue);
|
||||||
|
|
||||||
await stream.WriteAsync(targetMsg, 0, targetMsg.Length, cancellationToken).ConfigureAwait(false);
|
await stream.WriteAsync(buffer.AsMemory(0, targetMsgLen), cancellationToken).ConfigureAwait(false);
|
||||||
receivedBytes = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
|
receivedBytes = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// parse response to make sure it worked
|
// parse response to make sure it worked
|
||||||
if (!ParseReturnMessage(buffer, receivedBytes, out _))
|
if (!ParseReturnMessage(buffer, receivedBytes, out _))
|
||||||
|
@ -232,9 +234,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
{
|
{
|
||||||
foreach (var command in commandList)
|
foreach (var command in commandList)
|
||||||
{
|
{
|
||||||
var channelMsg = CreateSetMessage(_activeTuner, command.Item1, command.Item2, _lockkey);
|
var channelMsgLen = WriteSetMessage(buffer, _activeTuner, command.Item1, command.Item2, _lockkey);
|
||||||
await stream.WriteAsync(channelMsg, 0, channelMsg.Length, cancellationToken).ConfigureAwait(false);
|
await stream.WriteAsync(buffer.AsMemory(0, channelMsgLen), cancellationToken).ConfigureAwait(false);
|
||||||
int receivedBytes = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
|
int receivedBytes = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// parse response to make sure it worked
|
// parse response to make sure it worked
|
||||||
if (!ParseReturnMessage(buffer, receivedBytes, out _))
|
if (!ParseReturnMessage(buffer, receivedBytes, out _))
|
||||||
|
@ -265,17 +267,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
{
|
{
|
||||||
var stream = client.GetStream();
|
var stream = client.GetStream();
|
||||||
|
|
||||||
var releaseTarget = CreateSetMessage(_activeTuner, "target", "none", lockKeyValue);
|
|
||||||
await stream.WriteAsync(releaseTarget, 0, releaseTarget.Length).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var buffer = ArrayPool<byte>.Shared.Rent(8192);
|
var buffer = ArrayPool<byte>.Shared.Rent(8192);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
var releaseTargetLen = WriteSetMessage(buffer, _activeTuner, "target", "none", lockKeyValue);
|
||||||
var releaseKeyMsg = CreateSetMessage(_activeTuner, "lockkey", "none", lockKeyValue);
|
await stream.WriteAsync(buffer.AsMemory(0, releaseTargetLen)).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await stream.ReadAsync(buffer).ConfigureAwait(false);
|
||||||
|
var releaseKeyMsgLen = WriteSetMessage(buffer, _activeTuner, "lockkey", "none", lockKeyValue);
|
||||||
_lockkey = null;
|
_lockkey = null;
|
||||||
await stream.WriteAsync(releaseKeyMsg, 0, releaseKeyMsg.Length).ConfigureAwait(false);
|
await stream.WriteAsync(buffer.AsMemory(0, releaseKeyMsgLen)).ConfigureAwait(false);
|
||||||
await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
await stream.ReadAsync(buffer).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -283,109 +285,76 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] CreateGetMessage(int tuner, string name)
|
internal static int WriteGetMessage(Span<byte> buffer, int tuner, string name)
|
||||||
{
|
{
|
||||||
var byteName = Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "/tuner{0}/{1}\0", tuner, name));
|
var byteName = string.Format(CultureInfo.InvariantCulture, "/tuner{0}/{1}", tuner, name);
|
||||||
int messageLength = byteName.Length + 10; // 4 bytes for header + 4 bytes for crc + 2 bytes for tag name and length
|
int offset = WriteHeaderAndPayload(buffer, byteName);
|
||||||
|
return FinishPacket(buffer, offset);
|
||||||
var message = new byte[messageLength];
|
|
||||||
|
|
||||||
int offset = InsertHeaderAndName(byteName, messageLength, message);
|
|
||||||
|
|
||||||
bool flipEndian = BitConverter.IsLittleEndian;
|
|
||||||
|
|
||||||
// calculate crc and insert at the end of the message
|
|
||||||
var crcBytes = BitConverter.GetBytes(HdHomerunCrc.GetCrc32(message, messageLength - 4));
|
|
||||||
if (flipEndian)
|
|
||||||
{
|
|
||||||
Array.Reverse(crcBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer.BlockCopy(crcBytes, 0, message, offset, 4);
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] CreateSetMessage(int tuner, string name, string value, uint? lockkey)
|
private static int WriteSetMessage(Span<byte> buffer, int tuner, string name, string value, uint? lockkey)
|
||||||
{
|
{
|
||||||
var byteName = Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "/tuner{0}/{1}\0", tuner, name));
|
var byteName = string.Format(CultureInfo.InvariantCulture, "/tuner{0}/{1}", tuner, name);
|
||||||
var byteValue = Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "{0}\0", value));
|
int offset = WriteHeaderAndPayload(buffer, byteName);
|
||||||
|
|
||||||
|
buffer[offset++] = GetSetValue;
|
||||||
|
offset += WriteNullTerminatedString(buffer.Slice(offset), value);
|
||||||
|
|
||||||
int messageLength = byteName.Length + byteValue.Length + 12;
|
|
||||||
if (lockkey.HasValue)
|
if (lockkey.HasValue)
|
||||||
{
|
{
|
||||||
messageLength += 6;
|
buffer[offset++] = GetSetLockkey;
|
||||||
}
|
buffer[offset++] = 4;
|
||||||
|
BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(offset), lockkey.Value);
|
||||||
var message = new byte[messageLength];
|
|
||||||
|
|
||||||
int offset = InsertHeaderAndName(byteName, messageLength, message);
|
|
||||||
|
|
||||||
bool flipEndian = BitConverter.IsLittleEndian;
|
|
||||||
|
|
||||||
message[offset++] = GetSetValue;
|
|
||||||
message[offset++] = Convert.ToByte(byteValue.Length);
|
|
||||||
Buffer.BlockCopy(byteValue, 0, message, offset, byteValue.Length);
|
|
||||||
offset += byteValue.Length;
|
|
||||||
if (lockkey.HasValue)
|
|
||||||
{
|
|
||||||
message[offset++] = GetSetLockkey;
|
|
||||||
message[offset++] = 4;
|
|
||||||
var lockKeyBytes = BitConverter.GetBytes(lockkey.Value);
|
|
||||||
if (flipEndian)
|
|
||||||
{
|
|
||||||
Array.Reverse(lockKeyBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer.BlockCopy(lockKeyBytes, 0, message, offset, 4);
|
|
||||||
offset += 4;
|
offset += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate crc and insert at the end of the message
|
return FinishPacket(buffer, offset);
|
||||||
var crcBytes = BitConverter.GetBytes(HdHomerunCrc.GetCrc32(message, messageLength - 4));
|
|
||||||
if (flipEndian)
|
|
||||||
{
|
|
||||||
Array.Reverse(crcBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer.BlockCopy(crcBytes, 0, message, offset, 4);
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int InsertHeaderAndName(byte[] byteName, int messageLength, byte[] message)
|
internal static int WriteNullTerminatedString(Span<byte> buffer, ReadOnlySpan<char> payload)
|
||||||
{
|
{
|
||||||
// check to see if we need to flip endiannes
|
int len = Encoding.UTF8.GetBytes(payload, buffer.Slice(1)) + 1;
|
||||||
bool flipEndian = BitConverter.IsLittleEndian;
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
// create header bytes
|
// TODO: variable length: this can be 2 bytes if len > 127
|
||||||
var getSetBytes = BitConverter.GetBytes(GetSetRequest);
|
// Write length in front of value
|
||||||
var msgLenBytes = BitConverter.GetBytes((ushort)(messageLength - 8)); // Subtrace 4 bytes for header and 4 bytes for crc
|
buffer[0] = Convert.ToByte(len);
|
||||||
|
|
||||||
if (flipEndian)
|
// null-terminate
|
||||||
{
|
buffer[len++] = 0;
|
||||||
Array.Reverse(getSetBytes);
|
|
||||||
Array.Reverse(msgLenBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert header bytes into message
|
return len;
|
||||||
Buffer.BlockCopy(getSetBytes, 0, message, offset, 2);
|
}
|
||||||
offset += 2;
|
|
||||||
Buffer.BlockCopy(msgLenBytes, 0, message, offset, 2);
|
|
||||||
offset += 2;
|
|
||||||
|
|
||||||
// insert tag name and length
|
private static int WriteHeaderAndPayload(Span<byte> buffer, ReadOnlySpan<char> payload)
|
||||||
message[offset++] = GetSetName;
|
{
|
||||||
message[offset++] = Convert.ToByte(byteName.Length);
|
// Packet type
|
||||||
|
BinaryPrimitives.WriteUInt16BigEndian(buffer, GetSetRequest);
|
||||||
|
|
||||||
// insert name string
|
// We write the payload length at the end
|
||||||
Buffer.BlockCopy(byteName, 0, message, offset, byteName.Length);
|
int offset = 4;
|
||||||
offset += byteName.Length;
|
|
||||||
|
// Tag
|
||||||
|
buffer[offset++] = GetSetName;
|
||||||
|
|
||||||
|
// Payload length + data
|
||||||
|
int strLen = WriteNullTerminatedString(buffer.Slice(offset), payload);
|
||||||
|
offset += strLen;
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int FinishPacket(Span<byte> buffer, int offset)
|
||||||
|
{
|
||||||
|
// Payload length
|
||||||
|
BinaryPrimitives.WriteUInt16BigEndian(buffer.Slice(2), (ushort)(offset - 4));
|
||||||
|
|
||||||
|
// calculate crc and insert at the end of the message
|
||||||
|
var crc = Crc32.Compute(buffer.Slice(0, offset));
|
||||||
|
BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offset), crc);
|
||||||
|
|
||||||
|
return offset + 4;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool ParseReturnMessage(byte[] buf, int numBytes, out string returnVal)
|
private static bool ParseReturnMessage(byte[] buf, int numBytes, out string returnVal)
|
||||||
{
|
{
|
||||||
returnVal = string.Empty;
|
returnVal = string.Empty;
|
||||||
|
@ -442,90 +411,5 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
returnVal = Encoding.UTF8.GetString(buf, offset, valueLength - 1); // remove null terminator
|
returnVal = Encoding.UTF8.GetString(buf, offset, valueLength - 1); // remove null terminator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class HdHomerunCrc
|
|
||||||
{
|
|
||||||
private static uint[] crc_table = {
|
|
||||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
|
||||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
|
||||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
|
||||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
|
||||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
|
||||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
|
||||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
|
||||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
|
||||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
|
||||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
|
||||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
|
|
||||||
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
|
||||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
|
|
||||||
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
|
||||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
|
||||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
|
||||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
|
|
||||||
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
|
||||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
|
|
||||||
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
|
||||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
|
||||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
|
||||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
|
|
||||||
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
|
||||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
|
||||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
|
||||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
|
||||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
|
||||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
|
|
||||||
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
|
||||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
|
|
||||||
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
|
||||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
|
||||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
|
||||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
|
||||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
|
||||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
|
|
||||||
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
|
||||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
|
||||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
|
||||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
|
|
||||||
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
|
||||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
|
|
||||||
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
|
||||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
|
||||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
|
||||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
|
|
||||||
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
|
||||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
|
||||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
|
||||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
|
||||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
|
||||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
|
|
||||||
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
|
||||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
|
||||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
|
||||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
|
||||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
|
||||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
|
|
||||||
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
|
||||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
|
|
||||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
|
||||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
|
||||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
|
|
||||||
|
|
||||||
public static uint GetCrc32(byte[] bytes, int numBytes)
|
|
||||||
{
|
|
||||||
var hash = 0xffffffff;
|
|
||||||
for (var i = 0; i < numBytes; i++)
|
|
||||||
{
|
|
||||||
hash = (hash >> 8) ^ crc_table[(hash ^ bytes[i]) & 0xff];
|
|
||||||
}
|
|
||||||
|
|
||||||
var tmp = ~hash & 0xffffffff;
|
|
||||||
var b0 = tmp & 0xff;
|
|
||||||
var b1 = (tmp >> 8) & 0xff;
|
|
||||||
var b2 = (tmp >> 16) & 0xff;
|
|
||||||
var b3 = (tmp >> 24) & 0xff;
|
|
||||||
return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,5 +22,26 @@
|
||||||
"Artists": "Artistoj",
|
"Artists": "Artistoj",
|
||||||
"Application": "Aplikaĵo",
|
"Application": "Aplikaĵo",
|
||||||
"AppDeviceValues": "Aplikaĵo: {0}, Aparato: {1}",
|
"AppDeviceValues": "Aplikaĵo: {0}, Aparato: {1}",
|
||||||
"Albums": "Albumoj"
|
"Albums": "Albumoj",
|
||||||
|
"TasksLibraryCategory": "Libraro",
|
||||||
|
"VersionNumber": "Versio {0}",
|
||||||
|
"UserDownloadingItemWithValues": "{0} elŝutas {1}",
|
||||||
|
"UserCreatedWithName": "Uzanto {0} kreiĝis",
|
||||||
|
"User": "Uzanto",
|
||||||
|
"System": "Sistemo",
|
||||||
|
"Songs": "Kantoj",
|
||||||
|
"ScheduledTaskStartedWithName": "{0} komencis",
|
||||||
|
"ScheduledTaskFailedWithName": "{0} malsukcesis",
|
||||||
|
"PluginUninstalledWithName": "{0} malinstaliĝis",
|
||||||
|
"PluginInstalledWithName": "{0} instaliĝis",
|
||||||
|
"Plugin": "Kromprogramo",
|
||||||
|
"Playlists": "Ludlistoj",
|
||||||
|
"Photos": "Fotoj",
|
||||||
|
"NotificationOptionPluginUninstalled": "Kromprogramo malinstaliĝis",
|
||||||
|
"NotificationOptionNewLibraryContent": "Nova enhavo aldoniĝis",
|
||||||
|
"NotificationOptionPluginInstalled": "Kromprogramo instaliĝis",
|
||||||
|
"MusicVideos": "Muzikvideoj",
|
||||||
|
"LabelIpAddressValue": "IP-adreso: {0}",
|
||||||
|
"Genres": "Ĝenroj",
|
||||||
|
"DeviceOfflineWithName": "{0} malkonektis"
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@
|
||||||
"TaskRefreshPeopleDescription": "Tasyğyşhanadağy aktörler men rejisörler metaderekterın jaŋartady.",
|
"TaskRefreshPeopleDescription": "Tasyğyşhanadağy aktörler men rejisörler metaderekterın jaŋartady.",
|
||||||
"TaskCleanLogsDescription": "{0} künnen asqan jūrnal faildaryn joiady.",
|
"TaskCleanLogsDescription": "{0} künnen asqan jūrnal faildaryn joiady.",
|
||||||
"TaskRefreshLibraryDescription": "Tasyğyşhanadağy jaŋa faildardy skanerleidі jäne metaderekterdı jaŋğyrtady.",
|
"TaskRefreshLibraryDescription": "Tasyğyşhanadağy jaŋa faildardy skanerleidі jäne metaderekterdı jaŋğyrtady.",
|
||||||
"TaskRefreshChapterImagesDescription": "Sahnalary bar beineler üşіn nobailar jasaidy.",
|
"TaskRefreshChapterImagesDescription": "Sahnalary bar beineler üşın nobailar jasaidy.",
|
||||||
"TaskCleanCacheDescription": "Jüiede qajet emes keştelgen faildardy joiady.",
|
"TaskCleanCacheDescription": "Jüiede qajet emes keştelgen faildardy joiady.",
|
||||||
"TaskCleanActivityLogDescription": "Äreket jūrnalyndağy teŋşelgen jasynan asqan jazbalary joiady."
|
"TaskCleanActivityLogDescription": "Äreket jūrnalyndağy teŋşelgen jasynan asqan jazbalary joiady."
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,5 +113,9 @@
|
||||||
"TasksChannelsCategory": "Internetiniai Kanalai",
|
"TasksChannelsCategory": "Internetiniai Kanalai",
|
||||||
"TasksApplicationCategory": "Programa",
|
"TasksApplicationCategory": "Programa",
|
||||||
"TasksLibraryCategory": "Mediateka",
|
"TasksLibraryCategory": "Mediateka",
|
||||||
"TasksMaintenanceCategory": "Priežiūra"
|
"TasksMaintenanceCategory": "Priežiūra",
|
||||||
|
"TaskCleanActivityLog": "Švarus veiklos žurnalas",
|
||||||
|
"Undefined": "Neapibrėžtas",
|
||||||
|
"Forced": "Priverstas",
|
||||||
|
"Default": "Numatytas"
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"Folders": "Pastas",
|
"Folders": "Pastas",
|
||||||
"Genres": "Gêneros",
|
"Genres": "Gêneros",
|
||||||
"HeaderAlbumArtists": "Artistas do Álbum",
|
"HeaderAlbumArtists": "Artistas do Álbum",
|
||||||
"HeaderContinueWatching": "Continuar Assistindo",
|
"HeaderContinueWatching": "Continuar assistindo",
|
||||||
"HeaderFavoriteAlbums": "Álbuns Favoritos",
|
"HeaderFavoriteAlbums": "Álbuns Favoritos",
|
||||||
"HeaderFavoriteArtists": "Artistas favoritos",
|
"HeaderFavoriteArtists": "Artistas favoritos",
|
||||||
"HeaderFavoriteEpisodes": "Episódios favoritos",
|
"HeaderFavoriteEpisodes": "Episódios favoritos",
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.Localization
|
||||||
|
|
||||||
private List<CultureDto> _cultures;
|
private List<CultureDto> _cultures;
|
||||||
|
|
||||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
|
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="LocalizationManager" /> class.
|
/// Initializes a new instance of the <see cref="LocalizationManager" /> class.
|
||||||
|
|
|
@ -70,7 +70,7 @@ namespace Emby.Server.Implementations.Plugins
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
_pluginsPath = pluginsPath;
|
_pluginsPath = pluginsPath;
|
||||||
_appVersion = appVersion ?? throw new ArgumentNullException(nameof(appVersion));
|
_appVersion = appVersion ?? throw new ArgumentNullException(nameof(appVersion));
|
||||||
_jsonOptions = new JsonSerializerOptions(JsonDefaults.GetOptions())
|
_jsonOptions = new JsonSerializerOptions(JsonDefaults.Options)
|
||||||
{
|
{
|
||||||
WriteIndented = true
|
WriteIndented = true
|
||||||
};
|
};
|
||||||
|
@ -678,7 +678,7 @@ namespace Emby.Server.Implementations.Plugins
|
||||||
var entry = versions[x];
|
var entry = versions[x];
|
||||||
if (!string.Equals(lastName, entry.Name, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(lastName, entry.Name, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
entry.DllFiles.AddRange(Directory.EnumerateFiles(entry.Path, "*.dll", SearchOption.AllDirectories));
|
entry.DllFiles = Directory.GetFiles(entry.Path, "*.dll", SearchOption.AllDirectories);
|
||||||
if (entry.IsEnabledAndSupported)
|
if (entry.IsEnabledAndSupported)
|
||||||
{
|
{
|
||||||
lastName = entry.Name;
|
lastName = entry.Name;
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The options for the json Serializer.
|
/// The options for the json Serializer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
|
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ScheduledTaskWorker" /> class.
|
/// Initializes a new instance of the <see cref="ScheduledTaskWorker" /> class.
|
||||||
|
|
|
@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.Updates
|
||||||
_httpClientFactory = httpClientFactory;
|
_httpClientFactory = httpClientFactory;
|
||||||
_config = config;
|
_config = config;
|
||||||
_zipClient = zipClient;
|
_zipClient = zipClient;
|
||||||
_jsonSerializerOptions = JsonDefaults.GetOptions();
|
_jsonSerializerOptions = JsonDefaults.Options;
|
||||||
_pluginManager = pluginManager;
|
_pluginManager = pluginManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
private readonly IServerConfigurationManager _configurationManager;
|
private readonly IServerConfigurationManager _configurationManager;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
|
||||||
private readonly JsonSerializerOptions _serializerOptions = JsonDefaults.GetOptions();
|
private readonly JsonSerializerOptions _serializerOptions = JsonDefaults.Options;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ConfigurationController"/> class.
|
/// Initializes a new instance of the <see cref="ConfigurationController"/> class.
|
||||||
|
|
|
@ -61,7 +61,13 @@ namespace Jellyfin.Api.Controllers
|
||||||
{
|
{
|
||||||
// TODO: Deprecate with new iOS app
|
// TODO: Deprecate with new iOS app
|
||||||
var file = segmentId + Path.GetExtension(Request.Path);
|
var file = segmentId + Path.GetExtension(Request.Path);
|
||||||
file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file);
|
var transcodePath = _serverConfigurationManager.GetTranscodePath();
|
||||||
|
file = Path.GetFullPath(Path.Combine(transcodePath, file));
|
||||||
|
var fileDir = Path.GetDirectoryName(file);
|
||||||
|
if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodePath))
|
||||||
|
{
|
||||||
|
return BadRequest("Invalid segment.");
|
||||||
|
}
|
||||||
|
|
||||||
return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file)!, false, HttpContext);
|
return FileStreamResponseHelpers.GetStaticFileResult(file, MimeTypes.GetMimeType(file)!, false, HttpContext);
|
||||||
}
|
}
|
||||||
|
@ -81,7 +87,13 @@ namespace Jellyfin.Api.Controllers
|
||||||
public ActionResult GetHlsPlaylistLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string playlistId)
|
public ActionResult GetHlsPlaylistLegacy([FromRoute, Required] string itemId, [FromRoute, Required] string playlistId)
|
||||||
{
|
{
|
||||||
var file = playlistId + Path.GetExtension(Request.Path);
|
var file = playlistId + Path.GetExtension(Request.Path);
|
||||||
file = Path.Combine(_serverConfigurationManager.GetTranscodePath(), file);
|
var transcodePath = _serverConfigurationManager.GetTranscodePath();
|
||||||
|
file = Path.GetFullPath(Path.Combine(transcodePath, file));
|
||||||
|
var fileDir = Path.GetDirectoryName(file);
|
||||||
|
if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodePath) || Path.GetExtension(file) != ".m3u8")
|
||||||
|
{
|
||||||
|
return BadRequest("Invalid segment.");
|
||||||
|
}
|
||||||
|
|
||||||
return GetFileResult(file, file);
|
return GetFileResult(file, file);
|
||||||
}
|
}
|
||||||
|
@ -130,7 +142,12 @@ namespace Jellyfin.Api.Controllers
|
||||||
var file = segmentId + Path.GetExtension(Request.Path);
|
var file = segmentId + Path.GetExtension(Request.Path);
|
||||||
var transcodeFolderPath = _serverConfigurationManager.GetTranscodePath();
|
var transcodeFolderPath = _serverConfigurationManager.GetTranscodePath();
|
||||||
|
|
||||||
file = Path.Combine(transcodeFolderPath, file);
|
file = Path.GetFullPath(Path.Combine(transcodeFolderPath, file));
|
||||||
|
var fileDir = Path.GetDirectoryName(file);
|
||||||
|
if (string.IsNullOrEmpty(fileDir) || !fileDir.StartsWith(transcodeFolderPath))
|
||||||
|
{
|
||||||
|
return BadRequest("Invalid segment.");
|
||||||
|
}
|
||||||
|
|
||||||
var normalizedPlaylistId = playlistId;
|
var normalizedPlaylistId = playlistId;
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
: type;
|
: type;
|
||||||
|
|
||||||
var path = BaseItem.SupportedImageExtensions
|
var path = BaseItem.SupportedImageExtensions
|
||||||
.Select(i => Path.Combine(_applicationPaths.GeneralPath, name, filename + i))
|
.Select(i => Path.GetFullPath(Path.Combine(_applicationPaths.GeneralPath, name, filename + i)))
|
||||||
.FirstOrDefault(System.IO.File.Exists);
|
.FirstOrDefault(System.IO.File.Exists);
|
||||||
|
|
||||||
if (path == null)
|
if (path == null)
|
||||||
|
@ -82,6 +82,11 @@ namespace Jellyfin.Api.Controllers
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!path.StartsWith(_applicationPaths.GeneralPath))
|
||||||
|
{
|
||||||
|
return BadRequest("Invalid image path.");
|
||||||
|
}
|
||||||
|
|
||||||
var contentType = MimeTypes.GetMimeType(path);
|
var contentType = MimeTypes.GetMimeType(path);
|
||||||
return File(System.IO.File.OpenRead(path), contentType);
|
return File(System.IO.File.OpenRead(path), contentType);
|
||||||
}
|
}
|
||||||
|
@ -163,7 +168,8 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
|
/// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
|
||||||
private ActionResult GetImageFile(string basePath, string theme, string? name)
|
private ActionResult GetImageFile(string basePath, string theme, string? name)
|
||||||
{
|
{
|
||||||
var themeFolder = Path.Combine(basePath, theme);
|
var themeFolder = Path.GetFullPath(Path.Combine(basePath, theme));
|
||||||
|
|
||||||
if (Directory.Exists(themeFolder))
|
if (Directory.Exists(themeFolder))
|
||||||
{
|
{
|
||||||
var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(themeFolder, name + i))
|
var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(themeFolder, name + i))
|
||||||
|
@ -171,12 +177,18 @@ namespace Jellyfin.Api.Controllers
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
|
if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
|
||||||
{
|
{
|
||||||
|
if (!path.StartsWith(basePath))
|
||||||
|
{
|
||||||
|
return BadRequest("Invalid image path.");
|
||||||
|
}
|
||||||
|
|
||||||
var contentType = MimeTypes.GetMimeType(path);
|
var contentType = MimeTypes.GetMimeType(path);
|
||||||
|
|
||||||
return PhysicalFile(path, contentType);
|
return PhysicalFile(path, contentType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var allFolder = Path.Combine(basePath, "all");
|
var allFolder = Path.GetFullPath(Path.Combine(basePath, "all"));
|
||||||
if (Directory.Exists(allFolder))
|
if (Directory.Exists(allFolder))
|
||||||
{
|
{
|
||||||
var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(allFolder, name + i))
|
var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(allFolder, name + i))
|
||||||
|
@ -184,6 +196,11 @@ namespace Jellyfin.Api.Controllers
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
|
if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
|
||||||
{
|
{
|
||||||
|
if (!path.StartsWith(basePath))
|
||||||
|
{
|
||||||
|
return BadRequest("Invalid image path.");
|
||||||
|
}
|
||||||
|
|
||||||
var contentType = MimeTypes.GetMimeType(path);
|
var contentType = MimeTypes.GetMimeType(path);
|
||||||
return PhysicalFile(path, contentType);
|
return PhysicalFile(path, contentType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,6 +196,11 @@ namespace Jellyfin.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = _userManager.GetUserById(userId);
|
var user = _userManager.GetUserById(userId);
|
||||||
|
if (user?.ProfileImage == null)
|
||||||
|
{
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
System.IO.File.Delete(user.ProfileImage.Path);
|
System.IO.File.Delete(user.ProfileImage.Path);
|
||||||
|
@ -235,6 +240,11 @@ namespace Jellyfin.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = _userManager.GetUserById(userId);
|
var user = _userManager.GetUserById(userId);
|
||||||
|
if (user?.ProfileImage == null)
|
||||||
|
{
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
System.IO.File.Delete(user.ProfileImage.Path);
|
System.IO.File.Delete(user.ProfileImage.Path);
|
||||||
|
@ -1469,7 +1479,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
[FromQuery] int? imageIndex)
|
[FromQuery] int? imageIndex)
|
||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(userId);
|
var user = _userManager.GetUserById(userId);
|
||||||
if (user == null)
|
if (user?.ProfileImage == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instant playlist based on a given song.
|
/// Creates an instant playlist based on a given album.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The item id.</param>
|
/// <param name="id">The item id.</param>
|
||||||
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
||||||
|
@ -122,7 +122,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instant playlist based on a given song.
|
/// Creates an instant playlist based on a given playlist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The item id.</param>
|
/// <param name="id">The item id.</param>
|
||||||
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
||||||
|
@ -158,7 +158,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instant playlist based on a given song.
|
/// Creates an instant playlist based on a given genre.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The genre name.</param>
|
/// <param name="name">The genre name.</param>
|
||||||
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
||||||
|
@ -172,7 +172,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the playlist items.</returns>
|
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the playlist items.</returns>
|
||||||
[HttpGet("MusicGenres/{name}/InstantMix")]
|
[HttpGet("MusicGenres/{name}/InstantMix")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenre(
|
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenreByName(
|
||||||
[FromRoute, Required] string name,
|
[FromRoute, Required] string name,
|
||||||
[FromQuery] Guid? userId,
|
[FromQuery] Guid? userId,
|
||||||
[FromQuery] int? limit,
|
[FromQuery] int? limit,
|
||||||
|
@ -193,7 +193,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instant playlist based on a given song.
|
/// Creates an instant playlist based on a given artist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The item id.</param>
|
/// <param name="id">The item id.</param>
|
||||||
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
||||||
|
@ -229,7 +229,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instant playlist based on a given song.
|
/// Creates an instant playlist based on a given genre.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The item id.</param>
|
/// <param name="id">The item id.</param>
|
||||||
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
||||||
|
@ -243,7 +243,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the playlist items.</returns>
|
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the playlist items.</returns>
|
||||||
[HttpGet("MusicGenres/{id}/InstantMix")]
|
[HttpGet("MusicGenres/{id}/InstantMix")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenres(
|
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenreById(
|
||||||
[FromRoute, Required] Guid id,
|
[FromRoute, Required] Guid id,
|
||||||
[FromQuery] Guid? userId,
|
[FromQuery] Guid? userId,
|
||||||
[FromQuery] int? limit,
|
[FromQuery] int? limit,
|
||||||
|
@ -265,7 +265,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instant playlist based on a given song.
|
/// Creates an instant playlist based on a given item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The item id.</param>
|
/// <param name="id">The item id.</param>
|
||||||
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
||||||
|
@ -300,6 +300,80 @@ namespace Jellyfin.Api.Controllers
|
||||||
return GetResult(items, user, limit, dtoOptions);
|
return GetResult(items, user, limit, dtoOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instant playlist based on a given artist.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The item id.</param>
|
||||||
|
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
||||||
|
/// <param name="limit">Optional. The maximum number of records to return.</param>
|
||||||
|
/// <param name="fields">Optional. Specify additional fields of information to return in the output.</param>
|
||||||
|
/// <param name="enableImages">Optional. Include image information in output.</param>
|
||||||
|
/// <param name="enableUserData">Optional. Include user data.</param>
|
||||||
|
/// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
|
||||||
|
/// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
|
||||||
|
/// <response code="200">Instant playlist returned.</response>
|
||||||
|
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the playlist items.</returns>
|
||||||
|
[HttpGet("Artists/InstantMix")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[Obsolete("Use GetInstantMixFromArtists")]
|
||||||
|
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromArtists2(
|
||||||
|
[FromQuery, Required] Guid id,
|
||||||
|
[FromQuery] Guid? userId,
|
||||||
|
[FromQuery] int? limit,
|
||||||
|
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
|
||||||
|
[FromQuery] bool? enableImages,
|
||||||
|
[FromQuery] bool? enableUserData,
|
||||||
|
[FromQuery] int? imageTypeLimit,
|
||||||
|
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
|
||||||
|
{
|
||||||
|
return GetInstantMixFromArtists(
|
||||||
|
id,
|
||||||
|
userId,
|
||||||
|
limit,
|
||||||
|
fields,
|
||||||
|
enableImages,
|
||||||
|
enableUserData,
|
||||||
|
imageTypeLimit,
|
||||||
|
enableImageTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instant playlist based on a given genre.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The item id.</param>
|
||||||
|
/// <param name="userId">Optional. Filter by user id, and attach user data.</param>
|
||||||
|
/// <param name="limit">Optional. The maximum number of records to return.</param>
|
||||||
|
/// <param name="fields">Optional. Specify additional fields of information to return in the output.</param>
|
||||||
|
/// <param name="enableImages">Optional. Include image information in output.</param>
|
||||||
|
/// <param name="enableUserData">Optional. Include user data.</param>
|
||||||
|
/// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param>
|
||||||
|
/// <param name="enableImageTypes">Optional. The image types to include in the output.</param>
|
||||||
|
/// <response code="200">Instant playlist returned.</response>
|
||||||
|
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the playlist items.</returns>
|
||||||
|
[HttpGet("MusicGenres/InstantMix")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[Obsolete("Use GetInstantMixFromMusicGenres instead")]
|
||||||
|
public ActionResult<QueryResult<BaseItemDto>> GetInstantMixFromMusicGenreById2(
|
||||||
|
[FromQuery, Required] Guid id,
|
||||||
|
[FromQuery] Guid? userId,
|
||||||
|
[FromQuery] int? limit,
|
||||||
|
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
|
||||||
|
[FromQuery] bool? enableImages,
|
||||||
|
[FromQuery] bool? enableUserData,
|
||||||
|
[FromQuery] int? imageTypeLimit,
|
||||||
|
[FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes)
|
||||||
|
{
|
||||||
|
return GetInstantMixFromMusicGenreById(
|
||||||
|
id,
|
||||||
|
userId,
|
||||||
|
limit,
|
||||||
|
fields,
|
||||||
|
enableImages,
|
||||||
|
enableUserData,
|
||||||
|
imageTypeLimit,
|
||||||
|
enableImageTypes);
|
||||||
|
}
|
||||||
|
|
||||||
private QueryResult<BaseItemDto> GetResult(List<BaseItem> items, User? user, int? limit, DtoOptions dtoOptions)
|
private QueryResult<BaseItemDto> GetResult(List<BaseItem> items, User? user, int? limit, DtoOptions dtoOptions)
|
||||||
{
|
{
|
||||||
var list = items;
|
var list = items;
|
||||||
|
|
|
@ -303,7 +303,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <response code="204">Library scan started.</response>
|
/// <response code="204">Library scan started.</response>
|
||||||
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
||||||
[HttpGet("Library/Refresh")]
|
[HttpPost("Library/Refresh")]
|
||||||
[Authorize(Policy = Policies.RequiresElevation)]
|
[Authorize(Policy = Policies.RequiresElevation)]
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
public async Task<ActionResult> RefreshLibrary()
|
public async Task<ActionResult> RefreshLibrary()
|
||||||
|
@ -590,15 +590,15 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reports that new movies have been added by an external source.
|
/// Reports that new movies have been added by an external source.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="updates">A list of updated media paths.</param>
|
/// <param name="dto">The update paths.</param>
|
||||||
/// <response code="204">Report success.</response>
|
/// <response code="204">Report success.</response>
|
||||||
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
/// <returns>A <see cref="NoContentResult"/>.</returns>
|
||||||
[HttpPost("Library/Media/Updated")]
|
[HttpPost("Library/Media/Updated")]
|
||||||
[Authorize(Policy = Policies.DefaultAuthorization)]
|
[Authorize(Policy = Policies.DefaultAuthorization)]
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
public ActionResult PostUpdatedMedia([FromBody, Required] MediaUpdateInfoDto[] updates)
|
public ActionResult PostUpdatedMedia([FromBody, Required] MediaUpdateInfoDto dto)
|
||||||
{
|
{
|
||||||
foreach (var item in updates)
|
foreach (var item in dto.Updates)
|
||||||
{
|
{
|
||||||
_libraryMonitor.ReportFileSystemChanged(item.Path);
|
_libraryMonitor.ReportFileSystemChanged(item.Path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Jellyfin.Api.Constants;
|
using Jellyfin.Api.Constants;
|
||||||
|
@ -86,26 +87,19 @@ namespace Jellyfin.Api.Controllers
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a notification to all admins.
|
/// Sends a notification to all admins.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="url">The URL of the notification.</param>
|
/// <param name="notificationDto">The notification request.</param>
|
||||||
/// <param name="level">The level of the notification.</param>
|
|
||||||
/// <param name="name">The name of the notification.</param>
|
|
||||||
/// <param name="description">The description of the notification.</param>
|
|
||||||
/// <response code="204">Notification sent.</response>
|
/// <response code="204">Notification sent.</response>
|
||||||
/// <returns>A <cref see="NoContentResult"/>.</returns>
|
/// <returns>A <cref see="NoContentResult"/>.</returns>
|
||||||
[HttpPost("Admin")]
|
[HttpPost("Admin")]
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
public ActionResult CreateAdminNotification(
|
public ActionResult CreateAdminNotification([FromBody, Required] AdminNotificationDto notificationDto)
|
||||||
[FromQuery] string? url,
|
|
||||||
[FromQuery] NotificationLevel? level,
|
|
||||||
[FromQuery] string name = "",
|
|
||||||
[FromQuery] string description = "")
|
|
||||||
{
|
{
|
||||||
var notification = new NotificationRequest
|
var notification = new NotificationRequest
|
||||||
{
|
{
|
||||||
Name = name,
|
Name = notificationDto.Name,
|
||||||
Description = description,
|
Description = notificationDto.Description,
|
||||||
Url = url,
|
Url = notificationDto.Url,
|
||||||
Level = level ?? NotificationLevel.Normal,
|
Level = notificationDto.NotificationLevel ?? NotificationLevel.Normal,
|
||||||
UserIds = _userManager.Users
|
UserIds = _userManager.Users
|
||||||
.Where(user => user.HasPermission(PermissionKind.IsAdministrator))
|
.Where(user => user.HasPermission(PermissionKind.IsAdministrator))
|
||||||
.Select(user => user.Id)
|
.Select(user => user.Id)
|
||||||
|
@ -114,7 +108,6 @@ namespace Jellyfin.Api.Controllers
|
||||||
};
|
};
|
||||||
|
|
||||||
_notificationManager.SendNotification(notification, CancellationToken.None);
|
_notificationManager.SendNotification(notification, CancellationToken.None);
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace Jellyfin.Api.Controllers
|
||||||
{
|
{
|
||||||
_installationManager = installationManager;
|
_installationManager = installationManager;
|
||||||
_pluginManager = pluginManager;
|
_pluginManager = pluginManager;
|
||||||
_serializerOptions = JsonDefaults.GetOptions();
|
_serializerOptions = JsonDefaults.Options;
|
||||||
_config = config;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,10 @@ namespace Jellyfin.Api.Controllers
|
||||||
{
|
{
|
||||||
var user = _userManager.Users.First();
|
var user = _userManager.Users.First();
|
||||||
|
|
||||||
user.Username = startupUserDto.Name;
|
if (startupUserDto.Name != null)
|
||||||
|
{
|
||||||
|
user.Username = startupUserDto.Name;
|
||||||
|
}
|
||||||
|
|
||||||
await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
|
await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
namespace Jellyfin.Api.Models.LibraryDtos
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Jellyfin.Api.Models.LibraryDtos
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Media Update Info Dto.
|
/// Media Update Info Dto.
|
||||||
|
@ -6,14 +9,8 @@
|
||||||
public class MediaUpdateInfoDto
|
public class MediaUpdateInfoDto
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets media path.
|
/// Gets or sets the list of updates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Path { get; set; }
|
public IReadOnlyList<MediaUpdateInfoPathDto> Updates { get; set; } = Array.Empty<MediaUpdateInfoPathDto>();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets media update type.
|
|
||||||
/// Created, Modified, Deleted.
|
|
||||||
/// </summary>
|
|
||||||
public string? UpdateType { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
Jellyfin.Api/Models/LibraryDtos/MediaUpdateInfoPathDto.cs
Normal file
19
Jellyfin.Api/Models/LibraryDtos/MediaUpdateInfoPathDto.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
namespace Jellyfin.Api.Models.LibraryDtos
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The media update info path.
|
||||||
|
/// </summary>
|
||||||
|
public class MediaUpdateInfoPathDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets media path.
|
||||||
|
/// </summary>
|
||||||
|
public string? Path { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets media update type.
|
||||||
|
/// Created, Modified, Deleted.
|
||||||
|
/// </summary>
|
||||||
|
public string? UpdateType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
30
Jellyfin.Api/Models/NotificationDtos/AdminNotificationDto.cs
Normal file
30
Jellyfin.Api/Models/NotificationDtos/AdminNotificationDto.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using MediaBrowser.Model.Notifications;
|
||||||
|
|
||||||
|
namespace Jellyfin.Api.Models.NotificationDtos
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The admin notification dto.
|
||||||
|
/// </summary>
|
||||||
|
public class AdminNotificationDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the notification name.
|
||||||
|
/// </summary>
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the notification description.
|
||||||
|
/// </summary>
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the notification level.
|
||||||
|
/// </summary>
|
||||||
|
public NotificationLevel? NotificationLevel { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the notification url.
|
||||||
|
/// </summary>
|
||||||
|
public string? Url { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,67 +1,21 @@
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Jellyfin.Data.Enums;
|
using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
namespace Jellyfin.Data
|
namespace Jellyfin.Data
|
||||||
{
|
{
|
||||||
public static class DayOfWeekHelper
|
public static class DayOfWeekHelper
|
||||||
{
|
{
|
||||||
public static List<DayOfWeek> GetDaysOfWeek(DynamicDayOfWeek day)
|
public static DayOfWeek[] GetDaysOfWeek(DynamicDayOfWeek day)
|
||||||
{
|
{
|
||||||
var days = new List<DayOfWeek>(7);
|
return day switch
|
||||||
|
|
||||||
if (day == DynamicDayOfWeek.Sunday
|
|
||||||
|| day == DynamicDayOfWeek.Weekend
|
|
||||||
|| day == DynamicDayOfWeek.Everyday)
|
|
||||||
{
|
{
|
||||||
days.Add(DayOfWeek.Sunday);
|
DynamicDayOfWeek.Everyday => new[] { DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Saturday },
|
||||||
}
|
DynamicDayOfWeek.Weekday => new[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday },
|
||||||
|
DynamicDayOfWeek.Weekend => new[] { DayOfWeek.Sunday, DayOfWeek.Saturday },
|
||||||
if (day == DynamicDayOfWeek.Monday
|
_ => new[] { (DayOfWeek)day }
|
||||||
|| day == DynamicDayOfWeek.Weekday
|
};
|
||||||
|| day == DynamicDayOfWeek.Everyday)
|
|
||||||
{
|
|
||||||
days.Add(DayOfWeek.Monday);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (day == DynamicDayOfWeek.Tuesday
|
|
||||||
|| day == DynamicDayOfWeek.Weekday
|
|
||||||
|| day == DynamicDayOfWeek.Everyday)
|
|
||||||
{
|
|
||||||
days.Add(DayOfWeek.Tuesday);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (day == DynamicDayOfWeek.Wednesday
|
|
||||||
|| day == DynamicDayOfWeek.Weekday
|
|
||||||
|| day == DynamicDayOfWeek.Everyday)
|
|
||||||
{
|
|
||||||
days.Add(DayOfWeek.Wednesday);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (day == DynamicDayOfWeek.Thursday
|
|
||||||
|| day == DynamicDayOfWeek.Weekday
|
|
||||||
|| day == DynamicDayOfWeek.Everyday)
|
|
||||||
{
|
|
||||||
days.Add(DayOfWeek.Thursday);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (day == DynamicDayOfWeek.Friday
|
|
||||||
|| day == DynamicDayOfWeek.Weekday
|
|
||||||
|| day == DynamicDayOfWeek.Everyday)
|
|
||||||
{
|
|
||||||
days.Add(DayOfWeek.Friday);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (day == DynamicDayOfWeek.Saturday
|
|
||||||
|| day == DynamicDayOfWeek.Weekend
|
|
||||||
|| day == DynamicDayOfWeek.Everyday)
|
|
||||||
{
|
|
||||||
days.Add(DayOfWeek.Saturday);
|
|
||||||
}
|
|
||||||
|
|
||||||
return days;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using Jellyfin.Data.Enums;
|
using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
|
@ -27,14 +25,6 @@ namespace Jellyfin.Data.Entities
|
||||||
EndHour = endHour;
|
EndHour = endHour;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="AccessSchedule"/> class.
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </summary>
|
|
||||||
protected AccessSchedule()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id of this instance.
|
/// Gets or sets the id of this instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -42,8 +32,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// Identity, Indexed, Required.
|
/// Identity, Indexed, Required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[XmlIgnore]
|
[XmlIgnore]
|
||||||
[Key]
|
|
||||||
[Required]
|
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
public int Id { get; protected set; }
|
public int Id { get; protected set; }
|
||||||
|
|
||||||
|
@ -51,41 +39,24 @@ namespace Jellyfin.Data.Entities
|
||||||
/// Gets or sets the id of the associated user.
|
/// Gets or sets the id of the associated user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[XmlIgnore]
|
[XmlIgnore]
|
||||||
[Required]
|
|
||||||
public Guid UserId { get; protected set; }
|
public Guid UserId { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the day of week.
|
/// Gets or sets the day of week.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The day of week.</value>
|
/// <value>The day of week.</value>
|
||||||
[Required]
|
|
||||||
public DynamicDayOfWeek DayOfWeek { get; set; }
|
public DynamicDayOfWeek DayOfWeek { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the start hour.
|
/// Gets or sets the start hour.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The start hour.</value>
|
/// <value>The start hour.</value>
|
||||||
[Required]
|
|
||||||
public double StartHour { get; set; }
|
public double StartHour { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the end hour.
|
/// Gets or sets the end hour.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The end hour.</value>
|
/// <value>The end hour.</value>
|
||||||
[Required]
|
|
||||||
public double EndHour { get; set; }
|
public double EndHour { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Static create function (for use in LINQ queries, etc.)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dayOfWeek">The day of the week.</param>
|
|
||||||
/// <param name="startHour">The start hour.</param>
|
|
||||||
/// <param name="endHour">The end hour.</param>
|
|
||||||
/// <param name="userId">The associated user's id.</param>
|
|
||||||
/// <returns>The newly created instance.</returns>
|
|
||||||
public static AccessSchedule Create(DynamicDayOfWeek dayOfWeek, double startHour, double endHour, Guid userId)
|
|
||||||
{
|
|
||||||
return new AccessSchedule(dayOfWeek, startHour, endHour, userId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <param name="name">The name.</param>
|
/// <param name="name">The name.</param>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="type">The type.</param>
|
||||||
/// <param name="userId">The user id.</param>
|
/// <param name="userId">The user id.</param>
|
||||||
/// <param name="logLevel">The log level.</param>
|
public ActivityLog(string name, string type, Guid userId)
|
||||||
public ActivityLog(string name, string type, Guid userId, LogLevel logLevel = LogLevel.Information)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
{
|
{
|
||||||
|
@ -35,15 +34,7 @@ namespace Jellyfin.Data.Entities
|
||||||
Type = type;
|
Type = type;
|
||||||
UserId = userId;
|
UserId = userId;
|
||||||
DateCreated = DateTime.UtcNow;
|
DateCreated = DateTime.UtcNow;
|
||||||
LogSeverity = logLevel;
|
LogSeverity = LogLevel.Information;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ActivityLog"/> class.
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </summary>
|
|
||||||
protected ActivityLog()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -59,7 +50,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 512.
|
/// Required, Max length = 512.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(512)]
|
[MaxLength(512)]
|
||||||
[StringLength(512)]
|
[StringLength(512)]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
@ -72,7 +62,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(512)]
|
[MaxLength(512)]
|
||||||
[StringLength(512)]
|
[StringLength(512)]
|
||||||
public string Overview { get; set; }
|
public string? Overview { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the short overview.
|
/// Gets or sets the short overview.
|
||||||
|
@ -82,7 +72,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(512)]
|
[MaxLength(512)]
|
||||||
[StringLength(512)]
|
[StringLength(512)]
|
||||||
public string ShortOverview { get; set; }
|
public string? ShortOverview { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the type.
|
/// Gets or sets the type.
|
||||||
|
@ -90,7 +80,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 256.
|
/// Required, Max length = 256.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(256)]
|
[MaxLength(256)]
|
||||||
[StringLength(256)]
|
[StringLength(256)]
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
|
@ -111,7 +100,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(256)]
|
[MaxLength(256)]
|
||||||
[StringLength(256)]
|
[StringLength(256)]
|
||||||
public string ItemId { get; set; }
|
public string? ItemId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the date created. This should be in UTC.
|
/// Gets or sets the date created. This should be in UTC.
|
||||||
|
|
|
@ -15,22 +15,15 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <param name="userId">The user id.</param>
|
/// <param name="userId">The user id.</param>
|
||||||
/// <param name="itemId">The item id.</param>
|
/// <param name="itemId">The item id.</param>
|
||||||
/// <param name="client">The client.</param>
|
/// <param name="client">The client.</param>
|
||||||
/// <param name="preferenceKey">The preference key.</param>
|
/// <param name="key">The preference key.</param>
|
||||||
/// <param name="preferenceValue">The preference value.</param>
|
/// <param name="value">The preference value.</param>
|
||||||
public CustomItemDisplayPreferences(Guid userId, Guid itemId, string client, string preferenceKey, string preferenceValue)
|
public CustomItemDisplayPreferences(Guid userId, Guid itemId, string client, string key, string value)
|
||||||
{
|
{
|
||||||
UserId = userId;
|
UserId = userId;
|
||||||
ItemId = itemId;
|
ItemId = itemId;
|
||||||
Client = client;
|
Client = client;
|
||||||
Key = preferenceKey;
|
Key = key;
|
||||||
Value = preferenceValue;
|
Value = value;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="CustomItemDisplayPreferences"/> class.
|
|
||||||
/// </summary>
|
|
||||||
protected CustomItemDisplayPreferences()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -64,7 +57,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required. Max Length = 32.
|
/// Required. Max Length = 32.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(32)]
|
[MaxLength(32)]
|
||||||
[StringLength(32)]
|
[StringLength(32)]
|
||||||
public string Client { get; set; }
|
public string Client { get; set; }
|
||||||
|
@ -75,7 +67,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required.
|
/// Required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -84,7 +75,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required.
|
/// Required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
public string Value { get; set; }
|
public string Value { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,19 +30,10 @@ namespace Jellyfin.Data.Entities
|
||||||
SkipBackwardLength = 10000;
|
SkipBackwardLength = 10000;
|
||||||
ScrollDirection = ScrollDirection.Horizontal;
|
ScrollDirection = ScrollDirection.Horizontal;
|
||||||
ChromecastVersion = ChromecastVersion.Stable;
|
ChromecastVersion = ChromecastVersion.Stable;
|
||||||
DashboardTheme = string.Empty;
|
|
||||||
TvHome = string.Empty;
|
|
||||||
|
|
||||||
HomeSections = new HashSet<HomeSection>();
|
HomeSections = new HashSet<HomeSection>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="DisplayPreferences"/> class.
|
|
||||||
/// </summary>
|
|
||||||
protected DisplayPreferences()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Id.
|
/// Gets or sets the Id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -74,7 +65,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required. Max Length = 32.
|
/// Required. Max Length = 32.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(32)]
|
[MaxLength(32)]
|
||||||
[StringLength(32)]
|
[StringLength(32)]
|
||||||
public string Client { get; set; }
|
public string Client { get; set; }
|
||||||
|
@ -145,14 +135,14 @@ namespace Jellyfin.Data.Entities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MaxLength(32)]
|
[MaxLength(32)]
|
||||||
[StringLength(32)]
|
[StringLength(32)]
|
||||||
public string DashboardTheme { get; set; }
|
public string? DashboardTheme { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the tv home screen.
|
/// Gets or sets the tv home screen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MaxLength(32)]
|
[MaxLength(32)]
|
||||||
[StringLength(32)]
|
[StringLength(32)]
|
||||||
public string TvHome { get; set; }
|
public string? TvHome { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the home sections.
|
/// Gets or sets the home sections.
|
||||||
|
|
|
@ -32,16 +32,6 @@ namespace Jellyfin.Data.Entities
|
||||||
Preferences = new HashSet<Preference>();
|
Preferences = new HashSet<Preference>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Group"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Group()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id of this group.
|
/// Gets or sets the id of this group.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -56,7 +46,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 255.
|
/// Required, Max length = 255.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
|
@ -15,7 +15,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Identity. Required.
|
/// Identity. Required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Key]
|
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
public int Id { get; protected set; }
|
public int Id { get; protected set; }
|
||||||
|
|
||||||
|
|
|
@ -19,16 +19,6 @@ namespace Jellyfin.Data.Entities
|
||||||
LastModified = DateTime.UtcNow;
|
LastModified = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ImageInfo"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected ImageInfo()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -49,7 +39,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required.
|
/// Required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(512)]
|
[MaxLength(512)]
|
||||||
[StringLength(512)]
|
[StringLength(512)]
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
|
|
@ -28,13 +28,6 @@ namespace Jellyfin.Data.Entities
|
||||||
RememberIndexing = false;
|
RememberIndexing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ItemDisplayPreferences"/> class.
|
|
||||||
/// </summary>
|
|
||||||
protected ItemDisplayPreferences()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Id.
|
/// Gets or sets the Id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -66,7 +59,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required. Max Length = 32.
|
/// Required. Max Length = 32.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(32)]
|
[MaxLength(32)]
|
||||||
[StringLength(32)]
|
[StringLength(32)]
|
||||||
public string Client { get; set; }
|
public string Client { get; set; }
|
||||||
|
@ -106,7 +98,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required.
|
/// Required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(64)]
|
[MaxLength(64)]
|
||||||
[StringLength(64)]
|
[StringLength(64)]
|
||||||
public string SortBy { get; set; }
|
public string SortBy { get; set; }
|
||||||
|
|
|
@ -18,8 +18,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <param name="kind">The kind of art.</param>
|
/// <param name="kind">The kind of art.</param>
|
||||||
/// <param name="owner">The owner.</param>
|
public Artwork(string path, ArtKind kind)
|
||||||
public Artwork(string path, ArtKind kind, IHasArtwork owner)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
|
@ -28,18 +27,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
|
|
||||||
Path = path;
|
Path = path;
|
||||||
Kind = kind;
|
Kind = kind;
|
||||||
|
|
||||||
owner?.Artwork.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Artwork"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Artwork()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -57,7 +44,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 65535.
|
/// Required, Max length = 65535.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(65535)]
|
[MaxLength(65535)]
|
||||||
[StringLength(65535)]
|
[StringLength(65535)]
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
|
|
@ -13,7 +13,8 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Book"/> class.
|
/// Initializes a new instance of the <see cref="Book"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Book()
|
/// <param name="library">The library.</param>
|
||||||
|
public Book(Library library) : base(library)
|
||||||
{
|
{
|
||||||
BookMetadata = new HashSet<BookMetadata>();
|
BookMetadata = new HashSet<BookMetadata>();
|
||||||
Releases = new HashSet<Release>();
|
Releases = new HashSet<Release>();
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#pragma warning disable CA2227
|
#pragma warning disable CA2227
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using Jellyfin.Data.Interfaces;
|
using Jellyfin.Data.Interfaces;
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities.Libraries
|
namespace Jellyfin.Data.Entities.Libraries
|
||||||
|
@ -17,29 +15,11 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title or name of the object.</param>
|
/// <param name="title">The title or name of the object.</param>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="book">The book.</param>
|
public BookMetadata(string title, string language) : base(title, language)
|
||||||
public BookMetadata(string title, string language, Book book) : base(title, language)
|
|
||||||
{
|
{
|
||||||
if (book == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(book));
|
|
||||||
}
|
|
||||||
|
|
||||||
book.BookMetadata.Add(this);
|
|
||||||
|
|
||||||
Publishers = new HashSet<Company>();
|
Publishers = new HashSet<Company>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BookMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected BookMetadata()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the ISBN.
|
/// Gets or sets the ISBN.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -51,7 +31,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
public virtual ICollection<Company> Publishers { get; protected set; }
|
public virtual ICollection<Company> Publishers { get; protected set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[NotMapped]
|
|
||||||
public ICollection<Company> Companies => Publishers;
|
public ICollection<Company> Companies => Publishers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="startTime">The start time for this chapter.</param>
|
/// <param name="startTime">The start time for this chapter.</param>
|
||||||
/// <param name="release">The release.</param>
|
public Chapter(string language, long startTime)
|
||||||
public Chapter(string language, long startTime, Release release)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(language))
|
if (string.IsNullOrEmpty(language))
|
||||||
{
|
{
|
||||||
|
@ -27,23 +26,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
|
|
||||||
Language = language;
|
Language = language;
|
||||||
StartTime = startTime;
|
StartTime = startTime;
|
||||||
|
|
||||||
if (release == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(release));
|
|
||||||
}
|
|
||||||
|
|
||||||
release.Chapters.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Chapter"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Chapter()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -63,7 +45,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the language.
|
/// Gets or sets the language.
|
||||||
|
@ -72,7 +54,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// Required, Min length = 3, Max length = 3
|
/// Required, Min length = 3, Max length = 3
|
||||||
/// ISO-639-3 3-character language codes.
|
/// ISO-639-3 3-character language codes.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MinLength(3)]
|
[MinLength(3)]
|
||||||
[MaxLength(3)]
|
[MaxLength(3)]
|
||||||
[StringLength(3)]
|
[StringLength(3)]
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#pragma warning disable CA1711 // Identifiers should not have incorrect suffix
|
||||||
#pragma warning disable CA2227
|
#pragma warning disable CA2227
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -37,7 +38,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[ConcurrencyCheck]
|
[ConcurrencyCheck]
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Jellyfin.Data.Interfaces;
|
using Jellyfin.Data.Interfaces;
|
||||||
|
@ -13,39 +12,10 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="CollectionItem"/> class.
|
/// Initializes a new instance of the <see cref="CollectionItem"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="collection">The collection.</param>
|
/// <param name="libraryItem">The library item.</param>
|
||||||
/// <param name="previous">The previous item.</param>
|
public CollectionItem(LibraryItem libraryItem)
|
||||||
/// <param name="next">The next item.</param>
|
|
||||||
public CollectionItem(Collection collection, CollectionItem previous, CollectionItem next)
|
|
||||||
{
|
|
||||||
if (collection == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(collection));
|
|
||||||
}
|
|
||||||
|
|
||||||
collection.Items.Add(this);
|
|
||||||
|
|
||||||
if (next != null)
|
|
||||||
{
|
|
||||||
Next = next;
|
|
||||||
next.Previous = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previous != null)
|
|
||||||
{
|
|
||||||
Previous = previous;
|
|
||||||
previous.Next = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="CollectionItem"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected CollectionItem()
|
|
||||||
{
|
{
|
||||||
|
LibraryItem = libraryItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -75,7 +45,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// TODO check if this properly updated Dependant and has the proper principal relationship.
|
/// TODO check if this properly updated Dependant and has the proper principal relationship.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual CollectionItem Next { get; set; }
|
public virtual CollectionItem? Next { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the previous item in the collection.
|
/// Gets or sets the previous item in the collection.
|
||||||
|
@ -83,7 +53,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// TODO check if this properly updated Dependant and has the proper principal relationship.
|
/// TODO check if this properly updated Dependant and has the proper principal relationship.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual CollectionItem Previous { get; set; }
|
public virtual CollectionItem? Previous { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void OnSavingChanges()
|
public void OnSavingChanges()
|
||||||
|
|
|
@ -15,22 +15,10 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Company"/> class.
|
/// Initializes a new instance of the <see cref="Company"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="owner">The owner of this company.</param>
|
public Company()
|
||||||
public Company(IHasCompanies owner)
|
|
||||||
{
|
{
|
||||||
owner?.Companies.Add(this);
|
|
||||||
|
|
||||||
CompanyMetadata = new HashSet<CompanyMetadata>();
|
CompanyMetadata = new HashSet<CompanyMetadata>();
|
||||||
}
|
ChildCompanies = new HashSet<Company>();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Company"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Company()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -57,7 +45,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
public virtual ICollection<Company> ChildCompanies { get; protected set; }
|
public virtual ICollection<Company> ChildCompanies { get; protected set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[NotMapped]
|
|
||||||
public ICollection<Company> Companies => ChildCompanies;
|
public ICollection<Company> Companies => ChildCompanies;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities.Libraries
|
namespace Jellyfin.Data.Entities.Libraries
|
||||||
|
@ -13,21 +12,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title or name of the object.</param>
|
/// <param name="title">The title or name of the object.</param>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="company">The company.</param>
|
public CompanyMetadata(string title, string language) : base(title, language)
|
||||||
public CompanyMetadata(string title, string language, Company company) : base(title, language)
|
|
||||||
{
|
|
||||||
if (company == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(company));
|
|
||||||
}
|
|
||||||
|
|
||||||
company.CompanyMetadata.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="CompanyMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
protected CompanyMetadata()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +24,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(65535)]
|
[MaxLength(65535)]
|
||||||
[StringLength(65535)]
|
[StringLength(65535)]
|
||||||
public string Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the headquarters.
|
/// Gets or sets the headquarters.
|
||||||
|
@ -49,7 +34,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string Headquarters { get; set; }
|
public string? Headquarters { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the country code.
|
/// Gets or sets the country code.
|
||||||
|
@ -59,7 +44,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(2)]
|
[MaxLength(2)]
|
||||||
[StringLength(2)]
|
[StringLength(2)]
|
||||||
public string Country { get; set; }
|
public string? Country { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the homepage.
|
/// Gets or sets the homepage.
|
||||||
|
@ -69,6 +54,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Homepage { get; set; }
|
public string? Homepage { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="CustomItem"/> class.
|
/// Initializes a new instance of the <see cref="CustomItem"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CustomItem()
|
/// <param name="library">The library.</param>
|
||||||
|
public CustomItem(Library library) : base(library)
|
||||||
{
|
{
|
||||||
CustomItemMetadata = new HashSet<CustomItemMetadata>();
|
CustomItemMetadata = new HashSet<CustomItemMetadata>();
|
||||||
Releases = new HashSet<Release>();
|
Releases = new HashSet<Release>();
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities.Libraries
|
namespace Jellyfin.Data.Entities.Libraries
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -12,24 +10,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title or name of the object.</param>
|
/// <param name="title">The title or name of the object.</param>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="item">The item.</param>
|
public CustomItemMetadata(string title, string language) : base(title, language)
|
||||||
public CustomItemMetadata(string title, string language, CustomItem item) : base(title, language)
|
|
||||||
{
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
item.CustomItemMetadata.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="CustomItemMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected CustomItemMetadata()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma warning disable CA2227
|
#pragma warning disable CA2227
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Jellyfin.Data.Interfaces;
|
using Jellyfin.Data.Interfaces;
|
||||||
|
|
||||||
|
@ -14,30 +13,13 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Episode"/> class.
|
/// Initializes a new instance of the <see cref="Episode"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="season">The season.</param>
|
/// <param name="library">The library.</param>
|
||||||
public Episode(Season season)
|
public Episode(Library library) : base(library)
|
||||||
{
|
{
|
||||||
if (season == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(season));
|
|
||||||
}
|
|
||||||
|
|
||||||
season.Episodes.Add(this);
|
|
||||||
|
|
||||||
Releases = new HashSet<Release>();
|
Releases = new HashSet<Release>();
|
||||||
EpisodeMetadata = new HashSet<EpisodeMetadata>();
|
EpisodeMetadata = new HashSet<EpisodeMetadata>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Episode"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Episode()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the episode number.
|
/// Gets or sets the episode number.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities.Libraries
|
namespace Jellyfin.Data.Entities.Libraries
|
||||||
|
@ -13,24 +12,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title or name of the object.</param>
|
/// <param name="title">The title or name of the object.</param>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="episode">The episode.</param>
|
public EpisodeMetadata(string title, string language) : base(title, language)
|
||||||
public EpisodeMetadata(string title, string language, Episode episode) : base(title, language)
|
|
||||||
{
|
|
||||||
if (episode == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(episode));
|
|
||||||
}
|
|
||||||
|
|
||||||
episode.EpisodeMetadata.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="EpisodeMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected EpisodeMetadata()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +24,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Outline { get; set; }
|
public string? Outline { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the plot.
|
/// Gets or sets the plot.
|
||||||
|
@ -52,7 +34,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(65535)]
|
[MaxLength(65535)]
|
||||||
[StringLength(65535)]
|
[StringLength(65535)]
|
||||||
public string Plot { get; set; }
|
public string? Plot { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the tagline.
|
/// Gets or sets the tagline.
|
||||||
|
@ -62,6 +44,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Tagline { get; set; }
|
public string? Tagline { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Jellyfin.Data.Interfaces;
|
using Jellyfin.Data.Interfaces;
|
||||||
|
@ -14,32 +13,9 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// Initializes a new instance of the <see cref="Genre"/> class.
|
/// Initializes a new instance of the <see cref="Genre"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name.</param>
|
/// <param name="name">The name.</param>
|
||||||
/// <param name="itemMetadata">The metadata.</param>
|
public Genre(string name)
|
||||||
public Genre(string name, ItemMetadata itemMetadata)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name))
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|
||||||
if (itemMetadata == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(itemMetadata));
|
|
||||||
}
|
|
||||||
|
|
||||||
itemMetadata.Genres.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Genre"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Genre()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -57,7 +33,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Indexed, Required, Max length = 255.
|
/// Indexed, Required, Max length = 255.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
|
@ -42,16 +42,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
Sources = new HashSet<MetadataProviderId>();
|
Sources = new HashSet<MetadataProviderId>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ItemMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to being abstract.
|
|
||||||
/// </remarks>
|
|
||||||
protected ItemMetadata()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -67,7 +57,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 1024.
|
/// Required, Max length = 1024.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
|
@ -80,7 +69,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string OriginalTitle { get; set; }
|
public string? OriginalTitle { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the sort title.
|
/// Gets or sets the sort title.
|
||||||
|
@ -90,7 +79,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string SortTitle { get; set; }
|
public string? SortTitle { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the language.
|
/// Gets or sets the language.
|
||||||
|
@ -99,7 +88,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// Required, Min length = 3, Max length = 3.
|
/// Required, Min length = 3, Max length = 3.
|
||||||
/// ISO-639-3 3-character language codes.
|
/// ISO-639-3 3-character language codes.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MinLength(3)]
|
[MinLength(3)]
|
||||||
[MaxLength(3)]
|
[MaxLength(3)]
|
||||||
[StringLength(3)]
|
[StringLength(3)]
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Jellyfin.Data.Interfaces;
|
using Jellyfin.Data.Interfaces;
|
||||||
|
@ -14,24 +13,11 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// Initializes a new instance of the <see cref="Library"/> class.
|
/// Initializes a new instance of the <see cref="Library"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the library.</param>
|
/// <param name="name">The name of the library.</param>
|
||||||
public Library(string name)
|
/// <param name="path">The path of the library.</param>
|
||||||
|
public Library(string name, string path)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
Name = name;
|
Name = name;
|
||||||
}
|
Path = path;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Library"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Library()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -49,7 +35,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 128.
|
/// Required, Max length = 128.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(128)]
|
[MaxLength(128)]
|
||||||
[StringLength(128)]
|
[StringLength(128)]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
@ -60,7 +45,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required.
|
/// Required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
@ -20,13 +20,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
Library = library;
|
Library = library;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="LibraryItem"/> class.
|
|
||||||
/// </summary>
|
|
||||||
protected LibraryItem()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -51,7 +44,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required.
|
/// Required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
public virtual Library Library { get; set; }
|
public virtual Library Library { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
@ -19,8 +19,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path relative to the LibraryRoot.</param>
|
/// <param name="path">The path relative to the LibraryRoot.</param>
|
||||||
/// <param name="kind">The file kind.</param>
|
/// <param name="kind">The file kind.</param>
|
||||||
/// <param name="release">The release.</param>
|
public MediaFile(string path, MediaFileKind kind)
|
||||||
public MediaFile(string path, MediaFileKind kind, Release release)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
|
@ -30,26 +29,9 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
Path = path;
|
Path = path;
|
||||||
Kind = kind;
|
Kind = kind;
|
||||||
|
|
||||||
if (release == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(release));
|
|
||||||
}
|
|
||||||
|
|
||||||
release.MediaFiles.Add(this);
|
|
||||||
|
|
||||||
MediaFileStreams = new HashSet<MediaFileStream>();
|
MediaFileStreams = new HashSet<MediaFileStream>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MediaFile"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected MediaFile()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -65,7 +47,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 65535.
|
/// Required, Max length = 65535.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(65535)]
|
[MaxLength(65535)]
|
||||||
[StringLength(65535)]
|
[StringLength(65535)]
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
#pragma warning disable CA1711 // Identifiers should not have incorrect suffix
|
||||||
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Jellyfin.Data.Interfaces;
|
using Jellyfin.Data.Interfaces;
|
||||||
|
@ -14,27 +15,9 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// Initializes a new instance of the <see cref="MediaFileStream"/> class.
|
/// Initializes a new instance of the <see cref="MediaFileStream"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="streamNumber">The number of this stream.</param>
|
/// <param name="streamNumber">The number of this stream.</param>
|
||||||
/// <param name="mediaFile">The media file.</param>
|
public MediaFileStream(int streamNumber)
|
||||||
public MediaFileStream(int streamNumber, MediaFile mediaFile)
|
|
||||||
{
|
{
|
||||||
StreamNumber = streamNumber;
|
StreamNumber = streamNumber;
|
||||||
|
|
||||||
if (mediaFile == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(mediaFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaFile.MediaFileStreams.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MediaFileStream"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected MediaFileStream()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -24,16 +24,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
Name = name;
|
Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MetadataProvider"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected MetadataProvider()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -49,7 +39,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 1024.
|
/// Required, Max length = 1024.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
|
@ -14,8 +14,8 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// Initializes a new instance of the <see cref="MetadataProviderId"/> class.
|
/// Initializes a new instance of the <see cref="MetadataProviderId"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="providerId">The provider id.</param>
|
/// <param name="providerId">The provider id.</param>
|
||||||
/// <param name="itemMetadata">The metadata entity.</param>
|
/// <param name="metadataProvider">The metadata provider.</param>
|
||||||
public MetadataProviderId(string providerId, ItemMetadata itemMetadata)
|
public MetadataProviderId(string providerId, MetadataProvider metadataProvider)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(providerId))
|
if (string.IsNullOrEmpty(providerId))
|
||||||
{
|
{
|
||||||
|
@ -23,23 +23,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
}
|
}
|
||||||
|
|
||||||
ProviderId = providerId;
|
ProviderId = providerId;
|
||||||
|
MetadataProvider = metadataProvider;
|
||||||
if (itemMetadata == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(itemMetadata));
|
|
||||||
}
|
|
||||||
|
|
||||||
itemMetadata.Sources.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MetadataProviderId"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected MetadataProviderId()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -57,7 +41,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 255.
|
/// Required, Max length = 255.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string ProviderId { get; set; }
|
public string ProviderId { get; set; }
|
||||||
|
|
|
@ -13,7 +13,8 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Movie"/> class.
|
/// Initializes a new instance of the <see cref="Movie"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Movie()
|
/// <param name="library">The library.</param>
|
||||||
|
public Movie(Library library) : base(library)
|
||||||
{
|
{
|
||||||
Releases = new HashSet<Release>();
|
Releases = new HashSet<Release>();
|
||||||
MovieMetadata = new HashSet<MovieMetadata>();
|
MovieMetadata = new HashSet<MovieMetadata>();
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using Jellyfin.Data.Interfaces;
|
using Jellyfin.Data.Interfaces;
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities.Libraries
|
namespace Jellyfin.Data.Entities.Libraries
|
||||||
|
@ -17,22 +16,9 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title or name of the movie.</param>
|
/// <param name="title">The title or name of the movie.</param>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="movie">The movie.</param>
|
public MovieMetadata(string title, string language) : base(title, language)
|
||||||
public MovieMetadata(string title, string language, Movie movie) : base(title, language)
|
|
||||||
{
|
{
|
||||||
Studios = new HashSet<Company>();
|
Studios = new HashSet<Company>();
|
||||||
|
|
||||||
movie.MovieMetadata.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MovieMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected MovieMetadata()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -43,7 +29,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Outline { get; set; }
|
public string? Outline { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the tagline.
|
/// Gets or sets the tagline.
|
||||||
|
@ -53,7 +39,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Tagline { get; set; }
|
public string? Tagline { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the plot.
|
/// Gets or sets the plot.
|
||||||
|
@ -63,7 +49,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(65535)]
|
[MaxLength(65535)]
|
||||||
[StringLength(65535)]
|
[StringLength(65535)]
|
||||||
public string Plot { get; set; }
|
public string? Plot { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the country code.
|
/// Gets or sets the country code.
|
||||||
|
@ -73,7 +59,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(2)]
|
[MaxLength(2)]
|
||||||
[StringLength(2)]
|
[StringLength(2)]
|
||||||
public string Country { get; set; }
|
public string? Country { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the studios that produced this movie.
|
/// Gets or sets the studios that produced this movie.
|
||||||
|
@ -81,7 +67,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
public virtual ICollection<Company> Studios { get; protected set; }
|
public virtual ICollection<Company> Studios { get; protected set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[NotMapped]
|
|
||||||
public ICollection<Company> Companies => Studios;
|
public ICollection<Company> Companies => Studios;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MusicAlbum"/> class.
|
/// Initializes a new instance of the <see cref="MusicAlbum"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MusicAlbum()
|
/// <param name="library">The library.</param>
|
||||||
|
public MusicAlbum(Library library) : base(library)
|
||||||
{
|
{
|
||||||
MusicAlbumMetadata = new HashSet<MusicAlbumMetadata>();
|
MusicAlbumMetadata = new HashSet<MusicAlbumMetadata>();
|
||||||
Tracks = new HashSet<Track>();
|
Tracks = new HashSet<Track>();
|
||||||
|
|
|
@ -15,22 +15,9 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title or name of the album.</param>
|
/// <param name="title">The title or name of the album.</param>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="album">The music album.</param>
|
public MusicAlbumMetadata(string title, string language) : base(title, language)
|
||||||
public MusicAlbumMetadata(string title, string language, MusicAlbum album) : base(title, language)
|
|
||||||
{
|
{
|
||||||
Labels = new HashSet<Company>();
|
Labels = new HashSet<Company>();
|
||||||
|
|
||||||
album.MusicAlbumMetadata.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MusicAlbumMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected MusicAlbumMetadata()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -41,7 +28,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string Barcode { get; set; }
|
public string? Barcode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the label number.
|
/// Gets or sets the label number.
|
||||||
|
@ -51,7 +38,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string LabelNumber { get; set; }
|
public string? LabelNumber { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the country code.
|
/// Gets or sets the country code.
|
||||||
|
@ -61,7 +48,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(2)]
|
[MaxLength(2)]
|
||||||
[StringLength(2)]
|
[StringLength(2)]
|
||||||
public string Country { get; set; }
|
public string? Country { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a collection containing the labels.
|
/// Gets or sets a collection containing the labels.
|
||||||
|
|
|
@ -31,16 +31,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
Sources = new HashSet<MetadataProviderId>();
|
Sources = new HashSet<MetadataProviderId>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Person"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Person()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -56,7 +46,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 1024.
|
/// Required, Max length = 1024.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
@ -69,7 +58,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(256)]
|
[MaxLength(256)]
|
||||||
[StringLength(256)]
|
[StringLength(256)]
|
||||||
public string SourceId { get; set; }
|
public string? SourceId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the date added.
|
/// Gets or sets the date added.
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma warning disable CA2227
|
#pragma warning disable CA2227
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
@ -18,31 +17,15 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// Initializes a new instance of the <see cref="PersonRole"/> class.
|
/// Initializes a new instance of the <see cref="PersonRole"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The role type.</param>
|
/// <param name="type">The role type.</param>
|
||||||
/// <param name="itemMetadata">The metadata.</param>
|
/// <param name="person">The person.</param>
|
||||||
public PersonRole(PersonRoleType type, ItemMetadata itemMetadata)
|
public PersonRole(PersonRoleType type, Person person)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
|
Person = person;
|
||||||
if (itemMetadata == null)
|
Artwork = new HashSet<Artwork>();
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(itemMetadata));
|
|
||||||
}
|
|
||||||
|
|
||||||
itemMetadata.PersonRoles.Add(this);
|
|
||||||
|
|
||||||
Sources = new HashSet<MetadataProviderId>();
|
Sources = new HashSet<MetadataProviderId>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="PersonRole"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected PersonRole()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -60,7 +43,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Role { get; set; }
|
public string? Role { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the person's role type.
|
/// Gets or sets the person's role type.
|
||||||
|
@ -80,7 +63,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required.
|
/// Required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
public virtual Person Person { get; set; }
|
public virtual Person Person { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
@ -13,7 +13,8 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Photo"/> class.
|
/// Initializes a new instance of the <see cref="Photo"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Photo()
|
/// <param name="library">The library.</param>
|
||||||
|
public Photo(Library library) : base(library)
|
||||||
{
|
{
|
||||||
PhotoMetadata = new HashSet<PhotoMetadata>();
|
PhotoMetadata = new HashSet<PhotoMetadata>();
|
||||||
Releases = new HashSet<Release>();
|
Releases = new HashSet<Release>();
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities.Libraries
|
namespace Jellyfin.Data.Entities.Libraries
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -12,24 +10,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title or name of the photo.</param>
|
/// <param name="title">The title or name of the photo.</param>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="photo">The photo.</param>
|
public PhotoMetadata(string title, string language) : base(title, language)
|
||||||
public PhotoMetadata(string title, string language, Photo photo) : base(title, language)
|
|
||||||
{
|
|
||||||
if (photo == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(photo));
|
|
||||||
}
|
|
||||||
|
|
||||||
photo.PhotoMetadata.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="PhotoMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected PhotoMetadata()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Jellyfin.Data.Interfaces;
|
using Jellyfin.Data.Interfaces;
|
||||||
|
@ -14,27 +13,9 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// Initializes a new instance of the <see cref="Rating"/> class.
|
/// Initializes a new instance of the <see cref="Rating"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
/// <param name="itemMetadata">The metadata.</param>
|
public Rating(double value)
|
||||||
public Rating(double value, ItemMetadata itemMetadata)
|
|
||||||
{
|
{
|
||||||
Value = value;
|
Value = value;
|
||||||
|
|
||||||
if (itemMetadata == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(itemMetadata));
|
|
||||||
}
|
|
||||||
|
|
||||||
itemMetadata.Ratings.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Rating"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Rating()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -67,7 +48,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// Gets or sets the rating type.
|
/// Gets or sets the rating type.
|
||||||
/// If this is <c>null</c> it's the internal user rating.
|
/// If this is <c>null</c> it's the internal user rating.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual RatingSource RatingType { get; set; }
|
public virtual RatingSource? RatingType { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void OnSavingChanges()
|
public void OnSavingChanges()
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Jellyfin.Data.Interfaces;
|
using Jellyfin.Data.Interfaces;
|
||||||
|
@ -15,28 +14,10 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="minimumValue">The minimum value.</param>
|
/// <param name="minimumValue">The minimum value.</param>
|
||||||
/// <param name="maximumValue">The maximum value.</param>
|
/// <param name="maximumValue">The maximum value.</param>
|
||||||
/// <param name="rating">The rating.</param>
|
public RatingSource(double minimumValue, double maximumValue)
|
||||||
public RatingSource(double minimumValue, double maximumValue, Rating rating)
|
|
||||||
{
|
{
|
||||||
MinimumValue = minimumValue;
|
MinimumValue = minimumValue;
|
||||||
MaximumValue = maximumValue;
|
MaximumValue = maximumValue;
|
||||||
|
|
||||||
if (rating == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(rating));
|
|
||||||
}
|
|
||||||
|
|
||||||
rating.RatingType = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="RatingSource"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected RatingSource()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -56,7 +37,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the minimum value.
|
/// Gets or sets the minimum value.
|
||||||
|
@ -81,7 +62,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the metadata source.
|
/// Gets or sets the metadata source.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual MetadataProviderId Source { get; set; }
|
public virtual MetadataProviderId? Source { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void OnSavingChanges()
|
public void OnSavingChanges()
|
||||||
|
|
|
@ -17,8 +17,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// Initializes a new instance of the <see cref="Release"/> class.
|
/// Initializes a new instance of the <see cref="Release"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of this release.</param>
|
/// <param name="name">The name of this release.</param>
|
||||||
/// <param name="owner">The owner of this release.</param>
|
public Release(string name)
|
||||||
public Release(string name, IHasReleases owner)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
{
|
{
|
||||||
|
@ -27,22 +26,10 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
|
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|
||||||
owner?.Releases.Add(this);
|
|
||||||
|
|
||||||
MediaFiles = new HashSet<MediaFile>();
|
MediaFiles = new HashSet<MediaFile>();
|
||||||
Chapters = new HashSet<Chapter>();
|
Chapters = new HashSet<Chapter>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Release"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Release()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id.
|
/// Gets or sets the id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -58,7 +45,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 1024.
|
/// Required, Max length = 1024.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma warning disable CA2227
|
#pragma warning disable CA2227
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities.Libraries
|
namespace Jellyfin.Data.Entities.Libraries
|
||||||
|
@ -13,30 +12,13 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Season"/> class.
|
/// Initializes a new instance of the <see cref="Season"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="series">The series.</param>
|
/// <param name="library">The library.</param>
|
||||||
public Season(Series series)
|
public Season(Library library) : base(library)
|
||||||
{
|
{
|
||||||
if (series == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(series));
|
|
||||||
}
|
|
||||||
|
|
||||||
series.Seasons.Add(this);
|
|
||||||
|
|
||||||
Episodes = new HashSet<Episode>();
|
Episodes = new HashSet<Episode>();
|
||||||
SeasonMetadata = new HashSet<SeasonMetadata>();
|
SeasonMetadata = new HashSet<SeasonMetadata>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Season"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Season()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the season number.
|
/// Gets or sets the season number.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities.Libraries
|
namespace Jellyfin.Data.Entities.Libraries
|
||||||
|
@ -13,24 +12,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title or name of the object.</param>
|
/// <param name="title">The title or name of the object.</param>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="season">The season.</param>
|
public SeasonMetadata(string title, string language) : base(title, language)
|
||||||
public SeasonMetadata(string title, string language, Season season) : base(title, language)
|
|
||||||
{
|
|
||||||
if (season == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(season));
|
|
||||||
}
|
|
||||||
|
|
||||||
season.SeasonMetadata.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="SeasonMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected SeasonMetadata()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +24,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Outline { get; set; }
|
public string? Outline { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Series"/> class.
|
/// Initializes a new instance of the <see cref="Series"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Series()
|
/// <param name="library">The library.</param>
|
||||||
|
public Series(Library library) : base(library)
|
||||||
{
|
{
|
||||||
DateAdded = DateTime.UtcNow;
|
DateAdded = DateTime.UtcNow;
|
||||||
Seasons = new HashSet<Season>();
|
Seasons = new HashSet<Season>();
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma warning disable CA2227
|
#pragma warning disable CA2227
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
@ -18,29 +17,11 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title or name of the object.</param>
|
/// <param name="title">The title or name of the object.</param>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="series">The series.</param>
|
public SeriesMetadata(string title, string language) : base(title, language)
|
||||||
public SeriesMetadata(string title, string language, Series series) : base(title, language)
|
|
||||||
{
|
{
|
||||||
if (series == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(series));
|
|
||||||
}
|
|
||||||
|
|
||||||
series.SeriesMetadata.Add(this);
|
|
||||||
|
|
||||||
Networks = new HashSet<Company>();
|
Networks = new HashSet<Company>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="SeriesMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected SeriesMetadata()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the outline.
|
/// Gets or sets the outline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -49,7 +30,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Outline { get; set; }
|
public string? Outline { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the plot.
|
/// Gets or sets the plot.
|
||||||
|
@ -59,7 +40,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(65535)]
|
[MaxLength(65535)]
|
||||||
[StringLength(65535)]
|
[StringLength(65535)]
|
||||||
public string Plot { get; set; }
|
public string? Plot { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the tagline.
|
/// Gets or sets the tagline.
|
||||||
|
@ -69,7 +50,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(1024)]
|
[MaxLength(1024)]
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string Tagline { get; set; }
|
public string? Tagline { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the country code.
|
/// Gets or sets the country code.
|
||||||
|
@ -79,7 +60,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(2)]
|
[MaxLength(2)]
|
||||||
[StringLength(2)]
|
[StringLength(2)]
|
||||||
public string Country { get; set; }
|
public string? Country { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a collection containing the networks.
|
/// Gets or sets a collection containing the networks.
|
||||||
|
@ -87,7 +68,6 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
public virtual ICollection<Company> Networks { get; protected set; }
|
public virtual ICollection<Company> Networks { get; protected set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[NotMapped]
|
|
||||||
public ICollection<Company> Companies => Networks;
|
public ICollection<Company> Companies => Networks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma warning disable CA2227
|
#pragma warning disable CA2227
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Jellyfin.Data.Interfaces;
|
using Jellyfin.Data.Interfaces;
|
||||||
|
|
||||||
|
@ -14,30 +13,13 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Track"/> class.
|
/// Initializes a new instance of the <see cref="Track"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="album">The album.</param>
|
/// <param name="library">The library.</param>
|
||||||
public Track(MusicAlbum album)
|
public Track(Library library) : base(library)
|
||||||
{
|
{
|
||||||
if (album == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(album));
|
|
||||||
}
|
|
||||||
|
|
||||||
album.Tracks.Add(this);
|
|
||||||
|
|
||||||
Releases = new HashSet<Release>();
|
Releases = new HashSet<Release>();
|
||||||
TrackMetadata = new HashSet<TrackMetadata>();
|
TrackMetadata = new HashSet<TrackMetadata>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Track"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected Track()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the track number.
|
/// Gets or sets the track number.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities.Libraries
|
namespace Jellyfin.Data.Entities.Libraries
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -12,24 +10,7 @@ namespace Jellyfin.Data.Entities.Libraries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title or name of the object.</param>
|
/// <param name="title">The title or name of the object.</param>
|
||||||
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
/// <param name="language">ISO-639-3 3-character language codes.</param>
|
||||||
/// <param name="track">The track.</param>
|
public TrackMetadata(string title, string language) : base(title, language)
|
||||||
public TrackMetadata(string title, string language, Track track) : base(title, language)
|
|
||||||
{
|
|
||||||
if (track == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(track));
|
|
||||||
}
|
|
||||||
|
|
||||||
track.TrackMetadata.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="TrackMetadata"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </remarks>
|
|
||||||
protected TrackMetadata()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable CA1711 // Identifiers should not have incorrect suffix
|
||||||
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Jellyfin.Data.Enums;
|
using Jellyfin.Data.Enums;
|
||||||
|
@ -22,14 +24,6 @@ namespace Jellyfin.Data.Entities
|
||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Permission"/> class.
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </summary>
|
|
||||||
protected Permission()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id of this permission.
|
/// Gets or sets the id of this permission.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -23,14 +23,6 @@ namespace Jellyfin.Data.Entities
|
||||||
Value = value ?? throw new ArgumentNullException(nameof(value));
|
Value = value ?? throw new ArgumentNullException(nameof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Preference"/> class.
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </summary>
|
|
||||||
protected Preference()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the id of this preference.
|
/// Gets or sets the id of this preference.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -54,7 +46,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 65535.
|
/// Required, Max length = 65535.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(65535)]
|
[MaxLength(65535)]
|
||||||
[StringLength(65535)]
|
[StringLength(65535)]
|
||||||
public string Value { get; set; }
|
public string Value { get; set; }
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace Jellyfin.Data.Entities
|
||||||
PasswordResetProviderId = passwordResetProviderId;
|
PasswordResetProviderId = passwordResetProviderId;
|
||||||
|
|
||||||
AccessSchedules = new HashSet<AccessSchedule>();
|
AccessSchedules = new HashSet<AccessSchedule>();
|
||||||
|
DisplayPreferences = new HashSet<DisplayPreferences>();
|
||||||
ItemDisplayPreferences = new HashSet<ItemDisplayPreferences>();
|
ItemDisplayPreferences = new HashSet<ItemDisplayPreferences>();
|
||||||
// Groups = new HashSet<Group>();
|
// Groups = new HashSet<Group>();
|
||||||
Permissions = new HashSet<Permission>();
|
Permissions = new HashSet<Permission>();
|
||||||
|
@ -72,17 +73,6 @@ namespace Jellyfin.Data.Entities
|
||||||
PlayDefaultAudioTrack = true;
|
PlayDefaultAudioTrack = true;
|
||||||
SubtitleMode = SubtitlePlaybackMode.Default;
|
SubtitleMode = SubtitlePlaybackMode.Default;
|
||||||
SyncPlayAccess = SyncPlayUserAccessType.CreateAndJoinGroups;
|
SyncPlayAccess = SyncPlayUserAccessType.CreateAndJoinGroups;
|
||||||
|
|
||||||
AddDefaultPermissions();
|
|
||||||
AddDefaultPreferences();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="User"/> class.
|
|
||||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
|
||||||
/// </summary>
|
|
||||||
protected User()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -100,7 +90,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 255.
|
/// Required, Max length = 255.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
|
@ -113,7 +102,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(65535)]
|
[MaxLength(65535)]
|
||||||
[StringLength(65535)]
|
[StringLength(65535)]
|
||||||
public string Password { get; set; }
|
public string? Password { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the user's easy password, or <c>null</c> if none is set.
|
/// Gets or sets the user's easy password, or <c>null</c> if none is set.
|
||||||
|
@ -123,7 +112,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(65535)]
|
[MaxLength(65535)]
|
||||||
[StringLength(65535)]
|
[StringLength(65535)]
|
||||||
public string EasyPassword { get; set; }
|
public string? EasyPassword { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether the user must update their password.
|
/// Gets or sets a value indicating whether the user must update their password.
|
||||||
|
@ -141,7 +130,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string AudioLanguagePreference { get; set; }
|
public string? AudioLanguagePreference { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the authentication provider id.
|
/// Gets or sets the authentication provider id.
|
||||||
|
@ -149,7 +138,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 255.
|
/// Required, Max length = 255.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string AuthenticationProviderId { get; set; }
|
public string AuthenticationProviderId { get; set; }
|
||||||
|
@ -160,7 +148,6 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required, Max length = 255.
|
/// Required, Max length = 255.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string PasswordResetProviderId { get; set; }
|
public string PasswordResetProviderId { get; set; }
|
||||||
|
@ -217,7 +204,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[MaxLength(255)]
|
[MaxLength(255)]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string SubtitleLanguagePreference { get; set; }
|
public string? SubtitleLanguagePreference { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether missing episodes should be displayed.
|
/// Gets or sets a value indicating whether missing episodes should be displayed.
|
||||||
|
@ -312,7 +299,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// Gets or sets the user's profile image. Can be <c>null</c>.
|
/// Gets or sets the user's profile image. Can be <c>null</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// [ForeignKey("UserId")]
|
// [ForeignKey("UserId")]
|
||||||
public virtual ImageInfo ProfileImage { get; set; }
|
public virtual ImageInfo? ProfileImage { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the user's display preferences.
|
/// Gets or sets the user's display preferences.
|
||||||
|
@ -320,8 +307,7 @@ namespace Jellyfin.Data.Entities
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Required.
|
/// Required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Required]
|
public virtual ICollection<DisplayPreferences> DisplayPreferences { get; set; }
|
||||||
public virtual DisplayPreferences DisplayPreferences { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the level of sync play permissions this user has.
|
/// Gets or sets the level of sync play permissions this user has.
|
||||||
|
@ -494,18 +480,11 @@ namespace Jellyfin.Data.Entities
|
||||||
return Array.IndexOf(GetPreferenceValues<Guid>(PreferenceKind.GroupedFolders), id) != -1;
|
return Array.IndexOf(GetPreferenceValues<Guid>(PreferenceKind.GroupedFolders), id) != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsParentalScheduleAllowed(AccessSchedule schedule, DateTime date)
|
/// <summary>
|
||||||
{
|
/// Initializes the default permissions for a user. Should only be called on user creation.
|
||||||
var localTime = date.ToLocalTime();
|
/// </summary>
|
||||||
var hour = localTime.TimeOfDay.TotalHours;
|
|
||||||
|
|
||||||
return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek)
|
|
||||||
&& hour >= schedule.StartHour
|
|
||||||
&& hour <= schedule.EndHour;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: make these user configurable?
|
// TODO: make these user configurable?
|
||||||
private void AddDefaultPermissions()
|
public void AddDefaultPermissions()
|
||||||
{
|
{
|
||||||
Permissions.Add(new Permission(PermissionKind.IsAdministrator, false));
|
Permissions.Add(new Permission(PermissionKind.IsAdministrator, false));
|
||||||
Permissions.Add(new Permission(PermissionKind.IsDisabled, false));
|
Permissions.Add(new Permission(PermissionKind.IsDisabled, false));
|
||||||
|
@ -530,12 +509,25 @@ namespace Jellyfin.Data.Entities
|
||||||
Permissions.Add(new Permission(PermissionKind.EnableRemoteControlOfOtherUsers, false));
|
Permissions.Add(new Permission(PermissionKind.EnableRemoteControlOfOtherUsers, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddDefaultPreferences()
|
/// <summary>
|
||||||
|
/// Initializes the default preferences. Should only be called on user creation.
|
||||||
|
/// </summary>
|
||||||
|
public void AddDefaultPreferences()
|
||||||
{
|
{
|
||||||
foreach (var val in Enum.GetValues(typeof(PreferenceKind)).Cast<PreferenceKind>())
|
foreach (var val in Enum.GetValues(typeof(PreferenceKind)).Cast<PreferenceKind>())
|
||||||
{
|
{
|
||||||
Preferences.Add(new Preference(val, string.Empty));
|
Preferences.Add(new Preference(val, string.Empty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsParentalScheduleAllowed(AccessSchedule schedule, DateTime date)
|
||||||
|
{
|
||||||
|
var localTime = date.ToLocalTime();
|
||||||
|
var hour = localTime.TimeOfDay.TotalHours;
|
||||||
|
|
||||||
|
return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek)
|
||||||
|
&& hour >= schedule.StartHour
|
||||||
|
&& hour <= schedule.EndHour;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
using Jellyfin.Data.Enums;
|
using Jellyfin.Data.Enums;
|
||||||
|
|
||||||
namespace Jellyfin.Data
|
namespace Jellyfin.Data.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An abstraction representing an entity that has permissions.
|
/// An abstraction representing an entity that has permissions.
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
|
||||||
|
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<IncludeSymbols>true</IncludeSymbols>
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
|
@ -24,10 +27,6 @@
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
|
||||||
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -40,8 +39,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.3" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
|
||||||
|
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -30,6 +32,11 @@
|
||||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- Needed for https://github.com/dotnet/roslyn-analyzers/issues/4382 which is in the SDK yet -->
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3" PrivateAssets="All" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Code analysers-->
|
<!-- Code analysers-->
|
||||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
||||||
|
@ -37,8 +44,4 @@
|
||||||
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
|
||||||
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -274,8 +274,8 @@ namespace Jellyfin.Drawing.Skia
|
||||||
|
|
||||||
if (requiresTransparencyHack || forceCleanBitmap)
|
if (requiresTransparencyHack || forceCleanBitmap)
|
||||||
{
|
{
|
||||||
using var codec = SKCodec.Create(NormalizePath(path));
|
using SKCodec codec = SKCodec.Create(NormalizePath(path), out SKCodecResult res);
|
||||||
if (codec == null)
|
if (res != SKCodecResult.Success)
|
||||||
{
|
{
|
||||||
origin = GetSKEncodedOrigin(orientation);
|
origin = GetSKEncodedOrigin(orientation);
|
||||||
return null;
|
return null;
|
||||||
|
@ -345,11 +345,6 @@ namespace Jellyfin.Drawing.Skia
|
||||||
|
|
||||||
private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin)
|
private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin)
|
||||||
{
|
{
|
||||||
if (origin == SKEncodedOrigin.Default)
|
|
||||||
{
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
var needsFlip = origin == SKEncodedOrigin.LeftBottom
|
var needsFlip = origin == SKEncodedOrigin.LeftBottom
|
||||||
|| origin == SKEncodedOrigin.LeftTop
|
|| origin == SKEncodedOrigin.LeftTop
|
||||||
|| origin == SKEncodedOrigin.RightBottom
|
|| origin == SKEncodedOrigin.RightBottom
|
||||||
|
@ -447,7 +442,7 @@ namespace Jellyfin.Drawing.Skia
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
|
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat outputFormat)
|
||||||
{
|
{
|
||||||
if (inputPath.Length == 0)
|
if (inputPath.Length == 0)
|
||||||
{
|
{
|
||||||
|
@ -459,7 +454,7 @@ namespace Jellyfin.Drawing.Skia
|
||||||
throw new ArgumentException("String can't be empty.", nameof(outputPath));
|
throw new ArgumentException("String can't be empty.", nameof(outputPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
var skiaOutputFormat = GetImageFormat(selectedOutputFormat);
|
var skiaOutputFormat = GetImageFormat(outputFormat);
|
||||||
|
|
||||||
var hasBackgroundColor = !string.IsNullOrWhiteSpace(options.BackgroundColor);
|
var hasBackgroundColor = !string.IsNullOrWhiteSpace(options.BackgroundColor);
|
||||||
var hasForegroundColor = !string.IsNullOrWhiteSpace(options.ForegroundLayer);
|
var hasForegroundColor = !string.IsNullOrWhiteSpace(options.ForegroundLayer);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
|
||||||
|
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -18,10 +20,6 @@
|
||||||
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
|
||||||
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
||||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user