From 36312c92f56671484caaeaf89e28f7737723e97d Mon Sep 17 00:00:00 2001 From: Ken Brazier Date: Sun, 31 May 2020 16:40:02 -0600 Subject: [PATCH 01/93] 2354 open soft-links to read size --- Emby.Server.Implementations/IO/ManagedFileSystem.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 7461ec4f1d..8b75e8c708 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -245,6 +245,16 @@ namespace Emby.Server.Implementations.IO if (info is FileInfo fileInfo) { result.Length = fileInfo.Length; + + // Issue #2354 get the size of files behind symbolic links + if(fileInfo.Attributes.HasFlag(FileAttributes.ReparsePoint)) + { + using (Stream thisFileStream = File.OpenRead(fileInfo.ToString())) + { + result.Length = thisFileStream.Length; + } + } + result.DirectoryName = fileInfo.DirectoryName; } From ab10f210274ff46bf68b5af752a817bbd90f749a Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sun, 5 Jul 2020 17:47:23 +0100 Subject: [PATCH 02/93] Part 1 of a multi-PR change for Emby.DLNA --- .../ApplicationHost.cs | 40 ++++++++++++++++++- .../HttpServer/HttpListenerHost.cs | 5 +++ .../Services/ServiceController.cs | 4 +- MediaBrowser.Common/IApplicationHost.cs | 8 ++++ 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 18b6834ef5..f10ebdd01e 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -351,6 +351,42 @@ namespace Emby.Server.Implementations public object CreateInstance(Type type) => ActivatorUtilities.CreateInstance(ServiceProvider, type); + /// + /// Creates an instance of type and resolves all constructor dependencies. + /// + /// The type. + /// Additional argument for the constructor. + /// + public object CreateInstance(Type type, object parameter) + { + ConstructorInfo constructor = type.GetConstructors()[0]; + if (constructor != null) + { + ParameterInfo[] argInfo = constructor + .GetParameters(); + + object[] args = argInfo + .Select(o => o.ParameterType) + .Select(o => ServiceProvider.GetService(o)) + .ToArray(); + + if (parameter != null) + { + // Assumption is that the is always the last in the constructor's parameter list. + int argsLen = args.Length; + var argType = argInfo[argsLen - 1].ParameterType; + var paramType = parameter.GetType(); + if (argType.IsAssignableFrom(paramType) || argType == paramType) + { + args[argsLen - 1] = parameter; + return ActivatorUtilities.CreateInstance(ServiceProvider, type, args); + } + } + } + + return ActivatorUtilities.CreateInstance(ServiceProvider, type); + } + /// /// Creates an instance of type and resolves all constructor dependencies. /// @@ -566,8 +602,10 @@ namespace Emby.Server.Implementations serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); // TODO: Refactor to eliminate the circular dependency here so that Lazy isn't required + // TODO: Add StartupOptions.FFmpegPath to IConfiguration and remove this custom activation serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(provider => + ActivatorUtilities.CreateInstance(provider, _startupOptions.FFmpegPath ?? string.Empty)); // TODO: Refactor to eliminate the circular dependencies here so that Lazy isn't required serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index c3428ee62a..6860b7ecdf 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -107,6 +107,11 @@ namespace Emby.Server.Implementations.HttpServer return _appHost.CreateInstance(type); } + public object CreateInstance(Type type, object parameter) + { + return _appHost.CreateInstance(type, parameter); + } + private static string NormalizeUrlPath(string path) { if (path.Length > 0 && path[0] == '/') diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs index 857df591a1..2a780feb58 100644 --- a/Emby.Server.Implementations/Services/ServiceController.cs +++ b/Emby.Server.Implementations/Services/ServiceController.cs @@ -177,8 +177,8 @@ namespace Emby.Server.Implementations.Services var serviceType = httpHost.GetServiceTypeByRequest(requestType); - var service = httpHost.CreateInstance(serviceType); - + var service = httpHost.CreateInstance(serviceType, req); + var serviceRequiresContext = service as IRequiresRequest; if (serviceRequiresContext != null) { diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index e8d9282e40..cf4954eef1 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -125,5 +125,13 @@ namespace MediaBrowser.Common /// The type. /// System.Object. object CreateInstance(Type type); + + /// + /// Creates a new instance of a class. + /// + /// The type to create. + /// An addtional parameter. + /// Created instance. + object CreateInstance(Type type, object parameter); } } From 70c638d1d48178bc1458fe86a48b2b60b06b7171 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sun, 5 Jul 2020 18:12:56 +0100 Subject: [PATCH 03/93] Updated code as per jellyfin/master as version i amended didn't execute. --- Emby.Server.Implementations/ApplicationHost.cs | 3 +-- Emby.Server.Implementations/Services/ServiceController.cs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index f10ebdd01e..4d99bd759d 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -604,8 +604,7 @@ namespace Emby.Server.Implementations // TODO: Refactor to eliminate the circular dependency here so that Lazy isn't required // TODO: Add StartupOptions.FFmpegPath to IConfiguration and remove this custom activation serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); - serviceCollection.AddSingleton(provider => - ActivatorUtilities.CreateInstance(provider, _startupOptions.FFmpegPath ?? string.Empty)); + serviceCollection.AddSingleton(); // TODO: Refactor to eliminate the circular dependencies here so that Lazy isn't required serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs index 2a780feb58..b1f2a68273 100644 --- a/Emby.Server.Implementations/Services/ServiceController.cs +++ b/Emby.Server.Implementations/Services/ServiceController.cs @@ -178,7 +178,7 @@ namespace Emby.Server.Implementations.Services var serviceType = httpHost.GetServiceTypeByRequest(requestType); var service = httpHost.CreateInstance(serviceType, req); - + var serviceRequiresContext = service as IRequiresRequest; if (serviceRequiresContext != null) { @@ -189,5 +189,4 @@ namespace Emby.Server.Implementations.Services return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName()); } } - } From 29c4220227a5c31d0a34df4e2808dff88045db41 Mon Sep 17 00:00:00 2001 From: Sacha Korban Date: Tue, 7 Jul 2020 19:50:12 +1000 Subject: [PATCH 04/93] Fix support for mixed-protocol external subtitles --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index f1aa8ea5f8..a971115c9b 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -172,7 +172,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles inputFiles = new[] { mediaSource.Path }; } - var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false); + var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, _mediaSourceManager.GetPathProtocol(subtitleStream.Path), subtitleStream, cancellationToken).ConfigureAwait(false); var stream = await GetSubtitleStream(fileInfo.Path, fileInfo.Protocol, fileInfo.IsExternal, cancellationToken).ConfigureAwait(false); From 7367e667f78057d0e26b8dc4f2b7f8641366b86a Mon Sep 17 00:00:00 2001 From: David Date: Sat, 11 Jul 2020 12:35:18 +0200 Subject: [PATCH 05/93] Add socket support --- Jellyfin.Server/Program.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index ef3ebe90cb..025de916f5 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -343,6 +343,21 @@ namespace Jellyfin.Server } } } + + // Bind to unix socket (only on OSX and Linux) + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // TODO: allow configuration of socket path + var socketPath = $"{appPaths.DataPath}/socket.sock"; + // Workaround for https://github.com/aspnet/AspNetCore/issues/14134 + if (File.Exists(socketPath)) + { + File.Delete(socketPath); + } + + options.ListenUnixSocket(socketPath); + _logger.LogInformation($"Kestrel listening to unix socket {socketPath}"); + } }) .ConfigureAppConfiguration(config => config.ConfigureAppConfiguration(commandLineOpts, appPaths, startupConfig)) .UseSerilog() From 359b0044b848cf49e8c52bb30fb1a3e8cf8f16b7 Mon Sep 17 00:00:00 2001 From: Neil Burrows Date: Mon, 13 Jul 2020 15:12:51 +0100 Subject: [PATCH 06/93] Prevent failure to bind to Auto Discover port being a fatal error --- .../EntryPoints/UdpServerEntryPoint.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index b207397bda..a9e84c2384 100644 --- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs @@ -48,8 +48,16 @@ namespace Emby.Server.Implementations.EntryPoints /// public Task RunAsync() { - _udpServer = new UdpServer(_logger, _appHost, _config); - _udpServer.Start(PortNumber, _cancellationTokenSource.Token); + try + { + _udpServer = new UdpServer(_logger, _appHost, _config); + _udpServer.Start(PortNumber, _cancellationTokenSource.Token); + } + catch (System.Net.Sockets.SocketException ex) + { + _logger.LogWarning($"Unable to start AutoDiscovery listener on UDP port {PortNumber} - {ex.Message}"); + } + return Task.CompletedTask; } From 25e382748899dd1a0e001530fbffa80b8f4451a8 Mon Sep 17 00:00:00 2001 From: Neil Burrows Date: Mon, 13 Jul 2020 15:39:14 +0100 Subject: [PATCH 07/93] Update Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs Update log format message and log exception Co-authored-by: Cody Robibero --- Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index a9e84c2384..946b9a87b8 100644 --- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs @@ -55,7 +55,7 @@ namespace Emby.Server.Implementations.EntryPoints } catch (System.Net.Sockets.SocketException ex) { - _logger.LogWarning($"Unable to start AutoDiscovery listener on UDP port {PortNumber} - {ex.Message}"); + _logger.LogWarning(ex, "Unable to start AutoDiscovery listener on UDP port {PortNumber}", PortNumber); } return Task.CompletedTask; From da8eb1f15b034b946e6533baffca8ffa17bcb3a7 Mon Sep 17 00:00:00 2001 From: Neil Burrows Date: Mon, 13 Jul 2020 16:33:39 +0100 Subject: [PATCH 08/93] using System.Net.Sockets --- Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index 946b9a87b8..9486874d58 100644 --- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs @@ -1,3 +1,4 @@ +using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.Udp; @@ -53,7 +54,7 @@ namespace Emby.Server.Implementations.EntryPoints _udpServer = new UdpServer(_logger, _appHost, _config); _udpServer.Start(PortNumber, _cancellationTokenSource.Token); } - catch (System.Net.Sockets.SocketException ex) + catch (SocketException ex) { _logger.LogWarning(ex, "Unable to start AutoDiscovery listener on UDP port {PortNumber}", PortNumber); } From 12478c7196156d8aefdd3061926a9d5cc3ce6a20 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Mon, 13 Jul 2020 17:54:06 +0100 Subject: [PATCH 09/93] Update NotificationOption.cs Fixes serialisation bug --- MediaBrowser.Model/Notifications/NotificationOption.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MediaBrowser.Model/Notifications/NotificationOption.cs b/MediaBrowser.Model/Notifications/NotificationOption.cs index ea363d9b17..dc8d27baf2 100644 --- a/MediaBrowser.Model/Notifications/NotificationOption.cs +++ b/MediaBrowser.Model/Notifications/NotificationOption.cs @@ -15,6 +15,14 @@ namespace MediaBrowser.Model.Notifications SendToUsers = Array.Empty(); } + public NotificationOption() + { + Type = string.Empty; + DisabledServices = Array.Empty(); + DisabledMonitorUsers = Array.Empty(); + SendToUsers = Array.Empty(); + } + public string Type { get; set; } /// From 3b085f6a03bfe945e12b104bb042be1d00981cd2 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 17 Jun 2020 10:24:25 -0400 Subject: [PATCH 10/93] Remove UserManager.AddParts --- .../ApplicationHost.cs | 4 ++- .../Users/UserManager.cs | 35 +++++++++---------- .../Library/IUserManager.cs | 3 -- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index f6077400d6..908fe4b302 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -547,6 +547,9 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(ServerConfigurationManager); + serviceCollection.AddSingleton>>(() => GetExports()); + serviceCollection.AddSingleton>>(() => GetExports()); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); @@ -795,7 +798,6 @@ namespace Emby.Server.Implementations Resolve().AddParts(GetExports()); Resolve().AddParts(GetExports(), GetExports()); - Resolve().AddParts(GetExports(), GetExports()); Resolve().AddParts(GetExports()); } diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 6283a1bca5..d4b91f3c53 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -39,12 +39,11 @@ namespace Jellyfin.Server.Implementations.Users private readonly IApplicationHost _appHost; private readonly IImageProcessor _imageProcessor; private readonly ILogger _logger; - - private IAuthenticationProvider[] _authenticationProviders = null!; - private DefaultAuthenticationProvider _defaultAuthenticationProvider = null!; - private InvalidAuthProvider _invalidAuthProvider = null!; - private IPasswordResetProvider[] _passwordResetProviders = null!; - private DefaultPasswordResetProvider _defaultPasswordResetProvider = null!; + private readonly IReadOnlyCollection _passwordResetProviders; + private readonly IReadOnlyCollection _authenticationProviders; + private readonly InvalidAuthProvider _invalidAuthProvider; + private readonly DefaultAuthenticationProvider _defaultAuthenticationProvider; + private readonly DefaultPasswordResetProvider _defaultPasswordResetProvider; /// /// Initializes a new instance of the class. @@ -55,13 +54,17 @@ namespace Jellyfin.Server.Implementations.Users /// The application host. /// The image processor. /// The logger. + /// A function that returns available password reset providers. + /// A function that returns available authentication providers. public UserManager( JellyfinDbProvider dbProvider, ICryptoProvider cryptoProvider, INetworkManager networkManager, IApplicationHost appHost, IImageProcessor imageProcessor, - ILogger logger) + ILogger logger, + Func> passwordResetProviders, + Func> authenticationProviders) { _dbProvider = dbProvider; _cryptoProvider = cryptoProvider; @@ -69,6 +72,13 @@ namespace Jellyfin.Server.Implementations.Users _appHost = appHost; _imageProcessor = imageProcessor; _logger = logger; + + _passwordResetProviders = passwordResetProviders.Invoke(); + _authenticationProviders = authenticationProviders.Invoke(); + + _invalidAuthProvider = _authenticationProviders.OfType().First(); + _defaultAuthenticationProvider = _authenticationProviders.OfType().First(); + _defaultPasswordResetProvider = _passwordResetProviders.OfType().First(); } /// @@ -557,17 +567,6 @@ namespace Jellyfin.Server.Implementations.Users }; } - /// - public void AddParts(IEnumerable authenticationProviders, IEnumerable passwordResetProviders) - { - _authenticationProviders = authenticationProviders.ToArray(); - _passwordResetProviders = passwordResetProviders.ToArray(); - - _invalidAuthProvider = _authenticationProviders.OfType().First(); - _defaultAuthenticationProvider = _authenticationProviders.OfType().First(); - _defaultPasswordResetProvider = _passwordResetProviders.OfType().First(); - } - /// public void Initialize() { diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index e73fe71205..88b96ddbf8 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using MediaBrowser.Controller.Authentication; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Events; @@ -166,8 +165,6 @@ namespace MediaBrowser.Controller.Library /// true if XXXX, false otherwise. Task RedeemPasswordResetPin(string pin); - void AddParts(IEnumerable authenticationProviders, IEnumerable passwordResetProviders); - NameIdPair[] GetAuthenticationProviders(); NameIdPair[] GetPasswordResetProviders(); From 303c175714db50bf865939fd12c66dcbda229431 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 20 Jun 2020 17:58:09 -0400 Subject: [PATCH 11/93] Fix circular dependency --- Emby.Server.Implementations/ApplicationHost.cs | 3 --- .../Users/DefaultPasswordResetProvider.cs | 16 +++++++++------- .../Users/UserManager.cs | 17 +++++++++-------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 908fe4b302..1ff14bdb5c 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -547,9 +547,6 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(ServerConfigurationManager); - serviceCollection.AddSingleton>>(() => GetExports()); - serviceCollection.AddSingleton>>(() => GetExports()); - serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs index cf5a01f083..007c296436 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs @@ -6,6 +6,7 @@ using System.IO; using System.Security.Cryptography; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using MediaBrowser.Common; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; @@ -23,7 +24,7 @@ namespace Jellyfin.Server.Implementations.Users private const string BaseResetFileName = "passwordreset"; private readonly IJsonSerializer _jsonSerializer; - private readonly IUserManager _userManager; + private readonly IApplicationHost _appHost; private readonly string _passwordResetFileBase; private readonly string _passwordResetFileBaseDir; @@ -33,16 +34,17 @@ namespace Jellyfin.Server.Implementations.Users /// /// The configuration manager. /// The JSON serializer. - /// The user manager. + /// The application host. public DefaultPasswordResetProvider( IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, - IUserManager userManager) + IApplicationHost appHost) { _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath; _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, BaseResetFileName); _jsonSerializer = jsonSerializer; - _userManager = userManager; + _appHost = appHost; + // TODO: Remove the circular dependency on UserManager } /// @@ -54,6 +56,7 @@ namespace Jellyfin.Server.Implementations.Users /// public async Task RedeemPasswordResetPin(string pin) { + var userManager = _appHost.Resolve(); var usersReset = new List(); foreach (var resetFile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{BaseResetFileName}*")) { @@ -72,10 +75,10 @@ namespace Jellyfin.Server.Implementations.Users pin.Replace("-", string.Empty, StringComparison.Ordinal), StringComparison.InvariantCultureIgnoreCase)) { - var resetUser = _userManager.GetUserByName(spr.UserName) + var resetUser = userManager.GetUserByName(spr.UserName) ?? throw new ResourceNotFoundException($"User with a username of {spr.UserName} not found"); - await _userManager.ChangePassword(resetUser, pin).ConfigureAwait(false); + await userManager.ChangePassword(resetUser, pin).ConfigureAwait(false); usersReset.Add(resetUser.Username); File.Delete(resetFile); } @@ -121,7 +124,6 @@ namespace Jellyfin.Server.Implementations.Users } user.EasyPassword = pin; - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); return new ForgotPasswordResult { diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index d4b91f3c53..988b0c430b 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -54,17 +54,13 @@ namespace Jellyfin.Server.Implementations.Users /// The application host. /// The image processor. /// The logger. - /// A function that returns available password reset providers. - /// A function that returns available authentication providers. public UserManager( JellyfinDbProvider dbProvider, ICryptoProvider cryptoProvider, INetworkManager networkManager, IApplicationHost appHost, IImageProcessor imageProcessor, - ILogger logger, - Func> passwordResetProviders, - Func> authenticationProviders) + ILogger logger) { _dbProvider = dbProvider; _cryptoProvider = cryptoProvider; @@ -73,8 +69,8 @@ namespace Jellyfin.Server.Implementations.Users _imageProcessor = imageProcessor; _logger = logger; - _passwordResetProviders = passwordResetProviders.Invoke(); - _authenticationProviders = authenticationProviders.Invoke(); + _passwordResetProviders = appHost.GetExports(); + _authenticationProviders = appHost.GetExports(); _invalidAuthProvider = _authenticationProviders.OfType().First(); _defaultAuthenticationProvider = _authenticationProviders.OfType().First(); @@ -537,7 +533,12 @@ namespace Jellyfin.Server.Implementations.Users if (user != null && isInNetwork) { var passwordResetProvider = GetPasswordResetProvider(user); - return await passwordResetProvider.StartForgotPasswordProcess(user, isInNetwork).ConfigureAwait(false); + var result = await passwordResetProvider + .StartForgotPasswordProcess(user, isInNetwork) + .ConfigureAwait(false); + + await UpdateUserAsync(user).ConfigureAwait(false); + return result; } return new ForgotPasswordResult From 87f5a6bdb3e3856f2dfaddcc3b0902a45ff48ca2 Mon Sep 17 00:00:00 2001 From: Max Git Date: Wed, 15 Jul 2020 05:56:05 +0200 Subject: [PATCH 12/93] Move videostream null check to start of GetHardwareAcceleratedVideoDecoder --- .../MediaEncoding/EncodingHelper.cs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index cbfdf26959..fa06de0a36 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2523,21 +2523,21 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Gets the name of the output video codec. + /// Gets the ffmpeg option string for the hardware accelerated video decoder. /// + /// The encoding job info. + /// The encoding options. + /// The option string or null if none available. protected string GetHardwareAcceleratedVideoDecoder(EncodingJobInfo state, EncodingOptions encodingOptions) { - var videoType = state.MediaSource.VideoType ?? VideoType.VideoFile; var videoStream = state.VideoStream; - var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase)); - - if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) + if (videoStream == null) { return null; } + var videoType = state.MediaSource.VideoType ?? VideoType.VideoFile; // Only use alternative encoders for video files. // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully // Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this. @@ -2546,10 +2546,16 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - if (videoStream != null - && !string.IsNullOrEmpty(videoStream.Codec) - && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) + if (IsCopyCodec(state.OutputVideoCodec)) { + return null; + } + + if (!string.IsNullOrEmpty(videoStream.Codec) && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) + { + var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) + && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase)); + // Only hevc and vp9 formats have 10-bit hardware decoder support now. if (isColorDepth10 && !(string.Equals(videoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) || string.Equals(videoStream.Codec, "h265", StringComparison.OrdinalIgnoreCase) From b356ff6c8908e5479c0d2eb6e17b2910d8ed01e4 Mon Sep 17 00:00:00 2001 From: Max Git Date: Wed, 15 Jul 2020 06:58:36 +0200 Subject: [PATCH 13/93] Simplify name of IsCopyDoc --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index fa06de0a36..534e0c372e 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1351,7 +1351,7 @@ namespace MediaBrowser.Controller.MediaEncoding transcoderChannelLimit = 6; } - var isTranscodingAudio = !EncodingHelper.IsCopyCodec(codec); + var isTranscodingAudio = !IsCopyCodec(codec); int? resultChannels = state.GetRequestedAudioChannels(codec); if (isTranscodingAudio) @@ -2264,7 +2264,7 @@ namespace MediaBrowser.Controller.MediaEncoding flags.Add("+ignidx"); } - if (state.GenPtsInput || EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) + if (state.GenPtsInput || IsCopyCodec(state.OutputVideoCodec)) { flags.Add("+genpts"); } @@ -3008,7 +3008,7 @@ namespace MediaBrowser.Controller.MediaEncoding args += " -mpegts_m2ts_mode 1"; } - if (EncodingHelper.IsCopyCodec(videoCodec)) + if (IsCopyCodec(videoCodec)) { if (state.VideoStream != null && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) @@ -3110,7 +3110,7 @@ namespace MediaBrowser.Controller.MediaEncoding var args = "-codec:a:0 " + codec; - if (EncodingHelper.IsCopyCodec(codec)) + if (IsCopyCodec(codec)) { return args; } From a23920e2ad45c01439c668fe524ae892af1b1569 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Wed, 15 Jul 2020 13:18:02 +0200 Subject: [PATCH 14/93] Only fetch Next Up for episodes that have been fully matched --- .../TV/TVSeriesManager.cs | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index 21c12ae79f..552c9d1c1a 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -117,23 +117,19 @@ namespace Emby.Server.Implementations.TV limit = limit.Value + 10; } - var items = _libraryManager.GetItemList(new InternalItemsQuery(user) - { - IncludeItemTypes = new[] { typeof(Episode).Name }, - OrderBy = new[] { new ValueTuple(ItemSortBy.DatePlayed, SortOrder.Descending) }, - SeriesPresentationUniqueKey = presentationUniqueKey, - Limit = limit, - DtoOptions = new DtoOptions + var items = _libraryManager + .GetItemList(new InternalItemsQuery(user) { - Fields = new ItemFields[] - { - ItemFields.SeriesPresentationUniqueKey - }, - EnableImages = false - }, - GroupBySeriesPresentationUniqueKey = true - - }, parentsFolders.ToList()).Cast().Select(GetUniqueSeriesKey); + IncludeItemTypes = new[] {typeof(Episode).Name}, + OrderBy = new[] {new ValueTuple(ItemSortBy.DatePlayed, SortOrder.Descending)}, + SeriesPresentationUniqueKey = presentationUniqueKey, + Limit = limit, + DtoOptions = new DtoOptions {Fields = new ItemFields[] {ItemFields.SeriesPresentationUniqueKey}, EnableImages = false}, + GroupBySeriesPresentationUniqueKey = true + }, parentsFolders.ToList()) + .Cast() + .Where(episode => !string.IsNullOrEmpty(episode.SeriesPresentationUniqueKey)) + .Select(GetUniqueSeriesKey); // Avoid implicitly captured closure var episodes = GetNextUpEpisodes(request, user, items, dtoOptions); From 8c0168ef72501bf43cff2a27866785d3efcb79e1 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Wed, 15 Jul 2020 16:45:14 +0200 Subject: [PATCH 15/93] Fetch image keytypes before querying images --- .../Plugins/TheTvdb/TvdbClientManager.cs | 45 +++++++++++++++++++ .../TheTvdb/TvdbSeasonImageProvider.cs | 2 +- .../TheTvdb/TvdbSeriesImageProvider.cs | 5 ++- .../Plugins/TheTvdb/TvdbSeriesProvider.cs | 15 +++++-- .../Plugins/TheTvdb/TvdbUtils.cs | 3 +- 5 files changed, 63 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs index 2c6682f821..b9b477ecb4 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs @@ -229,6 +229,51 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb return GetEpisodesPageAsync(tvdbId, 1, episodeQuery, language, cancellationToken); } + public async Task> GetImageKeyTypesForSeriesAsync(int tvdbId, string language, CancellationToken cancellationToken) + { + var cacheKey = GenerateKey(nameof(TvDbClient.Series.GetImagesSummaryAsync), tvdbId); + var imagesSummary = await TryGetValue(cacheKey, language, () => TvDbClient.Series.GetImagesSummaryAsync(tvdbId, cancellationToken)).ConfigureAwait(false); + var keyTypes = new List(); + + if (imagesSummary.Data.Fanart > 0) + { + keyTypes.Add(KeyType.Fanart); + } + + if (imagesSummary.Data.Series > 0) + { + keyTypes.Add(KeyType.Series); + } + + if (imagesSummary.Data.Poster > 0) + { + keyTypes.Add(KeyType.Poster); + } + + return keyTypes; + } + + public async Task> GetImageKeyTypesForSeasonAsync(int tvdbId, string language, CancellationToken cancellationToken) + { + var cacheKey = GenerateKey(nameof(TvDbClient.Series.GetImagesSummaryAsync), tvdbId); + var imagesSummary = await TryGetValue(cacheKey, language, () => TvDbClient.Series.GetImagesSummaryAsync(tvdbId, cancellationToken)).ConfigureAwait(false); + var keyTypes = new List(); + + if (imagesSummary.Data.Season > 0) + { + keyTypes.Add(KeyType.Season); + } + + if (imagesSummary.Data.Fanart > 0) + { + keyTypes.Add(KeyType.Fanart); + } + + // TODO seasonwide is not supported in TvDbSharper + + return keyTypes; + } + private async Task TryGetValue(string key, string language, Func> resultFactory) { if (_cache.TryGetValue(key, out T cachedValue)) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs index 5af99a573e..2cf822ac04 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs @@ -65,7 +65,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb var language = item.GetPreferredMetadataLanguage(); var remoteImages = new List(); - var keyTypes = new[] { KeyType.Season, KeyType.Seasonwide, KeyType.Fanart }; + var keyTypes = await _tvdbClientManager.GetImageKeyTypesForSeasonAsync(tvdbId, language, cancellationToken).ConfigureAwait(false); foreach (var keyType in keyTypes) { var imageQuery = new ImagesQuery diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs index 7dd0128250..174c923870 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs @@ -59,9 +59,10 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb var language = item.GetPreferredMetadataLanguage(); var remoteImages = new List(); - var keyTypes = new[] { KeyType.Poster, KeyType.Series, KeyType.Fanart }; var tvdbId = Convert.ToInt32(item.GetProviderId(MetadataProvider.Tvdb)); - foreach (KeyType keyType in keyTypes) + var allowedKeyTypes = await _tvdbClientManager.GetImageKeyTypesForSeriesAsync(tvdbId, language, cancellationToken) + .ConfigureAwait(false); + foreach (KeyType keyType in allowedKeyTypes) { var imageQuery = new ImagesQuery { diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs index b3641dc9f4..196e801c03 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs @@ -247,10 +247,15 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb { Name = tvdbTitles.FirstOrDefault(), ProductionYear = firstAired.Year, - SearchProviderName = Name, - ImageUrl = TvdbUtils.BannerUrl + seriesSearchResult.Banner + SearchProviderName = Name }; + if (!string.IsNullOrEmpty(seriesSearchResult.Banner)) + { + // Results from their Search endpoints already include the /banners/ part in the url, because reasons... + remoteSearchResult.ImageUrl = TvdbUtils.TvdbImageBaseUrl + seriesSearchResult.Banner; + } + try { var seriesSesult = @@ -365,10 +370,14 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb Type = PersonType.Actor, Name = (actor.Name ?? string.Empty).Trim(), Role = actor.Role, - ImageUrl = TvdbUtils.BannerUrl + actor.Image, SortOrder = actor.SortOrder }; + if (!string.IsNullOrEmpty(actor.Image)) + { + personInfo.ImageUrl = TvdbUtils.TvdbImageBaseUrl + actor.Image; + } + if (!string.IsNullOrWhiteSpace(personInfo.Name)) { result.AddPerson(personInfo); diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbUtils.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbUtils.cs index 3f71041b2b..37a8d04a6f 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbUtils.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbUtils.cs @@ -9,7 +9,8 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb { public const string TvdbApiKey = "OG4V3YJ3FAP7FP2K"; public const string TvdbBaseUrl = "https://www.thetvdb.com/"; - public const string BannerUrl = TvdbBaseUrl + "banners/"; + public const string TvdbImageBaseUrl = "https://www.thetvdb.com"; + public const string BannerUrl = TvdbImageBaseUrl + "/banners/"; public static ImageType GetImageTypeFromKeyType(string keyType) { From 6d37a5fe528ed07ab3529e9dfc07c03d1c572558 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Wed, 15 Jul 2020 17:14:39 +0200 Subject: [PATCH 16/93] Change to IAsyncEnumerable --- .../Plugins/TheTvdb/TvdbClientManager.cs | 20 +++++++------------ .../TheTvdb/TvdbSeasonImageProvider.cs | 4 ++-- .../TheTvdb/TvdbSeriesImageProvider.cs | 4 ++-- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs index b9b477ecb4..8c1b22a885 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs @@ -229,49 +229,43 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb return GetEpisodesPageAsync(tvdbId, 1, episodeQuery, language, cancellationToken); } - public async Task> GetImageKeyTypesForSeriesAsync(int tvdbId, string language, CancellationToken cancellationToken) + public async IAsyncEnumerable GetImageKeyTypesForSeriesAsync(int tvdbId, string language, CancellationToken cancellationToken) { var cacheKey = GenerateKey(nameof(TvDbClient.Series.GetImagesSummaryAsync), tvdbId); var imagesSummary = await TryGetValue(cacheKey, language, () => TvDbClient.Series.GetImagesSummaryAsync(tvdbId, cancellationToken)).ConfigureAwait(false); - var keyTypes = new List(); if (imagesSummary.Data.Fanart > 0) { - keyTypes.Add(KeyType.Fanart); + yield return KeyType.Fanart; } if (imagesSummary.Data.Series > 0) { - keyTypes.Add(KeyType.Series); + yield return KeyType.Series; } if (imagesSummary.Data.Poster > 0) { - keyTypes.Add(KeyType.Poster); + yield return KeyType.Poster; } - - return keyTypes; } - public async Task> GetImageKeyTypesForSeasonAsync(int tvdbId, string language, CancellationToken cancellationToken) + public async IAsyncEnumerable GetImageKeyTypesForSeasonAsync(int tvdbId, string language, CancellationToken cancellationToken) { var cacheKey = GenerateKey(nameof(TvDbClient.Series.GetImagesSummaryAsync), tvdbId); var imagesSummary = await TryGetValue(cacheKey, language, () => TvDbClient.Series.GetImagesSummaryAsync(tvdbId, cancellationToken)).ConfigureAwait(false); - var keyTypes = new List(); if (imagesSummary.Data.Season > 0) { - keyTypes.Add(KeyType.Season); + yield return KeyType.Season; } if (imagesSummary.Data.Fanart > 0) { - keyTypes.Add(KeyType.Fanart); + yield return KeyType.Fanart; } // TODO seasonwide is not supported in TvDbSharper - - return keyTypes; } private async Task TryGetValue(string key, string language, Func> resultFactory) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs index 2cf822ac04..e9ba204754 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs @@ -65,8 +65,8 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb var language = item.GetPreferredMetadataLanguage(); var remoteImages = new List(); - var keyTypes = await _tvdbClientManager.GetImageKeyTypesForSeasonAsync(tvdbId, language, cancellationToken).ConfigureAwait(false); - foreach (var keyType in keyTypes) + var keyTypes = _tvdbClientManager.GetImageKeyTypesForSeasonAsync(tvdbId, language, cancellationToken).ConfigureAwait(false); + await foreach (var keyType in keyTypes) { var imageQuery = new ImagesQuery { diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs index 174c923870..c33aefbc19 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs @@ -60,9 +60,9 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb var language = item.GetPreferredMetadataLanguage(); var remoteImages = new List(); var tvdbId = Convert.ToInt32(item.GetProviderId(MetadataProvider.Tvdb)); - var allowedKeyTypes = await _tvdbClientManager.GetImageKeyTypesForSeriesAsync(tvdbId, language, cancellationToken) + var allowedKeyTypes = _tvdbClientManager.GetImageKeyTypesForSeriesAsync(tvdbId, language, cancellationToken) .ConfigureAwait(false); - foreach (KeyType keyType in allowedKeyTypes) + await foreach (KeyType keyType in allowedKeyTypes) { var imageQuery = new ImagesQuery { From 90fa1149fa8d7b770c91fd881bf150fd3fec521e Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Wed, 15 Jul 2020 19:04:36 +0200 Subject: [PATCH 17/93] Fix warnings --- .../TV/TVSeriesManager.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index 552c9d1c1a..d1818deff4 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -118,15 +118,16 @@ namespace Emby.Server.Implementations.TV } var items = _libraryManager - .GetItemList(new InternalItemsQuery(user) - { - IncludeItemTypes = new[] {typeof(Episode).Name}, - OrderBy = new[] {new ValueTuple(ItemSortBy.DatePlayed, SortOrder.Descending)}, - SeriesPresentationUniqueKey = presentationUniqueKey, - Limit = limit, - DtoOptions = new DtoOptions {Fields = new ItemFields[] {ItemFields.SeriesPresentationUniqueKey}, EnableImages = false}, - GroupBySeriesPresentationUniqueKey = true - }, parentsFolders.ToList()) + .GetItemList( + new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Episode).Name }, + OrderBy = new[] { new ValueTuple(ItemSortBy.DatePlayed, SortOrder.Descending) }, + SeriesPresentationUniqueKey = presentationUniqueKey, + Limit = limit, + DtoOptions = new DtoOptions { Fields = new[] { ItemFields.SeriesPresentationUniqueKey }, EnableImages = false }, + GroupBySeriesPresentationUniqueKey = true + }, parentsFolders.ToList()) .Cast() .Where(episode => !string.IsNullOrEmpty(episode.SeriesPresentationUniqueKey)) .Select(GetUniqueSeriesKey); From fa4e0a73d5eb0b33dc85dffb2a2d35033c5ce698 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 16 Jul 2020 11:21:46 +0200 Subject: [PATCH 18/93] Update Jellyfin.Server/Program.cs Co-authored-by: Cody Robibero --- Jellyfin.Server/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 025de916f5..3a414d7678 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -356,7 +356,7 @@ namespace Jellyfin.Server } options.ListenUnixSocket(socketPath); - _logger.LogInformation($"Kestrel listening to unix socket {socketPath}"); + _logger.LogInformation("Kestrel listening to unix socket {socketPath}", socketPath); } }) .ConfigureAppConfiguration(config => config.ConfigureAppConfiguration(commandLineOpts, appPaths, startupConfig)) From 32fb34a4cc675ba1751f6a66b72f7e7bda99d836 Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Thu, 16 Jul 2020 21:09:04 +0800 Subject: [PATCH 19/93] Fix QSV subtitle burn-in on windows and P010 detect --- .../MediaEncoding/EncodingHelper.cs | 171 ++++++++++++------ 1 file changed, 112 insertions(+), 59 deletions(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 534e0c372e..62811c3233 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -475,22 +475,34 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { - var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; - if (!hasTextSubs) + if (isQsvEncoder) { - if (isQsvEncoder) + if (isQsvDecoder) { - if (isQsvDecoder) + if (!isWindows) { - arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + if (hasGraphicalSubs) + { + arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); + } + else + { + arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + } } - // While using SW decoder else { - arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); + arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); } } + // While using SW decoder + else + { + arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); + } } } @@ -806,6 +818,34 @@ namespace MediaBrowser.Controller.MediaEncoding break; } } + else if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase)) + { + switch (encodingOptions.EncoderPreset) + { + case "veryslow": + case "slow": + case "slower": + param += "-quality quality"; + break; + + case "medium": + param += "-quality balanced"; + break; + + case "fast": + case "faster": + case "veryfast": + case "superfast": + case "ultrafast": + param += "-quality speed"; + break; + + default: + param += "-quality speed"; + break; + } + } else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) // webm { // Values 0-3, 0 being highest quality but slower @@ -1555,28 +1595,28 @@ namespace MediaBrowser.Controller.MediaEncoding var index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = "," + outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Substring(index); } else { index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = "," + outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Substring(index); } else { index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = "," + outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Substring(index); } else { index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = "," + outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Substring(index); } } } @@ -1591,17 +1631,18 @@ namespace MediaBrowser.Controller.MediaEncoding { videoSizeParam = string.Format( CultureInfo.InvariantCulture, - "scale={0}:{1}", + "scale={0}x{1}", state.VideoStream.Width.Value, state.VideoStream.Height.Value); // For QSV, feed it into hardware encoder now - if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + if (!isWindows && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { videoSizeParam += ",hwupload=extra_hw_frames=64"; } - // For VAAPI and CUVID decoder + // For VAAPI and NVDEC decoder // these encoders cannot automatically adjust the size of graphical subtitles to fit the output video, // thus needs to be manually adjusted. if (videoDecoder.IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 @@ -1618,7 +1659,7 @@ namespace MediaBrowser.Controller.MediaEncoding { videoSizeParam = string.Format( CultureInfo.InvariantCulture, - "scale={0}:{1}", + "scale={0}x{1}", width.Value, height.Value); } @@ -1634,7 +1675,10 @@ namespace MediaBrowser.Controller.MediaEncoding : state.SubtitleStream.Index; // Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference) - var retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\""; + // Always put the scaler before the overlay for better performance + var retStr = !string.IsNullOrEmpty(outputSizeParam) ? + " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"" : + " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\""; // When the input may or may not be hardware VAAPI decodable if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) @@ -1644,7 +1688,6 @@ namespace MediaBrowser.Controller.MediaEncoding [sub]: SW scaling subtitle to FixedOutputSize [base][sub]: SW overlay */ - outputSizeParam = outputSizeParam.TrimStart(','); retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\""; } @@ -1657,7 +1700,6 @@ namespace MediaBrowser.Controller.MediaEncoding [sub]: SW scaling subtitle to FixedOutputSize [base][sub]: SW overlay */ - outputSizeParam = outputSizeParam.TrimStart(','); retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\""; } else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) @@ -1666,14 +1708,14 @@ namespace MediaBrowser.Controller.MediaEncoding QSV in FFMpeg can now setup hardware overlay for transcodes. For software decoding and hardware encoding option, frames must be hwuploaded into hardware with fixed frame size. + Currently only supports linux. */ - if (videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1) - { - retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv=x=(W-w)/2:y=(H-h)/2{3}\""; - } - else + var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + if (!isWindows) { - retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]hwupload=extra_hw_frames=64[v];[v][sub]overlay_qsv=x=(W-w)/2:y=(H-h)/2{3}\""; + retStr = !string.IsNullOrEmpty(outputSizeParam) ? + " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" : + " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\""; } } @@ -1745,10 +1787,8 @@ namespace MediaBrowser.Controller.MediaEncoding requestedMaxWidth, requestedMaxHeight); - var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; - if ((string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) - || (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) && !hasTextSubs)) + || string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)) && width.HasValue && height.HasValue) { @@ -1769,15 +1809,20 @@ namespace MediaBrowser.Controller.MediaEncoding filters.Add( string.Format( CultureInfo.InvariantCulture, - "{0}=w={1}:h={2}:format=nv12", + "{0}=w={1}:h={2}:format=nv12{3}", qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi", outputWidth, - outputHeight)); + outputHeight, + (qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty)); } else { - // set w=0:h=0 for vpp_qsv to keep the original dimensions, otherwise it will fail. - filters.Add(string.Format(CultureInfo.InvariantCulture, "{0}format=nv12", qsv_or_vaapi ? "vpp_qsv=w=0:h=0:" : "scale_vaapi=")); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "{0}=format=nv12{1}", + qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi", + (qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty)); } } else if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 @@ -1998,8 +2043,6 @@ namespace MediaBrowser.Controller.MediaEncoding var inputHeight = videoStream?.Height; var threeDFormat = state.MediaSource.Video3DFormat; - var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; - // When the input may or may not be hardware VAAPI decodable if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) { @@ -2010,11 +2053,8 @@ namespace MediaBrowser.Controller.MediaEncoding // When the input may or may not be hardware QSV decodable else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { - if (!hasTextSubs) - { - filters.Add("format=nv12|qsv"); - filters.Add("hwupload=extra_hw_frames=64"); - } + filters.Add("format=nv12|qsv"); + filters.Add("hwupload=extra_hw_frames=64"); } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first @@ -2022,8 +2062,10 @@ namespace MediaBrowser.Controller.MediaEncoding && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { var codec = videoStream.Codec.ToLowerInvariant(); - var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase)); + var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) + && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase)); // Assert 10-bit hardware VAAPI decodable if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) @@ -2054,31 +2096,32 @@ namespace MediaBrowser.Controller.MediaEncoding { filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi")); } - else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) - { - if (!hasTextSubs) - { - filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_qsv")); - } - } } // Add software deinterlace filter before scaling filter - if (((state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) - && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) - && !string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) - || (hasTextSubs && state.DeInterlace("h264", true) && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))) + if (state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) { + var deintParam = string.Empty; var inputFramerate = videoStream?.RealFrameRate; // If it is already 60fps then it will create an output framerate that is much too high for roku and others to handle if (string.Equals(options.DeinterlaceMethod, "yadif_bob", StringComparison.OrdinalIgnoreCase) && (inputFramerate ?? 60) <= 30) { - filters.Add("yadif=1:-1:0"); + deintParam = "yadif=1:-1:0"; } else { - filters.Add("yadif=0:-1:0"); + deintParam = "yadif=0:-1:0"; + } + + if (!string.IsNullOrEmpty(deintParam)) + { + if (!string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) + && !string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) + && videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) == -1) + { + filters.Add(deintParam); + } } } @@ -2303,11 +2346,19 @@ namespace MediaBrowser.Controller.MediaEncoding && width.HasValue && height.HasValue) { - inputModifier += string.Format( - CultureInfo.InvariantCulture, - " -resize {0}x{1}", - width.Value, - height.Value); + if (width.HasValue && height.HasValue) + { + inputModifier += string.Format( + CultureInfo.InvariantCulture, + " -resize {0}x{1}", + width.Value, + height.Value); + } + + if (state.DeInterlace("h264", true)) + { + inputModifier += " -deint 1"; + } } } } @@ -2554,7 +2605,9 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(videoStream.Codec) && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) { var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) - && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase)); + && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase)); // Only hevc and vp9 formats have 10-bit hardware decoder support now. if (isColorDepth10 && !(string.Equals(videoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) From 0095cb194774bb373738a36a14296de38e18d9e3 Mon Sep 17 00:00:00 2001 From: crobibero Date: Thu, 16 Jul 2020 07:32:58 -0600 Subject: [PATCH 20/93] Add EnumeratorCancellation attribute --- MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs index 8c1b22a885..cd2f96f14a 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Providers; @@ -229,7 +230,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb return GetEpisodesPageAsync(tvdbId, 1, episodeQuery, language, cancellationToken); } - public async IAsyncEnumerable GetImageKeyTypesForSeriesAsync(int tvdbId, string language, CancellationToken cancellationToken) + public async IAsyncEnumerable GetImageKeyTypesForSeriesAsync(int tvdbId, string language, [EnumeratorCancellation] CancellationToken cancellationToken) { var cacheKey = GenerateKey(nameof(TvDbClient.Series.GetImagesSummaryAsync), tvdbId); var imagesSummary = await TryGetValue(cacheKey, language, () => TvDbClient.Series.GetImagesSummaryAsync(tvdbId, cancellationToken)).ConfigureAwait(false); @@ -250,7 +251,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb } } - public async IAsyncEnumerable GetImageKeyTypesForSeasonAsync(int tvdbId, string language, CancellationToken cancellationToken) + public async IAsyncEnumerable GetImageKeyTypesForSeasonAsync(int tvdbId, string language, [EnumeratorCancellation] CancellationToken cancellationToken) { var cacheKey = GenerateKey(nameof(TvDbClient.Series.GetImagesSummaryAsync), tvdbId); var imagesSummary = await TryGetValue(cacheKey, language, () => TvDbClient.Series.GetImagesSummaryAsync(tvdbId, cancellationToken)).ConfigureAwait(false); From f40bcff1134bf45495aaa877df348a9daff891ee Mon Sep 17 00:00:00 2001 From: crobibero Date: Thu, 16 Jul 2020 08:28:31 -0600 Subject: [PATCH 21/93] Catch HttpRequestException when requesting plugins --- Emby.Server.Implementations/Updates/InstallationManager.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 146ebaf25b..4f54c06dd2 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -148,6 +148,11 @@ namespace Emby.Server.Implementations.Updates _logger.LogError(ex, "An error occurred while accessing the plugin manifest: {Manifest}", manifest); return Array.Empty(); } + catch (HttpRequestException ex) + { + _logger.LogError(ex, "An error occurred while accessing the plugin manifest: {Manifest}", manifest); + return Array.Empty(); + } } /// From 0c64ad9b1634d37c09d1160411eb75f98f7a47ce Mon Sep 17 00:00:00 2001 From: ADRI IDZWAN MANSOR Date: Thu, 16 Jul 2020 11:36:39 +0000 Subject: [PATCH 22/93] Translated using Weblate (Malay) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ms/ --- .../Localization/Core/ms.json | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json index 79d078d4a8..7f8df12895 100644 --- a/Emby.Server.Implementations/Localization/Core/ms.json +++ b/Emby.Server.Implementations/Localization/Core/ms.json @@ -5,47 +5,47 @@ "Artists": "Artis", "AuthenticationSucceededWithUserName": "{0} berjaya disahkan", "Books": "Buku-buku", - "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}", + "CameraImageUploadedFrom": "Ada gambar dari kamera yang baru dimuat naik melalui {0}", "Channels": "Saluran", - "ChapterNameValue": "Chapter {0}", + "ChapterNameValue": "Bab {0}", "Collections": "Koleksi", - "DeviceOfflineWithName": "{0} has disconnected", - "DeviceOnlineWithName": "{0} is connected", + "DeviceOfflineWithName": "{0} telah diputuskan sambungan", + "DeviceOnlineWithName": "{0} telah disambung", "FailedLoginAttemptWithUserName": "Cubaan log masuk gagal dari {0}", - "Favorites": "Favorites", - "Folders": "Folders", + "Favorites": "Kegemaran", + "Folders": "Fail-fail", "Genres": "Genre-genre", - "HeaderAlbumArtists": "Album Artists", + "HeaderAlbumArtists": "Album Artis-artis", "HeaderCameraUploads": "Muatnaik Kamera", "HeaderContinueWatching": "Terus Menonton", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderLiveTV": "Live TV", - "HeaderNextUp": "Next Up", - "HeaderRecordingGroups": "Recording Groups", - "HomeVideos": "Home videos", - "Inherit": "Inherit", - "ItemAddedWithName": "{0} was added to the library", - "ItemRemovedWithName": "{0} was removed from the library", + "HeaderFavoriteAlbums": "Album-album Kegemaran", + "HeaderFavoriteArtists": "Artis-artis Kegemaran", + "HeaderFavoriteEpisodes": "Episod-episod Kegemaran", + "HeaderFavoriteShows": "Rancangan-rancangan Kegemaran", + "HeaderFavoriteSongs": "Lagu-lagu Kegemaran", + "HeaderLiveTV": "TV Siaran Langsung", + "HeaderNextUp": "Seterusnya", + "HeaderRecordingGroups": "Kumpulan-kumpulan Rakaman", + "HomeVideos": "Video Personal", + "Inherit": "Mewarisi", + "ItemAddedWithName": "{0} telah ditambahkan ke dalam pustaka", + "ItemRemovedWithName": "{0} telah dibuang daripada pustaka", "LabelIpAddressValue": "Alamat IP: {0}", - "LabelRunningTimeValue": "Running time: {0}", - "Latest": "Latest", - "MessageApplicationUpdated": "Jellyfin Server has been updated", - "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}", - "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated", - "MessageServerConfigurationUpdated": "Server configuration has been updated", - "MixedContent": "Mixed content", - "Movies": "Movies", + "LabelRunningTimeValue": "Masa berjalan: {0}", + "Latest": "Terbaru", + "MessageApplicationUpdated": "Jellyfin Server telah dikemas kini", + "MessageApplicationUpdatedTo": "Jellyfin Server telah dikemas kini ke {0}", + "MessageNamedServerConfigurationUpdatedWithValue": "Konfigurasi pelayan di bahagian {0} telah dikemas kini", + "MessageServerConfigurationUpdated": "Konfigurasi pelayan telah dikemas kini", + "MixedContent": "Kandungan campuran", + "Movies": "Filem", "Music": "Muzik", "MusicVideos": "Video muzik", - "NameInstallFailed": "{0} installation failed", - "NameSeasonNumber": "Season {0}", - "NameSeasonUnknown": "Season Unknown", - "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.", - "NotificationOptionApplicationUpdateAvailable": "Application update available", + "NameInstallFailed": "{0} pemasangan gagal", + "NameSeasonNumber": "Musim {0}", + "NameSeasonUnknown": "Musim Tidak Diketahui", + "NewVersionIsAvailable": "Versi terbaru Jellyfin Server bersedia untuk dimuat turunkan.", + "NotificationOptionApplicationUpdateAvailable": "Kemas kini aplikasi telah sedia", "NotificationOptionApplicationUpdateInstalled": "Application update installed", "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", From c1c1a2f7515edf157022a3ba421b5d66889aa525 Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Fri, 17 Jul 2020 01:30:35 +0800 Subject: [PATCH 23/93] Match the size of subtitle stream and video stream --- .../MediaEncoding/EncodingHelper.cs | 41 ++++++------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 62811c3233..ffe2bcf28a 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1625,45 +1625,31 @@ namespace MediaBrowser.Controller.MediaEncoding var videoSizeParam = string.Empty; var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty; + var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; // Setup subtitle scaling if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue) { - videoSizeParam = string.Format( + // Adjust the size of graphical subtitles to fit the video stream. + var videoStream = state.VideoStream; + var inputWidth = videoStream?.Width; + var inputHeight = videoStream?.Height; + var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight); + + if (width.HasValue && height.HasValue) + { + videoSizeParam = string.Format( CultureInfo.InvariantCulture, "scale={0}x{1}", - state.VideoStream.Width.Value, - state.VideoStream.Height.Value); + width.Value, + height.Value); + } // For QSV, feed it into hardware encoder now - var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; if (!isWindows && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { videoSizeParam += ",hwupload=extra_hw_frames=64"; } - - // For VAAPI and NVDEC decoder - // these encoders cannot automatically adjust the size of graphical subtitles to fit the output video, - // thus needs to be manually adjusted. - if (videoDecoder.IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 - || (IsVaapiSupported(state) && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) - && (videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 - || outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1))) - { - var videoStream = state.VideoStream; - var inputWidth = videoStream?.Width; - var inputHeight = videoStream?.Height; - var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight); - - if (width.HasValue && height.HasValue) - { - videoSizeParam = string.Format( - CultureInfo.InvariantCulture, - "scale={0}x{1}", - width.Value, - height.Value); - } - } } var mapPrefix = state.SubtitleStream.IsExternal ? @@ -1710,7 +1696,6 @@ namespace MediaBrowser.Controller.MediaEncoding with fixed frame size. Currently only supports linux. */ - var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; if (!isWindows) { retStr = !string.IsNullOrEmpty(outputSizeParam) ? From e1ba1fcebea0df71239bbc379ab436327488b9a8 Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Fri, 17 Jul 2020 01:41:24 +0800 Subject: [PATCH 24/93] fix indent --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ffe2bcf28a..6b3bbc34af 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1639,10 +1639,10 @@ namespace MediaBrowser.Controller.MediaEncoding if (width.HasValue && height.HasValue) { videoSizeParam = string.Format( - CultureInfo.InvariantCulture, - "scale={0}x{1}", - width.Value, - height.Value); + CultureInfo.InvariantCulture, + "scale={0}x{1}", + width.Value, + height.Value); } // For QSV, feed it into hardware encoder now From d3fa6b428a9a2220856d9a91266c1b6c7833093e Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Fri, 17 Jul 2020 14:37:29 +0800 Subject: [PATCH 25/93] bump the minimum required jellyfin-ffmpeg ver to 4.3.1-1 --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 896d8286b7..4dc766b913 100644 --- a/debian/control +++ b/debian/control @@ -21,7 +21,7 @@ Conflicts: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server Architecture: any Depends: at, libsqlite3-0, - jellyfin-ffmpeg (>= 4.2.1-2), + jellyfin-ffmpeg (>= 4.3.1-1), libfontconfig1, libfreetype6, libssl1.1 From cd714a724deab1e055d03b5923e7cf819c8ae805 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Fri, 17 Jul 2020 14:40:27 +0800 Subject: [PATCH 26/93] utilize jellyfin-ffmpeg for portable x64 --- deployment/build.windows.amd64 | 10 ++++------ windows/build-jellyfin.ps1 | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/deployment/build.windows.amd64 b/deployment/build.windows.amd64 index aae061e9d6..bd5dc64381 100755 --- a/deployment/build.windows.amd64 +++ b/deployment/build.windows.amd64 @@ -8,8 +8,7 @@ set -o xtrace # Version variables NSSM_VERSION="nssm-2.24-101-g897c7ad" NSSM_URL="http://files.evilt.win/nssm/${NSSM_VERSION}.zip" -FFMPEG_VERSION="ffmpeg-4.3-win64-static" -FFMPEG_URL="https://ffmpeg.zeranoe.com/builds/win64/static/${FFMPEG_VERSION}.zip" +FFMPEG_URL="https://repo.jellyfin.org/releases/server/windows/ffmpeg/jellyfin-ffmpeg.zip"; # Move to source directory pushd ${SOURCE_DIR} @@ -29,12 +28,11 @@ dotnet publish Jellyfin.Server --configuration Release --self-contained --runtim # Prepare addins addin_build_dir="$( mktemp -d )" wget ${NSSM_URL} -O ${addin_build_dir}/nssm.zip -wget ${FFMPEG_URL} -O ${addin_build_dir}/ffmpeg.zip +wget ${FFMPEG_URL} -O ${addin_build_dir}/jellyfin-ffmpeg.zip unzip ${addin_build_dir}/nssm.zip -d ${addin_build_dir} cp ${addin_build_dir}/${NSSM_VERSION}/win64/nssm.exe ${output_dir}/nssm.exe -unzip ${addin_build_dir}/ffmpeg.zip -d ${addin_build_dir} -cp ${addin_build_dir}/${FFMPEG_VERSION}/bin/ffmpeg.exe ${output_dir}/ffmpeg.exe -cp ${addin_build_dir}/${FFMPEG_VERSION}/bin/ffprobe.exe ${output_dir}/ffprobe.exe +unzip ${addin_build_dir}/jellyfin-ffmpeg.zip -d ${addin_build_dir}/jellyfin-ffmpeg +cp ${addin_build_dir}/jellyfin-ffmpeg/* ${output_dir} rm -rf ${addin_build_dir} # Prepare scripts diff --git a/windows/build-jellyfin.ps1 b/windows/build-jellyfin.ps1 index c762137a75..b76a8e0bbe 100644 --- a/windows/build-jellyfin.ps1 +++ b/windows/build-jellyfin.ps1 @@ -47,7 +47,7 @@ function Install-FFMPEG { param( [string]$ResolvedInstallLocation, [string]$Architecture, - [string]$FFMPEGVersionX86 = "ffmpeg-4.2.1-win32-shared" + [string]$FFMPEGVersionX86 = "ffmpeg-4.3-win32-shared" ) Write-Verbose "Checking Architecture" if($Architecture -notin @('x86','x64')){ From 7e53bc5ec5eb511e4326d576e97997974ce47328 Mon Sep 17 00:00:00 2001 From: Akachai Bunsorn Date: Fri, 17 Jul 2020 09:26:26 +0000 Subject: [PATCH 27/93] Translated using Weblate (Thai) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/th/ --- Emby.Server.Implementations/Localization/Core/th.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/th.json b/Emby.Server.Implementations/Localization/Core/th.json index 32538ac035..576aaeb1bb 100644 --- a/Emby.Server.Implementations/Localization/Core/th.json +++ b/Emby.Server.Implementations/Localization/Core/th.json @@ -67,5 +67,7 @@ "Artists": "นักแสดง", "Application": "แอปพลิเคชั่น", "AppDeviceValues": "App: {0}, อุปกรณ์: {1}", - "Albums": "อัลบั้ม" + "Albums": "อัลบั้ม", + "ScheduledTaskStartedWithName": "{0} เริ่มต้น", + "ScheduledTaskFailedWithName": "{0} ล้มเหลว" } From 77f9417d84b30a56226497329c59e0e1e50e61a4 Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Fri, 17 Jul 2020 19:32:15 +0800 Subject: [PATCH 28/93] enhance platform check and 10bit detect --- .../MediaEncoding/EncodingHelper.cs | 155 +++++++++++------- 1 file changed, 95 insertions(+), 60 deletions(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 6b3bbc34af..ffbda42c31 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using Jellyfin.Data.Enums; @@ -449,60 +450,66 @@ namespace MediaBrowser.Controller.MediaEncoding var arg = new StringBuilder(); var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty; var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty; - bool isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; - bool isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; - bool isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; - bool isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; + var isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; + var isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); - if (state.IsVideoRequest - && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) + if (!IsCopyCodec(outputVideoCodec)) { - if (isVaapiDecoder) + if (state.IsVideoRequest + && IsVaapiSupported(state) + && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { - arg.Append("-hwaccel_output_format vaapi ") - .Append("-vaapi_device ") - .Append(encodingOptions.VaapiDevice) - .Append(" "); - } - else if (!isVaapiDecoder && isVaapiEncoder) - { - arg.Append("-vaapi_device ") - .Append(encodingOptions.VaapiDevice) - .Append(" "); + if (isVaapiDecoder) + { + arg.Append("-hwaccel_output_format vaapi ") + .Append("-vaapi_device ") + .Append(encodingOptions.VaapiDevice) + .Append(" "); + } + else if (!isVaapiDecoder && isVaapiEncoder) + { + arg.Append("-vaapi_device ") + .Append(encodingOptions.VaapiDevice) + .Append(" "); + } } - } - if (state.IsVideoRequest - && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) - { - var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; - var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; - - if (isQsvEncoder) + if (state.IsVideoRequest + && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { - if (isQsvDecoder) + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + + if (isQsvEncoder) { - if (!isWindows) + if (isQsvDecoder) { - if (hasGraphicalSubs) + if (isLinux) { - arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); + if (hasGraphicalSubs) + { + arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); + } + else + { + arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + } } - else + + if (isWindows) { arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); } } + // While using SW decoder else { - arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); } } - // While using SW decoder - else - { - arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); - } } } @@ -1625,7 +1632,7 @@ namespace MediaBrowser.Controller.MediaEncoding var videoSizeParam = string.Empty; var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty; - var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); // Setup subtitle scaling if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue) @@ -1646,7 +1653,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // For QSV, feed it into hardware encoder now - if (!isWindows && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + if (isLinux && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { videoSizeParam += ",hwupload=extra_hw_frames=64"; } @@ -1696,7 +1703,7 @@ namespace MediaBrowser.Controller.MediaEncoding with fixed frame size. Currently only supports linux. */ - if (!isWindows) + if (isLinux) { retStr = !string.IsNullOrEmpty(outputSizeParam) ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" : @@ -2043,14 +2050,11 @@ namespace MediaBrowser.Controller.MediaEncoding } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first - else if (videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 + else if (IsVaapiSupported(state) && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { var codec = videoStream.Codec.ToLowerInvariant(); - var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) - && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase)); + var isColorDepth10 = IsColorDepth10(state); // Assert 10-bit hardware VAAPI decodable if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) @@ -2318,7 +2322,8 @@ namespace MediaBrowser.Controller.MediaEncoding { inputModifier += " " + videoDecoder; - if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1) + if (!IsCopyCodec(state.OutputVideoCodec) + && (videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1) { var videoStream = state.VideoStream; var inputWidth = videoStream?.Width; @@ -2589,10 +2594,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(videoStream.Codec) && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) { - var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) - && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase)); + var isColorDepth10 = IsColorDepth10(state); // Only hevc and vp9 formats have 10-bit hardware decoder support now. if (isColorDepth10 && !(string.Equals(videoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) @@ -2669,13 +2671,6 @@ namespace MediaBrowser.Controller.MediaEncoding case "h264": if (_mediaEncoder.SupportsDecoder("h264_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase)) { - // cuvid decoder does not support 10-bit input. - if ((videoStream.BitDepth ?? 8) > 8) - { - encodingOptions.HardwareDecodingCodecs = Array.Empty(); - return null; - } - return "-c:v h264_cuvid"; } @@ -2942,21 +2937,24 @@ namespace MediaBrowser.Controller.MediaEncoding /// public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec) { - var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); var isWindows8orLater = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1); var isDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va"); if ((isDxvaSupported || IsVaapiSupported(state)) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase)) { - if (!isWindows) + if (isLinux) { return "-hwaccel vaapi"; } - else if (isWindows8orLater) + + if (isWindows && isWindows8orLater) { return "-hwaccel d3d11va"; } - else + + if (isWindows && !isWindows8orLater) { return "-hwaccel dxva2"; } @@ -3225,5 +3223,42 @@ namespace MediaBrowser.Controller.MediaEncoding { return string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase); } + + public static bool IsColorDepth10(EncodingJobInfo state) + { + var result = false; + var videoStream = state.VideoStream; + + if (videoStream != null) + { + if (!string.IsNullOrEmpty(videoStream.PixelFormat)) + { + result = videoStream.PixelFormat.Contains("p10", StringComparison.OrdinalIgnoreCase); + if (result) + { + return true; + } + } + + if (!string.IsNullOrEmpty(videoStream.Profile)) + { + result = videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase); + if (result) + { + return true; + } + } + + result = (videoStream.BitDepth ?? 8) == 10; + if (result) + { + return true; + } + } + + return result; + } } } From 31ffd00dbd547c42db93df07ab9b1c87034bab13 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 12:51:55 +0100 Subject: [PATCH 29/93] Update ApplicationHost.cs --- .../ApplicationHost.cs | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 4d99bd759d..8d213ac57d 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -351,42 +351,6 @@ namespace Emby.Server.Implementations public object CreateInstance(Type type) => ActivatorUtilities.CreateInstance(ServiceProvider, type); - /// - /// Creates an instance of type and resolves all constructor dependencies. - /// - /// The type. - /// Additional argument for the constructor. - /// - public object CreateInstance(Type type, object parameter) - { - ConstructorInfo constructor = type.GetConstructors()[0]; - if (constructor != null) - { - ParameterInfo[] argInfo = constructor - .GetParameters(); - - object[] args = argInfo - .Select(o => o.ParameterType) - .Select(o => ServiceProvider.GetService(o)) - .ToArray(); - - if (parameter != null) - { - // Assumption is that the is always the last in the constructor's parameter list. - int argsLen = args.Length; - var argType = argInfo[argsLen - 1].ParameterType; - var paramType = parameter.GetType(); - if (argType.IsAssignableFrom(paramType) || argType == paramType) - { - args[argsLen - 1] = parameter; - return ActivatorUtilities.CreateInstance(ServiceProvider, type, args); - } - } - } - - return ActivatorUtilities.CreateInstance(ServiceProvider, type); - } - /// /// Creates an instance of type and resolves all constructor dependencies. /// From 02d3bb758866b7707971b282e40529e196a42880 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 12:53:20 +0100 Subject: [PATCH 30/93] Update ApplicationHost.cs --- Emby.Server.Implementations/ApplicationHost.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 8d213ac57d..18b6834ef5 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -566,7 +566,6 @@ namespace Emby.Server.Implementations serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); // TODO: Refactor to eliminate the circular dependency here so that Lazy isn't required - // TODO: Add StartupOptions.FFmpegPath to IConfiguration and remove this custom activation serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); serviceCollection.AddSingleton(); From a44309f56f300cfc670ca2fb62e93f5571aac66a Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 12:53:50 +0100 Subject: [PATCH 31/93] Update HttpListenerHost.cs --- Emby.Server.Implementations/HttpServer/HttpListenerHost.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 6860b7ecdf..7c0d06fb29 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -106,12 +106,7 @@ namespace Emby.Server.Implementations.HttpServer { return _appHost.CreateInstance(type); } - - public object CreateInstance(Type type, object parameter) - { - return _appHost.CreateInstance(type, parameter); - } - + private static string NormalizeUrlPath(string path) { if (path.Length > 0 && path[0] == '/') From 7cd4ae3b6e5d1d921132b55e46d3db4f3aefe59f Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 12:54:13 +0100 Subject: [PATCH 32/93] Update HttpListenerHost.cs --- Emby.Server.Implementations/HttpServer/HttpListenerHost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 7c0d06fb29..c3428ee62a 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.HttpServer { return _appHost.CreateInstance(type); } - + private static string NormalizeUrlPath(string path) { if (path.Length > 0 && path[0] == '/') From 912847ae8c9bf1bc951a0d1d293c05b9ff06bb0a Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 12:54:28 +0100 Subject: [PATCH 33/93] Update ServiceController.cs --- Emby.Server.Implementations/Services/ServiceController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs index b1f2a68273..d884d4f379 100644 --- a/Emby.Server.Implementations/Services/ServiceController.cs +++ b/Emby.Server.Implementations/Services/ServiceController.cs @@ -177,7 +177,7 @@ namespace Emby.Server.Implementations.Services var serviceType = httpHost.GetServiceTypeByRequest(requestType); - var service = httpHost.CreateInstance(serviceType, req); + var service = httpHost.CreateInstance(serviceType); var serviceRequiresContext = service as IRequiresRequest; if (serviceRequiresContext != null) From e33c6f6b29add0d5d19cf9d1607d9afd59151a2a Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 12:54:55 +0100 Subject: [PATCH 34/93] Update IApplicationHost.cs --- MediaBrowser.Common/IApplicationHost.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index cf4954eef1..e8d9282e40 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -125,13 +125,5 @@ namespace MediaBrowser.Common /// The type. /// System.Object. object CreateInstance(Type type); - - /// - /// Creates a new instance of a class. - /// - /// The type to create. - /// An addtional parameter. - /// Created instance. - object CreateInstance(Type type, object parameter); } } From 06beecc4f84971c75f4b1f015dd5ed74a55fe5df Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 12:56:52 +0100 Subject: [PATCH 35/93] Update ServiceHandler.cs --- Emby.Server.Implementations/Services/ServiceHandler.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs index a42f88ea09..c544c86f5b 100644 --- a/Emby.Server.Implementations/Services/ServiceHandler.cs +++ b/Emby.Server.Implementations/Services/ServiceHandler.cs @@ -78,7 +78,8 @@ namespace Emby.Server.Implementations.Services var request = await CreateRequest(httpHost, httpReq, _restPath, logger).ConfigureAwait(false); httpHost.ApplyRequestFilters(httpReq, httpRes, request); - + + httpRes.HttpContext.Items["ServiceStackRequest"] = httpReq; var response = await httpHost.ServiceController.Execute(httpHost, request, httpReq).ConfigureAwait(false); // Apply response filters From d9f94129555d3360eac4f18fe15fdb59c65a83d5 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 12:58:23 +0100 Subject: [PATCH 36/93] Update DlnaServerService.cs --- Emby.Dlna/Api/DlnaServerService.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs index 7fba2184a7..167996eeb8 100644 --- a/Emby.Dlna/Api/DlnaServerService.cs +++ b/Emby.Dlna/Api/DlnaServerService.cs @@ -127,11 +127,14 @@ namespace Emby.Dlna.Api public DlnaServerService( IDlnaManager dlnaManager, IHttpResultFactory httpResultFactory, - IServerConfigurationManager configurationManager) + IServerConfigurationManager configurationManager, + IHttpContextAccessor httpContextAccessor) { _dlnaManager = dlnaManager; _resultFactory = httpResultFactory; _configurationManager = configurationManager; + object request = httpContextAccessor?.HttpContext.Items["ServiceStackRequest"] ?? throw new ArgumentNullException(nameof(httpContextAccessor)); + Request = (IRequest)request; } private string GetHeader(string name) From 0140262e2fdd3e773e7773620d1c4e5743c3204d Mon Sep 17 00:00:00 2001 From: David Date: Fri, 17 Jul 2020 11:19:27 +0000 Subject: [PATCH 38/93] Translated using Weblate (German) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/ --- Emby.Server.Implementations/Localization/Core/de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/de.json b/Emby.Server.Implementations/Localization/Core/de.json index 82df43be11..a6e9779c95 100644 --- a/Emby.Server.Implementations/Localization/Core/de.json +++ b/Emby.Server.Implementations/Localization/Core/de.json @@ -3,7 +3,7 @@ "AppDeviceValues": "App: {0}, Gerät: {1}", "Application": "Anwendung", "Artists": "Interpreten", - "AuthenticationSucceededWithUserName": "{0} hat sich erfolgreich authentifiziert", + "AuthenticationSucceededWithUserName": "{0} hat sich erfolgreich angemeldet", "Books": "Bücher", "CameraImageUploadedFrom": "Ein neues Foto wurde von {0} hochgeladen", "Channels": "Kanäle", From fd2f18899b8ea4db5152d98d9822d6cff6d7d892 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 16:06:32 +0100 Subject: [PATCH 39/93] Update ServiceHandler.cs --- Emby.Server.Implementations/Services/ServiceHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs index c544c86f5b..3997a5ddb7 100644 --- a/Emby.Server.Implementations/Services/ServiceHandler.cs +++ b/Emby.Server.Implementations/Services/ServiceHandler.cs @@ -79,7 +79,7 @@ namespace Emby.Server.Implementations.Services httpHost.ApplyRequestFilters(httpReq, httpRes, request); - httpRes.HttpContext.Items["ServiceStackRequest"] = httpReq; + httpRes.HttpContext.SetServiceStackRequest(httpReq); var response = await httpHost.ServiceController.Execute(httpHost, request, httpReq).ConfigureAwait(false); // Apply response filters From 24c1776ff61481b85b016cc0fcfef0a319589fdc Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 16:06:52 +0100 Subject: [PATCH 40/93] Add files via upload --- .../Services/HttpContextExtension.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Emby.Server.Implementations/Services/HttpContextExtension.cs diff --git a/Emby.Server.Implementations/Services/HttpContextExtension.cs b/Emby.Server.Implementations/Services/HttpContextExtension.cs new file mode 100644 index 0000000000..6d3a600ab5 --- /dev/null +++ b/Emby.Server.Implementations/Services/HttpContextExtension.cs @@ -0,0 +1,33 @@ +using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; + +namespace Emby.Server.Implementations.Services +{ + /// + /// Extention to enable the service stack request to be stored in the HttpRequest object. + /// + public static class HttpContextExtension + { + private const string SERVICESTACKREQUEST = "ServiceRequestStack"; + + /// + /// Set the service stack request. + /// + /// The HttpContext instance. + /// The IRequest instance. + public static void SetServiceStackRequest(this HttpContext httpContext, IRequest request) + { + httpContext.Items[SERVICESTACKREQUEST] = request; + } + + /// + /// Get the service stack request. + /// + /// The HttpContext instance. + /// The service stack request instance. + public static IRequest GetServiceStack(this HttpContext httpContext) + { + return (IRequest)httpContext.Items[SERVICESTACKREQUEST]; + } + } +} From c7c28db17beaf67be68feb769e88ac5bf14dc534 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 16:08:26 +0100 Subject: [PATCH 41/93] Update DlnaServerService.cs --- Emby.Dlna/Api/DlnaServerService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs index 167996eeb8..049b201bbc 100644 --- a/Emby.Dlna/Api/DlnaServerService.cs +++ b/Emby.Dlna/Api/DlnaServerService.cs @@ -108,7 +108,7 @@ namespace Emby.Dlna.Api public string Filename { get; set; } } - public class DlnaServerService : IService, IRequiresRequest + public class DlnaServerService : IService { private const string XMLContentType = "text/xml; charset=UTF-8"; From 6b4cea604ce9128b6d306e010035c14f6cb75ec4 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 16:19:06 +0100 Subject: [PATCH 42/93] Suggested changes and removed some intellisense messages. --- MediaBrowser.Model/Notifications/NotificationOption.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/MediaBrowser.Model/Notifications/NotificationOption.cs b/MediaBrowser.Model/Notifications/NotificationOption.cs index dc8d27baf2..58aecb3d35 100644 --- a/MediaBrowser.Model/Notifications/NotificationOption.cs +++ b/MediaBrowser.Model/Notifications/NotificationOption.cs @@ -1,3 +1,4 @@ +#pragma warning disable CA1819 // Properties should not return arrays #pragma warning disable CS1591 using System; @@ -9,7 +10,6 @@ namespace MediaBrowser.Model.Notifications public NotificationOption(string type) { Type = type; - DisabledServices = Array.Empty(); DisabledMonitorUsers = Array.Empty(); SendToUsers = Array.Empty(); @@ -17,21 +17,20 @@ namespace MediaBrowser.Model.Notifications public NotificationOption() { - Type = string.Empty; DisabledServices = Array.Empty(); DisabledMonitorUsers = Array.Empty(); SendToUsers = Array.Empty(); } - public string Type { get; set; } + public string? Type { get; set; } /// - /// User Ids to not monitor (it's opt out). + /// Gets or sets user Ids to not monitor (it's opt out). /// public string[] DisabledMonitorUsers { get; set; } /// - /// User Ids to send to (if SendToUserMode == Custom) + /// Gets or sets user Ids to send to (if SendToUserMode == Custom). /// public string[] SendToUsers { get; set; } From 0f696104aca3309145b2e7f4169c4cf1be8ad81a Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 17 Jul 2020 16:23:12 +0100 Subject: [PATCH 43/93] using missing. --- Emby.Dlna/Api/DlnaServerService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs index 049b201bbc..7e5eb8f907 100644 --- a/Emby.Dlna/Api/DlnaServerService.cs +++ b/Emby.Dlna/Api/DlnaServerService.cs @@ -11,6 +11,7 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace Emby.Dlna.Api { From 4dd91f36676444680893e5029e72933e91df833b Mon Sep 17 00:00:00 2001 From: crobibero Date: Fri, 17 Jul 2020 12:17:11 -0600 Subject: [PATCH 44/93] Add UserId filter to ActivityLog Entries endpoint --- MediaBrowser.Api/System/ActivityLogService.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Api/System/ActivityLogService.cs b/MediaBrowser.Api/System/ActivityLogService.cs index 7ca31c21ab..4afa6e114a 100644 --- a/MediaBrowser.Api/System/ActivityLogService.cs +++ b/MediaBrowser.Api/System/ActivityLogService.cs @@ -56,7 +56,10 @@ namespace MediaBrowser.Api.System DateTime.Parse(request.MinDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); var filterFunc = new Func, IQueryable>( - entries => entries.Where(entry => entry.DateCreated >= minDate)); + entries => entries.Where(entry => entry.DateCreated >= minDate + && (!request.HasUserId.HasValue || (request.HasUserId.Value + ? entry.UserId != Guid.Empty + : entry.UserId == Guid.Empty)))); var result = _activityManager.GetPagedResult(filterFunc, request.StartIndex, request.Limit); From e152a6c82fae97be6bdfae0813e883ea05c68f15 Mon Sep 17 00:00:00 2001 From: crobibero Date: Fri, 17 Jul 2020 15:53:10 -0600 Subject: [PATCH 45/93] Increase delete logging --- .../Library/LibraryManager.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 77d44e1313..06cfc78b3a 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -341,7 +341,7 @@ namespace Emby.Server.Implementations.Library if (item is LiveTvProgram) { _logger.LogDebug( - "Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", + "Removing item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", item.GetType().Name, item.Name ?? "Unknown name", item.Path ?? string.Empty, @@ -350,7 +350,7 @@ namespace Emby.Server.Implementations.Library else { _logger.LogInformation( - "Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", + "Removing item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", item.GetType().Name, item.Name ?? "Unknown name", item.Path ?? string.Empty, @@ -368,7 +368,12 @@ namespace Emby.Server.Implementations.Library continue; } - _logger.LogDebug("Deleting path {MetadataPath}", metadataPath); + _logger.LogDebug( + "Deleting metadata path, Type: {0}, Name: {1}, Path: {2}, Id: {3}", + item.GetType().Name, + item.Name ?? "Unknown name", + metadataPath, + item.Id); try { @@ -392,7 +397,13 @@ namespace Emby.Server.Implementations.Library { try { - _logger.LogDebug("Deleting path {path}", fileSystemInfo.FullName); + _logger.LogInformation( + "Deleting item path, Type: {0}, Name: {1}, Path: {2}, Id: {3}", + item.GetType().Name, + item.Name ?? "Unknown name", + fileSystemInfo.FullName, + item.Id); + if (fileSystemInfo.IsDirectory) { Directory.Delete(fileSystemInfo.FullName, true); From 4742ddbb711e9c7b0141b592b9b005f85e85c0df Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 17 Jul 2020 19:48:11 -0400 Subject: [PATCH 46/93] Update .NET Core to 3.1.6 --- .../Emby.Server.Implementations.csproj | 8 ++++---- Jellyfin.Api/Jellyfin.Api.csproj | 2 +- Jellyfin.Data/Jellyfin.Data.csproj | 4 ++-- .../Jellyfin.Server.Implementations.csproj | 4 ++-- Jellyfin.Server/Jellyfin.Server.csproj | 4 ++-- MediaBrowser.Common/MediaBrowser.Common.csproj | 4 ++-- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 4 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 +- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 4 ++-- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 2 +- .../MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index f7ad59c10f..4351b9aa59 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -34,10 +34,10 @@ - - - - + + + + diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 93c4612b66..3693d5122a 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -14,7 +14,7 @@ - + diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 58d1ba2f36..8ce0f3848c 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index dcac1b34b1..21748ca192 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -24,11 +24,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 6a2d252ab7..b1bd38cffb 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -41,8 +41,8 @@ - - + + diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index c9ca153c71..7380f39fda 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 73e966344f..67f17f7a52 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 83bd0c07e6..902e29b20b 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -23,7 +23,7 @@ - + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 446e27df65..42c7cec535 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 2190208886..132050e7b2 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj index a767c00397..8309faebd1 100644 --- a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj +++ b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj @@ -8,7 +8,7 @@ - + From f9b0816b80793965ef044f6871a7ffd80e91d303 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sat, 18 Jul 2020 16:54:23 +0100 Subject: [PATCH 47/93] Changes a suggested. --- Emby.Dlna/Api/DlnaServerService.cs | 3 +-- .../Services/ServiceHandler.cs | 1 + .../Extensions/HttpContextExtensions.cs | 13 +++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) rename Emby.Server.Implementations/Services/HttpContextExtension.cs => MediaBrowser.Common/Extensions/HttpContextExtensions.cs (68%) diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs index 7e5eb8f907..a61a8d5abb 100644 --- a/Emby.Dlna/Api/DlnaServerService.cs +++ b/Emby.Dlna/Api/DlnaServerService.cs @@ -134,8 +134,7 @@ namespace Emby.Dlna.Api _dlnaManager = dlnaManager; _resultFactory = httpResultFactory; _configurationManager = configurationManager; - object request = httpContextAccessor?.HttpContext.Items["ServiceStackRequest"] ?? throw new ArgumentNullException(nameof(httpContextAccessor)); - Request = (IRequest)request; + Request = httpContextAccessor?.HttpContext.GetServiceStack() ?? throw new ArgumentNullException(nameof(httpContextAccessor)); } private string GetHeader(string name) diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs index 3997a5ddb7..3d4e1ca77b 100644 --- a/Emby.Server.Implementations/Services/ServiceHandler.cs +++ b/Emby.Server.Implementations/Services/ServiceHandler.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.HttpServer; +using MediaBrowser.Common.Extensions; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/Services/HttpContextExtension.cs b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs similarity index 68% rename from Emby.Server.Implementations/Services/HttpContextExtension.cs rename to MediaBrowser.Common/Extensions/HttpContextExtensions.cs index 6d3a600ab5..4bab42cc12 100644 --- a/Emby.Server.Implementations/Services/HttpContextExtension.cs +++ b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs @@ -1,27 +1,28 @@ using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; -namespace Emby.Server.Implementations.Services +namespace MediaBrowser.Common.Extensions { /// /// Extention to enable the service stack request to be stored in the HttpRequest object. + /// Static class containing extension methods for . /// - public static class HttpContextExtension + public static class HttpContextExtensions { - private const string SERVICESTACKREQUEST = "ServiceRequestStack"; + private const string SERVICESTACKREQUEST = "ServiceStackRequest"; /// - /// Set the service stack request. + /// Set the ServiceStack request. /// /// The HttpContext instance. - /// The IRequest instance. + /// The service stack request instance. public static void SetServiceStackRequest(this HttpContext httpContext, IRequest request) { httpContext.Items[SERVICESTACKREQUEST] = request; } /// - /// Get the service stack request. + /// Get the ServiceStack request. /// /// The HttpContext instance. /// The service stack request instance. From 69ba385782338723a83a2a107857f315ab014f79 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sat, 18 Jul 2020 16:55:46 +0100 Subject: [PATCH 48/93] Corrected comment --- MediaBrowser.Common/Extensions/HttpContextExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs index 4bab42cc12..142935c1a8 100644 --- a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs +++ b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs @@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Http; namespace MediaBrowser.Common.Extensions { /// - /// Extention to enable the service stack request to be stored in the HttpRequest object. /// Static class containing extension methods for . /// public static class HttpContextExtensions From b53bf2cd16f1e64b4a35d0f510ac30239a2e2cdb Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 18 Jul 2020 16:21:01 -0400 Subject: [PATCH 49/93] Remove obsolete network path code --- .../Library/LibraryManager.cs | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 06cfc78b3a..c27b73c74e 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -3011,21 +3011,6 @@ namespace Emby.Server.Implementations.Library }); } - private static bool ValidateNetworkPath(string path) - { - // if (Environment.OSVersion.Platform == PlatformID.Win32NT) - //{ - // // We can't validate protocol-based paths, so just allow them - // if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1) - // { - // return Directory.Exists(path); - // } - //} - - // Without native support for unc, we cannot validate this when running under mono - return true; - } - private const string ShortcutFileExtension = ".mblink"; public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo) @@ -3052,11 +3037,6 @@ namespace Emby.Server.Implementations.Library throw new FileNotFoundException("The path does not exist."); } - if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !ValidateNetworkPath(pathInfo.NetworkPath)) - { - throw new FileNotFoundException("The network path does not exist."); - } - var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath; var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); @@ -3095,11 +3075,6 @@ namespace Emby.Server.Implementations.Library throw new ArgumentNullException(nameof(pathInfo)); } - if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !ValidateNetworkPath(pathInfo.NetworkPath)) - { - throw new FileNotFoundException("The network path does not exist."); - } - var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath; var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); From d719ca78b40695b02b03c912b636652545eff3e8 Mon Sep 17 00:00:00 2001 From: Ken Date: Sat, 18 Jul 2020 19:39:31 -0600 Subject: [PATCH 50/93] Spacing standard on Emby.Server.Implementations/IO/ManagedFileSystem.cs Co-authored-by: Cody Robibero --- Emby.Server.Implementations/IO/ManagedFileSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 530c16195a..08e0cf447e 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -247,7 +247,7 @@ namespace Emby.Server.Implementations.IO result.Length = fileInfo.Length; // Issue #2354 get the size of files behind symbolic links - if(fileInfo.Attributes.HasFlag(FileAttributes.ReparsePoint)) + if (fileInfo.Attributes.HasFlag(FileAttributes.ReparsePoint)) { using (Stream thisFileStream = File.OpenRead(fileInfo.ToString())) { From eea142cad1d3bfe49f3fb804902b3346174c31ea Mon Sep 17 00:00:00 2001 From: Ken Date: Sat, 18 Jul 2020 19:40:28 -0600 Subject: [PATCH 51/93] FullName property instead of ToString in Emby.Server.Implementations/IO/ManagedFileSystem.cs Co-authored-by: Cody Robibero --- Emby.Server.Implementations/IO/ManagedFileSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 08e0cf447e..ab6483bf9f 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -249,7 +249,7 @@ namespace Emby.Server.Implementations.IO // Issue #2354 get the size of files behind symbolic links if (fileInfo.Attributes.HasFlag(FileAttributes.ReparsePoint)) { - using (Stream thisFileStream = File.OpenRead(fileInfo.ToString())) + using (Stream thisFileStream = File.OpenRead(fileInfo.FullName)) { result.Length = thisFileStream.Length; } From 2f38d9700cd6f6e80976d2bfe320d1a829a8eed4 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sat, 18 Jul 2020 20:29:27 -0600 Subject: [PATCH 52/93] fix UserManager UpdatePolicy --- Jellyfin.Server.Implementations/Users/UserManager.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 9aff808db0..e3a7d54677 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -671,7 +671,13 @@ namespace Jellyfin.Server.Implementations.Users public void UpdatePolicy(Guid userId, UserPolicy policy) { var dbContext = _dbProvider.CreateContext(); - var user = dbContext.Users.Find(userId) ?? throw new ArgumentException("No user exists with given Id!"); + var user = dbContext.Users + .Include(u => u.Permissions) + .Include(u => u.Preferences) + .Include(u => u.AccessSchedules) + .Include(u => u.ProfileImage) + .FirstOrDefault(u => u.Id == userId) + ?? throw new ArgumentException("No user exists with given Id!"); // The default number of login attempts is 3, but for some god forsaken reason it's sent to the server as "0" int? maxLoginAttempts = policy.LoginAttemptsBeforeLockout switch From 8a778c08d2bbd387ffcf92d2fb6004fda414a74d Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 19 Jul 2020 08:21:26 -0600 Subject: [PATCH 53/93] Fix tvdb actors url --- MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs index 196e801c03..df48629d03 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs @@ -375,7 +375,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb if (!string.IsNullOrEmpty(actor.Image)) { - personInfo.ImageUrl = TvdbUtils.TvdbImageBaseUrl + actor.Image; + personInfo.ImageUrl = TvdbUtils.BannerUrl + actor.Image; } if (!string.IsNullOrWhiteSpace(personInfo.Name)) From 59365150d8be78ef77872f79ef11a927ecb06d1b Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 19 Jul 2020 08:31:35 -0600 Subject: [PATCH 54/93] Remove profile image before setting new --- MediaBrowser.Api/Images/ImageService.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 8426a9a4f8..575b1157a4 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -895,6 +895,11 @@ namespace MediaBrowser.Api.Images // Handle image/png; charset=utf-8 mimeType = mimeType.Split(';').FirstOrDefault(); var userDataPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); + if (user.ProfileImage != null) + { + _userManager.ClearProfileImage(user); + } + user.ProfileImage = new Jellyfin.Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType))); await _providerManager From 672a35db94b147fc1479a4815f07b119f6a670b6 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sun, 19 Jul 2020 17:54:09 +0100 Subject: [PATCH 55/93] Update DlnaServerService.cs --- Emby.Dlna/Api/DlnaServerService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs index a61a8d5abb..d9c1669b0f 100644 --- a/Emby.Dlna/Api/DlnaServerService.cs +++ b/Emby.Dlna/Api/DlnaServerService.cs @@ -134,7 +134,7 @@ namespace Emby.Dlna.Api _dlnaManager = dlnaManager; _resultFactory = httpResultFactory; _configurationManager = configurationManager; - Request = httpContextAccessor?.HttpContext.GetServiceStack() ?? throw new ArgumentNullException(nameof(httpContextAccessor)); + Request = httpContextAccessor?.HttpContext.GetServiceStackRequest() ?? throw new ArgumentNullException(nameof(httpContextAccessor)); } private string GetHeader(string name) From 7becef73df136e3373d75ebdaa071da3aaf0d0da Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sun, 19 Jul 2020 17:54:29 +0100 Subject: [PATCH 56/93] Update MediaBrowser.Common/Extensions/HttpContextExtensions.cs Co-authored-by: Mark Monteiro --- MediaBrowser.Common/Extensions/HttpContextExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs index 142935c1a8..da14ebac62 100644 --- a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs +++ b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Common.Extensions /// /// The HttpContext instance. /// The service stack request instance. - public static IRequest GetServiceStack(this HttpContext httpContext) + public static IRequest GetServiceStackRequest(this HttpContext httpContext) { return (IRequest)httpContext.Items[SERVICESTACKREQUEST]; } From dfd00c7b244a031135cc1cfc8038cb0a80ca3c3d Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 19 Jul 2020 13:59:07 -0400 Subject: [PATCH 57/93] Add NuGet publish step to tag CI --- .ci/azure-pipelines-package.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.ci/azure-pipelines-package.yml b/.ci/azure-pipelines-package.yml index 5539b16ab4..68ec427cb7 100644 --- a/.ci/azure-pipelines-package.yml +++ b/.ci/azure-pipelines-package.yml @@ -139,3 +139,25 @@ jobs: sudo /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber) rm $0 exit + +- job: PublishNuget + displayName: 'Publish NuGet packages' + dependsOn: + - BuildPackage + condition: and((succeeded'BuildPackage'), startsWith(variables['Build.SourceBranch'], 'refs/tags')) + + pool: + vmImage: 'ubuntu-latest' + + steps: + - task: NuGetCommand@2 + inputs: + command: 'pack' + packagesToPack: Jellyfin.Data/Jellyfin.Data.csproj;MediaBrowser.Common/MediaBrowser.Common.csproj;MediaBrowser.Controller/MediaBrowser.Controller.csproj;MediaBrowser.Model/MediaBrowser.Model.csproj;Emby.Naming/Emby.Naming.csproj + packDestination: '$(Build.ArtifactStagingDirectory)' + + - task: NuGetCommand@2 + inputs: + command: 'push' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg' + includeNugetOrg: 'true' From 39be99504f00123a078d55f1352b0a892a89cfc3 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 19 Jul 2020 21:20:18 +0200 Subject: [PATCH 58/93] Improve DescriptionXmlBuilder * Replace XML escape code with SecurityElement.Escape * Optimize StringBuilder.Append calls --- Emby.Dlna/Server/DescriptionXmlBuilder.cs | 180 +++++++++------------- 1 file changed, 74 insertions(+), 106 deletions(-) diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs index 7143c31094..4a19061d71 100644 --- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs +++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Security; using System.Text; using Emby.Dlna.Common; using MediaBrowser.Model.Dlna; @@ -67,7 +68,7 @@ namespace Emby.Dlna.Server builder.AppendFormat(" {0}=\"{1}\"", att.Name, att.Value); } - builder.Append(">"); + builder.Append('>'); builder.Append(""); builder.Append("1"); @@ -76,7 +77,9 @@ namespace Emby.Dlna.Server if (!EnableAbsoluteUrls) { - builder.Append("" + Escape(_serverAddress) + ""); + builder.Append("") + .Append(SecurityElement.Escape(_serverAddress)) + .Append(""); } AppendDeviceInfo(builder); @@ -93,91 +96,14 @@ namespace Emby.Dlna.Server AppendIconList(builder); - builder.Append("" + Escape(_serverAddress) + "/web/index.html"); + builder.Append("") + .Append(SecurityElement.Escape(_serverAddress)) + .Append("/web/index.html"); AppendServiceList(builder); builder.Append(""); } - private static readonly char[] s_escapeChars = new char[] - { - '<', - '>', - '"', - '\'', - '&' - }; - - private static readonly string[] s_escapeStringPairs = new[] - { - "<", - "<", - ">", - ">", - "\"", - """, - "'", - "'", - "&", - "&" - }; - - private static string GetEscapeSequence(char c) - { - int num = s_escapeStringPairs.Length; - for (int i = 0; i < num; i += 2) - { - string text = s_escapeStringPairs[i]; - string result = s_escapeStringPairs[i + 1]; - if (text[0] == c) - { - return result; - } - } - - return c.ToString(CultureInfo.InvariantCulture); - } - - /// Replaces invalid XML characters in a string with their valid XML equivalent. - /// The input string with invalid characters replaced. - /// The string within which to escape invalid characters. - public static string Escape(string str) - { - if (str == null) - { - return null; - } - - StringBuilder stringBuilder = null; - int length = str.Length; - int num = 0; - while (true) - { - int num2 = str.IndexOfAny(s_escapeChars, num); - if (num2 == -1) - { - break; - } - - if (stringBuilder == null) - { - stringBuilder = new StringBuilder(); - } - - stringBuilder.Append(str, num, num2 - num); - stringBuilder.Append(GetEscapeSequence(str[num2])); - num = num2 + 1; - } - - if (stringBuilder == null) - { - return str; - } - - stringBuilder.Append(str, num, length - num); - return stringBuilder.ToString(); - } - private void AppendDeviceProperties(StringBuilder builder) { builder.Append(""); @@ -187,32 +113,54 @@ namespace Emby.Dlna.Server builder.Append("urn:schemas-upnp-org:device:MediaServer:1"); - builder.Append("" + Escape(GetFriendlyName()) + ""); - builder.Append("" + Escape(_profile.Manufacturer ?? string.Empty) + ""); - builder.Append("" + Escape(_profile.ManufacturerUrl ?? string.Empty) + ""); - - builder.Append("" + Escape(_profile.ModelDescription ?? string.Empty) + ""); - builder.Append("" + Escape(_profile.ModelName ?? string.Empty) + ""); - - builder.Append("" + Escape(_profile.ModelNumber ?? string.Empty) + ""); - builder.Append("" + Escape(_profile.ModelUrl ?? string.Empty) + ""); + builder.Append("") + .Append(SecurityElement.Escape(GetFriendlyName())) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(_profile.Manufacturer ?? string.Empty)) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(_profile.ManufacturerUrl ?? string.Empty)) + .Append(""); + + builder.Append("") + .Append(SecurityElement.Escape(_profile.ModelDescription ?? string.Empty)) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(_profile.ModelName ?? string.Empty)) + .Append(""); + + builder.Append("") + .Append(SecurityElement.Escape(_profile.ModelNumber ?? string.Empty)) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(_profile.ModelUrl ?? string.Empty)) + .Append(""); if (string.IsNullOrEmpty(_profile.SerialNumber)) { - builder.Append("" + Escape(_serverId) + ""); + builder.Append("") + .Append(SecurityElement.Escape(_serverId)) + .Append(""); } else { - builder.Append("" + Escape(_profile.SerialNumber) + ""); + builder.Append("") + .Append(SecurityElement.Escape(_profile.SerialNumber)) + .Append(""); } builder.Append(""); - builder.Append("uuid:" + Escape(_serverUdn) + ""); + builder.Append("uuid:") + .Append(SecurityElement.Escape(_serverUdn)) + .Append(""); if (!string.IsNullOrEmpty(_profile.SonyAggregationFlags)) { - builder.Append("" + Escape(_profile.SonyAggregationFlags) + ""); + builder.Append("") + .Append(SecurityElement.Escape(_profile.SonyAggregationFlags)) + .Append(""); } } @@ -250,11 +198,21 @@ namespace Emby.Dlna.Server { builder.Append(""); - builder.Append("" + Escape(icon.MimeType ?? string.Empty) + ""); - builder.Append("" + Escape(icon.Width.ToString(_usCulture)) + ""); - builder.Append("" + Escape(icon.Height.ToString(_usCulture)) + ""); - builder.Append("" + Escape(icon.Depth ?? string.Empty) + ""); - builder.Append("" + BuildUrl(icon.Url) + ""); + builder.Append("") + .Append(SecurityElement.Escape(icon.MimeType ?? string.Empty)) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(icon.Width.ToString(_usCulture))) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(icon.Height.ToString(_usCulture))) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(icon.Depth ?? string.Empty)) + .Append(""); + builder.Append("") + .Append(BuildUrl(icon.Url)) + .Append(""); builder.Append(""); } @@ -270,11 +228,21 @@ namespace Emby.Dlna.Server { builder.Append(""); - builder.Append("" + Escape(service.ServiceType ?? string.Empty) + ""); - builder.Append("" + Escape(service.ServiceId ?? string.Empty) + ""); - builder.Append("" + BuildUrl(service.ScpdUrl) + ""); - builder.Append("" + BuildUrl(service.ControlUrl) + ""); - builder.Append("" + BuildUrl(service.EventSubUrl) + ""); + builder.Append("") + .Append(SecurityElement.Escape(service.ServiceType ?? string.Empty)) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(service.ServiceId ?? string.Empty)) + .Append(""); + builder.Append("") + .Append(BuildUrl(service.ScpdUrl)) + .Append(""); + builder.Append("") + .Append(BuildUrl(service.ControlUrl)) + .Append(""); + builder.Append("") + .Append(BuildUrl(service.EventSubUrl)) + .Append(""); builder.Append(""); } @@ -298,7 +266,7 @@ namespace Emby.Dlna.Server url = _serverAddress.TrimEnd('/') + url; } - return Escape(url); + return SecurityElement.Escape(url); } private IEnumerable GetIcons() From 65453c0a84044e313b27cb639d80b5a85565eee2 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 19 Jul 2020 21:31:14 +0200 Subject: [PATCH 59/93] Fix build and more Append calls --- Emby.Dlna/PlayTo/Device.cs | 4 +-- Emby.Dlna/Server/DescriptionXmlBuilder.cs | 2 +- Emby.Dlna/Service/ServiceXmlBuilder.cs | 34 +++++++++++++++++------ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index c5080b90f3..72834c69d1 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -4,12 +4,12 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Security; using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using Emby.Dlna.Common; -using Emby.Dlna.Server; using Emby.Dlna.Ssdp; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; @@ -334,7 +334,7 @@ namespace Emby.Dlna.PlayTo return string.Empty; } - return DescriptionXmlBuilder.Escape(value); + return SecurityElement.Escape(value); } private Task SetPlay(TransportCommands avCommands, CancellationToken cancellationToken) diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs index 4a19061d71..bca9e81cd0 100644 --- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs +++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs @@ -65,7 +65,7 @@ namespace Emby.Dlna.Server foreach (var att in attributes) { - builder.AppendFormat(" {0}=\"{1}\"", att.Name, att.Value); + builder.AppendFormat(CultureInfo.InvariantCulture, " {0}=\"{1}\"", att.Name, att.Value); } builder.Append('>'); diff --git a/Emby.Dlna/Service/ServiceXmlBuilder.cs b/Emby.Dlna/Service/ServiceXmlBuilder.cs index af557aa144..6c7d6f8462 100644 --- a/Emby.Dlna/Service/ServiceXmlBuilder.cs +++ b/Emby.Dlna/Service/ServiceXmlBuilder.cs @@ -1,9 +1,9 @@ #pragma warning disable CS1591 using System.Collections.Generic; +using System.Security; using System.Text; using Emby.Dlna.Common; -using Emby.Dlna.Server; namespace Emby.Dlna.Service { @@ -37,7 +37,9 @@ namespace Emby.Dlna.Service { builder.Append(""); - builder.Append("" + DescriptionXmlBuilder.Escape(item.Name ?? string.Empty) + ""); + builder.Append("") + .Append(SecurityElement.Escape(item.Name ?? string.Empty)) + .Append(""); builder.Append(""); @@ -45,9 +47,15 @@ namespace Emby.Dlna.Service { builder.Append(""); - builder.Append("" + DescriptionXmlBuilder.Escape(argument.Name ?? string.Empty) + ""); - builder.Append("" + DescriptionXmlBuilder.Escape(argument.Direction ?? string.Empty) + ""); - builder.Append("" + DescriptionXmlBuilder.Escape(argument.RelatedStateVariable ?? string.Empty) + ""); + builder.Append("") + .Append(SecurityElement.Escape(argument.Name ?? string.Empty)) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(argument.Direction ?? string.Empty)) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(argument.RelatedStateVariable ?? string.Empty)) + .Append(""); builder.Append(""); } @@ -68,17 +76,25 @@ namespace Emby.Dlna.Service { var sendEvents = item.SendsEvents ? "yes" : "no"; - builder.Append(""); + builder.Append(""); - builder.Append("" + DescriptionXmlBuilder.Escape(item.Name ?? string.Empty) + ""); - builder.Append("" + DescriptionXmlBuilder.Escape(item.DataType ?? string.Empty) + ""); + builder.Append("") + .Append(SecurityElement.Escape(item.Name ?? string.Empty)) + .Append(""); + builder.Append("") + .Append(SecurityElement.Escape(item.DataType ?? string.Empty)) + .Append(""); if (item.AllowedValues.Length > 0) { builder.Append(""); foreach (var allowedValue in item.AllowedValues) { - builder.Append("" + DescriptionXmlBuilder.Escape(allowedValue) + ""); + builder.Append("") + .Append(SecurityElement.Escape(allowedValue)) + .Append(""); } builder.Append(""); From a5b673d542fd91dd445c325fabcf5b96f45dbe17 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 19 Jul 2020 17:06:58 -0400 Subject: [PATCH 60/93] Revert "bump the minimum required jellyfin-ffmpeg ver to 4.3.1-1" This reverts commit d3fa6b428a9a2220856d9a91266c1b6c7833093e. Don't change this, since 4.3.1 won't build on Stretch but we still want to support it. --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 4dc766b913..896d8286b7 100644 --- a/debian/control +++ b/debian/control @@ -21,7 +21,7 @@ Conflicts: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server Architecture: any Depends: at, libsqlite3-0, - jellyfin-ffmpeg (>= 4.3.1-1), + jellyfin-ffmpeg (>= 4.2.1-2), libfontconfig1, libfreetype6, libssl1.1 From 301ddc1dacb1f7a8c67c62e1ebeeb9badc478bb8 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sun, 19 Jul 2020 22:19:17 +0100 Subject: [PATCH 61/93] Update HttpContextExtensions.cs --- MediaBrowser.Common/Extensions/HttpContextExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs index da14ebac62..d746207c72 100644 --- a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs +++ b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Common.Extensions /// public static class HttpContextExtensions { - private const string SERVICESTACKREQUEST = "ServiceStackRequest"; + private const string ServiceStackRequest = "ServiceStackRequest"; /// /// Set the ServiceStack request. @@ -17,7 +17,7 @@ namespace MediaBrowser.Common.Extensions /// The service stack request instance. public static void SetServiceStackRequest(this HttpContext httpContext, IRequest request) { - httpContext.Items[SERVICESTACKREQUEST] = request; + httpContext.Items[ServiceStackRequest] = request; } /// @@ -27,7 +27,7 @@ namespace MediaBrowser.Common.Extensions /// The service stack request instance. public static IRequest GetServiceStackRequest(this HttpContext httpContext) { - return (IRequest)httpContext.Items[SERVICESTACKREQUEST]; + return (IRequest)httpContext.Items[ServiceStackRequest]; } } } From 2f2fe3552ddf1914814b78fd6fa911e7bc752416 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 19 Jul 2020 17:54:46 -0400 Subject: [PATCH 62/93] Fix typo in CI configuration --- .ci/azure-pipelines-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/azure-pipelines-package.yml b/.ci/azure-pipelines-package.yml index 68ec427cb7..2721112991 100644 --- a/.ci/azure-pipelines-package.yml +++ b/.ci/azure-pipelines-package.yml @@ -144,7 +144,7 @@ jobs: displayName: 'Publish NuGet packages' dependsOn: - BuildPackage - condition: and((succeeded'BuildPackage'), startsWith(variables['Build.SourceBranch'], 'refs/tags')) + condition: and(succeeded('BuildPackage'), startsWith(variables['Build.SourceBranch'], 'refs/tags')) pool: vmImage: 'ubuntu-latest' From 3fdbdf4078fb61310a0626404f7805804150de45 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 3 Jul 2020 14:02:04 -0400 Subject: [PATCH 63/93] Clean up ProviderManager.cs --- .../Manager/ProviderManager.cs | 247 +++++++++--------- 1 file changed, 128 insertions(+), 119 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 86a182fe50..98bcd8d31e 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -25,7 +23,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; using Priority_Queue; using Book = MediaBrowser.Controller.Entities.Book; @@ -42,33 +39,38 @@ namespace MediaBrowser.Providers.Manager /// public class ProviderManager : IProviderManager, IDisposable { + private readonly object _refreshQueueLock = new object(); private readonly ILogger _logger; private readonly IHttpClient _httpClient; private readonly ILibraryMonitor _libraryMonitor; private readonly IFileSystem _fileSystem; private readonly IServerApplicationPaths _appPaths; - private readonly IJsonSerializer _json; private readonly ILibraryManager _libraryManager; private readonly ISubtitleManager _subtitleManager; private readonly IServerConfigurationManager _configurationManager; + private readonly ConcurrentDictionary _activeRefreshes = new ConcurrentDictionary(); + private readonly CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); + private readonly SimplePriorityQueue> _refreshQueue = + new SimplePriorityQueue>(); - private IImageProvider[] ImageProviders { get; set; } - - private IMetadataService[] _metadataServices = { }; - private IMetadataProvider[] _metadataProviders = { }; + private IMetadataService[] _metadataServices = Array.Empty(); + private IMetadataProvider[] _metadataProviders = Array.Empty(); private IEnumerable _savers; - private IExternalId[] _externalIds; - - private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); - - public event EventHandler> RefreshStarted; - public event EventHandler> RefreshCompleted; - public event EventHandler>> RefreshProgress; + private bool _isProcessingRefreshQueue; + private bool _disposed; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// + /// The Http client. + /// The subtitle manager. + /// The configuration manager. + /// The library monitor. + /// The logger. + /// The filesystem. + /// The server application paths. + /// The library manager. public ProviderManager( IHttpClient httpClient, ISubtitleManager subtitleManager, @@ -77,8 +79,7 @@ namespace MediaBrowser.Providers.Manager ILogger logger, IFileSystem fileSystem, IServerApplicationPaths appPaths, - ILibraryManager libraryManager, - IJsonSerializer json) + ILibraryManager libraryManager) { _logger = logger; _httpClient = httpClient; @@ -87,16 +88,27 @@ namespace MediaBrowser.Providers.Manager _fileSystem = fileSystem; _appPaths = appPaths; _libraryManager = libraryManager; - _json = json; _subtitleManager = subtitleManager; } - /// - /// Adds the metadata providers. - /// - public void AddParts(IEnumerable imageProviders, IEnumerable metadataServices, - IEnumerable metadataProviders, IEnumerable metadataSavers, - IEnumerable externalIds) + /// + public event EventHandler> RefreshStarted; + + /// + public event EventHandler> RefreshCompleted; + + /// + public event EventHandler>> RefreshProgress; + + private IImageProvider[] ImageProviders { get; set; } + + /// + public void AddParts( + IEnumerable imageProviders, + IEnumerable metadataServices, + IEnumerable metadataProviders, + IEnumerable metadataSavers, + IEnumerable externalIds) { ImageProviders = imageProviders.ToArray(); @@ -104,27 +116,17 @@ namespace MediaBrowser.Providers.Manager _metadataProviders = metadataProviders.ToArray(); _externalIds = externalIds.OrderBy(i => i.ProviderName).ToArray(); - _savers = metadataSavers.Where(i => - { - var configurable = i as IConfigurableProvider; - - return configurable == null || configurable.IsEnabled; - }).ToArray(); + _savers = metadataSavers + .Where(i => !(i is IConfigurableProvider configurable) || configurable.IsEnabled) + .ToArray(); } + /// public Task RefreshSingleItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken) { - IMetadataService service = null; var type = item.GetType(); - foreach (var current in _metadataServices) - { - if (current.CanRefreshPrimary(type)) - { - service = current; - break; - } - } + var service = _metadataServices.FirstOrDefault(current => current.CanRefreshPrimary(type)); if (service == null) { @@ -147,35 +149,36 @@ namespace MediaBrowser.Providers.Manager return Task.FromResult(ItemUpdateType.None); } + /// public async Task SaveImage(BaseItem item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken) { - using (var response = await _httpClient.GetResponse(new HttpRequestOptions + using var response = await _httpClient.GetResponse(new HttpRequestOptions { CancellationToken = cancellationToken, Url = url, BufferContent = false + }).ConfigureAwait(false); - }).ConfigureAwait(false)) + // Workaround for tvheadend channel icons + // TODO: Isolate this hack into the tvh plugin + if (string.IsNullOrEmpty(response.ContentType)) { - // Workaround for tvheadend channel icons - // TODO: Isolate this hack into the tvh plugin - if (string.IsNullOrEmpty(response.ContentType)) + if (url.IndexOf("/imagecache/", StringComparison.OrdinalIgnoreCase) != -1) { - if (url.IndexOf("/imagecache/", StringComparison.OrdinalIgnoreCase) != -1) - { - response.ContentType = "image/png"; - } + response.ContentType = "image/png"; } - - await SaveImage(item, response.Content, response.ContentType, type, imageIndex, cancellationToken).ConfigureAwait(false); } + + await SaveImage(item, response.Content, response.ContentType, type, imageIndex, cancellationToken).ConfigureAwait(false); } + /// public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) { return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken); } + /// public Task SaveImage(BaseItem item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(source)) @@ -188,12 +191,14 @@ namespace MediaBrowser.Providers.Manager return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken); } + /// public Task SaveImage(User user, Stream source, string mimeType, string path) { return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger) .SaveImage(user, source, path); } + /// public async Task> GetAvailableRemoteImages(BaseItem item, RemoteImageQuery query, CancellationToken cancellationToken) { var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders); @@ -213,7 +218,7 @@ namespace MediaBrowser.Providers.Manager languages.Add(preferredLanguage); } - var tasks = providers.Select(i => GetImages(item, cancellationToken, i, languages, query.ImageType)); + var tasks = providers.Select(i => GetImages(item, i, languages, cancellationToken, query.ImageType)); var results = await Task.WhenAll(tasks).ConfigureAwait(false); @@ -224,12 +229,17 @@ namespace MediaBrowser.Providers.Manager /// Gets the images. /// /// The item. - /// The cancellation token. /// The provider. /// The preferred languages. + /// The cancellation token. /// The type. /// Task{IEnumerable{RemoteImageInfo}}. - private async Task> GetImages(BaseItem item, CancellationToken cancellationToken, IRemoteImageProvider provider, List preferredLanguages, ImageType? type = null) + private async Task> GetImages( + BaseItem item, + IRemoteImageProvider provider, + IReadOnlyCollection preferredLanguages, + CancellationToken cancellationToken, + ImageType? type = null) { try { @@ -260,11 +270,7 @@ namespace MediaBrowser.Providers.Manager } } - /// - /// Gets the supported image providers. - /// - /// The item. - /// IEnumerable{IImageProvider}. + /// public IEnumerable GetRemoteImageProviderInfo(BaseItem item) { return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo(i.Name, i.GetSupportedImages(item).ToArray())); @@ -283,7 +289,7 @@ namespace MediaBrowser.Providers.Manager var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); var typeFetcherOrder = typeOptions?.ImageFetcherOrder; - return ImageProviders.Where(i => CanRefresh(i, item, libraryOptions, options, refreshOptions, includeDisabled)) + return ImageProviders.Where(i => CanRefresh(i, item, libraryOptions, refreshOptions, includeDisabled)) .OrderBy(i => { // See if there's a user-defined order @@ -319,7 +325,7 @@ namespace MediaBrowser.Providers.Manager var currentOptions = globalMetadataOptions; return _metadataProviders.OfType>() - .Where(i => CanRefresh(i, item, libraryOptions, currentOptions, includeDisabled, forceEnableInternetMetadata)) + .Where(i => CanRefresh(i, item, libraryOptions, includeDisabled, forceEnableInternetMetadata)) .OrderBy(i => GetConfiguredOrder(item, i, libraryOptions, globalMetadataOptions)) .ThenBy(GetDefaultOrder); } @@ -329,14 +335,20 @@ namespace MediaBrowser.Providers.Manager var options = GetMetadataOptions(item); var libraryOptions = _libraryManager.GetLibraryOptions(item); - return GetImageProviders(item, libraryOptions, options, - new ImageRefreshOptions( - new DirectoryService(_fileSystem)), - includeDisabled) - .OfType(); + return GetImageProviders( + item, + libraryOptions, + options, + new ImageRefreshOptions(new DirectoryService(_fileSystem)), + includeDisabled).OfType(); } - private bool CanRefresh(IMetadataProvider provider, BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, bool includeDisabled, bool forceEnableInternetMetadata) + private bool CanRefresh( + IMetadataProvider provider, + BaseItem item, + LibraryOptions libraryOptions, + bool includeDisabled, + bool forceEnableInternetMetadata) { if (!includeDisabled) { @@ -372,7 +384,12 @@ namespace MediaBrowser.Providers.Manager return true; } - private bool CanRefresh(IImageProvider provider, BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled) + private bool CanRefresh( + IImageProvider provider, + BaseItem item, + LibraryOptions libraryOptions, + ImageRefreshOptions refreshOptions, + bool includeDisabled) { if (!includeDisabled) { @@ -412,9 +429,7 @@ namespace MediaBrowser.Providers.Manager /// System.Int32. private int GetOrder(IImageProvider provider) { - var hasOrder = provider as IHasOrder; - - if (hasOrder == null) + if (!(provider is IHasOrder hasOrder)) { return 0; } @@ -441,7 +456,7 @@ namespace MediaBrowser.Providers.Manager if (provider is IRemoteMetadataProvider) { var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); - var typeFetcherOrder = typeOptions == null ? null : typeOptions.MetadataFetcherOrder; + var typeFetcherOrder = typeOptions?.MetadataFetcherOrder; var fetcherOrder = typeFetcherOrder ?? globalMetadataOptions.MetadataFetcherOrder; @@ -459,9 +474,7 @@ namespace MediaBrowser.Providers.Manager private int GetDefaultOrder(IMetadataProvider provider) { - var hasOrder = provider as IHasOrder; - - if (hasOrder != null) + if (provider is IHasOrder hasOrder) { return hasOrder.Order; } @@ -469,9 +482,10 @@ namespace MediaBrowser.Providers.Manager return 0; } + /// public MetadataPluginSummary[] GetAllMetadataPlugins() { - return new MetadataPluginSummary[] + return new[] { GetPluginSummary(), GetPluginSummary(), @@ -493,7 +507,7 @@ namespace MediaBrowser.Providers.Manager where T : BaseItem, new() { // Give it a dummy path just so that it looks like a file system item - var dummy = new T() + var dummy = new T { Path = Path.Combine(_appPaths.InternalMetadataPath, "dummy"), ParentId = Guid.NewGuid() @@ -508,11 +522,12 @@ namespace MediaBrowser.Providers.Manager var libraryOptions = new LibraryOptions(); - var imageProviders = GetImageProviders(dummy, libraryOptions, options, - new ImageRefreshOptions( - new DirectoryService(_fileSystem)), - true) - .ToList(); + var imageProviders = GetImageProviders( + dummy, + libraryOptions, + options, + new ImageRefreshOptions(new DirectoryService(_fileSystem)), + true).ToList(); var pluginList = summary.Plugins.ToList(); @@ -572,7 +587,6 @@ namespace MediaBrowser.Providers.Manager private void AddImagePlugins(List list, T item, List imageProviders) where T : BaseItem { - // Locals list.AddRange(imageProviders.Where(i => (i is ILocalImageProvider)).Select(i => new MetadataPlugin { @@ -588,6 +602,7 @@ namespace MediaBrowser.Providers.Manager })); } + /// public MetadataOptions GetMetadataOptions(BaseItem item) { var type = item.GetType().Name; @@ -597,17 +612,13 @@ namespace MediaBrowser.Providers.Manager new MetadataOptions(); } - /// - /// Saves the metadata. - /// + /// public void SaveMetadata(BaseItem item, ItemUpdateType updateType) { SaveMetadata(item, updateType, _savers); } - /// - /// Saves the metadata. - /// + /// public void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable savers) { SaveMetadata(item, updateType, _savers.Where(i => savers.Contains(i.Name, StringComparer.OrdinalIgnoreCase))); @@ -619,7 +630,6 @@ namespace MediaBrowser.Providers.Manager /// The item. /// Type of the update. /// The savers. - /// Task. private void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable savers) { var libraryOptions = _libraryManager.GetLibraryOptions(item); @@ -628,11 +638,9 @@ namespace MediaBrowser.Providers.Manager { _logger.LogDebug("Saving {0} to {1}.", item.Path ?? item.Name, saver.Name); - var fileSaver = saver as IMetadataFileSaver; - - if (fileSaver != null) + if (saver is IMetadataFileSaver fileSaver) { - string path = null; + string path; try { @@ -699,11 +707,9 @@ namespace MediaBrowser.Providers.Manager { if (updateType >= ItemUpdateType.MetadataEdit) { - var fileSaver = saver as IMetadataFileSaver; - // Manual edit occurred // Even if save local is off, save locally anyway if the metadata file already exists - if (fileSaver == null || !File.Exists(fileSaver.GetSavePath(item))) + if (!(saver is IMetadataFileSaver fileSaver) || !File.Exists(fileSaver.GetSavePath(item))) { return false; } @@ -734,6 +740,7 @@ namespace MediaBrowser.Providers.Manager } } + /// public Task> GetRemoteSearchResults(RemoteSearchQuery searchInfo, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo @@ -748,7 +755,7 @@ namespace MediaBrowser.Providers.Manager return GetRemoteSearchResults(searchInfo, referenceItem, cancellationToken); } - public async Task> GetRemoteSearchResults(RemoteSearchQuery searchInfo, BaseItem referenceItem, CancellationToken cancellationToken) + private async Task> GetRemoteSearchResults(RemoteSearchQuery searchInfo, BaseItem referenceItem, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo { @@ -837,7 +844,9 @@ namespace MediaBrowser.Providers.Manager return resultList; } - private async Task> GetSearchResults(IRemoteSearchProvider provider, TLookupType searchInfo, + private async Task> GetSearchResults( + IRemoteSearchProvider provider, + TLookupType searchInfo, CancellationToken cancellationToken) where TLookupType : ItemLookupInfo { @@ -853,6 +862,7 @@ namespace MediaBrowser.Providers.Manager return list; } + /// public Task GetSearchImage(string providerName, string url, CancellationToken cancellationToken) { var provider = _metadataProviders.OfType().FirstOrDefault(i => string.Equals(i.Name, providerName, StringComparison.OrdinalIgnoreCase)); @@ -865,6 +875,7 @@ namespace MediaBrowser.Providers.Manager return provider.GetImageResponse(url, cancellationToken); } + /// public IEnumerable GetExternalIds(IHasProviderIds item) { return _externalIds.Where(i => @@ -881,6 +892,7 @@ namespace MediaBrowser.Providers.Manager }); } + /// public IEnumerable GetExternalUrls(BaseItem item) { return GetExternalIds(item) @@ -909,6 +921,7 @@ namespace MediaBrowser.Providers.Manager }).Where(i => i != null).Concat(item.GetRelatedUrls()); } + /// public IEnumerable GetExternalIdInfos(IHasProviderIds item) { return GetExternalIds(item) @@ -921,8 +934,7 @@ namespace MediaBrowser.Providers.Manager }); } - private ConcurrentDictionary _activeRefreshes = new ConcurrentDictionary(); - + /// public Dictionary GetRefreshQueue() { lock (_refreshQueueLock) @@ -938,6 +950,7 @@ namespace MediaBrowser.Providers.Manager } } + /// public void OnRefreshStart(BaseItem item) { _logger.LogInformation("OnRefreshStart {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); @@ -945,6 +958,7 @@ namespace MediaBrowser.Providers.Manager RefreshStarted?.Invoke(this, new GenericEventArgs(item)); } + /// public void OnRefreshComplete(BaseItem item) { _logger.LogInformation("OnRefreshComplete {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); @@ -954,6 +968,7 @@ namespace MediaBrowser.Providers.Manager RefreshCompleted?.Invoke(this, new GenericEventArgs(item)); } + /// public double? GetRefreshProgress(Guid id) { if (_activeRefreshes.TryGetValue(id, out double value)) @@ -964,6 +979,7 @@ namespace MediaBrowser.Providers.Manager return null; } + /// public void OnRefreshProgress(BaseItem item, double progress) { var id = item.Id; @@ -983,12 +999,7 @@ namespace MediaBrowser.Providers.Manager RefreshProgress?.Invoke(this, new GenericEventArgs>(new Tuple(item, progress))); } - private readonly SimplePriorityQueue> _refreshQueue = - new SimplePriorityQueue>(); - - private readonly object _refreshQueueLock = new object(); - private bool _isProcessingRefreshQueue; - + /// public void QueueRefresh(Guid id, MetadataRefreshOptions options, RefreshPriority priority) { if (_disposed) @@ -1032,7 +1043,7 @@ namespace MediaBrowser.Providers.Manager if (item != null) { // Try to throttle this a little bit. - await Task.Delay(100).ConfigureAwait(false); + await Task.Delay(100, cancellationToken).ConfigureAwait(false); var task = item is MusicArtist artist ? RefreshArtist(artist, refreshItem.Item2, cancellationToken) @@ -1062,17 +1073,14 @@ namespace MediaBrowser.Providers.Manager await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); // Collection folders don't validate their children so we'll have to simulate that here - - if (item is CollectionFolder collectionFolder) + switch (item) { - await RefreshCollectionFolderChildren(options, collectionFolder, cancellationToken).ConfigureAwait(false); - } - else - { - if (item is Folder folder) - { + case CollectionFolder collectionFolder: + await RefreshCollectionFolderChildren(options, collectionFolder, cancellationToken).ConfigureAwait(false); + break; + case Folder folder: await folder.ValidateChildren(new SimpleProgress(), cancellationToken, options).ConfigureAwait(false); - } + break; } } @@ -1082,7 +1090,7 @@ namespace MediaBrowser.Providers.Manager { await child.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); - await child.ValidateChildren(new SimpleProgress(), cancellationToken, options, true).ConfigureAwait(false); + await child.ValidateChildren(new SimpleProgress(), cancellationToken, options).ConfigureAwait(false); } } @@ -1118,12 +1126,13 @@ namespace MediaBrowser.Providers.Manager } } + /// public Task RefreshFullItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken) { return RefreshItem(item, options, cancellationToken); } - private bool _disposed; + /// public void Dispose() { _disposed = true; From d1e351a00ac47c2caa7e7e1a22e20c65d27cec7f Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 19 Jul 2020 20:21:30 -0600 Subject: [PATCH 64/93] Fix username case change --- Jellyfin.Server.Implementations/Users/UserManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index e3a7d54677..343f452c7d 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -152,12 +152,12 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Invalid username", nameof(newName)); } - if (user.Username.Equals(newName, StringComparison.OrdinalIgnoreCase)) + if (user.Username.Equals(newName, StringComparison.Ordinal)) { throw new ArgumentException("The new and old names must be different."); } - if (Users.Any(u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.OrdinalIgnoreCase))) + if (Users.Any(u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.Ordinal))) { throw new ArgumentException(string.Format( CultureInfo.InvariantCulture, From 6e11f779227ef719f6a4af666ef1ec27bc03410c Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sun, 19 Jul 2020 22:30:25 -0400 Subject: [PATCH 65/93] Add missing documentation. --- MediaBrowser.Providers/Manager/ProviderManager.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 98bcd8d31e..4ee065cd11 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -276,6 +276,12 @@ namespace MediaBrowser.Providers.Manager return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo(i.Name, i.GetSupportedImages(item).ToArray())); } + /// + /// Gets the image providers for the provided item. + /// + /// The item. + /// The image refresh options. + /// The image providers for the item. public IEnumerable GetImageProviders(BaseItem item, ImageRefreshOptions refreshOptions) { return GetImageProviders(item, _libraryManager.GetLibraryOptions(item), GetMetadataOptions(item), refreshOptions, false); @@ -310,6 +316,13 @@ namespace MediaBrowser.Providers.Manager .ThenBy(GetOrder); } + /// + /// Gets the metadata providers for the provided item. + /// + /// The item. + /// The library options. + /// The type of metadata provider. + /// The metadata providers. public IEnumerable> GetMetadataProviders(BaseItem item, LibraryOptions libraryOptions) where T : BaseItem { From 4ecedb2a12e3ebc464472b9f2ff0bfb06c9a4b87 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 19 Jul 2020 23:26:59 -0400 Subject: [PATCH 66/93] Fix bad dependency handling in 10.6.0-1 Fixes the incorrect dependency handling from 10.6.0, which was missing the Replaces and Breaks entries on jellyfin-server. Thus apt would complain about /etc/default/jellyfin being in two packages and fail to upgrade. With this configuration, I've verified that apt now handles this situation properly. --- debian/changelog | 6 ++++++ debian/control | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 35fb659571..d38d038051 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +jellyfin-server (10.6.0-2) unstable; urgency=medium + + * Fix upgrade bug + + -- Joshua Boniface Sun, 19 Jul 22:47:27 -0400 + jellyfin-server (10.6.0-1) unstable; urgency=medium * Forthcoming stable release diff --git a/debian/control b/debian/control index 896d8286b7..013ee13e03 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,6 @@ Section: misc Priority: optional Maintainer: Jellyfin Team Build-Depends: debhelper (>= 9), - dotnet-sdk-3.1, libc6-dev, libcurl4-openssl-dev, libfontconfig1-dev, @@ -15,8 +14,8 @@ Vcs-Git: https://github.org/jellyfin/jellyfin.git Vcs-Browser: https://github.org/jellyfin/jellyfin Package: jellyfin-server -Replaces: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server -Breaks: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server +Replaces: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server, jellyfin (<<10.6.0) +Breaks: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server, jellyfin (<<10.6.0) Conflicts: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server Architecture: any Depends: at, From 4966ca3616c44a0ae486de952725492b51e58e4c Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 19 Jul 2020 23:28:25 -0400 Subject: [PATCH 67/93] Remove the old Emby conflicts It's been long enough that this is no longer an issue. We still conflict on the ports 8096 and 8190, but this will simply result in a failure to start; allow users to get themselves into that situation if they wish. --- debian/control | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 013ee13e03..4515e78bf8 100644 --- a/debian/control +++ b/debian/control @@ -14,9 +14,8 @@ Vcs-Git: https://github.org/jellyfin/jellyfin.git Vcs-Browser: https://github.org/jellyfin/jellyfin Package: jellyfin-server -Replaces: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server, jellyfin (<<10.6.0) -Breaks: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server, jellyfin (<<10.6.0) -Conflicts: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server +Replaces: jellyfin (<<10.6.0) +Breaks: jellyfin (<<10.6.0) Architecture: any Depends: at, libsqlite3-0, From b1fe20aac5b33bb7c984cd84825fc91fd9972eb3 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 19 Jul 2020 23:36:48 -0400 Subject: [PATCH 68/93] Readd sed'd out dotnet-sdk dependency --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 4515e78bf8..39c2aa055b 100644 --- a/debian/control +++ b/debian/control @@ -3,6 +3,7 @@ Section: misc Priority: optional Maintainer: Jellyfin Team Build-Depends: debhelper (>= 9), + dotnet-sdk-3.1, libc6-dev, libcurl4-openssl-dev, libfontconfig1-dev, From 7324b44c4371b2c9543bc834e665daf6e764b554 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 20 Jul 2020 11:01:37 +0200 Subject: [PATCH 69/93] Fix warnings --- .../Library/CoreResolutionIgnoreRule.cs | 2 +- .../Library/ExclusiveLiveStream.cs | 24 +- .../Library/LibraryManager.cs | 214 +++++++++--------- .../Library/LiveStreamHelper.cs | 24 +- .../Library/MediaSourceManager.cs | 17 +- .../Library/MediaStreamSelector.cs | 2 +- .../Library/SearchEngine.cs | 18 +- .../Library/ILibraryManager.cs | 2 +- 8 files changed, 144 insertions(+), 159 deletions(-) diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index 77b2c0a694..3380e29d48 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.Library if (parent != null) { // Don't resolve these into audio files - if (string.Equals(Path.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename) + if (string.Equals(Path.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename, StringComparison.Ordinal) && _libraryManager.IsAudioFile(filename)) { return true; diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs index ab39a7223d..236453e805 100644 --- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs +++ b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs @@ -11,6 +11,17 @@ namespace Emby.Server.Implementations.Library { public class ExclusiveLiveStream : ILiveStream { + private readonly Func _closeFn; + + public ExclusiveLiveStream(MediaSourceInfo mediaSource, Func closeFn) + { + MediaSource = mediaSource; + EnableStreamSharing = false; + _closeFn = closeFn; + ConsumerCount = 1; + UniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); + } + public int ConsumerCount { get; set; } public string OriginalStreamId { get; set; } @@ -21,18 +32,7 @@ namespace Emby.Server.Implementations.Library public MediaSourceInfo MediaSource { get; set; } - public string UniqueId { get; private set; } - - private Func _closeFn; - - public ExclusiveLiveStream(MediaSourceInfo mediaSource, Func closeFn) - { - MediaSource = mediaSource; - EnableStreamSharing = false; - _closeFn = closeFn; - ConsumerCount = 1; - UniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - } + public string UniqueId { get; } public Task Close() { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index c27b73c74e..10e6119e94 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -60,6 +60,8 @@ namespace Emby.Server.Implementations.Library /// public class LibraryManager : ILibraryManager { + private const string ShortcutFileExtension = ".mblink"; + private readonly ILogger _logger; private readonly ITaskManager _taskManager; private readonly IUserManager _userManager; @@ -75,63 +77,24 @@ namespace Emby.Server.Implementations.Library private readonly ConcurrentDictionary _libraryItemsCache; private readonly IImageProcessor _imageProcessor; - private NamingOptions _namingOptions; - private string[] _videoFileExtensions; - - private ILibraryMonitor LibraryMonitor => _libraryMonitorFactory.Value; - - private IProviderManager ProviderManager => _providerManagerFactory.Value; - - private IUserViewManager UserViewManager => _userviewManagerFactory.Value; - - /// - /// Gets or sets the postscan tasks. - /// - /// The postscan tasks. - private ILibraryPostScanTask[] PostscanTasks { get; set; } - - /// - /// Gets or sets the intro providers. - /// - /// The intro providers. - private IIntroProvider[] IntroProviders { get; set; } - - /// - /// Gets or sets the list of entity resolution ignore rules. - /// - /// The entity resolution ignore rules. - private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; } - - /// - /// Gets or sets the list of currently registered entity resolvers. - /// - /// The entity resolvers enumerable. - private IItemResolver[] EntityResolvers { get; set; } - - private IMultiItemResolver[] MultiItemResolvers { get; set; } - /// - /// Gets or sets the comparers. + /// The _root folder sync lock. /// - /// The comparers. - private IBaseItemComparer[] Comparers { get; set; } + private readonly object _rootFolderSyncLock = new object(); + private readonly object _userRootFolderSyncLock = new object(); - /// - /// Occurs when [item added]. - /// - public event EventHandler ItemAdded; + private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24); - /// - /// Occurs when [item updated]. - /// - public event EventHandler ItemUpdated; + private NamingOptions _namingOptions; + private string[] _videoFileExtensions; /// - /// Occurs when [item removed]. + /// The _root folder. /// - public event EventHandler ItemRemoved; + private volatile AggregateFolder _rootFolder; + private volatile UserRootFolder _userRootFolder; - public bool IsScanRunning { get; private set; } + private bool _wizardCompleted; /// /// Initializes a new instance of the class. @@ -186,37 +149,19 @@ namespace Emby.Server.Implementations.Library } /// - /// Adds the parts. + /// Occurs when [item added]. /// - /// The rules. - /// The resolvers. - /// The intro providers. - /// The item comparers. - /// The post scan tasks. - public void AddParts( - IEnumerable rules, - IEnumerable resolvers, - IEnumerable introProviders, - IEnumerable itemComparers, - IEnumerable postscanTasks) - { - EntityResolutionIgnoreRules = rules.ToArray(); - EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray(); - MultiItemResolvers = EntityResolvers.OfType().ToArray(); - IntroProviders = introProviders.ToArray(); - Comparers = itemComparers.ToArray(); - PostscanTasks = postscanTasks.ToArray(); - } + public event EventHandler ItemAdded; /// - /// The _root folder. + /// Occurs when [item updated]. /// - private volatile AggregateFolder _rootFolder; + public event EventHandler ItemUpdated; /// - /// The _root folder sync lock. + /// Occurs when [item removed]. /// - private readonly object _rootFolderSyncLock = new object(); + public event EventHandler ItemRemoved; /// /// Gets the root folder. @@ -241,7 +186,68 @@ namespace Emby.Server.Implementations.Library } } - private bool _wizardCompleted; + private ILibraryMonitor LibraryMonitor => _libraryMonitorFactory.Value; + + private IProviderManager ProviderManager => _providerManagerFactory.Value; + + private IUserViewManager UserViewManager => _userviewManagerFactory.Value; + + /// + /// Gets or sets the postscan tasks. + /// + /// The postscan tasks. + private ILibraryPostScanTask[] PostscanTasks { get; set; } + + /// + /// Gets or sets the intro providers. + /// + /// The intro providers. + private IIntroProvider[] IntroProviders { get; set; } + + /// + /// Gets or sets the list of entity resolution ignore rules. + /// + /// The entity resolution ignore rules. + private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; } + + /// + /// Gets or sets the list of currently registered entity resolvers. + /// + /// The entity resolvers enumerable. + private IItemResolver[] EntityResolvers { get; set; } + + private IMultiItemResolver[] MultiItemResolvers { get; set; } + + /// + /// Gets or sets the comparers. + /// + /// The comparers. + private IBaseItemComparer[] Comparers { get; set; } + + public bool IsScanRunning { get; private set; } + + /// + /// Adds the parts. + /// + /// The rules. + /// The resolvers. + /// The intro providers. + /// The item comparers. + /// The post scan tasks. + public void AddParts( + IEnumerable rules, + IEnumerable resolvers, + IEnumerable introProviders, + IEnumerable itemComparers, + IEnumerable postscanTasks) + { + EntityResolutionIgnoreRules = rules.ToArray(); + EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray(); + MultiItemResolvers = EntityResolvers.OfType().ToArray(); + IntroProviders = introProviders.ToArray(); + Comparers = itemComparers.ToArray(); + PostscanTasks = postscanTasks.ToArray(); + } /// /// Records the configuration values. @@ -512,7 +518,7 @@ namespace Emby.Server.Implementations.Library // Try to normalize paths located underneath program-data in an attempt to make them more portable key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length) .TrimStart(new[] { '/', '\\' }) - .Replace("/", "\\"); + .Replace('/', '\\'); } if (forceCaseInsensitive || !_configurationManager.Configuration.EnableCaseSensitiveItemIds) @@ -775,14 +781,11 @@ namespace Emby.Server.Implementations.Library return rootFolder; } - private volatile UserRootFolder _userRootFolder; - private readonly object _syncLock = new object(); - public Folder GetUserRootFolder() { if (_userRootFolder == null) { - lock (_syncLock) + lock (_userRootFolderSyncLock) { if (_userRootFolder == null) { @@ -1332,7 +1335,7 @@ namespace Emby.Server.Implementations.Library return new QueryResult { - Items = _itemRepository.GetItemList(query).ToArray() + Items = _itemRepository.GetItemList(query) }; } @@ -1463,11 +1466,9 @@ namespace Emby.Server.Implementations.Library return _itemRepository.GetItems(query); } - var list = _itemRepository.GetItemList(query); - return new QueryResult { - Items = list + Items = _itemRepository.GetItemList(query) }; } @@ -1945,12 +1946,9 @@ namespace Emby.Server.Implementations.Library /// /// Updates the item. /// - public void UpdateItems(IEnumerable items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) + public void UpdateItems(IReadOnlyList items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) { - // Don't iterate multiple times - var itemsList = items.ToList(); - - foreach (var item in itemsList) + foreach (var item in items) { if (item.IsFileProtocol) { @@ -1962,11 +1960,11 @@ namespace Emby.Server.Implementations.Library UpdateImages(item, updateReason >= ItemUpdateType.ImageUpdate); } - _itemRepository.SaveItems(itemsList, cancellationToken); + _itemRepository.SaveItems(items, cancellationToken); if (ItemUpdated != null) { - foreach (var item in itemsList) + foreach (var item in items) { // With the live tv guide this just creates too much noise if (item.SourceType != SourceType.Library) @@ -2189,8 +2187,6 @@ namespace Emby.Server.Implementations.Library .FirstOrDefault(i => !string.IsNullOrEmpty(i)); } - private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24); - public UserView GetNamedView( User user, string name, @@ -2488,14 +2484,9 @@ namespace Emby.Server.Implementations.Library var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd; - var episodeInfo = episode.IsFileProtocol ? - resolver.Resolve(episode.Path, isFolder, null, null, isAbsoluteNaming) : - new Naming.TV.EpisodeInfo(); - - if (episodeInfo == null) - { - episodeInfo = new Naming.TV.EpisodeInfo(); - } + var episodeInfo = episode.IsFileProtocol + ? resolver.Resolve(episode.Path, isFolder, null, null, isAbsoluteNaming) ?? new Naming.TV.EpisodeInfo() + : new Naming.TV.EpisodeInfo(); try { @@ -2503,11 +2494,13 @@ namespace Emby.Server.Implementations.Library if (libraryOptions.EnableEmbeddedEpisodeInfos && string.Equals(episodeInfo.Container, "mp4", StringComparison.OrdinalIgnoreCase)) { // Read from metadata - var mediaInfo = _mediaEncoder.GetMediaInfo(new MediaInfoRequest - { - MediaSource = episode.GetMediaSources(false)[0], - MediaType = DlnaProfileType.Video - }, CancellationToken.None).GetAwaiter().GetResult(); + var mediaInfo = _mediaEncoder.GetMediaInfo( + new MediaInfoRequest + { + MediaSource = episode.GetMediaSources(false)[0], + MediaType = DlnaProfileType.Video + }, + CancellationToken.None).GetAwaiter().GetResult(); if (mediaInfo.ParentIndexNumber > 0) { episodeInfo.SeasonNumber = mediaInfo.ParentIndexNumber; @@ -2665,7 +2658,7 @@ namespace Emby.Server.Implementations.Library var videos = videoListResolver.Resolve(fileSystemChildren); - var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files.First().Path, StringComparison.OrdinalIgnoreCase)); + var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files[0].Path, StringComparison.OrdinalIgnoreCase)); if (currentVideo != null) { @@ -2682,9 +2675,7 @@ namespace Emby.Server.Implementations.Library .Select(video => { // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = GetItemById(video.Id) as Trailer; - - if (dbItem != null) + if (GetItemById(video.Id) is Trailer dbItem) { video = dbItem; } @@ -3011,8 +3002,6 @@ namespace Emby.Server.Implementations.Library }); } - private const string ShortcutFileExtension = ".mblink"; - public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo) { AddMediaPathInternal(virtualFolderName, pathInfo, true); @@ -3206,7 +3195,8 @@ namespace Emby.Server.Implementations.Library if (!Directory.Exists(virtualFolderPath)) { - throw new FileNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName)); + throw new FileNotFoundException( + string.Format(CultureInfo.InvariantCulture, "The media collection {0} does not exist", virtualFolderName)); } var shortcut = _fileSystem.GetFilePaths(virtualFolderPath, true) diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs index 9b9f53049c..041619d1e5 100644 --- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs +++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs @@ -23,9 +23,8 @@ namespace Emby.Server.Implementations.Library { private readonly IMediaEncoder _mediaEncoder; private readonly ILogger _logger; - - private IJsonSerializer _json; - private IApplicationPaths _appPaths; + private readonly IJsonSerializer _json; + private readonly IApplicationPaths _appPaths; public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger, IJsonSerializer json, IApplicationPaths appPaths) { @@ -72,13 +71,14 @@ namespace Emby.Server.Implementations.Library mediaSource.AnalyzeDurationMs = 3000; - mediaInfo = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest - { - MediaSource = mediaSource, - MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, - ExtractChapters = false - - }, cancellationToken).ConfigureAwait(false); + mediaInfo = await _mediaEncoder.GetMediaInfo( + new MediaInfoRequest + { + MediaSource = mediaSource, + MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, + ExtractChapters = false + }, + cancellationToken).ConfigureAwait(false); if (cacheFilePath != null) { @@ -126,7 +126,7 @@ namespace Emby.Server.Implementations.Library mediaSource.RunTimeTicks = null; } - var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Audio); + var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); if (audioStream == null || audioStream.Index == -1) { @@ -137,7 +137,7 @@ namespace Emby.Server.Implementations.Library mediaSource.DefaultAudioStreamIndex = audioStream.Index; } - var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Video); + var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); if (videoStream != null) { if (!videoStream.BitRate.HasValue) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index ceb36b389b..4e1316abf2 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -29,6 +29,9 @@ namespace Emby.Server.Implementations.Library { public class MediaSourceManager : IMediaSourceManager, IDisposable { + // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message. + private const char LiveStreamIdDelimeter = '_'; + private readonly IItemRepository _itemRepo; private readonly IUserManager _userManager; private readonly ILibraryManager _libraryManager; @@ -40,6 +43,11 @@ namespace Emby.Server.Implementations.Library private readonly ILocalizationManager _localizationManager; private readonly IApplicationPaths _appPaths; + private readonly Dictionary _openStreams = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); + + private readonly object _disposeLock = new object(); + private IMediaSourceProvider[] _providers; public MediaSourceManager( @@ -368,7 +376,6 @@ namespace Emby.Server.Implementations.Library } } - var preferredSubs = string.IsNullOrEmpty(user.SubtitleLanguagePreference) ? Array.Empty() : NormalizeLanguage(user.SubtitleLanguagePreference); @@ -451,9 +458,6 @@ namespace Emby.Server.Implementations.Library .ToList(); } - private readonly Dictionary _openStreams = new Dictionary(StringComparer.OrdinalIgnoreCase); - private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); - public async Task> OpenLiveStreamInternal(LiveStreamRequest request, CancellationToken cancellationToken) { await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -855,9 +859,6 @@ namespace Emby.Server.Implementations.Library } } - // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message. - private const char LiveStreamIdDelimeter = '_'; - private Tuple GetProvider(string key) { if (string.IsNullOrEmpty(key)) @@ -881,9 +882,9 @@ namespace Emby.Server.Implementations.Library public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } - private readonly object _disposeLock = new object(); /// /// Releases unmanaged and - optionally - managed resources. /// diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index ca904c4ec9..179e0ed986 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -89,7 +89,7 @@ namespace Emby.Server.Implementations.Library } // load forced subs if we have found no suitable full subtitles - stream = stream ?? streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)); + stream ??= streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)); if (stream != null) { diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 3df9cc06f1..d67c9e5426 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -20,13 +20,11 @@ namespace Emby.Server.Implementations.Library { public class SearchEngine : ISearchEngine { - private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; - public SearchEngine(ILogger logger, ILibraryManager libraryManager, IUserManager userManager) + public SearchEngine(ILibraryManager libraryManager, IUserManager userManager) { - _logger = logger; _libraryManager = libraryManager; _userManager = userManager; } @@ -34,11 +32,7 @@ namespace Emby.Server.Implementations.Library public QueryResult GetSearchHints(SearchQuery query) { User user = null; - - if (query.UserId.Equals(Guid.Empty)) - { - } - else + if (query.UserId != Guid.Empty) { user = _userManager.GetUserById(query.UserId); } @@ -48,19 +42,19 @@ namespace Emby.Server.Implementations.Library if (query.StartIndex.HasValue) { - results = results.Skip(query.StartIndex.Value).ToList(); + results = results.GetRange(query.StartIndex.Value, totalRecordCount - query.StartIndex.Value); } if (query.Limit.HasValue) { - results = results.Take(query.Limit.Value).ToList(); + results = results.GetRange(0, query.Limit.Value); } return new QueryResult { TotalRecordCount = totalRecordCount, - Items = results.ToArray() + Items = results }; } @@ -85,7 +79,7 @@ namespace Emby.Server.Implementations.Library if (string.IsNullOrEmpty(searchTerm)) { - throw new ArgumentNullException("SearchTerm can't be empty.", nameof(searchTerm)); + throw new ArgumentException("SearchTerm can't be empty.", nameof(query)); } searchTerm = searchTerm.Trim().RemoveDiacritics(); diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 9d6646857e..bb56c83c23 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -199,7 +199,7 @@ namespace MediaBrowser.Controller.Library /// /// Updates the item. /// - void UpdateItems(IEnumerable items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); + void UpdateItems(IReadOnlyList items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); From e98351b9128670abf12976af735cfb40d40be36d Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 20 Jul 2020 14:14:15 +0200 Subject: [PATCH 70/93] Replace \d with [0-9] in ffmpeg detection and scan code --- Emby.Naming/Common/NamingOptions.cs | 60 +++++++++---------- .../Encoder/EncoderValidator.cs | 4 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 1b343790e8..d1e17f4169 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -136,8 +136,8 @@ namespace Emby.Naming.Common CleanDateTimes = new[] { - @"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19\d{2}|20\d{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19\d{2}|20\d{2})*", - @"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19\d{2}|20\d{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19\d{2}|20\d{2})*" + @"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19[0-9]{2}|20[0-9]{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19[0-9]{2}|20[0-9]{2})*", + @"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9]{2}|20[0-9]{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19[0-9]{2}|20[0-9]{2})*" }; CleanStrings = new[] @@ -277,7 +277,7 @@ namespace Emby.Naming.Common // This isn't a Kodi naming rule, but the expression below causes false positives, // so we make sure this one gets tested first. // "Foo Bar 889" - new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?[\w\s]+?)\s(?\d{1,3})(-(?\d{2,3}))*[^\\\/x]*$") + new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?[\w\s]+?)\s(?[0-9]{1,3})(-(?[0-9]{2,3}))*[^\\\/x]*$") { IsNamed = true }, @@ -300,32 +300,32 @@ namespace Emby.Naming.Common // *** End Kodi Standard Naming // [bar] Foo - 1 [baz] - new EpisodeExpression(@".*?(\[.*?\])+.*?(?[\w\s]+?)[-\s_]+(?\d+).*$") + new EpisodeExpression(@".*?(\[.*?\])+.*?(?[\w\s]+?)[-\s_]+(?[0-9]+).*$") { IsNamed = true }, - new EpisodeExpression(@".*(\\|\/)[sS]?(?\d+)[xX](?\d+)[^\\\/]*$") + new EpisodeExpression(@".*(\\|\/)[sS]?(?[0-9]+)[xX](?[0-9]+)[^\\\/]*$") { IsNamed = true }, - new EpisodeExpression(@".*(\\|\/)[sS](?\d+)[x,X]?[eE](?\d+)[^\\\/]*$") + new EpisodeExpression(@".*(\\|\/)[sS](?[0-9]+)[x,X]?[eE](?[0-9]+)[^\\\/]*$") { IsNamed = true }, - new EpisodeExpression(@".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d+))[^\\\/]*$") + new EpisodeExpression(@".*(\\|\/)(?((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?[0-9]{1,4})[xX](?[0-9]+))[^\\\/]*$") { IsNamed = true }, - new EpisodeExpression(@".*(\\|\/)(?[^\\\/]*)[sS](?\d{1,4})[xX\.]?[eE](?\d+)[^\\\/]*$") + new EpisodeExpression(@".*(\\|\/)(?[^\\\/]*)[sS](?[0-9]{1,4})[xX\.]?[eE](?[0-9]+)[^\\\/]*$") { IsNamed = true }, // "01.avi" - new EpisodeExpression(@".*[\\\/](?\d+)(-(?\d+))*\.\w+$") + new EpisodeExpression(@".*[\\\/](?[0-9]+)(-(?[0-9]+))*\.\w+$") { IsOptimistic = true, IsNamed = true @@ -335,34 +335,34 @@ namespace Emby.Naming.Common new EpisodeExpression(@"([0-9]+)-([0-9]+)"), // "01 - blah.avi", "01-blah.avi" - new EpisodeExpression(@".*(\\|\/)(?\d{1,3})(-(?\d{2,3}))*\s?-\s?[^\\\/]*$") + new EpisodeExpression(@".*(\\|\/)(?[0-9]{1,3})(-(?[0-9]{2,3}))*\s?-\s?[^\\\/]*$") { IsOptimistic = true, IsNamed = true }, // "01.blah.avi" - new EpisodeExpression(@".*(\\|\/)(?\d{1,3})(-(?\d{2,3}))*\.[^\\\/]+$") + new EpisodeExpression(@".*(\\|\/)(?[0-9]{1,3})(-(?[0-9]{2,3}))*\.[^\\\/]+$") { IsOptimistic = true, IsNamed = true }, // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi", "blah 2 - 01 - blah" - new EpisodeExpression(@".*[\\\/][^\\\/]* - (?\d{1,3})(-(?\d{2,3}))*[^\\\/]*$") + new EpisodeExpression(@".*[\\\/][^\\\/]* - (?[0-9]{1,3})(-(?[0-9]{2,3}))*[^\\\/]*$") { IsOptimistic = true, IsNamed = true }, // "01 episode title.avi" - new EpisodeExpression(@"[Ss]eason[\._ ](?[0-9]+)[\\\/](?\d{1,3})([^\\\/]*)$") + new EpisodeExpression(@"[Ss]eason[\._ ](?[0-9]+)[\\\/](?[0-9]{1,3})([^\\\/]*)$") { IsOptimistic = true, IsNamed = true }, // "Episode 16", "Episode 16 - Title" - new EpisodeExpression(@".*[\\\/][^\\\/]* (?\d{1,3})(-(?\d{2,3}))*[^\\\/]*$") + new EpisodeExpression(@".*[\\\/][^\\\/]* (?[0-9]{1,3})(-(?[0-9]{2,3}))*[^\\\/]*$") { IsOptimistic = true, IsNamed = true @@ -625,17 +625,17 @@ namespace Emby.Naming.Common AudioBookPartsExpressions = new[] { // Detect specified chapters, like CH 01 - @"ch(?:apter)?[\s_-]?(?\d+)", + @"ch(?:apter)?[\s_-]?(?[0-9]+)", // Detect specified parts, like Part 02 - @"p(?:ar)?t[\s_-]?(?\d+)", + @"p(?:ar)?t[\s_-]?(?[0-9]+)", // Chapter is often beginning of filename - @"^(?\d+)", + "^(?[0-9]+)", // Part if often ending of filename - @"(?\d+)$", + "(?[0-9]+)$", // Sometimes named as 0001_005 (chapter_part) - @"(?\d+)_(?\d+)", + "(?[0-9]+)_(?[0-9]+)", // Some audiobooks are ripped from cd's, and will be named by disk number. - @"dis(?:c|k)[\s_-]?(?\d+)" + @"dis(?:c|k)[\s_-]?(?[0-9]+)" }; var extensions = VideoFileExtensions.ToList(); @@ -675,16 +675,16 @@ namespace Emby.Naming.Common MultipleEpisodeExpressions = new string[] { - @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})((-| - )\d{1,4}[eExX](?\d{1,3}))+[^\\\/]*$", - @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})((-| - )\d{1,4}[xX][eE](?\d{1,3}))+[^\\\/]*$", - @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})((-| - )?[xXeE](?\d{1,3}))+[^\\\/]*$", - @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})(-[xE]?[eE]?(?\d{1,3}))+[^\\\/]*$", - @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))((-| - )\d{1,4}[xXeE](?\d{1,3}))+[^\\\/]*$", - @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))((-| - )\d{1,4}[xX][eE](?\d{1,3}))+[^\\\/]*$", - @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))((-| - )?[xXeE](?\d{1,3}))+[^\\\/]*$", - @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))(-[xX]?[eE]?(?\d{1,3}))+[^\\\/]*$", - @".*(\\|\/)(?[^\\\/]*)[sS](?\d{1,4})[xX\.]?[eE](?\d{1,3})((-| - )?[xXeE](?\d{1,3}))+[^\\\/]*$", - @".*(\\|\/)(?[^\\\/]*)[sS](?\d{1,4})[xX\.]?[eE](?\d{1,3})(-[xX]?[eE]?(?\d{1,3}))+[^\\\/]*$" + @".*(\\|\/)[sS]?(?[0-9]{1,4})[xX](?[0-9]{1,3})((-| - )[0-9]{1,4}[eExX](?[0-9]{1,3}))+[^\\\/]*$", + @".*(\\|\/)[sS]?(?[0-9]{1,4})[xX](?[0-9]{1,3})((-| - )[0-9]{1,4}[xX][eE](?[0-9]{1,3}))+[^\\\/]*$", + @".*(\\|\/)[sS]?(?[0-9]{1,4})[xX](?[0-9]{1,3})((-| - )?[xXeE](?[0-9]{1,3}))+[^\\\/]*$", + @".*(\\|\/)[sS]?(?[0-9]{1,4})[xX](?[0-9]{1,3})(-[xE]?[eE]?(?[0-9]{1,3}))+[^\\\/]*$", + @".*(\\|\/)(?((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?[0-9]{1,4})[xX](?[0-9]{1,3}))((-| - )[0-9]{1,4}[xXeE](?[0-9]{1,3}))+[^\\\/]*$", + @".*(\\|\/)(?((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?[0-9]{1,4})[xX](?[0-9]{1,3}))((-| - )[0-9]{1,4}[xX][eE](?[0-9]{1,3}))+[^\\\/]*$", + @".*(\\|\/)(?((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?[0-9]{1,4})[xX](?[0-9]{1,3}))((-| - )?[xXeE](?[0-9]{1,3}))+[^\\\/]*$", + @".*(\\|\/)(?((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?[0-9]{1,4})[xX](?[0-9]{1,3}))(-[xX]?[eE]?(?[0-9]{1,3}))+[^\\\/]*$", + @".*(\\|\/)(?[^\\\/]*)[sS](?[0-9]{1,4})[xX\.]?[eE](?[0-9]{1,3})((-| - )?[xXeE](?[0-9]{1,3}))+[^\\\/]*$", + @".*(\\|\/)(?[^\\\/]*)[sS](?[0-9]{1,4})[xX\.]?[eE](?[0-9]{1,3})(-[xX]?[eE]?(?[0-9]{1,3}))+[^\\\/]*$" }.Select(i => new EpisodeExpression(i) { IsNamed = true diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 0fd0239b4a..5c43fdcfa9 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -198,7 +198,7 @@ namespace MediaBrowser.MediaEncoding.Encoder internal static Version GetFFmpegVersion(string output) { // For pre-built binaries the FFmpeg version should be mentioned at the very start of the output - var match = Regex.Match(output, @"^ffmpeg version n?((?:\d+\.?)+)"); + var match = Regex.Match(output, @"^ffmpeg version n?((?:[0-9]+\.?)+)"); if (match.Success) { @@ -225,7 +225,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var rc = new StringBuilder(144); foreach (Match m in Regex.Matches( output, - @"((?lib\w+)\s+(?\d+)\.\s*(?\d+))", + @"((?lib\w+)\s+(?[0-9]+)\.\s*(?[0-9]+))", RegexOptions.Multiline)) { rc.Append(m.Groups["name"]) From 5f89e813062323c168adddb3fe143c470859e04c Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Mon, 20 Jul 2020 20:48:20 +0800 Subject: [PATCH 71/93] fix qsv device creation on Comet Lake reddit: https://www.reddit.com/r/jellyfin/comments/huct4x/jellyfin_1060_released/fyn30ds --- .../MediaEncoding/EncodingHelper.cs | 82 ++++++++++++------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ffbda42c31..81ad3769a3 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -495,13 +495,13 @@ namespace MediaBrowser.Controller.MediaEncoding } else { - arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + arg.Append("-hwaccel qsv "); } } if (isWindows) { - arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + arg.Append("-hwaccel qsv "); } } // While using SW decoder @@ -1606,25 +1606,41 @@ namespace MediaBrowser.Controller.MediaEncoding } else { - index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("hwupload=extra_hw_frames", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } else { - index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } else { - index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } + else + { + index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); + if (index != -1) + { + outputSizeParam = outputSizeParam.Substring(index); + } + else + { + index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase); + if (index != -1) + { + outputSizeParam = outputSizeParam.Substring(index); + } + } + } } } } @@ -1790,6 +1806,10 @@ namespace MediaBrowser.Controller.MediaEncoding var outputWidth = width.Value; var outputHeight = height.Value; var qsv_or_vaapi = string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase); + var isDeintEnabled = state.DeInterlace("h264", true) + || state.DeInterlace("avc", true) + || state.DeInterlace("h265", true) + || state.DeInterlace("hevc", true); if (!videoWidth.HasValue || outputWidth != videoWidth.Value @@ -1805,7 +1825,7 @@ namespace MediaBrowser.Controller.MediaEncoding qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi", outputWidth, outputHeight, - (qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty)); + (qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty)); } else { @@ -1814,7 +1834,7 @@ namespace MediaBrowser.Controller.MediaEncoding CultureInfo.InvariantCulture, "{0}=format=nv12{1}", qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi", - (qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty)); + (qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty)); } } else if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 @@ -2026,7 +2046,6 @@ namespace MediaBrowser.Controller.MediaEncoding // http://sonnati.wordpress.com/2012/10/19/ffmpeg-the-swiss-army-knife-of-internet-streaming-part-vi/ var request = state.BaseRequest; - var videoStream = state.VideoStream; var filters = new List(); @@ -2035,23 +2054,31 @@ namespace MediaBrowser.Controller.MediaEncoding var inputHeight = videoStream?.Height; var threeDFormat = state.MediaSource.Video3DFormat; + var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; + var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1; + var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1; + var isNvdecH264Decoder = videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) != -1; + var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1; + var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + + var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + // When the input may or may not be hardware VAAPI decodable - if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + if (isVaapiH264Encoder) { filters.Add("format=nv12|vaapi"); filters.Add("hwupload"); } - // When the input may or may not be hardware QSV decodable - else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + // When burning in graphical subtitles using overlay_qsv, upload videostream to the same qsv context + else if (isLinux && hasGraphicalSubs && isQsvH264Encoder) { - filters.Add("format=nv12|qsv"); filters.Add("hwupload=extra_hw_frames=64"); } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first - else if (IsVaapiSupported(state) && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 - && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) + else if (IsVaapiSupported(state) && isVaapiDecoder && isLibX264Encoder) { var codec = videoStream.Codec.ToLowerInvariant(); var isColorDepth10 = IsColorDepth10(state); @@ -2079,16 +2106,19 @@ namespace MediaBrowser.Controller.MediaEncoding } // Add hardware deinterlace filter before scaling filter - if (state.DeInterlace("h264", true)) + if (state.DeInterlace("h264", true) || state.DeInterlace("avc", true)) { - if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + if (isVaapiH264Encoder) { filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi")); } } // Add software deinterlace filter before scaling filter - if (state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) + if (state.DeInterlace("h264", true) + || state.DeInterlace("avc", true) + || state.DeInterlace("h265", true) + || state.DeInterlace("hevc", true)) { var deintParam = string.Empty; var inputFramerate = videoStream?.RealFrameRate; @@ -2105,9 +2135,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(deintParam)) { - if (!string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) - && !string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) - && videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) == -1) + if (!isVaapiH264Encoder && !isQsvH264Encoder && !isNvdecH264Decoder) { filters.Add(deintParam); } @@ -2117,12 +2145,10 @@ namespace MediaBrowser.Controller.MediaEncoding // Add scaling filter: scale_*=format=nv12 or scale_*=w=*:h=*:format=nv12 or scale=expr filters.AddRange(GetScalingFilters(state, inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight)); - // Add parameters to use VAAPI with burn-in text subttiles (GH issue #642) - if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + // Add parameters to use VAAPI with burn-in text subtitles (GH issue #642) + if (isVaapiH264Encoder) { - if (state.SubtitleStream != null - && state.SubtitleStream.IsTextSubtitleStream - && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) + if (hasTextSubs) { // Test passed on Intel and AMD gfx filters.Add("hwmap=mode=read+write"); @@ -2132,9 +2158,7 @@ namespace MediaBrowser.Controller.MediaEncoding var output = string.Empty; - if (state.SubtitleStream != null - && state.SubtitleStream.IsTextSubtitleStream - && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) + if (hasTextSubs) { var subParam = GetTextSubtitleParam(state); @@ -2142,7 +2166,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Ensure proper filters are passed to ffmpeg in case of hardware acceleration via VA-API // Reference: https://trac.ffmpeg.org/wiki/Hardware/VAAPI - if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + if (isVaapiH264Encoder) { filters.Add("hwmap"); } From 9343e73b26d51ecbf65f809607ef49b1cdb646da Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 20 Jul 2020 07:45:24 -0600 Subject: [PATCH 72/93] Allow migration to optionally run on fresh install --- Jellyfin.Server/Migrations/IMigrationRoutine.cs | 5 +++++ Jellyfin.Server/Migrations/MigrationRunner.cs | 3 +-- .../Migrations/Routines/AddDefaultPluginRepository.cs | 3 +++ .../Migrations/Routines/CreateUserLoggingConfigFile.cs | 3 +++ .../Migrations/Routines/DisableTranscodingThrottling.cs | 3 +++ Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs | 3 +++ Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs | 3 +++ Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs | 3 +++ 8 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Jellyfin.Server/Migrations/IMigrationRoutine.cs b/Jellyfin.Server/Migrations/IMigrationRoutine.cs index 6b5780a262..c1000eeded 100644 --- a/Jellyfin.Server/Migrations/IMigrationRoutine.cs +++ b/Jellyfin.Server/Migrations/IMigrationRoutine.cs @@ -17,6 +17,11 @@ namespace Jellyfin.Server.Migrations /// public string Name { get; } + /// + /// Gets a value indicating whether to perform migration on a new install. + /// + public bool PerformOnNewInstall { get; } + /// /// Execute the migration routine. /// diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs index d633c554de..fe8910c3ca 100644 --- a/Jellyfin.Server/Migrations/MigrationRunner.cs +++ b/Jellyfin.Server/Migrations/MigrationRunner.cs @@ -43,9 +43,8 @@ namespace Jellyfin.Server.Migrations // If startup wizard is not finished, this is a fresh install. // Don't run any migrations, just mark all of them as applied. logger.LogInformation("Marking all known migrations as applied because this is a fresh install"); - migrationOptions.Applied.AddRange(migrations.Select(m => (m.Id, m.Name))); + migrationOptions.Applied.AddRange(migrations.Where(m => !m.PerformOnNewInstall).Select(m => (m.Id, m.Name))); host.ServerConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions); - return; } var appliedMigrationIds = migrationOptions.Applied.Select(m => m.Id).ToHashSet(); diff --git a/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs index a9d5ad16a1..f6d8c9cc0d 100644 --- a/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs +++ b/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs @@ -32,6 +32,9 @@ namespace Jellyfin.Server.Migrations.Routines /// public string Name => "AddDefaultPluginRepository"; + /// + public bool PerformOnNewInstall => true; + /// public void Perform() { diff --git a/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs b/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs index b15e092906..6821630db7 100644 --- a/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs +++ b/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs @@ -48,6 +48,9 @@ namespace Jellyfin.Server.Migrations.Routines /// public string Name => "CreateLoggingConfigHeirarchy"; + /// + public bool PerformOnNewInstall => false; + /// public void Perform() { diff --git a/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs b/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs index c18aa16293..0925a87b55 100644 --- a/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs +++ b/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs @@ -25,6 +25,9 @@ namespace Jellyfin.Server.Migrations.Routines /// public string Name => "DisableTranscodingThrottling"; + /// + public bool PerformOnNewInstall => false; + /// public void Perform() { diff --git a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs index fb3466e13e..6048160c63 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs @@ -41,6 +41,9 @@ namespace Jellyfin.Server.Migrations.Routines /// public string Name => "MigrateActivityLogDatabase"; + /// + public bool PerformOnNewInstall => false; + /// public void Perform() { diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index 2be10c7087..274e6ab736 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -54,6 +54,9 @@ namespace Jellyfin.Server.Migrations.Routines /// public string Name => "MigrateUserDatabase"; + /// + public bool PerformOnNewInstall => false; + /// public void Perform() { diff --git a/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs b/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs index 2ebef02414..6c26e47e15 100644 --- a/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs +++ b/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs @@ -29,6 +29,9 @@ namespace Jellyfin.Server.Migrations.Routines /// public string Name => "RemoveDuplicateExtras"; + /// + public bool PerformOnNewInstall => false; + /// public void Perform() { From bde1a38a88150b79e624fa20c6658cc783226135 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Mon, 20 Jul 2020 16:59:04 +0100 Subject: [PATCH 73/93] Two fixes --- .../Networking/NetworkManager.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs index 6aa1dfbc9b..54d0e29eda 100644 --- a/Emby.Server.Implementations/Networking/NetworkManager.cs +++ b/Emby.Server.Implementations/Networking/NetworkManager.cs @@ -152,6 +152,11 @@ namespace Emby.Server.Implementations.Networking return true; } + if (!IPAddress.TryParse(endpoint, out _)) + { + return false; + } + byte[] octet = IPAddress.Parse(endpoint).GetAddressBytes(); if ((octet[0] == 10) || @@ -268,6 +273,12 @@ namespace Emby.Server.Implementations.Networking string excludeAddress = "[" + addressString + "]"; var subnets = LocalSubnetsFn(); + // Include any address if LAN subnets aren't specified + if (subnets.Length == 0) + { + return true; + } + // Exclude any addresses if they appear in the LAN list in [ ] if (Array.IndexOf(subnets, excludeAddress) != -1) { From f983ea95d12f8924da4b5b0fdcc499e80d939da9 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Mon, 20 Jul 2020 17:18:50 +0100 Subject: [PATCH 74/93] Update Emby.Server.Implementations/Networking/NetworkManager.cs Co-authored-by: Cody Robibero --- Emby.Server.Implementations/Networking/NetworkManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs index 54d0e29eda..50cb44b284 100644 --- a/Emby.Server.Implementations/Networking/NetworkManager.cs +++ b/Emby.Server.Implementations/Networking/NetworkManager.cs @@ -152,12 +152,12 @@ namespace Emby.Server.Implementations.Networking return true; } - if (!IPAddress.TryParse(endpoint, out _)) + if (!IPAddress.TryParse(endpoint, out var ipAddress)) { return false; } - byte[] octet = IPAddress.Parse(endpoint).GetAddressBytes(); + byte[] octet = ipAddress.GetAddressBytes(); if ((octet[0] == 10) || (octet[0] == 172 && (octet[1] >= 16 && octet[1] <= 31)) || // RFC1918 From f4cafc2f31c777ef1a690790991d46fd37c608ac Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 20 Jul 2020 17:23:36 -0600 Subject: [PATCH 75/93] fix built in plugin js --- .../Plugins/AudioDb/Configuration/config.html | 8 ++++---- .../MusicBrainz/Configuration/config.html | 17 ++++++++--------- .../Plugins/Omdb/Configuration/config.html | 4 ++-- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/AudioDb/Configuration/config.html b/MediaBrowser.Providers/Plugins/AudioDb/Configuration/config.html index fbf413f2b5..6b750468a4 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/Configuration/config.html +++ b/MediaBrowser.Providers/Plugins/AudioDb/Configuration/config.html @@ -31,8 +31,8 @@ $('.configPage').on('pageshow', function () { Dashboard.showLoadingMsg(); ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { - $('#enable').checked = config.Enable; - $('#replaceAlbumName').checked = config.ReplaceAlbumName; + document.querySelector('#enable').checked = config.Enable; + document.querySelector('#replaceAlbumName').checked = config.ReplaceAlbumName; Dashboard.hideLoadingMsg(); }); @@ -43,8 +43,8 @@ var form = this; ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { - config.Enable = $('#enable', form).checked; - config.ReplaceAlbumName = $('#replaceAlbumName', form).checked; + config.Enable = document.querySelector('#enable').checked; + config.ReplaceAlbumName = document.querySelector('#replaceAlbumName').checked; ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult); }); diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html b/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html index 90196b046b..a962d18f72 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html @@ -39,10 +39,10 @@ $('.musicBrainzConfigPage').on('pageshow', function () { Dashboard.showLoadingMsg(); ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) { - $('#server').val(config.Server).change(); - $('#rateLimit').val(config.RateLimit).change(); - $('#enable').checked = config.Enable; - $('#replaceArtistName').checked = config.ReplaceArtistName; + document.querySelector('#server').value = config.Server; + document.querySelector('#rateLimit').value = config.RateLimit; + document.querySelector('#enable').checked = config.Enable; + document.querySelector('#replaceArtistName').checked = config.ReplaceArtistName; Dashboard.hideLoadingMsg(); }); @@ -51,12 +51,11 @@ $('.musicBrainzConfigForm').on('submit', function (e) { Dashboard.showLoadingMsg(); - var form = this; ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) { - config.Server = $('#server', form).val(); - config.RateLimit = $('#rateLimit', form).val(); - config.Enable = $('#enable', form).checked; - config.ReplaceArtistName = $('#replaceArtistName', form).checked; + config.Server = document.querySelector('#server').value; + config.RateLimit = document.querySelector('#rateLimit').value; + config.Enable = document.querySelector('#enable').checked; + config.ReplaceArtistName = document.querySelector('#replaceArtistName').checked; ApiClient.updatePluginConfiguration(MusicBrainzPluginConfig.uniquePluginId, config).then(Dashboard.processPluginConfigurationUpdateResult); }); diff --git a/MediaBrowser.Providers/Plugins/Omdb/Configuration/config.html b/MediaBrowser.Providers/Plugins/Omdb/Configuration/config.html index 8b117ec8d2..4d4a82034d 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/Configuration/config.html +++ b/MediaBrowser.Providers/Plugins/Omdb/Configuration/config.html @@ -27,7 +27,7 @@ $('.configPage').on('pageshow', function () { Dashboard.showLoadingMsg(); ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { - $('#castAndCrew').checked = config.CastAndCrew; + document.querySelector('#castAndCrew').checked = config.CastAndCrew; Dashboard.hideLoadingMsg(); }); }); @@ -37,7 +37,7 @@ var form = this; ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { - config.CastAndCrew = $('#castAndCrew', form).checked; + config.CastAndCrew = document.querySelector('#castAndCrew', form).checked; ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult); }); From 05f743480df6f61bfd3ced33a70827dab8528a4f Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 20 Jul 2020 17:31:20 -0600 Subject: [PATCH 76/93] fully remove jquery --- .../Plugins/AudioDb/Configuration/config.html | 42 ++++++++-------- .../MusicBrainz/Configuration/config.html | 49 ++++++++++--------- .../Plugins/Omdb/Configuration/config.html | 35 +++++++------ 3 files changed, 67 insertions(+), 59 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/AudioDb/Configuration/config.html b/MediaBrowser.Providers/Plugins/AudioDb/Configuration/config.html index 6b750468a4..82f26a8f26 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/Configuration/config.html +++ b/MediaBrowser.Providers/Plugins/AudioDb/Configuration/config.html @@ -28,29 +28,31 @@ pluginId: "a629c0da-fac5-4c7e-931a-7174223f14c8" }; - $('.configPage').on('pageshow', function () { - Dashboard.showLoadingMsg(); - ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { - document.querySelector('#enable').checked = config.Enable; - document.querySelector('#replaceAlbumName').checked = config.ReplaceAlbumName; - - Dashboard.hideLoadingMsg(); + document.querySelector('.configPage') + .addEventListener('pageshow', function () { + Dashboard.showLoadingMsg(); + ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { + document.querySelector('#enable').checked = config.Enable; + document.querySelector('#replaceAlbumName').checked = config.ReplaceAlbumName; + + Dashboard.hideLoadingMsg(); + }); }); - }); - - $('.configForm').on('submit', function (e) { - Dashboard.showLoadingMsg(); - var form = this; - ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { - config.Enable = document.querySelector('#enable').checked; - config.ReplaceAlbumName = document.querySelector('#replaceAlbumName').checked; - - ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult); + document.querySelector('.configForm') + .addEventListener('submit', function (e) { + Dashboard.showLoadingMsg(); + + ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { + config.Enable = document.querySelector('#enable').checked; + config.ReplaceAlbumName = document.querySelector('#replaceAlbumName').checked; + + ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult); + }); + + e.preventDefault(); + return false; }); - - return false; - }); diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html b/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html index a962d18f72..c91ba009ba 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html @@ -36,32 +36,35 @@ uniquePluginId: "8c95c4d2-e50c-4fb0-a4f3-6c06ff0f9a1a" }; - $('.musicBrainzConfigPage').on('pageshow', function () { - Dashboard.showLoadingMsg(); - ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) { - document.querySelector('#server').value = config.Server; - document.querySelector('#rateLimit').value = config.RateLimit; - document.querySelector('#enable').checked = config.Enable; - document.querySelector('#replaceArtistName').checked = config.ReplaceArtistName; + document.querySelector('.musicBrainzConfigPage') + .addEventListener('pageshow', function () { + Dashboard.showLoadingMsg(); + ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) { + document.querySelector('#server').value = config.Server; + document.querySelector('#rateLimit').value = config.RateLimit; + document.querySelector('#enable').checked = config.Enable; + document.querySelector('#replaceArtistName').checked = config.ReplaceArtistName; - Dashboard.hideLoadingMsg(); + Dashboard.hideLoadingMsg(); + }); }); - }); - - $('.musicBrainzConfigForm').on('submit', function (e) { - Dashboard.showLoadingMsg(); - - ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) { - config.Server = document.querySelector('#server').value; - config.RateLimit = document.querySelector('#rateLimit').value; - config.Enable = document.querySelector('#enable').checked; - config.ReplaceArtistName = document.querySelector('#replaceArtistName').checked; - - ApiClient.updatePluginConfiguration(MusicBrainzPluginConfig.uniquePluginId, config).then(Dashboard.processPluginConfigurationUpdateResult); + + document.querySelector('.musicBrainzConfigForm') + .addEventListener('submit', function (e) { + Dashboard.showLoadingMsg(); + + ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) { + config.Server = document.querySelector('#server').value; + config.RateLimit = document.querySelector('#rateLimit').value; + config.Enable = document.querySelector('#enable').checked; + config.ReplaceArtistName = document.querySelector('#replaceArtistName').checked; + + ApiClient.updatePluginConfiguration(MusicBrainzPluginConfig.uniquePluginId, config).then(Dashboard.processPluginConfigurationUpdateResult); + }); + + e.preventDefault(); + return false; }); - - return false; - }); diff --git a/MediaBrowser.Providers/Plugins/Omdb/Configuration/config.html b/MediaBrowser.Providers/Plugins/Omdb/Configuration/config.html index 4d4a82034d..f4375b3cb5 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/Configuration/config.html +++ b/MediaBrowser.Providers/Plugins/Omdb/Configuration/config.html @@ -24,25 +24,28 @@ pluginId: "a628c0da-fac5-4c7e-9d1a-7134223f14c8" }; - $('.configPage').on('pageshow', function () { - Dashboard.showLoadingMsg(); - ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { - document.querySelector('#castAndCrew').checked = config.CastAndCrew; - Dashboard.hideLoadingMsg(); + document.querySelector('.configPage') + .addEventListener('pageshow', function () { + Dashboard.showLoadingMsg(); + ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { + document.querySelector('#castAndCrew').checked = config.CastAndCrew; + Dashboard.hideLoadingMsg(); + }); }); - }); - $('.configForm').on('submit', function (e) { - Dashboard.showLoadingMsg(); - - var form = this; - ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { - config.CastAndCrew = document.querySelector('#castAndCrew', form).checked; - ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult); + + document.querySelector('.configForm') + .addEventListener('submit', function (e) { + Dashboard.showLoadingMsg(); + + ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) { + config.CastAndCrew = document.querySelector('#castAndCrew').checked; + ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult); + }); + + e.preventDefault(); + return false; }); - - return false; - }); From d4c6415f9908715f8cd6f90fd754d300d007c06f Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Tue, 21 Jul 2020 11:41:28 +0800 Subject: [PATCH 77/93] minor changes --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 81ad3769a3..04d03080bf 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -460,7 +460,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (!IsCopyCodec(outputVideoCodec)) { if (state.IsVideoRequest - && IsVaapiSupported(state) + && _mediaEncoder.SupportsHwaccel("vaapi") && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { if (isVaapiDecoder) @@ -1701,7 +1701,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first - else if (IsVaapiSupported(state) && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 + else if (_mediaEncoder.SupportsHwaccel("vaapi") && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { /* From 6c076b216289bf7f679895b13bd690e9921655f1 Mon Sep 17 00:00:00 2001 From: crobibero Date: Tue, 21 Jul 2020 08:27:12 -0600 Subject: [PATCH 78/93] Try adding plugin repository again --- Jellyfin.Server/Migrations/MigrationRunner.cs | 3 +- .../Routines/ReaddDefaultPluginRepository.cs | 49 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs index fe8910c3ca..98a90500cb 100644 --- a/Jellyfin.Server/Migrations/MigrationRunner.cs +++ b/Jellyfin.Server/Migrations/MigrationRunner.cs @@ -21,7 +21,8 @@ namespace Jellyfin.Server.Migrations typeof(Routines.MigrateActivityLogDb), typeof(Routines.RemoveDuplicateExtras), typeof(Routines.AddDefaultPluginRepository), - typeof(Routines.MigrateUserDb) + typeof(Routines.MigrateUserDb), + typeof(Routines.ReaddDefaultPluginRepository) }; /// diff --git a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs new file mode 100644 index 0000000000..b281b5cc09 --- /dev/null +++ b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs @@ -0,0 +1,49 @@ +using System; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Model.Updates; + +namespace Jellyfin.Server.Migrations.Routines +{ + /// + /// Migration to initialize system configuration with the default plugin repository. + /// + public class ReaddDefaultPluginRepository : IMigrationRoutine + { + private readonly IServerConfigurationManager _serverConfigurationManager; + + private readonly RepositoryInfo _defaultRepositoryInfo = new RepositoryInfo + { + Name = "Jellyfin Stable", + Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json" + }; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + public ReaddDefaultPluginRepository(IServerConfigurationManager serverConfigurationManager) + { + _serverConfigurationManager = serverConfigurationManager; + } + + /// + public Guid Id => Guid.Parse("5F86E7F6-D966-4C77-849D-7A7B40B68C4E"); + + /// + public string Name => "ReaddDefaultPluginRepository"; + + /// + public bool PerformOnNewInstall => true; + + /// + public void Perform() + { + // Only add if repository list is empty + if (_serverConfigurationManager.Configuration.PluginRepositories.Count == 0) + { + _serverConfigurationManager.Configuration.PluginRepositories.Add(_defaultRepositoryInfo); + _serverConfigurationManager.SaveConfiguration(); + } + } + } +} \ No newline at end of file From 9787b2fe8a3004788e6d1b58217f74c41ecec826 Mon Sep 17 00:00:00 2001 From: crobibero Date: Tue, 21 Jul 2020 10:19:53 -0600 Subject: [PATCH 79/93] Detach tracked entries on dispose --- Jellyfin.Server.Implementations/JellyfinDb.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index 53120a763e..acc6eec1c5 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using System.Linq; using Jellyfin.Data; using Jellyfin.Data.Entities; @@ -133,6 +134,18 @@ namespace Jellyfin.Server.Implementations return base.SaveChanges(); } + /// + public override void Dispose() + { + foreach (var entry in ChangeTracker.Entries()) + { + entry.State = EntityState.Detached; + } + + GC.SuppressFinalize(this); + base.Dispose(); + } + /// protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { From 0c5ac10a68ff0d968579b67d48b0bc00580f6bf4 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 21 Jul 2020 14:25:52 -0400 Subject: [PATCH 80/93] Make IncrementInvalidLoginAttemptCount async. --- Jellyfin.Server.Implementations/Users/UserManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 343f452c7d..52e09a55a2 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -512,7 +512,7 @@ namespace Jellyfin.Server.Implementations.Users } else { - IncrementInvalidLoginAttemptCount(user); + await IncrementInvalidLoginAttemptCount(user).ConfigureAwait(false); _logger.LogInformation( "Authentication request for {UserName} has been denied (IP: {IP}).", user.Username, @@ -882,7 +882,7 @@ namespace Jellyfin.Server.Implementations.Users } } - private void IncrementInvalidLoginAttemptCount(User user) + private async Task IncrementInvalidLoginAttemptCount(User user) { user.InvalidLoginAttemptCount++; int? maxInvalidLogins = user.LoginAttemptsBeforeLockout; @@ -896,7 +896,7 @@ namespace Jellyfin.Server.Implementations.Users user.InvalidLoginAttemptCount); } - UpdateUser(user); + await UpdateUserAsync(user).ConfigureAwait(false); } } } From 2fa29527918570a1b100dec5bac78bca8e41e23e Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 21 Jul 2020 16:40:38 -0400 Subject: [PATCH 81/93] Skip image processing for live tv sources --- .../Library/LibraryManager.cs | 88 ++++++++++--------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index c27b73c74e..e02213710e 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1882,59 +1882,63 @@ namespace Emby.Server.Implementations.Library return; } - foreach (var img in outdated) + // Skip image processing for live tv + if (item.SourceType == SourceType.Library) { - var image = img; - if (!img.IsLocalFile) + foreach (var img in outdated) { - try + var image = img; + if (!img.IsLocalFile) { - var index = item.GetImageIndex(img); - image = ConvertImageToLocal(item, img, index).ConfigureAwait(false).GetAwaiter().GetResult(); + try + { + var index = item.GetImageIndex(img); + image = ConvertImageToLocal(item, img, index).ConfigureAwait(false).GetAwaiter().GetResult(); + } + catch (ArgumentException) + { + _logger.LogWarning("Cannot get image index for {0}", img.Path); + continue; + } + catch (InvalidOperationException) + { + _logger.LogWarning("Cannot fetch image from {0}", img.Path); + continue; + } } - catch (ArgumentException) + + try { - _logger.LogWarning("Cannot get image index for {0}", img.Path); - continue; + ImageDimensions size = _imageProcessor.GetImageDimensions(item, image); + image.Width = size.Width; + image.Height = size.Height; } - catch (InvalidOperationException) + catch (Exception ex) { - _logger.LogWarning("Cannot fetch image from {0}", img.Path); + _logger.LogError(ex, "Cannnot get image dimensions for {0}", image.Path); + image.Width = 0; + image.Height = 0; continue; } - } - - try - { - ImageDimensions size = _imageProcessor.GetImageDimensions(item, image); - image.Width = size.Width; - image.Height = size.Height; - } - catch (Exception ex) - { - _logger.LogError(ex, "Cannnot get image dimensions for {0}", image.Path); - image.Width = 0; - image.Height = 0; - continue; - } - try - { - image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path); - } - catch (Exception ex) - { - _logger.LogError(ex, "Cannot compute blurhash for {0}", image.Path); - image.BlurHash = string.Empty; - } + try + { + image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path); + } + catch (Exception ex) + { + _logger.LogError(ex, "Cannot compute blurhash for {0}", image.Path); + image.BlurHash = string.Empty; + } - try - { - image.DateModified = _fileSystem.GetLastWriteTimeUtc(image.Path); - } - catch (Exception ex) - { - _logger.LogError(ex, "Cannot update DateModified for {0}", image.Path); + try + { + image.DateModified = _fileSystem.GetLastWriteTimeUtc(image.Path); + } + catch (Exception ex) + { + _logger.LogError(ex, "Cannot update DateModified for {0}", image.Path); + } } } From 4d681e3cad3e74fa99dae4a483c7e258e345b001 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 22 Jul 2020 14:34:51 +0200 Subject: [PATCH 82/93] Optimize StringBuilder.Append calls --- Emby.Dlna/Eventing/EventManager.cs | 14 +++++++++----- .../Data/SqliteItemRepository.cs | 14 +++++++++----- .../Services/ServicePath.cs | 6 ++++-- .../MediaEncoding/EncodingHelper.cs | 6 +++--- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Emby.Dlna/Eventing/EventManager.cs b/Emby.Dlna/Eventing/EventManager.cs index 56c90c8b3a..7d02f5e960 100644 --- a/Emby.Dlna/Eventing/EventManager.cs +++ b/Emby.Dlna/Eventing/EventManager.cs @@ -152,11 +152,15 @@ namespace Emby.Dlna.Eventing builder.Append(""); foreach (var key in stateVariables.Keys) { - builder.Append(""); - builder.Append("<" + key + ">"); - builder.Append(stateVariables[key]); - builder.Append(""); - builder.Append(""); + builder.Append("") + .Append('<') + .Append(key) + .Append('>') + .Append(stateVariables[key]) + .Append("') + .Append(""); } builder.Append(""); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index a6390b1ef2..9f5566424c 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -1110,7 +1110,8 @@ namespace Emby.Server.Implementations.Data continue; } - str.Append(ToValueString(i) + "|"); + str.Append(ToValueString(i)) + .Append('|'); } str.Length -= 1; // Remove last | @@ -2471,7 +2472,7 @@ namespace Emby.Server.Implementations.Data var item = query.SimilarTo; var builder = new StringBuilder(); - builder.Append("("); + builder.Append('('); if (string.IsNullOrEmpty(item.OfficialRating)) { @@ -2509,7 +2510,7 @@ namespace Emby.Server.Implementations.Data if (!string.IsNullOrEmpty(query.SearchTerm)) { var builder = new StringBuilder(); - builder.Append("("); + builder.Append('('); builder.Append("((CleanName like @SearchTermStartsWith or (OriginalTitle not null and OriginalTitle like @SearchTermStartsWith)) * 10)"); @@ -5238,7 +5239,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type { if (i > 0) { - insertText.Append(","); + insertText.Append(','); } insertText.AppendFormat("(@ItemId, @AncestorId{0}, @AncestorIdText{0})", i.ToString(CultureInfo.InvariantCulture)); @@ -6331,7 +6332,10 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type foreach (var column in _mediaAttachmentSaveColumns.Skip(1)) { - insertText.Append("@" + column + index + ","); + insertText.Append('@') + .Append(column) + .Append(index) + .Append(','); } insertText.Length -= 1; diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 89538ae729..bdda7c089e 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -488,7 +488,8 @@ namespace Emby.Server.Implementations.Services sb.Append(value); for (var j = pathIx + 1; j < requestComponents.Length; j++) { - sb.Append(PathSeperatorChar + requestComponents[j]); + sb.Append(PathSeperatorChar) + .Append(requestComponents[j]); } value = sb.ToString(); @@ -505,7 +506,8 @@ namespace Emby.Server.Implementations.Services pathIx++; while (!string.Equals(requestComponents[pathIx], stopLiteral, StringComparison.OrdinalIgnoreCase)) { - sb.Append(PathSeperatorChar + requestComponents[pathIx++]); + sb.Append(PathSeperatorChar) + .Append(requestComponents[pathIx++]); } value = sb.ToString(); diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ffbda42c31..74ebab6a72 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -372,7 +372,7 @@ namespace MediaBrowser.Controller.MediaEncoding public int GetVideoProfileScore(string profile) { // strip spaces because they may be stripped out on the query string - profile = profile.Replace(" ", ""); + profile = profile.Replace(" ", string.Empty, CultureInfo.InvariantCulture); return Array.FindIndex(_videoProfiles, x => string.Equals(x, profile, StringComparison.OrdinalIgnoreCase)); } @@ -468,13 +468,13 @@ namespace MediaBrowser.Controller.MediaEncoding arg.Append("-hwaccel_output_format vaapi ") .Append("-vaapi_device ") .Append(encodingOptions.VaapiDevice) - .Append(" "); + .Append(' '); } else if (!isVaapiDecoder && isVaapiEncoder) { arg.Append("-vaapi_device ") .Append(encodingOptions.VaapiDevice) - .Append(" "); + .Append(' '); } } From b9004a0246d4df800ad8a601d4b7c21a78792982 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 22 Jul 2020 14:56:58 +0200 Subject: [PATCH 83/93] Fix build --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 74ebab6a72..5894abb0d2 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -372,7 +372,7 @@ namespace MediaBrowser.Controller.MediaEncoding public int GetVideoProfileScore(string profile) { // strip spaces because they may be stripped out on the query string - profile = profile.Replace(" ", string.Empty, CultureInfo.InvariantCulture); + profile = profile.Replace(" ", string.Empty, StringComparison.Ordinal); return Array.FindIndex(_videoProfiles, x => string.Equals(x, profile, StringComparison.OrdinalIgnoreCase)); } From a1511e430c07ff5c9b9a9324842d9a0f42c89c8b Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 22 Jul 2020 08:23:56 -0600 Subject: [PATCH 84/93] implement change properly --- .../MusicBrainz/Configuration/config.html | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html b/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html index c91ba009ba..1945e6cb49 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html @@ -40,8 +40,20 @@ .addEventListener('pageshow', function () { Dashboard.showLoadingMsg(); ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) { - document.querySelector('#server').value = config.Server; - document.querySelector('#rateLimit').value = config.RateLimit; + var server = document.querySelector('#server'); + server.value = config.Server; + server.dispatchEvent(new Event('change', { + bubbles: true, + cancelable: false + })); + + var rateLimit = document.querySelector('#rateLimit'); + rateLimit.value = config.RateLimit; + rateLimit.dispatchEvent(new Event('change', { + bubbles: true, + cancelable: false + })); + document.querySelector('#enable').checked = config.Enable; document.querySelector('#replaceArtistName').checked = config.ReplaceArtistName; From e973757485e1c76979a17f8d2dc94f664f2f5ad0 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 22 Jul 2020 11:32:29 -0400 Subject: [PATCH 85/93] Simplify logic --- .../Library/LibraryManager.cs | 91 +++++++++---------- 1 file changed, 44 insertions(+), 47 deletions(-) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index e02213710e..51c19fde79 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1876,69 +1876,66 @@ namespace Emby.Server.Implementations.Library } var outdated = forceUpdate ? item.ImageInfos.Where(i => i.Path != null).ToArray() : item.ImageInfos.Where(ImageNeedsRefresh).ToArray(); - if (outdated.Length == 0) + // Skip image processing if current or live tv source + if (outdated.Length == 0 || item.SourceType != SourceType.Library) { RegisterItem(item); return; } - // Skip image processing for live tv - if (item.SourceType == SourceType.Library) + foreach (var img in outdated) { - foreach (var img in outdated) + var image = img; + if (!img.IsLocalFile) { - var image = img; - if (!img.IsLocalFile) - { - try - { - var index = item.GetImageIndex(img); - image = ConvertImageToLocal(item, img, index).ConfigureAwait(false).GetAwaiter().GetResult(); - } - catch (ArgumentException) - { - _logger.LogWarning("Cannot get image index for {0}", img.Path); - continue; - } - catch (InvalidOperationException) - { - _logger.LogWarning("Cannot fetch image from {0}", img.Path); - continue; - } - } - try { - ImageDimensions size = _imageProcessor.GetImageDimensions(item, image); - image.Width = size.Width; - image.Height = size.Height; + var index = item.GetImageIndex(img); + image = ConvertImageToLocal(item, img, index).ConfigureAwait(false).GetAwaiter().GetResult(); } - catch (Exception ex) + catch (ArgumentException) { - _logger.LogError(ex, "Cannnot get image dimensions for {0}", image.Path); - image.Width = 0; - image.Height = 0; + _logger.LogWarning("Cannot get image index for {0}", img.Path); continue; } - - try - { - image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path); - } - catch (Exception ex) + catch (InvalidOperationException) { - _logger.LogError(ex, "Cannot compute blurhash for {0}", image.Path); - image.BlurHash = string.Empty; + _logger.LogWarning("Cannot fetch image from {0}", img.Path); + continue; } + } - try - { - image.DateModified = _fileSystem.GetLastWriteTimeUtc(image.Path); - } - catch (Exception ex) - { - _logger.LogError(ex, "Cannot update DateModified for {0}", image.Path); - } + try + { + ImageDimensions size = _imageProcessor.GetImageDimensions(item, image); + image.Width = size.Width; + image.Height = size.Height; + } + catch (Exception ex) + { + _logger.LogError(ex, "Cannnot get image dimensions for {0}", image.Path); + image.Width = 0; + image.Height = 0; + continue; + } + + try + { + image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path); + } + catch (Exception ex) + { + _logger.LogError(ex, "Cannot compute blurhash for {0}", image.Path); + image.BlurHash = string.Empty; + } + + try + { + image.DateModified = _fileSystem.GetLastWriteTimeUtc(image.Path); + } + catch (Exception ex) + { + _logger.LogError(ex, "Cannot update DateModified for {0}", image.Path); } } From f50348ca0b03a7928e58eb3b188532b98d6f46fa Mon Sep 17 00:00:00 2001 From: "E.Smith" <31170571+azlm8t@users.noreply.github.com> Date: Sun, 19 Jul 2020 12:59:28 +0100 Subject: [PATCH 86/93] Log path on lookup errors If the lookup fails (due to a bad id in an nfo file for example), then we had no indication of which directory failed, so the user can not fix the problem. Now we include the path in the error message such as: MediaBrowser.Providers.TV.SeriesMetadataService: Error in DummySeasonProvider for /media/x/y/z and MediaBrowser.Providers.Manager.ProviderManager: TvdbSeriesImageProvider failed in GetImageInfos for type Series at /media/x/y/z --- MediaBrowser.Providers/Manager/ProviderManager.cs | 4 ++-- MediaBrowser.Providers/TV/SeriesMetadataService.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 4ee065cd11..9170c70025 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -265,7 +265,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - _logger.LogError(ex, "{0} failed in GetImageInfos for type {1}", provider.GetType().Name, item.GetType().Name); + _logger.LogError(ex, "{ProviderName} failed in GetImageInfos for type {ItemType} at {ItemPath}", provider.GetType().Name, item.GetType().Name, item.Path); return new List(); } } @@ -430,7 +430,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - _logger.LogError(ex, "{0} failed in Supports for type {1}", provider.GetType().Name, item.GetType().Name); + _logger.LogError(ex, "{ProviderName} failed in Supports for type {ItemType} at {ItemPath}", provider.GetType().Name, item.GetType().Name, item.Path); return false; } } diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index 4181d37efb..a2c0e62c19 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.TV } catch (Exception ex) { - Logger.LogError(ex, "Error in DummySeasonProvider"); + Logger.LogError(ex, "Error in DummySeasonProvider for {ItemPath}", item.Path); } } From b4532ad3a2ea0066fa901bd46b6236aac46bceb7 Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 22 Jul 2020 11:35:31 -0600 Subject: [PATCH 87/93] add missing using --- .../Users/UserManager.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 343f452c7d..38468ce42e 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -102,7 +102,16 @@ namespace Jellyfin.Server.Implementations.Users } /// - public IEnumerable UsersIds => _dbProvider.CreateContext().Users.Select(u => u.Id); + public IEnumerable UsersIds + { + get + { + using var dbContext = _dbProvider.CreateContext(); + return dbContext.Users + .Select(user => user.Id) + .ToList(); + } + } /// public User? GetUserById(Guid id) @@ -637,7 +646,7 @@ namespace Jellyfin.Server.Implementations.Users /// public void UpdateConfiguration(Guid userId, UserConfiguration config) { - var dbContext = _dbProvider.CreateContext(); + using var dbContext = _dbProvider.CreateContext(); var user = dbContext.Users .Include(u => u.Permissions) .Include(u => u.Preferences) @@ -670,7 +679,7 @@ namespace Jellyfin.Server.Implementations.Users /// public void UpdatePolicy(Guid userId, UserPolicy policy) { - var dbContext = _dbProvider.CreateContext(); + using var dbContext = _dbProvider.CreateContext(); var user = dbContext.Users .Include(u => u.Permissions) .Include(u => u.Preferences) From 6cbfae209d5e4621624d9cc249c601f46c3721c5 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 22 Jul 2020 20:57:29 +0200 Subject: [PATCH 88/93] Make CreateUser async --- Jellyfin.Api/Controllers/StartupController.cs | 8 ++-- .../Users/UserManager.cs | 42 +++++++++++-------- MediaBrowser.Api/UserService.cs | 2 +- .../Library/IUserManager.cs | 4 +- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs index 04f134b8bf..93fb22c4eb 100644 --- a/Jellyfin.Api/Controllers/StartupController.cs +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -46,14 +46,12 @@ namespace Jellyfin.Api.Controllers [HttpGet("Configuration")] public StartupConfigurationDto GetStartupConfiguration() { - var result = new StartupConfigurationDto + return new StartupConfigurationDto { UICulture = _config.Configuration.UICulture, MetadataCountryCode = _config.Configuration.MetadataCountryCode, PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage }; - - return result; } /// @@ -92,10 +90,10 @@ namespace Jellyfin.Api.Controllers /// /// The first user. [HttpGet("User")] - public StartupUserDto GetFirstUser() + public async Task GetFirstUser() { // TODO: Remove this method when startup wizard no longer requires an existing user. - _userManager.Initialize(); + await _userManager.InitializeAsync().ConfigureAwait(false); var user = _userManager.Users.First(); return new StartupUserDto { diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 343f452c7d..5d72ff9382 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -188,8 +188,24 @@ namespace Jellyfin.Server.Implementations.Users await dbContext.SaveChangesAsync().ConfigureAwait(false); } + internal async Task CreateUserInternalAsync(string name, JellyfinDb dbContext) + { + // TODO: Remove after user item data is migrated. + var max = await dbContext.Users.AnyAsync().ConfigureAwait(false) + ? await dbContext.Users.Select(u => u.InternalId).MaxAsync().ConfigureAwait(false) + : 0; + + return new User( + name, + _defaultAuthenticationProvider.GetType().FullName, + _defaultPasswordResetProvider.GetType().FullName) + { + InternalId = max + 1 + }; + } + /// - public User CreateUser(string name) + public async Task CreateUserAsync(string name) { if (!IsValidUsername(name)) { @@ -198,18 +214,10 @@ namespace Jellyfin.Server.Implementations.Users using var dbContext = _dbProvider.CreateContext(); - // TODO: Remove after user item data is migrated. - var max = dbContext.Users.Any() ? dbContext.Users.Select(u => u.InternalId).Max() : 0; + var newUser = await CreateUserInternalAsync(name, dbContext).ConfigureAwait(false); - var newUser = new User( - name, - _defaultAuthenticationProvider.GetType().FullName, - _defaultPasswordResetProvider.GetType().FullName) - { - InternalId = max + 1 - }; - dbContext.Users.Add(newUser); - dbContext.SaveChanges(); + await dbContext.Users.AddAsync(newUser).ConfigureAwait(false); + await dbContext.SaveChangesAsync().ConfigureAwait(false); OnUserCreated?.Invoke(this, new GenericEventArgs(newUser)); @@ -572,12 +580,12 @@ namespace Jellyfin.Server.Implementations.Users } /// - public void Initialize() + public async Task InitializeAsync() { // TODO: Refactor the startup wizard so that it doesn't require a user to already exist. using var dbContext = _dbProvider.CreateContext(); - if (dbContext.Users.Any()) + if (await dbContext.Users.AnyAsync().ConfigureAwait(false)) { return; } @@ -595,13 +603,13 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Provided username is not valid!", defaultName); } - var newUser = CreateUser(defaultName); + var newUser = await CreateUserInternalAsync(defaultName, dbContext).ConfigureAwait(false); newUser.SetPermission(PermissionKind.IsAdministrator, true); newUser.SetPermission(PermissionKind.EnableContentDeletion, true); newUser.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, true); - dbContext.Users.Update(newUser); - dbContext.SaveChanges(); + await dbContext.Users.AddAsync(newUser).ConfigureAwait(false); + await dbContext.SaveChangesAsync().ConfigureAwait(false); } /// diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 6e9d788dc1..440d1840d9 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -525,7 +525,7 @@ namespace MediaBrowser.Api /// System.Object. public async Task Post(CreateUserByName request) { - var newUser = _userManager.CreateUser(request.Name); + var newUser = await _userManager.CreateUserAsync(request.Name).ConfigureAwait(false); // no need to authenticate password for new user if (request.Password != null) diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index e73fe71205..a2ff0c1bc7 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -55,7 +55,7 @@ namespace MediaBrowser.Controller.Library /// /// Initializes the user manager and ensures that a user exists. /// - void Initialize(); + Task InitializeAsync(); /// /// Gets a user by Id. @@ -106,7 +106,7 @@ namespace MediaBrowser.Controller.Library /// The created user. /// name /// - User CreateUser(string name); + Task CreateUserAsync(string name); /// /// Deletes the specified user. From 941f326c0b786ba8bac02dd745ea998055e6e554 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 22 Jul 2020 21:07:13 +0200 Subject: [PATCH 89/93] Don't AddAsync --- Jellyfin.Server.Implementations/Users/UserManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 5d72ff9382..a0dd2a6b38 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -216,7 +216,7 @@ namespace Jellyfin.Server.Implementations.Users var newUser = await CreateUserInternalAsync(name, dbContext).ConfigureAwait(false); - await dbContext.Users.AddAsync(newUser).ConfigureAwait(false); + dbContext.Users.Add(newUser); await dbContext.SaveChangesAsync().ConfigureAwait(false); OnUserCreated?.Invoke(this, new GenericEventArgs(newUser)); @@ -608,7 +608,7 @@ namespace Jellyfin.Server.Implementations.Users newUser.SetPermission(PermissionKind.EnableContentDeletion, true); newUser.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, true); - await dbContext.Users.AddAsync(newUser).ConfigureAwait(false); + dbContext.Users.Add(newUser); await dbContext.SaveChangesAsync().ConfigureAwait(false); } From 200f36959638187a220ad152d42333a787a83f8e Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Mon, 29 Jun 2020 23:00:46 -0400 Subject: [PATCH 90/93] Use interfaces in app host constructors --- Emby.Server.Implementations/ApplicationHost.cs | 4 ++-- Jellyfin.Server/CoreAppHost.cs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index f6077400d6..8e1bf97667 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -192,7 +192,7 @@ namespace Emby.Server.Implementations /// Gets or sets the application paths. /// /// The application paths. - protected ServerApplicationPaths ApplicationPaths { get; set; } + protected IServerApplicationPaths ApplicationPaths { get; set; } /// /// Gets or sets all concrete types. @@ -236,7 +236,7 @@ namespace Emby.Server.Implementations /// Initializes a new instance of the class. /// public ApplicationHost( - ServerApplicationPaths applicationPaths, + IServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, IStartupOptions options, IFileSystem fileSystem, diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 207eaa98d1..71b0fd8f35 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -9,6 +9,7 @@ using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Activity; using Jellyfin.Server.Implementations.Users; using MediaBrowser.Common.Net; +using MediaBrowser.Controller; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Activity; @@ -33,9 +34,9 @@ namespace Jellyfin.Server /// The to be used by the . /// The to be used by the . public CoreAppHost( - ServerApplicationPaths applicationPaths, + IServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, - StartupOptions options, + IStartupOptions options, IFileSystem fileSystem, INetworkManager networkManager) : base( From 7adac7561ad814a08a30632fecd296e1b2142112 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 22 Jul 2020 19:52:14 -0400 Subject: [PATCH 91/93] Use System.Text.Json in LiveTvManager --- Emby.Server.Implementations/LiveTv/LiveTvManager.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 4c1de3bccf..1b075d86a8 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.Library; @@ -28,7 +29,6 @@ using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; using Episode = MediaBrowser.Controller.Entities.TV.Episode; @@ -54,7 +54,6 @@ namespace Emby.Server.Implementations.LiveTv private readonly ILibraryManager _libraryManager; private readonly ITaskManager _taskManager; private readonly ILocalizationManager _localization; - private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly IChannelManager _channelManager; private readonly LiveTvDtoService _tvDtoService; @@ -73,7 +72,6 @@ namespace Emby.Server.Implementations.LiveTv ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, - IJsonSerializer jsonSerializer, IFileSystem fileSystem, IChannelManager channelManager, LiveTvDtoService liveTvDtoService) @@ -85,7 +83,6 @@ namespace Emby.Server.Implementations.LiveTv _libraryManager = libraryManager; _taskManager = taskManager; _localization = localization; - _jsonSerializer = jsonSerializer; _fileSystem = fileSystem; _dtoService = dtoService; _userDataManager = userDataManager; @@ -2234,7 +2231,7 @@ namespace Emby.Server.Implementations.LiveTv public async Task SaveTunerHost(TunerHostInfo info, bool dataSourceChanged = true) { - info = _jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info)); + info = JsonSerializer.Deserialize(JsonSerializer.Serialize(info)); var provider = _tunerHosts.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); @@ -2278,7 +2275,7 @@ namespace Emby.Server.Implementations.LiveTv { // Hack to make the object a pure ListingsProviderInfo instead of an AddListingProvider // ServerConfiguration.SaveConfiguration crashes during xml serialization for AddListingProvider - info = _jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info)); + info = JsonSerializer.Deserialize(JsonSerializer.Serialize(info)); var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); From 0e855953a2078c2229cffedf015baa107be1cbf4 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 23 Jul 2020 12:03:46 +0200 Subject: [PATCH 92/93] Update Jellyfin.Server/Program.cs Co-authored-by: Bond-009 --- Jellyfin.Server/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 3a414d7678..444a91c024 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -356,7 +356,7 @@ namespace Jellyfin.Server } options.ListenUnixSocket(socketPath); - _logger.LogInformation("Kestrel listening to unix socket {socketPath}", socketPath); + _logger.LogInformation("Kestrel listening to unix socket {SocketPath}", socketPath); } }) .ConfigureAppConfiguration(config => config.ConfigureAppConfiguration(commandLineOpts, appPaths, startupConfig)) From 722f6f5a261cb008977db48f3e4f885258239bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Fern=C3=A1ndez?= Date: Thu, 23 Jul 2020 20:51:15 +0200 Subject: [PATCH 93/93] fix typo in debian's config file --- debian/conf/jellyfin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/conf/jellyfin b/debian/conf/jellyfin index 64c98520cb..7cbfa88ee8 100644 --- a/debian/conf/jellyfin +++ b/debian/conf/jellyfin @@ -31,7 +31,7 @@ JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg" #JELLYFIN_SERVICE_OPT="--service" # [OPTIONAL] run Jellyfin without the web app -#JELLYFIN_NOWEBAPP_OPT="--noautorunwebapp" +#JELLYFIN_NOWEBAPP_OPT="--nowebclient" # # SysV init/Upstart options @@ -40,4 +40,4 @@ JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg" # Application username JELLYFIN_USER="jellyfin" # Full application command -JELLYFIN_ARGS="$JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLFIN_NOWEBAPP_OPT" +JELLYFIN_ARGS="$JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT"