From 80877aa945c5af9ffd6ca811d981ba417942ed9f Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sat, 17 Apr 2021 09:27:58 +0100 Subject: Cleaned up "value assigned is not used in any execution path" --- Emby.Server.Implementations/HttpServer/WebSocketConnection.cs | 4 ++-- .../LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 2 +- Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 06acb56061..c661e6757f 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using System.Buffers; @@ -182,7 +182,7 @@ namespace Emby.Server.Implementations.HttpServer } WebSocketMessage? stub; - long bytesConsumed = 0; + long bytesConsumed; try { stub = DeserializeWebSocketMessage(buffer, out bytesConsumed); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index b16ccc561a..61262eb14e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -87,7 +87,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun Logger.LogInformation("Opening HDHR UDP Live stream from {host}", uri.Host); var remoteAddress = IPAddress.Parse(uri.Host); - IPAddress localAddress = null; + IPAddress localAddress; using (var tcpClient = new TcpClient()) { try diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index 7bed06de36..0e5f65c724 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -258,7 +258,6 @@ namespace Emby.Server.Implementations.QuickConnect } // Expire stale connection requests - var code = string.Empty; var values = _currentRequests.Values.ToList(); for (int i = 0; i < values.Count; i++) @@ -266,7 +265,7 @@ namespace Emby.Server.Implementations.QuickConnect var added = values[i].DateAdded ?? DateTime.UnixEpoch; if (DateTime.UtcNow > added.AddMinutes(Timeout) || expireAll) { - code = values[i].Code; + var code = values[i].Code; _logger.LogDebug("Removing expired request {code}", code); if (!_currentRequests.TryRemove(code, out _)) -- cgit v1.2.3 From 1d6224c9c66b31c9df602b4281c870a9c400767c Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 26 Apr 2021 07:02:26 -0600 Subject: Add endpoint to log client events --- Emby.Server.Implementations/ApplicationHost.cs | 3 + Jellyfin.Api/Controllers/ClientLogController.cs | 69 ++++++++++++++++++++ .../Models/ClientLogDtos/ClientLogEventDto.cs | 54 ++++++++++++++++ Jellyfin.Server/Jellyfin.Server.csproj | 1 + Jellyfin.Server/Program.cs | 49 ++++++++++---- .../ClientEvent/ClientEventLogger.cs | 38 +++++++++++ .../ClientEvent/IClientEventLogger.cs | 16 +++++ .../MediaBrowser.Controller.csproj | 2 +- MediaBrowser.Model/ClientLog/ClientLogEvent.cs | 75 ++++++++++++++++++++++ 9 files changed, 295 insertions(+), 12 deletions(-) create mode 100644 Jellyfin.Api/Controllers/ClientLogController.cs create mode 100644 Jellyfin.Api/Models/ClientLogDtos/ClientLogEventDto.cs create mode 100644 MediaBrowser.Controller/ClientEvent/ClientEventLogger.cs create mode 100644 MediaBrowser.Controller/ClientEvent/IClientEventLogger.cs create mode 100644 MediaBrowser.Model/ClientLog/ClientLogEvent.cs (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 703f8d20da..b05e0409d9 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -55,6 +55,7 @@ using MediaBrowser.Common.Updates; using MediaBrowser.Controller; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Chapters; +using MediaBrowser.Controller.ClientEvent; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; @@ -680,6 +681,8 @@ namespace Emby.Server.Implementations ServiceCollection.AddScoped(); ServiceCollection.AddScoped(); + ServiceCollection.AddScoped(); + ServiceCollection.AddSingleton(); } diff --git a/Jellyfin.Api/Controllers/ClientLogController.cs b/Jellyfin.Api/Controllers/ClientLogController.cs new file mode 100644 index 0000000000..8e38cd13c5 --- /dev/null +++ b/Jellyfin.Api/Controllers/ClientLogController.cs @@ -0,0 +1,69 @@ +using Jellyfin.Api.Models.ClientLogDtos; +using MediaBrowser.Controller.ClientEvent; +using MediaBrowser.Model.ClientLog; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Controllers +{ + /// + /// Client log controller. + /// + public class ClientLogController : BaseJellyfinApiController + { + private readonly IClientEventLogger _clientEventLogger; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + public ClientLogController(IClientEventLogger clientEventLogger) + { + _clientEventLogger = clientEventLogger; + } + + /// + /// Post event from client. + /// + /// The client log dto. + /// Event logged. + /// Submission status. + [HttpPost] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public ActionResult LogEvent([FromBody] ClientLogEventDto clientLogEventDto) + { + Log(clientLogEventDto); + return NoContent(); + } + + /// + /// Bulk post events from client. + /// + /// The list of client log dtos. + /// All events logged. + /// Submission status. + [HttpPost("Bulk")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public ActionResult LogEvents([FromBody] ClientLogEventDto[] clientLogEventDtos) + { + foreach (var dto in clientLogEventDtos) + { + Log(dto); + } + + return NoContent(); + } + + private void Log(ClientLogEventDto dto) + { + _clientEventLogger.Log(new ClientLogEvent( + dto.Timestamp, + dto.Level, + dto.UserId, + dto.ClientName, + dto.ClientVersion, + dto.DeviceId, + dto.Message)); + } + } +} \ No newline at end of file diff --git a/Jellyfin.Api/Models/ClientLogDtos/ClientLogEventDto.cs b/Jellyfin.Api/Models/ClientLogDtos/ClientLogEventDto.cs new file mode 100644 index 0000000000..8ee1eab726 --- /dev/null +++ b/Jellyfin.Api/Models/ClientLogDtos/ClientLogEventDto.cs @@ -0,0 +1,54 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Api.Models.ClientLogDtos +{ + /// + /// The client log dto. + /// + public class ClientLogEventDto + { + /// + /// Gets or sets the event timestamp. + /// + [Required] + public DateTime Timestamp { get; set; } + + /// + /// Gets or sets the log level. + /// + [Required] + public LogLevel Level { get; set; } + + /// + /// Gets or sets the user id. + /// + public Guid? UserId { get; set; } + + /// + /// Gets or sets the client name. + /// + [Required] + public string ClientName { get; set; } = string.Empty; + + /// + /// Gets or sets the client version. + /// + [Required] + public string ClientVersion { get; set; } = string.Empty; + + /// + /// + /// Gets or sets the device id. + /// + [Required] + public string DeviceId { get; set; } = string.Empty; + + /// + /// Gets or sets the log message. + /// + [Required] + public string Message { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 3496cabe8e..ef842ee26b 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -49,6 +49,7 @@ + diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index c10b2ddb3a..b8d3ba2397 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -14,6 +14,7 @@ using Emby.Server.Implementations; using Emby.Server.Implementations.IO; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; +using MediaBrowser.Controller.ClientEvent; using MediaBrowser.Controller.Extensions; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; @@ -24,6 +25,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Serilog; using Serilog.Extensions.Logging; +using Serilog.Filters; using SQLitePCL; using ConfigurationExtensions = MediaBrowser.Controller.Extensions.ConfigurationExtensions; using ILogger = Microsoft.Extensions.Logging.ILogger; @@ -585,22 +587,47 @@ namespace Jellyfin.Server { // Serilog.Log is used by SerilogLoggerFactory when no logger is specified Serilog.Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(configuration) - .Enrich.FromLogContext() - .Enrich.WithThreadId() + .WriteTo.Logger(lc => + lc.ReadFrom.Configuration(configuration) + .Enrich.FromLogContext() + .Enrich.WithThreadId() + .Filter.ByExcluding(Matching.FromSource())) + .WriteTo.Logger(lc => + lc + .WriteTo.Map( + "ClientName", + (clientName, wt) + => wt.File( + Path.Combine(appPaths.LogDirectoryPath, $"log_{clientName}_.log"), + rollingInterval: RollingInterval.Day, + outputTemplate: "{Message:l}{NewLine}{Exception}", + encoding: Encoding.UTF8)) + .Filter.ByIncludingOnly(Matching.FromSource())) .CreateLogger(); } catch (Exception ex) { Serilog.Log.Logger = new LoggerConfiguration() - .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}") - .WriteTo.Async(x => x.File( - Path.Combine(appPaths.LogDirectoryPath, "log_.log"), - rollingInterval: RollingInterval.Day, - outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message}{NewLine}{Exception}", - encoding: Encoding.UTF8)) - .Enrich.FromLogContext() - .Enrich.WithThreadId() + .WriteTo.Logger(lc => + lc.WriteTo.Async(x => x.File( + Path.Combine(appPaths.LogDirectoryPath, "log_.log"), + rollingInterval: RollingInterval.Day, + outputTemplate: "{Message:l}{NewLine}{Exception}", + encoding: Encoding.UTF8)) + .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}") + .Enrich.FromLogContext() + .Enrich.WithThreadId()) + .WriteTo.Logger(lc => + lc + .WriteTo.Map( + "ClientName", + (clientName, wt) + => wt.File( + Path.Combine(appPaths.LogDirectoryPath, $"log_{clientName}_.log"), + rollingInterval: RollingInterval.Day, + outputTemplate: "{Message:l}{NewLine}{Exception}", + encoding: Encoding.UTF8)) + .Filter.ByIncludingOnly(Matching.FromSource())) .CreateLogger(); Serilog.Log.Logger.Fatal(ex, "Failed to create/read logger configuration"); diff --git a/MediaBrowser.Controller/ClientEvent/ClientEventLogger.cs b/MediaBrowser.Controller/ClientEvent/ClientEventLogger.cs new file mode 100644 index 0000000000..c00a38d1bc --- /dev/null +++ b/MediaBrowser.Controller/ClientEvent/ClientEventLogger.cs @@ -0,0 +1,38 @@ +using System; +using MediaBrowser.Model.ClientLog; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.Controller.ClientEvent +{ + /// + public class ClientEventLogger : IClientEventLogger + { + private const string LogString = "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level}] [{ClientName}:{ClientVersion}]: UserId: {UserId} DeviceId: {DeviceId}{NewLine}{Message}"; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + public ClientEventLogger(ILogger logger) + { + _logger = logger; + } + + /// + public void Log(ClientLogEvent clientLogEvent) + { + _logger.Log( + LogLevel.Critical, + LogString, + clientLogEvent.Timestamp, + clientLogEvent.Level.ToString(), + clientLogEvent.ClientName, + clientLogEvent.ClientVersion, + clientLogEvent.UserId ?? Guid.Empty, + clientLogEvent.DeviceId, + Environment.NewLine, + clientLogEvent.Message); + } + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/ClientEvent/IClientEventLogger.cs b/MediaBrowser.Controller/ClientEvent/IClientEventLogger.cs new file mode 100644 index 0000000000..bf799c7bf8 --- /dev/null +++ b/MediaBrowser.Controller/ClientEvent/IClientEventLogger.cs @@ -0,0 +1,16 @@ +using MediaBrowser.Model.ClientLog; + +namespace MediaBrowser.Controller.ClientEvent +{ + /// + /// The client event logger. + /// + public interface IClientEventLogger + { + /// + /// Logs the event from the client. + /// + /// The client log event. + void Log(ClientLogEvent clientLogEvent); + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 8c68b47dd7..7c95ab818c 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -16,7 +16,7 @@ - + diff --git a/MediaBrowser.Model/ClientLog/ClientLogEvent.cs b/MediaBrowser.Model/ClientLog/ClientLogEvent.cs new file mode 100644 index 0000000000..e4ee881454 --- /dev/null +++ b/MediaBrowser.Model/ClientLog/ClientLogEvent.cs @@ -0,0 +1,75 @@ +using System; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.Model.ClientLog +{ + /// + /// The client log event. + /// + public class ClientLogEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The log timestamp. + /// The log level. + /// The user id. + /// The client name. + /// The client version. + /// The device id. + /// The message. + public ClientLogEvent( + DateTime timestamp, + LogLevel level, + Guid? userId, + string clientName, + string clientVersion, + string deviceId, + string message) + { + Timestamp = timestamp; + UserId = userId; + ClientName = clientName; + ClientVersion = clientVersion; + DeviceId = deviceId; + Message = message; + Level = level; + } + + /// + /// Gets the event timestamp. + /// + public DateTime Timestamp { get; } + + /// + /// Gets the log level. + /// + public LogLevel Level { get; } + + /// + /// Gets the user id. + /// + public Guid? UserId { get; } + + /// + /// Gets the client name. + /// + public string ClientName { get; } + + /// + /// Gets the client version. + /// + public string ClientVersion { get; } + + /// + /// + /// Gets the device id. + /// + public string DeviceId { get; } + + /// + /// Gets the log message. + /// + public string Message { get; } + } +} \ No newline at end of file -- cgit v1.2.3 From 5741fa7dfa4b1e8e8cb1f977a7eb531b994b93ae Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sat, 24 Apr 2021 23:54:48 +0100 Subject: Fix url for LiveTV --- Emby.Server.Implementations/ApplicationHost.cs | 8 +--- Jellyfin.Networking/Manager/NetworkManager.cs | 1 + .../NetworkManagerTests.cs | 2 +- .../Jellyfin.Networking.Tests/NetworkParseTests.cs | 48 ++++++++++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 703f8d20da..7b4592fbc0 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1203,12 +1203,8 @@ namespace Emby.Server.Implementations /// public string GetLoopbackHttpApiUrl() { - if (NetManager.IsIP6Enabled) - { - return GetLocalApiUrl("::1", Uri.UriSchemeHttp, HttpPort); - } - - return GetLocalApiUrl("127.0.0.1", Uri.UriSchemeHttp, HttpPort); + // Passing an external address cause GetBindInterface to return an externally accessible interface (if possible). + return GetLocalApiUrl(NetManager.GetBindInterface("8.8.8.8", out var _), Uri.UriSchemeHttp, HttpPort); } /// diff --git a/Jellyfin.Networking/Manager/NetworkManager.cs b/Jellyfin.Networking/Manager/NetworkManager.cs index 73e8b2cd72..fd8455dc85 100644 --- a/Jellyfin.Networking/Manager/NetworkManager.cs +++ b/Jellyfin.Networking/Manager/NetworkManager.cs @@ -990,6 +990,7 @@ namespace Jellyfin.Networking.Manager // Read and parse bind addresses and exclusions, removing ones that don't exist. _bindAddresses = CreateIPCollection(lanAddresses).ThatAreContainedInNetworks(_interfaceAddresses); _bindExclusions = CreateIPCollection(lanAddresses, true).ThatAreContainedInNetworks(_interfaceAddresses); + _logger.LogInformation("Using bind addresses: {0}", _bindAddresses.AsString()); _logger.LogInformation("Using bind exclusions: {0}", _bindExclusions.AsString()); } diff --git a/tests/Jellyfin.Networking.Tests/NetworkManagerTests.cs b/tests/Jellyfin.Networking.Tests/NetworkManagerTests.cs index 1cad625b73..61f9132528 100644 --- a/tests/Jellyfin.Networking.Tests/NetworkManagerTests.cs +++ b/tests/Jellyfin.Networking.Tests/NetworkManagerTests.cs @@ -34,7 +34,7 @@ namespace Jellyfin.Networking.Tests } /// - /// Checks that thge given IP address is not in the network provided. + /// Checks that the given IP address is not in the network provided. /// /// Network address(es). /// The IP to check. diff --git a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs index 9b0da2b3c4..ea14772910 100644 --- a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs +++ b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.ObjectModel; +using System.Linq; using System.Net; using Jellyfin.Networking.Configuration; using Jellyfin.Networking.Manager; @@ -530,5 +531,52 @@ namespace Jellyfin.Networking.Tests Assert.NotEqual(nm.HasRemoteAccess(IPAddress.Parse(remoteIp)), denied); } + + [Theory] + [InlineData("192.168.1.209/24,-16,eth16", "192.168.1.0/24", "", "192.168.1.209")] // Only 1 address so use it. + [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "", "192.168.1.208")] // LAN address is specified by default. + [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "10.0.0.1", "10.0.0.1")] // return bind address + [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "10.0.0.1", "192.168.1.209")] // return internal bind address (Internal takes priority) + + public void Get_Appropriate_Interface_NoSource(string interfaces, string lan, string bind, string result) + { + var conf = new NetworkConfiguration() + { + EnableIPV4 = true, + LocalNetworkSubnets = lan.Split(','), + LocalNetworkAddresses = bind.Split(',') + }; + + NetworkManager.MockNetworkSettings = interfaces; + using var nm = new NetworkManager(GetMockConfig(conf), new NullLogger()); + + var interfaceToUse = nm.GetBindInterface(string.Empty, out var port); + + Assert.Equal(interfaceToUse, result); + } + + [Theory] + [InlineData("192.168.1.209/24,-16,eth16", "192.168.1.0/24", "", "192.168.1.210", "192.168.1.209")] // Source on LAN + [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "", "192.168.1.209", "192.168.1.208")] // Source on LAN + [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "", "8.8.8.8", "10.0.0.1")] // Source external. + [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "10.0.0.1", "192.168.1.209", "10.0.0.1")] // LAN not bound, so return external. + [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "192.168.1.208,10.0.0.1", "8.8.8.8", "10.0.0.1")] // return external bind address + [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "192.168.1.208,10.0.0.1", "192.168.1.210", "192.168.1.208")] // return LAN bind address + public void Get_Appropriate_Interface_ForSource(string interfaces, string lan, string bind, string source, string result) + { + var conf = new NetworkConfiguration() + { + EnableIPV4 = true, + LocalNetworkSubnets = lan.Split(','), + LocalNetworkAddresses = bind.Split(',') + }; + + NetworkManager.MockNetworkSettings = interfaces; + using var nm = new NetworkManager(GetMockConfig(conf), new NullLogger()); + + var interfaceToUse = nm.GetBindInterface(source, out var port); + + Assert.Equal(interfaceToUse, result); + } } } -- cgit v1.2.3 From 78e97dbaa99a9acc8b0abc04a72480976aef3c24 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Mon, 26 Apr 2021 19:56:15 +0100 Subject: updated comment --- Emby.Server.Implementations/ApplicationHost.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 7b4592fbc0..e7ca70d04d 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1203,7 +1203,8 @@ namespace Emby.Server.Implementations /// public string GetLoopbackHttpApiUrl() { - // Passing an external address cause GetBindInterface to return an externally accessible interface (if possible). + // Passing an external address cause GetBindInterface to return the externally facing interface on a multi-adapter system. + // LocalNetworkSubnets and LocalNetworkAddresses are used in conjunction with the ip address to help select the best interface. return GetLocalApiUrl(NetManager.GetBindInterface("8.8.8.8", out var _), Uri.UriSchemeHttp, HttpPort); } -- cgit v1.2.3 From 851f610e11907a7c90e10d00400514a6585f50c6 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Mon, 26 Apr 2021 19:59:35 +0100 Subject: Changed other method to match for consistency. --- Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 3a738fd5d2..d7ea9d6406 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.LiveTv // Dummy this up so that direct play checks can still run if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) { - source.Path = _appHost.GetSmartApiUrl(string.Empty); + source.Path = _appHost.GetLoopbackHttpApiUrl(); } } -- cgit v1.2.3 From 21826405197ad6a5ac51a3eccc5bb50004bdc54b Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Fri, 30 Apr 2021 09:08:56 +0100 Subject: Update Emby.Server.Implementations/ApplicationHost.cs Co-authored-by: Cody Robibero --- Emby.Server.Implementations/ApplicationHost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index e7ca70d04d..26a2d7298d 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1205,7 +1205,7 @@ namespace Emby.Server.Implementations { // Passing an external address cause GetBindInterface to return the externally facing interface on a multi-adapter system. // LocalNetworkSubnets and LocalNetworkAddresses are used in conjunction with the ip address to help select the best interface. - return GetLocalApiUrl(NetManager.GetBindInterface("8.8.8.8", out var _), Uri.UriSchemeHttp, HttpPort); + return GetLocalApiUrl(NetManager.GetBindInterface("0.0.0.0", out var _), Uri.UriSchemeHttp, HttpPort); } /// -- cgit v1.2.3 From a5aabbb88538f8ab3f95f3accf31adb1be24503d Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sat, 1 May 2021 17:14:37 +0100 Subject: Update ApplicationHost.cs Renamed method --- Emby.Server.Implementations/ApplicationHost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 26a2d7298d..c28b4ae1c1 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1201,7 +1201,7 @@ namespace Emby.Server.Implementations } /// - public string GetLoopbackHttpApiUrl() + public string GetExternalFacingHttpApiUrl() { // Passing an external address cause GetBindInterface to return the externally facing interface on a multi-adapter system. // LocalNetworkSubnets and LocalNetworkAddresses are used in conjunction with the ip address to help select the best interface. -- cgit v1.2.3 From 2fbc1190bcb287407722a75db6992c5c65adfd70 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sat, 1 May 2021 17:15:45 +0100 Subject: Update LiveTvMediaSourceProvider.cs --- Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index d7ea9d6406..804794caae 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.LiveTv // Dummy this up so that direct play checks can still run if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) { - source.Path = _appHost.GetLoopbackHttpApiUrl(); + source.Path = _appHost.GetExternalFacingHttpApiUrl(); } } -- cgit v1.2.3 From 7936ea59eb199980eaa47891a0e017143bbf8319 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sat, 1 May 2021 17:21:14 +0100 Subject: Changed selection method --- Emby.Server.Implementations/ApplicationHost.cs | 22 ++++++++++++--- .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/LiveTvMediaSourceProvider.cs | 2 +- .../TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 2 +- .../LiveTv/TunerHosts/SharedHttpStream.cs | 2 +- Jellyfin.Networking/Manager/NetworkManager.cs | 31 +++------------------- MediaBrowser.Controller/IServerApplicationHost.cs | 5 ++-- .../Jellyfin.Networking.Tests/NetworkParseTests.cs | 4 +-- 8 files changed, 29 insertions(+), 41 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index c28b4ae1c1..bd2bb54bdc 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1201,11 +1201,25 @@ namespace Emby.Server.Implementations } /// - public string GetExternalFacingHttpApiUrl() + public string GetInterfaceHttpApiUrl() { - // Passing an external address cause GetBindInterface to return the externally facing interface on a multi-adapter system. - // LocalNetworkSubnets and LocalNetworkAddresses are used in conjunction with the ip address to help select the best interface. - return GetLocalApiUrl(NetManager.GetBindInterface("0.0.0.0", out var _), Uri.UriSchemeHttp, HttpPort); + // Published server ends with a / + if (!string.IsNullOrEmpty(PublishedServerUrl)) + { + // Published server ends with a '/', so we need to remove it. + return PublishedServerUrl.Trim('/'); + } + + var bind = NetManager.GetInternalBindAddresses().FirstOrDefault() ?? new IPNetAddress(IPAddress.None); + + string smart = NetManager.GetBindInterface(bind, out var port); + // If the smartAPI doesn't start with http then treat it as a host or ip. + if (smart.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + return smart.Trim('/'); + } + + return GetLocalApiUrl(smart.Trim('/'), null, port); } /// diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index c9d9cc49af..d61f74dd23 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1031,7 +1031,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var stream = new MediaSourceInfo { - EncoderPath = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveRecordings/" + info.Id + "/stream", + EncoderPath = _appHost.GetInterfaceHttpApiUrl() + "/LiveTv/LiveRecordings/" + info.Id + "/stream", EncoderProtocol = MediaProtocol.Http, Path = info.Path, Protocol = MediaProtocol.File, diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 804794caae..b5f0b2118c 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.LiveTv // Dummy this up so that direct play checks can still run if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) { - source.Path = _appHost.GetExternalFacingHttpApiUrl(); + source.Path = _appHost.GetInterfaceHttpApiUrl(); } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index b16ccc561a..d6ea320ead 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -148,7 +148,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun // OpenedMediaSource.Path = tempFile; // OpenedMediaSource.ReadAtNativeFramerate = true; - MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; + MediaSource.Path = _appHost.GetInterfaceHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; MediaSource.Protocol = MediaProtocol.Http; // OpenedMediaSource.SupportsDirectPlay = false; // OpenedMediaSource.SupportsDirectStream = true; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index eeb2426f4f..b9a567e40a 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -97,7 +97,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts // OpenedMediaSource.Path = tempFile; // OpenedMediaSource.ReadAtNativeFramerate = true; - MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; + MediaSource.Path = _appHost.GetInterfaceHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; MediaSource.Protocol = MediaProtocol.Http; // OpenedMediaSource.Path = TempFilePath; diff --git a/Jellyfin.Networking/Manager/NetworkManager.cs b/Jellyfin.Networking/Manager/NetworkManager.cs index fd8455dc85..52e2f7964c 100644 --- a/Jellyfin.Networking/Manager/NetworkManager.cs +++ b/Jellyfin.Networking/Manager/NetworkManager.cs @@ -455,10 +455,10 @@ namespace Jellyfin.Networking.Manager } // No bind address, so return all internal interfaces. - return CreateCollection(_internalInterfaces.Where(p => !p.IsLoopback())); + return CreateCollection(_internalInterfaces); } - return new Collection(_bindAddresses); + return new Collection(_bindAddresses.Where(IsInLocalNetwork).ToArray()); } /// @@ -481,7 +481,7 @@ namespace Jellyfin.Networking.Manager } // As private addresses can be redefined by Configuration.LocalNetworkAddresses - return _lanSubnets.ContainsAddress(address) && !_excludedSubnets.ContainsAddress(address); + return address.IsLoopback() || (_lanSubnets.ContainsAddress(address) && !_excludedSubnets.ContainsAddress(address)); } /// @@ -647,16 +647,6 @@ namespace Jellyfin.Networking.Manager _interfaceAddresses.AddItem(address, false); _interfaceNames[parts[2]] = Math.Abs(index); } - - if (IsIP4Enabled) - { - _interfaceAddresses.AddItem(IPNetAddress.IP4Loopback); - } - - if (IsIP6Enabled) - { - _interfaceAddresses.AddItem(IPNetAddress.IP6Loopback); - } } InitialiseLAN(config); @@ -990,7 +980,6 @@ namespace Jellyfin.Networking.Manager // Read and parse bind addresses and exclusions, removing ones that don't exist. _bindAddresses = CreateIPCollection(lanAddresses).ThatAreContainedInNetworks(_interfaceAddresses); _bindExclusions = CreateIPCollection(lanAddresses, true).ThatAreContainedInNetworks(_interfaceAddresses); - _logger.LogInformation("Using bind addresses: {0}", _bindAddresses.AsString()); _logger.LogInformation("Using bind exclusions: {0}", _bindExclusions.AsString()); } @@ -1038,17 +1027,14 @@ namespace Jellyfin.Networking.Manager // Subnets are the same as the calculated internal interface. _lanSubnets = new Collection(); - // We must listen on loopback for LiveTV to function regardless of the settings. if (IsIP6Enabled) { - _lanSubnets.AddItem(IPNetAddress.IP6Loopback); _lanSubnets.AddItem(IPNetAddress.Parse("fc00::/7")); // ULA _lanSubnets.AddItem(IPNetAddress.Parse("fe80::/10")); // Site local } if (IsIP4Enabled) { - _lanSubnets.AddItem(IPNetAddress.IP4Loopback); _lanSubnets.AddItem(IPNetAddress.Parse("10.0.0.0/8")); _lanSubnets.AddItem(IPNetAddress.Parse("172.16.0.0/12")); _lanSubnets.AddItem(IPNetAddress.Parse("192.168.0.0/16")); @@ -1056,17 +1042,6 @@ namespace Jellyfin.Networking.Manager } else { - // We must listen on loopback for LiveTV to function regardless of the settings. - if (IsIP6Enabled) - { - _lanSubnets.AddItem(IPNetAddress.IP6Loopback); - } - - if (IsIP4Enabled) - { - _lanSubnets.AddItem(IPNetAddress.IP4Loopback); - } - // Internal interfaces must be private, not excluded and part of the LocalNetworkSubnet. _internalInterfaces = CreateCollection(_interfaceAddresses.Where(i => IsInLocalNetwork(i))); } diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 6a65a8e47a..a284dcecab 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -88,11 +88,10 @@ namespace MediaBrowser.Controller string GetSmartApiUrl(string hostname, int? port = null); /// - /// Gets a localhost URL that can be used to access the API using the loop-back IP address. - /// over HTTP (not HTTPS). + /// Gets an URL that can be used to access the API over HTTP (not HTTPS). /// /// The API URL. - string GetLoopbackHttpApiUrl(); + string GetInterfaceHttpApiUrl(); /// /// Gets a local (LAN) URL that can be used to access the API. diff --git a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs index f203f9b429..53c17bfb13 100644 --- a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs +++ b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs @@ -35,9 +35,9 @@ namespace Jellyfin.Networking.Tests // eth16 only [InlineData("192.168.1.208/24,-16,eth16|200.200.200.200/24,11,eth11", "192.168.1.0/24", "[192.168.1.208/24]")] // All interfaces excluded. (including loopbacks) - [InlineData("192.168.1.208/24,-16,vEthernet1|192.168.2.208/24,-16,vEthernet212|200.200.200.200/24,11,eth11", "192.168.1.0/24", "[127.0.0.1/8,::1/128]")] + [InlineData("192.168.1.208/24,-16,vEthernet1|192.168.2.208/24,-16,vEthernet212|200.200.200.200/24,11,eth11", "192.168.1.0/24", "[]")] // vEthernet1 and vEthernet212 should be excluded. - [InlineData("192.168.1.200/24,-20,vEthernet1|192.168.2.208/24,-16,vEthernet212|200.200.200.200/24,11,eth11", "192.168.1.0/24;200.200.200.200/24", "[200.200.200.200/24,127.0.0.1/8,::1/128]")] + [InlineData("192.168.1.200/24,-20,vEthernet1|192.168.2.208/24,-16,vEthernet212|200.200.200.200/24,11,eth11", "192.168.1.0/24;200.200.200.200/24", "[200.200.200.200/24]")] // Overlapping interface, [InlineData("192.168.1.110/24,-20,br0|192.168.1.10/24,-16,br0|200.200.200.200/24,11,eth11", "192.168.1.0/24", "[192.168.1.110/24,192.168.1.10/24]")] public void IgnoreVirtualInterfaces(string interfaces, string lan, string value) -- cgit v1.2.3 From 7ff52bf755b6bed22ecef8d22fafacfce83890b7 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Mon, 3 May 2021 19:30:56 +0100 Subject: Renamed --- Emby.Server.Implementations/ApplicationHost.cs | 21 ++++----------------- Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/LiveTvMediaSourceProvider.cs | 2 +- .../TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 2 +- .../LiveTv/TunerHosts/SharedHttpStream.cs | 2 +- MediaBrowser.Controller/IServerApplicationHost.cs | 2 +- 6 files changed, 9 insertions(+), 22 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index bd2bb54bdc..b94036533f 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1201,25 +1201,12 @@ namespace Emby.Server.Implementations } /// - public string GetInterfaceHttpApiUrl() + public string GetUrlForUseByHttpApi() { - // Published server ends with a / - if (!string.IsNullOrEmpty(PublishedServerUrl)) - { - // Published server ends with a '/', so we need to remove it. - return PublishedServerUrl.Trim('/'); - } - - var bind = NetManager.GetInternalBindAddresses().FirstOrDefault() ?? new IPNetAddress(IPAddress.None); + var bind = NetManager.GetInternalBindAddresses().FirstOrDefault() ?? + NetManager.GetAllBindInterfaces(true).FirstOrDefault(); - string smart = NetManager.GetBindInterface(bind, out var port); - // If the smartAPI doesn't start with http then treat it as a host or ip. - if (smart.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - return smart.Trim('/'); - } - - return GetLocalApiUrl(smart.Trim('/'), null, port); + return GetLocalApiUrl(bind.Address.ToString(), Uri.UriSchemeHttp); } /// diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index d61f74dd23..c580a6ebfb 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1031,7 +1031,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var stream = new MediaSourceInfo { - EncoderPath = _appHost.GetInterfaceHttpApiUrl() + "/LiveTv/LiveRecordings/" + info.Id + "/stream", + EncoderPath = _appHost.GetUrlForUseByHttpApi() + "/LiveTv/LiveRecordings/" + info.Id + "/stream", EncoderProtocol = MediaProtocol.Http, Path = info.Path, Protocol = MediaProtocol.File, diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index b5f0b2118c..09a8563158 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.LiveTv // Dummy this up so that direct play checks can still run if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) { - source.Path = _appHost.GetInterfaceHttpApiUrl(); + source.Path = _appHost.GetUrlForUseByHttpApi(); } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index d6ea320ead..6404ba19c7 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -148,7 +148,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun // OpenedMediaSource.Path = tempFile; // OpenedMediaSource.ReadAtNativeFramerate = true; - MediaSource.Path = _appHost.GetInterfaceHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; + MediaSource.Path = _appHost.GetUrlForUseByHttpApi() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; MediaSource.Protocol = MediaProtocol.Http; // OpenedMediaSource.SupportsDirectPlay = false; // OpenedMediaSource.SupportsDirectStream = true; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index b9a567e40a..23c8d8dd5c 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -97,7 +97,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts // OpenedMediaSource.Path = tempFile; // OpenedMediaSource.ReadAtNativeFramerate = true; - MediaSource.Path = _appHost.GetInterfaceHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; + MediaSource.Path = _appHost.GetUrlForUseByHttpApi() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; MediaSource.Protocol = MediaProtocol.Http; // OpenedMediaSource.Path = TempFilePath; diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index a284dcecab..d054e2a19e 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -91,7 +91,7 @@ namespace MediaBrowser.Controller /// Gets an URL that can be used to access the API over HTTP (not HTTPS). /// /// The API URL. - string GetInterfaceHttpApiUrl(); + string GetUrlForUseByHttpApi(); /// /// Gets a local (LAN) URL that can be used to access the API. -- cgit v1.2.3 From 417a7011c7b5fe4a5ca5ce7c0b61c14f15bc748b Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Tue, 4 May 2021 16:32:17 +0100 Subject: changed to first --- Emby.Server.Implementations/ApplicationHost.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index b94036533f..ce24e933d7 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1203,8 +1203,9 @@ namespace Emby.Server.Implementations /// public string GetUrlForUseByHttpApi() { + // GetBindInterfaces will return an interface. var bind = NetManager.GetInternalBindAddresses().FirstOrDefault() ?? - NetManager.GetAllBindInterfaces(true).FirstOrDefault(); + NetManager.GetAllBindInterfaces(true).First(); return GetLocalApiUrl(bind.Address.ToString(), Uri.UriSchemeHttp); } -- cgit v1.2.3 From 95988ce33dccd36cb5d4e82a83ef8e4b3bc2382b Mon Sep 17 00:00:00 2001 From: Deathspike Date: Tue, 17 Aug 2021 20:10:15 +0200 Subject: Fix embedded subtitles taking priority over external ones --- .../Library/MediaStreamSelector.cs | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index b833122ea0..71e3404d07 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -57,14 +57,18 @@ namespace Emby.Server.Implementations.Library { // Prefer embedded metadata over smart logic - stream = streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => s.IsForced) ?? - streams.FirstOrDefault(s => s.IsDefault); + stream = streams.FirstOrDefault(s => s.IsExternal && s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? + streams.FirstOrDefault(s => s.IsExternal && s.IsForced) ?? + streams.FirstOrDefault(s => s.IsExternal && s.IsDefault) ?? + streams.FirstOrDefault(s => s.IsExternal) ?? + streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? + streams.FirstOrDefault(s => s.IsForced) ?? + streams.FirstOrDefault(s => s.IsDefault); // if the audio language is not understood by the user, load their preferred subs, if there are any if (stream == null && !preferredLanguages.Contains(audioTrackLanguage, StringComparer.OrdinalIgnoreCase)) { - stream = streams.Where(s => !s.IsForced).FirstOrDefault(s => preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); + stream = streams.FirstOrDefault(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); } } else if (mode == SubtitlePlaybackMode.Smart) @@ -74,24 +78,30 @@ namespace Emby.Server.Implementations.Library // if the audio language is not understood by the user, load their preferred subs, if there are any if (!preferredLanguages.Contains(audioTrackLanguage, StringComparer.OrdinalIgnoreCase)) { - stream = streams.Where(s => !s.IsForced).FirstOrDefault(s => preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); + stream = streams.FirstOrDefault(s => s.IsExternal && !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)) ?? + streams.FirstOrDefault(s => s.IsExternal && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)) ?? + streams.FirstOrDefault(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)) ?? + streams.FirstOrDefault(s => preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); } } else if (mode == SubtitlePlaybackMode.Always) { // always load the most suitable full subtitles - stream = streams.FirstOrDefault(s => !s.IsForced); + stream = streams.FirstOrDefault(s => s.IsExternal && !s.IsForced) ?? + streams.FirstOrDefault(s => !s.IsForced); } else if (mode == SubtitlePlaybackMode.OnlyForced) { // always load the most suitable full subtitles - stream = streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => s.IsForced); + stream = streams.FirstOrDefault(s => s.IsExternal && s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? + streams.FirstOrDefault(s => s.IsExternal && s.IsForced) ?? + streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? + streams.FirstOrDefault(s => s.IsForced); } // load forced subs if we have found no suitable full subtitles - stream ??= streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)); + stream ??= streams.FirstOrDefault(s => s.IsExternal && s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? + streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)); if (stream != null) { -- cgit v1.2.3 From 47be1bf69f62d72ecf81cc95347f3c8c5a6a5174 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Fri, 3 Sep 2021 10:59:40 -0600 Subject: Enable nullable for SchedulesDirect --- .../LiveTv/Listings/SchedulesDirect.cs | 22 ++++------ .../Listings/SchedulesDirectDtos/BroadcasterDto.cs | 10 ++--- .../Listings/SchedulesDirectDtos/CaptionDto.cs | 6 +-- .../LiveTv/Listings/SchedulesDirectDtos/CastDto.cs | 14 +++---- .../Listings/SchedulesDirectDtos/ChannelDto.cs | 9 ++-- .../SchedulesDirectDtos/ContentRatingDto.cs | 6 +-- .../LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs | 12 +++--- .../LiveTv/Listings/SchedulesDirectDtos/DayDto.cs | 17 ++------ .../SchedulesDirectDtos/Description1000Dto.cs | 6 +-- .../SchedulesDirectDtos/Description100Dto.cs | 6 +-- .../SchedulesDirectDtos/DescriptionsProgramDto.cs | 7 ++-- .../SchedulesDirectDtos/EventDetailsDto.cs | 4 +- .../Listings/SchedulesDirectDtos/GracenoteDto.cs | 2 - .../Listings/SchedulesDirectDtos/HeadendsDto.cs | 11 +++-- .../Listings/SchedulesDirectDtos/ImageDataDto.cs | 22 +++++----- .../Listings/SchedulesDirectDtos/LineupDto.cs | 12 +++--- .../Listings/SchedulesDirectDtos/LineupsDto.cs | 9 ++-- .../LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs | 6 +-- .../LiveTv/Listings/SchedulesDirectDtos/MapDto.cs | 8 ++-- .../Listings/SchedulesDirectDtos/MetadataDto.cs | 8 ++-- .../SchedulesDirectDtos/MetadataProgramsDto.cs | 4 +- .../SchedulesDirectDtos/MetadataScheduleDto.cs | 10 ++--- .../Listings/SchedulesDirectDtos/MovieDto.cs | 7 ++-- .../Listings/SchedulesDirectDtos/MultipartDto.cs | 2 - .../SchedulesDirectDtos/ProgramDetailsDto.cs | 49 +++++++++++----------- .../Listings/SchedulesDirectDtos/ProgramDto.cs | 21 +++++----- .../SchedulesDirectDtos/QualityRatingDto.cs | 12 +++--- .../Listings/SchedulesDirectDtos/RatingDto.cs | 6 +-- .../SchedulesDirectDtos/RecommendationDto.cs | 6 +-- .../RequestScheduleForChannelDto.cs | 7 ++-- .../Listings/SchedulesDirectDtos/ShowImagesDto.cs | 7 ++-- .../Listings/SchedulesDirectDtos/StationDto.cs | 19 ++++----- .../Listings/SchedulesDirectDtos/TitleDto.cs | 4 +- .../Listings/SchedulesDirectDtos/TokenDto.cs | 15 ++++--- 34 files changed, 153 insertions(+), 213 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 8125ed57df..41c3bafa06 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -16,7 +16,6 @@ using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos; using Jellyfin.Extensions.Json; -using MediaBrowser.Common; using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Cryptography; @@ -34,7 +33,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1); - private readonly IApplicationHost _appHost; private readonly ICryptoProvider _cryptoProvider; private readonly ConcurrentDictionary _tokens = new ConcurrentDictionary(); @@ -44,12 +42,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings public SchedulesDirect( ILogger logger, IHttpClientFactory httpClientFactory, - IApplicationHost appHost, ICryptoProvider cryptoProvider) { _logger = logger; _httpClientFactory = httpClientFactory; - _appHost = appHost; _cryptoProvider = cryptoProvider; } @@ -120,8 +116,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs"); programRequestOptions.Headers.TryAddWithoutValidation("token", token); - var programsID = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct(); - programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programsID) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json); + var programIds = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct(); + programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programIds) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json); using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false); await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); @@ -225,21 +221,21 @@ namespace Emby.Server.Implementations.LiveTv.Listings string newID = programId + "T" + startAt.Ticks + "C" + channelId; - if (programInfo.AudioProperties != null) + if (programInfo.AudioProperties.Count != 0) { - if (programInfo.AudioProperties.Exists(item => string.Equals(item, "atmos", StringComparison.OrdinalIgnoreCase))) + if (programInfo.AudioProperties.Contains("atmos", StringComparer.OrdinalIgnoreCase)) { audioType = ProgramAudio.Atmos; } - else if (programInfo.AudioProperties.Exists(item => string.Equals(item, "dd 5.1", StringComparison.OrdinalIgnoreCase))) + else if (programInfo.AudioProperties.Contains("dd 5.1", StringComparer.OrdinalIgnoreCase)) { audioType = ProgramAudio.DolbyDigital; } - else if (programInfo.AudioProperties.Exists(item => string.Equals(item, "dd", StringComparison.OrdinalIgnoreCase))) + else if (programInfo.AudioProperties.Contains("dd", StringComparer.OrdinalIgnoreCase)) { audioType = ProgramAudio.DolbyDigital; } - else if (programInfo.AudioProperties.Exists(item => string.Equals(item, "stereo", StringComparison.OrdinalIgnoreCase))) + else if (programInfo.AudioProperties.Contains("stereo", StringComparer.OrdinalIgnoreCase)) { audioType = ProgramAudio.Stereo; } @@ -520,7 +516,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings lineups.Add(new NameIdPair { Name = string.IsNullOrWhiteSpace(lineup.Name) ? lineup.Lineup : lineup.Name, - Id = lineup.Uri[18..] + Id = lineup.Uri?[18..] }); } } @@ -790,7 +786,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { var channelNumber = GetChannelNumber(channel); - var station = allStations.Find(item => string.Equals(item.StationId, channel.StationId, StringComparison.OrdinalIgnoreCase)) + var station = allStations.FirstOrDefault(item => string.Equals(item.StationId, channel.StationId, StringComparison.OrdinalIgnoreCase)) ?? new StationDto { StationId = channel.StationId diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs index b881b307c3..95ac996e01 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,24 +11,24 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the city. /// [JsonPropertyName("city")] - public string City { get; set; } + public string? City { get; set; } /// /// Gets or sets the state. /// [JsonPropertyName("state")] - public string State { get; set; } + public string? State { get; set; } /// /// Gets or sets the postal code. /// [JsonPropertyName("postalCode")] - public string Postalcode { get; set; } + public string? Postalcode { get; set; } /// /// Gets or sets the country. /// [JsonPropertyName("country")] - public string Country { get; set; } + public string? Country { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs index 96b67d1eb3..f6251b9ad8 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the content. /// [JsonPropertyName("content")] - public string Content { get; set; } + public string? Content { get; set; } /// /// Gets or sets the lang. /// [JsonPropertyName("lang")] - public string Lang { get; set; } + public string? Lang { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs index dac6f5f3e0..0b7a2c63ad 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,36 +11,36 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the billing order. /// [JsonPropertyName("billingOrder")] - public string BillingOrder { get; set; } + public string? BillingOrder { get; set; } /// /// Gets or sets the role. /// [JsonPropertyName("role")] - public string Role { get; set; } + public string? Role { get; set; } /// /// Gets or sets the name id. /// [JsonPropertyName("nameId")] - public string NameId { get; set; } + public string? NameId { get; set; } /// /// Gets or sets the person id. /// [JsonPropertyName("personId")] - public string PersonId { get; set; } + public string? PersonId { get; set; } /// /// Gets or sets the name. /// [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets or sets the character name. /// [JsonPropertyName("characterName")] - public string CharacterName { get; set; } + public string? CharacterName { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs index 8c9c2c1fcc..87c327ed82 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,18 +13,18 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the list of maps. /// [JsonPropertyName("map")] - public List Map { get; set; } + public IReadOnlyList Map { get; set; } = Array.Empty(); /// /// Gets or sets the list of stations. /// [JsonPropertyName("stations")] - public List Stations { get; set; } + public IReadOnlyList Stations { get; set; } = Array.Empty(); /// /// Gets or sets the metadata. /// [JsonPropertyName("metadata")] - public MetadataDto Metadata { get; set; } + public MetadataDto? Metadata { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs index 135b5bb08b..c19cd2e48d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the body. /// [JsonPropertyName("body")] - public string Body { get; set; } + public string? Body { get; set; } /// /// Gets or sets the code. /// [JsonPropertyName("code")] - public string Code { get; set; } + public string? Code { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs index 82d1001c88..f00c9accdd 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,30 +11,30 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the billing order. /// [JsonPropertyName("billingOrder")] - public string BillingOrder { get; set; } + public string? BillingOrder { get; set; } /// /// Gets or sets the role. /// [JsonPropertyName("role")] - public string Role { get; set; } + public string? Role { get; set; } /// /// Gets or sets the name id. /// [JsonPropertyName("nameId")] - public string NameId { get; set; } + public string? NameId { get; set; } /// /// Gets or sets the person id. /// [JsonPropertyName("personId")] - public string PersonId { get; set; } + public string? PersonId { get; set; } /// /// Gets or sets the name. /// [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs index 68876b0686..1a371965cf 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -10,30 +9,22 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// public class DayDto { - /// - /// Initializes a new instance of the class. - /// - public DayDto() - { - Programs = new List(); - } - /// /// Gets or sets the station id. /// [JsonPropertyName("stationID")] - public string StationId { get; set; } + public string? StationId { get; set; } /// /// Gets or sets the list of programs. /// [JsonPropertyName("programs")] - public List Programs { get; set; } + public IReadOnlyList Programs { get; set; } = Array.Empty(); /// /// Gets or sets the metadata schedule. /// [JsonPropertyName("metadata")] - public MetadataScheduleDto Metadata { get; set; } + public MetadataScheduleDto? Metadata { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs index d3e6ff3935..ca6ae7fb13 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the description language. /// [JsonPropertyName("descriptionLanguage")] - public string DescriptionLanguage { get; set; } + public string? DescriptionLanguage { get; set; } /// /// Gets or sets the description. /// [JsonPropertyName("description")] - public string Description { get; set; } + public string? Description { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs index 04360266c9..1577219ed2 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the description language. /// [JsonPropertyName("descriptionLanguage")] - public string DescriptionLanguage { get; set; } + public string? DescriptionLanguage { get; set; } /// /// Gets or sets the description. /// [JsonPropertyName("description")] - public string Description { get; set; } + public string? Description { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs index 3af36ae965..eaf4a340bd 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,12 +13,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the list of description 100. /// [JsonPropertyName("description100")] - public List Description100 { get; set; } + public IReadOnlyList Description100 { get; set; } = Array.Empty(); /// /// Gets or sets the list of description1000. /// [JsonPropertyName("description1000")] - public List Description1000 { get; set; } + public IReadOnlyList Description1000 { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs index c3b2bd9c13..fbdfb1f716 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,6 +11,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the sub type. /// [JsonPropertyName("subType")] - public string SubType { get; set; } + public string? SubType { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs index 3d8bea362a..6852d89d71 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs index 1fb3decb23..b9844562f3 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,24 +13,24 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the headend. /// [JsonPropertyName("headend")] - public string Headend { get; set; } + public string? Headend { get; set; } /// /// Gets or sets the transport. /// [JsonPropertyName("transport")] - public string Transport { get; set; } + public string? Transport { get; set; } /// /// Gets or sets the location. /// [JsonPropertyName("location")] - public string Location { get; set; } + public string? Location { get; set; } /// /// Gets or sets the list of lineups. /// [JsonPropertyName("lineups")] - public List Lineups { get; set; } + public IReadOnlyList Lineups { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs index 912e680dd7..7e554ff1ce 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,60 +11,60 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the width. /// [JsonPropertyName("width")] - public string Width { get; set; } + public string? Width { get; set; } /// /// Gets or sets the height. /// [JsonPropertyName("height")] - public string Height { get; set; } + public string? Height { get; set; } /// /// Gets or sets the uri. /// [JsonPropertyName("uri")] - public string Uri { get; set; } + public string? Uri { get; set; } /// /// Gets or sets the size. /// [JsonPropertyName("size")] - public string Size { get; set; } + public string? Size { get; set; } /// /// Gets or sets the aspect. /// [JsonPropertyName("aspect")] - public string aspect { get; set; } + public string? aspect { get; set; } /// /// Gets or sets the category. /// [JsonPropertyName("category")] - public string Category { get; set; } + public string? Category { get; set; } /// /// Gets or sets the text. /// [JsonPropertyName("text")] - public string Text { get; set; } + public string? Text { get; set; } /// /// Gets or sets the primary. /// [JsonPropertyName("primary")] - public string Primary { get; set; } + public string? Primary { get; set; } /// /// Gets or sets the tier. /// [JsonPropertyName("tier")] - public string Tier { get; set; } + public string? Tier { get; set; } /// /// Gets or sets the caption. /// [JsonPropertyName("caption")] - public CaptionDto Caption { get; set; } + public CaptionDto? Caption { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs index 52e920aa61..676e745258 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,30 +11,30 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the linup. /// [JsonPropertyName("lineup")] - public string Lineup { get; set; } + public string? Lineup { get; set; } /// /// Gets or sets the lineup name. /// [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets or sets the transport. /// [JsonPropertyName("transport")] - public string Transport { get; set; } + public string? Transport { get; set; } /// /// Gets or sets the location. /// [JsonPropertyName("location")] - public string Location { get; set; } + public string? Location { get; set; } /// /// Gets or sets the uri. /// [JsonPropertyName("uri")] - public string Uri { get; set; } + public string? Uri { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs index 15139ba3b2..b0ee0ac8eb 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -20,18 +19,18 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the server id. /// [JsonPropertyName("serverID")] - public string ServerId { get; set; } + public string? ServerId { get; set; } /// /// Gets or sets the datetime. /// [JsonPropertyName("datetime")] - public string Datetime { get; set; } + public string? Datetime { get; set; } /// /// Gets or sets the list of lineups. /// [JsonPropertyName("lineups")] - public List Lineups { get; set; } + public IReadOnlyList Lineups { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs index 7b235ed7f6..fecc55e037 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,7 +11,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the url. /// [JsonPropertyName("URL")] - public string Url { get; set; } + public string? Url { get; set; } /// /// Gets or sets the height. @@ -31,6 +29,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the md5. /// [JsonPropertyName("md5")] - public string Md5 { get; set; } + public string? Md5 { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs index 5140277b2c..cc1841c176 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,19 +11,19 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the station id. /// [JsonPropertyName("stationID")] - public string StationId { get; set; } + public string? StationId { get; set; } /// /// Gets or sets the channel. /// [JsonPropertyName("channel")] - public string Channel { get; set; } + public string? Channel { get; set; } /// /// Gets or sets the logical channel number. /// [JsonPropertyName("logicalChannelNumber")] - public string LogicalChannelNumber { get; set; } + public string? LogicalChannelNumber { get; set; } /// /// Gets or sets the uhfvhf. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs index 5a3893a35f..40faa493c5 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,18 +11,18 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the linup. /// [JsonPropertyName("lineup")] - public string Lineup { get; set; } + public string? Lineup { get; set; } /// /// Gets or sets the modified timestamp. /// [JsonPropertyName("modified")] - public string Modified { get; set; } + public string? Modified { get; set; } /// /// Gets or sets the transport. /// [JsonPropertyName("transport")] - public string Transport { get; set; } + public string? Transport { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs index 4057e98024..843ef9091d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,6 +11,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the gracenote object. /// [JsonPropertyName("gracenote")] - public GracenoteDto Gracenote { get; set; } + public GracenoteDto? Gracenote { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs index 4979296da4..68fbeec46d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,25 +11,25 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the modified timestamp. /// [JsonPropertyName("modified")] - public string Modified { get; set; } + public string? Modified { get; set; } /// /// Gets or sets the md5. /// [JsonPropertyName("md5")] - public string Md5 { get; set; } + public string? Md5 { get; set; } /// /// Gets or sets the start date. /// [JsonPropertyName("startDate")] - public string StartDate { get; set; } + public string? StartDate { get; set; } /// /// Gets or sets the end date. /// [JsonPropertyName("endDate")] - public string EndDate { get; set; } + public string? EndDate { get; set; } /// /// Gets or sets the days count. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs index 48d731d890..31bef423b2 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,7 +13,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the year. /// [JsonPropertyName("year")] - public string Year { get; set; } + public string? Year { get; set; } /// /// Gets or sets the duration. @@ -26,6 +25,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the list of quality rating. /// [JsonPropertyName("qualityRating")] - public List QualityRating { get; set; } + public IReadOnlyList QualityRating { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs index 42eddfff26..e8b15dc07c 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs index a84c47c129..bfaed1e081 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,85 +13,85 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the audience. /// [JsonPropertyName("audience")] - public string Audience { get; set; } + public string? Audience { get; set; } /// /// Gets or sets the program id. /// [JsonPropertyName("programID")] - public string ProgramId { get; set; } + public string? ProgramId { get; set; } /// /// Gets or sets the list of titles. /// [JsonPropertyName("titles")] - public List Titles { get; set; } + public IReadOnlyList Titles { get; set; } = Array.Empty(); /// /// Gets or sets the event details object. /// [JsonPropertyName("eventDetails")] - public EventDetailsDto EventDetails { get; set; } + public EventDetailsDto? EventDetails { get; set; } /// /// Gets or sets the descriptions. /// [JsonPropertyName("descriptions")] - public DescriptionsProgramDto Descriptions { get; set; } + public DescriptionsProgramDto? Descriptions { get; set; } /// /// Gets or sets the original air date. /// [JsonPropertyName("originalAirDate")] - public string OriginalAirDate { get; set; } + public string? OriginalAirDate { get; set; } /// /// Gets or sets the list of genres. /// [JsonPropertyName("genres")] - public List Genres { get; set; } + public IReadOnlyList Genres { get; set; } = Array.Empty(); /// /// Gets or sets the episode title. /// [JsonPropertyName("episodeTitle150")] - public string EpisodeTitle150 { get; set; } + public string? EpisodeTitle150 { get; set; } /// /// Gets or sets the list of metadata. /// [JsonPropertyName("metadata")] - public List Metadata { get; set; } + public IReadOnlyList Metadata { get; set; } = Array.Empty(); /// /// Gets or sets the list of content raitings. /// [JsonPropertyName("contentRating")] - public List ContentRating { get; set; } + public IReadOnlyList ContentRating { get; set; } = Array.Empty(); /// /// Gets or sets the list of cast. /// [JsonPropertyName("cast")] - public List Cast { get; set; } + public IReadOnlyList Cast { get; set; } = Array.Empty(); /// /// Gets or sets the list of crew. /// [JsonPropertyName("crew")] - public List Crew { get; set; } + public IReadOnlyList Crew { get; set; } = Array.Empty(); /// /// Gets or sets the entity type. /// [JsonPropertyName("entityType")] - public string EntityType { get; set; } + public string? EntityType { get; set; } /// /// Gets or sets the show type. /// [JsonPropertyName("showType")] - public string ShowType { get; set; } + public string? ShowType { get; set; } /// /// Gets or sets a value indicating whether there is image artwork. @@ -104,54 +103,54 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the primary image. /// [JsonPropertyName("primaryImage")] - public string PrimaryImage { get; set; } + public string? PrimaryImage { get; set; } /// /// Gets or sets the thumb image. /// [JsonPropertyName("thumbImage")] - public string ThumbImage { get; set; } + public string? ThumbImage { get; set; } /// /// Gets or sets the backdrop image. /// [JsonPropertyName("backdropImage")] - public string BackdropImage { get; set; } + public string? BackdropImage { get; set; } /// /// Gets or sets the banner image. /// [JsonPropertyName("bannerImage")] - public string BannerImage { get; set; } + public string? BannerImage { get; set; } /// /// Gets or sets the image id. /// [JsonPropertyName("imageID")] - public string ImageId { get; set; } + public string? ImageId { get; set; } /// /// Gets or sets the md5. /// [JsonPropertyName("md5")] - public string Md5 { get; set; } + public string? Md5 { get; set; } /// /// Gets or sets the list of content advisory. /// [JsonPropertyName("contentAdvisory")] - public List ContentAdvisory { get; set; } + public IReadOnlyList ContentAdvisory { get; set; } = Array.Empty(); /// /// Gets or sets the movie object. /// [JsonPropertyName("movie")] - public MovieDto Movie { get; set; } + public MovieDto? Movie { get; set; } /// /// Gets or sets the list of recommendations. /// [JsonPropertyName("recommendations")] - public List Recommendations { get; set; } + public IReadOnlyList Recommendations { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs index ad5389100c..ff039c1cf1 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,13 +13,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the program id. /// [JsonPropertyName("programID")] - public string ProgramId { get; set; } + public string? ProgramId { get; set; } /// /// Gets or sets the air date time. /// [JsonPropertyName("airDateTime")] - public string AirDateTime { get; set; } + public string? AirDateTime { get; set; } /// /// Gets or sets the duration. @@ -32,25 +31,25 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the md5. /// [JsonPropertyName("md5")] - public string Md5 { get; set; } + public string? Md5 { get; set; } /// /// Gets or sets the list of audio properties. /// [JsonPropertyName("audioProperties")] - public List AudioProperties { get; set; } + public IReadOnlyList AudioProperties { get; set; } = Array.Empty(); /// /// Gets or sets the list of video properties. /// [JsonPropertyName("videoProperties")] - public List VideoProperties { get; set; } + public IReadOnlyList VideoProperties { get; set; } = Array.Empty(); /// /// Gets or sets the list of ratings. /// [JsonPropertyName("ratings")] - public List Ratings { get; set; } + public IReadOnlyList Ratings { get; set; } = Array.Empty(); /// /// Gets or sets a value indicating whether this program is new. @@ -62,13 +61,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the multipart object. /// [JsonPropertyName("multipart")] - public MultipartDto Multipart { get; set; } + public MultipartDto? Multipart { get; set; } /// /// Gets or sets the live tape delay. /// [JsonPropertyName("liveTapeDelay")] - public string LiveTapeDelay { get; set; } + public string? LiveTapeDelay { get; set; } /// /// Gets or sets a value indicating whether this is the premiere. @@ -86,6 +85,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the premiere or finale. /// [JsonPropertyName("isPremiereOrFinale")] - public string IsPremiereOrFinale { get; set; } + public string? IsPremiereOrFinale { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs index 5cd0a74595..c5ddcf7c51 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,30 +11,30 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the ratings body. /// [JsonPropertyName("ratingsBody")] - public string RatingsBody { get; set; } + public string? RatingsBody { get; set; } /// /// Gets or sets the rating. /// [JsonPropertyName("rating")] - public string Rating { get; set; } + public string? Rating { get; set; } /// /// Gets or sets the min rating. /// [JsonPropertyName("minRating")] - public string MinRating { get; set; } + public string? MinRating { get; set; } /// /// Gets or sets the max rating. /// [JsonPropertyName("maxRating")] - public string MaxRating { get; set; } + public string? MaxRating { get; set; } /// /// Gets or sets the increment. /// [JsonPropertyName("increment")] - public string Increment { get; set; } + public string? Increment { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs index 948b831446..e04b619a4d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the body. /// [JsonPropertyName("body")] - public string Body { get; set; } + public string? Body { get; set; } /// /// Gets or sets the code. /// [JsonPropertyName("code")] - public string Code { get; set; } + public string? Code { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs index 1308f45ce7..c8f79fd1c2 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,12 +11,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the program id. /// [JsonPropertyName("programID")] - public string ProgramId { get; set; } + public string? ProgramId { get; set; } /// /// Gets or sets the title. /// [JsonPropertyName("title120")] - public string Title120 { get; set; } + public string? Title120 { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs index fb7a31ac85..0cd05709b3 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,12 +13,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the station id. /// [JsonPropertyName("stationID")] - public string StationId { get; set; } + public string? StationId { get; set; } /// /// Gets or sets the list of dates. /// [JsonPropertyName("date")] - public List Date { get; set; } + public IReadOnlyList Date { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs index 34302370d6..84e224b71e 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,12 +13,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the program id. /// [JsonPropertyName("programID")] - public string ProgramId { get; set; } + public string? ProgramId { get; set; } /// /// Gets or sets the list of data. /// [JsonPropertyName("data")] - public List Data { get; set; } + public IReadOnlyList Data { get; set; } = Array.Empty(); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs index 12f3576c65..1b76b22e32 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -14,49 +13,49 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the station id. /// [JsonPropertyName("stationID")] - public string StationId { get; set; } + public string? StationId { get; set; } /// /// Gets or sets the name. /// [JsonPropertyName("name")] - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets or sets the callsign. /// [JsonPropertyName("callsign")] - public string Callsign { get; set; } + public string? Callsign { get; set; } /// /// Gets or sets the broadcast language. /// [JsonPropertyName("broadcastLanguage")] - public List BroadcastLanguage { get; set; } + public IReadOnlyList BroadcastLanguage { get; set; } = Array.Empty(); /// /// Gets or sets the description language. /// [JsonPropertyName("descriptionLanguage")] - public List DescriptionLanguage { get; set; } + public IReadOnlyList DescriptionLanguage { get; set; } = Array.Empty(); /// /// Gets or sets the broadcaster. /// [JsonPropertyName("broadcaster")] - public BroadcasterDto Broadcaster { get; set; } + public BroadcasterDto? Broadcaster { get; set; } /// /// Gets or sets the affiliate. /// [JsonPropertyName("affiliate")] - public string Affiliate { get; set; } + public string? Affiliate { get; set; } /// /// Gets or sets the logo. /// [JsonPropertyName("logo")] - public LogoDto Logo { get; set; } + public LogoDto? Logo { get; set; } /// /// Gets or set a value indicating whether it is commercial free. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs index 06c95524b0..61cd4a9b00 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs @@ -1,5 +1,3 @@ -#nullable disable - using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -13,6 +11,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the title. /// [JsonPropertyName("title120")] - public string Title120 { get; set; } + public string? Title120 { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs index c3ec1c7d61..fb5ed95ac9 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs @@ -1,5 +1,4 @@ -#nullable disable - +using System; using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -19,18 +18,24 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the response message. /// [JsonPropertyName("message")] - public string Message { get; set; } + public string? Message { get; set; } /// /// Gets or sets the server id. /// [JsonPropertyName("serverID")] - public string ServerId { get; set; } + public string? ServerId { get; set; } /// /// Gets or sets the token. /// [JsonPropertyName("token")] - public string Token { get; set; } + public string? Token { get; set; } + + /// + /// Gets or sets the current datetime. + /// + [JsonPropertyName("datetime")] + public DateTime? DateTime { get; set; } } } -- cgit v1.2.3 From 47e24a2cf77e6c3fe50eb5398fa56950a047ed7b Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Fri, 3 Sep 2021 12:35:52 -0600 Subject: Add SchedulesDirect json tests --- .../LiveTv/Listings/SchedulesDirect.cs | 62 +++--- .../Listings/SchedulesDirectDtos/ImageDataDto.cs | 2 +- .../Listings/SchedulesDirectDtos/LineupDto.cs | 6 + .../Listings/SchedulesDirectDtos/LineupsDto.cs | 2 +- .../LiveTv/Listings/SchedulesDirectDtos/MapDto.cs | 12 + .../SchedulesDirectDtos/MetadataProgramsDto.cs | 2 +- .../SchedulesDirectDtos/ProgramDetailsDto.cs | 2 +- .../Listings/SchedulesDirectDtos/ProgramDto.cs | 2 +- .../Listings/SchedulesDirectDtos/TokenDto.cs | 6 + .../Jellyfin.Server.Implementations.Tests.csproj | 3 + .../SchedulesDirectDeserializeTests.cs | 245 +++++++++++++++++++++ .../TestData/headends_response.json | 113 ++++++++++ .../SchedulesDirect/TestData/lineup_response.json | 18 ++ .../SchedulesDirect/TestData/lineups_response.json | 40 ++++ .../TestData/metadata_programs_response.json | 51 +++++ .../TestData/programs_response.json | 245 +++++++++++++++++++++ .../TestData/schedules_request.json | 16 ++ .../TestData/schedules_response.json | 35 +++ .../TestData/token_live_response.json | 7 + .../TestData/token_offline_response.json | 8 + 20 files changed, 841 insertions(+), 36 deletions(-) create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 41c3bafa06..e8562b8c57 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -9,12 +9,14 @@ using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Json; using System.Net.Mime; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos; +using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; @@ -110,19 +112,19 @@ namespace Emby.Server.Implementations.LiveTv.Listings options.Headers.TryAddWithoutValidation("token", token); using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); + var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); + _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules!.Count, channelId); using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs"); programRequestOptions.Headers.TryAddWithoutValidation("token", token); var programIds = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct(); - programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programIds) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json); + programRequestOptions.Content = new StringContent(JsonSerializer.Serialize(programIds), Encoding.UTF8, MediaTypeNames.Application.Json); using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false); await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - var programDict = programDetails.ToDictionary(p => p.ProgramId, y => y); + var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); + var programDict = programDetails!.ToDictionary(p => p.ProgramId, y => y); var programIdsWithImages = programDetails .Where(p => p.HasImageArtwork).Select(p => p.ProgramId) @@ -138,6 +140,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings // schedule.ProgramId + " which says it has images? " + // programDict[schedule.ProgramId].hasImageArtwork); + if (string.IsNullOrEmpty(schedule.ProgramId)) + { + continue; + } + if (images != null) { var imageIndex = images.FindIndex(i => i.ProgramId == schedule.ProgramId[..10]); @@ -145,7 +152,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { var programEntry = programDict[schedule.ProgramId]; - var allImages = images[imageIndex].Data ?? new List(); + var allImages = images[imageIndex].Data; var imagesWithText = allImages.Where(i => string.Equals(i.Text, "yes", StringComparison.OrdinalIgnoreCase)); var imagesWithoutText = allImages.Where(i => string.Equals(i.Text, "no", StringComparison.OrdinalIgnoreCase)); @@ -213,7 +220,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings private ProgramInfo GetProgram(string channelId, ProgramDto programInfo, ProgramDetailsDto details) { - var startAt = GetDate(programInfo.AirDateTime); + if (programInfo.AirDateTime == null) + { + return null; + } + + var startAt = programInfo.AirDateTime.Value; var endAt = startAt.AddSeconds(programInfo.Duration); var audioType = ProgramAudio.Stereo; @@ -351,9 +363,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings } } - if (!string.IsNullOrWhiteSpace(details.OriginalAirDate)) + if (details.OriginalAirDate != null) { - info.OriginalAirDate = DateTime.Parse(details.OriginalAirDate, CultureInfo.InvariantCulture); + info.OriginalAirDate = details.OriginalAirDate; info.ProductionYear = info.OriginalAirDate.Value.Year; } @@ -380,18 +392,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings return info; } - private static DateTime GetDate(string value) - { - var date = DateTime.ParseExact(value, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.InvariantCulture); - - if (date.Kind != DateTimeKind.Utc) - { - date = DateTime.SpecifyKind(date, DateTimeKind.Utc); - } - - return date; - } - private string GetProgramImage(string apiUrl, IEnumerable images, bool returnDefaultImage, double desiredAspect) { var match = images @@ -445,14 +445,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings return result; } - private async Task> GetImageForPrograms( + private async Task> GetImageForPrograms( ListingsProviderInfo info, IReadOnlyList programIds, CancellationToken cancellationToken) { if (programIds.Count == 0) { - return new List(); + return Array.Empty(); } StringBuilder str = new StringBuilder("[", 1 + (programIds.Count * 13)); @@ -476,13 +476,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings { using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false); await using var response = await innerResponse2.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - return await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); + return await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.LogError(ex, "Error getting image info from schedules direct"); - return new List(); + return Array.Empty(); } } @@ -505,7 +505,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false); await using var response = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); if (root != null) { @@ -647,7 +647,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - if (string.Equals(root.Message, "OK", StringComparison.Ordinal)) + if (string.Equals(root?.Message, "OK", StringComparison.Ordinal)) { _logger.LogInformation("Authenticated with Schedules Direct token: {Token}", root.Token); return root.Token; @@ -704,12 +704,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = httpResponse.Content; var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - return root.Lineups.Any(i => string.Equals(info.ListingsId, i.Lineup, StringComparison.OrdinalIgnoreCase)); + return root?.Lineups.Any(i => string.Equals(info.ListingsId, i.Lineup, StringComparison.OrdinalIgnoreCase)) ?? false; } catch (HttpRequestException ex) { // SchedulesDirect returns 400 if no lineups are configured. - if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest) + if (ex.StatusCode is HttpStatusCode.BadRequest) { return false; } @@ -775,10 +775,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.Map.Count); + _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root!.Map.Count); _logger.LogInformation("Mapping Stations to Channel"); - var allStations = root.Stations ?? new List(); + var allStations = root.Stations; var map = root.Map; var list = new List(map.Count); diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs index 7e554ff1ce..a1ae3ca6d4 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs @@ -35,7 +35,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the aspect. /// [JsonPropertyName("aspect")] - public string? aspect { get; set; } + public string? Aspect { get; set; } /// /// Gets or sets the category. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs index 676e745258..3dc64e5d8a 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs @@ -36,5 +36,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// [JsonPropertyName("uri")] public string? Uri { get; set; } + + /// + /// Gets or sets a value indicating whether this lineup was deleted. + /// + [JsonPropertyName("isDeleted")] + public bool? IsDeleted { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs index b0ee0ac8eb..a635c59870 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs @@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the datetime. /// [JsonPropertyName("datetime")] - public string? Datetime { get; set; } + public DateTime? Datetime { get; set; } /// /// Gets or sets the list of lineups. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs index cc1841c176..2420307b4f 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs @@ -19,6 +19,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos [JsonPropertyName("channel")] public string? Channel { get; set; } + /// + /// Gets or sets the provider callsign. + /// + [JsonPropertyName("providerCallsign")] + public string? ProvderCallsign { get; set; } + /// /// Gets or sets the logical channel number. /// @@ -42,5 +48,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// [JsonPropertyName("atscMinor")] public int AtscMinor { get; set; } + + /// + /// Gets or sets the match type. + /// + [JsonPropertyName("matchType")] + public string? MatchType { get;set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs index 843ef9091d..43f2901566 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs @@ -10,7 +10,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// /// Gets or sets the gracenote object. /// - [JsonPropertyName("gracenote")] + [JsonPropertyName("Gracenote")] public GracenoteDto? Gracenote { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs index bfaed1e081..84c48f67f3 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs @@ -43,7 +43,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the original air date. /// [JsonPropertyName("originalAirDate")] - public string? OriginalAirDate { get; set; } + public DateTime? OriginalAirDate { get; set; } /// /// Gets or sets the list of genres. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs index ff039c1cf1..60389b45bf 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs @@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the air date time. /// [JsonPropertyName("airDateTime")] - public string? AirDateTime { get; set; } + public DateTime? AirDateTime { get; set; } /// /// Gets or sets the duration. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs index fb5ed95ac9..561f79c5af 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs @@ -37,5 +37,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// [JsonPropertyName("datetime")] public DateTime? DateTime { get; set; } + + /// + /// Gets or sets the response message. + /// + [JsonPropertyName("response")] + public string? Response { get; set; } } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index 9b6ab7bdf5..e02e357ca0 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -16,6 +16,9 @@ PreserveNewest + + PreserveNewest + diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs new file mode 100644 index 0000000000..84ac3ea477 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos; +using Jellyfin.Extensions.Json; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect +{ + public class SchedulesDirectDeserializeTests + { + private readonly JsonSerializerOptions _jsonOptions; + + public SchedulesDirectDeserializeTests() + { + _jsonOptions = JsonDefaults.Options; + } + + /// + /// /token reponse. + /// + [Fact] + public void Deserialize_Token_Response_Live_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/token_live_response.json"); + var tokenDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(tokenDto); + Assert.Equal(0, tokenDto!.Code); + Assert.Equal("OK", tokenDto.Message); + Assert.Equal("AWS-SD-web.1", tokenDto.ServerId); + Assert.Equal(new DateTime(2016, 08, 23, 13, 55, 25, DateTimeKind.Utc), tokenDto.DateTime); + Assert.Equal("f3fca79989cafe7dead71beefedc812b", tokenDto.Token); + } + + /// + /// /token response. + /// + [Fact] + public void Deserialize_Token_Response_Offline_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/token_offline_response.json"); + var tokenDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(tokenDto); + Assert.Equal(3_000, tokenDto!.Code); + Assert.Equal("Server offline for maintenance.", tokenDto.Message); + Assert.Equal("20141201.web.1", tokenDto.ServerId); + Assert.Equal(new DateTime(2015, 04, 23, 00, 03, 32, DateTimeKind.Utc), tokenDto.DateTime); + Assert.Equal("CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE", tokenDto.Token); + Assert.Equal("SERVICE_OFFLINE", tokenDto.Response); + } + + /// + /// /schedules request. + /// + [Fact] + public void Serialize_Schedule_Request_Success() + { + var expectedString = File.ReadAllText("LiveTv/SchedulesDirect/TestData/schedules_request.json").Trim(); + + var requestObject = new RequestScheduleForChannelDto[] + { + new RequestScheduleForChannelDto + { + StationId = "20454", + Date = new[] + { + "2015-03-13", + "2015-03-17" + } + }, + new RequestScheduleForChannelDto + { + StationId = "10021", + Date = new[] + { + "2015-03-12", + "2015-03-13" + } + } + }; + + var jsonOptions = new JsonSerializerOptions(_jsonOptions) + { + WriteIndented = true + }; + + var requestString = JsonSerializer.Serialize(requestObject, jsonOptions); + Assert.Equal(expectedString, requestString); + } + + /// + /// /schedules response. + /// + [Fact] + public void Deserialize_Schedule_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/schedules_response.json"); + var days = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(days); + Assert.Equal(1, days!.Count); + + var dayDto = days[0]; + Assert.Equal("20454", dayDto.StationId); + Assert.Equal(2, dayDto.Programs.Count); + + Assert.Equal("SH005371070000", dayDto.Programs[0].ProgramId); + Assert.Equal(new DateTime(2015, 03, 03, 00, 00, 00, DateTimeKind.Utc), dayDto.Programs[0].AirDateTime); + Assert.Equal(1_800, dayDto.Programs[0].Duration); + Assert.Equal("Sy8HEMBPcuiAx3FBukUhKQ", dayDto.Programs[0].Md5); + Assert.True(dayDto.Programs[0].New); + Assert.Equal(2, dayDto.Programs[0].AudioProperties.Count); + Assert.Equal("stereo", dayDto.Programs[0].AudioProperties[0]); + Assert.Equal("cc", dayDto.Programs[0].AudioProperties[1]); + Assert.Equal(1, dayDto.Programs[0].VideoProperties.Count); + Assert.Equal("hdtv", dayDto.Programs[0].VideoProperties[0]); + } + + /// + /// /programs response. + /// + [Fact] + public void Deserialize_Program_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/programs_response.json"); + var programDtos = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(programDtos); + Assert.Equal(2, programDtos!.Count); + Assert.Equal("EP000000060003", programDtos[0].ProgramId); + Assert.Equal(1, programDtos[0].Titles.Count); + Assert.Equal("'Allo 'Allo!", programDtos[0].Titles[0].Title120); + Assert.Equal("Series", programDtos[0].EventDetails?.SubType); + Assert.Equal("en", programDtos[0].Descriptions?.Description1000[0].DescriptionLanguage); + Assert.Equal("A disguised British Intelligence officer is sent to help the airmen.", programDtos[0].Descriptions?.Description1000[0].Description); + Assert.Equal(new DateTime(1985, 11, 04), programDtos[0].OriginalAirDate); + Assert.Equal(1, programDtos[0].Genres.Count); + Assert.Equal("Sitcom", programDtos[0].Genres[0]); + Assert.Equal("The Poloceman Cometh", programDtos[0].EpisodeTitle150); + Assert.Equal(2, programDtos[0].Metadata[0].Gracenote?.Season); + Assert.Equal(3, programDtos[0].Metadata[0].Gracenote?.Episode); + Assert.Equal(13, programDtos[0].Cast.Count); + Assert.Equal("383774", programDtos[0].Cast[0].PersonId); + Assert.Equal("392649", programDtos[0].Cast[0].NameId); + Assert.Equal("Gorden Kaye", programDtos[0].Cast[0].Name); + Assert.Equal("Actor", programDtos[0].Cast[0].Role); + Assert.Equal("01", programDtos[0].Cast[0].BillingOrder); + Assert.Equal(3, programDtos[0].Crew.Count); + Assert.Equal("354407", programDtos[0].Crew[0].PersonId); + Assert.Equal("363281", programDtos[0].Crew[0].NameId); + Assert.Equal("David Croft", programDtos[0].Crew[0].Name); + Assert.Equal("Director", programDtos[0].Crew[0].Role); + Assert.Equal("01", programDtos[0].Crew[0].BillingOrder); + } + + /// + /// /metadata/programs response. + /// + [Fact] + public void Deserialize_Metadata_Programs_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/metadata_programs_response.json"); + var showImagesDtos = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(showImagesDtos); + Assert.Equal(1, showImagesDtos!.Count); + Assert.Equal("SH00712240", showImagesDtos[0].ProgramId); + Assert.Equal(4, showImagesDtos[0].Data.Count); + Assert.Equal("135", showImagesDtos[0].Data[0].Width); + Assert.Equal("180", showImagesDtos[0].Data[0].Height); + Assert.Equal("assets/p282288_b_v2_aa.jpg", showImagesDtos[0].Data[0].Uri); + Assert.Equal("Sm", showImagesDtos[0].Data[0].Size); + Assert.Equal("3x4", showImagesDtos[0].Data[0].Aspect); + Assert.Equal("Banner-L3", showImagesDtos[0].Data[0].Category); + Assert.Equal("yes", showImagesDtos[0].Data[0].Text); + Assert.Equal("true", showImagesDtos[0].Data[0].Primary); + Assert.Equal("Series", showImagesDtos[0].Data[0].Tier); + } + + /// + /// /headends response. + /// + [Fact] + public void Deserialize_Headends_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/headends_response.json"); + var headendsDtos = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(headendsDtos); + Assert.Equal(8, headendsDtos!.Count); + Assert.Equal("CA00053", headendsDtos[0].Headend); + Assert.Equal("Cable", headendsDtos[0].Transport); + Assert.Equal("Beverly Hills", headendsDtos[0].Location); + Assert.Equal(2, headendsDtos[0].Lineups.Count); + Assert.Equal("Time Warner Cable - Cable", headendsDtos[0].Lineups[0].Name); + Assert.Equal("USA-CA00053-DEFAULT", headendsDtos[0].Lineups[0].Lineup); + Assert.Equal("/20141201/lineups/USA-CA00053-DEFAULT", headendsDtos[0].Lineups[0].Uri); + } + + /// + /// /lineups response. + /// + [Fact] + public void Deserialize_Lineups_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/lineups_response.json"); + var lineupsDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(lineupsDto); + Assert.Equal(0, lineupsDto!.Code); + Assert.Equal("20141201.web.1", lineupsDto.ServerId); + Assert.Equal(new DateTime(2015, 04, 17, 14, 22, 17, DateTimeKind.Utc), lineupsDto.Datetime); + Assert.Equal(5, lineupsDto.Lineups.Count); + Assert.Equal("GBR-0001317-DEFAULT", lineupsDto.Lineups[0].Lineup); + Assert.Equal("Freeview - Carlton - LWT (Southeast)", lineupsDto.Lineups[0].Name); + Assert.Equal("DVB-T", lineupsDto.Lineups[0].Transport); + Assert.Equal("London", lineupsDto.Lineups[0].Location); + Assert.Equal("/20141201/lineups/GBR-0001317-DEFAULT", lineupsDto.Lineups[0].Uri); + + Assert.Equal("DELETED LINEUP", lineupsDto.Lineups[4].Name); + Assert.True(lineupsDto.Lineups[4].IsDeleted); + } + + /// + /// /lineup/:id response. + /// + [Fact] + public void Deserialize_Lineup_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/lineup_response.json"); + var channelDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(channelDto); + Assert.Equal(2, channelDto!.Map.Count); + Assert.Equal("24326", channelDto.Map[0].StationId); + Assert.Equal("001", channelDto.Map[0].Channel); + Assert.Equal("BBC ONE South", channelDto.Map[0].ProvderCallsign); + Assert.Equal("1", channelDto.Map[0].LogicalChannelNumber); + Assert.Equal("providerCallsign", channelDto.Map[0].MatchType); + } + } +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json new file mode 100644 index 0000000000..a1a96cf87a --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json @@ -0,0 +1,113 @@ +[ + { + "headend": "CA00053", + "transport": "Cable", + "location": "Beverly Hills", + "lineups": [ + { + "name": "Time Warner Cable - Cable", + "lineup": "USA-CA00053-DEFAULT", + "uri": "/20141201/lineups/USA-CA00053-DEFAULT" + }, + { + "name": "Time Warner Cable - Digital", + "lineup": "USA-CA00053-X", + "uri": "/20141201/lineups/USA-CA00053-X" + } + ] + }, + { + "headend": "CA61222", + "transport": "Cable", + "location": "Beverly Hills", + "lineups": [ + { + "name": "Mulholland Estates - Cable", + "lineup": "USA-CA61222-DEFAULT", + "uri": "/20141201/lineups/USA-CA61222-DEFAULT" + } + ] + }, + { + "headend": "CA66511", + "transport": "Cable", + "location": "Los Angeles", + "lineups": [ + { + "name": "AT&T U-verse TV - Digital", + "lineup": "USA-CA66511-X", + "uri": "/20141201/lineups/USA-CA66511-X" + } + ] + }, + { + "headend": "CA67309", + "transport": "Cable", + "location": "Westchester", + "lineups": [ + { + "name": "Time Warner Cable Sherman Oaks - Cable", + "lineup": "USA-CA67309-DEFAULT", + "uri": "/20141201/lineups/USA-CA67309-DEFAULT" + }, + { + "name": "Time Warner Cable Sherman Oaks - Digital", + "lineup": "USA-CA67309-X", + "uri": "/20141201/lineups/USA-CA67309-X" + } + ] + }, + { + "headend": "CA67310", + "transport": "Cable", + "location": "Eagle Rock", + "lineups": [ + { + "name": "Time Warner Cable City of Los Angeles - Cable", + "lineup": "USA-CA67310-DEFAULT", + "uri": "/20141201/lineups/USA-CA67310-DEFAULT" + }, + { + "name": "Time Warner Cable City of Los Angeles - Digital", + "lineup": "USA-CA67310-X", + "uri": "/20141201/lineups/USA-CA67310-X" + } + ] + }, + { + "headend": "DISH803", + "transport": "Satellite", + "location": "Los Angeles", + "lineups": [ + { + "name": "DISH Los Angeles - Satellite", + "lineup": "USA-DISH803-DEFAULT", + "uri": "/20141201/lineups/USA-DISH803-DEFAULT" + } + ] + }, + { + "headend": "DITV803", + "transport": "Satellite", + "location": "Los Angeles", + "lineups": [ + { + "name": "DIRECTV Los Angeles - Satellite", + "lineup": "USA-DITV803-DEFAULT", + "uri": "/20141201/lineups/USA-DITV803-DEFAULT" + } + ] + }, + { + "headend": "90210", + "transport": "Antenna", + "location": "90210", + "lineups": [ + { + "name": "Antenna", + "lineup": "USA-OTA-90210", + "uri": "/20141201/lineups/USA-OTA-90210" + } + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json new file mode 100644 index 0000000000..5c5e36e301 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json @@ -0,0 +1,18 @@ +{ + "map": [ + { + "stationID": "24326", + "channel": "001", + "providerCallsign": "BBC ONE South", + "logicalChannelNumber": "1", + "matchType": "providerCallsign" + }, + { + "stationID": "17154", + "channel": "002", + "providerCallsign": "BBC TWO", + "logicalChannelNumber": "2", + "matchType": "providerCallsign" + } + ] +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json new file mode 100644 index 0000000000..257b682eef --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json @@ -0,0 +1,40 @@ +{ + "code": 0, + "serverID": "20141201.web.1", + "datetime": "2015-04-17T14:22:17Z", + "lineups": [ + { + "lineup": "GBR-0001317-DEFAULT", + "name": "Freeview - Carlton - LWT (Southeast)", + "transport": "DVB-T", + "location": "London", + "uri": "/20141201/lineups/GBR-0001317-DEFAULT" + }, + { + "lineup": "USA-IL57303-X", + "name": "Comcast Waukegan/Lake Forest Area - Digital", + "transport": "Cable", + "location": "Lake Forest", + "uri": "/20141201/lineups/USA-IL57303-X" + }, + { + "lineup": "USA-NY67791-X", + "name": "Verizon Fios Queens - Digital", + "transport": "Cable", + "location": "Fresh Meadows", + "uri": "/20141201/lineups/USA-NY67791-X" + }, + { + "lineup": "USA-OTA-60030", + "name": "Local Over the Air Broadcast", + "transport": "Antenna", + "location": "60030", + "uri": "/20141201/lineups/USA-OTA-60030" + }, + { + "lineup": "USA-WI61859-DEFAULT", + "name": "DELETED LINEUP", + "isDeleted": true + } + ] +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json new file mode 100644 index 0000000000..b75e777b48 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json @@ -0,0 +1,51 @@ +[ + { + "programID": "SH00712240", + "data": [ + { + "width": "135", + "height": "180", + "uri": "assets/p282288_b_v2_aa.jpg", + "size": "Sm", + "aspect": "3x4", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + }, + { + "width": "720", + "height": "540", + "uri": "assets/p282288_b_h6_aa.jpg", + "size": "Lg", + "aspect": "4x3", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + }, + { + "width": "960", + "height": "1440", + "uri": "assets/p282288_b_v8_aa.jpg", + "size": "Ms", + "aspect": "2x3", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + }, + { + "width": "180", + "height": "135", + "uri": "assets/p282288_b_h5_aa.jpg", + "size": "Sm", + "aspect": "4x3", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + } + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json new file mode 100644 index 0000000000..154c02f973 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json @@ -0,0 +1,245 @@ +[ + { + "programID": "EP000000060003", + "titles": [{ + "title120": "'Allo 'Allo!" + }], + "eventDetails": { + "subType": "Series" + }, + "descriptions": { + "description1000": [{ + "descriptionLanguage": "en", + "description": "A disguised British Intelligence officer is sent to help the airmen." + }] + }, + "originalAirDate": "1985-11-04", + "genres": ["Sitcom"], + "episodeTitle150": "The Poloceman Cometh", + "metadata": [{ + "Gracenote": { + "season": 2, + "episode": 3 + } + }], + "cast": [{ + "personId": "383774", + "nameId": "392649", + "name": "Gorden Kaye", + "role": "Actor", + "billingOrder": "01" + }, { + "personId": "246840", + "nameId": "250387", + "name": "Carmen Silvera", + "role": "Actor", + "billingOrder": "02" + }, { + "personId": "376955", + "nameId": "385830", + "name": "Rose Hill", + "role": "Actor", + "billingOrder": "03" + }, { + "personId": "259773", + "nameId": "263340", + "name": "Vicki Michelle", + "role": "Actor", + "billingOrder": "04" + }, { + "personId": "353113", + "nameId": "361987", + "name": "Kirsten Cooke", + "role": "Actor", + "billingOrder": "05" + }, { + "personId": "77787", + "nameId": "77787", + "name": "Richard Marner", + "role": "Actor", + "billingOrder": "06" + }, { + "personId": "230921", + "nameId": "234193", + "name": "Guy Siner", + "role": "Actor", + "billingOrder": "07" + }, { + "personId": "374934", + "nameId": "383809", + "name": "Kim Hartman", + "role": "Actor", + "billingOrder": "08" + }, { + "personId": "369151", + "nameId": "378026", + "name": "Richard Gibson", + "role": "Actor", + "billingOrder": "09" + }, { + "personId": "343690", + "nameId": "352564", + "name": "Arthur Bostrom", + "role": "Actor", + "billingOrder": "10" + }, { + "personId": "352557", + "nameId": "361431", + "name": "John D. Collins", + "role": "Actor", + "billingOrder": "11" + }, { + "personId": "605275", + "nameId": "627734", + "name": "Nicholas Frankau", + "role": "Actor", + "billingOrder": "12" + }, { + "personId": "373394", + "nameId": "382269", + "name": "Jack Haig", + "role": "Actor", + "billingOrder": "13" + }], + "crew": [{ + "personId": "354407", + "nameId": "363281", + "name": "David Croft", + "role": "Director", + "billingOrder": "01" + }, { + "personId": "354407", + "nameId": "363281", + "name": "David Croft", + "role": "Writer", + "billingOrder": "02" + }, { + "personId": "105145", + "nameId": "105145", + "name": "Jeremy Lloyd", + "role": "Writer", + "billingOrder": "03" + }], + "showType": "Series", + "hasImageArtwork": true, + "md5": "Jo5NKxoo44xRvBCAq8QT2A" + }, + { + "programID": "EP000000510142", + "titles": [{ + "title120": "A Different World" + }], + "eventDetails": { + "subType": "Series" + }, + "descriptions": { + "description1000": [{ + "descriptionLanguage": "en", + "description": "Whitley and Dwayne tell new students about their honeymoon in Los Angeles." + }] + }, + "originalAirDate": "1992-09-24", + "genres": ["Sitcom"], + "episodeTitle150": "Honeymoon in L.A.", + "metadata": [{ + "Gracenote": { + "season": 6, + "episode": 1 + } + }], + "cast": [{ + "personId": "700", + "nameId": "700", + "name": "Jasmine Guy", + "role": "Actor", + "billingOrder": "01" + }, { + "personId": "729", + "nameId": "729", + "name": "Kadeem Hardison", + "role": "Actor", + "billingOrder": "02" + }, { + "personId": "120", + "nameId": "120", + "name": "Darryl M. Bell", + "role": "Actor", + "billingOrder": "03" + }, { + "personId": "1729", + "nameId": "1729", + "name": "Cree Summer", + "role": "Actor", + "billingOrder": "04" + }, { + "personId": "217", + "nameId": "217", + "name": "Charnele Brown", + "role": "Actor", + "billingOrder": "05" + }, { + "personId": "1811", + "nameId": "1811", + "name": "Glynn Turman", + "role": "Actor", + "billingOrder": "06" + }, { + "personId": "1232", + "nameId": "1232", + "name": "Lou Myers", + "role": "Actor", + "billingOrder": "07" + }, { + "personId": "1363", + "nameId": "1363", + "name": "Jada Pinkett", + "role": "Guest Star", + "billingOrder": "08" + }, { + "personId": "222967", + "nameId": "225536", + "name": "Ajai Sanders", + "role": "Guest Star", + "billingOrder": "09" + }, { + "personId": "181744", + "nameId": "183292", + "name": "Karen Malina White", + "role": "Guest Star", + "billingOrder": "10" + }, { + "personId": "305017", + "nameId": "318897", + "name": "Patrick Y. Malone", + "role": "Guest Star", + "billingOrder": "11" + }, { + "personId": "9841", + "nameId": "9841", + "name": "Bumper Robinson", + "role": "Guest Star", + "billingOrder": "12" + }, { + "personId": "426422", + "nameId": "435297", + "name": "Sister Souljah", + "role": "Guest Star", + "billingOrder": "13" + }, { + "personId": "25", + "nameId": "25", + "name": "Debbie Allen", + "role": "Guest Star", + "billingOrder": "14" + }, { + "personId": "668", + "nameId": "668", + "name": "Gilbert Gottfried", + "role": "Guest Star", + "billingOrder": "15" + }], + "showType": "Series", + "hasImageArtwork": true, + "md5": "P5kz0QmCeYxIA+yL0H4DWw" + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json new file mode 100644 index 0000000000..72248921ae --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json @@ -0,0 +1,16 @@ +[ + { + "stationID": "20454", + "date": [ + "2015-03-13", + "2015-03-17" + ] + }, + { + "stationID": "10021", + "date": [ + "2015-03-12", + "2015-03-13" + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json new file mode 100644 index 0000000000..f474f3aff2 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json @@ -0,0 +1,35 @@ +[ + { + "stationID": "20454", + "programs": [ + { + "programID": "SH005371070000", + "airDateTime": "2015-03-03T00:00:00Z", + "duration": 1800, + "md5": "Sy8HEMBPcuiAx3FBukUhKQ", + "new": true, + "audioProperties": [ + "stereo", + "cc" + ], + "videoProperties": [ + "hdtv" + ] + }, + { + "programID": "EP000014577244", + "airDateTime": "2015-03-03T00:30:00Z", + "duration": 1800, + "md5": "25DNXVXO192JI7Y9vSW9lQ", + "new": true, + "audioProperties": [ + "stereo", + "cc" + ], + "videoProperties": [ + "hdtv" + ] + } + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json new file mode 100644 index 0000000000..73b0a54c4e --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json @@ -0,0 +1,7 @@ +{ + "code": 0, + "message": "OK", + "serverID": "AWS-SD-web.1", + "datetime": "2016-08-23T13:55:25Z", + "token": "f3fca79989cafe7dead71beefedc812b" +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json new file mode 100644 index 0000000000..b630c24041 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json @@ -0,0 +1,8 @@ +{ + "response": "SERVICE_OFFLINE", + "code": 3000, + "serverID": "20141201.web.1", + "message": "Server offline for maintenance.", + "datetime": "2015-04-23T00:03:32Z", + "token": "CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE" +} -- cgit v1.2.3 From 0587b539ec899c35b5bea73801d5007575f86b94 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Fri, 3 Sep 2021 13:36:07 -0600 Subject: Suggestions from review --- .../LiveTv/Listings/SchedulesDirect.cs | 25 ++- .../Jellyfin.Server.Implementations.Tests.csproj | 3 - .../SchedulesDirectDeserializeTests.cs | 25 +-- .../TestData/headends_response.json | 113 ---------- .../SchedulesDirect/TestData/lineup_response.json | 18 -- .../SchedulesDirect/TestData/lineups_response.json | 40 ---- .../TestData/metadata_programs_response.json | 51 ----- .../TestData/programs_response.json | 245 --------------------- .../TestData/schedules_request.json | 16 -- .../TestData/schedules_response.json | 35 --- .../TestData/token_live_response.json | 7 - .../TestData/token_offline_response.json | 8 - .../SchedulesDirect/headends_response.json | 1 + .../Test Data/SchedulesDirect/lineup_response.json | 1 + .../SchedulesDirect/lineups_response.json | 1 + .../metadata_programs_response.json | 1 + .../SchedulesDirect/programs_response.json | 1 + .../SchedulesDirect/schedules_request.json | 1 + .../SchedulesDirect/schedules_response.json | 1 + .../SchedulesDirect/token_live_response.json | 1 + .../SchedulesDirect/token_offline_response.json | 1 + 21 files changed, 40 insertions(+), 555 deletions(-) delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index e8562b8c57..6686b625f4 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -9,6 +9,7 @@ using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Net.Http.Json; using System.Net.Mime; using System.Text; @@ -113,18 +114,29 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules!.Count, channelId); + if (dailySchedules == null) + { + return Array.Empty(); + } + + _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs"); programRequestOptions.Headers.TryAddWithoutValidation("token", token); var programIds = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct(); - programRequestOptions.Content = new StringContent(JsonSerializer.Serialize(programIds), Encoding.UTF8, MediaTypeNames.Application.Json); + programRequestOptions.Content = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(programIds, _jsonOptions)); + programRequestOptions.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(MediaTypeNames.Application.Json); using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false); await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - var programDict = programDetails!.ToDictionary(p => p.ProgramId, y => y); + if (programDetails == null) + { + return Array.Empty(); + } + + var programDict = programDetails.ToDictionary(p => p.ProgramId, y => y); var programIdsWithImages = programDetails .Where(p => p.HasImageArtwork).Select(p => p.ProgramId) @@ -775,7 +787,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root!.Map.Count); + if (root == null) + { + return new List(); + } + + _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.Map.Count); _logger.LogInformation("Mapping Stations to Channel"); var allStations = root.Stations; diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index e02e357ca0..9b6ab7bdf5 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -16,9 +16,6 @@ PreserveNewest - - PreserveNewest - diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs index 84ac3ea477..ab08e22ab1 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Token_Response_Live_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/token_live_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/token_live_response.json"); var tokenDto = JsonSerializer.Deserialize(bytes); Assert.NotNull(tokenDto); @@ -40,7 +40,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Token_Response_Offline_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/token_offline_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/token_offline_response.json"); var tokenDto = JsonSerializer.Deserialize(bytes); Assert.NotNull(tokenDto); @@ -58,7 +58,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Serialize_Schedule_Request_Success() { - var expectedString = File.ReadAllText("LiveTv/SchedulesDirect/TestData/schedules_request.json").Trim(); + var expectedString = File.ReadAllText("Test Data/SchedulesDirect/schedules_request.json").Trim(); var requestObject = new RequestScheduleForChannelDto[] { @@ -82,12 +82,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect } }; - var jsonOptions = new JsonSerializerOptions(_jsonOptions) - { - WriteIndented = true - }; - - var requestString = JsonSerializer.Serialize(requestObject, jsonOptions); + var requestString = JsonSerializer.Serialize(requestObject, _jsonOptions); Assert.Equal(expectedString, requestString); } @@ -97,7 +92,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Schedule_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/schedules_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/schedules_response.json"); var days = JsonSerializer.Deserialize>(bytes); Assert.NotNull(days); @@ -125,7 +120,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Program_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/programs_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/programs_response.json"); var programDtos = JsonSerializer.Deserialize>(bytes); Assert.NotNull(programDtos); @@ -162,7 +157,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Metadata_Programs_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/metadata_programs_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/metadata_programs_response.json"); var showImagesDtos = JsonSerializer.Deserialize>(bytes); Assert.NotNull(showImagesDtos); @@ -186,7 +181,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Headends_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/headends_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/headends_response.json"); var headendsDtos = JsonSerializer.Deserialize>(bytes); Assert.NotNull(headendsDtos); @@ -206,7 +201,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Lineups_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/lineups_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/lineups_response.json"); var lineupsDto = JsonSerializer.Deserialize(bytes); Assert.NotNull(lineupsDto); @@ -230,7 +225,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect [Fact] public void Deserialize_Lineup_Response_Success() { - var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/lineup_response.json"); + var bytes = File.ReadAllBytes("Test Data/SchedulesDirect/lineup_response.json"); var channelDto = JsonSerializer.Deserialize(bytes); Assert.NotNull(channelDto); diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json deleted file mode 100644 index a1a96cf87a..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json +++ /dev/null @@ -1,113 +0,0 @@ -[ - { - "headend": "CA00053", - "transport": "Cable", - "location": "Beverly Hills", - "lineups": [ - { - "name": "Time Warner Cable - Cable", - "lineup": "USA-CA00053-DEFAULT", - "uri": "/20141201/lineups/USA-CA00053-DEFAULT" - }, - { - "name": "Time Warner Cable - Digital", - "lineup": "USA-CA00053-X", - "uri": "/20141201/lineups/USA-CA00053-X" - } - ] - }, - { - "headend": "CA61222", - "transport": "Cable", - "location": "Beverly Hills", - "lineups": [ - { - "name": "Mulholland Estates - Cable", - "lineup": "USA-CA61222-DEFAULT", - "uri": "/20141201/lineups/USA-CA61222-DEFAULT" - } - ] - }, - { - "headend": "CA66511", - "transport": "Cable", - "location": "Los Angeles", - "lineups": [ - { - "name": "AT&T U-verse TV - Digital", - "lineup": "USA-CA66511-X", - "uri": "/20141201/lineups/USA-CA66511-X" - } - ] - }, - { - "headend": "CA67309", - "transport": "Cable", - "location": "Westchester", - "lineups": [ - { - "name": "Time Warner Cable Sherman Oaks - Cable", - "lineup": "USA-CA67309-DEFAULT", - "uri": "/20141201/lineups/USA-CA67309-DEFAULT" - }, - { - "name": "Time Warner Cable Sherman Oaks - Digital", - "lineup": "USA-CA67309-X", - "uri": "/20141201/lineups/USA-CA67309-X" - } - ] - }, - { - "headend": "CA67310", - "transport": "Cable", - "location": "Eagle Rock", - "lineups": [ - { - "name": "Time Warner Cable City of Los Angeles - Cable", - "lineup": "USA-CA67310-DEFAULT", - "uri": "/20141201/lineups/USA-CA67310-DEFAULT" - }, - { - "name": "Time Warner Cable City of Los Angeles - Digital", - "lineup": "USA-CA67310-X", - "uri": "/20141201/lineups/USA-CA67310-X" - } - ] - }, - { - "headend": "DISH803", - "transport": "Satellite", - "location": "Los Angeles", - "lineups": [ - { - "name": "DISH Los Angeles - Satellite", - "lineup": "USA-DISH803-DEFAULT", - "uri": "/20141201/lineups/USA-DISH803-DEFAULT" - } - ] - }, - { - "headend": "DITV803", - "transport": "Satellite", - "location": "Los Angeles", - "lineups": [ - { - "name": "DIRECTV Los Angeles - Satellite", - "lineup": "USA-DITV803-DEFAULT", - "uri": "/20141201/lineups/USA-DITV803-DEFAULT" - } - ] - }, - { - "headend": "90210", - "transport": "Antenna", - "location": "90210", - "lineups": [ - { - "name": "Antenna", - "lineup": "USA-OTA-90210", - "uri": "/20141201/lineups/USA-OTA-90210" - } - ] - } -] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json deleted file mode 100644 index 5c5e36e301..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "map": [ - { - "stationID": "24326", - "channel": "001", - "providerCallsign": "BBC ONE South", - "logicalChannelNumber": "1", - "matchType": "providerCallsign" - }, - { - "stationID": "17154", - "channel": "002", - "providerCallsign": "BBC TWO", - "logicalChannelNumber": "2", - "matchType": "providerCallsign" - } - ] -} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json deleted file mode 100644 index 257b682eef..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "code": 0, - "serverID": "20141201.web.1", - "datetime": "2015-04-17T14:22:17Z", - "lineups": [ - { - "lineup": "GBR-0001317-DEFAULT", - "name": "Freeview - Carlton - LWT (Southeast)", - "transport": "DVB-T", - "location": "London", - "uri": "/20141201/lineups/GBR-0001317-DEFAULT" - }, - { - "lineup": "USA-IL57303-X", - "name": "Comcast Waukegan/Lake Forest Area - Digital", - "transport": "Cable", - "location": "Lake Forest", - "uri": "/20141201/lineups/USA-IL57303-X" - }, - { - "lineup": "USA-NY67791-X", - "name": "Verizon Fios Queens - Digital", - "transport": "Cable", - "location": "Fresh Meadows", - "uri": "/20141201/lineups/USA-NY67791-X" - }, - { - "lineup": "USA-OTA-60030", - "name": "Local Over the Air Broadcast", - "transport": "Antenna", - "location": "60030", - "uri": "/20141201/lineups/USA-OTA-60030" - }, - { - "lineup": "USA-WI61859-DEFAULT", - "name": "DELETED LINEUP", - "isDeleted": true - } - ] -} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json deleted file mode 100644 index b75e777b48..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json +++ /dev/null @@ -1,51 +0,0 @@ -[ - { - "programID": "SH00712240", - "data": [ - { - "width": "135", - "height": "180", - "uri": "assets/p282288_b_v2_aa.jpg", - "size": "Sm", - "aspect": "3x4", - "category": "Banner-L3", - "text": "yes", - "primary": "true", - "tier": "Series" - }, - { - "width": "720", - "height": "540", - "uri": "assets/p282288_b_h6_aa.jpg", - "size": "Lg", - "aspect": "4x3", - "category": "Banner-L3", - "text": "yes", - "primary": "true", - "tier": "Series" - }, - { - "width": "960", - "height": "1440", - "uri": "assets/p282288_b_v8_aa.jpg", - "size": "Ms", - "aspect": "2x3", - "category": "Banner-L3", - "text": "yes", - "primary": "true", - "tier": "Series" - }, - { - "width": "180", - "height": "135", - "uri": "assets/p282288_b_h5_aa.jpg", - "size": "Sm", - "aspect": "4x3", - "category": "Banner-L3", - "text": "yes", - "primary": "true", - "tier": "Series" - } - ] - } -] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json deleted file mode 100644 index 154c02f973..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json +++ /dev/null @@ -1,245 +0,0 @@ -[ - { - "programID": "EP000000060003", - "titles": [{ - "title120": "'Allo 'Allo!" - }], - "eventDetails": { - "subType": "Series" - }, - "descriptions": { - "description1000": [{ - "descriptionLanguage": "en", - "description": "A disguised British Intelligence officer is sent to help the airmen." - }] - }, - "originalAirDate": "1985-11-04", - "genres": ["Sitcom"], - "episodeTitle150": "The Poloceman Cometh", - "metadata": [{ - "Gracenote": { - "season": 2, - "episode": 3 - } - }], - "cast": [{ - "personId": "383774", - "nameId": "392649", - "name": "Gorden Kaye", - "role": "Actor", - "billingOrder": "01" - }, { - "personId": "246840", - "nameId": "250387", - "name": "Carmen Silvera", - "role": "Actor", - "billingOrder": "02" - }, { - "personId": "376955", - "nameId": "385830", - "name": "Rose Hill", - "role": "Actor", - "billingOrder": "03" - }, { - "personId": "259773", - "nameId": "263340", - "name": "Vicki Michelle", - "role": "Actor", - "billingOrder": "04" - }, { - "personId": "353113", - "nameId": "361987", - "name": "Kirsten Cooke", - "role": "Actor", - "billingOrder": "05" - }, { - "personId": "77787", - "nameId": "77787", - "name": "Richard Marner", - "role": "Actor", - "billingOrder": "06" - }, { - "personId": "230921", - "nameId": "234193", - "name": "Guy Siner", - "role": "Actor", - "billingOrder": "07" - }, { - "personId": "374934", - "nameId": "383809", - "name": "Kim Hartman", - "role": "Actor", - "billingOrder": "08" - }, { - "personId": "369151", - "nameId": "378026", - "name": "Richard Gibson", - "role": "Actor", - "billingOrder": "09" - }, { - "personId": "343690", - "nameId": "352564", - "name": "Arthur Bostrom", - "role": "Actor", - "billingOrder": "10" - }, { - "personId": "352557", - "nameId": "361431", - "name": "John D. Collins", - "role": "Actor", - "billingOrder": "11" - }, { - "personId": "605275", - "nameId": "627734", - "name": "Nicholas Frankau", - "role": "Actor", - "billingOrder": "12" - }, { - "personId": "373394", - "nameId": "382269", - "name": "Jack Haig", - "role": "Actor", - "billingOrder": "13" - }], - "crew": [{ - "personId": "354407", - "nameId": "363281", - "name": "David Croft", - "role": "Director", - "billingOrder": "01" - }, { - "personId": "354407", - "nameId": "363281", - "name": "David Croft", - "role": "Writer", - "billingOrder": "02" - }, { - "personId": "105145", - "nameId": "105145", - "name": "Jeremy Lloyd", - "role": "Writer", - "billingOrder": "03" - }], - "showType": "Series", - "hasImageArtwork": true, - "md5": "Jo5NKxoo44xRvBCAq8QT2A" - }, - { - "programID": "EP000000510142", - "titles": [{ - "title120": "A Different World" - }], - "eventDetails": { - "subType": "Series" - }, - "descriptions": { - "description1000": [{ - "descriptionLanguage": "en", - "description": "Whitley and Dwayne tell new students about their honeymoon in Los Angeles." - }] - }, - "originalAirDate": "1992-09-24", - "genres": ["Sitcom"], - "episodeTitle150": "Honeymoon in L.A.", - "metadata": [{ - "Gracenote": { - "season": 6, - "episode": 1 - } - }], - "cast": [{ - "personId": "700", - "nameId": "700", - "name": "Jasmine Guy", - "role": "Actor", - "billingOrder": "01" - }, { - "personId": "729", - "nameId": "729", - "name": "Kadeem Hardison", - "role": "Actor", - "billingOrder": "02" - }, { - "personId": "120", - "nameId": "120", - "name": "Darryl M. Bell", - "role": "Actor", - "billingOrder": "03" - }, { - "personId": "1729", - "nameId": "1729", - "name": "Cree Summer", - "role": "Actor", - "billingOrder": "04" - }, { - "personId": "217", - "nameId": "217", - "name": "Charnele Brown", - "role": "Actor", - "billingOrder": "05" - }, { - "personId": "1811", - "nameId": "1811", - "name": "Glynn Turman", - "role": "Actor", - "billingOrder": "06" - }, { - "personId": "1232", - "nameId": "1232", - "name": "Lou Myers", - "role": "Actor", - "billingOrder": "07" - }, { - "personId": "1363", - "nameId": "1363", - "name": "Jada Pinkett", - "role": "Guest Star", - "billingOrder": "08" - }, { - "personId": "222967", - "nameId": "225536", - "name": "Ajai Sanders", - "role": "Guest Star", - "billingOrder": "09" - }, { - "personId": "181744", - "nameId": "183292", - "name": "Karen Malina White", - "role": "Guest Star", - "billingOrder": "10" - }, { - "personId": "305017", - "nameId": "318897", - "name": "Patrick Y. Malone", - "role": "Guest Star", - "billingOrder": "11" - }, { - "personId": "9841", - "nameId": "9841", - "name": "Bumper Robinson", - "role": "Guest Star", - "billingOrder": "12" - }, { - "personId": "426422", - "nameId": "435297", - "name": "Sister Souljah", - "role": "Guest Star", - "billingOrder": "13" - }, { - "personId": "25", - "nameId": "25", - "name": "Debbie Allen", - "role": "Guest Star", - "billingOrder": "14" - }, { - "personId": "668", - "nameId": "668", - "name": "Gilbert Gottfried", - "role": "Guest Star", - "billingOrder": "15" - }], - "showType": "Series", - "hasImageArtwork": true, - "md5": "P5kz0QmCeYxIA+yL0H4DWw" - } -] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json deleted file mode 100644 index 72248921ae..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "stationID": "20454", - "date": [ - "2015-03-13", - "2015-03-17" - ] - }, - { - "stationID": "10021", - "date": [ - "2015-03-12", - "2015-03-13" - ] - } -] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json deleted file mode 100644 index f474f3aff2..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json +++ /dev/null @@ -1,35 +0,0 @@ -[ - { - "stationID": "20454", - "programs": [ - { - "programID": "SH005371070000", - "airDateTime": "2015-03-03T00:00:00Z", - "duration": 1800, - "md5": "Sy8HEMBPcuiAx3FBukUhKQ", - "new": true, - "audioProperties": [ - "stereo", - "cc" - ], - "videoProperties": [ - "hdtv" - ] - }, - { - "programID": "EP000014577244", - "airDateTime": "2015-03-03T00:30:00Z", - "duration": 1800, - "md5": "25DNXVXO192JI7Y9vSW9lQ", - "new": true, - "audioProperties": [ - "stereo", - "cc" - ], - "videoProperties": [ - "hdtv" - ] - } - ] - } -] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json deleted file mode 100644 index 73b0a54c4e..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "code": 0, - "message": "OK", - "serverID": "AWS-SD-web.1", - "datetime": "2016-08-23T13:55:25Z", - "token": "f3fca79989cafe7dead71beefedc812b" -} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json deleted file mode 100644 index b630c24041..0000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "response": "SERVICE_OFFLINE", - "code": 3000, - "serverID": "20141201.web.1", - "message": "Server offline for maintenance.", - "datetime": "2015-04-23T00:03:32Z", - "token": "CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE" -} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json new file mode 100644 index 0000000000..015afeecc0 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/headends_response.json @@ -0,0 +1 @@ +[{"headend":"CA00053","transport":"Cable","location":"Beverly Hills","lineups":[{"name":"Time Warner Cable - Cable","lineup":"USA-CA00053-DEFAULT","uri":"/20141201/lineups/USA-CA00053-DEFAULT"},{"name":"Time Warner Cable - Digital","lineup":"USA-CA00053-X","uri":"/20141201/lineups/USA-CA00053-X"}]},{"headend":"CA61222","transport":"Cable","location":"Beverly Hills","lineups":[{"name":"Mulholland Estates - Cable","lineup":"USA-CA61222-DEFAULT","uri":"/20141201/lineups/USA-CA61222-DEFAULT"}]},{"headend":"CA66511","transport":"Cable","location":"Los Angeles","lineups":[{"name":"AT&T U-verse TV - Digital","lineup":"USA-CA66511-X","uri":"/20141201/lineups/USA-CA66511-X"}]},{"headend":"CA67309","transport":"Cable","location":"Westchester","lineups":[{"name":"Time Warner Cable Sherman Oaks - Cable","lineup":"USA-CA67309-DEFAULT","uri":"/20141201/lineups/USA-CA67309-DEFAULT"},{"name":"Time Warner Cable Sherman Oaks - Digital","lineup":"USA-CA67309-X","uri":"/20141201/lineups/USA-CA67309-X"}]},{"headend":"CA67310","transport":"Cable","location":"Eagle Rock","lineups":[{"name":"Time Warner Cable City of Los Angeles - Cable","lineup":"USA-CA67310-DEFAULT","uri":"/20141201/lineups/USA-CA67310-DEFAULT"},{"name":"Time Warner Cable City of Los Angeles - Digital","lineup":"USA-CA67310-X","uri":"/20141201/lineups/USA-CA67310-X"}]},{"headend":"DISH803","transport":"Satellite","location":"Los Angeles","lineups":[{"name":"DISH Los Angeles - Satellite","lineup":"USA-DISH803-DEFAULT","uri":"/20141201/lineups/USA-DISH803-DEFAULT"}]},{"headend":"DITV803","transport":"Satellite","location":"Los Angeles","lineups":[{"name":"DIRECTV Los Angeles - Satellite","lineup":"USA-DITV803-DEFAULT","uri":"/20141201/lineups/USA-DITV803-DEFAULT"}]},{"headend":"90210","transport":"Antenna","location":"90210","lineups":[{"name":"Antenna","lineup":"USA-OTA-90210","uri":"/20141201/lineups/USA-OTA-90210"}]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json new file mode 100644 index 0000000000..0720894702 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineup_response.json @@ -0,0 +1 @@ +{"map":[{"stationID":"24326","channel":"001","providerCallsign":"BBC ONE South","logicalChannelNumber":"1","matchType":"providerCallsign"},{"stationID":"17154","channel":"002","providerCallsign":"BBC TWO","logicalChannelNumber":"2","matchType":"providerCallsign"}]} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json new file mode 100644 index 0000000000..032a84e59e --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/lineups_response.json @@ -0,0 +1 @@ +{"code":0,"serverID":"20141201.web.1","datetime":"2015-04-17T14:22:17Z","lineups":[{"lineup":"GBR-0001317-DEFAULT","name":"Freeview - Carlton - LWT (Southeast)","transport":"DVB-T","location":"London","uri":"/20141201/lineups/GBR-0001317-DEFAULT"},{"lineup":"USA-IL57303-X","name":"Comcast Waukegan/Lake Forest Area - Digital","transport":"Cable","location":"Lake Forest","uri":"/20141201/lineups/USA-IL57303-X"},{"lineup":"USA-NY67791-X","name":"Verizon Fios Queens - Digital","transport":"Cable","location":"Fresh Meadows","uri":"/20141201/lineups/USA-NY67791-X"},{"lineup":"USA-OTA-60030","name":"Local Over the Air Broadcast","transport":"Antenna","location":"60030","uri":"/20141201/lineups/USA-OTA-60030"},{"lineup":"USA-WI61859-DEFAULT","name":"DELETED LINEUP","isDeleted":true}]} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json new file mode 100644 index 0000000000..78166f09a4 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/metadata_programs_response.json @@ -0,0 +1 @@ +[{"programID":"SH00712240","data":[{"width":"135","height":"180","uri":"assets/p282288_b_v2_aa.jpg","size":"Sm","aspect":"3x4","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"},{"width":"720","height":"540","uri":"assets/p282288_b_h6_aa.jpg","size":"Lg","aspect":"4x3","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"},{"width":"960","height":"1440","uri":"assets/p282288_b_v8_aa.jpg","size":"Ms","aspect":"2x3","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"},{"width":"180","height":"135","uri":"assets/p282288_b_h5_aa.jpg","size":"Sm","aspect":"4x3","category":"Banner-L3","text":"yes","primary":"true","tier":"Series"}]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json new file mode 100644 index 0000000000..fe2a944364 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/programs_response.json @@ -0,0 +1 @@ +[{"programID":"EP000000060003","titles":[{"title120":"'Allo 'Allo!"}],"eventDetails":{"subType":"Series"},"descriptions":{"description1000":[{"descriptionLanguage":"en","description":"A disguised British Intelligence officer is sent to help the airmen."}]},"originalAirDate":"1985-11-04","genres":["Sitcom"],"episodeTitle150":"The Poloceman Cometh","metadata":[{"Gracenote":{"season":2,"episode":3}}],"cast":[{"personId":"383774","nameId":"392649","name":"Gorden Kaye","role":"Actor","billingOrder":"01"},{"personId":"246840","nameId":"250387","name":"Carmen Silvera","role":"Actor","billingOrder":"02"},{"personId":"376955","nameId":"385830","name":"Rose Hill","role":"Actor","billingOrder":"03"},{"personId":"259773","nameId":"263340","name":"Vicki Michelle","role":"Actor","billingOrder":"04"},{"personId":"353113","nameId":"361987","name":"Kirsten Cooke","role":"Actor","billingOrder":"05"},{"personId":"77787","nameId":"77787","name":"Richard Marner","role":"Actor","billingOrder":"06"},{"personId":"230921","nameId":"234193","name":"Guy Siner","role":"Actor","billingOrder":"07"},{"personId":"374934","nameId":"383809","name":"Kim Hartman","role":"Actor","billingOrder":"08"},{"personId":"369151","nameId":"378026","name":"Richard Gibson","role":"Actor","billingOrder":"09"},{"personId":"343690","nameId":"352564","name":"Arthur Bostrom","role":"Actor","billingOrder":"10"},{"personId":"352557","nameId":"361431","name":"John D. Collins","role":"Actor","billingOrder":"11"},{"personId":"605275","nameId":"627734","name":"Nicholas Frankau","role":"Actor","billingOrder":"12"},{"personId":"373394","nameId":"382269","name":"Jack Haig","role":"Actor","billingOrder":"13"}],"crew":[{"personId":"354407","nameId":"363281","name":"David Croft","role":"Director","billingOrder":"01"},{"personId":"354407","nameId":"363281","name":"David Croft","role":"Writer","billingOrder":"02"},{"personId":"105145","nameId":"105145","name":"Jeremy Lloyd","role":"Writer","billingOrder":"03"}],"showType":"Series","hasImageArtwork":true,"md5":"Jo5NKxoo44xRvBCAq8QT2A"},{"programID":"EP000000510142","titles":[{"title120":"A Different World"}],"eventDetails":{"subType":"Series"},"descriptions":{"description1000":[{"descriptionLanguage":"en","description":"Whitley and Dwayne tell new students about their honeymoon in Los Angeles."}]},"originalAirDate":"1992-09-24","genres":["Sitcom"],"episodeTitle150":"Honeymoon in L.A.","metadata":[{"Gracenote":{"season":6,"episode":1}}],"cast":[{"personId":"700","nameId":"700","name":"Jasmine Guy","role":"Actor","billingOrder":"01"},{"personId":"729","nameId":"729","name":"Kadeem Hardison","role":"Actor","billingOrder":"02"},{"personId":"120","nameId":"120","name":"Darryl M. Bell","role":"Actor","billingOrder":"03"},{"personId":"1729","nameId":"1729","name":"Cree Summer","role":"Actor","billingOrder":"04"},{"personId":"217","nameId":"217","name":"Charnele Brown","role":"Actor","billingOrder":"05"},{"personId":"1811","nameId":"1811","name":"Glynn Turman","role":"Actor","billingOrder":"06"},{"personId":"1232","nameId":"1232","name":"Lou Myers","role":"Actor","billingOrder":"07"},{"personId":"1363","nameId":"1363","name":"Jada Pinkett","role":"Guest Star","billingOrder":"08"},{"personId":"222967","nameId":"225536","name":"Ajai Sanders","role":"Guest Star","billingOrder":"09"},{"personId":"181744","nameId":"183292","name":"Karen Malina White","role":"Guest Star","billingOrder":"10"},{"personId":"305017","nameId":"318897","name":"Patrick Y. Malone","role":"Guest Star","billingOrder":"11"},{"personId":"9841","nameId":"9841","name":"Bumper Robinson","role":"Guest Star","billingOrder":"12"},{"personId":"426422","nameId":"435297","name":"Sister Souljah","role":"Guest Star","billingOrder":"13"},{"personId":"25","nameId":"25","name":"Debbie Allen","role":"Guest Star","billingOrder":"14"},{"personId":"668","nameId":"668","name":"Gilbert Gottfried","role":"Guest Star","billingOrder":"15"}],"showType":"Series","hasImageArtwork":true,"md5":"P5kz0QmCeYxIA+yL0H4DWw"}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json new file mode 100644 index 0000000000..5ef1bfb1c4 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_request.json @@ -0,0 +1 @@ +[{"stationID":"20454","date":["2015-03-13","2015-03-17"]},{"stationID":"10021","date":["2015-03-12","2015-03-13"]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json new file mode 100644 index 0000000000..4a97e55172 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/schedules_response.json @@ -0,0 +1 @@ +[{"stationID":"20454","programs":[{"programID":"SH005371070000","airDateTime":"2015-03-03T00:00:00Z","duration":1800,"md5":"Sy8HEMBPcuiAx3FBukUhKQ","new":true,"audioProperties":["stereo","cc"],"videoProperties":["hdtv"]},{"programID":"EP000014577244","airDateTime":"2015-03-03T00:30:00Z","duration":1800,"md5":"25DNXVXO192JI7Y9vSW9lQ","new":true,"audioProperties":["stereo","cc"],"videoProperties":["hdtv"]}]}] diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json new file mode 100644 index 0000000000..e5fb64a6fa --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_live_response.json @@ -0,0 +1 @@ +{"code":0,"message":"OK","serverID":"AWS-SD-web.1","datetime":"2016-08-23T13:55:25Z","token":"f3fca79989cafe7dead71beefedc812b"} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json new file mode 100644 index 0000000000..b66a4ed0c4 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/SchedulesDirect/token_offline_response.json @@ -0,0 +1 @@ +{"response":"SERVICE_OFFLINE","code":3000,"serverID":"20141201.web.1","message":"Server offline for maintenance.","datetime":"2015-04-23T00:03:32Z","token":"CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE"} -- cgit v1.2.3 From 23e6c918a22c85751cc0907cd0074ee3f3445664 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Mon, 6 Sep 2021 11:08:40 -0600 Subject: Remove Linq to index search --- Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 6686b625f4..1f963e4a29 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; -using System.Net.Http.Json; using System.Net.Mime; using System.Text; using System.Text.Json; @@ -803,11 +802,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings { var channelNumber = GetChannelNumber(channel); - var station = allStations.FirstOrDefault(item => string.Equals(item.StationId, channel.StationId, StringComparison.OrdinalIgnoreCase)) - ?? new StationDto - { - StationId = channel.StationId - }; + var stationIndex = allStations.FindIndex(item => string.Equals(item.StationId, channel.StationId, StringComparison.OrdinalIgnoreCase)); + var station = stationIndex == -1 + ? new StationDto { StationId = channel.StationId } + : allStations[stationIndex]; var channelInfo = new ChannelInfo { -- cgit v1.2.3 From be9663ae896dd28aa9a455469391f0304cc73a5f Mon Sep 17 00:00:00 2001 From: cvium Date: Tue, 7 Sep 2021 10:27:55 +0200 Subject: Use GetSmartApiUrl instead (hopefully it works) --- Emby.Server.Implementations/ApplicationHost.cs | 9 +-------- tests/Jellyfin.Networking.Tests/NetworkParseTests.cs | 8 ++++---- 2 files changed, 5 insertions(+), 12 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index c244e7cfa4..da99ea647e 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1186,14 +1186,7 @@ namespace Emby.Server.Implementations } /// - public string GetUrlForUseByHttpApi() - { - // GetBindInterfaces will return an interface. - var bind = NetManager.GetInternalBindAddresses().FirstOrDefault() ?? - NetManager.GetAllBindInterfaces(true).First(); - - return GetLocalApiUrl(bind.Address.ToString(), Uri.UriSchemeHttp); - } + public string GetUrlForUseByHttpApi() => GetSmartApiUrl(string.Empty); /// public string GetLocalApiUrl(string hostname, string scheme = null, int? port = null) diff --git a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs index 170f0279fd..b7385fde8b 100644 --- a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs +++ b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs @@ -482,9 +482,9 @@ namespace Jellyfin.Networking.Tests [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "", "192.168.1.208")] // LAN address is specified by default. [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "10.0.0.1", "10.0.0.1")] // return bind address - public void Get_Appropriate_Interface_NoSource(string interfaces, string lan, string bind, string result) + public void GetBindInterface_NoSourceGiven_Success(string interfaces, string lan, string bind, string result) { - var conf = new NetworkConfiguration() + var conf = new NetworkConfiguration { EnableIPV4 = true, LocalNetworkSubnets = lan.Split(','), @@ -506,9 +506,9 @@ namespace Jellyfin.Networking.Tests [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "10.0.0.1", "192.168.1.209", "10.0.0.1")] // LAN not bound, so return external. [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "192.168.1.208,10.0.0.1", "8.8.8.8", "10.0.0.1")] // return external bind address [InlineData("192.168.1.208/24,-16,eth16|10.0.0.1/24,10,eth7", "192.168.1.0/24", "192.168.1.208,10.0.0.1", "192.168.1.210", "192.168.1.208")] // return LAN bind address - public void Get_Appropriate_Interface_ForSource(string interfaces, string lan, string bind, string source, string result) + public void GetBindInterface_ValidSourceGiven_Success(string interfaces, string lan, string bind, string source, string result) { - var conf = new NetworkConfiguration() + var conf = new NetworkConfiguration { EnableIPV4 = true, LocalNetworkSubnets = lan.Split(','), -- cgit v1.2.3 From 153e9202397f236a4a415bd033c3b398b6e6573c Mon Sep 17 00:00:00 2001 From: cvium Date: Tue, 7 Sep 2021 11:48:06 +0200 Subject: Ignore published server url for local access --- Emby.Server.Implementations/ApplicationHost.cs | 31 ++++++++-------------- .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/LiveTvMediaSourceProvider.cs | 2 +- .../TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 2 +- .../LiveTv/TunerHosts/SharedHttpStream.cs | 2 +- MediaBrowser.Controller/IServerApplicationHost.cs | 2 +- 6 files changed, 16 insertions(+), 25 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index da99ea647e..d507c3fd19 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1135,12 +1135,6 @@ namespace Emby.Server.Implementations } string smart = NetManager.GetBindInterface(remoteAddr, out port); - // If the smartAPI doesn't start with http then treat it as a host or ip. - if (smart.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - return smart.Trim('/'); - } - return GetLocalApiUrl(smart.Trim('/'), null, port); } @@ -1155,12 +1149,6 @@ namespace Emby.Server.Implementations } string smart = NetManager.GetBindInterface(request, out port); - // If the smartAPI doesn't start with http then treat it as a host or ip. - if (smart.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - return smart.Trim('/'); - } - return GetLocalApiUrl(smart.Trim('/'), request.Scheme, port); } @@ -1175,22 +1163,25 @@ namespace Emby.Server.Implementations } string smart = NetManager.GetBindInterface(hostname, out port); - - // If the smartAPI doesn't start with http then treat it as a host or ip. - if (smart.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - return smart.Trim('/'); - } - return GetLocalApiUrl(smart.Trim('/'), null, port); } /// - public string GetUrlForUseByHttpApi() => GetSmartApiUrl(string.Empty); + public string GetApiUrlForLocalAccess() + { + string smart = NetManager.GetBindInterface(string.Empty, out var port); + return GetLocalApiUrl(smart.Trim('/'), null, port); + } /// public string GetLocalApiUrl(string hostname, string scheme = null, int? port = null) { + // If the smartAPI doesn't start with http then treat it as a host or ip. + if (hostname.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + return hostname.TrimEnd('/'); + } + // NOTE: If no BaseUrl is set then UriBuilder appends a trailing slash, but if there is no BaseUrl it does // not. For consistency, always trim the trailing slash. return new UriBuilder diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 0205ed9e5d..67f824e71d 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1027,7 +1027,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var stream = new MediaSourceInfo { - EncoderPath = _appHost.GetUrlForUseByHttpApi() + "/LiveTv/LiveRecordings/" + info.Id + "/stream", + EncoderPath = _appHost.GetApiUrlForLocalAccess() + "/LiveTv/LiveRecordings/" + info.Id + "/stream", EncoderProtocol = MediaProtocol.Http, Path = info.Path, Protocol = MediaProtocol.File, diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 1af9396d76..4b7584af34 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -104,7 +104,7 @@ namespace Emby.Server.Implementations.LiveTv // Dummy this up so that direct play checks can still run if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) { - source.Path = _appHost.GetUrlForUseByHttpApi(); + source.Path = _appHost.GetApiUrlForLocalAccess(); } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index a8a8ac7291..9901f41f93 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -146,7 +146,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun // OpenedMediaSource.Path = tempFile; // OpenedMediaSource.ReadAtNativeFramerate = true; - MediaSource.Path = _appHost.GetUrlForUseByHttpApi() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; + MediaSource.Path = _appHost.GetApiUrlForLocalAccess() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; MediaSource.Protocol = MediaProtocol.Http; // OpenedMediaSource.SupportsDirectPlay = false; // OpenedMediaSource.SupportsDirectStream = true; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index b3e5541397..67879cbae9 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -97,7 +97,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts // OpenedMediaSource.Path = tempFile; // OpenedMediaSource.ReadAtNativeFramerate = true; - MediaSource.Path = _appHost.GetUrlForUseByHttpApi() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; + MediaSource.Path = _appHost.GetApiUrlForLocalAccess() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; MediaSource.Protocol = MediaProtocol.Http; // OpenedMediaSource.Path = TempFilePath; diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 52a7ff2040..3c275391f2 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -85,7 +85,7 @@ namespace MediaBrowser.Controller /// Gets an URL that can be used to access the API over HTTP (not HTTPS). /// /// The API URL. - string GetUrlForUseByHttpApi(); + string GetApiUrlForLocalAccess(); /// /// Gets a local (LAN) URL that can be used to access the API. -- cgit v1.2.3 From 1a8dcae5e4024ba30aa2f3e998e0df87ea6f4f1b Mon Sep 17 00:00:00 2001 From: "Mr. Chip53" Date: Sun, 12 Sep 2021 13:30:53 -0500 Subject: Fix #6171 --- .../LiveTv/Listings/XmlTvListingsProvider.cs | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 8202fab861..1c103f402a 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -59,34 +59,34 @@ namespace Emby.Server.Implementations.LiveTv.Listings return _config.Configuration.PreferredMetadataLanguage; } - private async Task GetXml(string path, CancellationToken cancellationToken) + private async Task GetXml(ListingsProviderInfo info, CancellationToken cancellationToken) { - _logger.LogInformation("xmltv path: {Path}", path); + _logger.LogInformation("xmltv path: {Path}", info.Path); - if (!path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + if (!info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { - return UnzipIfNeeded(path, path); + return UnzipIfNeeded(info.Path, info.Path); } - string cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + ".xml"; + string cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + "-" + info.Id + ".xml"; string cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename); if (File.Exists(cacheFile)) { - return UnzipIfNeeded(path, cacheFile); + return UnzipIfNeeded(info.Path, cacheFile); } - _logger.LogInformation("Downloading xmltv listings from {Path}", path); + _logger.LogInformation("Downloading xmltv listings from {Path}", info.Path); Directory.CreateDirectory(Path.GetDirectoryName(cacheFile)); - using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(path, cancellationToken).ConfigureAwait(false); + using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(info.Path, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO)) { await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } - return UnzipIfNeeded(path, cacheFile); + return UnzipIfNeeded(info.Path, cacheFile); } private string UnzipIfNeeded(string originalUrl, string file) @@ -162,7 +162,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings _logger.LogDebug("Getting xmltv programs for channel {Id}", channelId); - string path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); + string path = await GetXml(info, cancellationToken).ConfigureAwait(false); _logger.LogDebug("Opening XmlTvReader for {Path}", path); var reader = new XmlTvReader(path, GetLanguage(info)); @@ -256,7 +256,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings public async Task> GetLineups(ListingsProviderInfo info, string country, string location) { // In theory this should never be called because there is always only one lineup - string path = await GetXml(info.Path, CancellationToken.None).ConfigureAwait(false); + string path = await GetXml(info, CancellationToken.None).ConfigureAwait(false); _logger.LogDebug("Opening XmlTvReader for {Path}", path); var reader = new XmlTvReader(path, GetLanguage(info)); IEnumerable results = reader.GetChannels(); @@ -268,7 +268,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings public async Task> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken) { // In theory this should never be called because there is always only one lineup - string path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); + string path = await GetXml(info, cancellationToken).ConfigureAwait(false); _logger.LogDebug("Opening XmlTvReader for {Path}", path); var reader = new XmlTvReader(path, GetLanguage(info)); var results = reader.GetChannels(); -- cgit v1.2.3 From 7a7fe3e681eca87cde631336c9af565fd6dfe0d7 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sun, 12 Sep 2021 13:56:26 -0600 Subject: Fix types and property names --- .../LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs | 2 +- .../LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs | 5 +++-- .../LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs | 2 +- .../LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs | 6 +++--- 4 files changed, 8 insertions(+), 7 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs index a635c59870..f190817813 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs @@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the datetime. /// [JsonPropertyName("datetime")] - public DateTime? Datetime { get; set; } + public DateTime? LineupTimestamp { get; set; } /// /// Gets or sets the list of lineups. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs index 68fbeec46d..04560ab55d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs @@ -1,3 +1,4 @@ +using System; using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos @@ -23,13 +24,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the start date. /// [JsonPropertyName("startDate")] - public string? StartDate { get; set; } + public DateTime? StartDate { get; set; } /// /// Gets or sets the end date. /// [JsonPropertyName("endDate")] - public string? EndDate { get; set; } + public DateTime? EndDate { get; set; } /// /// Gets or sets the days count. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs index 561f79c5af..afb9994869 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs @@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the current datetime. /// [JsonPropertyName("datetime")] - public DateTime? DateTime { get; set; } + public DateTime? TokenTimestamp { get; set; } /// /// Gets or sets the response message. diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs index a494d883ec..3b3e38bd1f 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs @@ -30,7 +30,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect Assert.Equal(0, tokenDto!.Code); Assert.Equal("OK", tokenDto.Message); Assert.Equal("AWS-SD-web.1", tokenDto.ServerId); - Assert.Equal(new DateTime(2016, 08, 23, 13, 55, 25, DateTimeKind.Utc), tokenDto.DateTime); + Assert.Equal(new DateTime(2016, 08, 23, 13, 55, 25, DateTimeKind.Utc), tokenDto.TokenTimestamp); Assert.Equal("f3fca79989cafe7dead71beefedc812b", tokenDto.Token); } @@ -47,7 +47,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect Assert.Equal(3_000, tokenDto!.Code); Assert.Equal("Server offline for maintenance.", tokenDto.Message); Assert.Equal("20141201.web.1", tokenDto.ServerId); - Assert.Equal(new DateTime(2015, 04, 23, 00, 03, 32, DateTimeKind.Utc), tokenDto.DateTime); + Assert.Equal(new DateTime(2015, 04, 23, 00, 03, 32, DateTimeKind.Utc), tokenDto.TokenTimestamp); Assert.Equal("CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE", tokenDto.Token); Assert.Equal("SERVICE_OFFLINE", tokenDto.Response); } @@ -207,7 +207,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect Assert.NotNull(lineupsDto); Assert.Equal(0, lineupsDto!.Code); Assert.Equal("20141201.web.1", lineupsDto.ServerId); - Assert.Equal(new DateTime(2015, 04, 17, 14, 22, 17, DateTimeKind.Utc), lineupsDto.Datetime); + Assert.Equal(new DateTime(2015, 04, 17, 14, 22, 17, DateTimeKind.Utc), lineupsDto.LineupTimestamp); Assert.Equal(5, lineupsDto.Lineups.Count); Assert.Equal("GBR-0001317-DEFAULT", lineupsDto.Lineups[0].Lineup); Assert.Equal("Freeview - Carlton - LWT (Southeast)", lineupsDto.Lineups[0].Name); -- cgit v1.2.3 From ea439c5ccf7a61157544accd60109afc12dbc2d2 Mon Sep 17 00:00:00 2001 From: Fredrik Lindberg Date: Thu, 26 Aug 2021 20:01:56 +0200 Subject: Improve series name matching Add a series path resolver that attempts to extract only the series name from a path that contains more information that just the name. --- Emby.Naming/Common/NamingOptions.cs | 14 +++++ Emby.Naming/TV/SeriesInfo.cs | 29 ++++++++++ Emby.Naming/TV/SeriesPathParser.cs | 61 ++++++++++++++++++++++ Emby.Naming/TV/SeriesPathParserResult.cs | 19 +++++++ Emby.Naming/TV/SeriesResolver.cs | 49 +++++++++++++++++ .../Library/Resolvers/TV/SeriesResolver.cs | 8 +-- .../TV/SeriesPathParserTest.cs | 28 ++++++++++ .../TV/SeriesResolverTests.cs | 28 ++++++++++ 8 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 Emby.Naming/TV/SeriesInfo.cs create mode 100644 Emby.Naming/TV/SeriesPathParser.cs create mode 100644 Emby.Naming/TV/SeriesPathParserResult.cs create mode 100644 Emby.Naming/TV/SeriesResolver.cs create mode 100644 tests/Jellyfin.Naming.Tests/TV/SeriesPathParserTest.cs create mode 100644 tests/Jellyfin.Naming.Tests/TV/SeriesResolverTests.cs (limited to 'Emby.Server.Implementations') diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 915ce42cc9..192171a385 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -368,6 +368,20 @@ namespace Emby.Naming.Common IsOptimistic = true, IsNamed = true }, + + // Series and season only expression + // "the show/season 1", "the show/s01" + new EpisodeExpression(@"(.*(\\|\/))*(?.+)\/[Ss](eason)?[\. _\-]*(?[0-9]+)") + { + IsNamed = true + }, + + // Series and season only expression + // "the show S01", "the show season 1" + new EpisodeExpression(@"(.*(\\|\/))*(?.+)[\. _\-]+[sS](eason)?[\. _\-]*(?[0-9]+)") + { + IsNamed = true + }, }; EpisodeWithoutSeasonExpressions = new[] diff --git a/Emby.Naming/TV/SeriesInfo.cs b/Emby.Naming/TV/SeriesInfo.cs new file mode 100644 index 0000000000..5d6cb4bd37 --- /dev/null +++ b/Emby.Naming/TV/SeriesInfo.cs @@ -0,0 +1,29 @@ +namespace Emby.Naming.TV +{ + /// + /// Holder object for Series information. + /// + public class SeriesInfo + { + /// + /// Initializes a new instance of the class. + /// + /// Path to the file. + public SeriesInfo(string path) + { + Path = path; + } + + /// + /// Gets or sets the path. + /// + /// The path. + public string Path { get; set; } + + /// + /// Gets or sets the name of the series. + /// + /// The name of the series. + public string? Name { get; set; } + } +} diff --git a/Emby.Naming/TV/SeriesPathParser.cs b/Emby.Naming/TV/SeriesPathParser.cs new file mode 100644 index 0000000000..a62e5f4d63 --- /dev/null +++ b/Emby.Naming/TV/SeriesPathParser.cs @@ -0,0 +1,61 @@ +using System.Globalization; +using Emby.Naming.Common; + +namespace Emby.Naming.TV +{ + /// + /// Used to parse information about series from paths containing more information that only the series name. + /// Uses the same regular expressions as the EpisodePathParser but have different success criteria. + /// + public static class SeriesPathParser + { + /// + /// Parses information about series from path. + /// + /// object containing EpisodeExpressions and MultipleEpisodeExpressions. + /// Path. + /// Returns object. + public static SeriesPathParserResult Parse(NamingOptions options, string path) + { + SeriesPathParserResult? result = null; + + foreach (var expression in options.EpisodeExpressions) + { + var currentResult = Parse(path, expression); + if (currentResult.Success) + { + result = currentResult; + break; + } + } + + if (result != null) + { + if (!string.IsNullOrEmpty(result.SeriesName)) + { + result.SeriesName = result.SeriesName.Trim(' ', '_', '.', '-'); + } + } + + return result ?? new SeriesPathParserResult(); + } + + private static SeriesPathParserResult Parse(string name, EpisodeExpression expression) + { + var result = new SeriesPathParserResult(); + + var match = expression.Regex.Match(name); + + if (match.Success && match.Groups.Count >= 3) + { + if (expression.IsNamed) + { + result.SeriesName = match.Groups["seriesname"].Value; + result.Success = !string.IsNullOrEmpty(result.SeriesName) && !string.IsNullOrEmpty(match.Groups["seasonnumber"]?.Value); + } + } + + return result; + } + } +} diff --git a/Emby.Naming/TV/SeriesPathParserResult.cs b/Emby.Naming/TV/SeriesPathParserResult.cs new file mode 100644 index 0000000000..44cd2fdfa1 --- /dev/null +++ b/Emby.Naming/TV/SeriesPathParserResult.cs @@ -0,0 +1,19 @@ +namespace Emby.Naming.TV +{ + /// + /// Holder object for result. + /// + public class SeriesPathParserResult + { + /// + /// Gets or sets the name of the series. + /// + /// The name of the series. + public string? SeriesName { get; set; } + + /// + /// Gets or sets a value indicating whether parsing was successful. + /// + public bool Success { get; set; } + } +} diff --git a/Emby.Naming/TV/SeriesResolver.cs b/Emby.Naming/TV/SeriesResolver.cs new file mode 100644 index 0000000000..156a03c9ed --- /dev/null +++ b/Emby.Naming/TV/SeriesResolver.cs @@ -0,0 +1,49 @@ +using System.IO; +using System.Text.RegularExpressions; +using Emby.Naming.Common; + +namespace Emby.Naming.TV +{ + /// + /// Used to resolve information about series from path. + /// + public static class SeriesResolver + { + /// + /// Regex that matches strings of at least 2 characters separated by a dot or underscore. + /// Used for removing separators between words, i.e turns "The_show" into "The show" while + /// preserving namings like "S.H.O.W". + /// + private static readonly Regex _seriesNameRegex = new Regex(@"((?[^\._]{2,})[\._]*)|([\._](?[^\._]{2,}))"); + + /// + /// Resolve information about series from path. + /// + /// object passed to . + /// Path to series. + /// SeriesInfo. + public static SeriesInfo Resolve(NamingOptions options, string path) + { + string seriesName = Path.GetFileName(path); + + SeriesPathParserResult result = SeriesPathParser.Parse(options, path); + if (result.Success) + { + if (!string.IsNullOrEmpty(result.SeriesName)) + { + seriesName = result.SeriesName; + } + } + + if (!string.IsNullOrEmpty(seriesName)) + { + seriesName = _seriesNameRegex.Replace(seriesName, "${a} ${b}").Trim(); + } + + return new SeriesInfo(path) + { + Name = seriesName + }; + } + } +} diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index a1562abd31..a997584a6e 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -55,6 +55,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV return null; } + var seriesInfo = Naming.TV.SeriesResolver.Resolve(_libraryManager.GetNamingOptions(), args.Path); + var collectionType = args.GetCollectionType(); if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) { @@ -64,7 +66,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV return new Series { Path = args.Path, - Name = Path.GetFileName(args.Path) + Name = seriesInfo.Name }; } } @@ -81,7 +83,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV return new Series { Path = args.Path, - Name = Path.GetFileName(args.Path) + Name = seriesInfo.Name }; } @@ -95,7 +97,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV return new Series { Path = args.Path, - Name = Path.GetFileName(args.Path) + Name = seriesInfo.Name }; } } diff --git a/tests/Jellyfin.Naming.Tests/TV/SeriesPathParserTest.cs b/tests/Jellyfin.Naming.Tests/TV/SeriesPathParserTest.cs new file mode 100644 index 0000000000..ceb5f8b736 --- /dev/null +++ b/tests/Jellyfin.Naming.Tests/TV/SeriesPathParserTest.cs @@ -0,0 +1,28 @@ +using Emby.Naming.Common; +using Emby.Naming.TV; +using Xunit; + +namespace Jellyfin.Naming.Tests.TV +{ + public class SeriesPathParserTest + { + [Theory] + [InlineData("The.Show.S01", "The.Show")] + [InlineData("/The.Show.S01", "The.Show")] + [InlineData("/some/place/The.Show.S01", "The.Show")] + [InlineData("/something/The.Show.S01", "The.Show")] + [InlineData("The Show Season 10", "The Show")] + [InlineData("The Show S01E01", "The Show")] + [InlineData("The Show S01E01 Episode", "The Show")] + [InlineData("/something/The Show/Season 1", "The Show")] + [InlineData("/something/The Show/S01", "The Show")] + public void SeriesPathParserParseTest(string path, string name) + { + NamingOptions o = new NamingOptions(); + var res = SeriesPathParser.Parse(o, path); + + Assert.Equal(name, res.SeriesName); + Assert.True(res.Success); + } + } +} diff --git a/tests/Jellyfin.Naming.Tests/TV/SeriesResolverTests.cs b/tests/Jellyfin.Naming.Tests/TV/SeriesResolverTests.cs new file mode 100644 index 0000000000..97f4b40582 --- /dev/null +++ b/tests/Jellyfin.Naming.Tests/TV/SeriesResolverTests.cs @@ -0,0 +1,28 @@ +using Emby.Naming.Common; +using Emby.Naming.TV; +using Xunit; + +namespace Jellyfin.Naming.Tests.TV +{ + public class SeriesResolverTests + { + [Theory] + [InlineData("The.Show.S01", "The Show")] + [InlineData("The.Show.S01.COMPLETE", "The Show")] + [InlineData("S.H.O.W.S01", "S.H.O.W")] + [InlineData("The.Show.P.I.S01", "The Show P.I")] + [InlineData("The_Show_Season_1", "The Show")] + [InlineData("/something/The_Show/Season 10", "The Show")] + [InlineData("The Show", "The Show")] + [InlineData("/some/path/The Show", "The Show")] + [InlineData("/some/path/The Show s02e10 720p hdtv", "The Show")] + [InlineData("/some/path/The Show s02e10 the episode 720p hdtv", "The Show")] + public void SeriesResolverResolveTest(string path, string name) + { + NamingOptions o = new NamingOptions(); + var res = SeriesResolver.Resolve(o, path); + + Assert.Equal(name, res.Name); + } + } +} -- cgit v1.2.3 From 90174f68e2b477e613d756d78cbfd89c2a33f30a Mon Sep 17 00:00:00 2001 From: Fredrik Lindberg Date: Tue, 31 Aug 2021 22:22:55 +0200 Subject: Dynamically populate LocalAddress based on HTTP request Support populating the LocalAddress field in the system info endpoint based on the x-forwarded-host and x-forwarded-proto header. The x-forwarded-host header must contain both the host and port for the url to be properly constructed. Behind network configuration option that is disabled by default. --- Emby.Server.Implementations/ApplicationHost.cs | 22 +++++++++++++++++----- Jellyfin.Api/Controllers/SystemController.cs | 4 ++-- .../Configuration/NetworkConfiguration.cs | 5 +++++ .../Extensions/ApiServiceCollectionExtensions.cs | 3 ++- MediaBrowser.Controller/IServerApplicationHost.cs | 6 +++--- 5 files changed, 29 insertions(+), 11 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index bf7ddace2d..64ec5833f4 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1073,9 +1073,9 @@ namespace Emby.Server.Implementations /// /// Gets the system status. /// - /// Where this request originated. + /// Where this request originated. /// SystemInfo. - public SystemInfo GetSystemInfo(IPAddress source) + public SystemInfo GetSystemInfo(HttpRequest request) { return new SystemInfo { @@ -1097,7 +1097,7 @@ namespace Emby.Server.Implementations CanLaunchWebBrowser = CanLaunchWebBrowser, TranscodingTempPath = ConfigurationManager.GetTranscodePath(), ServerName = FriendlyName, - LocalAddress = GetSmartApiUrl(source), + LocalAddress = GetSmartApiUrl(request), SupportsLibraryMonitor = true, EncoderLocation = _mediaEncoder.EncoderLocation, SystemArchitecture = RuntimeInformation.OSArchitecture, @@ -1110,7 +1110,7 @@ namespace Emby.Server.Implementations .Select(i => new WakeOnLanInfo(i)) .ToList(); - public PublicSystemInfo GetPublicSystemInfo(IPAddress address) + public PublicSystemInfo GetPublicSystemInfo(HttpRequest request) { return new PublicSystemInfo { @@ -1119,7 +1119,7 @@ namespace Emby.Server.Implementations Id = SystemId, OperatingSystem = MediaBrowser.Common.System.OperatingSystem.Id.ToString(), ServerName = FriendlyName, - LocalAddress = GetSmartApiUrl(address), + LocalAddress = GetSmartApiUrl(request), StartupWizardCompleted = ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted }; } @@ -1150,6 +1150,18 @@ namespace Emby.Server.Implementations /// public string GetSmartApiUrl(HttpRequest request, int? port = null) { + // Return the host in the HTTP request as the API url + if (ConfigurationManager.GetNetworkConfiguration().EnablePublishedServerUriByRequest) + { + int? requestPort = request.Host.Port; + if ((requestPort == 80 && string.Equals(request.Scheme, "http", StringComparison.OrdinalIgnoreCase)) || (requestPort == 443 && string.Equals(request.Scheme, "https", StringComparison.OrdinalIgnoreCase))) + { + requestPort = -1; + } + + return GetLocalApiUrl(request.Host.Host, request.Scheme, requestPort); + } + // Published server ends with a / if (!string.IsNullOrEmpty(PublishedServerUrl)) { diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index bbbe5fb8da..ff81cc53b1 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -66,7 +66,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetSystemInfo() { - return _appHost.GetSystemInfo(Request.HttpContext.Connection.RemoteIpAddress ?? IPAddress.Loopback); + return _appHost.GetSystemInfo(Request); } /// @@ -78,7 +78,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetPublicSystemInfo() { - return _appHost.GetPublicSystemInfo(Request.HttpContext.Connection.RemoteIpAddress ?? IPAddress.Loopback); + return _appHost.GetPublicSystemInfo(Request); } /// diff --git a/Jellyfin.Networking/Configuration/NetworkConfiguration.cs b/Jellyfin.Networking/Configuration/NetworkConfiguration.cs index faf814c060..61db223d92 100644 --- a/Jellyfin.Networking/Configuration/NetworkConfiguration.cs +++ b/Jellyfin.Networking/Configuration/NetworkConfiguration.cs @@ -226,5 +226,10 @@ namespace Jellyfin.Networking.Configuration /// Gets or sets the known proxies. If the proxy is a network, it's added to the KnownNetworks. /// public string[] KnownProxies { get; set; } = Array.Empty(); + + /// + /// Gets or sets a value indicating whether the published server uri is based on information in HTTP requests. + /// + public bool EnablePublishedServerUriByRequest { get; set; } = false; } } diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index f19e87aba5..266dfef696 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -188,7 +188,8 @@ namespace Jellyfin.Server.Extensions // https://github.com/dotnet/aspnetcore/blob/master/src/Middleware/HttpOverrides/src/ForwardedHeadersMiddleware.cs // Enable debug logging on Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersMiddleware to help investigate issues. - options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost; + if (config.KnownProxies.Length == 0) { options.KnownNetworks.Clear(); diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 753c18bc7e..07aea6ad19 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -51,11 +51,11 @@ namespace MediaBrowser.Controller /// /// Gets the system info. /// - /// The originator of the request. + /// The HTTP request. /// SystemInfo. - SystemInfo GetSystemInfo(IPAddress source); + SystemInfo GetSystemInfo(HttpRequest request); - PublicSystemInfo GetPublicSystemInfo(IPAddress address); + PublicSystemInfo GetPublicSystemInfo(HttpRequest request); /// /// Gets a URL specific for the request. -- cgit v1.2.3 From 9234e5bf80194e45acac25c60cb76f401bffaf96 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sun, 26 Sep 2021 08:14:36 -0600 Subject: Remove all instances of en-US culture --- Emby.Dlna/Didl/DidlBuilder.cs | 28 +++++++-------- Emby.Dlna/Eventing/DlnaEventManager.cs | 8 ++--- Emby.Dlna/PlayTo/Device.cs | 12 +++---- Emby.Dlna/PlayTo/PlayToController.cs | 8 ++--- Emby.Dlna/PlayTo/SsdpHttpClient.cs | 8 ++--- Emby.Dlna/Server/DescriptionXmlBuilder.cs | 5 ++- .../MediaEncoder/EncodingManager.cs | 3 +- Jellyfin.Api/Controllers/ImageController.cs | 2 +- Jellyfin.Api/Controllers/SubtitleController.cs | 2 +- MediaBrowser.Controller/Entities/Year.cs | 4 +-- .../MediaEncoding/EncodingHelper.cs | 42 +++++++++++----------- MediaBrowser.Controller/MediaEncoding/JobLogger.cs | 11 +++--- .../Images/LocalImageProvider.cs | 4 +-- .../Parsers/BaseItemXmlParser.cs | 8 ++--- MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 12 +++---- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 11 ++---- .../Probing/ProbeResultNormalizer.cs | 27 +++++++------- .../Globalization/ILocalizationManager.cs | 4 +-- MediaBrowser.Providers/Manager/ImageSaver.cs | 18 +++++----- .../Plugins/Omdb/OmdbProvider.cs | 13 ++++--- MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs | 10 +++--- .../Parsers/EpisodeNfoParser.cs | 10 +++--- .../Savers/EpisodeNfoSaver.cs | 18 +++++----- 23 files changed, 116 insertions(+), 152 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index c000784997..0a84f30c4c 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -41,8 +41,6 @@ namespace Emby.Dlna.Didl private const string NsUpnp = "urn:schemas-upnp-org:metadata-1-0/upnp/"; private const string NsDlna = "urn:schemas-dlna-org:metadata-1-0/"; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly DeviceProfile _profile; private readonly IImageProcessor _imageProcessor; private readonly string _serverAddress; @@ -317,7 +315,7 @@ namespace Emby.Dlna.Didl if (mediaSource.RunTimeTicks.HasValue) { - writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture)); + writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", CultureInfo.InvariantCulture)); } if (filter.Contains("res@size")) @@ -328,7 +326,7 @@ namespace Emby.Dlna.Didl if (size.HasValue) { - writer.WriteAttributeString("size", size.Value.ToString(_usCulture)); + writer.WriteAttributeString("size", size.Value.ToString(CultureInfo.InvariantCulture)); } } } @@ -342,7 +340,7 @@ namespace Emby.Dlna.Didl if (targetChannels.HasValue) { - writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(_usCulture)); + writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(CultureInfo.InvariantCulture)); } if (filter.Contains("res@resolution")) @@ -361,12 +359,12 @@ namespace Emby.Dlna.Didl if (targetSampleRate.HasValue) { - writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(_usCulture)); + writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(CultureInfo.InvariantCulture)); } if (totalBitrate.HasValue) { - writer.WriteAttributeString("bitrate", totalBitrate.Value.ToString(_usCulture)); + writer.WriteAttributeString("bitrate", totalBitrate.Value.ToString(CultureInfo.InvariantCulture)); } var mediaProfile = _profile.GetVideoMediaProfile( @@ -552,7 +550,7 @@ namespace Emby.Dlna.Didl if (mediaSource.RunTimeTicks.HasValue) { - writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture)); + writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", CultureInfo.InvariantCulture)); } if (filter.Contains("res@size")) @@ -563,7 +561,7 @@ namespace Emby.Dlna.Didl if (size.HasValue) { - writer.WriteAttributeString("size", size.Value.ToString(_usCulture)); + writer.WriteAttributeString("size", size.Value.ToString(CultureInfo.InvariantCulture)); } } } @@ -575,17 +573,17 @@ namespace Emby.Dlna.Didl if (targetChannels.HasValue) { - writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(_usCulture)); + writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(CultureInfo.InvariantCulture)); } if (targetSampleRate.HasValue) { - writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(_usCulture)); + writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(CultureInfo.InvariantCulture)); } if (targetAudioBitrate.HasValue) { - writer.WriteAttributeString("bitrate", targetAudioBitrate.Value.ToString(_usCulture)); + writer.WriteAttributeString("bitrate", targetAudioBitrate.Value.ToString(CultureInfo.InvariantCulture)); } var mediaProfile = _profile.GetAudioMediaProfile( @@ -639,7 +637,7 @@ namespace Emby.Dlna.Didl writer.WriteAttributeString("restricted", "1"); writer.WriteAttributeString("searchable", "1"); - writer.WriteAttributeString("childCount", childCount.ToString(_usCulture)); + writer.WriteAttributeString("childCount", childCount.ToString(CultureInfo.InvariantCulture)); var clientId = GetClientId(folder, stubType); @@ -931,11 +929,11 @@ namespace Emby.Dlna.Didl if (item.IndexNumber.HasValue) { - AddValue(writer, "upnp", "originalTrackNumber", item.IndexNumber.Value.ToString(_usCulture), NsUpnp); + AddValue(writer, "upnp", "originalTrackNumber", item.IndexNumber.Value.ToString(CultureInfo.InvariantCulture), NsUpnp); if (item is Episode) { - AddValue(writer, "upnp", "episodeNumber", item.IndexNumber.Value.ToString(_usCulture), NsUpnp); + AddValue(writer, "upnp", "episodeNumber", item.IndexNumber.Value.ToString(CultureInfo.InvariantCulture), NsUpnp); } } } diff --git a/Emby.Dlna/Eventing/DlnaEventManager.cs b/Emby.Dlna/Eventing/DlnaEventManager.cs index b39bd5ce9b..d17e238715 100644 --- a/Emby.Dlna/Eventing/DlnaEventManager.cs +++ b/Emby.Dlna/Eventing/DlnaEventManager.cs @@ -26,8 +26,6 @@ namespace Emby.Dlna.Eventing private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - public DlnaEventManager(ILogger logger, IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; @@ -83,7 +81,7 @@ namespace Emby.Dlna.Eventing if (!string.IsNullOrEmpty(header)) { // Starts with SECOND- - if (int.TryParse(header.AsSpan().RightPart('-'), NumberStyles.Integer, _usCulture, out var val)) + if (int.TryParse(header.AsSpan().RightPart('-'), NumberStyles.Integer, CultureInfo.InvariantCulture, out var val)) { return val; } @@ -106,7 +104,7 @@ namespace Emby.Dlna.Eventing var response = new EventSubscriptionResponse(string.Empty, "text/plain"); response.Headers["SID"] = subscriptionId; - response.Headers["TIMEOUT"] = string.IsNullOrEmpty(requestedTimeoutString) ? ("SECOND-" + timeoutSeconds.ToString(_usCulture)) : requestedTimeoutString; + response.Headers["TIMEOUT"] = string.IsNullOrEmpty(requestedTimeoutString) ? ("SECOND-" + timeoutSeconds.ToString(CultureInfo.InvariantCulture)) : requestedTimeoutString; return response; } @@ -163,7 +161,7 @@ namespace Emby.Dlna.Eventing options.Headers.TryAddWithoutValidation("NT", subscription.NotificationType); options.Headers.TryAddWithoutValidation("NTS", "upnp:propchange"); options.Headers.TryAddWithoutValidation("SID", subscription.Id); - options.Headers.TryAddWithoutValidation("SEQ", subscription.TriggerCount.ToString(_usCulture)); + options.Headers.TryAddWithoutValidation("SEQ", subscription.TriggerCount.ToString(CultureInfo.InvariantCulture)); try { diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 11fcd81cff..0b22880003 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -20,8 +20,6 @@ namespace Emby.Dlna.PlayTo { public class Device : IDisposable { - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; @@ -640,7 +638,7 @@ namespace Emby.Dlna.PlayTo return; } - Volume = int.Parse(volumeValue, UsCulture); + Volume = int.Parse(volumeValue, CultureInfo.InvariantCulture); if (Volume > 0) { @@ -842,7 +840,7 @@ namespace Emby.Dlna.PlayTo if (!string.IsNullOrWhiteSpace(duration) && !string.Equals(duration, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase)) { - Duration = TimeSpan.Parse(duration, UsCulture); + Duration = TimeSpan.Parse(duration, CultureInfo.InvariantCulture); } else { @@ -854,7 +852,7 @@ namespace Emby.Dlna.PlayTo if (!string.IsNullOrWhiteSpace(position) && !string.Equals(position, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase)) { - Position = TimeSpan.Parse(position, UsCulture); + Position = TimeSpan.Parse(position, CultureInfo.InvariantCulture); } var track = result.Document.Descendants("TrackMetaData").FirstOrDefault(); @@ -1194,8 +1192,8 @@ namespace Emby.Dlna.PlayTo var depth = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("depth")); var url = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("url")); - var widthValue = int.Parse(width, NumberStyles.Integer, UsCulture); - var heightValue = int.Parse(height, NumberStyles.Integer, UsCulture); + var widthValue = int.Parse(width, NumberStyles.Integer, CultureInfo.InvariantCulture); + var heightValue = int.Parse(height, NumberStyles.Integer, CultureInfo.InvariantCulture); return new DeviceIcon { diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 0e49fd2c02..f25d8017ef 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -30,8 +30,6 @@ namespace Emby.Dlna.PlayTo { public class PlayToController : ISessionController, IDisposable { - private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US")); - private readonly SessionInfo _session; private readonly ISessionManager _sessionManager; private readonly ILibraryManager _libraryManager; @@ -716,7 +714,7 @@ namespace Emby.Dlna.PlayTo case GeneralCommandType.SetAudioStreamIndex: if (command.Arguments.TryGetValue("Index", out string index)) { - if (int.TryParse(index, NumberStyles.Integer, _usCulture, out var val)) + if (int.TryParse(index, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val)) { return SetAudioStreamIndex(val); } @@ -728,7 +726,7 @@ namespace Emby.Dlna.PlayTo case GeneralCommandType.SetSubtitleStreamIndex: if (command.Arguments.TryGetValue("Index", out index)) { - if (int.TryParse(index, NumberStyles.Integer, _usCulture, out var val)) + if (int.TryParse(index, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val)) { return SetSubtitleStreamIndex(val); } @@ -740,7 +738,7 @@ namespace Emby.Dlna.PlayTo case GeneralCommandType.SetVolume: if (command.Arguments.TryGetValue("Volume", out string vol)) { - if (int.TryParse(vol, NumberStyles.Integer, _usCulture, out var volume)) + if (int.TryParse(vol, NumberStyles.Integer, CultureInfo.InvariantCulture, out var volume)) { return _device.SetVolume(volume, cancellationToken); } diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs index 4b92fbff43..cade7b4c2c 100644 --- a/Emby.Dlna/PlayTo/SsdpHttpClient.cs +++ b/Emby.Dlna/PlayTo/SsdpHttpClient.cs @@ -20,8 +20,6 @@ namespace Emby.Dlna.PlayTo private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50"; private const string FriendlyName = "Jellyfin"; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly IHttpClientFactory _httpClientFactory; public SsdpHttpClient(IHttpClientFactory httpClientFactory) @@ -80,10 +78,10 @@ namespace Emby.Dlna.PlayTo { using var options = new HttpRequestMessage(new HttpMethod("SUBSCRIBE"), url); options.Headers.UserAgent.ParseAdd(USERAGENT); - options.Headers.TryAddWithoutValidation("HOST", ip + ":" + port.ToString(_usCulture)); - options.Headers.TryAddWithoutValidation("CALLBACK", "<" + localIp + ":" + eventport.ToString(_usCulture) + ">"); + options.Headers.TryAddWithoutValidation("HOST", ip + ":" + port.ToString(CultureInfo.InvariantCulture)); + options.Headers.TryAddWithoutValidation("CALLBACK", "<" + localIp + ":" + eventport.ToString(CultureInfo.InvariantCulture) + ">"); options.Headers.TryAddWithoutValidation("NT", "upnp:event"); - options.Headers.TryAddWithoutValidation("TIMEOUT", "Second-" + timeOut.ToString(_usCulture)); + options.Headers.TryAddWithoutValidation("TIMEOUT", "Second-" + timeOut.ToString(CultureInfo.InvariantCulture)); using var response = await _httpClientFactory.CreateClient(NamedClient.Default) .SendAsync(options, HttpCompletionOption.ResponseHeadersRead) diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs index 09525aae4e..80a45f2b25 100644 --- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs +++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs @@ -15,7 +15,6 @@ namespace Emby.Dlna.Server { private readonly DeviceProfile _profile; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly string _serverUdn; private readonly string _serverAddress; private readonly string _serverName; @@ -193,10 +192,10 @@ namespace Emby.Dlna.Server .Append(SecurityElement.Escape(icon.MimeType ?? string.Empty)) .Append(""); builder.Append("") - .Append(SecurityElement.Escape(icon.Width.ToString(_usCulture))) + .Append(SecurityElement.Escape(icon.Width.ToString(CultureInfo.InvariantCulture))) .Append(""); builder.Append("") - .Append(SecurityElement.Escape(icon.Height.ToString(_usCulture))) + .Append(SecurityElement.Escape(icon.Height.ToString(CultureInfo.InvariantCulture))) .Append(""); builder.Append("") .Append(SecurityElement.Escape(icon.Depth ?? string.Empty)) diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index 8aaa1f7bbe..ac6606d39a 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -23,7 +23,6 @@ namespace Emby.Server.Implementations.MediaEncoder { public class EncodingManager : IEncodingManager { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IFileSystem _fileSystem; private readonly ILogger _logger; private readonly IMediaEncoder _encoder; @@ -193,7 +192,7 @@ namespace Emby.Server.Implementations.MediaEncoder private string GetChapterImagePath(Video video, long chapterPositionTicks) { - var filename = video.DateModified.Ticks.ToString(_usCulture) + "_" + chapterPositionTicks.ToString(_usCulture) + ".jpg"; + var filename = video.DateModified.Ticks.ToString(CultureInfo.InvariantCulture) + "_" + chapterPositionTicks.ToString(CultureInfo.InvariantCulture) + ".jpg"; return Path.Combine(GetChapterImagesPath(video), filename); } diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index b1c860d61f..86933074d0 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -2007,7 +2007,7 @@ namespace Jellyfin.Api.Controllers Response.Headers.Add(HeaderNames.CacheControl, "public"); } - Response.Headers.Add(HeaderNames.LastModified, dateImageModified.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss \"GMT\"", new CultureInfo("en-US", false))); + Response.Headers.Add(HeaderNames.LastModified, dateImageModified.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss \"GMT\"", CultureInfo.InvariantCulture)); // if the image was not modified since "ifModifiedSinceHeader"-header, return a HTTP status code 304 not modified if (!(dateImageModified > ifModifiedSinceHeader) && cacheDuration.HasValue) diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index 11f67ee894..1849dd0478 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -376,7 +376,7 @@ namespace Jellyfin.Api.Controllers var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks); var url = string.Format( - CultureInfo.CurrentCulture, + CultureInfo.InvariantCulture, "stream.vtt?CopyTimestamps=true&AddVttTimeMap=true&StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}", positionTicks.ToString(CultureInfo.InvariantCulture), endPositionTicks.ToString(CultureInfo.InvariantCulture), diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index 0853200dd1..afdaf448b7 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -57,9 +57,7 @@ namespace MediaBrowser.Controller.Entities public IList GetTaggedItems(InternalItemsQuery query) { - var usCulture = new CultureInfo("en-US"); - - if (!int.TryParse(Name, NumberStyles.Integer, usCulture, out var year)) + if (!int.TryParse(Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year)) { return new List(); } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index bdb3793325..5715194b85 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -21,8 +21,6 @@ namespace MediaBrowser.Controller.MediaEncoding { public class EncodingHelper { - private static readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly IMediaEncoder _mediaEncoder; private readonly ISubtitleEncoder _subtitleEncoder; @@ -816,7 +814,7 @@ namespace MediaBrowser.Controller.MediaEncoding public static string NormalizeTranscodingLevel(EncodingJobInfo state, string level) { - if (double.TryParse(level, NumberStyles.Any, _usCulture, out double requestLevel)) + if (double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out double requestLevel)) { if (string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase) || string.Equals(state.ActualOutputVideoCodec, "h265", StringComparison.OrdinalIgnoreCase)) @@ -911,7 +909,7 @@ namespace MediaBrowser.Controller.MediaEncoding CultureInfo.InvariantCulture, "subtitles='{0}:si={1}'{2}", _mediaEncoder.EscapeSubtitleFilterPath(mediaPath), - state.InternalSubtitleStreamOffset.ToString(_usCulture), + state.InternalSubtitleStreamOffset.ToString(CultureInfo.InvariantCulture), // fallbackFontParam, setPtsParam); } @@ -1217,7 +1215,7 @@ namespace MediaBrowser.Controller.MediaEncoding param += string.Format( CultureInfo.InvariantCulture, " -speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}", - profileScore.ToString(_usCulture), + profileScore.ToString(CultureInfo.InvariantCulture), crf, qmin, qmax); @@ -1289,7 +1287,7 @@ namespace MediaBrowser.Controller.MediaEncoding var framerate = GetFramerateParam(state); if (framerate.HasValue) { - param += string.Format(CultureInfo.InvariantCulture, " -r {0}", framerate.Value.ToString(_usCulture)); + param += string.Format(CultureInfo.InvariantCulture, " -r {0}", framerate.Value.ToString(CultureInfo.InvariantCulture)); } var targetVideoCodec = state.ActualOutputVideoCodec; @@ -1393,7 +1391,7 @@ namespace MediaBrowser.Controller.MediaEncoding else if (string.Equals(videoEncoder, "hevc_qsv", StringComparison.OrdinalIgnoreCase)) { // hevc_qsv use -level 51 instead of -level 153. - if (double.TryParse(level, NumberStyles.Any, _usCulture, out double hevcLevel)) + if (double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out double hevcLevel)) { param += " -level " + (hevcLevel / 3); } @@ -1555,7 +1553,7 @@ namespace MediaBrowser.Controller.MediaEncoding // If a specific level was requested, the source must match or be less than var level = state.GetRequestedLevel(videoStream.Codec); if (!string.IsNullOrEmpty(level) - && double.TryParse(level, NumberStyles.Any, _usCulture, out var requestLevel)) + && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out var requestLevel)) { if (!videoStream.Level.HasValue) { @@ -1803,7 +1801,7 @@ namespace MediaBrowser.Controller.MediaEncoding && state.AudioStream.Channels.Value > 5 && !encodingOptions.DownMixAudioBoost.Equals(1)) { - filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(_usCulture)); + filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(CultureInfo.InvariantCulture)); } var isCopyingTimestamps = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive; @@ -2434,8 +2432,8 @@ namespace MediaBrowser.Controller.MediaEncoding { if (isExynosV4L2) { - var widthParam = requestedWidth.Value.ToString(_usCulture); - var heightParam = requestedHeight.Value.ToString(_usCulture); + var widthParam = requestedWidth.Value.ToString(CultureInfo.InvariantCulture); + var heightParam = requestedHeight.Value.ToString(CultureInfo.InvariantCulture); filters.Add( string.Format( @@ -2453,8 +2451,8 @@ namespace MediaBrowser.Controller.MediaEncoding // If Max dimensions were supplied, for width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size else if (requestedMaxWidth.HasValue && requestedMaxHeight.HasValue) { - var maxWidthParam = requestedMaxWidth.Value.ToString(_usCulture); - var maxHeightParam = requestedMaxHeight.Value.ToString(_usCulture); + var maxWidthParam = requestedMaxWidth.Value.ToString(CultureInfo.InvariantCulture); + var maxHeightParam = requestedMaxHeight.Value.ToString(CultureInfo.InvariantCulture); if (isExynosV4L2) { @@ -2486,7 +2484,7 @@ namespace MediaBrowser.Controller.MediaEncoding } else { - var widthParam = requestedWidth.Value.ToString(_usCulture); + var widthParam = requestedWidth.Value.ToString(CultureInfo.InvariantCulture); filters.Add( string.Format( @@ -2499,7 +2497,7 @@ namespace MediaBrowser.Controller.MediaEncoding // If a fixed height was requested else if (requestedHeight.HasValue) { - var heightParam = requestedHeight.Value.ToString(_usCulture); + var heightParam = requestedHeight.Value.ToString(CultureInfo.InvariantCulture); if (isExynosV4L2) { @@ -2522,7 +2520,7 @@ namespace MediaBrowser.Controller.MediaEncoding // If a max width was requested else if (requestedMaxWidth.HasValue) { - var maxWidthParam = requestedMaxWidth.Value.ToString(_usCulture); + var maxWidthParam = requestedMaxWidth.Value.ToString(CultureInfo.InvariantCulture); if (isExynosV4L2) { @@ -2545,7 +2543,7 @@ namespace MediaBrowser.Controller.MediaEncoding // If a max height was requested else if (requestedMaxHeight.HasValue) { - var maxHeightParam = requestedMaxHeight.Value.ToString(_usCulture); + var maxHeightParam = requestedMaxHeight.Value.ToString(CultureInfo.InvariantCulture); if (isExynosV4L2) { @@ -4122,12 +4120,12 @@ namespace MediaBrowser.Controller.MediaEncoding if (bitrate.HasValue) { - args += " -ab " + bitrate.Value.ToString(_usCulture); + args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); } if (state.OutputAudioSampleRate.HasValue) { - args += " -ar " + state.OutputAudioSampleRate.Value.ToString(_usCulture); + args += " -ar " + state.OutputAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture); } args += GetAudioFilterParam(state, encodingOptions); @@ -4143,12 +4141,12 @@ namespace MediaBrowser.Controller.MediaEncoding if (bitrate.HasValue) { - audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(_usCulture)); + audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture)); } if (state.OutputAudioChannels.HasValue) { - audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(_usCulture)); + audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture)); } // opus will fail on 44100 @@ -4156,7 +4154,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (state.OutputAudioSampleRate.HasValue) { - audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(_usCulture)); + audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture)); } } diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs index c4ddc5618d..933f440ac6 100644 --- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs +++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs @@ -13,7 +13,6 @@ namespace MediaBrowser.Controller.MediaEncoding { public class JobLogger { - private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US")); private readonly ILogger _logger; public JobLogger(ILogger logger) @@ -87,7 +86,7 @@ namespace MediaBrowser.Controller.MediaEncoding { var rate = parts[i + 1]; - if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val)) + if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val)) { framerate = val; } @@ -96,7 +95,7 @@ namespace MediaBrowser.Controller.MediaEncoding { var rate = part.Split('=', 2)[^1]; - if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val)) + if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val)) { framerate = val; } @@ -106,7 +105,7 @@ namespace MediaBrowser.Controller.MediaEncoding { var time = part.Split('=', 2)[^1]; - if (TimeSpan.TryParse(time, _usCulture, out var val)) + if (TimeSpan.TryParse(time, CultureInfo.InvariantCulture, out var val)) { var currentMs = startMs + val.TotalMilliseconds; @@ -128,7 +127,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (scale.HasValue) { - if (long.TryParse(size, NumberStyles.Any, _usCulture, out var val)) + if (long.TryParse(size, NumberStyles.Any, CultureInfo.InvariantCulture, out var val)) { bytesTranscoded = val * scale.Value; } @@ -147,7 +146,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (scale.HasValue) { - if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val)) + if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val)) { bitRate = (int)Math.Ceiling(val * scale.Value); } diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs index b7398880ef..988581df92 100644 --- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs @@ -60,8 +60,6 @@ namespace MediaBrowser.LocalMetadata.Images private readonly IFileSystem _fileSystem; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - /// /// Initializes a new instance of the class. /// @@ -434,7 +432,7 @@ namespace MediaBrowser.LocalMetadata.Images var seasonMarker = seasonNumber.Value == 0 ? "-specials" - : seasonNumber.Value.ToString("00", _usCulture); + : seasonNumber.Value.ToString("00", CultureInfo.InvariantCulture); // Get this one directly from the file system since we have to go up a level if (!string.Equals(prefix, seasonMarker, StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index 7c9e681d6a..5a36c16630 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -21,8 +21,6 @@ namespace MediaBrowser.LocalMetadata.Parsers public class BaseItemXmlParser where T : BaseItem { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private Dictionary? _validProviderIds; /// @@ -180,7 +178,7 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrEmpty(text)) { - if (float.TryParse(text, NumberStyles.Any, _usCulture, out var value)) + if (float.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { item.CriticRating = value; } @@ -332,7 +330,7 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrWhiteSpace(text)) { - if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, _usCulture, out var runtime)) + if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, CultureInfo.InvariantCulture, out var runtime)) { item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; } @@ -1095,7 +1093,7 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { - if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var intVal)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intVal)) { sortOrder = intVal; } diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 6a3896eb6f..6f66fd61b0 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -25,8 +25,6 @@ namespace MediaBrowser.LocalMetadata.Savers /// public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss"; - private static readonly CultureInfo _usCulture = new CultureInfo("en-US"); - /// /// Initializes a new instance of the class. /// @@ -205,7 +203,7 @@ namespace MediaBrowser.LocalMetadata.Savers if (item.CriticRating.HasValue) { - writer.WriteElementString("CriticRating", item.CriticRating.Value.ToString(_usCulture)); + writer.WriteElementString("CriticRating", item.CriticRating.Value.ToString(CultureInfo.InvariantCulture)); } if (!string.IsNullOrEmpty(item.Overview)) @@ -289,12 +287,12 @@ namespace MediaBrowser.LocalMetadata.Savers if (item.CommunityRating.HasValue) { - writer.WriteElementString("Rating", item.CommunityRating.Value.ToString(_usCulture)); + writer.WriteElementString("Rating", item.CommunityRating.Value.ToString(CultureInfo.InvariantCulture)); } if (item.ProductionYear.HasValue && item is not Person) { - writer.WriteElementString("ProductionYear", item.ProductionYear.Value.ToString(_usCulture)); + writer.WriteElementString("ProductionYear", item.ProductionYear.Value.ToString(CultureInfo.InvariantCulture)); } if (item is IHasAspectRatio hasAspectRatio) @@ -322,7 +320,7 @@ namespace MediaBrowser.LocalMetadata.Savers { var timespan = TimeSpan.FromTicks(runTimeTicks.Value); - writer.WriteElementString("RunningTime", Math.Floor(timespan.TotalMinutes).ToString(_usCulture)); + writer.WriteElementString("RunningTime", Math.Floor(timespan.TotalMinutes).ToString(CultureInfo.InvariantCulture)); } if (item.ProviderIds != null) @@ -395,7 +393,7 @@ namespace MediaBrowser.LocalMetadata.Savers if (person.SortOrder.HasValue) { - writer.WriteElementString("SortOrder", person.SortOrder.Value.ToString(_usCulture)); + writer.WriteElementString("SortOrder", person.SortOrder.Value.ToString(CultureInfo.InvariantCulture)); } writer.WriteEndElement(); diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 4cbd1bbc80..06fe95ce82 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -43,11 +43,6 @@ namespace MediaBrowser.MediaEncoding.Encoder /// internal const int DefaultHdrImageExtractionTimeout = 20000; - /// - /// The us culture. - /// - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly ILogger _logger; private readonly IServerConfigurationManager _configurationManager; private readonly IFileSystem _fileSystem; @@ -687,7 +682,7 @@ namespace MediaBrowser.MediaEncoding.Encoder public string GetTimeParameter(TimeSpan time) { - return time.ToString(@"hh\:mm\:ss\.fff", _usCulture); + return time.ToString(@"hh\:mm\:ss\.fff", CultureInfo.InvariantCulture); } public async Task ExtractVideoImagesOnInterval( @@ -704,11 +699,11 @@ namespace MediaBrowser.MediaEncoding.Encoder { var inputArgument = GetInputArgument(inputFile, mediaSource); - var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(_usCulture); + var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(CultureInfo.InvariantCulture); if (maxWidth.HasValue) { - var maxWidthParam = maxWidth.Value.ToString(_usCulture); + var maxWidthParam = maxWidth.Value.ToString(CultureInfo.InvariantCulture); vf += string.Format(CultureInfo.InvariantCulture, ",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam); } diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 26f629a315..9ed6c264ee 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -30,7 +30,6 @@ namespace MediaBrowser.MediaEncoding.Probing private static readonly Regex _performerPattern = new (@"(?.*) \((?.*)\)"); - private readonly CultureInfo _usCulture = new ("en-US"); private readonly ILogger _logger; private readonly ILocalizationManager _localization; @@ -83,7 +82,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (!string.IsNullOrEmpty(data.Format.BitRate)) { - if (int.TryParse(data.Format.BitRate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(data.Format.BitRate, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { info.Bitrate = value; } @@ -191,7 +190,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (data.Format != null && !string.IsNullOrEmpty(data.Format.Duration)) { - info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.Format.Duration, _usCulture)).Ticks; + info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.Format.Duration, CultureInfo.InvariantCulture)).Ticks; } FetchWtvInfo(info, data); @@ -673,7 +672,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (!string.IsNullOrEmpty(streamInfo.SampleRate)) { - if (int.TryParse(streamInfo.SampleRate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(streamInfo.SampleRate, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { stream.SampleRate = value; } @@ -802,7 +801,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (!string.IsNullOrEmpty(streamInfo.BitRate)) { - if (int.TryParse(streamInfo.BitRate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(streamInfo.BitRate, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { bitrate = value; } @@ -815,7 +814,7 @@ namespace MediaBrowser.MediaEncoding.Probing && (stream.Type == MediaStreamType.Video || (isAudio && stream.Type == MediaStreamType.Audio))) { // If the stream info doesn't have a bitrate get the value from the media format info - if (int.TryParse(formatInfo.BitRate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(formatInfo.BitRate, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { bitrate = value; } @@ -921,8 +920,8 @@ namespace MediaBrowser.MediaEncoding.Probing var parts = (original ?? string.Empty).Split(':'); if (!(parts.Length == 2 && - int.TryParse(parts[0], NumberStyles.Any, _usCulture, out var width) && - int.TryParse(parts[1], NumberStyles.Any, _usCulture, out var height) && + int.TryParse(parts[0], NumberStyles.Any, CultureInfo.InvariantCulture, out var width) && + int.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var height) && width > 0 && height > 0)) { @@ -1008,11 +1007,11 @@ namespace MediaBrowser.MediaEncoding.Probing if (parts.Length == 2) { - result = float.Parse(parts[0], _usCulture) / float.Parse(parts[1], _usCulture); + result = float.Parse(parts[0], CultureInfo.InvariantCulture) / float.Parse(parts[1], CultureInfo.InvariantCulture); } else { - result = float.Parse(parts[0], _usCulture); + result = float.Parse(parts[0], CultureInfo.InvariantCulture); } return float.IsNaN(result) ? null : result; @@ -1039,7 +1038,7 @@ namespace MediaBrowser.MediaEncoding.Probing // If we got something, parse it if (!string.IsNullOrEmpty(duration)) { - data.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, _usCulture)).Ticks; + data.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, CultureInfo.InvariantCulture)).Ticks; } } @@ -1101,7 +1100,7 @@ namespace MediaBrowser.MediaEncoding.Probing return; } - info.Size = string.IsNullOrEmpty(data.Format.Size) ? null : long.Parse(data.Format.Size, _usCulture); + info.Size = string.IsNullOrEmpty(data.Format.Size) ? null : long.Parse(data.Format.Size, CultureInfo.InvariantCulture); } private void SetAudioInfoFromTags(MediaInfo audio, IReadOnlyDictionary tags) @@ -1144,7 +1143,7 @@ namespace MediaBrowser.MediaEncoding.Probing { Name = match.Groups["name"].Value, Type = PersonType.Actor, - Role = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(match.Groups["instrument"].Value) + Role = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(match.Groups["instrument"].Value) }); } } @@ -1443,7 +1442,7 @@ namespace MediaBrowser.MediaEncoding.Probing .ToArray(); } - if (tags.TryGetValue("WM/OriginalReleaseTime", out var year) && int.TryParse(year, NumberStyles.Integer, _usCulture, out var parsedYear)) + if (tags.TryGetValue("WM/OriginalReleaseTime", out var year) && int.TryParse(year, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedYear)) { video.ProductionYear = parsedYear; } diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs index b213e7aa00..406d32cde1 100644 --- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs +++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs @@ -56,10 +56,10 @@ namespace MediaBrowser.Model.Globalization IEnumerable GetLocalizationOptions(); /// - /// Returns the correct for the given language. + /// Returns the correct for the given language. /// /// The language. - /// The correct for the given language. + /// The correct for the given language. CultureDto? FindLanguageInfo(string language); } } diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 7d259a9d36..4b05edd67b 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -29,8 +29,6 @@ namespace MediaBrowser.Providers.Manager /// public class ImageSaver { - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// /// The _config. /// @@ -377,7 +375,7 @@ namespace MediaBrowser.Providers.Manager var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : season.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); var imageFilename = "season" + seasonMarker + "-landscape" + extension; @@ -400,7 +398,7 @@ namespace MediaBrowser.Providers.Manager var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : season.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); var imageFilename = "season" + seasonMarker + "-banner" + extension; @@ -495,12 +493,12 @@ namespace MediaBrowser.Providers.Manager var filenames = images.Select(i => Path.GetFileNameWithoutExtension(i.Path)).ToList(); var current = 1; - while (filenames.Contains(numberedIndexPrefix + current.ToString(UsCulture), StringComparer.OrdinalIgnoreCase)) + while (filenames.Contains(numberedIndexPrefix + current.ToString(CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase)) { current++; } - return numberedIndexPrefix + current.ToString(UsCulture); + return numberedIndexPrefix + current.ToString(CultureInfo.InvariantCulture); } /// @@ -539,7 +537,7 @@ namespace MediaBrowser.Providers.Manager var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : season.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); var imageFilename = "season" + seasonMarker + "-fanart" + extension; @@ -556,7 +554,7 @@ namespace MediaBrowser.Providers.Manager if (item.IsInMixedFolder) { - return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + outputIndex.ToString(UsCulture), extension) }; + return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + outputIndex.ToString(CultureInfo.InvariantCulture), extension) }; } var extraFanartFilename = GetBackdropSaveFilename(item.GetImages(ImageType.Backdrop), "fanart", "fanart", outputIndex); @@ -568,7 +566,7 @@ namespace MediaBrowser.Providers.Manager if (EnableExtraThumbsDuplication) { - list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension)); + list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(CultureInfo.InvariantCulture) + extension)); } return list.ToArray(); @@ -582,7 +580,7 @@ namespace MediaBrowser.Providers.Manager var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : season.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); var imageFilename = "season" + seasonMarker + "-poster" + extension; diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 479ae0f391..b2bc58eea1 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -26,7 +26,6 @@ namespace MediaBrowser.Providers.Plugins.Omdb private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly IHttpClientFactory _httpClientFactory; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IApplicationHost _appHost; private readonly JsonSerializerOptions _jsonOptions; @@ -79,7 +78,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } if (!string.IsNullOrEmpty(result.Year) && result.Year.Length >= 4 - && int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, _usCulture, out var year) + && int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, CultureInfo.InvariantCulture, out var year) && year >= 0) { item.ProductionYear = year; @@ -93,14 +92,14 @@ namespace MediaBrowser.Providers.Plugins.Omdb } if (!string.IsNullOrEmpty(result.imdbVotes) - && int.TryParse(result.imdbVotes, NumberStyles.Number, _usCulture, out var voteCount) + && int.TryParse(result.imdbVotes, NumberStyles.Number, CultureInfo.InvariantCulture, out var voteCount) && voteCount >= 0) { // item.VoteCount = voteCount; } if (!string.IsNullOrEmpty(result.imdbRating) - && float.TryParse(result.imdbRating, NumberStyles.Any, _usCulture, out var imdbRating) + && float.TryParse(result.imdbRating, NumberStyles.Any, CultureInfo.InvariantCulture, out var imdbRating) && imdbRating >= 0) { item.CommunityRating = imdbRating; @@ -191,7 +190,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } if (!string.IsNullOrEmpty(result.Year) && result.Year.Length >= 4 - && int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, _usCulture, out var year) + && int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, CultureInfo.InvariantCulture, out var year) && year >= 0) { item.ProductionYear = year; @@ -205,14 +204,14 @@ namespace MediaBrowser.Providers.Plugins.Omdb } if (!string.IsNullOrEmpty(result.imdbVotes) - && int.TryParse(result.imdbVotes, NumberStyles.Number, _usCulture, out var voteCount) + && int.TryParse(result.imdbVotes, NumberStyles.Number, CultureInfo.InvariantCulture, out var voteCount) && voteCount >= 0) { // item.VoteCount = voteCount; } if (!string.IsNullOrEmpty(result.imdbRating) - && float.TryParse(result.imdbRating, NumberStyles.Any, _usCulture, out var imdbRating) + && float.TryParse(result.imdbRating, NumberStyles.Any, CultureInfo.InvariantCulture, out var imdbRating) && imdbRating >= 0) { item.CommunityRating = imdbRating; diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index f7f4ea0652..9d558b6ce7 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -58,8 +58,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers _directoryService = directoryService; } - protected CultureInfo UsCulture { get; } = new CultureInfo("en-US"); - /// /// Gets the logger. /// @@ -309,7 +307,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrEmpty(text)) { - if (float.TryParse(text, NumberStyles.Any, UsCulture, out var value)) + if (float.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { item.CriticRating = value; } @@ -370,7 +368,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val) && userData != null) { - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var count)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var count)) { userData.PlayCount = count; } @@ -475,7 +473,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(text)) { - if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, UsCulture, out var runtime)) + if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, CultureInfo.InvariantCulture, out var runtime)) { item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; } @@ -1265,7 +1263,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var intVal)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intVal)) { sortOrder = intVal; } diff --git a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs index 3a305024ee..d2f349ad7a 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs @@ -163,7 +163,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var rval)) { item.AirsBeforeEpisodeNumber = rval; } @@ -179,7 +179,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var rval)) { item.AirsAfterSeasonNumber = rval; } @@ -195,7 +195,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var rval)) { item.AirsBeforeSeasonNumber = rval; } @@ -211,7 +211,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var rval)) { item.AirsBeforeSeasonNumber = rval; } @@ -227,7 +227,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) + if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var rval)) { item.AirsBeforeEpisodeNumber = rval; } diff --git a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs index 62f80e81bd..2cd3fdf028 100644 --- a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs @@ -17,8 +17,6 @@ namespace MediaBrowser.XbmcMetadata.Savers /// public class EpisodeNfoSaver : BaseNfoSaver { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - /// /// Initializes a new instance of the class. /// @@ -60,17 +58,17 @@ namespace MediaBrowser.XbmcMetadata.Savers if (episode.IndexNumber.HasValue) { - writer.WriteElementString("episode", episode.IndexNumber.Value.ToString(_usCulture)); + writer.WriteElementString("episode", episode.IndexNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.IndexNumberEnd.HasValue) { - writer.WriteElementString("episodenumberend", episode.IndexNumberEnd.Value.ToString(_usCulture)); + writer.WriteElementString("episodenumberend", episode.IndexNumberEnd.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.ParentIndexNumber.HasValue) { - writer.WriteElementString("season", episode.ParentIndexNumber.Value.ToString(_usCulture)); + writer.WriteElementString("season", episode.ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.PremiereDate.HasValue) @@ -84,28 +82,28 @@ namespace MediaBrowser.XbmcMetadata.Savers { if (episode.AirsAfterSeasonNumber.HasValue && episode.AirsAfterSeasonNumber.Value != -1) { - writer.WriteElementString("airsafter_season", episode.AirsAfterSeasonNumber.Value.ToString(_usCulture)); + writer.WriteElementString("airsafter_season", episode.AirsAfterSeasonNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.AirsBeforeEpisodeNumber.HasValue && episode.AirsBeforeEpisodeNumber.Value != -1) { - writer.WriteElementString("airsbefore_episode", episode.AirsBeforeEpisodeNumber.Value.ToString(_usCulture)); + writer.WriteElementString("airsbefore_episode", episode.AirsBeforeEpisodeNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.AirsBeforeSeasonNumber.HasValue && episode.AirsBeforeSeasonNumber.Value != -1) { - writer.WriteElementString("airsbefore_season", episode.AirsBeforeSeasonNumber.Value.ToString(_usCulture)); + writer.WriteElementString("airsbefore_season", episode.AirsBeforeSeasonNumber.Value.ToString(CultureInfo.InvariantCulture)); } if (episode.AirsBeforeEpisodeNumber.HasValue && episode.AirsBeforeEpisodeNumber.Value != -1) { - writer.WriteElementString("displayepisode", episode.AirsBeforeEpisodeNumber.Value.ToString(_usCulture)); + writer.WriteElementString("displayepisode", episode.AirsBeforeEpisodeNumber.Value.ToString(CultureInfo.InvariantCulture)); } var specialSeason = episode.AiredSeasonNumber; if (specialSeason.HasValue && specialSeason.Value != -1) { - writer.WriteElementString("displayseason", specialSeason.Value.ToString(_usCulture)); + writer.WriteElementString("displayseason", specialSeason.Value.ToString(CultureInfo.InvariantCulture)); } } } -- cgit v1.2.3 From 7668cd13f559d25833ad53e85e939f1d7b836111 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sun, 26 Sep 2021 16:23:43 -0600 Subject: Create output directory when extracting archive files --- Emby.Server.Implementations/Archiving/ZipClient.cs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Archiving/ZipClient.cs b/Emby.Server.Implementations/Archiving/ZipClient.cs index 591ae547d6..9e1d550ebc 100644 --- a/Emby.Server.Implementations/Archiving/ZipClient.cs +++ b/Emby.Server.Implementations/Archiving/ZipClient.cs @@ -45,6 +45,7 @@ namespace Emby.Server.Implementations.Archiving options.Overwrite = true; } + Directory.CreateDirectory(targetPath); reader.WriteAllToDirectory(targetPath, options); } @@ -58,6 +59,7 @@ namespace Emby.Server.Implementations.Archiving Overwrite = overwriteExistingFiles }; + Directory.CreateDirectory(targetPath); reader.WriteAllToDirectory(targetPath, options); } @@ -71,6 +73,7 @@ namespace Emby.Server.Implementations.Archiving Overwrite = overwriteExistingFiles }; + Directory.CreateDirectory(targetPath); reader.WriteAllToDirectory(targetPath, options); } @@ -120,6 +123,7 @@ namespace Emby.Server.Implementations.Archiving Overwrite = overwriteExistingFiles }; + Directory.CreateDirectory(targetPath); reader.WriteAllToDirectory(targetPath, options); } @@ -151,6 +155,7 @@ namespace Emby.Server.Implementations.Archiving Overwrite = overwriteExistingFiles }; + Directory.CreateDirectory(targetPath); reader.WriteAllToDirectory(targetPath, options); } } -- cgit v1.2.3 From 7bf2ece20e11cefca9160d75cd0d9e80bb04fe46 Mon Sep 17 00:00:00 2001 From: Tim040 Date: Wed, 29 Sep 2021 14:19:51 +0000 Subject: Translated using Weblate (Dutch) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nl/ --- Emby.Server.Implementations/Localization/Core/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/nl.json b/Emby.Server.Implementations/Localization/Core/nl.json index f79840c781..79f921bcb2 100644 --- a/Emby.Server.Implementations/Localization/Core/nl.json +++ b/Emby.Server.Implementations/Localization/Core/nl.json @@ -15,7 +15,7 @@ "Favorites": "Favorieten", "Folders": "Mappen", "Genres": "Genres", - "HeaderAlbumArtists": "Albumartiesten", + "HeaderAlbumArtists": "Artiests Album", "HeaderContinueWatching": "Kijken hervatten", "HeaderFavoriteAlbums": "Favoriete albums", "HeaderFavoriteArtists": "Favoriete artiesten", -- cgit v1.2.3 From 1ee58bf0200986cbddcab8ce9fd4fa930bee84e1 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 1 Oct 2021 11:21:22 +0200 Subject: Enable nullable for ItemDataProvider --- .../LiveTv/EmbyTV/ItemDataProvider.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index 4a031e4752..46979bfc57 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -1,9 +1,8 @@ -#nullable disable - #pragma warning disable CS1591 using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text.Json; @@ -18,7 +17,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private readonly string _dataPath; private readonly object _fileDataLock = new object(); private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; - private T[] _items; + private T[]? _items; public ItemDataProvider( ILogger logger, @@ -34,6 +33,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV protected Func EqualityComparer { get; } + [MemberNotNull(nameof(_items))] private void EnsureLoaded() { if (_items != null) @@ -49,6 +49,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var bytes = File.ReadAllBytes(_dataPath); _items = JsonSerializer.Deserialize(bytes, _jsonOptions); + if (_items == null) + { + Logger.LogError("Error deserializing {Path}, data was null", _dataPath); + _items = Array.Empty(); + } + return; } catch (JsonException ex) @@ -62,7 +68,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private void SaveList() { - Directory.CreateDirectory(Path.GetDirectoryName(_dataPath)); + Directory.CreateDirectory(Path.GetDirectoryName(_dataPath) ?? throw new ArgumentException("Path can't be a root directory.", nameof(_dataPath))); var jsonString = JsonSerializer.Serialize(_items, _jsonOptions); File.WriteAllText(_dataPath, jsonString); } -- cgit v1.2.3 From 5043a887cc1a837fae76b7ebd7403750dfef6c7d Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 11:54:31 -0400 Subject: Document IStartupOptions --- Emby.Server.Implementations/IStartupOptions.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/IStartupOptions.cs b/Emby.Server.Implementations/IStartupOptions.cs index 1d97882db5..3769ae4dd8 100644 --- a/Emby.Server.Implementations/IStartupOptions.cs +++ b/Emby.Server.Implementations/IStartupOptions.cs @@ -1,7 +1,8 @@ -#pragma warning disable CS1591 - namespace Emby.Server.Implementations { + /// + /// Specifies the contract for server startup options. + /// public interface IStartupOptions { /// @@ -10,7 +11,7 @@ namespace Emby.Server.Implementations string? FFmpegPath { get; } /// - /// Gets a value value indicating whether to run as service by the --service command line option. + /// Gets a value indicating whether to run as service by the --service command line option. /// bool IsService { get; } -- cgit v1.2.3 From 4ba9b6c30568c239ab9070734746c03765faac8f Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 12:53:51 -0400 Subject: Fix warnings in ScheduledTasks --- .../ScheduledTasks/ScheduledTaskWorker.cs | 14 ++++----- .../ScheduledTasks/TaskManager.cs | 26 ++++++++--------- .../ScheduledTasks/Tasks/ChapterImagesTask.cs | 6 ++++ .../ScheduledTasks/Tasks/OptimizeDatabaseTask.cs | 3 ++ .../ScheduledTasks/Tasks/PeopleValidationTask.cs | 29 ++++++++++--------- .../Tasks/RefreshMediaLibraryTask.cs | 33 ++++++++-------------- 6 files changed, 56 insertions(+), 55 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index fb93c375d8..f2cdfeb16c 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -10,9 +10,9 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Events; +using Jellyfin.Extensions.Json; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using Jellyfin.Extensions.Json; using MediaBrowser.Common.Progress; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; @@ -24,6 +24,11 @@ namespace Emby.Server.Implementations.ScheduledTasks /// public class ScheduledTaskWorker : IScheduledTaskWorker { + /// + /// The options for the json Serializer. + /// + private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; + /// /// Gets or sets the application paths. /// @@ -66,11 +71,6 @@ namespace Emby.Server.Implementations.ScheduledTasks /// private string _id; - /// - /// The options for the json Serializer. - /// - private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; - /// /// Initializes a new instance of the class. /// @@ -365,7 +365,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// Task options. /// Task. - /// Cannot execute a Task that is already running + /// Cannot execute a Task that is already running. public async Task Execute(TaskOptions options) { var task = Task.Run(async () => await ExecuteInternal(options).ConfigureAwait(false)); diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index 4f0df75bf8..0431858fca 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -19,16 +19,6 @@ namespace Emby.Server.Implementations.ScheduledTasks /// public class TaskManager : ITaskManager { - public event EventHandler> TaskExecuting; - - public event EventHandler TaskCompleted; - - /// - /// Gets the list of Scheduled Tasks. - /// - /// The scheduled tasks. - public IScheduledTaskWorker[] ScheduledTasks { get; private set; } - /// /// The _task queue. /// @@ -53,10 +43,20 @@ namespace Emby.Server.Implementations.ScheduledTasks ScheduledTasks = Array.Empty(); } + public event EventHandler> TaskExecuting; + + public event EventHandler TaskCompleted; + + /// + /// Gets the list of Scheduled Tasks. + /// + /// The scheduled tasks. + public IScheduledTaskWorker[] ScheduledTasks { get; private set; } + /// /// Cancels if running and queue. /// - /// + /// The task type. /// Task options. public void CancelIfRunningAndQueue(TaskOptions options) where T : IScheduledTask @@ -76,7 +76,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// Cancels if running. /// - /// + /// The task type. public void CancelIfRunning() where T : IScheduledTask { @@ -87,7 +87,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// Queues the scheduled task. /// - /// + /// The task type. /// Task options. public void QueueScheduledTask(TaskOptions options) where T : IScheduledTask diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs index b764a139cb..09ea6271d9 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs @@ -39,6 +39,12 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// Initializes a new instance of the class. /// + /// The library manager.. + /// The item repository. + /// The application paths. + /// The encoding manager. + /// The filesystem. + /// The localization manager. public ChapterImagesTask( ILibraryManager libraryManager, IItemRepository itemRepo, diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs index 1ad1d0f50a..35a4aeef69 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs @@ -22,6 +22,9 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks /// /// Initializes a new instance of the class. /// + /// The logger. + /// The localization manager. + /// The jellyfin DB context provider. public OptimizeDatabaseTask( ILogger logger, ILocalizationManager localization, diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs index 57d294a408..53c692a461 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs @@ -32,9 +32,24 @@ namespace Emby.Server.Implementations.ScheduledTasks _localization = localization; } + public string Name => _localization.GetLocalizedString("TaskRefreshPeople"); + + public string Description => _localization.GetLocalizedString("TaskRefreshPeopleDescription"); + + public string Category => _localization.GetLocalizedString("TasksLibraryCategory"); + + public string Key => "RefreshPeople"; + + public bool IsHidden => false; + + public bool IsEnabled => true; + + public bool IsLogged => true; + /// /// Creates the triggers that define when the task will run. /// + /// An containing the default trigger infos for this task. public IEnumerable GetDefaultTriggers() { return new[] @@ -57,19 +72,5 @@ namespace Emby.Server.Implementations.ScheduledTasks { return _libraryManager.ValidatePeople(cancellationToken, progress); } - - public string Name => _localization.GetLocalizedString("TaskRefreshPeople"); - - public string Description => _localization.GetLocalizedString("TaskRefreshPeopleDescription"); - - public string Category => _localization.GetLocalizedString("TasksLibraryCategory"); - - public string Key => "RefreshPeople"; - - public bool IsHidden => false; - - public bool IsEnabled => true; - - public bool IsLogged => true; } } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs index 51b620404b..2184b3d033 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs @@ -33,6 +33,18 @@ namespace Emby.Server.Implementations.ScheduledTasks _localization = localization; } + /// + public string Name => _localization.GetLocalizedString("TaskRefreshLibrary"); + + /// + public string Description => _localization.GetLocalizedString("TaskRefreshLibraryDescription"); + + /// + public string Category => _localization.GetLocalizedString("TasksLibraryCategory"); + + /// + public string Key => "RefreshLibrary"; + /// /// Creates the triggers that define when the task will run. /// @@ -60,26 +72,5 @@ namespace Emby.Server.Implementations.ScheduledTasks return ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken); } - - /// - public string Name => _localization.GetLocalizedString("TaskRefreshLibrary"); - - /// - public string Description => _localization.GetLocalizedString("TaskRefreshLibraryDescription"); - - /// - public string Category => _localization.GetLocalizedString("TasksLibraryCategory"); - - /// - public string Key => "RefreshLibrary"; - - /// - public bool IsHidden => false; - - /// - public bool IsEnabled => true; - - /// - public bool IsLogged => true; } } -- cgit v1.2.3 From 21007aec2038b88734ae19287081bcb1b04f6300 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 13:03:04 -0400 Subject: Fix warnings in Data --- .../Data/BaseSqliteRepository.cs | 51 --- .../Data/ManagedConnection.cs | 4 +- .../Data/SqliteItemRepository.cs | 481 +++++++++++---------- .../Data/SqliteUserDataRepository.cs | 7 +- .../Data/SynchronouseMode.cs | 30 ++ Emby.Server.Implementations/Data/TempStoreMode.cs | 23 + 6 files changed, 302 insertions(+), 294 deletions(-) create mode 100644 Emby.Server.Implementations/Data/SynchronouseMode.cs create mode 100644 Emby.Server.Implementations/Data/TempStoreMode.cs (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 01c9fbca81..4f6c811028 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -249,55 +249,4 @@ namespace Emby.Server.Implementations.Data _disposed = true; } } - - /// - /// The disk synchronization mode, controls how aggressively SQLite will write data - /// all the way out to physical storage. - /// - public enum SynchronousMode - { - /// - /// SQLite continues without syncing as soon as it has handed data off to the operating system. - /// - Off = 0, - - /// - /// SQLite database engine will still sync at the most critical moments. - /// - Normal = 1, - - /// - /// SQLite database engine will use the xSync method of the VFS - /// to ensure that all content is safely written to the disk surface prior to continuing. - /// - Full = 2, - - /// - /// EXTRA synchronous is like FULL with the addition that the directory containing a rollback journal - /// is synced after that journal is unlinked to commit a transaction in DELETE mode. - /// - Extra = 3 - } - - /// - /// Storage mode used by temporary database files. - /// - public enum TempStoreMode - { - /// - /// The compile-time C preprocessor macro SQLITE_TEMP_STORE - /// is used to determine where temporary tables and indices are stored. - /// - Default = 0, - - /// - /// Temporary tables and indices are stored in a file. - /// - File = 1, - - /// - /// Temporary tables and indices are kept in as if they were pure in-memory databases memory. - /// - Memory = 2 - } } diff --git a/Emby.Server.Implementations/Data/ManagedConnection.cs b/Emby.Server.Implementations/Data/ManagedConnection.cs index afc8966f9c..44dad5b178 100644 --- a/Emby.Server.Implementations/Data/ManagedConnection.cs +++ b/Emby.Server.Implementations/Data/ManagedConnection.cs @@ -9,8 +9,10 @@ namespace Emby.Server.Implementations.Data { public class ManagedConnection : IDisposable { - private SQLiteDatabaseConnection? _db; private readonly SemaphoreSlim _writeLock; + + private SQLiteDatabaseConnection? _db; + private bool _disposed = false; public ManagedConnection(SQLiteDatabaseConnection db, SemaphoreSlim writeLock) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 0a48b844dd..13f1df7c86 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -46,6 +46,11 @@ namespace Emby.Server.Implementations.Data private const string FromText = " from TypedBaseItems A"; private const string ChaptersTableName = "Chapters2"; + private const string SaveItemCommandText = + @"replace into TypedBaseItems + (guid,type,data,Path,StartDate,EndDate,ChannelId,IsMovie,IsSeries,EpisodeTitle,IsRepeat,CommunityRating,CustomRating,IndexNumber,IsLocked,Name,OfficialRating,MediaType,Overview,ParentIndexNumber,PremiereDate,ProductionYear,ParentId,Genres,InheritedParentalRatingValue,SortName,ForcedSortName,RunTimeTicks,Size,DateCreated,DateModified,PreferredMetadataLanguage,PreferredMetadataCountryCode,Width,Height,DateLastRefreshed,DateLastSaved,IsInMixedFolder,LockedFields,Studios,Audio,ExternalServiceId,Tags,IsFolder,UnratedType,TopParentId,TrailerTypes,CriticRating,CleanName,PresentationUniqueKey,OriginalTitle,PrimaryVersionId,DateLastMediaAdded,Album,IsVirtualItem,SeriesName,UserDataKey,SeasonName,SeasonId,SeriesId,ExternalSeriesId,Tagline,ProviderIds,Images,ProductionLocations,ExtraIds,TotalBitrate,ExtraType,Artists,AlbumArtists,ExternalId,SeriesPresentationUniqueKey,ShowId,OwnerId) + values (@guid,@type,@data,@Path,@StartDate,@EndDate,@ChannelId,@IsMovie,@IsSeries,@EpisodeTitle,@IsRepeat,@CommunityRating,@CustomRating,@IndexNumber,@IsLocked,@Name,@OfficialRating,@MediaType,@Overview,@ParentIndexNumber,@PremiereDate,@ProductionYear,@ParentId,@Genres,@InheritedParentalRatingValue,@SortName,@ForcedSortName,@RunTimeTicks,@Size,@DateCreated,@DateModified,@PreferredMetadataLanguage,@PreferredMetadataCountryCode,@Width,@Height,@DateLastRefreshed,@DateLastSaved,@IsInMixedFolder,@LockedFields,@Studios,@Audio,@ExternalServiceId,@Tags,@IsFolder,@UnratedType,@TopParentId,@TrailerTypes,@CriticRating,@CleanName,@PresentationUniqueKey,@OriginalTitle,@PrimaryVersionId,@DateLastMediaAdded,@Album,@IsVirtualItem,@SeriesName,@UserDataKey,@SeasonName,@SeasonId,@SeriesId,@ExternalSeriesId,@Tagline,@ProviderIds,@Images,@ProductionLocations,@ExtraIds,@TotalBitrate,@ExtraType,@Artists,@AlbumArtists,@ExternalId,@SeriesPresentationUniqueKey,@ShowId,@OwnerId)"; + private readonly IServerConfigurationManager _config; private readonly IServerApplicationHost _appHost; private readonly ILocalizationManager _localization; @@ -55,6 +60,231 @@ namespace Emby.Server.Implementations.Data private readonly TypeMapper _typeMapper; private readonly JsonSerializerOptions _jsonOptions; + private readonly ItemFields[] _allItemFields = Enum.GetValues(); + + private static readonly string[] _retriveItemColumns = + { + "type", + "data", + "StartDate", + "EndDate", + "ChannelId", + "IsMovie", + "IsSeries", + "EpisodeTitle", + "IsRepeat", + "CommunityRating", + "CustomRating", + "IndexNumber", + "IsLocked", + "PreferredMetadataLanguage", + "PreferredMetadataCountryCode", + "Width", + "Height", + "DateLastRefreshed", + "Name", + "Path", + "PremiereDate", + "Overview", + "ParentIndexNumber", + "ProductionYear", + "OfficialRating", + "ForcedSortName", + "RunTimeTicks", + "Size", + "DateCreated", + "DateModified", + "guid", + "Genres", + "ParentId", + "Audio", + "ExternalServiceId", + "IsInMixedFolder", + "DateLastSaved", + "LockedFields", + "Studios", + "Tags", + "TrailerTypes", + "OriginalTitle", + "PrimaryVersionId", + "DateLastMediaAdded", + "Album", + "CriticRating", + "IsVirtualItem", + "SeriesName", + "SeasonName", + "SeasonId", + "SeriesId", + "PresentationUniqueKey", + "InheritedParentalRatingValue", + "ExternalSeriesId", + "Tagline", + "ProviderIds", + "Images", + "ProductionLocations", + "ExtraIds", + "TotalBitrate", + "ExtraType", + "Artists", + "AlbumArtists", + "ExternalId", + "SeriesPresentationUniqueKey", + "ShowId", + "OwnerId" + }; + + private static readonly string _retriveItemColumnsSelectQuery = $"select {string.Join(',', _retriveItemColumns)} from TypedBaseItems where guid = @guid"; + + private static readonly string[] _mediaStreamSaveColumns = + { + "ItemId", + "StreamIndex", + "StreamType", + "Codec", + "Language", + "ChannelLayout", + "Profile", + "AspectRatio", + "Path", + "IsInterlaced", + "BitRate", + "Channels", + "SampleRate", + "IsDefault", + "IsForced", + "IsExternal", + "Height", + "Width", + "AverageFrameRate", + "RealFrameRate", + "Level", + "PixelFormat", + "BitDepth", + "IsAnamorphic", + "RefFrames", + "CodecTag", + "Comment", + "NalLengthSize", + "IsAvc", + "Title", + "TimeBase", + "CodecTimeBase", + "ColorPrimaries", + "ColorSpace", + "ColorTransfer" + }; + + private static readonly string _mediaStreamSaveColumnsInsertQuery = + $"insert into mediastreams ({string.Join(',', _mediaStreamSaveColumns)}) values "; + + private static readonly string _mediaStreamSaveColumnsSelectQuery = + $"select {string.Join(',', _mediaStreamSaveColumns)} from mediastreams where ItemId=@ItemId"; + + private static readonly string[] _mediaAttachmentSaveColumns = + { + "ItemId", + "AttachmentIndex", + "Codec", + "CodecTag", + "Comment", + "Filename", + "MIMEType" + }; + + private static readonly string _mediaAttachmentSaveColumnsSelectQuery = + $"select {string.Join(',', _mediaAttachmentSaveColumns)} from mediaattachments where ItemId=@ItemId"; + + private static readonly string _mediaAttachmentInsertPrefix; + + private static readonly HashSet _programTypes = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "Program", + "TvChannel", + "LiveTvProgram", + "LiveTvTvChannel" + }; + + private static readonly HashSet _programExcludeParentTypes = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "Series", + "Season", + "MusicAlbum", + "MusicArtist", + "PhotoAlbum" + }; + + private static readonly HashSet _serviceTypes = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "TvChannel", + "LiveTvTvChannel" + }; + + private static readonly HashSet _startDateTypes = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "Program", + "LiveTvProgram" + }; + + private static readonly HashSet _seriesTypes = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "Book", + "AudioBook", + "Episode", + "Season" + }; + + private static readonly HashSet _artistExcludeParentTypes = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "Series", + "Season", + "PhotoAlbum" + }; + + private static readonly HashSet _artistsTypes = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "Audio", + "MusicAlbum", + "MusicVideo", + "AudioBook", + "AudioPodcast" + }; + + private static readonly Type[] _knownTypes = + { + typeof(LiveTvProgram), + typeof(LiveTvChannel), + typeof(Series), + typeof(Audio), + typeof(MusicAlbum), + typeof(MusicArtist), + typeof(MusicGenre), + typeof(MusicVideo), + typeof(Movie), + typeof(Playlist), + typeof(AudioBook), + typeof(Trailer), + typeof(BoxSet), + typeof(Episode), + typeof(Season), + typeof(Series), + typeof(Book), + typeof(CollectionFolder), + typeof(Folder), + typeof(Genre), + typeof(Person), + typeof(Photo), + typeof(PhotoAlbum), + typeof(Studio), + typeof(UserRootFolder), + typeof(UserView), + typeof(Video), + typeof(Year), + typeof(Channel), + typeof(AggregateFolder) + }; + + private readonly Dictionary _types = GetTypeMapDictionary(); + static SqliteItemRepository() { var queryPrefixText = new StringBuilder(); @@ -115,6 +345,8 @@ namespace Emby.Server.Implementations.Data /// /// Opens the connection to the database. /// + /// The user data repository. + /// The user manager. public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager) { const string CreateMediaStreamsTableCommand @@ -154,7 +386,7 @@ namespace Emby.Server.Implementations.Data "drop index if exists idx_TypedBaseItems", "drop index if exists idx_mediastreams", "drop index if exists idx_mediastreams1", - "drop index if exists idx_"+ChaptersTableName, + "drop index if exists idx_" + ChaptersTableName, "drop index if exists idx_UserDataKeys1", "drop index if exists idx_UserDataKeys2", "drop index if exists idx_TypeTopParentId3", @@ -340,151 +572,12 @@ namespace Emby.Server.Implementations.Data userDataRepo.Initialize(userManager, WriteLock, WriteConnection); } - private static readonly string[] _retriveItemColumns = - { - "type", - "data", - "StartDate", - "EndDate", - "ChannelId", - "IsMovie", - "IsSeries", - "EpisodeTitle", - "IsRepeat", - "CommunityRating", - "CustomRating", - "IndexNumber", - "IsLocked", - "PreferredMetadataLanguage", - "PreferredMetadataCountryCode", - "Width", - "Height", - "DateLastRefreshed", - "Name", - "Path", - "PremiereDate", - "Overview", - "ParentIndexNumber", - "ProductionYear", - "OfficialRating", - "ForcedSortName", - "RunTimeTicks", - "Size", - "DateCreated", - "DateModified", - "guid", - "Genres", - "ParentId", - "Audio", - "ExternalServiceId", - "IsInMixedFolder", - "DateLastSaved", - "LockedFields", - "Studios", - "Tags", - "TrailerTypes", - "OriginalTitle", - "PrimaryVersionId", - "DateLastMediaAdded", - "Album", - "CriticRating", - "IsVirtualItem", - "SeriesName", - "SeasonName", - "SeasonId", - "SeriesId", - "PresentationUniqueKey", - "InheritedParentalRatingValue", - "ExternalSeriesId", - "Tagline", - "ProviderIds", - "Images", - "ProductionLocations", - "ExtraIds", - "TotalBitrate", - "ExtraType", - "Artists", - "AlbumArtists", - "ExternalId", - "SeriesPresentationUniqueKey", - "ShowId", - "OwnerId" - }; - - private static readonly string _retriveItemColumnsSelectQuery = $"select {string.Join(',', _retriveItemColumns)} from TypedBaseItems where guid = @guid"; - - private static readonly string[] _mediaStreamSaveColumns = - { - "ItemId", - "StreamIndex", - "StreamType", - "Codec", - "Language", - "ChannelLayout", - "Profile", - "AspectRatio", - "Path", - "IsInterlaced", - "BitRate", - "Channels", - "SampleRate", - "IsDefault", - "IsForced", - "IsExternal", - "Height", - "Width", - "AverageFrameRate", - "RealFrameRate", - "Level", - "PixelFormat", - "BitDepth", - "IsAnamorphic", - "RefFrames", - "CodecTag", - "Comment", - "NalLengthSize", - "IsAvc", - "Title", - "TimeBase", - "CodecTimeBase", - "ColorPrimaries", - "ColorSpace", - "ColorTransfer" - }; - - private static readonly string _mediaStreamSaveColumnsInsertQuery = - $"insert into mediastreams ({string.Join(',', _mediaStreamSaveColumns)}) values "; - - private static readonly string _mediaStreamSaveColumnsSelectQuery = - $"select {string.Join(',', _mediaStreamSaveColumns)} from mediastreams where ItemId=@ItemId"; - - private static readonly string[] _mediaAttachmentSaveColumns = - { - "ItemId", - "AttachmentIndex", - "Codec", - "CodecTag", - "Comment", - "Filename", - "MIMEType" - }; - - private static readonly string _mediaAttachmentSaveColumnsSelectQuery = - $"select {string.Join(',', _mediaAttachmentSaveColumns)} from mediaattachments where ItemId=@ItemId"; - - private static readonly string _mediaAttachmentInsertPrefix; - - private const string SaveItemCommandText = - @"replace into TypedBaseItems - (guid,type,data,Path,StartDate,EndDate,ChannelId,IsMovie,IsSeries,EpisodeTitle,IsRepeat,CommunityRating,CustomRating,IndexNumber,IsLocked,Name,OfficialRating,MediaType,Overview,ParentIndexNumber,PremiereDate,ProductionYear,ParentId,Genres,InheritedParentalRatingValue,SortName,ForcedSortName,RunTimeTicks,Size,DateCreated,DateModified,PreferredMetadataLanguage,PreferredMetadataCountryCode,Width,Height,DateLastRefreshed,DateLastSaved,IsInMixedFolder,LockedFields,Studios,Audio,ExternalServiceId,Tags,IsFolder,UnratedType,TopParentId,TrailerTypes,CriticRating,CleanName,PresentationUniqueKey,OriginalTitle,PrimaryVersionId,DateLastMediaAdded,Album,IsVirtualItem,SeriesName,UserDataKey,SeasonName,SeasonId,SeriesId,ExternalSeriesId,Tagline,ProviderIds,Images,ProductionLocations,ExtraIds,TotalBitrate,ExtraType,Artists,AlbumArtists,ExternalId,SeriesPresentationUniqueKey,ShowId,OwnerId) - values (@guid,@type,@data,@Path,@StartDate,@EndDate,@ChannelId,@IsMovie,@IsSeries,@EpisodeTitle,@IsRepeat,@CommunityRating,@CustomRating,@IndexNumber,@IsLocked,@Name,@OfficialRating,@MediaType,@Overview,@ParentIndexNumber,@PremiereDate,@ProductionYear,@ParentId,@Genres,@InheritedParentalRatingValue,@SortName,@ForcedSortName,@RunTimeTicks,@Size,@DateCreated,@DateModified,@PreferredMetadataLanguage,@PreferredMetadataCountryCode,@Width,@Height,@DateLastRefreshed,@DateLastSaved,@IsInMixedFolder,@LockedFields,@Studios,@Audio,@ExternalServiceId,@Tags,@IsFolder,@UnratedType,@TopParentId,@TrailerTypes,@CriticRating,@CleanName,@PresentationUniqueKey,@OriginalTitle,@PrimaryVersionId,@DateLastMediaAdded,@Album,@IsVirtualItem,@SeriesName,@UserDataKey,@SeasonName,@SeasonId,@SeriesId,@ExternalSeriesId,@Tagline,@ProviderIds,@Images,@ProductionLocations,@ExtraIds,@TotalBitrate,@ExtraType,@Artists,@AlbumArtists,@ExternalId,@SeriesPresentationUniqueKey,@ShowId,@OwnerId)"; - /// /// Save a standard item in the repo. /// /// The item. /// The cancellation token. - /// item + /// is null. public void SaveItem(BaseItem item, CancellationToken cancellationToken) { if (item == null) @@ -509,7 +602,7 @@ namespace Emby.Server.Implementations.Data connection.RunInTransaction( db => { - using (var saveImagesStatement = base.PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id")) + using (var saveImagesStatement = PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id")) { saveImagesStatement.TryBind("@Id", item.Id.ToByteArray()); saveImagesStatement.TryBind("@Images", SerializeImages(item.ImageInfos)); @@ -526,9 +619,7 @@ namespace Emby.Server.Implementations.Data /// The items. /// The cancellation token. /// - /// items - /// or - /// cancellationToken + /// or is null. /// public void SaveItems(IEnumerable items, CancellationToken cancellationToken) { @@ -1216,8 +1307,8 @@ namespace Emby.Server.Implementations.Data /// /// The id. /// BaseItem. - /// id - /// + /// is null. + /// is . public BaseItem RetrieveItem(Guid id) { if (id == Guid.Empty) @@ -1986,6 +2077,8 @@ namespace Emby.Server.Implementations.Data /// /// Saves the chapters. /// + /// The item id. + /// The chapters. public void SaveChapters(Guid id, IReadOnlyList chapters) { CheckDisposed(); @@ -2085,8 +2178,6 @@ namespace Emby.Server.Implementations.Data || query.IsLiked.HasValue; } - private readonly ItemFields[] _allFields = Enum.GetValues(); - private bool HasField(InternalItemsQuery query, ItemFields name) { switch (name) @@ -2119,23 +2210,6 @@ namespace Emby.Server.Implementations.Data } } - private static readonly HashSet _programExcludeParentTypes = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "Series", - "Season", - "MusicAlbum", - "MusicArtist", - "PhotoAlbum" - }; - - private static readonly HashSet _programTypes = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "Program", - "TvChannel", - "LiveTvProgram", - "LiveTvTvChannel" - }; - private bool HasProgramAttributes(InternalItemsQuery query) { if (_programExcludeParentTypes.Contains(query.ParentType)) @@ -2151,12 +2225,6 @@ namespace Emby.Server.Implementations.Data return query.IncludeItemTypes.Any(x => _programTypes.Contains(x)); } - private static readonly HashSet _serviceTypes = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "TvChannel", - "LiveTvTvChannel" - }; - private bool HasServiceName(InternalItemsQuery query) { if (_programExcludeParentTypes.Contains(query.ParentType)) @@ -2172,12 +2240,6 @@ namespace Emby.Server.Implementations.Data return query.IncludeItemTypes.Any(x => _serviceTypes.Contains(x)); } - private static readonly HashSet _startDateTypes = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "Program", - "LiveTvProgram" - }; - private bool HasStartDate(InternalItemsQuery query) { if (_programExcludeParentTypes.Contains(query.ParentType)) @@ -2213,22 +2275,6 @@ namespace Emby.Server.Implementations.Data return query.IncludeItemTypes.Contains("Trailer", StringComparer.OrdinalIgnoreCase); } - private static readonly HashSet _artistExcludeParentTypes = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "Series", - "Season", - "PhotoAlbum" - }; - - private static readonly HashSet _artistsTypes = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "Audio", - "MusicAlbum", - "MusicVideo", - "AudioBook", - "AudioPodcast" - }; - private bool HasArtistFields(InternalItemsQuery query) { if (_artistExcludeParentTypes.Contains(query.ParentType)) @@ -2244,14 +2290,6 @@ namespace Emby.Server.Implementations.Data return query.IncludeItemTypes.Any(x => _artistsTypes.Contains(x)); } - private static readonly HashSet _seriesTypes = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "Book", - "AudioBook", - "Episode", - "Season" - }; - private bool HasSeriesFields(InternalItemsQuery query) { if (string.Equals(query.ParentType, "PhotoAlbum", StringComparison.OrdinalIgnoreCase)) @@ -2269,7 +2307,7 @@ namespace Emby.Server.Implementations.Data private void SetFinalColumnsToSelect(InternalItemsQuery query, List columns) { - foreach (var field in _allFields) + foreach (var field in _allItemFields) { if (!HasField(query, field)) { @@ -4811,40 +4849,6 @@ namespace Emby.Server.Implementations.Data return false; } - private static readonly Type[] _knownTypes = - { - typeof(LiveTvProgram), - typeof(LiveTvChannel), - typeof(Series), - typeof(Audio), - typeof(MusicAlbum), - typeof(MusicArtist), - typeof(MusicGenre), - typeof(MusicVideo), - typeof(Movie), - typeof(Playlist), - typeof(AudioBook), - typeof(Trailer), - typeof(BoxSet), - typeof(Episode), - typeof(Season), - typeof(Series), - typeof(Book), - typeof(CollectionFolder), - typeof(Folder), - typeof(Genre), - typeof(Person), - typeof(Photo), - typeof(PhotoAlbum), - typeof(Studio), - typeof(UserRootFolder), - typeof(UserView), - typeof(Video), - typeof(Year), - typeof(Channel), - typeof(AggregateFolder) - }; - public void UpdateInheritedValues() { string sql = string.Join( @@ -4886,9 +4890,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type return dict; } - // Not crazy about having this all the way down here, but at least it's in one place - private readonly Dictionary _types = GetTypeMapDictionary(); - private string MapIncludeItemTypes(string value) { if (_types.TryGetValue(value, out string result)) diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 829f1de2f6..107096b5f2 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -32,6 +32,9 @@ namespace Emby.Server.Implementations.Data /// /// Opens the connection to the database. /// + /// The user manager. + /// The lock to use for database IO. + /// The connection to use for database IO. public void Initialize(IUserManager userManager, SemaphoreSlim dbLock, SQLiteDatabaseConnection dbConnection) { WriteLock.Dispose(); @@ -49,8 +52,8 @@ namespace Emby.Server.Implementations.Data connection.RunInTransaction( db => { - db.ExecuteAll(string.Join(';', new[] { - + db.ExecuteAll(string.Join(';', new[] + { "create table if not exists UserDatas (key nvarchar not null, userId INT not null, rating float null, played bit not null, playCount int not null, isFavorite bit not null, playbackPositionTicks bigint not null, lastPlayedDate datetime null, AudioStreamIndex INT, SubtitleStreamIndex INT)", "drop index if exists idx_userdata", diff --git a/Emby.Server.Implementations/Data/SynchronouseMode.cs b/Emby.Server.Implementations/Data/SynchronouseMode.cs new file mode 100644 index 0000000000..cde524e2e0 --- /dev/null +++ b/Emby.Server.Implementations/Data/SynchronouseMode.cs @@ -0,0 +1,30 @@ +namespace Emby.Server.Implementations.Data; + +/// +/// The disk synchronization mode, controls how aggressively SQLite will write data +/// all the way out to physical storage. +/// +public enum SynchronousMode +{ + /// + /// SQLite continues without syncing as soon as it has handed data off to the operating system. + /// + Off = 0, + + /// + /// SQLite database engine will still sync at the most critical moments. + /// + Normal = 1, + + /// + /// SQLite database engine will use the xSync method of the VFS + /// to ensure that all content is safely written to the disk surface prior to continuing. + /// + Full = 2, + + /// + /// EXTRA synchronous is like FULL with the addition that the directory containing a rollback journal + /// is synced after that journal is unlinked to commit a transaction in DELETE mode. + /// + Extra = 3 +} diff --git a/Emby.Server.Implementations/Data/TempStoreMode.cs b/Emby.Server.Implementations/Data/TempStoreMode.cs new file mode 100644 index 0000000000..d2427ce478 --- /dev/null +++ b/Emby.Server.Implementations/Data/TempStoreMode.cs @@ -0,0 +1,23 @@ +namespace Emby.Server.Implementations.Data; + +/// +/// Storage mode used by temporary database files. +/// +public enum TempStoreMode +{ + /// + /// The compile-time C preprocessor macro SQLITE_TEMP_STORE + /// is used to determine where temporary tables and indices are stored. + /// + Default = 0, + + /// + /// Temporary tables and indices are stored in a file. + /// + File = 1, + + /// + /// Temporary tables and indices are kept in as if they were pure in-memory databases memory. + /// + Memory = 2 +} -- cgit v1.2.3 From 9af16fcb6c892238b734c267873b1fc137d38e66 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 3 Oct 2021 19:52:38 +0200 Subject: Remove workaround for dotnet/runtime#42790 --- Emby.Dlna/DlnaManager.cs | 9 ++++--- Emby.Drawing/ImageProcessor.cs | 2 +- .../AppBase/ConfigurationHelper.cs | 9 +++---- .../LiveTv/EmbyTV/DirectRecorder.cs | 6 ++--- .../LiveTv/EmbyTV/EmbyTV.cs | 12 +++------ .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- Jellyfin.Api/Controllers/RemoteImageController.cs | 31 ---------------------- MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 12 +++++++-- .../Subtitles/SubtitleEncoder.cs | 1 - MediaBrowser.Model/IO/AsyncFile.cs | 19 +++++++++++++ MediaBrowser.Providers/Manager/ImageSaver.cs | 6 +++-- .../Manager/ItemImageProvider.cs | 2 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 3 +-- .../Plugins/AudioDb/AudioDbAlbumProvider.cs | 7 +++-- .../Plugins/AudioDb/AudioDbArtistProvider.cs | 6 +++-- .../Studios/StudiosImageProvider.cs | 7 ++--- .../Subtitles/SubtitleManager.cs | 6 +++-- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 11 ++++++-- 18 files changed, 77 insertions(+), 74 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 8fe9d484e7..73e8a0008e 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -359,14 +359,17 @@ namespace Emby.Dlna // The stream should exist as we just got its name from GetManifestResourceNames using (var stream = _assembly.GetManifestResourceStream(name)!) { + var length = stream.Length; var fileInfo = _fileSystem.GetFileInfo(path); - if (!fileInfo.Exists || fileInfo.Length != stream.Length) + if (!fileInfo.Exists || fileInfo.Length != length) { Directory.CreateDirectory(systemProfilesPath); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + var fileOptions = AsyncFile.WriteOptions; + fileOptions.Mode = FileMode.CreateNew; + fileOptions.PreallocationSize = length; + using (var fileStream = new FileStream(path, fileOptions)) { await stream.CopyToAsync(fileStream).ConfigureAwait(false); } diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 9b130fdfd8..ac73cfa421 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -102,7 +102,7 @@ namespace Emby.Drawing { var file = await ProcessImage(options).ConfigureAwait(false); - using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + using (var fileStream = AsyncFile.OpenRead(file.Item1)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs index 0308a68e42..3a916e5c01 100644 --- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs +++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs @@ -41,20 +41,19 @@ namespace Emby.Server.Implementations.AppBase xmlSerializer.SerializeToStream(configuration, stream); // Take the object we just got and serialize it back to bytes - byte[] newBytes = stream.GetBuffer(); - int newBytesLen = (int)stream.Length; + Span newBytes = stream.GetBuffer().AsSpan(0, (int)stream.Length); // If the file didn't exist before, or if something has changed, re-save - if (buffer == null || !newBytes.AsSpan(0, newBytesLen).SequenceEqual(buffer)) + if (buffer == null || !newBytes.SequenceEqual(buffer)) { var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path)); Directory.CreateDirectory(directory); + // Save it after load in case we got new items - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) { - fs.Write(newBytes, 0, newBytesLen); + fs.Write(newBytes); } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 41381d55bd..6937cc0971 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -46,8 +46,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + using (var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { onStarted(); @@ -79,8 +78,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); + await using var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); onStarted(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 64e54aa99e..980b42729a 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1848,14 +1848,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var stream = new FileStream(nfoPath, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { var settings = new XmlWriterSettings { Indent = true, - Encoding = Encoding.UTF8, - CloseOutput = false + Encoding = Encoding.UTF8 }; using (var writer = XmlWriter.Create(stream, settings)) @@ -1913,14 +1911,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var stream = new FileStream(nfoPath, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { var settings = new XmlWriterSettings { Indent = true, - Encoding = Encoding.UTF8, - CloseOutput = false + Encoding = Encoding.UTF8 }; var options = _config.GetNfoConfiguration(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 3633fa3e10..016a3e83fa 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + _logFileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index 8a33b12f4c..35921ede8f 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -183,36 +183,5 @@ namespace Jellyfin.Api.Controllers { return Path.Combine(_applicationPaths.CachePath, "remote-images", filename.Substring(0, 1), filename); } - - /// - /// Downloads the image. - /// - /// The URL. - /// The URL hash. - /// The pointer cache path. - /// Task. - private async Task DownloadImage(Uri url, Guid urlHash, string pointerCachePath) - { - var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); - using var response = await httpClient.GetAsync(url).ConfigureAwait(false); - if (response.Content.Headers.ContentType?.MediaType == null) - { - throw new ResourceNotFoundException(nameof(response.Content.Headers.ContentType)); - } - - var ext = response.Content.Headers.ContentType.MediaType.AsSpan().RightPart('/').ToString(); - var fullCachePath = GetFullCachePath(urlHash + "." + ext); - - var fullCacheDirectory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid."); - Directory.CreateDirectory(fullCacheDirectory); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); - await response.Content.CopyToAsync(fileStream).ConfigureAwait(false); - - var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath) ?? throw new ArgumentException($"Provided path ({pointerCachePath}) is not valid.", nameof(pointerCachePath)); - Directory.CreateDirectory(pointerCacheDirectory); - await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath, CancellationToken.None) - .ConfigureAwait(false); - } } } diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 6f66fd61b0..5e7af23fc3 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -113,11 +113,19 @@ namespace MediaBrowser.LocalMetadata.Savers { var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path)); Directory.CreateDirectory(directory); + // On Windows, savint the file will fail if the file is hidden or readonly FileSystem.SetAttributes(path, false, false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) + var fileStreamOptions = new FileStreamOptions() + { + Mode = FileMode.Create, + Access = FileAccess.Write, + Share = FileShare.None, + PreallocationSize = stream.Length + }; + + using (var filestream = new FileStream(path, fileStreamOptions)) { stream.CopyTo(filestream); } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 022cdbe9d3..bfc17904cd 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -679,7 +679,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (!string.Equals(text, newText, StringComparison.Ordinal)) { - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) using (var writer = new StreamWriter(fileStream, encoding)) { diff --git a/MediaBrowser.Model/IO/AsyncFile.cs b/MediaBrowser.Model/IO/AsyncFile.cs index caee9c5289..3c8007d1c4 100644 --- a/MediaBrowser.Model/IO/AsyncFile.cs +++ b/MediaBrowser.Model/IO/AsyncFile.cs @@ -7,6 +7,25 @@ namespace MediaBrowser.Model.IO /// public static class AsyncFile { + /// + /// Gets the default for reading files async. + /// + public static FileStreamOptions ReadOptions => new FileStreamOptions() + { + Options = FileOptions.Asynchronous + }; + + /// + /// Gets the default for writing files async. + /// + public static FileStreamOptions WriteOptions => new FileStreamOptions() + { + Mode = FileMode.OpenOrCreate, + Access = FileAccess.Write, + Share = FileShare.None, + Options = FileOptions.Asynchronous + }; + /// /// Opens an existing file for reading. /// diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 4b05edd67b..3d8dd14860 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -261,8 +261,10 @@ namespace MediaBrowser.Providers.Manager _fileSystem.SetAttributes(path, false, false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + var fileStreamOptions = AsyncFile.WriteOptions; + fileStreamOptions.Mode = FileMode.Create; + fileStreamOptions.PreallocationSize = source.Length; + await using (var fs = new FileStream(path, fileStreamOptions)) { await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 73bca5aa59..3593697d7e 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -163,7 +163,7 @@ namespace MediaBrowser.Providers.Manager { var mimeType = MimeTypes.GetMimeType(response.Path); - var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + var stream = AsyncFile.OpenRead(response.Path); await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index b51a254172..9be887e9c3 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -210,8 +210,7 @@ namespace MediaBrowser.Providers.Manager throw new ArgumentNullException(nameof(source)); } - var fileStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - + var fileStream = AsyncFile.OpenRead(source); return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs index 3e0b0014eb..ebdcb94eb6 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs @@ -172,8 +172,11 @@ namespace MediaBrowser.Providers.Plugins.AudioDb using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + + var fileStreamOptions = AsyncFile.WriteOptions; + fileStreamOptions.Mode = FileMode.Create; + fileStreamOptions.PreallocationSize = stream.Length; + await using var xmlFileStream = new FileStream(path, fileStreamOptions); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs index e0b2f9c588..321013b17c 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs @@ -154,8 +154,10 @@ namespace MediaBrowser.Providers.Plugins.AudioDb Directory.CreateDirectory(Path.GetDirectoryName(path)); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + var fileStreamOptions = AsyncFile.WriteOptions; + fileStreamOptions.Mode = FileMode.Create; + fileStreamOptions.PreallocationSize = stream.Length; + await using var xmlFileStream = new FileStream(path, fileStreamOptions); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index 7b2454efc9..a1873eaae4 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -172,19 +172,16 @@ namespace MediaBrowser.Providers.Studios public IEnumerable GetAvailableImages(string file) { - using var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read); + using var fileStream = File.OpenRead(file); using var reader = new StreamReader(fileStream); - var lines = new List(); foreach (var line in reader.ReadAllLines()) { if (!string.IsNullOrWhiteSpace(line)) { - lines.Add(line); + yield return line; } } - - return lines; } } } diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index 772e617abb..e625b0dd2a 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -244,8 +244,10 @@ namespace MediaBrowser.Providers.Subtitles { Directory.CreateDirectory(Path.GetDirectoryName(savePath)); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, FileOptions.Asynchronous); + var fileOptions = AsyncFile.WriteOptions; + fileOptions.Mode = FileMode.CreateNew; + fileOptions.PreallocationSize = stream.Length; + using var fs = new FileStream(savePath, fileOptions); await stream.CopyToAsync(fs).ConfigureAwait(false); return; diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 38726a6f08..594402258a 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -203,8 +203,15 @@ namespace MediaBrowser.XbmcMetadata.Savers // On Windows, saving the file will fail if the file is hidden or readonly FileSystem.SetAttributes(path, false, false); - // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) + var fileStreamOptions = new FileStreamOptions() + { + Mode = FileMode.Create, + Access = FileAccess.Write, + Share = FileShare.None, + PreallocationSize = stream.Length + }; + + using (var filestream = new FileStream(path, fileStreamOptions)) { stream.CopyTo(filestream); } -- cgit v1.2.3 From 078200d8d4ba6d986cce8881b17d30b82e58b038 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 13:23:05 -0400 Subject: Fix warnings in Sorting --- .../Sorting/AiredEpisodeOrderComparer.cs | 12 ++++---- .../Sorting/AlbumArtistComparer.cs | 12 ++++---- .../Sorting/AlbumComparer.cs | 12 ++++---- .../Sorting/CriticRatingComparer.cs | 12 ++++---- .../Sorting/DateCreatedComparer.cs | 12 ++++---- .../Sorting/DatePlayedComparer.cs | 12 ++++---- .../Sorting/NameComparer.cs | 12 ++++---- .../Sorting/PlayCountComparer.cs | 36 +++++++++++----------- .../Sorting/PremiereDateComparer.cs | 12 ++++---- .../Sorting/ProductionYearComparer.cs | 12 ++++---- .../Sorting/RandomComparer.cs | 12 ++++---- .../Sorting/RuntimeComparer.cs | 12 ++++---- .../Sorting/SortNameComparer.cs | 12 ++++---- .../Sorting/StudioComparer.cs | 12 ++++---- 14 files changed, 96 insertions(+), 96 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs b/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs index 037eb170ac..db8b689491 100644 --- a/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs +++ b/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs @@ -10,6 +10,12 @@ namespace Emby.Server.Implementations.Sorting { public class AiredEpisodeOrderComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.AiredEpisodeOrder; + /// /// Compares the specified x. /// @@ -155,11 +161,5 @@ namespace Emby.Server.Implementations.Sorting return comparisonResult; } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.AiredEpisodeOrder; } } diff --git a/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs b/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs index 42e644970c..bd19666238 100644 --- a/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs +++ b/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs @@ -12,6 +12,12 @@ namespace Emby.Server.Implementations.Sorting /// public class AlbumArtistComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.AlbumArtist; + /// /// Compares the specified x. /// @@ -34,11 +40,5 @@ namespace Emby.Server.Implementations.Sorting return audio?.AlbumArtists.FirstOrDefault(); } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.AlbumArtist; } } diff --git a/Emby.Server.Implementations/Sorting/AlbumComparer.cs b/Emby.Server.Implementations/Sorting/AlbumComparer.cs index 1db3f5e9ca..fe7dc84cbf 100644 --- a/Emby.Server.Implementations/Sorting/AlbumComparer.cs +++ b/Emby.Server.Implementations/Sorting/AlbumComparer.cs @@ -11,6 +11,12 @@ namespace Emby.Server.Implementations.Sorting /// public class AlbumComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.Album; + /// /// Compares the specified x. /// @@ -33,11 +39,5 @@ namespace Emby.Server.Implementations.Sorting return audio == null ? string.Empty : audio.Album; } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.Album; } } diff --git a/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs b/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs index d20dedc2d4..ba1835e4f2 100644 --- a/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs +++ b/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs @@ -9,6 +9,12 @@ namespace Emby.Server.Implementations.Sorting /// public class CriticRatingComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.CriticRating; + /// /// Compares the specified x. /// @@ -24,11 +30,5 @@ namespace Emby.Server.Implementations.Sorting { return x?.CriticRating ?? 0; } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.CriticRating; } } diff --git a/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs b/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs index d3f10f78cb..8b460166ca 100644 --- a/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs +++ b/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs @@ -10,6 +10,12 @@ namespace Emby.Server.Implementations.Sorting /// public class DateCreatedComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.DateCreated; + /// /// Compares the specified x. /// @@ -30,11 +36,5 @@ namespace Emby.Server.Implementations.Sorting return DateTime.Compare(x.DateCreated, y.DateCreated); } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.DateCreated; } } diff --git a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs index 08a44319f2..ec818253be 100644 --- a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs @@ -32,6 +32,12 @@ namespace Emby.Server.Implementations.Sorting /// The user data repository. public IUserDataManager UserDataRepository { get; set; } + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.DatePlayed; + /// /// Compares the specified x. /// @@ -59,11 +65,5 @@ namespace Emby.Server.Implementations.Sorting return DateTime.MinValue; } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.DatePlayed; } } diff --git a/Emby.Server.Implementations/Sorting/NameComparer.cs b/Emby.Server.Implementations/Sorting/NameComparer.cs index 4de81a69e3..8f87717f49 100644 --- a/Emby.Server.Implementations/Sorting/NameComparer.cs +++ b/Emby.Server.Implementations/Sorting/NameComparer.cs @@ -10,6 +10,12 @@ namespace Emby.Server.Implementations.Sorting /// public class NameComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.Name; + /// /// Compares the specified x. /// @@ -30,11 +36,5 @@ namespace Emby.Server.Implementations.Sorting return string.Compare(x.Name, y.Name, StringComparison.CurrentCultureIgnoreCase); } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.Name; } } diff --git a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs index 04e4865cbf..45c9044c52 100644 --- a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs +++ b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs @@ -19,6 +19,24 @@ namespace Emby.Server.Implementations.Sorting /// The user. public User User { get; set; } + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.PlayCount; + + /// + /// Gets or sets the user data repository. + /// + /// The user data repository. + public IUserDataManager UserDataRepository { get; set; } + + /// + /// Gets or sets the user manager. + /// + /// The user manager. + public IUserManager UserManager { get; set; } + /// /// Compares the specified x. /// @@ -41,23 +59,5 @@ namespace Emby.Server.Implementations.Sorting return userdata == null ? 0 : userdata.PlayCount; } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.PlayCount; - - /// - /// Gets or sets the user data repository. - /// - /// The user data repository. - public IUserDataManager UserDataRepository { get; set; } - - /// - /// Gets or sets the user manager. - /// - /// The user manager. - public IUserManager UserManager { get; set; } } } diff --git a/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs b/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs index c98f97bf1e..b217556ef3 100644 --- a/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs +++ b/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs @@ -10,6 +10,12 @@ namespace Emby.Server.Implementations.Sorting /// public class PremiereDateComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.PremiereDate; + /// /// Compares the specified x. /// @@ -52,11 +58,5 @@ namespace Emby.Server.Implementations.Sorting return DateTime.MinValue; } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.PremiereDate; } } diff --git a/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs b/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs index df9f9957d6..d2022df7a6 100644 --- a/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs +++ b/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs @@ -9,6 +9,12 @@ namespace Emby.Server.Implementations.Sorting /// public class ProductionYearComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.ProductionYear; + /// /// Compares the specified x. /// @@ -44,11 +50,5 @@ namespace Emby.Server.Implementations.Sorting return 0; } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.ProductionYear; } } diff --git a/Emby.Server.Implementations/Sorting/RandomComparer.cs b/Emby.Server.Implementations/Sorting/RandomComparer.cs index af3bc27508..bf0168222d 100644 --- a/Emby.Server.Implementations/Sorting/RandomComparer.cs +++ b/Emby.Server.Implementations/Sorting/RandomComparer.cs @@ -10,6 +10,12 @@ namespace Emby.Server.Implementations.Sorting /// public class RandomComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.Random; + /// /// Compares the specified x. /// @@ -20,11 +26,5 @@ namespace Emby.Server.Implementations.Sorting { return Guid.NewGuid().CompareTo(Guid.NewGuid()); } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.Random; } } diff --git a/Emby.Server.Implementations/Sorting/RuntimeComparer.cs b/Emby.Server.Implementations/Sorting/RuntimeComparer.cs index 1293153031..e32e5552e4 100644 --- a/Emby.Server.Implementations/Sorting/RuntimeComparer.cs +++ b/Emby.Server.Implementations/Sorting/RuntimeComparer.cs @@ -12,6 +12,12 @@ namespace Emby.Server.Implementations.Sorting /// public class RuntimeComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.Runtime; + /// /// Compares the specified x. /// @@ -32,11 +38,5 @@ namespace Emby.Server.Implementations.Sorting return (x.RunTimeTicks ?? 0).CompareTo(y.RunTimeTicks ?? 0); } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.Runtime; } } diff --git a/Emby.Server.Implementations/Sorting/SortNameComparer.cs b/Emby.Server.Implementations/Sorting/SortNameComparer.cs index 8d30716d39..fb97a0349d 100644 --- a/Emby.Server.Implementations/Sorting/SortNameComparer.cs +++ b/Emby.Server.Implementations/Sorting/SortNameComparer.cs @@ -12,6 +12,12 @@ namespace Emby.Server.Implementations.Sorting /// public class SortNameComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.SortName; + /// /// Compares the specified x. /// @@ -32,11 +38,5 @@ namespace Emby.Server.Implementations.Sorting return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase); } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.SortName; } } diff --git a/Emby.Server.Implementations/Sorting/StudioComparer.cs b/Emby.Server.Implementations/Sorting/StudioComparer.cs index 6826aee3b1..4d89cfa8b2 100644 --- a/Emby.Server.Implementations/Sorting/StudioComparer.cs +++ b/Emby.Server.Implementations/Sorting/StudioComparer.cs @@ -13,6 +13,12 @@ namespace Emby.Server.Implementations.Sorting { public class StudioComparer : IBaseItemComparer { + /// + /// Gets the name. + /// + /// The name. + public string Name => ItemSortBy.Studio; + /// /// Compares the specified x. /// @@ -33,11 +39,5 @@ namespace Emby.Server.Implementations.Sorting return AlphanumericComparator.CompareValues(x.Studios.FirstOrDefault(), y.Studios.FirstOrDefault()); } - - /// - /// Gets the name. - /// - /// The name. - public string Name => ItemSortBy.Studio; } } -- cgit v1.2.3 From c09ef74b516c04b820bf7cdd1060ab7ceb102c13 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 13:31:31 -0400 Subject: Fix warnings in IO --- Emby.Server.Implementations/IO/LibraryMonitor.cs | 36 ++++++++++++---------- .../IO/ManagedFileSystem.cs | 18 +++++------ 2 files changed, 29 insertions(+), 25 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index aa80bccd72..e9d069cd33 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -41,6 +41,25 @@ namespace Emby.Server.Implementations.IO private bool _disposed = false; + /// + /// Initializes a new instance of the class. + /// + /// The logger. + /// The library manager. + /// The configuration manager. + /// The filesystem. + public LibraryMonitor( + ILogger logger, + ILibraryManager libraryManager, + IServerConfigurationManager configurationManager, + IFileSystem fileSystem) + { + _libraryManager = libraryManager; + _logger = logger; + _configurationManager = configurationManager; + _fileSystem = fileSystem; + } + /// /// Add the path to our temporary ignore list. Use when writing to a path within our listening scope. /// @@ -95,21 +114,6 @@ namespace Emby.Server.Implementations.IO } } - /// - /// Initializes a new instance of the class. - /// - public LibraryMonitor( - ILogger logger, - ILibraryManager libraryManager, - IServerConfigurationManager configurationManager, - IFileSystem fileSystem) - { - _libraryManager = libraryManager; - _logger = logger; - _configurationManager = configurationManager; - _fileSystem = fileSystem; - } - private bool IsLibraryMonitorEnabled(BaseItem item) { if (item is BasePluginFolder) @@ -199,7 +203,7 @@ namespace Emby.Server.Implementations.IO /// The LST. /// The path. /// true if [contains parent folder] [the specified LST]; otherwise, false. - /// path + /// is null. private static bool ContainsParentFolder(IEnumerable lst, string path) { if (string.IsNullOrEmpty(path)) diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 77da46cd6d..eeee288425 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.IO /// public class ManagedFileSystem : IFileSystem { - protected ILogger Logger; + private readonly ILogger _logger; private readonly List _shortcutHandlers = new List(); private readonly string _tempPath; @@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.IO ILogger logger, IApplicationPaths applicationPaths) { - Logger = logger; + _logger = logger; _tempPath = applicationPaths.TempDirectory; } @@ -41,7 +41,7 @@ namespace Emby.Server.Implementations.IO /// /// The filename. /// true if the specified filename is shortcut; otherwise, false. - /// filename + /// is null. public virtual bool IsShortcut(string filename) { if (string.IsNullOrEmpty(filename)) @@ -58,7 +58,7 @@ namespace Emby.Server.Implementations.IO /// /// The filename. /// System.String. - /// filename + /// is null. public virtual string? ResolveShortcut(string filename) { if (string.IsNullOrEmpty(filename)) @@ -233,9 +233,9 @@ namespace Emby.Server.Implementations.IO result.IsDirectory = info is DirectoryInfo || (info.Attributes & FileAttributes.Directory) == FileAttributes.Directory; // if (!result.IsDirectory) - //{ + // { // result.IsHidden = (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden; - //} + // } if (info is FileInfo fileInfo) { @@ -254,7 +254,7 @@ namespace Emby.Server.Implementations.IO catch (FileNotFoundException ex) { // Dangling symlinks cannot be detected before opening the file unfortunately... - Logger.LogError(ex, "Reading the file size of the symlink at {Path} failed. Marking the file as not existing.", fileInfo.FullName); + _logger.LogError(ex, "Reading the file size of the symlink at {Path} failed. Marking the file as not existing.", fileInfo.FullName); result.Exists = false; } } @@ -343,7 +343,7 @@ namespace Emby.Server.Implementations.IO } catch (Exception ex) { - Logger.LogError(ex, "Error determining CreationTimeUtc for {FullName}", info.FullName); + _logger.LogError(ex, "Error determining CreationTimeUtc for {FullName}", info.FullName); return DateTime.MinValue; } } @@ -382,7 +382,7 @@ namespace Emby.Server.Implementations.IO } catch (Exception ex) { - Logger.LogError(ex, "Error determining LastAccessTimeUtc for {FullName}", info.FullName); + _logger.LogError(ex, "Error determining LastAccessTimeUtc for {FullName}", info.FullName); return DateTime.MinValue; } } -- cgit v1.2.3 From 8c8ca9adedf3e9df3c6fb83ee0967f0af5fc9fc3 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 13:35:06 -0400 Subject: Fix warnings in UdpSocket --- Emby.Server.Implementations/Net/UdpSocket.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs index 9b799e854d..0c451ccb60 100644 --- a/Emby.Server.Implementations/Net/UdpSocket.cs +++ b/Emby.Server.Implementations/Net/UdpSocket.cs @@ -16,11 +16,7 @@ namespace Emby.Server.Implementations.Net public sealed class UdpSocket : ISocket, IDisposable { - private Socket _socket; private readonly int _localPort; - private bool _disposed = false; - - public Socket Socket => _socket; private readonly SocketAsyncEventArgs _receiveSocketAsyncEventArgs = new SocketAsyncEventArgs() { @@ -32,6 +28,8 @@ namespace Emby.Server.Implementations.Net SocketFlags = SocketFlags.None }; + private Socket _socket; + private bool _disposed = false; private TaskCompletionSource _currentReceiveTaskCompletionSource; private TaskCompletionSource _currentSendTaskCompletionSource; @@ -64,6 +62,8 @@ namespace Emby.Server.Implementations.Net InitReceiveSocketAsyncEventArgs(); } + public Socket Socket => _socket; + public IPAddress LocalIPAddress { get; } private void InitReceiveSocketAsyncEventArgs() -- cgit v1.2.3 From 7ae055f740aa72ebe585d3c34a015a4a96e01ea2 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 13:36:56 -0400 Subject: Fix warnings in UdpServer --- Emby.Server.Implementations/Udp/UdpServer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs index 8179e26c5e..bf51c39684 100644 --- a/Emby.Server.Implementations/Udp/UdpServer.cs +++ b/Emby.Server.Implementations/Udp/UdpServer.cs @@ -29,10 +29,10 @@ namespace Emby.Server.Implementations.Udp private readonly IServerApplicationHost _appHost; private readonly IConfiguration _config; - private Socket _udpSocket; - private IPEndPoint _endpoint; private readonly byte[] _receiveBuffer = new byte[8192]; + private Socket _udpSocket; + private IPEndPoint _endpoint; private bool _disposed = false; /// -- cgit v1.2.3 From b17a452d1677f6511fa9c066e16c9c7a00dca518 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 13:41:42 -0400 Subject: Fix warnings in ServerApplicationPaths --- Emby.Server.Implementations/ServerApplicationPaths.cs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs index 6cf9a8f71e..369a2b0d88 100644 --- a/Emby.Server.Implementations/ServerApplicationPaths.cs +++ b/Emby.Server.Implementations/ServerApplicationPaths.cs @@ -12,6 +12,11 @@ namespace Emby.Server.Implementations /// /// Initializes a new instance of the class. /// + /// The path for Jellyfin's data. + /// The path for Jellyfin's logging directory. + /// The path for Jellyfin's configuration directory. + /// The path for Jellyfin's cache directory. + /// The path for Jellyfin's web UI. public ServerApplicationPaths( string programDataPath, string logDirectoryPath, -- cgit v1.2.3 From 7ea4c844c89e0bfa7a21c7a34e51182ec791ee8c Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 13:45:11 -0400 Subject: Fix warnings in InstallationManager --- Emby.Server.Implementations/Updates/InstallationManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 7b0afa4e24..4a022c5dbc 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -10,8 +10,8 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Events; -using MediaBrowser.Common.Configuration; using Jellyfin.Extensions.Json; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; -- cgit v1.2.3 From aa3c33060d775c8d050bd3975cd692c80081ea66 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 13:46:25 -0400 Subject: Fix warnings in Playlists --- .../Playlists/ManualPlaylistsFolder.cs | 58 ---------------------- .../Playlists/PlaylistsFolder.cs | 58 ++++++++++++++++++++++ 2 files changed, 58 insertions(+), 58 deletions(-) delete mode 100644 Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs create mode 100644 Emby.Server.Implementations/Playlists/PlaylistsFolder.cs (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs deleted file mode 100644 index 8b1cee89d1..0000000000 --- a/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs +++ /dev/null @@ -1,58 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; -using System.Linq; -using System.Text.Json.Serialization; -using Jellyfin.Data.Entities; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Playlists; -using MediaBrowser.Model.Querying; - -namespace Emby.Server.Implementations.Playlists -{ - public class PlaylistsFolder : BasePluginFolder - { - public PlaylistsFolder() - { - Name = "Playlists"; - } - - [JsonIgnore] - public override bool IsHidden => true; - - [JsonIgnore] - public override bool SupportsInheritedParentImages => false; - - [JsonIgnore] - public override string CollectionType => MediaBrowser.Model.Entities.CollectionType.Playlists; - - public override bool IsVisible(User user) - { - return base.IsVisible(user) && GetChildren(user, true).Any(); - } - - protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) - { - return base.GetEligibleChildrenForRecursiveChildren(user).OfType(); - } - - protected override QueryResult GetItemsInternal(InternalItemsQuery query) - { - if (query.User == null) - { - query.Recursive = false; - return base.GetItemsInternal(query); - } - - query.Recursive = true; - query.IncludeItemTypes = new[] { "Playlist" }; - query.Parent = null; - return LibraryManager.GetItemsResult(query); - } - - public override string GetClientTypeName() - { - return "ManualPlaylistsFolder"; - } - } -} diff --git a/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs b/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs new file mode 100644 index 0000000000..8b1cee89d1 --- /dev/null +++ b/Emby.Server.Implementations/Playlists/PlaylistsFolder.cs @@ -0,0 +1,58 @@ +#pragma warning disable CS1591 + +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Playlists; +using MediaBrowser.Model.Querying; + +namespace Emby.Server.Implementations.Playlists +{ + public class PlaylistsFolder : BasePluginFolder + { + public PlaylistsFolder() + { + Name = "Playlists"; + } + + [JsonIgnore] + public override bool IsHidden => true; + + [JsonIgnore] + public override bool SupportsInheritedParentImages => false; + + [JsonIgnore] + public override string CollectionType => MediaBrowser.Model.Entities.CollectionType.Playlists; + + public override bool IsVisible(User user) + { + return base.IsVisible(user) && GetChildren(user, true).Any(); + } + + protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) + { + return base.GetEligibleChildrenForRecursiveChildren(user).OfType(); + } + + protected override QueryResult GetItemsInternal(InternalItemsQuery query) + { + if (query.User == null) + { + query.Recursive = false; + return base.GetItemsInternal(query); + } + + query.Recursive = true; + query.IncludeItemTypes = new[] { "Playlist" }; + query.Parent = null; + return LibraryManager.GetItemsResult(query); + } + + public override string GetClientTypeName() + { + return "ManualPlaylistsFolder"; + } + } +} -- cgit v1.2.3 From 876a902356fb5c0e502b440d591287a53e2488fc Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 2 Oct 2021 13:59:58 -0400 Subject: Fix warnings in Library --- Emby.Server.Implementations/Library/LibraryManager.cs | 4 ++-- Emby.Server.Implementations/Library/MediaSourceManager.cs | 2 +- Emby.Server.Implementations/Library/PathExtensions.cs | 2 +- .../Library/Resolvers/Audio/MusicAlbumResolver.cs | 3 +++ .../Library/Resolvers/BaseVideoResolver.cs | 4 ++++ .../Library/Resolvers/Books/BookResolver.cs | 7 +++---- .../Library/Resolvers/Movies/MovieResolver.cs | 4 ++-- .../Library/Resolvers/SpecialFolderResolver.cs | 1 - Emby.Server.Implementations/Library/SearchEngine.cs | 2 +- Emby.Server.Implementations/Library/UserDataManager.cs | 15 +++++++-------- Emby.Server.Implementations/Library/UserViewManager.cs | 3 ++- .../Library/Validators/ArtistsValidator.cs | 11 +++++++---- 12 files changed, 33 insertions(+), 25 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 132486b4a6..1326f60fe5 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -647,7 +647,7 @@ namespace Emby.Server.Implementations.Library /// Determines whether a path should be ignored based on its contents - called after the contents have been read. /// /// The args. - /// true if XXXX, false otherwise + /// true if XXXX, false otherwise. private static bool ShouldResolvePathContents(ItemResolveArgs args) { // Ignore any folders containing a file called .ignore @@ -1266,7 +1266,7 @@ namespace Emby.Server.Implementations.Library /// /// The id. /// BaseItem. - /// id + /// is null. public BaseItem GetItemById(Guid id) { if (id == Guid.Empty) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 16231c73fc..351fced348 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -13,9 +13,9 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Extensions.Json; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using Jellyfin.Extensions.Json; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; diff --git a/Emby.Server.Implementations/Library/PathExtensions.cs b/Emby.Server.Implementations/Library/PathExtensions.cs index 86b8039fab..d5b855cdf2 100644 --- a/Emby.Server.Implementations/Library/PathExtensions.cs +++ b/Emby.Server.Implementations/Library/PathExtensions.cs @@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.Library /// The original path. /// The original sub path. /// The new sub path. - /// The result of the sub path replacement + /// The result of the sub path replacement. /// The path after replacing the sub path. /// , or is empty. public static bool TryReplaceSubPath( diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 8e1eccb10a..60720dd2f7 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -82,6 +82,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio /// /// Determine if the supplied file data points to a music album. /// + /// The path to check. + /// The directory service. + /// true if the provided path points to a music album, false otherwise. public bool IsMusicAlbum(string path, IDirectoryService directoryService) { return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService, _logger, _fileSystem, _libraryManager); diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs index b102b86cfb..9ff99fa431 100644 --- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs @@ -275,6 +275,10 @@ namespace Emby.Server.Implementations.Library.Resolvers /// /// Determines whether [is DVD directory] [the specified directory name]. /// + /// The full path of the directory. + /// The name of the directory. + /// The directory service. + /// true if the provided directory is a DVD directory, false otherwise. protected bool IsDvdDirectory(string fullPath, string directoryName, IDirectoryService directoryService) { if (!string.Equals(directoryName, "video_ts", StringComparison.OrdinalIgnoreCase)) diff --git a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs index 68076730b3..e685c87f1a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs @@ -49,13 +49,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books { var bookFiles = args.FileSystemChildren.Where(f => { - var fileExtension = Path.GetExtension(f.FullName) ?? - string.Empty; + var fileExtension = Path.GetExtension(f.FullName) + ?? string.Empty; return _validExtensions.Contains( fileExtension, - StringComparer - .OrdinalIgnoreCase); + StringComparer.OrdinalIgnoreCase); }).ToList(); // Don't return a Book if there is more (or less) than one document in the directory diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 8b55a77449..f3b6ef0a28 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -24,6 +24,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies /// public class MovieResolver : BaseVideoResolver -- cgit v1.2.3 From fc96305e780904dd49e315a5a8b17784ee9b3492 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Oct 2021 12:01:09 +0000 Subject: Bump DotNet.Glob from 3.1.2 to 3.1.3 Bumps [DotNet.Glob](https://github.com/dazinator/DotNet.Glob) from 3.1.2 to 3.1.3. - [Release notes](https://github.com/dazinator/DotNet.Glob/releases) - [Changelog](https://github.com/dazinator/DotNet.Glob/blob/develop/ReleaseNotes.md) - [Commits](https://github.com/dazinator/DotNet.Glob/compare/3.1.2...3.1.3) --- updated-dependencies: - dependency-name: DotNet.Glob dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 0e1386ef55..062ad4885e 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -34,7 +34,7 @@ - + -- cgit v1.2.3 From 017380f1ddccb46ce270f1d0df8e07d639ba3704 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Mon, 4 Oct 2021 07:43:40 -0600 Subject: Reference dotnet6-rc1 packages --- Emby.Dlna/Emby.Dlna.csproj | 2 +- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 10 +++++----- Jellyfin.Api/Jellyfin.Api.csproj | 4 ++-- Jellyfin.Data/Jellyfin.Data.csproj | 2 +- .../Jellyfin.Server.Implementations.csproj | 8 ++++---- .../Security/AuthorizationContext.cs | 2 +- Jellyfin.Server.Implementations/Users/UserManager.cs | 5 +++++ Jellyfin.Server/Jellyfin.Server.csproj | 8 ++++---- MediaBrowser.Common/MediaBrowser.Common.csproj | 4 ++-- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 6 +++--- MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj | 4 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 4 ++-- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 6 +++--- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 4 ++-- .../Jellyfin.Server.Integration.Tests.csproj | 6 +++--- tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj | 6 +++--- 16 files changed, 43 insertions(+), 38 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index 1d4e3b047d..5348aed637 100644 --- a/Emby.Dlna/Emby.Dlna.csproj +++ b/Emby.Dlna/Emby.Dlna.csproj @@ -73,7 +73,7 @@ - + diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 428cad0715..fb19726104 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -25,11 +25,11 @@ - - - - - + + + + + diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 1c451ef6c1..f46c0cbd11 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 19aef704c0..f1bfaa63e0 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -35,7 +35,7 @@ - + diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index 337f5cb82a..d9e6d794b3 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -19,13 +19,13 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs b/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs index ba2cfc724e..3ab043c648 100644 --- a/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs +++ b/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs @@ -2,12 +2,12 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Threading.Tasks; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; using Microsoft.Net.Http.Headers; namespace Jellyfin.Server.Implementations.Security diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 02377bfd72..704a6a84ef 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -701,6 +701,11 @@ namespace Jellyfin.Server.Implementations.Users /// public async Task ClearProfileImageAsync(User user) { + if (user.ProfileImage == null) + { + return; + } + await using var dbContext = _dbProvider.CreateContext(); dbContext.Remove(user.ProfileImage); await dbContext.SaveChangesAsync().ConfigureAwait(false); diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 074d43fba8..6603105fa3 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -31,10 +31,10 @@ - - - - + + + + diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 6358c00001..c87d58a147 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 47cec7d77f..997772c04c 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -15,10 +15,10 @@ - - + + - + diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 30cfb904e1..22bba23663 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -24,8 +24,8 @@ - - + + diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index b0a12a9c90..0ac58e3551 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -35,9 +35,9 @@ - + - + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 29d6b01f23..71a3554fd6 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -16,9 +16,9 @@ - - - + + + diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index b52ea078af..8b581857fe 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -15,8 +15,8 @@ - - + + diff --git a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj index 7939c7118e..38687ae61a 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj +++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj @@ -9,14 +9,14 @@ - - + + - + diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index b30e690a5e..db24df240c 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -10,13 +10,13 @@ - - + + - + -- cgit v1.2.3 From d245e45254057c62d058cfad3e56484a77093718 Mon Sep 17 00:00:00 2001 From: joanMelchor Date: Sun, 3 Oct 2021 17:12:37 +0000 Subject: Translated using Weblate (Catalan) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/ --- Emby.Server.Implementations/Localization/Core/ca.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/ca.json b/Emby.Server.Implementations/Localization/Core/ca.json index 7715daa7ce..db3c13d800 100644 --- a/Emby.Server.Implementations/Localization/Core/ca.json +++ b/Emby.Server.Implementations/Localization/Core/ca.json @@ -15,7 +15,7 @@ "Favorites": "Preferits", "Folders": "Carpetes", "Genres": "Gèneres", - "HeaderAlbumArtists": "Artistes del Àlbum", + "HeaderAlbumArtists": "Àlbum de l'artista", "HeaderContinueWatching": "Continua Veient", "HeaderFavoriteAlbums": "Àlbums Preferits", "HeaderFavoriteArtists": "Artistes Predilectes", -- cgit v1.2.3 From e0db541381a669ff5ba618e618e162ba0d0ef1c9 Mon Sep 17 00:00:00 2001 From: Patrick Barron <18354464+barronpm@users.noreply.github.com> Date: Tue, 5 Oct 2021 22:07:16 -0400 Subject: Update indentation --- Emby.Server.Implementations/Library/UserViewManager.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index b4ac49a38b..eda494815d 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -341,14 +341,15 @@ namespace Emby.Server.Implementations.Library mediaTypes = mediaTypes.Distinct().ToList(); } - var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0 ? new[] - { - nameof(Person), - nameof(Studio), - nameof(Year), - nameof(MusicGenre), - nameof(Genre) - } + var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0 + ? new[] + { + nameof(Person), + nameof(Studio), + nameof(Year), + nameof(MusicGenre), + nameof(Genre) + } : Array.Empty(); var query = new InternalItemsQuery(user) -- cgit v1.2.3 From 03f933aaa07113b0ae6971921249691c8455d5ba Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 6 Oct 2021 11:30:45 +0200 Subject: Fix the last few warnings Enables TreatWarningsAsErrors for all projects --- Emby.Server.Implementations/ApplicationHost.cs | 38 +++----- .../Data/BaseSqliteRepository.cs | 2 +- .../Emby.Server.Implementations.csproj | 5 -- .../Images/BaseDynamicImageProvider.cs | 4 +- .../Images/BaseFolderImageProvider.cs | 67 ++++++++++++++ .../Images/FolderImageProvider.cs | 69 -------------- .../Images/GenreImageProvider.cs | 41 --------- .../Images/MusicAlbumImageProvider.cs | 19 ++++ .../Images/MusicGenreImageProvider.cs | 59 ++++++++++++ .../Images/PhotoAlbumImageProvider.cs | 19 ++++ .../Library/Resolvers/FolderResolver.cs | 22 +---- .../Library/Resolvers/GenericFolderResolver.cs | 27 ++++++ .../Library/Resolvers/Movies/BoxSetResolver.cs | 2 +- .../Library/Resolvers/PhotoAlbumResolver.cs | 2 +- .../Library/Resolvers/PlaylistResolver.cs | 2 +- .../Library/Resolvers/SpecialFolderResolver.cs | 2 +- .../Library/Resolvers/TV/SeasonResolver.cs | 2 +- .../Library/Resolvers/TV/SeriesResolver.cs | 2 +- .../Listings/SchedulesDirectDtos/ImageDataDto.cs | 2 +- .../Listings/SchedulesDirectDtos/StationDto.cs | 100 ++++++++++----------- .../HdHomerun/HdHomerunChannelCommands.cs | 35 ++++++++ .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 10 +-- .../TunerHosts/HdHomerun/HdHomerunManager.cs | 66 -------------- .../HdHomerun/IHdHomerunChannelCommands.cs | 11 +++ .../HdHomerun/LegacyHdHomerunChannelCommands.cs | 38 ++++++++ .../MediaBrowser.Controller.csproj | 5 -- MediaBrowser.Model/MediaBrowser.Model.csproj | 5 -- 27 files changed, 353 insertions(+), 303 deletions(-) create mode 100644 Emby.Server.Implementations/Images/BaseFolderImageProvider.cs create mode 100644 Emby.Server.Implementations/Images/MusicAlbumImageProvider.cs create mode 100644 Emby.Server.Implementations/Images/MusicGenreImageProvider.cs create mode 100644 Emby.Server.Implementations/Images/PhotoAlbumImageProvider.cs create mode 100644 Emby.Server.Implementations/Library/Resolvers/GenericFolderResolver.cs create mode 100644 Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunChannelCommands.cs create mode 100644 Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/IHdHomerunChannelCommands.cs create mode 100644 Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/LegacyHdHomerunChannelCommands.cs (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 3a504d2f43..1f11bdad74 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -306,7 +306,7 @@ namespace Emby.Server.Implementations /// public string Name => ApplicationProductName; - private CertificateInfo CertificateInfo { get; set; } + private string CertificatePath { get; set; } public X509Certificate2 Certificate { get; private set; } @@ -548,12 +548,8 @@ namespace Emby.Server.Implementations HttpsPort = NetworkConfiguration.DefaultHttpsPort; } - CertificateInfo = new CertificateInfo - { - Path = networkConfiguration.CertificatePath, - Password = networkConfiguration.CertificatePassword - }; - Certificate = GetCertificate(CertificateInfo); + CertificatePath = networkConfiguration.CertificatePath; + Certificate = GetCertificate(CertificatePath, networkConfiguration.CertificatePassword); RegisterServices(); @@ -729,30 +725,27 @@ namespace Emby.Server.Implementations logger.LogInformation("Application directory: {ApplicationPath}", appPaths.ProgramSystemPath); } - private X509Certificate2 GetCertificate(CertificateInfo info) + private X509Certificate2 GetCertificate(string path, string password) { - var certificateLocation = info?.Path; - - if (string.IsNullOrWhiteSpace(certificateLocation)) + if (string.IsNullOrWhiteSpace(path)) { return null; } try { - if (!File.Exists(certificateLocation)) + if (!File.Exists(path)) { return null; } // Don't use an empty string password - var password = string.IsNullOrWhiteSpace(info.Password) ? null : info.Password; + password = string.IsNullOrWhiteSpace(password) ? null : password; - var localCert = new X509Certificate2(certificateLocation, password, X509KeyStorageFlags.UserKeySet); - // localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA; + var localCert = new X509Certificate2(path, password, X509KeyStorageFlags.UserKeySet); if (!localCert.HasPrivateKey) { - Logger.LogError("No private key included in SSL cert {CertificateLocation}.", certificateLocation); + Logger.LogError("No private key included in SSL cert {CertificateLocation}.", path); return null; } @@ -760,7 +753,7 @@ namespace Emby.Server.Implementations } catch (Exception ex) { - Logger.LogError(ex, "Error loading cert from {CertificateLocation}", certificateLocation); + Logger.LogError(ex, "Error loading cert from {CertificateLocation}", path); return null; } } @@ -882,7 +875,7 @@ namespace Emby.Server.Implementations "http://" + i + ":" + HttpPort + "/" }; - if (CertificateInfo != null) + if (Certificate != null) { prefixes.Add("https://" + i + ":" + HttpsPort + "/"); } @@ -946,7 +939,7 @@ namespace Emby.Server.Implementations var newPath = networkConfig.CertificatePath; if (!string.IsNullOrWhiteSpace(newPath) - && !string.Equals(CertificateInfo?.Path, newPath, StringComparison.Ordinal)) + && !string.Equals(CertificatePath, newPath, StringComparison.Ordinal)) { if (File.Exists(newPath)) { @@ -1293,11 +1286,4 @@ namespace Emby.Server.Implementations _disposed = true; } } - - internal class CertificateInfo - { - public string Path { get; set; } - - public string Password { get; set; } - } } diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 4f6c811028..73c31f49d1 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -98,7 +98,7 @@ namespace Emby.Server.Implementations.Data /// The write connection. protected SQLiteDatabaseConnection WriteConnection { get; set; } - protected ManagedConnection GetConnection(bool _ = false) + protected ManagedConnection GetConnection(bool readOnly = false) { WriteLock.Wait(); if (WriteConnection != null) diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 428cad0715..82e4c3d697 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -47,11 +47,6 @@ true AD0001 - false - - - - true diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 4a026fd218..7589869457 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -65,13 +65,13 @@ namespace Emby.Server.Implementations.Images if (SupportedImages.Contains(ImageType.Primary)) { var primaryResult = await FetchAsync(item, ImageType.Primary, options, cancellationToken).ConfigureAwait(false); - updateType = updateType | primaryResult; + updateType |= primaryResult; } if (SupportedImages.Contains(ImageType.Thumb)) { var thumbResult = await FetchAsync(item, ImageType.Thumb, options, cancellationToken).ConfigureAwait(false); - updateType = updateType | thumbResult; + updateType |= thumbResult; } return updateType; diff --git a/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs b/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs new file mode 100644 index 0000000000..1c69056d20 --- /dev/null +++ b/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs @@ -0,0 +1,67 @@ +#nullable disable + +#pragma warning disable CS1591 + +using System.Collections.Generic; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Querying; + +namespace Emby.Server.Implementations.Images +{ + public abstract class BaseFolderImageProvider : BaseDynamicImageProvider + where T : Folder, new() + { + private readonly ILibraryManager _libraryManager; + + public BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) + : base(fileSystem, providerManager, applicationPaths, imageProcessor) + { + _libraryManager = libraryManager; + } + + protected override IReadOnlyList GetItemsWithImages(BaseItem item) + { + return _libraryManager.GetItemList(new InternalItemsQuery + { + Parent = item, + DtoOptions = new DtoOptions(true), + ImageTypes = new ImageType[] { ImageType.Primary }, + OrderBy = new (string, SortOrder)[] + { + (ItemSortBy.IsFolder, SortOrder.Ascending), + (ItemSortBy.SortName, SortOrder.Ascending) + }, + Limit = 1 + }); + } + + protected override string CreateImage(BaseItem item, IReadOnlyCollection itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) + { + return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary); + } + + protected override bool Supports(BaseItem item) + { + return item is T; + } + + protected override bool HasChangedByDate(BaseItem item, ItemImageInfo image) + { + if (item is MusicAlbum) + { + return false; + } + + return base.HasChangedByDate(item, image); + } + } +} diff --git a/Emby.Server.Implementations/Images/FolderImageProvider.cs b/Emby.Server.Implementations/Images/FolderImageProvider.cs index 859017f869..4376bd356c 100644 --- a/Emby.Server.Implementations/Images/FolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/FolderImageProvider.cs @@ -2,69 +2,16 @@ #pragma warning disable CS1591 -using System.Collections.Generic; -using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; -using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Images { - public abstract class BaseFolderImageProvider : BaseDynamicImageProvider - where T : Folder, new() - { - protected ILibraryManager _libraryManager; - - public BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) - : base(fileSystem, providerManager, applicationPaths, imageProcessor) - { - _libraryManager = libraryManager; - } - - protected override IReadOnlyList GetItemsWithImages(BaseItem item) - { - return _libraryManager.GetItemList(new InternalItemsQuery - { - Parent = item, - DtoOptions = new DtoOptions(true), - ImageTypes = new ImageType[] { ImageType.Primary }, - OrderBy = new System.ValueTuple[] - { - new System.ValueTuple(ItemSortBy.IsFolder, SortOrder.Ascending), - new System.ValueTuple(ItemSortBy.SortName, SortOrder.Ascending) - }, - Limit = 1 - }); - } - - protected override string CreateImage(BaseItem item, IReadOnlyCollection itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) - { - return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary); - } - - protected override bool Supports(BaseItem item) - { - return item is T; - } - - protected override bool HasChangedByDate(BaseItem item, ItemImageInfo image) - { - if (item is MusicAlbum) - { - return false; - } - - return base.HasChangedByDate(item, image); - } - } - public class FolderImageProvider : BaseFolderImageProvider { public FolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) @@ -87,20 +34,4 @@ namespace Emby.Server.Implementations.Images return true; } } - - public class MusicAlbumImageProvider : BaseFolderImageProvider - { - public MusicAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) - : base(fileSystem, providerManager, applicationPaths, imageProcessor, libraryManager) - { - } - } - - public class PhotoAlbumImageProvider : BaseFolderImageProvider - { - public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) - : base(fileSystem, providerManager, applicationPaths, imageProcessor, libraryManager) - { - } - } } diff --git a/Emby.Server.Implementations/Images/GenreImageProvider.cs b/Emby.Server.Implementations/Images/GenreImageProvider.cs index 6da431c68e..1f5090f7f5 100644 --- a/Emby.Server.Implementations/Images/GenreImageProvider.cs +++ b/Emby.Server.Implementations/Images/GenreImageProvider.cs @@ -8,7 +8,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; @@ -19,46 +18,6 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Images { - /// - /// Class MusicGenreImageProvider. - /// - public class MusicGenreImageProvider : BaseDynamicImageProvider - { - /// - /// The library manager. - /// - private readonly ILibraryManager _libraryManager; - - public MusicGenreImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) : base(fileSystem, providerManager, applicationPaths, imageProcessor) - { - _libraryManager = libraryManager; - } - - /// - /// Get children objects used to create an music genre image. - /// - /// The music genre used to create the image. - /// Any relevant children objects. - protected override IReadOnlyList GetItemsWithImages(BaseItem item) - { - return _libraryManager.GetItemList(new InternalItemsQuery - { - Genres = new[] { item.Name }, - IncludeItemTypes = new[] - { - nameof(MusicAlbum), - nameof(MusicVideo), - nameof(Audio) - }, - OrderBy = new[] { (ItemSortBy.Random, SortOrder.Ascending) }, - Limit = 4, - Recursive = true, - ImageTypes = new[] { ImageType.Primary }, - DtoOptions = new DtoOptions(false) - }); - } - } - /// /// Class GenreImageProvider. /// diff --git a/Emby.Server.Implementations/Images/MusicAlbumImageProvider.cs b/Emby.Server.Implementations/Images/MusicAlbumImageProvider.cs new file mode 100644 index 0000000000..ce83673638 --- /dev/null +++ b/Emby.Server.Implementations/Images/MusicAlbumImageProvider.cs @@ -0,0 +1,19 @@ +#pragma warning disable CS1591 + +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.IO; + +namespace Emby.Server.Implementations.Images +{ + public class MusicAlbumImageProvider : BaseFolderImageProvider + { + public MusicAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) + : base(fileSystem, providerManager, applicationPaths, imageProcessor, libraryManager) + { + } + } +} diff --git a/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs b/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs new file mode 100644 index 0000000000..baf1c90517 --- /dev/null +++ b/Emby.Server.Implementations/Images/MusicGenreImageProvider.cs @@ -0,0 +1,59 @@ +#nullable disable + +#pragma warning disable CS1591 + +using System.Collections.Generic; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Querying; + +namespace Emby.Server.Implementations.Images +{ + /// + /// Class MusicGenreImageProvider. + /// + public class MusicGenreImageProvider : BaseDynamicImageProvider + { + /// + /// The library manager. + /// + private readonly ILibraryManager _libraryManager; + + public MusicGenreImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) : base(fileSystem, providerManager, applicationPaths, imageProcessor) + { + _libraryManager = libraryManager; + } + + /// + /// Get children objects used to create an music genre image. + /// + /// The music genre used to create the image. + /// Any relevant children objects. + protected override IReadOnlyList GetItemsWithImages(BaseItem item) + { + return _libraryManager.GetItemList(new InternalItemsQuery + { + Genres = new[] { item.Name }, + IncludeItemTypes = new[] + { + nameof(MusicAlbum), + nameof(MusicVideo), + nameof(Audio) + }, + OrderBy = new[] { (ItemSortBy.Random, SortOrder.Ascending) }, + Limit = 4, + Recursive = true, + ImageTypes = new[] { ImageType.Primary }, + DtoOptions = new DtoOptions(false) + }); + } + } +} diff --git a/Emby.Server.Implementations/Images/PhotoAlbumImageProvider.cs b/Emby.Server.Implementations/Images/PhotoAlbumImageProvider.cs new file mode 100644 index 0000000000..1ddb4c7579 --- /dev/null +++ b/Emby.Server.Implementations/Images/PhotoAlbumImageProvider.cs @@ -0,0 +1,19 @@ +#pragma warning disable CS1591 + +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.IO; + +namespace Emby.Server.Implementations.Images +{ + public class PhotoAlbumImageProvider : BaseFolderImageProvider + { + public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager) + : base(fileSystem, providerManager, applicationPaths, imageProcessor, libraryManager) + { + } + } +} diff --git a/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs index 7aaee017dd..db7703cd60 100644 --- a/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs @@ -9,7 +9,7 @@ namespace Emby.Server.Implementations.Library.Resolvers /// /// Class FolderResolver. /// - public class FolderResolver : FolderResolver + public class FolderResolver : GenericFolderResolver { /// /// Gets the priority. @@ -32,24 +32,4 @@ namespace Emby.Server.Implementations.Library.Resolvers return null; } } - - /// - /// Class FolderResolver. - /// - /// The type of the T item type. - public abstract class FolderResolver : ItemResolver - where TItemType : Folder, new() - { - /// - /// Sets the initial item values. - /// - /// The item. - /// The args. - protected override void SetInitialItemValues(TItemType item, ItemResolveArgs args) - { - base.SetInitialItemValues(item, args); - - item.IsRoot = args.Parent == null; - } - } } diff --git a/Emby.Server.Implementations/Library/Resolvers/GenericFolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/GenericFolderResolver.cs new file mode 100644 index 0000000000..f109a5e9a2 --- /dev/null +++ b/Emby.Server.Implementations/Library/Resolvers/GenericFolderResolver.cs @@ -0,0 +1,27 @@ +#nullable disable + +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; + +namespace Emby.Server.Implementations.Library.Resolvers +{ + /// + /// Class FolderResolver. + /// + /// The type of the T item type. + public abstract class GenericFolderResolver : ItemResolver + where TItemType : Folder, new() + { + /// + /// Sets the initial item values. + /// + /// The item. + /// The args. + protected override void SetInitialItemValues(TItemType item, ItemResolveArgs args) + { + base.SetInitialItemValues(item, args); + + item.IsRoot = args.Parent == null; + } + } +} diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs index 69d71d0d9a..e7abe1e6da 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies /// /// Class BoxSetResolver. /// - public class BoxSetResolver : FolderResolver + public class BoxSetResolver : GenericFolderResolver { /// /// Resolves the specified args. diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs index 534bc80ddc..1c560e8a6e 100644 --- a/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Library.Resolvers /// /// Class PhotoAlbumResolver. /// - public class PhotoAlbumResolver : FolderResolver + public class PhotoAlbumResolver : GenericFolderResolver { private readonly IImageProcessor _imageProcessor; private readonly ILibraryManager _libraryManager; diff --git a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs index 2c4ead7198..8ce59717d0 100644 --- a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs @@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Resolvers /// /// for library items. /// - public class PlaylistResolver : FolderResolver + public class PlaylistResolver : GenericFolderResolver { private string[] _musicPlaylistCollectionTypes = { diff --git a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs index a42ac41446..6bb9996415 100644 --- a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs @@ -13,7 +13,7 @@ using MediaBrowser.Model.IO; namespace Emby.Server.Implementations.Library.Resolvers { - public class SpecialFolderResolver : FolderResolver + public class SpecialFolderResolver : GenericFolderResolver { private readonly IFileSystem _fileSystem; private readonly IServerApplicationPaths _appPaths; diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs index 7d707df182..063f67543f 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV /// /// Class SeasonResolver. /// - public class SeasonResolver : FolderResolver + public class SeasonResolver : GenericFolderResolver { private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localization; diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index 4d8a6494c7..b7fbe01c5a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -18,7 +18,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV /// /// Class SeriesResolver. /// - public class SeriesResolver : FolderResolver + public class SeriesResolver : GenericFolderResolver { private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs index 912e680dd7..4e9efc60f4 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs @@ -37,7 +37,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the aspect. /// [JsonPropertyName("aspect")] - public string aspect { get; set; } + public string Aspect { get; set; } /// /// Gets or sets the category. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs index 12f3576c65..c37f19678f 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs @@ -6,62 +6,62 @@ using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos { /// - /// Station dto. - /// - public class StationDto - { - /// - /// Gets or sets the station id. - /// - [JsonPropertyName("stationID")] - public string StationId { get; set; } + /// Station dto. + /// + public class StationDto + { + /// + /// Gets or sets the station id. + /// + [JsonPropertyName("stationID")] + public string StationId { get; set; } - /// - /// Gets or sets the name. - /// - [JsonPropertyName("name")] - public string Name { get; set; } + /// + /// Gets or sets the name. + /// + [JsonPropertyName("name")] + public string Name { get; set; } - /// - /// Gets or sets the callsign. - /// - [JsonPropertyName("callsign")] - public string Callsign { get; set; } + /// + /// Gets or sets the callsign. + /// + [JsonPropertyName("callsign")] + public string Callsign { get; set; } - /// - /// Gets or sets the broadcast language. - /// - [JsonPropertyName("broadcastLanguage")] - public List BroadcastLanguage { get; set; } + /// + /// Gets or sets the broadcast language. + /// + [JsonPropertyName("broadcastLanguage")] + public List BroadcastLanguage { get; set; } - /// - /// Gets or sets the description language. - /// - [JsonPropertyName("descriptionLanguage")] - public List DescriptionLanguage { get; set; } + /// + /// Gets or sets the description language. + /// + [JsonPropertyName("descriptionLanguage")] + public List DescriptionLanguage { get; set; } - /// - /// Gets or sets the broadcaster. - /// - [JsonPropertyName("broadcaster")] - public BroadcasterDto Broadcaster { get; set; } + /// + /// Gets or sets the broadcaster. + /// + [JsonPropertyName("broadcaster")] + public BroadcasterDto Broadcaster { get; set; } - /// - /// Gets or sets the affiliate. - /// - [JsonPropertyName("affiliate")] - public string Affiliate { get; set; } + /// + /// Gets or sets the affiliate. + /// + [JsonPropertyName("affiliate")] + public string Affiliate { get; set; } - /// - /// Gets or sets the logo. - /// - [JsonPropertyName("logo")] - public LogoDto Logo { get; set; } + /// + /// Gets or sets the logo. + /// + [JsonPropertyName("logo")] + public LogoDto Logo { get; set; } - /// - /// Gets or set a value indicating whether it is commercial free. - /// - [JsonPropertyName("isCommercialFree")] - public bool? IsCommercialFree { get; set; } - } + /// + /// Gets or sets a value indicating whether it is commercial free. + /// + [JsonPropertyName("isCommercialFree")] + public bool? IsCommercialFree { get; set; } + } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunChannelCommands.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunChannelCommands.cs new file mode 100644 index 0000000000..069b4fab6b --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunChannelCommands.cs @@ -0,0 +1,35 @@ +#pragma warning disable CS1591 + +using System; +using System.Collections.Generic; + +namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun +{ + public class HdHomerunChannelCommands : IHdHomerunChannelCommands + { + private string? _channel; + private string? _profile; + + public HdHomerunChannelCommands(string? channel, string? profile) + { + _channel = channel; + _profile = profile; + } + + public IEnumerable<(string, string)> GetCommands() + { + if (!string.IsNullOrEmpty(_channel)) + { + if (!string.IsNullOrEmpty(_profile) + && !string.Equals(_profile, "native", StringComparison.OrdinalIgnoreCase)) + { + yield return ("vchannel", $"{_channel} transcode={_profile}"); + } + else + { + yield return ("vchannel", _channel); + } + } + } + } +} diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 4d538c6043..78ea7bd0f5 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -87,11 +87,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return lineup.Where(i => !i.DRM).ToList(); } - private class HdHomerunChannelInfo : ChannelInfo - { - public bool IsLegacyTuner { get; set; } - } - protected override async Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken) { var lineup = await GetLineup(tuner, cancellationToken).ConfigureAwait(false); @@ -715,5 +710,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return hostInfo; } + + private class HdHomerunChannelInfo : ChannelInfo + { + public bool IsLegacyTuner { get; set; } + } } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs index b2e555c7dc..f0f61297f6 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs @@ -5,12 +5,10 @@ using System; using System.Buffers; using System.Buffers.Binary; -using System.Collections.Generic; using System.Globalization; using System.Net; using System.Net.Sockets; using System.Text; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; @@ -18,70 +16,6 @@ using MediaBrowser.Controller.LiveTv; namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { - public interface IHdHomerunChannelCommands - { - IEnumerable<(string, string)> GetCommands(); - } - - public class LegacyHdHomerunChannelCommands : IHdHomerunChannelCommands - { - private string _channel; - private string _program; - - public LegacyHdHomerunChannelCommands(string url) - { - // parse url for channel and program - var regExp = new Regex(@"\/ch([0-9]+)-?([0-9]*)"); - var match = regExp.Match(url); - if (match.Success) - { - _channel = match.Groups[1].Value; - _program = match.Groups[2].Value; - } - } - - public IEnumerable<(string, string)> GetCommands() - { - if (!string.IsNullOrEmpty(_channel)) - { - yield return ("channel", _channel); - } - - if (!string.IsNullOrEmpty(_program)) - { - yield return ("program", _program); - } - } - } - - public class HdHomerunChannelCommands : IHdHomerunChannelCommands - { - private string _channel; - private string _profile; - - public HdHomerunChannelCommands(string channel, string profile) - { - _channel = channel; - _profile = profile; - } - - public IEnumerable<(string, string)> GetCommands() - { - if (!string.IsNullOrEmpty(_channel)) - { - if (!string.IsNullOrEmpty(_profile) - && !string.Equals(_profile, "native", StringComparison.OrdinalIgnoreCase)) - { - yield return ("vchannel", $"{_channel} transcode={_profile}"); - } - else - { - yield return ("vchannel", _channel); - } - } - } - } - public sealed class HdHomerunManager : IDisposable { public const int HdHomeRunPort = 65001; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/IHdHomerunChannelCommands.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/IHdHomerunChannelCommands.cs new file mode 100644 index 0000000000..1533549320 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/IHdHomerunChannelCommands.cs @@ -0,0 +1,11 @@ +#pragma warning disable CS1591 + +using System.Collections.Generic; + +namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun +{ + public interface IHdHomerunChannelCommands + { + IEnumerable<(string, string)> GetCommands(); + } +} diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/LegacyHdHomerunChannelCommands.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/LegacyHdHomerunChannelCommands.cs new file mode 100644 index 0000000000..26627b8aa6 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/LegacyHdHomerunChannelCommands.cs @@ -0,0 +1,38 @@ +#pragma warning disable CS1591 + +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun +{ + public class LegacyHdHomerunChannelCommands : IHdHomerunChannelCommands + { + private string? _channel; + private string? _program; + + public LegacyHdHomerunChannelCommands(string url) + { + // parse url for channel and program + var regExp = new Regex(@"\/ch([0-9]+)-?([0-9]*)"); + var match = regExp.Match(url); + if (match.Success) + { + _channel = match.Groups[1].Value; + _program = match.Groups[2].Value; + } + } + + public IEnumerable<(string, string)> GetCommands() + { + if (!string.IsNullOrEmpty(_channel)) + { + yield return ("channel", _channel); + } + + if (!string.IsNullOrEmpty(_program)) + { + yield return ("program", _program); + } + } + } +} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 47cec7d77f..4b3a75b90b 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -39,11 +39,6 @@ true true snupkg - false - - - - true diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index b0a12a9c90..91803ade6e 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -21,11 +21,6 @@ true true snupkg - false - - - - true -- cgit v1.2.3 From 6297fa5bf70880a2254f226d33da658b6b4ff05a Mon Sep 17 00:00:00 2001 From: Systerm Date: Wed, 6 Oct 2021 20:50:46 +0000 Subject: Translated using Weblate (Portuguese) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt/ --- .../Localization/Core/pt.json | 75 +++++++++++----------- 1 file changed, 38 insertions(+), 37 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/pt.json b/Emby.Server.Implementations/Localization/Core/pt.json index 474dacd7cc..a9dbd53ea2 100644 --- a/Emby.Server.Implementations/Localization/Core/pt.json +++ b/Emby.Server.Implementations/Localization/Core/pt.json @@ -1,6 +1,6 @@ { - "HeaderLiveTV": "TV em Directo", - "Collections": "Colecções", + "HeaderLiveTV": "TV Ao Vivo", + "Collections": "Coleções", "Books": "Livros", "Artists": "Artistas", "Albums": "Álbuns", @@ -10,29 +10,29 @@ "HeaderFavoriteAlbums": "Álbuns Favoritos", "HeaderFavoriteEpisodes": "Episódios Favoritos", "HeaderFavoriteShows": "Séries Favoritas", - "HeaderContinueWatching": "Continuar a Assistir", + "HeaderContinueWatching": "Continuar assistindo", "HeaderAlbumArtists": "Artistas do Álbum", - "Genres": "Géneros", - "Folders": "Directórios", + "Genres": "Gêneros", + "Folders": "Diretórios", "Favorites": "Favoritos", "Channels": "Canais", - "UserDownloadingItemWithValues": "{0} está a ser transferido {1}", + "UserDownloadingItemWithValues": "{0} está sendo baixado {1}", "VersionNumber": "Versão {0}", "ValueHasBeenAddedToLibrary": "{0} foi adicionado à sua biblioteca multimédia", "UserStoppedPlayingItemWithValues": "{0} terminou a reprodução de {1} em {2}", - "UserStartedPlayingItemWithValues": "{0} está a reproduzir {1} em {2}", - "UserPolicyUpdatedWithName": "A política do utilizador {0} foi alterada", - "UserPasswordChangedWithName": "A palavra-passe do utilizador {0} foi alterada", - "UserOnlineFromDevice": "{0} ligou-se a partir de {1}", + "UserStartedPlayingItemWithValues": "{0} está reproduzindo {1} em {2}", + "UserPolicyUpdatedWithName": "A política do usuário {0} foi alterada", + "UserPasswordChangedWithName": "A senha do usuário {0} foi alterada", + "UserOnlineFromDevice": "{0} está online a partir de {1}", "UserOfflineFromDevice": "{0} desconectou-se a partir de {1}", - "UserLockedOutWithName": "O utilizador {0} foi bloqueado", - "UserDeletedWithName": "O utilizador {0} foi removido", - "UserCreatedWithName": "O utilizador {0} foi criado", - "User": "Utilizador", + "UserLockedOutWithName": "O usuário {0} foi bloqueado", + "UserDeletedWithName": "O usuário {0} foi removido", + "UserCreatedWithName": "O usuário {0} foi criado", + "User": "Usuário", "TvShows": "Séries", "System": "Sistema", "SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas de {0} para {1}", - "StartupEmbyServerIsLoading": "O servidor Jellyfin está a iniciar. Tente novamente dentro de momentos.", + "StartupEmbyServerIsLoading": "O servidor Jellyfin está iniciando. Tente novamente dentro de momentos.", "ServerNameNeedsToBeRestarted": "{0} necessita ser reiniciado", "ScheduledTaskStartedWithName": "{0} iniciou", "ScheduledTaskFailedWithName": "{0} falhou", @@ -43,38 +43,38 @@ "Plugin": "Plugin", "NotificationOptionVideoPlaybackStopped": "Reprodução de vídeo parada", "NotificationOptionVideoPlayback": "Reprodução de vídeo iniciada", - "NotificationOptionUserLockedOut": "Utilizador bloqueado", - "NotificationOptionTaskFailed": "Falha em tarefa agendada", + "NotificationOptionUserLockedOut": "Usuário bloqueado", + "NotificationOptionTaskFailed": "Falha na tarefa agendada", "NotificationOptionServerRestartRequired": "É necessário reiniciar o servidor", - "NotificationOptionPluginUpdateInstalled": "Plugin actualizado", + "NotificationOptionPluginUpdateInstalled": "Plugin atualizado", "NotificationOptionPluginUninstalled": "Plugin desinstalado", "NotificationOptionPluginInstalled": "Plugin instalado", "NotificationOptionPluginError": "Falha no plugin", "NotificationOptionNewLibraryContent": "Novo conteúdo adicionado", "NotificationOptionInstallationFailed": "Falha de instalação", - "NotificationOptionCameraImageUploaded": "Imagem de câmara enviada", + "NotificationOptionCameraImageUploaded": "Imagem de câmera enviada", "NotificationOptionAudioPlaybackStopped": "Reprodução Parada", "NotificationOptionAudioPlayback": "Reprodução Iniciada", - "NotificationOptionApplicationUpdateInstalled": "A actualização da aplicação foi instalada", - "NotificationOptionApplicationUpdateAvailable": "Uma actualização da aplicação está disponível", - "NewVersionIsAvailable": "Uma nova versão do servidor Jellyfin está disponível para transferência.", + "NotificationOptionApplicationUpdateInstalled": "A atualização do aplicativo foi instalada", + "NotificationOptionApplicationUpdateAvailable": "Uma atualização do aplicativo está disponível", + "NewVersionIsAvailable": "Uma nova versão do servidor Jellyfin está disponível para download.", "NameSeasonUnknown": "Temporada Desconhecida", "NameSeasonNumber": "Temporada {0}", "NameInstallFailed": "Falha na instalação de {0}", "MusicVideos": "Videoclipes", "Music": "Música", - "MixedContent": "Conteúdo Misto", - "MessageServerConfigurationUpdated": "A configuração do servidor foi actualizada", - "MessageNamedServerConfigurationUpdatedWithValue": "As configurações do servidor na secção {0} foram atualizadas", + "MixedContent": "Conteúdo diverso", + "MessageServerConfigurationUpdated": "A configuração do servidor foi atualizada", + "MessageNamedServerConfigurationUpdatedWithValue": "As configurações do servidor na seção {0} foram atualizadas", "MessageApplicationUpdatedTo": "O servidor Jellyfin foi atualizado para a versão {0}", - "MessageApplicationUpdated": "O servidor Jellyfin foi actualizado", + "MessageApplicationUpdated": "O servidor Jellyfin foi atualizado", "Latest": "Mais Recente", "LabelRunningTimeValue": "Duração: {0}", "LabelIpAddressValue": "Endereço de IP: {0}", "ItemRemovedWithName": "{0} foi removido da biblioteca", "ItemAddedWithName": "{0} foi adicionado à biblioteca", "Inherit": "Herdar", - "HomeVideos": "Vídeos Caseiros", + "HomeVideos": "Vídeos principais", "HeaderRecordingGroups": "Grupos de Gravação", "ValueSpecialEpisodeName": "Episódio Especial - {0}", "Sync": "Sincronização", @@ -83,22 +83,22 @@ "Playlists": "Listas de Reprodução", "Photos": "Fotografias", "Movies": "Filmes", - "FailedLoginAttemptWithUserName": "Tentativa de ligação falhada a partir de {0}", - "DeviceOnlineWithName": "{0} está connectado", + "FailedLoginAttemptWithUserName": "Tentativa falha de login a partir de {0}", + "DeviceOnlineWithName": "{0} está conectado", "DeviceOfflineWithName": "{0} desconectou-se", "ChapterNameValue": "Capítulo {0}", "CameraImageUploadedFrom": "Uma nova imagem da câmara foi enviada a partir de {0}", "AuthenticationSucceededWithUserName": "{0} autenticado com sucesso", - "Application": "Aplicação", - "AppDeviceValues": "Aplicação {0}, Dispositivo: {1}", + "Application": "Aplicativo", + "AppDeviceValues": "Aplicativo {0}, Dispositivo: {1}", "TaskCleanCache": "Limpar Diretório de Cache", - "TasksApplicationCategory": "Aplicação", + "TasksApplicationCategory": "Aplicativo", "TasksLibraryCategory": "Biblioteca", "TasksMaintenanceCategory": "Manutenção", "TaskRefreshChannels": "Atualizar Canais", "TaskUpdatePlugins": "Atualizar Plugins", "TaskCleanLogsDescription": "Deletar arquivos de log que existe a mais de {0} dias.", - "TaskCleanLogs": "Limpar diretório de log", + "TaskCleanLogs": "Limpar diretório de logs", "TaskRefreshLibrary": "Escanear biblioteca de mídias", "TaskRefreshChapterImagesDescription": "Cria miniaturas para vídeos que têm capítulos.", "TaskCleanCacheDescription": "Apaga ficheiros em cache que já não são usados pelo sistema.", @@ -109,14 +109,15 @@ "TaskRefreshChannelsDescription": "Atualiza as informações do canal da Internet.", "TaskCleanTranscodeDescription": "Apagar os ficheiros com mais de um dia, de Transcode.", "TaskCleanTranscode": "Limpar o diretório de Transcode", - "TaskUpdatePluginsDescription": "Download e instala as atualizações para plug-ins configurados para atualização automática.", + "TaskUpdatePluginsDescription": "Baixa e instala as atualizações para plug-ins configurados para atualização automática.", "TaskRefreshPeopleDescription": "Atualiza os metadados para atores e diretores na tua biblioteca de media.", "TaskRefreshPeople": "Atualizar pessoas", - "TaskRefreshLibraryDescription": "Pesquisa a tua biblioteca de media por novos ficheiros e atualiza os metadados.", - "TaskCleanActivityLog": "Limpar registo de atividade", + "TaskRefreshLibraryDescription": "Pesquisa sua biblioteca de media por novos arquivos e atualiza os metadados.", + "TaskCleanActivityLog": "Limpar registro de atividade", "Undefined": "Indefinido", "Forced": "Forçado", "Default": "Predefinição", "TaskCleanActivityLogDescription": "Apaga itens no registro com idade acima do que é configurado.", - "TaskOptimizeDatabase": "Otimizar base de dados" + "TaskOptimizeDatabase": "Otimizar base de dados", + "TaskOptimizeDatabaseDescription": "Base de dados compacta e corta espaço livre. A execução desta tarefa depois de digitalizar a biblioteca ou de fazer outras alterações que impliquem modificações na base de dados pode melhorar o desempenho." } -- cgit v1.2.3 From 3b492d4af8c432cc11b11e946b72aaf97cf63c95 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 8 Oct 2021 15:02:58 +0200 Subject: Use static crypto rng --- .../Cryptography/CryptographyProvider.cs | 54 +++------------------- .../Users/DefaultPasswordResetProvider.cs | 11 ++--- 2 files changed, 9 insertions(+), 56 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs index 4a9b280852..673810c49d 100644 --- a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs +++ b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs @@ -10,8 +10,12 @@ namespace Emby.Server.Implementations.Cryptography /// /// Class providing abstractions over cryptographic functions. /// - public class CryptographyProvider : ICryptoProvider, IDisposable + public class CryptographyProvider : ICryptoProvider { + // FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto + // Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1 + // there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one + // Please note the default method of PBKDF2 is not included, it cannot be used to generate hashes cleanly as it is actually a pbkdf with sha1 private static readonly HashSet _supportedHashMethods = new HashSet() { "MD5", @@ -30,22 +34,6 @@ namespace Emby.Server.Implementations.Cryptography "System.Security.Cryptography.SHA512" }; - private RandomNumberGenerator _randomNumberGenerator; - - private bool _disposed; - - /// - /// Initializes a new instance of the class. - /// - public CryptographyProvider() - { - // FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto - // Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1 - // there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one - // Please note the default method of PBKDF2 is not included, it cannot be used to generate hashes cleanly as it is actually a pbkdf with sha1 - _randomNumberGenerator = RandomNumberGenerator.Create(); - } - /// public string DefaultHashMethod => "PBKDF2"; @@ -101,36 +89,6 @@ namespace Emby.Server.Implementations.Cryptography /// public byte[] GenerateSalt(int length) - { - byte[] salt = new byte[length]; - _randomNumberGenerator.GetBytes(salt); - return salt; - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - - if (disposing) - { - _randomNumberGenerator.Dispose(); - } - - _disposed = true; - } + => RandomNumberGenerator.GetBytes(length); } } diff --git a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs index 25ef01dce9..5e84255f91 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs @@ -93,13 +93,9 @@ namespace Jellyfin.Server.Implementations.Users /// public async Task StartForgotPasswordProcess(User user, bool isInNetwork) { - string pin; - using (var cryptoRandom = RandomNumberGenerator.Create()) - { - byte[] bytes = new byte[4]; - cryptoRandom.GetBytes(bytes); - pin = BitConverter.ToString(bytes); - } + byte[] bytes = new byte[4]; + RandomNumberGenerator.Fill(bytes); + string pin = BitConverter.ToString(bytes); DateTime expireTime = DateTime.UtcNow.AddMinutes(30); string filePath = _passwordResetFileBase + user.Id + ".json"; @@ -114,7 +110,6 @@ namespace Jellyfin.Server.Implementations.Users await using (FileStream fileStream = AsyncFile.OpenWrite(filePath)) { await JsonSerializer.SerializeAsync(fileStream, spr).ConfigureAwait(false); - await fileStream.FlushAsync().ConfigureAwait(false); } user.EasyPassword = pin; -- cgit v1.2.3 From d05062fec06ecba1049beefffe8d8f521d3e1881 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 8 Oct 2021 15:40:13 +0200 Subject: Use new Random.Shared instead of creating new instances --- Emby.Server.Implementations/Dto/DtoService.cs | 2 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs | 3 +-- Jellyfin.Api/Controllers/MediaInfoController.cs | 2 +- tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs | 4 +--- 4 files changed, 4 insertions(+), 7 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 74400b5128..ad76f3d6d4 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -420,7 +420,7 @@ namespace Emby.Server.Implementations.Dto // Just return something so that apps that are expecting a value won't think the folders are empty if (folder is ICollectionFolder || folder is UserView) { - return new Random().Next(1, 10); + return Random.Shared.Next(1, 10); } return folder.GetChildCount(user); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs index b2e555c7dc..08ed1a32ac 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs @@ -150,8 +150,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun if (!_lockkey.HasValue) { - var rand = new Random(); - _lockkey = (uint)rand.Next(); + _lockkey = (uint)Random.Shared.Next(); } var lockKeyValue = _lockkey.Value; diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs index 96ef2d678b..b422eb78c6 100644 --- a/Jellyfin.Api/Controllers/MediaInfoController.cs +++ b/Jellyfin.Api/Controllers/MediaInfoController.cs @@ -316,7 +316,7 @@ namespace Jellyfin.Api.Controllers byte[] buffer = ArrayPool.Shared.Rent(size); try { - new Random().NextBytes(buffer); + Random.Shared.NextBytes(buffer); return File(buffer, MediaTypeNames.Application.Octet); } finally diff --git a/tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs b/tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs index c72216d94b..a73cfb0781 100644 --- a/tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs +++ b/tests/Jellyfin.Extensions.Tests/ShuffleExtensionsTests.cs @@ -5,13 +5,11 @@ namespace Jellyfin.Extensions.Tests { public static class ShuffleExtensionsTests { - private static readonly Random _rng = new Random(); - [Fact] public static void Shuffle_Valid_Correct() { byte[] original = new byte[1 << 6]; - _rng.NextBytes(original); + Random.Shared.NextBytes(original); byte[] shuffled = (byte[])original.Clone(); shuffled.Shuffle(); -- cgit v1.2.3 From a81dfabdb649b98e1a809dfee941b75637623e9e Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sat, 9 Oct 2021 07:16:50 -0600 Subject: Fix indentation and build errors --- .../LiveTv/Listings/SchedulesDirectDtos/MapDto.cs | 2 +- .../Listings/SchedulesDirectDtos/StationDto.cs | 100 ++++++++++----------- 2 files changed, 51 insertions(+), 51 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs index 2420307b4f..ffd02d474b 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs @@ -53,6 +53,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the match type. /// [JsonPropertyName("matchType")] - public string? MatchType { get;set; } + public string? MatchType { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs index 1b76b22e32..d797fd49b1 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs @@ -5,62 +5,62 @@ using System.Text.Json.Serialization; namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos { /// - /// Station dto. - /// - public class StationDto - { - /// - /// Gets or sets the station id. - /// - [JsonPropertyName("stationID")] - public string? StationId { get; set; } + /// Station dto. + /// + public class StationDto + { + /// + /// Gets or sets the station id. + /// + [JsonPropertyName("stationID")] + public string? StationId { get; set; } - /// - /// Gets or sets the name. - /// - [JsonPropertyName("name")] - public string? Name { get; set; } + /// + /// Gets or sets the name. + /// + [JsonPropertyName("name")] + public string? Name { get; set; } - /// - /// Gets or sets the callsign. - /// - [JsonPropertyName("callsign")] - public string? Callsign { get; set; } + /// + /// Gets or sets the callsign. + /// + [JsonPropertyName("callsign")] + public string? Callsign { get; set; } - /// - /// Gets or sets the broadcast language. - /// - [JsonPropertyName("broadcastLanguage")] - public IReadOnlyList BroadcastLanguage { get; set; } = Array.Empty(); + /// + /// Gets or sets the broadcast language. + /// + [JsonPropertyName("broadcastLanguage")] + public IReadOnlyList BroadcastLanguage { get; set; } = Array.Empty(); - /// - /// Gets or sets the description language. - /// - [JsonPropertyName("descriptionLanguage")] - public IReadOnlyList DescriptionLanguage { get; set; } = Array.Empty(); + /// + /// Gets or sets the description language. + /// + [JsonPropertyName("descriptionLanguage")] + public IReadOnlyList DescriptionLanguage { get; set; } = Array.Empty(); - /// - /// Gets or sets the broadcaster. - /// - [JsonPropertyName("broadcaster")] - public BroadcasterDto? Broadcaster { get; set; } + /// + /// Gets or sets the broadcaster. + /// + [JsonPropertyName("broadcaster")] + public BroadcasterDto? Broadcaster { get; set; } - /// - /// Gets or sets the affiliate. - /// - [JsonPropertyName("affiliate")] - public string? Affiliate { get; set; } + /// + /// Gets or sets the affiliate. + /// + [JsonPropertyName("affiliate")] + public string? Affiliate { get; set; } - /// - /// Gets or sets the logo. - /// - [JsonPropertyName("logo")] - public LogoDto? Logo { get; set; } + /// + /// Gets or sets the logo. + /// + [JsonPropertyName("logo")] + public LogoDto? Logo { get; set; } - /// - /// Gets or set a value indicating whether it is commercial free. - /// - [JsonPropertyName("isCommercialFree")] - public bool? IsCommercialFree { get; set; } - } + /// + /// Gets or sets a value indicating whether it is commercial free. + /// + [JsonPropertyName("isCommercialFree")] + public bool? IsCommercialFree { get; set; } + } } -- cgit v1.2.3 From 2b004e1f762c5e43c8321bc1aa9740d8102a0426 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Sat, 9 Oct 2021 21:36:39 +0300 Subject: Add more sorting to Latest --- Emby.Server.Implementations/Library/UserViewManager.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index eda494815d..711647e7a6 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -355,7 +355,12 @@ namespace Emby.Server.Implementations.Library var query = new InternalItemsQuery(user) { IncludeItemTypes = includeItemTypes, - OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) }, + OrderBy = new[] + { + (ItemSortBy.DateCreated, SortOrder.Descending), + (ItemSortBy.SortName, SortOrder.Descending), + (ItemSortBy.ProductionYear, SortOrder.Descending) + }, IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null, ExcludeItemTypes = excludeItemTypes, IsVirtualItem = false, -- cgit v1.2.3 From aa93774b29193680799979c9c94bbb5ae2316a8a Mon Sep 17 00:00:00 2001 From: TheGoose Date: Sat, 9 Oct 2021 10:10:41 +0000 Subject: Translated using Weblate (English (United Kingdom)) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/en_GB/ --- Emby.Server.Implementations/Localization/Core/en-GB.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/en-GB.json b/Emby.Server.Implementations/Localization/Core/en-GB.json index 8b2e8b6b1c..86ce9240e5 100644 --- a/Emby.Server.Implementations/Localization/Core/en-GB.json +++ b/Emby.Server.Implementations/Localization/Core/en-GB.json @@ -15,7 +15,7 @@ "Favorites": "Favourites", "Folders": "Folders", "Genres": "Genres", - "HeaderAlbumArtists": "Album Artists", + "HeaderAlbumArtists": "Artist's Album", "HeaderContinueWatching": "Continue Watching", "HeaderFavoriteAlbums": "Favourite Albums", "HeaderFavoriteArtists": "Favourite Artists", @@ -25,7 +25,7 @@ "HeaderLiveTV": "Live TV", "HeaderNextUp": "Next Up", "HeaderRecordingGroups": "Recording Groups", - "HomeVideos": "Home videos", + "HomeVideos": "Home Videos", "Inherit": "Inherit", "ItemAddedWithName": "{0} was added to the library", "ItemRemovedWithName": "{0} was removed from the library", @@ -39,7 +39,7 @@ "MixedContent": "Mixed content", "Movies": "Movies", "Music": "Music", - "MusicVideos": "Music videos", + "MusicVideos": "Music Videos", "NameInstallFailed": "{0} installation failed", "NameSeasonNumber": "Season {0}", "NameSeasonUnknown": "Season Unknown", -- cgit v1.2.3 From e3edd7ae2c7d8bc564537bca7e7b1cbf91c2713e Mon Sep 17 00:00:00 2001 From: rimasx Date: Mon, 11 Oct 2021 15:39:56 -0400 Subject: Added translation using Weblate (Estonian) --- Emby.Server.Implementations/Localization/Core/et.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 Emby.Server.Implementations/Localization/Core/et.json (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/et.json b/Emby.Server.Implementations/Localization/Core/et.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/Emby.Server.Implementations/Localization/Core/et.json @@ -0,0 +1 @@ +{} -- cgit v1.2.3 From 2b10251b32ad00290f6be00060ec6ccf47574b5d Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Tue, 12 Oct 2021 18:31:58 -0600 Subject: Update to dotnet6.rc2 --- Emby.Dlna/Emby.Dlna.csproj | 2 +- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 10 +++++----- Jellyfin.Api/Jellyfin.Api.csproj | 4 ++-- Jellyfin.Data/Jellyfin.Data.csproj | 2 +- .../Jellyfin.Server.Implementations.csproj | 8 ++++---- Jellyfin.Server/Jellyfin.Server.csproj | 8 ++++---- MediaBrowser.Common/MediaBrowser.Common.csproj | 4 ++-- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 6 +++--- MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj | 4 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 4 ++-- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 6 +++--- deployment/Dockerfile.centos.amd64 | 2 +- deployment/Dockerfile.fedora.amd64 | 2 +- deployment/Dockerfile.ubuntu.amd64 | 2 +- deployment/Dockerfile.ubuntu.arm64 | 2 +- deployment/Dockerfile.ubuntu.armhf | 2 +- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 4 ++-- .../Jellyfin.Server.Integration.Tests.csproj | 4 ++-- tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj | 4 ++-- 19 files changed, 40 insertions(+), 40 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index e4f30d4e0a..c8332e44e4 100644 --- a/Emby.Dlna/Emby.Dlna.csproj +++ b/Emby.Dlna/Emby.Dlna.csproj @@ -72,7 +72,7 @@ - + diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index dafcded089..9372cba9f2 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -25,11 +25,11 @@ - - - - - + + + + + diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index cdc69618a9..8a559704c0 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index f1bfaa63e0..2de53e7c83 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -35,7 +35,7 @@ - + diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index d9e6d794b3..e26cf093b9 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -19,13 +19,13 @@ - - - + + + 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 be2318c544..8983eb50fd 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -31,10 +31,10 @@ - - - - + + + + diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index c87d58a147..9c8ce4ac57 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 007355acdc..d378808658 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -15,10 +15,10 @@ - - + + - + diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 22bba23663..a6caca8db7 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -24,8 +24,8 @@ - - + + diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index e6a5b1711c..16bc4adf8a 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -30,9 +30,9 @@ - + - + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 71a3554fd6..15badfad7e 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -16,9 +16,9 @@ - - - + + + diff --git a/deployment/Dockerfile.centos.amd64 b/deployment/Dockerfile.centos.amd64 index 178f94f719..78f051e4fb 100644 --- a/deployment/Dockerfile.centos.amd64 +++ b/deployment/Dockerfile.centos.amd64 @@ -13,7 +13,7 @@ RUN yum update -yq \ && yum install -yq @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel git wget # Install DotNET SDK -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5fcb98bb-21e1-47a5-bb8e-bb25f41a3e52/04811d5d05b7e694f040d2a13c1aae4c/dotnet-sdk-6.0.100-rc.1.21463.6-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/20283373-1d83-4879-8278-0afb7fd4035e/56f204f174743b29a656499ad0fc93c3/dotnet-sdk-6.0.100-rc.2.21505.57-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.fedora.amd64 b/deployment/Dockerfile.fedora.amd64 index f0f2977a40..14eeb6eed8 100644 --- a/deployment/Dockerfile.fedora.amd64 +++ b/deployment/Dockerfile.fedora.amd64 @@ -12,7 +12,7 @@ RUN dnf update -yq \ && dnf install -yq @buildsys-build rpmdevtools git dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel systemd wget # Install DotNET SDK -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5fcb98bb-21e1-47a5-bb8e-bb25f41a3e52/04811d5d05b7e694f040d2a13c1aae4c/dotnet-sdk-6.0.100-rc.1.21463.6-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/20283373-1d83-4879-8278-0afb7fd4035e/56f204f174743b29a656499ad0fc93c3/dotnet-sdk-6.0.100-rc.2.21505.57-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.ubuntu.amd64 b/deployment/Dockerfile.ubuntu.amd64 index fe1b4981bc..8733be89cf 100644 --- a/deployment/Dockerfile.ubuntu.amd64 +++ b/deployment/Dockerfile.ubuntu.amd64 @@ -17,7 +17,7 @@ RUN apt-get update -yqq \ libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 # Install dotnet repository -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5fcb98bb-21e1-47a5-bb8e-bb25f41a3e52/04811d5d05b7e694f040d2a13c1aae4c/dotnet-sdk-6.0.100-rc.1.21463.6-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/20283373-1d83-4879-8278-0afb7fd4035e/56f204f174743b29a656499ad0fc93c3/dotnet-sdk-6.0.100-rc.2.21505.57-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.ubuntu.arm64 b/deployment/Dockerfile.ubuntu.arm64 index d984f5d898..6ae0d53ccb 100644 --- a/deployment/Dockerfile.ubuntu.arm64 +++ b/deployment/Dockerfile.ubuntu.arm64 @@ -16,7 +16,7 @@ RUN apt-get update -yqq \ mmv build-essential lsb-release # Install dotnet repository -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5fcb98bb-21e1-47a5-bb8e-bb25f41a3e52/04811d5d05b7e694f040d2a13c1aae4c/dotnet-sdk-6.0.100-rc.1.21463.6-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/20283373-1d83-4879-8278-0afb7fd4035e/56f204f174743b29a656499ad0fc93c3/dotnet-sdk-6.0.100-rc.2.21505.57-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.ubuntu.armhf b/deployment/Dockerfile.ubuntu.armhf index c013e6797e..154388148c 100644 --- a/deployment/Dockerfile.ubuntu.armhf +++ b/deployment/Dockerfile.ubuntu.armhf @@ -16,7 +16,7 @@ RUN apt-get update -yqq \ mmv build-essential lsb-release # Install dotnet repository -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5fcb98bb-21e1-47a5-bb8e-bb25f41a3e52/04811d5d05b7e694f040d2a13c1aae4c/dotnet-sdk-6.0.100-rc.1.21463.6-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/20283373-1d83-4879-8278-0afb7fd4035e/56f204f174743b29a656499ad0fc93c3/dotnet-sdk-6.0.100-rc.2.21505.57-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 8b581857fe..922b3d94f7 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -15,8 +15,8 @@ - - + + diff --git a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj index 38687ae61a..9d7b447edd 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj +++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index db24df240c..67ae0e0802 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -10,8 +10,8 @@ - - + + -- cgit v1.2.3 From e88e1fa8e9aa49323f4b55fd8cc6185cd9fb9059 Mon Sep 17 00:00:00 2001 From: JULIAN AUGUSTO RUIZ MARTINEZ Date: Wed, 13 Oct 2021 19:30:04 +0000 Subject: Translated using Weblate (Pirate) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pr/ --- Emby.Server.Implementations/Localization/Core/pr.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/pr.json b/Emby.Server.Implementations/Localization/Core/pr.json index 0967ef424b..e3a3bfaf1c 100644 --- a/Emby.Server.Implementations/Localization/Core/pr.json +++ b/Emby.Server.Implementations/Localization/Core/pr.json @@ -1 +1,5 @@ -{} +{ + "Books": "Libros", + "AuthenticationSucceededWithUserName": "{0} autentificado correctamente", + "Artists": "Artistas" +} -- cgit v1.2.3 From a720b12ec33f3b3d9dc1121d71f929a739a70012 Mon Sep 17 00:00:00 2001 From: lyaschuchenko Date: Tue, 12 Oct 2021 14:24:18 +0000 Subject: Translated using Weblate (Ukrainian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/uk/ --- Emby.Server.Implementations/Localization/Core/uk.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/uk.json b/Emby.Server.Implementations/Localization/Core/uk.json index 5a2069df56..e99ed6f0b9 100644 --- a/Emby.Server.Implementations/Localization/Core/uk.json +++ b/Emby.Server.Implementations/Localization/Core/uk.json @@ -1,5 +1,5 @@ { - "MusicVideos": "Музичні відеокліпи", + "MusicVideos": "Відеокліпи", "Music": "Музика", "Movies": "Фільми", "MessageApplicationUpdatedTo": "Jellyfin Server оновлено до версії {0}", @@ -16,7 +16,7 @@ "HeaderFavoriteArtists": "Улюблені виконавці", "HeaderFavoriteAlbums": "Улюблені альбоми", "HeaderContinueWatching": "Продовжити перегляд", - "HeaderAlbumArtists": "Виконавці альбому", + "HeaderAlbumArtists": "Виконавці альбомів", "Genres": "Жанри", "Folders": "Каталоги", "Favorites": "Улюблені", @@ -38,7 +38,7 @@ "NotificationOptionPluginInstalled": "Плагін встановлено", "NotificationOptionPluginError": "Помилка плагіна", "NotificationOptionNewLibraryContent": "Додано новий контент", - "HomeVideos": "Домашнє відео", + "HomeVideos": "Мої відео", "FailedLoginAttemptWithUserName": "Невдала спроба входу від {0}", "LabelRunningTimeValue": "Тривалість: {0}", "TaskDownloadMissingSubtitlesDescription": "Шукає в Інтернеті відсутні субтитри на основі конфігурації метаданих.", @@ -117,5 +117,7 @@ "TaskCleanActivityLogDescription": "Видаляє старші за встановлений термін записи з журналу активності.", "TaskCleanActivityLog": "Очистити журнал активності", "Undefined": "Не визначено", - "Default": "За замовчуванням" + "Default": "За замовчуванням", + "TaskOptimizeDatabase": "Оптимізувати базу даних", + "TaskOptimizeDatabaseDescription": "Стиснення бази даних та збільшення вільного простору. Виконання цього завдання після сканування бібліотеки або внесення інших змін, які передбачають модифікацію бази даних, може покращити продуктивність." } -- cgit v1.2.3 From 6cc4be85fc6362b2f0552b315ff73dbad686eccd Mon Sep 17 00:00:00 2001 From: rimasx Date: Wed, 13 Oct 2021 13:54:46 +0000 Subject: Translated using Weblate (Estonian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/ --- .../Localization/Core/et.json | 119 ++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/et.json b/Emby.Server.Implementations/Localization/Core/et.json index 0967ef424b..3e57d96ca2 100644 --- a/Emby.Server.Implementations/Localization/Core/et.json +++ b/Emby.Server.Implementations/Localization/Core/et.json @@ -1 +1,118 @@ -{} +{ + "TaskCleanActivityLogDescription": "Kustutab määratud ajast vanemad tegevuslogi kirjed.", + "UserDownloadingItemWithValues": "{0} laeb alla {1}", + "HeaderRecordingGroups": "Salvestusrühmad", + "TaskOptimizeDatabaseDescription": "Tihendab ja puhastab andmebaasi. Selle toimingu tegemine pärast meediakogu andmebaasiga seotud muudatuste skannimist võib jõudlust parandada.", + "TaskOptimizeDatabase": "Optimeeri andmebaasi", + "TaskDownloadMissingSubtitlesDescription": "Otsib veebist puuduvaid subtiitreid vastavalt määratud metaandmete seadetele.", + "TaskDownloadMissingSubtitles": "Laadi alla puuduvad subtiitrid", + "TaskRefreshChannelsDescription": "Värskendab veebikanalite teavet.", + "TaskRefreshChannels": "Värskenda kanaleid", + "TaskCleanTranscodeDescription": "Kustutab üle ühe päeva vanused transkodeerimisfailid.", + "TaskCleanTranscode": "Puhasta transkoodimise kataloog", + "TaskUpdatePluginsDescription": "Laadib alla ja paigaldab nende pluginate uuendused, mis on seadistatud automaatselt uuenduma.", + "TaskUpdatePlugins": "Uuenda pluginaid", + "TaskRefreshPeopleDescription": "Värskendab meediakogus näitlejate ja režissööride metaandmeid.", + "TaskRefreshPeople": "Värskenda inimesi", + "TaskCleanLogsDescription": "Kustutab logifailid, mis on vanemad kui {0} päeva.", + "TaskCleanLogs": "Puhasta logikataloog", + "TaskRefreshLibraryDescription": "Otsib meedikogust uusi faile ja värskendab metaandmeid.", + "Collections": "Kollektsioonid", + "TaskRefreshLibrary": "Skaneeri meediakogu", + "TaskRefreshChapterImagesDescription": "Loob peatükkidega videote jaoks pisipildid.", + "TaskRefreshChapterImages": "Eralda peatükipildid", + "TaskCleanCacheDescription": "Kustutab vahemälufailid, mida süsteem enam ei vaja.", + "TaskCleanCache": "Puhasta vahemälu kataloog", + "TaskCleanActivityLog": "Puhasta tegevuslogi", + "TasksChannelsCategory": "Veebikanalid", + "TasksApplicationCategory": "Rakendus", + "TasksLibraryCategory": "Meediakogu", + "TasksMaintenanceCategory": "Hooldus", + "VersionNumber": "Versioon {0}", + "ValueSpecialEpisodeName": "Eriepisood - {0}", + "ValueHasBeenAddedToLibrary": "{0} lisati meediakogusse", + "UserStartedPlayingItemWithValues": "{0} taasesitab {1} serveris {2}", + "UserPasswordChangedWithName": "Kasutaja {0} parooli on muudetud", + "UserLockedOutWithName": "Kasutaja {0} on lukustatud", + "UserDeletedWithName": "Kasutaja {0} on kustutatud", + "UserCreatedWithName": "Kasutaja {0} on loodud", + "ScheduledTaskStartedWithName": "{0} käivitati", + "ProviderValue": "Allikas: {0}", + "StartupEmbyServerIsLoading": "Jellyfin server laadib. Proovi varsti uuesti.", + "User": "Kasutaja", + "Undefined": "Määratlemata", + "TvShows": "Seriaalid", + "System": "Süsteem", + "Sync": "Sünkrooni", + "Songs": "Laulud", + "Shows": "Seriaalid", + "ServerNameNeedsToBeRestarted": "{0} tuleb taaskäivitada", + "ScheduledTaskFailedWithName": "{0} nurjus", + "PluginUpdatedWithName": "{0} uuendati", + "PluginUninstalledWithName": "{0} eemaldati", + "PluginInstalledWithName": "{0} paigaldati", + "Plugin": "Plugin", + "Playlists": "Pleilistid", + "Photos": "Fotod", + "NotificationOptionVideoPlaybackStopped": "Video taasesitus on peatatud", + "NotificationOptionVideoPlayback": "Video taasesitus algas", + "NotificationOptionUserLockedOut": "Kasutaja on lukustatud", + "NotificationOptionTaskFailed": "Ajastatud ülesanne nurjus", + "NotificationOptionServerRestartRequired": "Vajalik on serveri taaskäivitamine", + "NotificationOptionPluginUpdateInstalled": "Paigaldati plugina uuendus", + "NotificationOptionPluginUninstalled": "Plugin eemaldati", + "NotificationOptionPluginInstalled": "Plugin paigaldati", + "NotificationOptionPluginError": "Plugina tõrge", + "NotificationOptionNewLibraryContent": "Lisati uut sisu", + "NotificationOptionInstallationFailed": "Paigaldamine nurjus", + "NotificationOptionCameraImageUploaded": "Kaamera pilt on üles laaditud", + "NotificationOptionAudioPlaybackStopped": "Heli taasesitus peatati", + "NotificationOptionAudioPlayback": "Heli taasesitus algas", + "NotificationOptionApplicationUpdateInstalled": "Rakenduse uuendus paigaldati", + "NotificationOptionApplicationUpdateAvailable": "Rakenduse uuendus on saadaval", + "NewVersionIsAvailable": "Jellyfin serveri uus versioon on allalaadimiseks saadaval.", + "NameSeasonUnknown": "Tundmatu hooaeg", + "NameSeasonNumber": "Hooaeg {0}", + "NameInstallFailed": "{0} paigaldamine nurjus", + "MusicVideos": "Muusikavideod", + "Music": "Muusika", + "Movies": "Filmid", + "MixedContent": "Segatud sisu", + "MessageServerConfigurationUpdated": "Serveri seadistust uuendati", + "MessageNamedServerConfigurationUpdatedWithValue": "Serveri seadistusosa {0} uuendati", + "MessageApplicationUpdatedTo": "Jellyfin server uuendati versioonile {0}", + "MessageApplicationUpdated": "Jellyfin server uuendati", + "Latest": "Uusimad", + "LabelRunningTimeValue": "Kestus: {0}", + "LabelIpAddressValue": "IP aadress: {0}", + "ItemRemovedWithName": "{0} eemaldati meediakogust", + "ItemAddedWithName": "{0} lisati meediakogusse", + "Inherit": "Päri", + "HomeVideos": "Koduvideod", + "HeaderNextUp": "Järgmisena", + "HeaderLiveTV": "Otse TV", + "HeaderFavoriteSongs": "Lemmiklood", + "HeaderFavoriteShows": "Lemmikseriaalid", + "HeaderFavoriteEpisodes": "Lemmikepisoodid", + "HeaderFavoriteArtists": "Lemmikesitajad", + "HeaderFavoriteAlbums": "Lemmikalbumid", + "HeaderContinueWatching": "Jätka vaatamist", + "HeaderAlbumArtists": "Albumi esitaja", + "Genres": "Žanrid", + "Forced": "Sunnitud", + "Folders": "Kaustad", + "Favorites": "Lemmikud", + "FailedLoginAttemptWithUserName": "Ebaõnnestunud sisselogimiskatse kasutajalt {0}", + "DeviceOnlineWithName": "{0} on ühendatud", + "DeviceOfflineWithName": "{0} katkestas ühenduse", + "Default": "Vaikimisi", + "ChapterNameValue": "Peatükk {0}", + "Channels": "Kanalid", + "CameraImageUploadedFrom": "Uus kaamera pilt laaditi üles allikalt {0}", + "Books": "Raamatud", + "AuthenticationSucceededWithUserName": "{0} autentimine õnnestus", + "Artists": "Esitajad", + "Application": "Rakendus", + "AppDeviceValues": "Rakendus: {0}, seade: {1}", + "Albums": "Albumid" +} -- cgit v1.2.3 From b084afa1a04dd97bd5e9ffbae50e8d4848eec259 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Oct 2021 12:01:09 +0000 Subject: Bump prometheus-net.DotNetRuntime from 4.2.1 to 4.2.2 Bumps [prometheus-net.DotNetRuntime](https://github.com/djluck/prometheus-net.DotNetRuntime) from 4.2.1 to 4.2.2. - [Release notes](https://github.com/djluck/prometheus-net.DotNetRuntime/releases) - [Commits](https://github.com/djluck/prometheus-net.DotNetRuntime/compare/4.2.1...4.2.2) --- updated-dependencies: - dependency-name: prometheus-net.DotNetRuntime dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 9372cba9f2..c1ce4b5572 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -31,7 +31,7 @@ - + -- cgit v1.2.3 From dd0c1d3d27b455cc73d03bcc48becef298404dee Mon Sep 17 00:00:00 2001 From: Jessica Date: Mon, 18 Oct 2021 14:01:33 -0400 Subject: Added translation using Weblate (Welsh) --- Emby.Server.Implementations/Localization/Core/cy.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 Emby.Server.Implementations/Localization/Core/cy.json (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/cy.json b/Emby.Server.Implementations/Localization/Core/cy.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/Emby.Server.Implementations/Localization/Core/cy.json @@ -0,0 +1 @@ +{} -- cgit v1.2.3 From 4d324707157d444efa43c21869f73b8378901dd3 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Mon, 18 Oct 2021 13:39:48 +0000 Subject: Translated using Weblate (Esperanto) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eo/ --- Emby.Server.Implementations/Localization/Core/eo.json | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/eo.json b/Emby.Server.Implementations/Localization/Core/eo.json index ca615cc8cf..a6516a130d 100644 --- a/Emby.Server.Implementations/Localization/Core/eo.json +++ b/Emby.Server.Implementations/Localization/Core/eo.json @@ -1,17 +1,17 @@ { "NotificationOptionInstallationFailed": "Instalada fiasko", - "NotificationOptionAudioPlaybackStopped": "Sono de ludado haltis", + "NotificationOptionAudioPlaybackStopped": "Ludado de sono haltis", "NotificationOptionAudioPlayback": "Ludado de sono startis", "NameSeasonUnknown": "Sezono Nekonata", "NameSeasonNumber": "Sezono {0}", "NameInstallFailed": "{0} instalado fiaskis", "Music": "Muziko", "Movies": "Filmoj", - "ItemRemovedWithName": "{0} forigis el la biblioteko", - "ItemAddedWithName": "{0} aldonis al la biblioteko", + "ItemRemovedWithName": "{0} forigis el la libraro", + "ItemAddedWithName": "{0} aldonis al la libraro", "HeaderLiveTV": "Viva Televido", "HeaderContinueWatching": "Daŭrigi Spektado", - "HeaderAlbumArtists": "Artistoj de Albumo", + "HeaderAlbumArtists": "Albumo de artisto", "Folders": "Dosierujoj", "DeviceOnlineWithName": "{0} estas konektita", "Default": "Defaŭlte", @@ -30,7 +30,7 @@ "User": "Uzanto", "System": "Sistemo", "Songs": "Kantoj", - "ScheduledTaskStartedWithName": "{0} komencis", + "ScheduledTaskStartedWithName": "{0} startis", "ScheduledTaskFailedWithName": "{0} malsukcesis", "PluginUninstalledWithName": "{0} malinstaliĝis", "PluginInstalledWithName": "{0} instaliĝis", @@ -43,5 +43,10 @@ "MusicVideos": "Muzikvideoj", "LabelIpAddressValue": "IP-adreso: {0}", "Genres": "Ĝenroj", - "DeviceOfflineWithName": "{0} malkonektis" + "DeviceOfflineWithName": "{0} malkonektis", + "HeaderFavoriteArtists": "Favorataj Artistoj", + "Shows": "Serioj", + "HeaderFavoriteShows": "Favorataj Serioj", + "TvShows": "TV-serioj", + "Favorites": "Favoratoj" } -- cgit v1.2.3 From 8388f7c462d50065a931a42ff2c7b34a0d7e1c34 Mon Sep 17 00:00:00 2001 From: Jessica Date: Mon, 18 Oct 2021 18:19:17 +0000 Subject: Translated using Weblate (Welsh) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/cy/ --- Emby.Server.Implementations/Localization/Core/cy.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/cy.json b/Emby.Server.Implementations/Localization/Core/cy.json index 0967ef424b..0fa72dea41 100644 --- a/Emby.Server.Implementations/Localization/Core/cy.json +++ b/Emby.Server.Implementations/Localization/Core/cy.json @@ -1 +1,14 @@ -{} +{ + "DeviceOnlineWithName": "Mae {0} wedi'i gysylltu", + "DeviceOfflineWithName": "Mae {0} wedi datgysylltu", + "Default": "Diofyn", + "Collections": "Casgliadau", + "ChapterNameValue": "Pennod {0}", + "Channels": "Sianeli", + "CameraImageUploadedFrom": "Mae delwedd camera newydd wedi'i lanlwytho o {0}", + "Books": "Llyfrau", + "AuthenticationSucceededWithUserName": "{0} wedi’i ddilysu’n llwyddiannus", + "Artists": "Artistiaid", + "AppDeviceValues": "Ap: {0}, Dyfais: {1}", + "Albums": "Albwmau" +} -- cgit v1.2.3 From 7d8fb947b65638c41a9f6475306a1b81c577f089 Mon Sep 17 00:00:00 2001 From: "Sindre S. Kjær" Date: Tue, 19 Oct 2021 19:19:17 +0000 Subject: Translated using Weblate (Norwegian Bokmål) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nb_NO/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Emby.Server.Implementations/Localization/Core/nb.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json index 81c1eefe74..317bdcfcb6 100644 --- a/Emby.Server.Implementations/Localization/Core/nb.json +++ b/Emby.Server.Implementations/Localization/Core/nb.json @@ -119,5 +119,6 @@ "Forced": "Tvunget", "Default": "Standard", "TaskCleanActivityLogDescription": "Sletter oppføringer i aktivitetsloggen som er eldre enn den konfigurerte alderen.", - "TaskOptimizeDatabase": "Optimiser database" + "TaskOptimizeDatabase": "Optimiser database", + "TaskOptimizeDatabaseDescription": "Komprimerer database og frigjør plass. Denne prosessen kan forbedre ytelsen etter skanning av bibliotek eller andre handlinger som fører til databaseendringer." } -- cgit v1.2.3 From b53dea7113726c052a13e3cfa309730787db22cb Mon Sep 17 00:00:00 2001 From: WWWesten Date: Thu, 21 Oct 2021 11:21:38 +0000 Subject: Translated using Weblate (Esperanto) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eo/ --- .../Localization/Core/eo.json | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/eo.json b/Emby.Server.Implementations/Localization/Core/eo.json index a6516a130d..e04f3c2414 100644 --- a/Emby.Server.Implementations/Localization/Core/eo.json +++ b/Emby.Server.Implementations/Localization/Core/eo.json @@ -10,7 +10,7 @@ "ItemRemovedWithName": "{0} forigis el la libraro", "ItemAddedWithName": "{0} aldonis al la libraro", "HeaderLiveTV": "Viva Televido", - "HeaderContinueWatching": "Daŭrigi Spektado", + "HeaderContinueWatching": "Daŭrigi Spektadon", "HeaderAlbumArtists": "Albumo de artisto", "Folders": "Dosierujoj", "DeviceOnlineWithName": "{0} estas konektita", @@ -48,5 +48,28 @@ "Shows": "Serioj", "HeaderFavoriteShows": "Favorataj Serioj", "TvShows": "TV-serioj", - "Favorites": "Favoratoj" + "Favorites": "Favoratoj", + "TaskCleanLogs": "Purigi Ĵurnalan Katalogon", + "TaskRefreshLibrary": "Skanu Plurmedian Libraron", + "ValueSpecialEpisodeName": "Speciala - {0}", + "TaskOptimizeDatabase": "Optimigi datumbazon", + "TaskRefreshChannels": "Refreŝigi Kanalojn", + "TaskUpdatePlugins": "Ĝisdatigi Kromprogramojn", + "TaskRefreshPeople": "Refreŝigi Homojn", + "TasksChannelsCategory": "Interretaj Kanaloj", + "ProviderValue": "Provizanto: {0}", + "NotificationOptionPluginError": "Kromprograma malsukceso", + "MixedContent": "Miksita enhavo", + "TasksApplicationCategory": "Aplikaĵo", + "TasksMaintenanceCategory": "Prizorgado", + "Undefined": "Nedifinita", + "Sync": "Sinkronigo", + "Latest": "Plej novaj", + "Inherit": "Hereda", + "HomeVideos": "Hejmaj Videoj", + "HeaderNextUp": "Sekva Plue", + "HeaderFavoriteSongs": "Favorataj Kantoj", + "HeaderFavoriteEpisodes": "Favorataj Epizodoj", + "HeaderFavoriteAlbums": "Favorataj Albumoj", + "Forced": "Forcita" } -- cgit v1.2.3 From 1e69530752d52af9e091d5325a7bd01d125cbe25 Mon Sep 17 00:00:00 2001 From: rimasx Date: Wed, 20 Oct 2021 04:30:06 +0000 Subject: Translated using Weblate (Estonian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/ --- Emby.Server.Implementations/Localization/Core/et.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/et.json b/Emby.Server.Implementations/Localization/Core/et.json index 3e57d96ca2..c3596ecf14 100644 --- a/Emby.Server.Implementations/Localization/Core/et.json +++ b/Emby.Server.Implementations/Localization/Core/et.json @@ -45,7 +45,7 @@ "System": "Süsteem", "Sync": "Sünkrooni", "Songs": "Laulud", - "Shows": "Seriaalid", + "Shows": "Sarjad", "ServerNameNeedsToBeRestarted": "{0} tuleb taaskäivitada", "ScheduledTaskFailedWithName": "{0} nurjus", "PluginUpdatedWithName": "{0} uuendati", -- cgit v1.2.3 From d4c1912e64f5e9d82f2106f1c9ca47d6addf16fa Mon Sep 17 00:00:00 2001 From: WWWesten Date: Sat, 23 Oct 2021 10:15:08 +0000 Subject: Translated using Weblate (Esperanto) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eo/ --- .../Localization/Core/eo.json | 56 ++++++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/eo.json b/Emby.Server.Implementations/Localization/Core/eo.json index e04f3c2414..7ce87502cc 100644 --- a/Emby.Server.Implementations/Localization/Core/eo.json +++ b/Emby.Server.Implementations/Localization/Core/eo.json @@ -1,7 +1,7 @@ { "NotificationOptionInstallationFailed": "Instalada fiasko", "NotificationOptionAudioPlaybackStopped": "Ludado de sono haltis", - "NotificationOptionAudioPlayback": "Ludado de sono startis", + "NotificationOptionAudioPlayback": "Ludado de sono lanĉis", "NameSeasonUnknown": "Sezono Nekonata", "NameSeasonNumber": "Sezono {0}", "NameInstallFailed": "{0} instalado fiaskis", @@ -9,7 +9,7 @@ "Movies": "Filmoj", "ItemRemovedWithName": "{0} forigis el la libraro", "ItemAddedWithName": "{0} aldonis al la libraro", - "HeaderLiveTV": "Viva Televido", + "HeaderLiveTV": "TV-etero", "HeaderContinueWatching": "Daŭrigi Spektadon", "HeaderAlbumArtists": "Albumo de artisto", "Folders": "Dosierujoj", @@ -30,7 +30,7 @@ "User": "Uzanto", "System": "Sistemo", "Songs": "Kantoj", - "ScheduledTaskStartedWithName": "{0} startis", + "ScheduledTaskStartedWithName": "{0} lanĉis", "ScheduledTaskFailedWithName": "{0} malsukcesis", "PluginUninstalledWithName": "{0} malinstaliĝis", "PluginInstalledWithName": "{0} instaliĝis", @@ -71,5 +71,53 @@ "HeaderFavoriteSongs": "Favorataj Kantoj", "HeaderFavoriteEpisodes": "Favorataj Epizodoj", "HeaderFavoriteAlbums": "Favorataj Albumoj", - "Forced": "Forcita" + "Forced": "Forcita", + "ServerNameNeedsToBeRestarted": "{0} devas esti relanĉita", + "NotificationOptionVideoPlayback": "La videoludado lanĉis", + "NotificationOptionServerRestartRequired": "Servila relanĉigo bezonata", + "TaskOptimizeDatabaseDescription": "Kompaktigas datenbazon kaj trunkas liberan lokon. Lanĉi ĉi tiun taskon post la librara skanado aŭ fari aliajn ŝanĝojn, kiuj implicas datenbazajn modifojn, povus plibonigi rendimenton.", + "TaskUpdatePluginsDescription": "Elŝutas kaj instalas ĝisdatigojn por kromprogramojn, kiuj estas agorditaj por ĝisdatigi aŭtomate.", + "TaskDownloadMissingSubtitlesDescription": "Serĉas en interreto mankantajn subtekstojn surbaze de metadatena agordaro.", + "TaskRefreshPeopleDescription": "Ĝisdatigas metadatenojn por aktoroj kaj reĵisoroj en via plurmedia libraro.", + "TaskCleanLogsDescription": "Forigas ĵurnalajn dosierojn aĝajn pli ol {0} tagojn.", + "TaskRefreshLibraryDescription": "Skanas vian plurmedian libraron por novaj dosieroj kaj refreŝigas metadatenaron.", + "NewVersionIsAvailable": "Nova versio de Jellyfin Server estas elŝutebla.", + "TaskCleanCacheDescription": "Forigas stapla dosierojn ne plu necesajn de la sistemo.", + "TaskCleanActivityLogDescription": "Forigas aktivecan ĵurnalaĵojn pli malnovajn ol la agordita aĝo.", + "TaskCleanTranscodeDescription": "Forigas transkodajn dosierojn aĝajn pli ol unu tagon.", + "ValueHasBeenAddedToLibrary": "{0} estis aldonita al via plurmedia libraro", + "SubtitleDownloadFailureFromForItem": "Subtekstoj malsukcesis elŝuti de {0} por {1}", + "StartupEmbyServerIsLoading": "Jellyfin Server ŝarĝas. Provi denove baldaŭ.", + "TaskRefreshChapterImagesDescription": "Kreas bildetojn por videoj kiuj havas ĉapitrojn.", + "UserStoppedPlayingItemWithValues": "{0} finis ludi {1} ĉe {2}", + "UserPolicyUpdatedWithName": "Uzanta politiko estis ĝisdatigita por {0}", + "UserPasswordChangedWithName": "Pasvorto estis ŝanĝita por uzanto {0}", + "UserStartedPlayingItemWithValues": "{0} ludas {1} ĉe {2}", + "UserLockedOutWithName": "Uzanto {0} estas elŝlosita", + "UserOnlineFromDevice": "{0} estas enreta de {1}", + "UserOfflineFromDevice": "{0} malkonektis de {1}", + "UserDeletedWithName": "Uzanto {0} estis forigita", + "MessageServerConfigurationUpdated": "Servila agordaro estis ĝisdatigita", + "MessageNamedServerConfigurationUpdatedWithValue": "Servila agorda sekcio {0} estis ĝisdatigita", + "MessageApplicationUpdatedTo": "Jellyfin Server estis ĝisdatigita al {0}", + "MessageApplicationUpdated": "Jellyfin Server estis ĝisdatigita", + "TaskRefreshChannelsDescription": "Refreŝigas informon pri interretaj kanaloj.", + "TaskDownloadMissingSubtitles": "Elŝutu mankantajn subtekstojn", + "TaskCleanTranscode": "Malplenigi Transkodadan Katalogon", + "TaskRefreshChapterImages": "Eltiru Ĉapitro-Bildojn", + "TaskCleanCache": "Malplenigi Staplan Katalogon", + "TaskCleanActivityLog": "Malplenigi Aktivecan Ĵurnalon", + "PluginUpdatedWithName": "{0} estis ĝisdatigita", + "NotificationOptionVideoPlaybackStopped": "La videoludado haltis", + "NotificationOptionUserLockedOut": "Uzanto ŝlosita", + "NotificationOptionTaskFailed": "Planita tasko malsukcesis", + "NotificationOptionPluginUpdateInstalled": "Ĝisdatigo de kromprogramo instalita", + "NotificationOptionCameraImageUploaded": "Kamera bildo alŝutita", + "NotificationOptionApplicationUpdateInstalled": "Aplikaĵa ĝisdatigo instalita", + "NotificationOptionApplicationUpdateAvailable": "Ĝisdatigo de aplikaĵo havebla", + "LabelRunningTimeValue": "Ludada tempo: {0}", + "HeaderRecordingGroups": "Rikordadaj Grupoj", + "FailedLoginAttemptWithUserName": "Malsukcesa ensaluta provo de {0}", + "CameraImageUploadedFrom": "Nova kamera bildo estis alŝutita de {0}", + "AuthenticationSucceededWithUserName": "{0} sukcese aŭtentikigis" } -- cgit v1.2.3 From f2656b7ee2ea9c395a796d2117ffe445a26d7603 Mon Sep 17 00:00:00 2001 From: ButterflyOfFire Date: Sat, 23 Oct 2021 11:25:19 +0000 Subject: Translated using Weblate (Arabic) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/ --- Emby.Server.Implementations/Localization/Core/ar.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json index 5a4a4d5a91..ee70aa8d86 100644 --- a/Emby.Server.Implementations/Localization/Core/ar.json +++ b/Emby.Server.Implementations/Localization/Core/ar.json @@ -15,7 +15,7 @@ "Favorites": "المفضلة", "Folders": "المجلدات", "Genres": "التضنيفات", - "HeaderAlbumArtists": "فناني الألبومات", + "HeaderAlbumArtists": "ألبوم الفنان", "HeaderContinueWatching": "استئناف", "HeaderFavoriteAlbums": "الألبومات المفضلة", "HeaderFavoriteArtists": "الفنانون المفضلون", @@ -25,7 +25,7 @@ "HeaderLiveTV": "التلفاز المباشر", "HeaderNextUp": "التالي", "HeaderRecordingGroups": "مجموعات التسجيل", - "HomeVideos": "الفيديوهات المنزلية", + "HomeVideos": "الفيديوهات الشخصية", "Inherit": "توريث", "ItemAddedWithName": "تم إضافة {0} للمكتبة", "ItemRemovedWithName": "تم إزالة {0} من المكتبة", -- cgit v1.2.3 From b830d38a347fd045e0a8573e69180dd5d296fdd9 Mon Sep 17 00:00:00 2001 From: Roel van Uden <> Date: Tue, 26 Oct 2021 12:59:11 +0200 Subject: Rework subtitle selection to reduce code clutter --- .../Library/MediaStreamSelector.cs | 49 +++++++--------------- 1 file changed, 15 insertions(+), 34 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index 71e3404d07..f94eeda8fc 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -38,14 +38,11 @@ namespace Emby.Server.Implementations.Library } public static int? GetDefaultSubtitleStreamIndex( - List streams, + IEnumerable streams, string[] preferredLanguages, SubtitlePlaybackMode mode, string audioTrackLanguage) { - streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages) - .ToList(); - MediaStream stream = null; if (mode == SubtitlePlaybackMode.None) @@ -53,62 +50,46 @@ namespace Emby.Server.Implementations.Library return null; } + var sortedStreams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages) + .OrderByDescending(x => x.IsExternal) + .ThenByDescending(x => x.IsForced && string.Equals(x.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) + .ThenByDescending(x => x.IsForced) + .ThenByDescending(x => x.IsDefault) + .ToList(); + if (mode == SubtitlePlaybackMode.Default) { // Prefer embedded metadata over smart logic - - stream = streams.FirstOrDefault(s => s.IsExternal && s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => s.IsExternal && s.IsForced) ?? - streams.FirstOrDefault(s => s.IsExternal && s.IsDefault) ?? - streams.FirstOrDefault(s => s.IsExternal) ?? - streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => s.IsForced) ?? - streams.FirstOrDefault(s => s.IsDefault); + stream = sortedStreams.FirstOrDefault(s => s.IsExternal || s.IsForced || s.IsDefault); // if the audio language is not understood by the user, load their preferred subs, if there are any if (stream == null && !preferredLanguages.Contains(audioTrackLanguage, StringComparer.OrdinalIgnoreCase)) { - stream = streams.FirstOrDefault(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); + stream = sortedStreams.FirstOrDefault(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); } } else if (mode == SubtitlePlaybackMode.Smart) { - // Prefer smart logic over embedded metadata - // if the audio language is not understood by the user, load their preferred subs, if there are any if (!preferredLanguages.Contains(audioTrackLanguage, StringComparer.OrdinalIgnoreCase)) { - stream = streams.FirstOrDefault(s => s.IsExternal && !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => s.IsExternal && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); + stream = sortedStreams.FirstOrDefault(s => preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); } } else if (mode == SubtitlePlaybackMode.Always) { // always load the most suitable full subtitles - stream = streams.FirstOrDefault(s => s.IsExternal && !s.IsForced) ?? - streams.FirstOrDefault(s => !s.IsForced); + stream = sortedStreams.FirstOrDefault(s => !s.IsForced); } else if (mode == SubtitlePlaybackMode.OnlyForced) { // always load the most suitable full subtitles - stream = streams.FirstOrDefault(s => s.IsExternal && s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => s.IsExternal && s.IsForced) ?? - streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => s.IsForced); + stream = sortedStreams.FirstOrDefault(x => x.IsForced); } // load forced subs if we have found no suitable full subtitles - stream ??= streams.FirstOrDefault(s => s.IsExternal && s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) ?? - streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)); - - if (stream != null) - { - return stream.Index; - } - - return null; + stream ??= sortedStreams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)); + return stream?.Index; } private static IEnumerable GetSortedStreams(IEnumerable streams, MediaStreamType type, string[] languagePreferences) -- cgit v1.2.3 From 1b6eb2ff2d2cc3973fa529c721cf50e3ad849646 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 26 Oct 2021 13:56:30 +0200 Subject: Enable nullable for more files --- Emby.Server.Implementations/Channels/ChannelManager.cs | 4 +--- Jellyfin.Server.Implementations/Users/UserManager.cs | 6 +----- MediaBrowser.Model/Channels/ChannelFeatures.cs | 8 +++++--- MediaBrowser.Model/Channels/ChannelQuery.cs | 5 ++--- .../Configuration/BaseApplicationConfiguration.cs | 7 +++---- MediaBrowser.Model/Configuration/LibraryOptions.cs | 13 ++++++------- MediaBrowser.Model/Configuration/UserConfiguration.cs | 5 ++--- MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs | 3 +-- MediaBrowser.Model/Dlna/DeviceIdentification.cs | 1 - MediaBrowser.Model/Dlna/ITranscoderSupport.cs | 1 - MediaBrowser.Model/Users/PinRedeemResult.cs | 5 +++-- 11 files changed, 24 insertions(+), 34 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 178f30de05..09aee602af 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -586,7 +586,7 @@ namespace Emby.Server.Implementations.Channels { var supportsLatest = provider is ISupportsLatestMedia; - return new ChannelFeatures + return new ChannelFeatures(channel.Name, channel.Id) { CanFilter = !features.MaxPageSize.HasValue, CanSearch = provider is ISearchableChannel, @@ -596,8 +596,6 @@ namespace Emby.Server.Implementations.Channels MediaTypes = features.MediaTypes.ToArray(), SupportsSortOrderToggle = features.SupportsSortOrderToggle, SupportsLatestMedia = supportsLatest, - Name = channel.Name, - Id = channel.Id.ToString("N", CultureInfo.InvariantCulture), SupportsContentDownloading = features.SupportsContentDownloading, AutoRefreshLevels = features.AutoRefreshLevels }; diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 704a6a84ef..8ca6e8d21b 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -530,11 +530,7 @@ namespace Jellyfin.Server.Implementations.Users } } - return new PinRedeemResult - { - Success = false, - UsersReset = Array.Empty() - }; + return new PinRedeemResult(); } /// diff --git a/MediaBrowser.Model/Channels/ChannelFeatures.cs b/MediaBrowser.Model/Channels/ChannelFeatures.cs index d925b78b6d..1ca8e80a6f 100644 --- a/MediaBrowser.Model/Channels/ChannelFeatures.cs +++ b/MediaBrowser.Model/Channels/ChannelFeatures.cs @@ -1,4 +1,3 @@ -#nullable disable #pragma warning disable CS1591 using System; @@ -7,11 +6,14 @@ namespace MediaBrowser.Model.Channels { public class ChannelFeatures { - public ChannelFeatures() + public ChannelFeatures(string name, Guid id) { MediaTypes = Array.Empty(); ContentTypes = Array.Empty(); DefaultSortFields = Array.Empty(); + + Name = name; + Id = id; } /// @@ -24,7 +26,7 @@ namespace MediaBrowser.Model.Channels /// Gets or sets the identifier. /// /// The identifier. - public string Id { get; set; } + public Guid Id { get; set; } /// /// Gets or sets a value indicating whether this instance can search. diff --git a/MediaBrowser.Model/Channels/ChannelQuery.cs b/MediaBrowser.Model/Channels/ChannelQuery.cs index 59966127fb..f9380ce3a3 100644 --- a/MediaBrowser.Model/Channels/ChannelQuery.cs +++ b/MediaBrowser.Model/Channels/ChannelQuery.cs @@ -1,4 +1,3 @@ -#nullable disable #pragma warning disable CS1591 using System; @@ -13,13 +12,13 @@ namespace MediaBrowser.Model.Channels /// Gets or sets the fields to return within the items, in addition to basic information. /// /// The fields. - public ItemFields[] Fields { get; set; } + public ItemFields[]? Fields { get; set; } public bool? EnableImages { get; set; } public int? ImageTypeLimit { get; set; } - public ImageType[] EnableImageTypes { get; set; } + public ImageType[]? EnableImageTypes { get; set; } /// /// Gets or sets the user identifier. diff --git a/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs b/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs index b00d2fffb7..57759a7d39 100644 --- a/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs +++ b/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs @@ -1,4 +1,3 @@ -#nullable disable using System; using System.Xml.Serialization; @@ -35,21 +34,21 @@ namespace MediaBrowser.Model.Configuration /// Gets or sets the cache path. /// /// The cache path. - public string CachePath { get; set; } + public string? CachePath { get; set; } /// /// Gets or sets the last known version that was ran using the configuration. /// /// The version from previous run. [XmlIgnore] - public Version PreviousVersion { get; set; } + public Version? PreviousVersion { get; set; } /// /// Gets or sets the stringified PreviousVersion to be stored/loaded, /// because System.Version itself isn't xml-serializable. /// /// String value of PreviousVersion. - public string PreviousVersionStr + public string? PreviousVersionStr { get => PreviousVersion?.ToString(); set diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs index 24698360ec..aae5359b1d 100644 --- a/MediaBrowser.Model/Configuration/LibraryOptions.cs +++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs @@ -1,4 +1,3 @@ -#nullable disable #pragma warning disable CS1591 using System; @@ -52,21 +51,21 @@ namespace MediaBrowser.Model.Configuration /// Gets or sets the preferred metadata language. /// /// The preferred metadata language. - public string PreferredMetadataLanguage { get; set; } + public string? PreferredMetadataLanguage { get; set; } /// /// Gets or sets the metadata country code. /// /// The metadata country code. - public string MetadataCountryCode { get; set; } + public string? MetadataCountryCode { get; set; } public string SeasonZeroDisplayName { get; set; } - public string[] MetadataSavers { get; set; } + public string[]? MetadataSavers { get; set; } public string[] DisabledLocalMetadataReaders { get; set; } - public string[] LocalMetadataReaderOrder { get; set; } + public string[]? LocalMetadataReaderOrder { get; set; } public string[] DisabledSubtitleFetchers { get; set; } @@ -76,7 +75,7 @@ namespace MediaBrowser.Model.Configuration public bool SkipSubtitlesIfAudioTrackMatches { get; set; } - public string[] SubtitleDownloadLanguages { get; set; } + public string[]? SubtitleDownloadLanguages { get; set; } public bool RequirePerfectSubtitleMatch { get; set; } @@ -84,7 +83,7 @@ namespace MediaBrowser.Model.Configuration public TypeOptions[] TypeOptions { get; set; } - public TypeOptions GetTypeOptions(string type) + public TypeOptions? GetTypeOptions(string type) { foreach (var options in TypeOptions) { diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 935e6cbe10..81359462c3 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -1,4 +1,3 @@ -#nullable disable #pragma warning disable CS1591 using System; @@ -33,7 +32,7 @@ namespace MediaBrowser.Model.Configuration /// Gets or sets the audio language preference. /// /// The audio language preference. - public string AudioLanguagePreference { get; set; } + public string? AudioLanguagePreference { get; set; } /// /// Gets or sets a value indicating whether [play default audio track]. @@ -45,7 +44,7 @@ namespace MediaBrowser.Model.Configuration /// Gets or sets the subtitle language preference. /// /// The subtitle language preference. - public string SubtitleLanguagePreference { get; set; } + public string? SubtitleLanguagePreference { get; set; } public bool DisplayMissingEpisodes { get; set; } diff --git a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs index 8ad070dcbf..07129d7150 100644 --- a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs +++ b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs @@ -1,4 +1,3 @@ -#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Configuration @@ -13,7 +12,7 @@ namespace MediaBrowser.Model.Configuration EnablePathSubstitution = true; } - public string UserId { get; set; } + public string? UserId { get; set; } public string ReleaseDateFormat { get; set; } diff --git a/MediaBrowser.Model/Dlna/DeviceIdentification.cs b/MediaBrowser.Model/Dlna/DeviceIdentification.cs index c511801f4f..6625b79814 100644 --- a/MediaBrowser.Model/Dlna/DeviceIdentification.cs +++ b/MediaBrowser.Model/Dlna/DeviceIdentification.cs @@ -1,4 +1,3 @@ -#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Dlna/ITranscoderSupport.cs b/MediaBrowser.Model/Dlna/ITranscoderSupport.cs index d9bd094d9f..a70ce44cc6 100644 --- a/MediaBrowser.Model/Dlna/ITranscoderSupport.cs +++ b/MediaBrowser.Model/Dlna/ITranscoderSupport.cs @@ -1,4 +1,3 @@ -#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Dlna diff --git a/MediaBrowser.Model/Users/PinRedeemResult.cs b/MediaBrowser.Model/Users/PinRedeemResult.cs index 7e4553bac8..23fa631e86 100644 --- a/MediaBrowser.Model/Users/PinRedeemResult.cs +++ b/MediaBrowser.Model/Users/PinRedeemResult.cs @@ -1,6 +1,7 @@ -#nullable disable #pragma warning disable CS1591 +using System; + namespace MediaBrowser.Model.Users { public class PinRedeemResult @@ -15,6 +16,6 @@ namespace MediaBrowser.Model.Users /// Gets or sets the users reset. /// /// The users reset. - public string[] UsersReset { get; set; } + public string[] UsersReset { get; set; } = Array.Empty(); } } -- cgit v1.2.3 From 2410b3a3cfeff716740c0c6c15f1896a224771a9 Mon Sep 17 00:00:00 2001 From: Deathspike Date: Tue, 26 Oct 2021 20:51:35 +0200 Subject: Resolve subtitle selection feedback (#6446) --- Emby.Server.Implementations/Library/MediaStreamSelector.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index f94eeda8fc..b3837fedb4 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -50,7 +50,8 @@ namespace Emby.Server.Implementations.Library return null; } - var sortedStreams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages) + var sortedStreams = streams + .Where(i => i.Type == MediaStreamType.Subtitle) .OrderByDescending(x => x.IsExternal) .ThenByDescending(x => x.IsForced && string.Equals(x.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)) .ThenByDescending(x => x.IsForced) @@ -73,7 +74,8 @@ namespace Emby.Server.Implementations.Library // if the audio language is not understood by the user, load their preferred subs, if there are any if (!preferredLanguages.Contains(audioTrackLanguage, StringComparer.OrdinalIgnoreCase)) { - stream = sortedStreams.FirstOrDefault(s => preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); + stream = streams.FirstOrDefault(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)) ?? + streams.FirstOrDefault(s => preferredLanguages.Contains(s.Language, StringComparer.OrdinalIgnoreCase)); } } else if (mode == SubtitlePlaybackMode.Always) -- cgit v1.2.3 From a1b63aaa08ec318df7e3992e4cfc3e9fce5c8b48 Mon Sep 17 00:00:00 2001 From: Alan Azar Date: Mon, 25 Oct 2021 18:31:58 +0000 Subject: Translated using Weblate (Arabic) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/ --- Emby.Server.Implementations/Localization/Core/ar.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json index ee70aa8d86..f60d2fd016 100644 --- a/Emby.Server.Implementations/Localization/Core/ar.json +++ b/Emby.Server.Implementations/Localization/Core/ar.json @@ -33,7 +33,7 @@ "LabelRunningTimeValue": "المدة: {0}", "Latest": "الأحدث", "MessageApplicationUpdated": "لقد تم تحديث خادم Jellyfin", - "MessageApplicationUpdatedTo": "تم تحديث سيرفر Jellyfin الى {0}", + "MessageApplicationUpdatedTo": "تم تحديث خادم Jellyfin الى {0}", "MessageNamedServerConfigurationUpdatedWithValue": "تم تحديث إعدادات الخادم في قسم {0}", "MessageServerConfigurationUpdated": "تم تحديث إعدادات الخادم", "MixedContent": "محتوى مختلط", @@ -43,7 +43,7 @@ "NameInstallFailed": "فشل التثبيت {0}", "NameSeasonNumber": "الموسم {0}", "NameSeasonUnknown": "الموسم غير معروف", - "NewVersionIsAvailable": "نسخة جديدة من سيرفر Jellyfin متوفرة للتحميل.", + "NewVersionIsAvailable": "نسخة جديدة من خادم Jellyfin متوفرة للتحميل.", "NotificationOptionApplicationUpdateAvailable": "يوجد تحديث للتطبيق", "NotificationOptionApplicationUpdateInstalled": "تم تحديث التطبيق", "NotificationOptionAudioPlayback": "بدأ تشغيل المقطع الصوتي", @@ -55,7 +55,7 @@ "NotificationOptionPluginInstalled": "تم تثبيت الملحق", "NotificationOptionPluginUninstalled": "تمت إزالة الملحق", "NotificationOptionPluginUpdateInstalled": "تم تثبيت تحديثات الملحق", - "NotificationOptionServerRestartRequired": "يجب إعادة تشغيل السيرفر", + "NotificationOptionServerRestartRequired": "يجب إعادة تشغيل الخادم", "NotificationOptionTaskFailed": "فشل في المهمة المجدولة", "NotificationOptionUserLockedOut": "تم إقفال حساب المستخدم", "NotificationOptionVideoPlayback": "بدأ تشغيل الفيديو", @@ -72,7 +72,7 @@ "ServerNameNeedsToBeRestarted": "يحتاج لإعادة تشغيله {0}", "Shows": "الحلقات", "Songs": "الأغاني", - "StartupEmbyServerIsLoading": "سيرفر Jellyfin قيد التشغيل . الرجاء المحاولة بعد قليل.", + "StartupEmbyServerIsLoading": "خادم Jellyfin قيد التشغيل . الرجاء المحاولة بعد قليل.", "SubtitleDownloadFailureForItem": "عملية إنزال الترجمة فشلت لـ{0}", "SubtitleDownloadFailureFromForItem": "الترجمات فشلت في التحميل من {0} الى {1}", "Sync": "مزامنة", -- cgit v1.2.3 From 91655bb5fea6c711c66d3527aceee91edd9a4000 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Tue, 26 Oct 2021 11:54:25 +0000 Subject: Translated using Weblate (Esperanto) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eo/ --- Emby.Server.Implementations/Localization/Core/eo.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/eo.json b/Emby.Server.Implementations/Localization/Core/eo.json index 7ce87502cc..f92b5f6730 100644 --- a/Emby.Server.Implementations/Localization/Core/eo.json +++ b/Emby.Server.Implementations/Localization/Core/eo.json @@ -7,8 +7,8 @@ "NameInstallFailed": "{0} instalado fiaskis", "Music": "Muziko", "Movies": "Filmoj", - "ItemRemovedWithName": "{0} forigis el la libraro", - "ItemAddedWithName": "{0} aldonis al la libraro", + "ItemRemovedWithName": "{0} forigis el la plurmediteko", + "ItemAddedWithName": "{0} aldonis al la plurmediteko", "HeaderLiveTV": "TV-etero", "HeaderContinueWatching": "Daŭrigi Spektadon", "HeaderAlbumArtists": "Albumo de artisto", @@ -23,7 +23,7 @@ "Application": "Aplikaĵo", "AppDeviceValues": "Aplikaĵo: {0}, Aparato: {1}", "Albums": "Albumoj", - "TasksLibraryCategory": "Libraro", + "TasksLibraryCategory": "Plurmediteko", "VersionNumber": "Versio {0}", "UserDownloadingItemWithValues": "{0} elŝutas {1}", "UserCreatedWithName": "Uzanto {0} kreiĝis", @@ -50,7 +50,7 @@ "TvShows": "TV-serioj", "Favorites": "Favoratoj", "TaskCleanLogs": "Purigi Ĵurnalan Katalogon", - "TaskRefreshLibrary": "Skanu Plurmedian Libraron", + "TaskRefreshLibrary": "Skanu Plurmeditekon", "ValueSpecialEpisodeName": "Speciala - {0}", "TaskOptimizeDatabase": "Optimigi datumbazon", "TaskRefreshChannels": "Refreŝigi Kanalojn", @@ -75,17 +75,17 @@ "ServerNameNeedsToBeRestarted": "{0} devas esti relanĉita", "NotificationOptionVideoPlayback": "La videoludado lanĉis", "NotificationOptionServerRestartRequired": "Servila relanĉigo bezonata", - "TaskOptimizeDatabaseDescription": "Kompaktigas datenbazon kaj trunkas liberan lokon. Lanĉi ĉi tiun taskon post la librara skanado aŭ fari aliajn ŝanĝojn, kiuj implicas datenbazajn modifojn, povus plibonigi rendimenton.", + "TaskOptimizeDatabaseDescription": "Kompaktigas datenbazon kaj trunkas liberan lokon. Lanĉi ĉi tiun taskon post la teka skanado aŭ fari aliajn ŝanĝojn, kiuj implicas datenbazajn modifojn, povus plibonigi rendimenton.", "TaskUpdatePluginsDescription": "Elŝutas kaj instalas ĝisdatigojn por kromprogramojn, kiuj estas agorditaj por ĝisdatigi aŭtomate.", "TaskDownloadMissingSubtitlesDescription": "Serĉas en interreto mankantajn subtekstojn surbaze de metadatena agordaro.", - "TaskRefreshPeopleDescription": "Ĝisdatigas metadatenojn por aktoroj kaj reĵisoroj en via plurmedia libraro.", + "TaskRefreshPeopleDescription": "Ĝisdatigas metadatenojn por aktoroj kaj reĵisoroj en via plurmediteko.", "TaskCleanLogsDescription": "Forigas ĵurnalajn dosierojn aĝajn pli ol {0} tagojn.", - "TaskRefreshLibraryDescription": "Skanas vian plurmedian libraron por novaj dosieroj kaj refreŝigas metadatenaron.", + "TaskRefreshLibraryDescription": "Skanas vian plurmeditekon por novaj dosieroj kaj refreŝigas metadatenaron.", "NewVersionIsAvailable": "Nova versio de Jellyfin Server estas elŝutebla.", "TaskCleanCacheDescription": "Forigas stapla dosierojn ne plu necesajn de la sistemo.", "TaskCleanActivityLogDescription": "Forigas aktivecan ĵurnalaĵojn pli malnovajn ol la agordita aĝo.", "TaskCleanTranscodeDescription": "Forigas transkodajn dosierojn aĝajn pli ol unu tagon.", - "ValueHasBeenAddedToLibrary": "{0} estis aldonita al via plurmedia libraro", + "ValueHasBeenAddedToLibrary": "{0} estis aldonita al via plurmediteko", "SubtitleDownloadFailureFromForItem": "Subtekstoj malsukcesis elŝuti de {0} por {1}", "StartupEmbyServerIsLoading": "Jellyfin Server ŝarĝas. Provi denove baldaŭ.", "TaskRefreshChapterImagesDescription": "Kreas bildetojn por videoj kiuj havas ĉapitrojn.", -- cgit v1.2.3 From 4599ce659c75ffb6dcd21bdbff62cab1eb24c99c Mon Sep 17 00:00:00 2001 From: De sousa John Date: Mon, 25 Oct 2021 07:40:39 +0000 Subject: Translated using Weblate (French) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fr/ --- Emby.Server.Implementations/Localization/Core/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json index c3e52eb81a..1265b6ef58 100644 --- a/Emby.Server.Implementations/Localization/Core/fr.json +++ b/Emby.Server.Implementations/Localization/Core/fr.json @@ -1,7 +1,7 @@ { "Albums": "Albums", "AppDeviceValues": "Application : {0}, Appareil : {1}", - "Application": "Application", + "Application": "Applications", "Artists": "Artistes", "AuthenticationSucceededWithUserName": "{0} authentifié avec succès", "Books": "Livres", -- cgit v1.2.3 From fc2e826b4de1582f2ae2d453bdc6d71262c72d67 Mon Sep 17 00:00:00 2001 From: Alan Azar Date: Wed, 27 Oct 2021 15:21:02 +0000 Subject: Translated using Weblate (Arabic) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/ --- Emby.Server.Implementations/Localization/Core/ar.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json index f60d2fd016..99220cca97 100644 --- a/Emby.Server.Implementations/Localization/Core/ar.json +++ b/Emby.Server.Implementations/Localization/Core/ar.json @@ -16,7 +16,7 @@ "Folders": "المجلدات", "Genres": "التضنيفات", "HeaderAlbumArtists": "ألبوم الفنان", - "HeaderContinueWatching": "استئناف", + "HeaderContinueWatching": "استمر بالمشاهدة", "HeaderFavoriteAlbums": "الألبومات المفضلة", "HeaderFavoriteArtists": "الفنانون المفضلون", "HeaderFavoriteEpisodes": "الحلقات المفضلة", -- cgit v1.2.3 From 17973964faed0958190817484bba1603dd8ad51d Mon Sep 17 00:00:00 2001 From: Kenneth SB Date: Wed, 27 Oct 2021 16:49:49 +0000 Subject: Translated using Weblate (Danish) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/da/ --- Emby.Server.Implementations/Localization/Core/da.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json index b2c484a31e..cfe365f57a 100644 --- a/Emby.Server.Implementations/Localization/Core/da.json +++ b/Emby.Server.Implementations/Localization/Core/da.json @@ -15,7 +15,7 @@ "Favorites": "Favoritter", "Folders": "Mapper", "Genres": "Genrer", - "HeaderAlbumArtists": "Albumkunstnere", + "HeaderAlbumArtists": "Kunstnerens album", "HeaderContinueWatching": "Fortsæt Afspilning", "HeaderFavoriteAlbums": "Favoritalbummer", "HeaderFavoriteArtists": "Favoritkunstnere", -- cgit v1.2.3 From 5a7433472ef88c7e8e52840425a7296e242155ee Mon Sep 17 00:00:00 2001 From: Alan Azar Date: Fri, 29 Oct 2021 04:42:23 +0000 Subject: Translated using Weblate (Arabic) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/ --- Emby.Server.Implementations/Localization/Core/ar.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json index 99220cca97..a83a453b4c 100644 --- a/Emby.Server.Implementations/Localization/Core/ar.json +++ b/Emby.Server.Implementations/Localization/Core/ar.json @@ -12,7 +12,7 @@ "DeviceOfflineWithName": "قُطِع الاتصال ب{0}", "DeviceOnlineWithName": "{0} متصل", "FailedLoginAttemptWithUserName": "عملية تسجيل الدخول فشلت من {0}", - "Favorites": "المفضلة", + "Favorites": "مفضلات", "Folders": "المجلدات", "Genres": "التضنيفات", "HeaderAlbumArtists": "ألبوم الفنان", -- cgit v1.2.3 From a22c57ff3323c3e06ffdd828f887ee37933e8ece Mon Sep 17 00:00:00 2001 From: Pedro Almeida Date: Sun, 31 Oct 2021 15:13:23 +0000 Subject: Fix localization typo with Réunion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Emby.Server.Implementations/Localization/countries.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/countries.json b/Emby.Server.Implementations/Localization/countries.json index b08a3ae798..22ffc5e097 100644 --- a/Emby.Server.Implementations/Localization/countries.json +++ b/Emby.Server.Implementations/Localization/countries.json @@ -630,7 +630,7 @@ "TwoLetterISORegionName": "MD" }, { - "DisplayName": "Réunion", + "DisplayName": "Réunion", "Name": "RE", "ThreeLetterISORegionName": "REU", "TwoLetterISORegionName": "RE" -- cgit v1.2.3 From 10a173c01164304449787f275df5b70d58b4debd Mon Sep 17 00:00:00 2001 From: Pedro Almeida Date: Sun, 31 Oct 2021 15:28:51 +0000 Subject: Add pt-pt as culture Makes pt-pt selectable as metadata language --- Emby.Server.Implementations/Localization/iso6392.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/iso6392.txt b/Emby.Server.Implementations/Localization/iso6392.txt index 488901822d..66fba33304 100644 --- a/Emby.Server.Implementations/Localization/iso6392.txt +++ b/Emby.Server.Implementations/Localization/iso6392.txt @@ -349,7 +349,8 @@ pli||pi|Pali|pali pol||pl|Polish|polonais pon|||Pohnpeian|pohnpei por||pt|Portuguese|portugais -pob||pt-br|Portuguese (Brazil)|portugais +pop||pt-pt|Portuguese (Portugal)|portugais (pt-pt) +pob||pt-br|Portuguese (Brazil)|portugais (pt-br) pra|||Prakrit languages|prâkrit, langues pro|||Provençal, Old (to 1500)|provençal ancien (jusqu'à 1500) pus||ps|Pushto; Pashto|pachto -- cgit v1.2.3 From a229526454750de978397571b0b19426f195dd3d Mon Sep 17 00:00:00 2001 From: WWWesten <4700006+WWWesten@users.noreply.github.com> Date: Mon, 1 Nov 2021 23:47:31 +0500 Subject: Update LocalizationManager.cs --- .../Localization/LocalizationManager.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 03919197e2..a5a530a565 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -372,9 +372,11 @@ namespace Emby.Server.Implementations.Localization /// public IEnumerable GetLocalizationOptions() { - yield return new LocalizationOption("Arabic", "ar"); + yield return new LocalizationOption("Afrikaans", "af"); + yield return new LocalizationOption("Arabic", "ar"); yield return new LocalizationOption("Bulgarian (Bulgaria)", "bg-BG"); yield return new LocalizationOption("Catalan", "ca"); + yield return new LocalizationOption("Chinese (Hong Kong)", "zh-HK"); yield return new LocalizationOption("Chinese Simplified", "zh-CN"); yield return new LocalizationOption("Chinese Traditional", "zh-TW"); yield return new LocalizationOption("Croatian", "hr"); @@ -383,32 +385,48 @@ namespace Emby.Server.Implementations.Localization yield return new LocalizationOption("Dutch", "nl"); yield return new LocalizationOption("English (United Kingdom)", "en-GB"); yield return new LocalizationOption("English (United States)", "en-US"); + yield return new LocalizationOption("Esperanto", "eo"); + yield return new LocalizationOption("Estonian", "et"); + yield return new LocalizationOption("Finnish", "fi"); yield return new LocalizationOption("French", "fr"); yield return new LocalizationOption("French (Canada)", "fr-CA"); yield return new LocalizationOption("German", "de"); yield return new LocalizationOption("Greek", "el"); yield return new LocalizationOption("Hebrew", "he"); yield return new LocalizationOption("Hungarian", "hu"); + yield return new LocalizationOption("Icelandic", "is"); + yield return new LocalizationOption("Indonesian", "id"); yield return new LocalizationOption("Italian", "it"); + yield return new LocalizationOption("Japanese", "ja"); yield return new LocalizationOption("Kazakh", "kk"); yield return new LocalizationOption("Korean", "ko"); + yield return new LocalizationOption("Latvian", "lv"); yield return new LocalizationOption("Lithuanian", "lt-LT"); yield return new LocalizationOption("Malay", "ms"); + yield return new LocalizationOption("Malayalam", "ml"); yield return new LocalizationOption("Norwegian Bokmål", "nb"); + yield return new LocalizationOption("Norwegian Nynorsk", "nn"); yield return new LocalizationOption("Persian", "fa"); yield return new LocalizationOption("Polish", "pl"); + yield return new LocalizationOption("Portuguese", "pt"); yield return new LocalizationOption("Portuguese (Brazil)", "pt-BR"); yield return new LocalizationOption("Portuguese (Portugal)", "pt-PT"); + yield return new LocalizationOption("Romanian", "ro"); yield return new LocalizationOption("Russian", "ru"); + yield return new LocalizationOption("Serbian", "sr"); yield return new LocalizationOption("Slovak", "sk"); yield return new LocalizationOption("Slovenian (Slovenia)", "sl-SI"); yield return new LocalizationOption("Spanish", "es"); yield return new LocalizationOption("Spanish (Argentina)", "es-AR"); + yield return new LocalizationOption("Spanish (Latin America)", "es-419"); yield return new LocalizationOption("Spanish (Mexico)", "es-MX"); yield return new LocalizationOption("Swedish", "sv"); yield return new LocalizationOption("Swiss German", "gsw"); + yield return new LocalizationOption("Tamil", "ta"); + yield return new LocalizationOption("Telugu", "te"); yield return new LocalizationOption("Turkish", "tr"); yield return new LocalizationOption("Tiếng Việt", "vi"); + yield return new LocalizationOption("Ukrainian", "uk"); } } } -- cgit v1.2.3 From 967fd66ca9b416bb8ca0796304ab912a45f3dd1d Mon Sep 17 00:00:00 2001 From: WWWesten <4700006+WWWesten@users.noreply.github.com> Date: Tue, 2 Nov 2021 00:22:16 +0500 Subject: Update LocalizationManager.cs --- .../Localization/LocalizationManager.cs | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index a5a530a565..1524fcdb2b 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -372,11 +372,11 @@ namespace Emby.Server.Implementations.Localization /// public IEnumerable GetLocalizationOptions() { - yield return new LocalizationOption("Afrikaans", "af"); - yield return new LocalizationOption("Arabic", "ar"); + yield return new LocalizationOption("Afrikaans", "af"); + yield return new LocalizationOption("Arabic", "ar"); yield return new LocalizationOption("Bulgarian (Bulgaria)", "bg-BG"); yield return new LocalizationOption("Catalan", "ca"); - yield return new LocalizationOption("Chinese (Hong Kong)", "zh-HK"); + yield return new LocalizationOption("Chinese (Hong Kong)", "zh-HK"); yield return new LocalizationOption("Chinese Simplified", "zh-CN"); yield return new LocalizationOption("Chinese Traditional", "zh-TW"); yield return new LocalizationOption("Croatian", "hr"); @@ -385,48 +385,48 @@ namespace Emby.Server.Implementations.Localization yield return new LocalizationOption("Dutch", "nl"); yield return new LocalizationOption("English (United Kingdom)", "en-GB"); yield return new LocalizationOption("English (United States)", "en-US"); - yield return new LocalizationOption("Esperanto", "eo"); - yield return new LocalizationOption("Estonian", "et"); - yield return new LocalizationOption("Finnish", "fi"); + yield return new LocalizationOption("Esperanto", "eo"); + yield return new LocalizationOption("Estonian", "et"); + yield return new LocalizationOption("Finnish", "fi"); yield return new LocalizationOption("French", "fr"); yield return new LocalizationOption("French (Canada)", "fr-CA"); yield return new LocalizationOption("German", "de"); yield return new LocalizationOption("Greek", "el"); yield return new LocalizationOption("Hebrew", "he"); yield return new LocalizationOption("Hungarian", "hu"); - yield return new LocalizationOption("Icelandic", "is"); - yield return new LocalizationOption("Indonesian", "id"); + yield return new LocalizationOption("Icelandic", "is"); + yield return new LocalizationOption("Indonesian", "id"); yield return new LocalizationOption("Italian", "it"); - yield return new LocalizationOption("Japanese", "ja"); + yield return new LocalizationOption("Japanese", "ja"); yield return new LocalizationOption("Kazakh", "kk"); yield return new LocalizationOption("Korean", "ko"); - yield return new LocalizationOption("Latvian", "lv"); + yield return new LocalizationOption("Latvian", "lv"); yield return new LocalizationOption("Lithuanian", "lt-LT"); yield return new LocalizationOption("Malay", "ms"); - yield return new LocalizationOption("Malayalam", "ml"); + yield return new LocalizationOption("Malayalam", "ml"); yield return new LocalizationOption("Norwegian Bokmål", "nb"); - yield return new LocalizationOption("Norwegian Nynorsk", "nn"); + yield return new LocalizationOption("Norwegian Nynorsk", "nn"); yield return new LocalizationOption("Persian", "fa"); yield return new LocalizationOption("Polish", "pl"); - yield return new LocalizationOption("Portuguese", "pt"); + yield return new LocalizationOption("Portuguese", "pt"); yield return new LocalizationOption("Portuguese (Brazil)", "pt-BR"); yield return new LocalizationOption("Portuguese (Portugal)", "pt-PT"); - yield return new LocalizationOption("Romanian", "ro"); + yield return new LocalizationOption("Romanian", "ro"); yield return new LocalizationOption("Russian", "ru"); - yield return new LocalizationOption("Serbian", "sr"); + yield return new LocalizationOption("Serbian", "sr"); yield return new LocalizationOption("Slovak", "sk"); yield return new LocalizationOption("Slovenian (Slovenia)", "sl-SI"); yield return new LocalizationOption("Spanish", "es"); yield return new LocalizationOption("Spanish (Argentina)", "es-AR"); - yield return new LocalizationOption("Spanish (Latin America)", "es-419"); + yield return new LocalizationOption("Spanish (Latin America)", "es-419"); yield return new LocalizationOption("Spanish (Mexico)", "es-MX"); yield return new LocalizationOption("Swedish", "sv"); yield return new LocalizationOption("Swiss German", "gsw"); - yield return new LocalizationOption("Tamil", "ta"); - yield return new LocalizationOption("Telugu", "te"); + yield return new LocalizationOption("Tamil", "ta"); + yield return new LocalizationOption("Telugu", "te"); yield return new LocalizationOption("Turkish", "tr"); yield return new LocalizationOption("Tiếng Việt", "vi"); - yield return new LocalizationOption("Ukrainian", "uk"); + yield return new LocalizationOption("Ukrainian", "uk"); } } } -- cgit v1.2.3 From 5529625025f53b6397c500d8cce2b3c5be28e63c Mon Sep 17 00:00:00 2001 From: Pedro Almeida Date: Mon, 1 Nov 2021 15:38:14 +0000 Subject: Translated using Weblate (Portuguese (Portugal)) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_PT/ --- Emby.Server.Implementations/Localization/Core/pt-PT.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/pt-PT.json b/Emby.Server.Implementations/Localization/Core/pt-PT.json index 8c41edf963..525a02c883 100644 --- a/Emby.Server.Implementations/Localization/Core/pt-PT.json +++ b/Emby.Server.Implementations/Localization/Core/pt-PT.json @@ -39,7 +39,7 @@ "MixedContent": "Conteúdo Misto", "Movies": "Filmes", "Music": "Música", - "MusicVideos": "Videoclips", + "MusicVideos": "Videoclipes", "NameInstallFailed": "{0} falha na instalação", "NameSeasonNumber": "Temporada {0}", "NameSeasonUnknown": "Temporada Desconhecida", @@ -118,5 +118,7 @@ "TaskCleanActivityLog": "Limpar registo de atividade", "Undefined": "Indefinido", "Forced": "Forçado", - "Default": "Padrão" + "Default": "Padrão", + "TaskOptimizeDatabaseDescription": "Base de dados compacta e corta espaço livre. A execução desta tarefa depois de digitalizar a biblioteca ou de fazer outras alterações que impliquem modificações na base de dados pode melhorar o desempenho.", + "TaskOptimizeDatabase": "Otimizar base de dados" } -- cgit v1.2.3 From 104e36f2f9c6440a7547a4c76d80a69d5af84eea Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 2 Nov 2021 16:02:52 +0100 Subject: Streamline startup code --- Emby.Server.Implementations/ApplicationHost.cs | 150 ++++++++++----------- Jellyfin.Server/CoreAppHost.cs | 49 +++---- Jellyfin.Server/Program.cs | 41 +++--- MediaBrowser.Common/IApplicationHost.cs | 4 +- .../JellyfinApplicationFactory.cs | 10 +- .../TestAppHost.cs | 12 +- 6 files changed, 123 insertions(+), 143 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 6fd152a42d..512700ac24 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -147,25 +147,20 @@ namespace Emby.Server.Implementations /// Instance of the interface. /// Instance of the interface. /// The interface. - /// Instance of the interface. - /// Instance of the interface. public ApplicationHost( IServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, IStartupOptions options, - IConfiguration startupConfig, - IFileSystem fileSystem, - IServiceCollection serviceCollection) + IConfiguration startupConfig) { ApplicationPaths = applicationPaths; LoggerFactory = loggerFactory; _startupOptions = options; _startupConfig = startupConfig; - _fileSystemManager = fileSystem; - ServiceCollection = serviceCollection; + _fileSystemManager = new ManagedFileSystem(LoggerFactory.CreateLogger(), applicationPaths); Logger = LoggerFactory.CreateLogger(); - fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem)); + _fileSystemManager.AddShortcutHandler(new MbLinkShortcutHandler(_fileSystemManager)); ApplicationVersion = typeof(ApplicationHost).Assembly.GetName().Version; ApplicationVersionString = ApplicationVersion.ToString(3); @@ -230,8 +225,6 @@ namespace Emby.Server.Implementations /// protected ILogger Logger { get; } - protected IServiceCollection ServiceCollection { get; } - /// /// Gets the logger factory. /// @@ -521,7 +514,7 @@ namespace Emby.Server.Implementations } /// - public void Init() + public void Init(IServiceCollection serviceCollection) { DiscoverTypes(); @@ -551,128 +544,129 @@ namespace Emby.Server.Implementations CertificatePath = networkConfiguration.CertificatePath; Certificate = GetCertificate(CertificatePath, networkConfiguration.CertificatePassword); - RegisterServices(); + RegisterServices(serviceCollection); - _pluginManager.RegisterServices(ServiceCollection); + _pluginManager.RegisterServices(serviceCollection); } /// /// Registers services/resources with the service collection that will be available via DI. /// - protected virtual void RegisterServices() + /// Instance of the interface. + protected virtual void RegisterServices(IServiceCollection serviceCollection) { - ServiceCollection.AddSingleton(_startupOptions); + serviceCollection.AddSingleton(_startupOptions); - ServiceCollection.AddMemoryCache(); + serviceCollection.AddMemoryCache(); - ServiceCollection.AddSingleton(ConfigurationManager); - ServiceCollection.AddSingleton(ConfigurationManager); - ServiceCollection.AddSingleton(this); - ServiceCollection.AddSingleton(_pluginManager); - ServiceCollection.AddSingleton(ApplicationPaths); + serviceCollection.AddSingleton(ConfigurationManager); + serviceCollection.AddSingleton(ConfigurationManager); + serviceCollection.AddSingleton(this); + serviceCollection.AddSingleton(_pluginManager); + serviceCollection.AddSingleton(ApplicationPaths); - ServiceCollection.AddSingleton(_fileSystemManager); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(_fileSystemManager); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(NetManager); + serviceCollection.AddSingleton(NetManager); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(_xmlSerializer); + serviceCollection.AddSingleton(_xmlSerializer); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(this); - ServiceCollection.AddSingleton(ApplicationPaths); + serviceCollection.AddSingleton(this); + serviceCollection.AddSingleton(ApplicationPaths); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); // TODO: Refactor to eliminate the circular dependencies here so that Lazy isn't required - ServiceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); - ServiceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); - ServiceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); - ServiceCollection.AddSingleton(); + serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); + serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); + serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); // TODO: Refactor to eliminate the circular dependency here so that Lazy isn't required - ServiceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); - ServiceCollection.AddSingleton(); + serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddScoped(); + serviceCollection.AddScoped(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddScoped(); - ServiceCollection.AddScoped(); - ServiceCollection.AddScoped(); + serviceCollection.AddSingleton(); + serviceCollection.AddScoped(); + serviceCollection.AddScoped(); + serviceCollection.AddScoped(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); } /// diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 21bd9ba011..67e50b92d9 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -22,7 +22,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Activity; -using MediaBrowser.Model.IO; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -42,67 +41,61 @@ namespace Jellyfin.Server /// The to be used by the . /// The to be used by the . /// The to be used by the . - /// The to be used by the . - /// The to be used by the . public CoreAppHost( IServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, IStartupOptions options, - IConfiguration startupConfig, - IFileSystem fileSystem, - IServiceCollection collection) + IConfiguration startupConfig) : base( applicationPaths, loggerFactory, options, - startupConfig, - fileSystem, - collection) + startupConfig) { } /// - protected override void RegisterServices() + protected override void RegisterServices(IServiceCollection serviceCollection) { // Register an image encoder bool useSkiaEncoder = SkiaEncoder.IsNativeLibAvailable(); Type imageEncoderType = useSkiaEncoder ? typeof(SkiaEncoder) : typeof(NullImageEncoder); - ServiceCollection.AddSingleton(typeof(IImageEncoder), imageEncoderType); + serviceCollection.AddSingleton(typeof(IImageEncoder), imageEncoderType); // Log a warning if the Skia encoder could not be used if (!useSkiaEncoder) { - Logger.LogWarning($"Skia not available. Will fallback to {nameof(NullImageEncoder)}."); + Logger.LogWarning("Skia not available. Will fallback to {ImageEncoder}.", nameof(NullImageEncoder)); } - ServiceCollection.AddDbContextPool( + serviceCollection.AddDbContextPool( options => options .UseLoggerFactory(LoggerFactory) .UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}")); - ServiceCollection.AddEventServices(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddEventServices(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); // TODO search the assemblies instead of adding them manually? - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddSingleton(); + serviceCollection.AddSingleton(); - ServiceCollection.AddScoped(); + serviceCollection.AddScoped(); - base.RegisterServices(); + base.RegisterServices(serviceCollection); } /// diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 45699f3aff..5f848be9e1 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -10,7 +10,6 @@ using System.Threading; using System.Threading.Tasks; using CommandLine; using Emby.Server.Implementations; -using Emby.Server.Implementations.IO; using Jellyfin.Server.Implementations; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; @@ -157,34 +156,36 @@ namespace Jellyfin.Server ApplicationHost.LogEnvironmentInfo(_logger, appPaths); + // If hosting the web client, validate the client content path + if (startupConfig.HostWebClient()) + { + string? webContentPath = appPaths.WebPath; + if (!Directory.Exists(webContentPath) || !Directory.EnumerateFiles(webContentPath).Any()) + { + _logger.LogError( + "The server is expected to host the web client, but the provided content directory is either " + + "invalid or empty: {WebContentPath}. If you do not want to host the web client with the " + + "server, you may set the '--nowebclient' command line flag, or set" + + "'{ConfigKey}=false' in your config settings.", + webContentPath, + ConfigurationExtensions.HostWebClientKey); + Environment.ExitCode = 1; + return; + } + } + PerformStaticInitialization(); - var serviceCollection = new ServiceCollection(); var appHost = new CoreAppHost( appPaths, _loggerFactory, options, - startupConfig, - new ManagedFileSystem(_loggerFactory.CreateLogger(), appPaths), - serviceCollection); + startupConfig); try { - // If hosting the web client, validate the client content path - if (startupConfig.HostWebClient()) - { - string? webContentPath = appHost.ConfigurationManager.ApplicationPaths.WebPath; - if (!Directory.Exists(webContentPath) || Directory.GetFiles(webContentPath).Length == 0) - { - throw new InvalidOperationException( - "The server is expected to host the web client, but the provided content directory is either " + - $"invalid or empty: {webContentPath}. If you do not want to host the web client with the " + - "server, you may set the '--nowebclient' command line flag, or set" + - $"'{ConfigurationExtensions.HostWebClientKey}=false' in your config settings."); - } - } - - appHost.Init(); + var serviceCollection = new ServiceCollection(); + appHost.Init(serviceCollection); var webHost = new WebHostBuilder().ConfigureWebHostBuilder(appHost, serviceCollection, options, startupConfig, appPaths).Build(); diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index 192a776115..e49ab41f4f 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Reflection; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; namespace MediaBrowser.Common { @@ -137,7 +138,8 @@ namespace MediaBrowser.Common /// /// Initializes this instance. /// - void Init(); + /// Instance of the interface. + void Init(IServiceCollection serviceCollection); /// /// Creates the instance. diff --git a/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs b/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs index 976e19d468..3d34a18e7f 100644 --- a/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs +++ b/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs @@ -3,7 +3,6 @@ using System.Collections.Concurrent; using System.IO; using System.Threading; using Emby.Server.Implementations; -using Emby.Server.Implementations.IO; using MediaBrowser.Common; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; @@ -67,7 +66,7 @@ namespace Jellyfin.Server.Integration.Tests var startupConfig = Program.CreateAppConfiguration(commandLineOpts, appPaths); ILoggerFactory loggerFactory = new SerilogLoggerFactory(); - var serviceCollection = new ServiceCollection(); + _disposableComponents.Add(loggerFactory); // Create the app host and initialize it @@ -75,11 +74,10 @@ namespace Jellyfin.Server.Integration.Tests appPaths, loggerFactory, commandLineOpts, - new ConfigurationBuilder().Build(), - new ManagedFileSystem(loggerFactory.CreateLogger(), appPaths), - serviceCollection); + new ConfigurationBuilder().Build()); _disposableComponents.Add(appHost); - appHost.Init(); + var serviceCollection = new ServiceCollection(); + appHost.Init(serviceCollection); // Configure the web host builder Program.ConfigureWebHostBuilder(builder, appHost, serviceCollection, commandLineOpts, startupConfig, appPaths); diff --git a/tests/Jellyfin.Server.Integration.Tests/TestAppHost.cs b/tests/Jellyfin.Server.Integration.Tests/TestAppHost.cs index 0a463cfa39..bf74efa09e 100644 --- a/tests/Jellyfin.Server.Integration.Tests/TestAppHost.cs +++ b/tests/Jellyfin.Server.Integration.Tests/TestAppHost.cs @@ -2,9 +2,7 @@ using System.Collections.Generic; using System.Reflection; using Emby.Server.Implementations; using MediaBrowser.Controller; -using MediaBrowser.Model.IO; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace Jellyfin.Server.Integration.Tests @@ -21,22 +19,16 @@ namespace Jellyfin.Server.Integration.Tests /// The to be used by the . /// The to be used by the . /// The to be used by the . - /// The to be used by the . - /// The to be used by the . public TestAppHost( IServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, IStartupOptions options, - IConfiguration startup, - IFileSystem fileSystem, - IServiceCollection collection) + IConfiguration startup) : base( applicationPaths, loggerFactory, options, - startup, - fileSystem, - collection) + startup) { } -- cgit v1.2.3 From 70b9f9bf560e4f9ff47ecb00c22561e3065a20de Mon Sep 17 00:00:00 2001 From: nextlooper42 Date: Tue, 2 Nov 2021 22:26:20 +0000 Subject: Translated using Weblate (Slovak) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sk/ --- Emby.Server.Implementations/Localization/Core/sk.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/sk.json b/Emby.Server.Implementations/Localization/Core/sk.json index ad90bd8134..37da7d5ab3 100644 --- a/Emby.Server.Implementations/Localization/Core/sk.json +++ b/Emby.Server.Implementations/Localization/Core/sk.json @@ -39,7 +39,7 @@ "MixedContent": "Zmiešaný obsah", "Movies": "Filmy", "Music": "Hudba", - "MusicVideos": "Hudobné videá", + "MusicVideos": "Hudobné videoklipy", "NameInstallFailed": "Inštalácia {0} zlyhala", "NameSeasonNumber": "Séria {0}", "NameSeasonUnknown": "Neznáma séria", -- cgit v1.2.3 From 654bd6fff141fb53661e2a99fc6a48478c92e8dd Mon Sep 17 00:00:00 2001 From: WWWesten Date: Thu, 4 Nov 2021 08:18:21 +0000 Subject: Translated using Weblate (Turkish) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/tr/ --- Emby.Server.Implementations/Localization/Core/tr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/tr.json b/Emby.Server.Implementations/Localization/Core/tr.json index e661299c41..8fadb88ac8 100644 --- a/Emby.Server.Implementations/Localization/Core/tr.json +++ b/Emby.Server.Implementations/Localization/Core/tr.json @@ -8,7 +8,7 @@ "CameraImageUploadedFrom": "{0} 'den yeni bir kamera resmi yüklendi", "Channels": "Kanallar", "ChapterNameValue": "Bölüm {0}", - "Collections": "Koleksiyon", + "Collections": "Koleksiyonlar", "DeviceOfflineWithName": "{0} bağlantısı kesildi", "DeviceOnlineWithName": "{0} bağlı", "FailedLoginAttemptWithUserName": "{0} adresinden giriş başarısız oldu", -- cgit v1.2.3 From 5aadf8c291df8a9f9a3bb6d4407979fc456ab6d4 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Wed, 3 Nov 2021 06:33:55 +0000 Subject: Translated using Weblate (Esperanto) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eo/ --- Emby.Server.Implementations/Localization/Core/eo.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/eo.json b/Emby.Server.Implementations/Localization/Core/eo.json index f92b5f6730..8ac466908c 100644 --- a/Emby.Server.Implementations/Localization/Core/eo.json +++ b/Emby.Server.Implementations/Localization/Core/eo.json @@ -1,5 +1,5 @@ { - "NotificationOptionInstallationFailed": "Instalada fiasko", + "NotificationOptionInstallationFailed": "Instalada malsukceso", "NotificationOptionAudioPlaybackStopped": "Ludado de sono haltis", "NotificationOptionAudioPlayback": "Ludado de sono lanĉis", "NameSeasonUnknown": "Sezono Nekonata", @@ -48,17 +48,17 @@ "Shows": "Serioj", "HeaderFavoriteShows": "Favorataj Serioj", "TvShows": "TV-serioj", - "Favorites": "Favoratoj", + "Favorites": "Favorataj", "TaskCleanLogs": "Purigi Ĵurnalan Katalogon", - "TaskRefreshLibrary": "Skanu Plurmeditekon", + "TaskRefreshLibrary": "Skani Plurmeditekon", "ValueSpecialEpisodeName": "Speciala - {0}", - "TaskOptimizeDatabase": "Optimigi datumbazon", + "TaskOptimizeDatabase": "Optimigi datenbazon", "TaskRefreshChannels": "Refreŝigi Kanalojn", "TaskUpdatePlugins": "Ĝisdatigi Kromprogramojn", "TaskRefreshPeople": "Refreŝigi Homojn", "TasksChannelsCategory": "Interretaj Kanaloj", "ProviderValue": "Provizanto: {0}", - "NotificationOptionPluginError": "Kromprograma malsukceso", + "NotificationOptionPluginError": "Kromprogramo malsukcesis", "MixedContent": "Miksita enhavo", "TasksApplicationCategory": "Aplikaĵo", "TasksMaintenanceCategory": "Prizorgado", @@ -102,9 +102,9 @@ "MessageApplicationUpdatedTo": "Jellyfin Server estis ĝisdatigita al {0}", "MessageApplicationUpdated": "Jellyfin Server estis ĝisdatigita", "TaskRefreshChannelsDescription": "Refreŝigas informon pri interretaj kanaloj.", - "TaskDownloadMissingSubtitles": "Elŝutu mankantajn subtekstojn", + "TaskDownloadMissingSubtitles": "Elŝuti mankantajn subtekstojn", "TaskCleanTranscode": "Malplenigi Transkodadan Katalogon", - "TaskRefreshChapterImages": "Eltiru Ĉapitro-Bildojn", + "TaskRefreshChapterImages": "Eltiri Ĉapitraj Bildojn", "TaskCleanCache": "Malplenigi Staplan Katalogon", "TaskCleanActivityLog": "Malplenigi Aktivecan Ĵurnalon", "PluginUpdatedWithName": "{0} estis ĝisdatigita", -- cgit v1.2.3 From 13668a6ecb40b4b68f1cfaebfb7bb3807e9a9cef Mon Sep 17 00:00:00 2001 From: WWWesten Date: Thu, 4 Nov 2021 10:35:48 +0000 Subject: Translated using Weblate (Russian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ru/ --- Emby.Server.Implementations/Localization/Core/ru.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/ru.json b/Emby.Server.Implementations/Localization/Core/ru.json index cd016b51b4..36f4e3e7c9 100644 --- a/Emby.Server.Implementations/Localization/Core/ru.json +++ b/Emby.Server.Implementations/Localization/Core/ru.json @@ -119,6 +119,6 @@ "Undefined": "Не определено", "Forced": "Форсир-ые", "Default": "По умолчанию", - "TaskOptimizeDatabaseDescription": "Сжимает базу данных и обрезает свободное место. Выполнение этой задачи после сканирования библиотеки или внесения других изменений, предполагающих модификации базы данных, может повысить производительность.", + "TaskOptimizeDatabaseDescription": "Сжимает базу данных и вырезает свободные места. Выполнение этой задачи после сканирования библиотеки или внесения других изменений, предполагающих модификации базы данных, может повысить производительность.", "TaskOptimizeDatabase": "Оптимизировать базу данных" } -- cgit v1.2.3 From 1e93c6ae3052653efbadba29657f83c660b35941 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Thu, 4 Nov 2021 10:32:21 +0000 Subject: Translated using Weblate (Esperanto) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eo/ --- Emby.Server.Implementations/Localization/Core/eo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/eo.json b/Emby.Server.Implementations/Localization/Core/eo.json index 8ac466908c..12541a756a 100644 --- a/Emby.Server.Implementations/Localization/Core/eo.json +++ b/Emby.Server.Implementations/Localization/Core/eo.json @@ -52,7 +52,7 @@ "TaskCleanLogs": "Purigi Ĵurnalan Katalogon", "TaskRefreshLibrary": "Skani Plurmeditekon", "ValueSpecialEpisodeName": "Speciala - {0}", - "TaskOptimizeDatabase": "Optimigi datenbazon", + "TaskOptimizeDatabase": "Optimumigi datenbazon", "TaskRefreshChannels": "Refreŝigi Kanalojn", "TaskUpdatePlugins": "Ĝisdatigi Kromprogramojn", "TaskRefreshPeople": "Refreŝigi Homojn", @@ -75,7 +75,7 @@ "ServerNameNeedsToBeRestarted": "{0} devas esti relanĉita", "NotificationOptionVideoPlayback": "La videoludado lanĉis", "NotificationOptionServerRestartRequired": "Servila relanĉigo bezonata", - "TaskOptimizeDatabaseDescription": "Kompaktigas datenbazon kaj trunkas liberan lokon. Lanĉi ĉi tiun taskon post la teka skanado aŭ fari aliajn ŝanĝojn, kiuj implicas datenbazajn modifojn, povus plibonigi rendimenton.", + "TaskOptimizeDatabaseDescription": "Kompaktigas datenbazon kaj trunkas liberan lokon. Lanĉi ĉi tiun taskon post la plurmediteka skanado aŭ fari aliajn ŝanĝojn, kiuj implicas datenbazajn modifojn, povus plibonigi rendimenton.", "TaskUpdatePluginsDescription": "Elŝutas kaj instalas ĝisdatigojn por kromprogramojn, kiuj estas agorditaj por ĝisdatigi aŭtomate.", "TaskDownloadMissingSubtitlesDescription": "Serĉas en interreto mankantajn subtekstojn surbaze de metadatena agordaro.", "TaskRefreshPeopleDescription": "Ĝisdatigas metadatenojn por aktoroj kaj reĵisoroj en via plurmediteko.", -- cgit v1.2.3 From b4bf5af7c8b169c616ca5a9bc83248a80636bedb Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Fri, 5 Nov 2021 21:31:12 +0100 Subject: Remove ImageType.Screenshot and ItemFields.Screenshot --- Emby.Server.Implementations/Dto/DtoService.cs | 9 -------- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- MediaBrowser.Model/Entities/ImageType.cs | 3 +++ MediaBrowser.Model/Querying/ItemFields.cs | 3 +++ MediaBrowser.Providers/Manager/ImageSaver.cs | 3 --- .../Manager/ItemImageProvider.cs | 26 +++------------------- .../Manager/ItemImageProviderTests.cs | 2 -- 7 files changed, 10 insertions(+), 38 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index ad76f3d6d4..9287f52728 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -755,15 +755,6 @@ namespace Emby.Server.Implementations.Dto dto.BackdropImageTags = GetTagsAndFillBlurhashes(dto, item, ImageType.Backdrop, backdropLimit); } - if (options.ContainsField(ItemFields.ScreenshotImageTags)) - { - var screenshotLimit = options.GetImageLimit(ImageType.Screenshot); - if (screenshotLimit > 0) - { - dto.ScreenshotImageTags = GetTagsAndFillBlurhashes(dto, item, ImageType.Screenshot, screenshotLimit); - } - } - if (options.ContainsField(ItemFields.Genres)) { dto.Genres = item.Genres; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 0df70705e5..63749b1f33 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2577,7 +2577,7 @@ namespace MediaBrowser.Controller.Entities public bool AllowsMultipleImages(ImageType type) { - return type == ImageType.Backdrop || type == ImageType.Screenshot || type == ImageType.Chapter; + return type == ImageType.Backdrop || type == ImageType.Chapter; } public Task SwapImagesAsync(ImageType type, int index1, int index2) diff --git a/MediaBrowser.Model/Entities/ImageType.cs b/MediaBrowser.Model/Entities/ImageType.cs index 6ea9ee419e..ee74106321 100644 --- a/MediaBrowser.Model/Entities/ImageType.cs +++ b/MediaBrowser.Model/Entities/ImageType.cs @@ -1,3 +1,5 @@ +using System; + namespace MediaBrowser.Model.Entities { /// @@ -48,6 +50,7 @@ namespace MediaBrowser.Model.Entities /// /// The screenshot. /// + [Obsolete("Screenshot image type is no longer used.")] Screenshot = 8, /// diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index ef4698f3f9..e6c3a6c260 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -1,5 +1,7 @@ #pragma warning disable CS1591 +using System; + namespace MediaBrowser.Model.Querying { /// @@ -143,6 +145,7 @@ namespace MediaBrowser.Model.Querying /// /// The screenshot image tags. /// + [Obsolete("Screenshot image type is no longer used.")] ScreenshotImageTags, SeriesPrimaryImage, diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 8ded2d1446..d2a3344bef 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -439,9 +439,6 @@ namespace MediaBrowser.Providers.Manager case ImageType.Backdrop: filename = GetBackdropSaveFilename(item.GetImages(type), "backdrop", "backdrop", imageIndex); break; - case ImageType.Screenshot: - filename = GetBackdropSaveFilename(item.GetImages(type), "screenshot", "screenshot", imageIndex); - break; default: filename = type.ToString().ToLowerInvariant(); break; diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index d5959db772..1022a3faed 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -109,12 +109,6 @@ namespace MediaBrowser.Providers.Manager oldBackdropImages = item.GetImages(ImageType.Backdrop).ToArray(); } - var oldScreenshotImages = Array.Empty(); - if (refreshOptions.IsReplacingImage(ImageType.Screenshot)) - { - oldScreenshotImages = item.GetImages(ImageType.Screenshot).ToArray(); - } - var result = new RefreshResult { UpdateType = ItemUpdateType.None }; var typeName = item.GetType().Name; @@ -122,14 +116,13 @@ namespace MediaBrowser.Providers.Manager // track library limits, adding buffer to allow lazy replacing of current images var backdropLimit = typeOptions.GetLimit(ImageType.Backdrop) + oldBackdropImages.Length; - var screenshotLimit = typeOptions.GetLimit(ImageType.Screenshot) + oldScreenshotImages.Length; var downloadedImages = new List(); foreach (var provider in providers) { if (provider is IRemoteImageProvider remoteProvider) { - await RefreshFromProvider(item, remoteProvider, refreshOptions, typeOptions, backdropLimit, screenshotLimit, downloadedImages, result, cancellationToken).ConfigureAwait(false); + await RefreshFromProvider(item, remoteProvider, refreshOptions, typeOptions, backdropLimit, downloadedImages, result, cancellationToken).ConfigureAwait(false); continue; } @@ -145,11 +138,6 @@ namespace MediaBrowser.Providers.Manager PruneImages(item, oldBackdropImages); } - if (oldScreenshotImages.Length > 0 && oldScreenshotImages.Length < item.GetImages(ImageType.Screenshot).Count()) - { - PruneImages(item, oldScreenshotImages); - } - return result; } @@ -243,9 +231,8 @@ namespace MediaBrowser.Providers.Manager /// The images. /// The saved options. /// The backdrop limit. - /// The screenshot limit. /// true if the specified item contains images; otherwise, false. - private bool ContainsImages(BaseItem item, List images, TypeOptions savedOptions, int backdropLimit, int screenshotLimit) + private bool ContainsImages(BaseItem item, List images, TypeOptions savedOptions, int backdropLimit) { // Using .Any causes the creation of a DisplayClass aka. variable capture for (var i = 0; i < _singularImages.Length; i++) @@ -262,11 +249,6 @@ namespace MediaBrowser.Providers.Manager return false; } - if (images.Contains(ImageType.Screenshot) && item.GetImages(ImageType.Screenshot).Count() < screenshotLimit) - { - return false; - } - return true; } @@ -278,7 +260,6 @@ namespace MediaBrowser.Providers.Manager /// The refresh options. /// The saved options. /// The backdrop limit. - /// The screenshot limit. /// The downloaded images. /// The result. /// The cancellation token. @@ -289,7 +270,6 @@ namespace MediaBrowser.Providers.Manager ImageRefreshOptions refreshOptions, TypeOptions savedOptions, int backdropLimit, - int screenshotLimit, ICollection downloadedImages, RefreshResult result, CancellationToken cancellationToken) @@ -303,7 +283,7 @@ namespace MediaBrowser.Providers.Manager if (!refreshOptions.ReplaceAllImages && refreshOptions.ReplaceImages.Length == 0 && - ContainsImages(item, provider.GetSupportedImages(item).ToList(), savedOptions, backdropLimit, screenshotLimit)) + ContainsImages(item, provider.GetSupportedImages(item).ToList(), savedOptions, backdropLimit)) { return; } diff --git a/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs index 6011c8dd52..9f73ed7fc4 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs @@ -207,10 +207,8 @@ namespace Jellyfin.Providers.Tests.Manager [Theory] [InlineData(ImageType.Primary, 1, false)] [InlineData(ImageType.Backdrop, 2, false)] - [InlineData(ImageType.Screenshot, 2, false)] [InlineData(ImageType.Primary, 1, true)] [InlineData(ImageType.Backdrop, 2, true)] - [InlineData(ImageType.Screenshot, 2, true)] public async void RefreshImages_PopulatedItemPopulatedProviderDynamic_UpdatesImagesIfForced(ImageType imageType, int imageCount, bool forceRefresh) { var item = GetItemWithImages(imageType, imageCount, false); -- cgit v1.2.3 From d95c281142462277560e1f9ac8d9e28db9c7b242 Mon Sep 17 00:00:00 2001 From: cvium Date: Sat, 6 Nov 2021 22:44:05 +0100 Subject: Load all types when checking plugin DLLs --- Emby.Server.Implementations/Plugins/PluginManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Plugins/PluginManager.cs b/Emby.Server.Implementations/Plugins/PluginManager.cs index d52c0b2a14..d70a15dbc1 100644 --- a/Emby.Server.Implementations/Plugins/PluginManager.cs +++ b/Emby.Server.Implementations/Plugins/PluginManager.cs @@ -126,7 +126,8 @@ namespace Emby.Server.Implementations.Plugins { assembly = Assembly.LoadFrom(file); - assembly.GetExportedTypes(); + // Load all required types to verify that the plugin will load + assembly.GetTypes(); } catch (FileLoadException ex) { @@ -134,7 +135,7 @@ namespace Emby.Server.Implementations.Plugins ChangePluginState(plugin, PluginStatus.Malfunctioned); continue; } - catch (TypeLoadException ex) // Undocumented exception + catch (SystemException ex) when (ex is TypeLoadException or ReflectionTypeLoadException) // Undocumented exception { _logger.LogError(ex, "Failed to load assembly {Path}. This error occurs when a plugin references an incompatible version of one of the shared libraries. Disabling plugin.", file); ChangePluginState(plugin, PluginStatus.NotSupported); -- cgit v1.2.3 From 0f528966919518a190c33291946ba5947cc29670 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 7 Nov 2021 15:33:39 +0100 Subject: Fix UnauthorizedAccessException in GetDrives ``` [15:01:24] [ERR] [55] Jellyfin.Server.Middleware.ExceptionMiddleware: Error processing request. URL GET /Environment/Drives. System.UnauthorizedAccessException: Access to the path is denied. ---> System.IO.IOException: Operation not permitted --- End of inner exception stack trace --- at System.IO.DriveInfo.CheckStatfsResultAndThrowIfNecessary(Int32 result) at System.IO.DriveInfo.get_TotalSize() at Emby.Server.Implementations.IO.ManagedFileSystem.<>c.b__32_0(DriveInfo d) in /home/bond/dev/jellyfin/Emby.Server.Implementations/IO/ManagedFileSystem.cs:line 583 at System.Linq.Enumerable.WhereSelectArrayIterator`2.ToList() at Emby.Server.Implementations.IO.ManagedFileSystem.GetDrives() in /home/bond/dev/jellyfin/Emby.Server.Implementations/IO/ManagedFileSystem.cs:line 583 at Jellyfin.Api.Controllers.EnvironmentController.GetDrives() in /home/bond/dev/jellyfin/Jellyfin.Api/Controllers/EnvironmentController.cs:line 153 at lambda_method559(Closure , Object , Object[] ) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync() at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync() ``` --- Emby.Server.Implementations/IO/ManagedFileSystem.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index eeee288425..3aefb841e5 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -580,7 +580,11 @@ namespace Emby.Server.Implementations.IO { // check for ready state to avoid waiting for drives to timeout // some drives on linux have no actual size or are used for other purposes - return DriveInfo.GetDrives().Where(d => d.IsReady && d.TotalSize != 0 && d.DriveType != DriveType.Ram) + return DriveInfo.GetDrives() + .Where( + d => (d.DriveType == DriveType.Fixed || d.DriveType == DriveType.Network || d.DriveType == DriveType.Removable) + && d.IsReady + && d.TotalSize != 0) .Select(d => new FileSystemMetadata { Name = d.Name, -- cgit v1.2.3 From 4dfb7b18ae6e49003da702aefa449bca0bbecaf4 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 7 Nov 2021 22:32:08 +0100 Subject: Add some docs and tests --- .../IO/ManagedFileSystem.cs | 37 ++++++++++++++++++---- .../Library/MediaSourceManager.cs | 37 ++++++++-------------- .../Library/IMediaSourceManager.cs | 7 ---- .../Library/MediaSourceManagerTests.cs | 32 +++++++++++++++++++ 4 files changed, 75 insertions(+), 38 deletions(-) create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Library/MediaSourceManagerTests.cs (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 3aefb841e5..777cd2cd46 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.Globalization; @@ -23,6 +21,11 @@ namespace Emby.Server.Implementations.IO private readonly string _tempPath; private static readonly bool _isEnvironmentCaseInsensitive = OperatingSystem.IsWindows(); + /// + /// Initializes a new instance of the class. + /// + /// The instance to use. + /// The instance to use. public ManagedFileSystem( ILogger logger, IApplicationPaths applicationPaths) @@ -31,6 +34,7 @@ namespace Emby.Server.Implementations.IO _tempPath = applicationPaths.TempDirectory; } + /// public virtual void AddShortcutHandler(IShortcutHandler handler) { _shortcutHandlers.Add(handler); @@ -72,6 +76,7 @@ namespace Emby.Server.Implementations.IO return handler?.Resolve(filename); } + /// public virtual string MakeAbsolutePath(string folderPath, string filePath) { // path is actually a stream @@ -358,11 +363,13 @@ namespace Emby.Server.Implementations.IO return GetCreationTimeUtc(GetFileSystemInfo(path)); } + /// public virtual DateTime GetCreationTimeUtc(FileSystemMetadata info) { return info.CreationTimeUtc; } + /// public virtual DateTime GetLastWriteTimeUtc(FileSystemMetadata info) { return info.LastWriteTimeUtc; @@ -397,6 +404,7 @@ namespace Emby.Server.Implementations.IO return GetLastWriteTimeUtc(GetFileSystemInfo(path)); } + /// public virtual void SetHidden(string path, bool isHidden) { if (!OperatingSystem.IsWindows()) @@ -421,6 +429,7 @@ namespace Emby.Server.Implementations.IO } } + /// public virtual void SetAttributes(string path, bool isHidden, bool readOnly) { if (!OperatingSystem.IsWindows()) @@ -444,7 +453,7 @@ namespace Emby.Server.Implementations.IO if (readOnly) { - attributes = attributes | FileAttributes.ReadOnly; + attributes |= FileAttributes.ReadOnly; } else { @@ -453,7 +462,7 @@ namespace Emby.Server.Implementations.IO if (isHidden) { - attributes = attributes | FileAttributes.Hidden; + attributes |= FileAttributes.Hidden; } else { @@ -498,6 +507,7 @@ namespace Emby.Server.Implementations.IO File.Copy(temp1, file2, true); } + /// public virtual bool ContainsSubPath(string parentPath, string path) { if (string.IsNullOrEmpty(parentPath)) @@ -515,6 +525,7 @@ namespace Emby.Server.Implementations.IO _isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); } + /// public virtual string NormalizePath(string path) { if (string.IsNullOrEmpty(path)) @@ -530,6 +541,7 @@ namespace Emby.Server.Implementations.IO return Path.TrimEndingDirectorySeparator(path); } + /// public virtual bool AreEqual(string path1, string path2) { if (path1 == null && path2 == null) @@ -548,6 +560,7 @@ namespace Emby.Server.Implementations.IO _isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); } + /// public virtual string GetFileNameWithoutExtension(FileSystemMetadata info) { if (info.IsDirectory) @@ -558,11 +571,11 @@ namespace Emby.Server.Implementations.IO return Path.GetFileNameWithoutExtension(info.FullName); } + /// public virtual bool IsPathFile(string path) { - // Cannot use Path.IsPathRooted because it returns false under mono when using windows-based paths, e.g. C:\\ - if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) != -1 && - !path.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) + if (path.Contains("://", StringComparison.OrdinalIgnoreCase) + && !path.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) { return false; } @@ -570,12 +583,14 @@ namespace Emby.Server.Implementations.IO return true; } + /// public virtual void DeleteFile(string path) { SetAttributes(path, false, false); File.Delete(path); } + /// public virtual List GetDrives() { // check for ready state to avoid waiting for drives to timeout @@ -593,16 +608,19 @@ namespace Emby.Server.Implementations.IO }).ToList(); } + /// public virtual IEnumerable GetDirectories(string path, bool recursive = false) { return ToMetadata(new DirectoryInfo(path).EnumerateDirectories("*", GetEnumerationOptions(recursive))); } + /// public virtual IEnumerable GetFiles(string path, bool recursive = false) { return GetFiles(path, null, false, recursive); } + /// public virtual IEnumerable GetFiles(string path, IReadOnlyList? extensions, bool enableCaseSensitiveExtensions, bool recursive = false) { var enumerationOptions = GetEnumerationOptions(recursive); @@ -633,6 +651,7 @@ namespace Emby.Server.Implementations.IO return ToMetadata(files); } + /// public virtual IEnumerable GetFileSystemEntries(string path, bool recursive = false) { var directoryInfo = new DirectoryInfo(path); @@ -646,16 +665,19 @@ namespace Emby.Server.Implementations.IO return infos.Select(GetFileSystemMetadata); } + /// public virtual IEnumerable GetDirectoryPaths(string path, bool recursive = false) { return Directory.EnumerateDirectories(path, "*", GetEnumerationOptions(recursive)); } + /// public virtual IEnumerable GetFilePaths(string path, bool recursive = false) { return GetFilePaths(path, null, false, recursive); } + /// public virtual IEnumerable GetFilePaths(string path, string[]? extensions, bool enableCaseSensitiveExtensions, bool recursive = false) { var enumerationOptions = GetEnumerationOptions(recursive); @@ -686,6 +708,7 @@ namespace Emby.Server.Implementations.IO return files; } + /// public virtual IEnumerable GetFileSystemEntryPaths(string path, bool recursive = false) { return Directory.EnumerateFileSystemEntries(path, "*", GetEnumerationOptions(recursive)); diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 351fced348..972d4ebbbf 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -45,6 +45,7 @@ namespace Emby.Server.Implementations.Library private readonly IMediaEncoder _mediaEncoder; private readonly ILocalizationManager _localizationManager; private readonly IApplicationPaths _appPaths; + private readonly IDirectoryService _directoryService; private readonly ConcurrentDictionary _openStreams = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); @@ -61,7 +62,8 @@ namespace Emby.Server.Implementations.Library ILogger logger, IFileSystem fileSystem, IUserDataManager userDataManager, - IMediaEncoder mediaEncoder) + IMediaEncoder mediaEncoder, + IDirectoryService directoryService) { _itemRepo = itemRepo; _userManager = userManager; @@ -72,6 +74,7 @@ namespace Emby.Server.Implementations.Library _mediaEncoder = mediaEncoder; _localizationManager = localizationManager; _appPaths = applicationPaths; + _directoryService = directoryService; } public void AddParts(IEnumerable providers) @@ -106,16 +109,6 @@ namespace Emby.Server.Implementations.Library return false; } - public List GetMediaStreams(string mediaSourceId) - { - var list = GetMediaStreams(new MediaStreamQuery - { - ItemId = new Guid(mediaSourceId) - }); - - return GetMediaStreamsForItem(list); - } - public List GetMediaStreams(Guid itemId) { var list = GetMediaStreams(new MediaStreamQuery @@ -161,7 +154,7 @@ namespace Emby.Server.Implementations.Library if (allowMediaProbe && mediaSources[0].Type != MediaSourceType.Placeholder && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Audio || i.Type == MediaStreamType.Video)) { await item.RefreshMetadata( - new MetadataRefreshOptions(new DirectoryService(_fileSystem)) + new MetadataRefreshOptions(_directoryService) { EnableRemoteContentProbe = true, MetadataRefreshMode = MetadataRefreshMode.FullRefresh @@ -212,6 +205,7 @@ namespace Emby.Server.Implementations.Library return SortMediaSources(list); } + /// > public MediaProtocol GetPathProtocol(string path) { if (path.StartsWith("Rtsp", StringComparison.OrdinalIgnoreCase)) @@ -258,7 +252,7 @@ namespace Emby.Server.Implementations.Library { if (path != null) { - if (path.IndexOf(".m3u", StringComparison.OrdinalIgnoreCase) != -1) + if (path.Contains(".m3u", StringComparison.OrdinalIgnoreCase)) { return false; } @@ -297,7 +291,7 @@ namespace Emby.Server.Implementations.Library catch (Exception ex) { _logger.LogError(ex, "Error getting media sources"); - return new List(); + return Enumerable.Empty(); } } @@ -494,14 +488,11 @@ namespace Emby.Server.Implementations.Library _liveStreamSemaphore.Release(); } - // TODO: Don't hardcode this - const bool isAudio = false; - try { if (mediaSource.MediaStreams.Any(i => i.Index != -1) || !mediaSource.SupportsProbing) { - AddMediaInfo(mediaSource, isAudio); + AddMediaInfo(mediaSource); } else { @@ -509,14 +500,14 @@ namespace Emby.Server.Implementations.Library string cacheKey = request.OpenToken; await new LiveStreamHelper(_mediaEncoder, _logger, _appPaths) - .AddMediaInfoWithProbe(mediaSource, isAudio, cacheKey, true, cancellationToken) + .AddMediaInfoWithProbe(mediaSource, false, cacheKey, true, cancellationToken) .ConfigureAwait(false); } } catch (Exception ex) { _logger.LogError(ex, "Error probing live tv stream"); - AddMediaInfo(mediaSource, isAudio); + AddMediaInfo(mediaSource); } // TODO: @bond Fix @@ -536,7 +527,7 @@ namespace Emby.Server.Implementations.Library return new Tuple(new LiveStreamResponse(clone), liveStream as IDirectStreamProvider); } - private static void AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio) + private static void AddMediaInfo(MediaSourceInfo mediaSource) { mediaSource.DefaultSubtitleStreamIndex = null; @@ -855,9 +846,7 @@ namespace Emby.Server.Implementations.Library return (provider, keyId); } - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// + /// public void Dispose() { Dispose(true); diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index e802796d34..f1758a9d80 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -30,13 +30,6 @@ namespace MediaBrowser.Controller.Library /// IEnumerable<MediaStream>. List GetMediaStreams(Guid itemId); - /// - /// Gets the media streams. - /// - /// The media source identifier. - /// IEnumerable<MediaStream>. - List GetMediaStreams(string mediaSourceId); - /// /// Gets the media streams. /// diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/MediaSourceManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/MediaSourceManagerTests.cs new file mode 100644 index 0000000000..8ed3d8b944 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/MediaSourceManagerTests.cs @@ -0,0 +1,32 @@ +using AutoFixture; +using AutoFixture.AutoMoq; +using Emby.Server.Implementations.IO; +using Emby.Server.Implementations.Library; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.MediaInfo; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.Library +{ + public class MediaSourceManagerTests + { + private readonly MediaSourceManager _mediaSourceManager; + + public MediaSourceManagerTests() + { + IFixture fixture = new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true }); + fixture.Inject(fixture.Create()); + _mediaSourceManager = fixture.Create(); + } + + [Theory] + [InlineData(@"C:\mydir\myfile.ext", MediaProtocol.File)] + [InlineData("/mydir/myfile.ext", MediaProtocol.File)] + [InlineData("file:///mydir/myfile.ext", MediaProtocol.File)] + [InlineData("http://example.com/stream.m3u8", MediaProtocol.Http)] + [InlineData("https://example.com/stream.m3u8", MediaProtocol.Http)] + [InlineData("rtsp://media.example.com:554/twister/audiotrack", MediaProtocol.Rtsp)] + public void GetPathProtocol_ValidArg_Correct(string path, MediaProtocol expected) + => Assert.Equal(expected, _mediaSourceManager.GetPathProtocol(path)); + } +} -- cgit v1.2.3 From 82e6a21f3bff6a3666a6c28d218ed936457cf5d1 Mon Sep 17 00:00:00 2001 From: cvium Date: Mon, 8 Nov 2021 10:58:04 +0100 Subject: Use the new method in DLNA --- Emby.Dlna/Main/DlnaEntryPoint.cs | 15 ++++----------- Emby.Server.Implementations/ApplicationHost.cs | 9 ++++++--- MediaBrowser.Controller/IServerApplicationHost.cs | 5 +++-- 3 files changed, 13 insertions(+), 16 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index 5d252d8dc4..8e89d9ae6a 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -52,7 +52,6 @@ namespace Emby.Dlna.Main private readonly ISocketFactory _socketFactory; private readonly INetworkManager _networkManager; private readonly object _syncLock = new object(); - private readonly NetworkConfiguration _netConfig; private readonly bool _disabled; private PlayToManager _manager; @@ -125,8 +124,8 @@ namespace Emby.Dlna.Main config); Current = this; - _netConfig = config.GetConfiguration("network"); - _disabled = appHost.ListenWithHttps && _netConfig.RequireHttps; + var netConfig = config.GetConfiguration("network"); + _disabled = appHost.ListenWithHttps && netConfig.RequireHttps; if (_disabled && _config.GetDlnaConfiguration().EnableServer) { @@ -318,15 +317,9 @@ namespace Emby.Dlna.Main var fullService = "urn:schemas-upnp-org:device:MediaServer:1"; - _logger.LogInformation("Registering publisher for {0} on {1}", fullService, address); + _logger.LogInformation("Registering publisher for {ResourceName} on {DeviceAddress}", fullService, address); - var uri = new UriBuilder(_appHost.GetSmartApiUrl(address.Address) + descriptorUri); - if (!string.IsNullOrEmpty(_appHost.PublishedServerUrl)) - { - // DLNA will only work over http, so we must reset to http:// : {port}. - uri.Scheme = "http"; - uri.Port = _netConfig.HttpServerPortNumber; - } + var uri = new UriBuilder(_appHost.GetApiUrlForLocalAccess(false) + descriptorUri); var device = new SsdpRootDevice { diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 7da0e2f21e..4f2fdfd3cb 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1166,10 +1166,13 @@ namespace Emby.Server.Implementations } /// - public string GetApiUrlForLocalAccess() + public string GetApiUrlForLocalAccess(bool allowHttps) { - string smart = NetManager.GetBindInterface(string.Empty, out var port); - return GetLocalApiUrl(smart.Trim('/'), null, port); + // With an empty source, the port will be null + string smart = NetManager.GetBindInterface(string.Empty, out _); + var scheme = allowHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; + var port = allowHttps ? HttpsPort : HttpPort; + return GetLocalApiUrl(smart.Trim('/'), scheme, port); } /// diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index ff7f9372f0..7da492af3c 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -81,10 +81,11 @@ namespace MediaBrowser.Controller string GetSmartApiUrl(string hostname, int? port = null); /// - /// Gets an URL that can be used to access the API over HTTP (not HTTPS). + /// Gets an URL that can be used to access the API over LAN. /// + /// A value indicating whether to allow HTTPS. /// The API URL. - string GetApiUrlForLocalAccess(); + string GetApiUrlForLocalAccess(bool allowHttps = true); /// /// Gets a local (LAN) URL that can be used to access the API. -- cgit v1.2.3 From 15dd23e4da10847537e7a8a49d0f75ab0b2fd339 Mon Sep 17 00:00:00 2001 From: rimasx Date: Sun, 7 Nov 2021 20:49:19 +0000 Subject: Translated using Weblate (Estonian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/ --- Emby.Server.Implementations/Localization/Core/et.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/et.json b/Emby.Server.Implementations/Localization/Core/et.json index c3596ecf14..e5405e5154 100644 --- a/Emby.Server.Implementations/Localization/Core/et.json +++ b/Emby.Server.Implementations/Localization/Core/et.json @@ -17,7 +17,7 @@ "TaskCleanLogsDescription": "Kustutab logifailid, mis on vanemad kui {0} päeva.", "TaskCleanLogs": "Puhasta logikataloog", "TaskRefreshLibraryDescription": "Otsib meedikogust uusi faile ja värskendab metaandmeid.", - "Collections": "Kollektsioonid", + "Collections": "Kogumikud", "TaskRefreshLibrary": "Skaneeri meediakogu", "TaskRefreshChapterImagesDescription": "Loob peatükkidega videote jaoks pisipildid.", "TaskRefreshChapterImages": "Eralda peatükipildid", -- cgit v1.2.3 From 40045d21470ce0eb15e5c9700d6a1449dbf7c36e Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Mon, 8 Nov 2021 06:55:16 -0700 Subject: Update to full dotnet 6 --- .ci/azure-pipelines-abi.yml | 1 - .ci/azure-pipelines-main.yml | 1 - .ci/azure-pipelines-package.yml | 1 - .ci/azure-pipelines-test.yml | 1 - .github/workflows/codeql-analysis.yml | 3 +-- .github/workflows/openapi.yml | 2 -- Emby.Dlna/Emby.Dlna.csproj | 2 +- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 10 +++++----- Jellyfin.Api/Jellyfin.Api.csproj | 4 ++-- Jellyfin.Data/Jellyfin.Data.csproj | 2 +- .../Jellyfin.Server.Implementations.csproj | 8 ++++---- Jellyfin.Server/Jellyfin.Server.csproj | 8 ++++---- MediaBrowser.Common/MediaBrowser.Common.csproj | 4 ++-- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 6 +++--- MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj | 4 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 4 ++-- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 6 +++--- deployment/Dockerfile.centos.amd64 | 2 +- deployment/Dockerfile.fedora.amd64 | 2 +- deployment/Dockerfile.ubuntu.amd64 | 2 +- deployment/Dockerfile.ubuntu.arm64 | 2 +- deployment/Dockerfile.ubuntu.armhf | 2 +- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 4 ++-- .../Jellyfin.Server.Integration.Tests.csproj | 4 ++-- tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj | 4 ++-- 25 files changed, 41 insertions(+), 48 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/.ci/azure-pipelines-abi.yml b/.ci/azure-pipelines-abi.yml index 31f861f63f..cf74a4201b 100644 --- a/.ci/azure-pipelines-abi.yml +++ b/.ci/azure-pipelines-abi.yml @@ -34,7 +34,6 @@ jobs: inputs: packageType: sdk version: ${{ parameters.DotNetSdkVersion }} - includePreviewVersions: true - task: DotNetCoreCLI@2 displayName: 'Install ABI CompatibilityChecker Tool' diff --git a/.ci/azure-pipelines-main.yml b/.ci/azure-pipelines-main.yml index 1086d51d27..b7112ba245 100644 --- a/.ci/azure-pipelines-main.yml +++ b/.ci/azure-pipelines-main.yml @@ -54,7 +54,6 @@ jobs: inputs: packageType: sdk version: ${{ parameters.DotNetSdkVersion }} - includePreviewVersions: true - task: DotNetCoreCLI@2 displayName: 'Publish Server' diff --git a/.ci/azure-pipelines-package.yml b/.ci/azure-pipelines-package.yml index 4abe52b43b..e227d5fe60 100644 --- a/.ci/azure-pipelines-package.yml +++ b/.ci/azure-pipelines-package.yml @@ -199,7 +199,6 @@ jobs: inputs: packageType: 'sdk' version: '6.0.x' - includePreviewVersions: true - task: DotNetCoreCLI@2 displayName: 'Build Stable Nuget packages' diff --git a/.ci/azure-pipelines-test.yml b/.ci/azure-pipelines-test.yml index 80a5732eee..cc94dc2c5a 100644 --- a/.ci/azure-pipelines-test.yml +++ b/.ci/azure-pipelines-test.yml @@ -41,7 +41,6 @@ jobs: inputs: packageType: sdk version: ${{ parameters.DotNetSdkVersion }} - includePreviewVersions: true - task: SonarCloudPrepare@1 displayName: 'Prepare analysis on SonarCloud' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e07d913b5a..ea1d30cdfa 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -25,8 +25,7 @@ jobs: uses: actions/setup-dotnet@v1 with: dotnet-version: '6.0.x' - include-prerelease: true - + - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index ea9188f1b1..3e93468401 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -20,7 +20,6 @@ jobs: uses: actions/setup-dotnet@v1 with: dotnet-version: '6.0.x' - include-prerelease: true - name: Generate openapi.json run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests" - name: Upload openapi.json @@ -45,7 +44,6 @@ jobs: uses: actions/setup-dotnet@v1 with: dotnet-version: '6.0.x' - include-prerelease: true - name: Generate openapi.json run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests" - name: Upload openapi.json diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index c8332e44e4..7fdbd44f00 100644 --- a/Emby.Dlna/Emby.Dlna.csproj +++ b/Emby.Dlna/Emby.Dlna.csproj @@ -72,7 +72,7 @@ - + diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index c1ce4b5572..03f9f50eae 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -25,11 +25,11 @@ - - - - - + + + + + diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 57480b2f35..a3598edfa4 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 2de53e7c83..248b29cbb7 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -35,7 +35,7 @@ - + diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index e26cf093b9..73ee694245 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -19,13 +19,13 @@ - - - + + + 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 a75d747be4..045ed6a2ba 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -31,10 +31,10 @@ - - - - + + + + diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 9c8ce4ac57..587fbcee00 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index d378808658..71466ce3aa 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -15,10 +15,10 @@ - - + + - + diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index c1fd8e5fb4..6bb8bcdab3 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -24,8 +24,8 @@ - - + + diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 16bc4adf8a..1ac0f1d5e6 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -30,9 +30,9 @@ - + - + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 9d0a6944bb..b421121111 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -16,9 +16,9 @@ - - - + + + diff --git a/deployment/Dockerfile.centos.amd64 b/deployment/Dockerfile.centos.amd64 index 78f051e4fb..3967a165d2 100644 --- a/deployment/Dockerfile.centos.amd64 +++ b/deployment/Dockerfile.centos.amd64 @@ -13,7 +13,7 @@ RUN yum update -yq \ && yum install -yq @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel git wget # Install DotNET SDK -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/20283373-1d83-4879-8278-0afb7fd4035e/56f204f174743b29a656499ad0fc93c3/dotnet-sdk-6.0.100-rc.2.21505.57-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/17b6759f-1af0-41bc-ab12-209ba0377779/e8d02195dbf1434b940e0f05ae086453/dotnet-sdk-6.0.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.fedora.amd64 b/deployment/Dockerfile.fedora.amd64 index 14eeb6eed8..bc40a8059e 100644 --- a/deployment/Dockerfile.fedora.amd64 +++ b/deployment/Dockerfile.fedora.amd64 @@ -12,7 +12,7 @@ RUN dnf update -yq \ && dnf install -yq @buildsys-build rpmdevtools git dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel systemd wget # Install DotNET SDK -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/20283373-1d83-4879-8278-0afb7fd4035e/56f204f174743b29a656499ad0fc93c3/dotnet-sdk-6.0.100-rc.2.21505.57-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/17b6759f-1af0-41bc-ab12-209ba0377779/e8d02195dbf1434b940e0f05ae086453/dotnet-sdk-6.0.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.ubuntu.amd64 b/deployment/Dockerfile.ubuntu.amd64 index 8733be89cf..c1b541c596 100644 --- a/deployment/Dockerfile.ubuntu.amd64 +++ b/deployment/Dockerfile.ubuntu.amd64 @@ -17,7 +17,7 @@ RUN apt-get update -yqq \ libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 # Install dotnet repository -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/20283373-1d83-4879-8278-0afb7fd4035e/56f204f174743b29a656499ad0fc93c3/dotnet-sdk-6.0.100-rc.2.21505.57-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/17b6759f-1af0-41bc-ab12-209ba0377779/e8d02195dbf1434b940e0f05ae086453/dotnet-sdk-6.0.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.ubuntu.arm64 b/deployment/Dockerfile.ubuntu.arm64 index 6ae0d53ccb..6aa98a2890 100644 --- a/deployment/Dockerfile.ubuntu.arm64 +++ b/deployment/Dockerfile.ubuntu.arm64 @@ -16,7 +16,7 @@ RUN apt-get update -yqq \ mmv build-essential lsb-release # Install dotnet repository -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/20283373-1d83-4879-8278-0afb7fd4035e/56f204f174743b29a656499ad0fc93c3/dotnet-sdk-6.0.100-rc.2.21505.57-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/17b6759f-1af0-41bc-ab12-209ba0377779/e8d02195dbf1434b940e0f05ae086453/dotnet-sdk-6.0.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/Dockerfile.ubuntu.armhf b/deployment/Dockerfile.ubuntu.armhf index 154388148c..cc9d8dc797 100644 --- a/deployment/Dockerfile.ubuntu.armhf +++ b/deployment/Dockerfile.ubuntu.armhf @@ -16,7 +16,7 @@ RUN apt-get update -yqq \ mmv build-essential lsb-release # Install dotnet repository -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/20283373-1d83-4879-8278-0afb7fd4035e/56f204f174743b29a656499ad0fc93c3/dotnet-sdk-6.0.100-rc.2.21505.57-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/17b6759f-1af0-41bc-ab12-209ba0377779/e8d02195dbf1434b940e0f05ae086453/dotnet-sdk-6.0.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 57ec86316c..2aced06691 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -15,8 +15,8 @@ - - + + diff --git a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj index 889220d86e..5b884cddf6 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj +++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index 3daa45e56c..29d7646a66 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -10,8 +10,8 @@ - - + + -- cgit v1.2.3 From 958a4f509c0d8a326eedc6a95a9f9e2d31e5391f Mon Sep 17 00:00:00 2001 From: hoanghuy309 Date: Mon, 8 Nov 2021 17:53:18 +0000 Subject: Translated using Weblate (Vietnamese) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/vi/ --- Emby.Server.Implementations/Localization/Core/vi.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/vi.json b/Emby.Server.Implementations/Localization/Core/vi.json index 33aa0eea07..548e395a9f 100644 --- a/Emby.Server.Implementations/Localization/Core/vi.json +++ b/Emby.Server.Implementations/Localization/Core/vi.json @@ -62,11 +62,11 @@ "PluginUninstalledWithName": "{0} đã được gỡ bỏ", "PluginInstalledWithName": "{0} đã được cài đặt", "Plugin": "Plugin", - "NotificationOptionVideoPlaybackStopped": "Phát lại video đã dừng", + "NotificationOptionVideoPlaybackStopped": "Đã dừng phát lại video", "NotificationOptionVideoPlayback": "Đã bắt đầu phát lại video", "NotificationOptionUserLockedOut": "Người dùng bị khóa", "NotificationOptionTaskFailed": "Lỗi tác vụ đã lên lịch", - "NotificationOptionServerRestartRequired": "Yêu cầu khởi động lại Server", + "NotificationOptionServerRestartRequired": "Yêu cầu khởi động lại máy chủ", "NotificationOptionPluginUpdateInstalled": "Cập nhật Plugin đã được cài đặt", "NotificationOptionPluginUninstalled": "Đã gỡ bỏ Plugin", "NotificationOptionPluginInstalled": "Đã cài đặt Plugin", @@ -75,7 +75,7 @@ "NotificationOptionInstallationFailed": "Cài đặt thất bại", "NotificationOptionCameraImageUploaded": "Đã tải lên hình ảnh máy ảnh", "NotificationOptionAudioPlaybackStopped": "Phát lại âm thanh đã dừng", - "NotificationOptionAudioPlayback": "Phát lại âm thanh đã bắt đầu", + "NotificationOptionAudioPlayback": "Đã bắt đầu phát lại âm thanh", "NotificationOptionApplicationUpdateInstalled": "Bản cập nhật ứng dụng đã được cài đặt", "NotificationOptionApplicationUpdateAvailable": "Bản cập nhật ứng dụng hiện sẵn có", "NewVersionIsAvailable": "Một phiên bản mới của Jellyfin Server sẵn có để tải.", -- cgit v1.2.3 From 5726535a262ce5f671bb0b74dd00c485d17633f0 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 9 Nov 2021 13:14:31 +0100 Subject: Fix some warnings 609 left --- Emby.Naming/Common/NamingOptions.cs | 2 ++ Emby.Server.Implementations/Dto/DtoService.cs | 2 +- Emby.Server.Implementations/IO/LibraryMonitor.cs | 2 +- Emby.Server.Implementations/Library/LibraryManager.cs | 14 +++++++------- .../Library/Validators/PeopleValidator.cs | 2 +- Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 8 ++++---- .../LiveTv/EmbyTV/EncodedRecorder.cs | 12 ++++++------ Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs | 2 +- Emby.Server.Implementations/LiveTv/LiveTvManager.cs | 6 +++--- .../LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 2 +- .../ScheduledTasks/Tasks/DeleteCacheFileTask.cs | 8 ++++---- .../ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs | 8 ++++---- Jellyfin.Api/Controllers/DynamicHlsController.cs | 6 +++--- Jellyfin.Api/Controllers/SubtitleController.cs | 2 +- Jellyfin.Server.Implementations/Events/EventManager.cs | 2 +- Jellyfin.Server/Middleware/ResponseTimeMiddleware.cs | 2 +- Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs | 2 +- Jellyfin.Server/Program.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 2 +- MediaBrowser.Controller/IO/FileData.cs | 4 ++-- MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 2 +- MediaBrowser.Providers/Manager/ItemImageProvider.cs | 4 ++-- MediaBrowser.Providers/Manager/MetadataService.cs | 6 +++--- MediaBrowser.XbmcMetadata/EntryPoint.cs | 2 +- jellyfin.ruleset | 6 ++++++ .../Controllers/DashboardControllerTests.cs | 2 +- 27 files changed, 61 insertions(+), 53 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 5ddcf37fe6..7bc9fbce84 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CA1819 + using System; using System.Linq; using System.Text.RegularExpressions; diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 9287f52728..c6b32a52c9 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -497,7 +497,7 @@ namespace Emby.Server.Implementations.Dto } catch (Exception ex) { - _logger.LogError(ex, "Error getting {imageType} image info for {path}", image.Type, image.Path); + _logger.LogError(ex, "Error getting {ImageType} image info for {Path}", image.Type, image.Path); return null; } } diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index e9d069cd33..7ebc800b9a 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -276,7 +276,7 @@ namespace Emby.Server.Implementations.IO } catch (Exception ex) { - _logger.LogError(ex, "Error watching path: {path}", path); + _logger.LogError(ex, "Error watching path: {Path}", path); } }); } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 1326f60fe5..2dbb569c63 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -492,7 +492,7 @@ namespace Emby.Server.Implementations.Library } catch (Exception ex) { - _logger.LogError(ex, "Error in {resolver} resolving {path}", resolver.GetType().Name, args.Path); + _logger.LogError(ex, "Error in {Resolver} resolving {Path}", resolver.GetType().Name, args.Path); return null; } } @@ -799,7 +799,7 @@ namespace Emby.Server.Implementations.Library { var userRootPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath; - _logger.LogDebug("Creating userRootPath at {path}", userRootPath); + _logger.LogDebug("Creating userRootPath at {Path}", userRootPath); Directory.CreateDirectory(userRootPath); var newItemId = GetNewItemId(userRootPath, typeof(UserRootFolder)); @@ -810,7 +810,7 @@ namespace Emby.Server.Implementations.Library } catch (Exception ex) { - _logger.LogError(ex, "Error creating UserRootFolder {path}", newItemId); + _logger.LogError(ex, "Error creating UserRootFolder {Path}", newItemId); } if (tmpItem == null) @@ -827,7 +827,7 @@ namespace Emby.Server.Implementations.Library } _userRootFolder = tmpItem; - _logger.LogDebug("Setting userRootFolder: {folder}", _userRootFolder); + _logger.LogDebug("Setting userRootFolder: {Folder}", _userRootFolder); } } } @@ -1213,7 +1213,7 @@ namespace Emby.Server.Implementations.Library } catch (Exception ex) { - _logger.LogError(ex, "Error resolving shortcut file {file}", i); + _logger.LogError(ex, "Error resolving shortcut file {File}", i); return null; } }) @@ -1698,7 +1698,7 @@ namespace Emby.Server.Implementations.Library if (video == null) { - _logger.LogError("Intro resolver returned null for {path}.", info.Path); + _logger.LogError("Intro resolver returned null for {Path}.", info.Path); } else { @@ -1717,7 +1717,7 @@ namespace Emby.Server.Implementations.Library } catch (Exception ex) { - _logger.LogError(ex, "Error resolving path {path}.", info.Path); + _logger.LogError(ex, "Error resolving path {Path}.", info.Path); } } else diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs index 8739a9e1be..8a9a4b8652 100644 --- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs @@ -78,7 +78,7 @@ namespace Emby.Server.Implementations.Library.Validators } catch (Exception ex) { - _logger.LogError(ex, "Error validating IBN entry {person}", person); + _logger.LogError(ex, "Error validating IBN entry {Person}", person); } // Update progress diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 980b42729a..e5abb523c5 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1308,16 +1308,16 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV await recorder.Record(directStreamProvider, mediaStreamInfo, recordPath, duration, onStarted, activeRecordingInfo.CancellationTokenSource.Token).ConfigureAwait(false); recordingStatus = RecordingStatus.Completed; - _logger.LogInformation("Recording completed: {recordPath}", recordPath); + _logger.LogInformation("Recording completed: {RecordPath}", recordPath); } catch (OperationCanceledException) { - _logger.LogInformation("Recording stopped: {recordPath}", recordPath); + _logger.LogInformation("Recording stopped: {RecordPath}", recordPath); recordingStatus = RecordingStatus.Completed; } catch (Exception ex) { - _logger.LogError(ex, "Error recording to {recordPath}", recordPath); + _logger.LogError(ex, "Error recording to {RecordPath}", recordPath); recordingStatus = RecordingStatus.Error; } @@ -1404,7 +1404,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } catch (Exception ex) { - _logger.LogError(ex, "Error deleting 0-byte failed recording file {path}", path); + _logger.LogError(ex, "Error deleting 0-byte failed recording file {Path}", path); } } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 835028b92a..8688688e92 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -225,13 +225,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { try { - _logger.LogInformation("Stopping ffmpeg recording process for {path}", _targetPath); + _logger.LogInformation("Stopping ffmpeg recording process for {Path}", _targetPath); _process.StandardInput.WriteLine("q"); } catch (Exception ex) { - _logger.LogError(ex, "Error stopping recording transcoding job for {path}", _targetPath); + _logger.LogError(ex, "Error stopping recording transcoding job for {Path}", _targetPath); } if (_hasExited) @@ -241,7 +241,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV try { - _logger.LogInformation("Calling recording process.WaitForExit for {path}", _targetPath); + _logger.LogInformation("Calling recording process.WaitForExit for {Path}", _targetPath); if (_process.WaitForExit(10000)) { @@ -250,7 +250,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } catch (Exception ex) { - _logger.LogError(ex, "Error waiting for recording process to exit for {path}", _targetPath); + _logger.LogError(ex, "Error waiting for recording process to exit for {Path}", _targetPath); } if (_hasExited) @@ -260,13 +260,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV try { - _logger.LogInformation("Killing ffmpeg recording process for {path}", _targetPath); + _logger.LogInformation("Killing ffmpeg recording process for {Path}", _targetPath); _process.Kill(); } catch (Exception ex) { - _logger.LogError(ex, "Error killing recording transcoding job for {path}", _targetPath); + _logger.LogError(ex, "Error killing recording transcoding job for {Path}", _targetPath); } } } diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs index 21e1409ac0..598e3f88a6 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -393,7 +393,7 @@ namespace Emby.Server.Implementations.LiveTv } catch (Exception ex) { - _logger.LogError(ex, "Error getting image info for {name}", info.Name); + _logger.LogError(ex, "Error getting image info for {Name}", info.Name); } return null; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index ea1a28fe86..a41b63f284 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1054,7 +1054,7 @@ namespace Emby.Server.Implementations.LiveTv { cancellationToken.ThrowIfCancellationRequested(); - _logger.LogDebug("Refreshing guide from {name}", service.Name); + _logger.LogDebug("Refreshing guide from {Name}", service.Name); try { @@ -1135,7 +1135,7 @@ namespace Emby.Server.Implementations.LiveTv } catch (Exception ex) { - _logger.LogError(ex, "Error getting channel information for {name}", channelInfo.Item2.Name); + _logger.LogError(ex, "Error getting channel information for {Name}", channelInfo.Item2.Name); } numComplete++; @@ -1248,7 +1248,7 @@ namespace Emby.Server.Implementations.LiveTv } catch (Exception ex) { - _logger.LogError(ex, "Error getting programs for channel {name}", currentChannel.Name); + _logger.LogError(ex, "Error getting programs for channel {Name}", currentChannel.Name); } numComplete++; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 31445e1ecc..b621055d8e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -82,7 +82,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun Directory.CreateDirectory(Path.GetDirectoryName(TempFilePath)); - Logger.LogInformation("Opening HDHR UDP Live stream from {host}", uri.Host); + Logger.LogInformation("Opening HDHR UDP Live stream from {Host}", uri.Host); var remoteAddress = IPAddress.Parse(uri.Host); IPAddress localAddress = null; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs index a575b260cb..0941902fcd 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -161,11 +161,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks } catch (UnauthorizedAccessException ex) { - _logger.LogError(ex, "Error deleting directory {path}", directory); + _logger.LogError(ex, "Error deleting directory {Path}", directory); } catch (IOException ex) { - _logger.LogError(ex, "Error deleting directory {path}", directory); + _logger.LogError(ex, "Error deleting directory {Path}", directory); } } } @@ -179,11 +179,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks } catch (UnauthorizedAccessException ex) { - _logger.LogError(ex, "Error deleting file {path}", path); + _logger.LogError(ex, "Error deleting file {Path}", path); } catch (IOException ex) { - _logger.LogError(ex, "Error deleting file {path}", path); + _logger.LogError(ex, "Error deleting file {Path}", path); } } } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs index b13fc7fc68..099d781cd9 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs @@ -141,11 +141,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks } catch (UnauthorizedAccessException ex) { - _logger.LogError(ex, "Error deleting directory {path}", directory); + _logger.LogError(ex, "Error deleting directory {Path}", directory); } catch (IOException ex) { - _logger.LogError(ex, "Error deleting directory {path}", directory); + _logger.LogError(ex, "Error deleting directory {Path}", directory); } } } @@ -159,11 +159,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks } catch (UnauthorizedAccessException ex) { - _logger.LogError(ex, "Error deleting file {path}", path); + _logger.LogError(ex, "Error deleting file {Path}", path); } catch (IOException ex) { - _logger.LogError(ex, "Error deleting file {path}", path); + _logger.LogError(ex, "Error deleting file {Path}", path); } } } diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 475b804643..049fd503bd 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1794,7 +1794,7 @@ namespace Jellyfin.Api.Controllers return; } - _logger.LogDebug("Deleting partial HLS file {path}", path); + _logger.LogDebug("Deleting partial HLS file {Path}", path); try { @@ -1802,7 +1802,7 @@ namespace Jellyfin.Api.Controllers } catch (IOException ex) { - _logger.LogError(ex, "Error deleting partial stream file(s) {path}", path); + _logger.LogError(ex, "Error deleting partial stream file(s) {Path}", path); var task = Task.Delay(100); task.Wait(); @@ -1810,7 +1810,7 @@ namespace Jellyfin.Api.Controllers } catch (Exception ex) { - _logger.LogError(ex, "Error deleting partial stream file(s) {path}", path); + _logger.LogError(ex, "Error deleting partial stream file(s) {Path}", path); } } diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index db8307f284..16acedcf35 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -528,7 +528,7 @@ namespace Jellyfin.Api.Controllers if (fontFile != null && fileSize != null && fileSize > 0) { - _logger.LogDebug("Fallback font size is {fileSize} Bytes", fileSize); + _logger.LogDebug("Fallback font size is {FileSize} Bytes", fileSize); return PhysicalFile(fontFile.FullName, MimeTypes.GetMimeType(fontFile.FullName)); } else diff --git a/Jellyfin.Server.Implementations/Events/EventManager.cs b/Jellyfin.Server.Implementations/Events/EventManager.cs index 8c5d8f2ce6..7f7c4750d8 100644 --- a/Jellyfin.Server.Implementations/Events/EventManager.cs +++ b/Jellyfin.Server.Implementations/Events/EventManager.cs @@ -57,7 +57,7 @@ namespace Jellyfin.Server.Implementations.Events } catch (Exception e) { - _logger.LogError(e, "Uncaught exception in EventConsumer {type}: ", service.GetType()); + _logger.LogError(e, "Uncaught exception in EventConsumer {Type}: ", service.GetType()); } } } diff --git a/Jellyfin.Server/Middleware/ResponseTimeMiddleware.cs b/Jellyfin.Server/Middleware/ResponseTimeMiddleware.cs index 74874da1b0..da9b691365 100644 --- a/Jellyfin.Server/Middleware/ResponseTimeMiddleware.cs +++ b/Jellyfin.Server/Middleware/ResponseTimeMiddleware.cs @@ -68,7 +68,7 @@ namespace Jellyfin.Server.Middleware if (_enableWarning && watch.ElapsedMilliseconds > _warningThreshold) { _logger.LogWarning( - "Slow HTTP Response from {url} to {remoteIp} in {elapsed:g} with Status Code {statusCode}", + "Slow HTTP Response from {Url} to {RemoteIp} in {Elapsed:g} with Status Code {StatusCode}", context.Request.GetDisplayUrl(), context.GetNormalizedRemoteIp(), watch.Elapsed, diff --git a/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs b/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs index e4d2937e7e..2f1d791573 100644 --- a/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs +++ b/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs @@ -51,7 +51,7 @@ namespace Jellyfin.Server.Middleware return; } - if (!key.Contains('=')) + if (!key.Contains('=', StringComparison.Ordinal)) { _store = value; return; diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 5c7012d581..6e4c2280be 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -675,7 +675,7 @@ namespace Jellyfin.Server private static string NormalizeCommandLineArgument(string arg) { - if (!arg.Contains(" ", StringComparison.OrdinalIgnoreCase)) + if (!arg.Contains(' ', StringComparison.Ordinal)) { return arg; } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 63749b1f33..a76ca23055 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1452,7 +1452,7 @@ namespace MediaBrowser.Controller.Entities } catch (Exception ex) { - Logger.LogError(ex, "Error refreshing owned items for {path}", Path ?? Name); + Logger.LogError(ex, "Error refreshing owned items for {Path}", Path ?? Name); } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index fc6380e1ad..ffd1c7f0a6 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -303,7 +303,7 @@ namespace MediaBrowser.Controller.Entities if (dictionary.ContainsKey(id)) { Logger.LogError( - "Found folder containing items with duplicate id. Path: {path}, Child Name: {ChildName}", + "Found folder containing items with duplicate id. Path: {Path}, Child Name: {ChildName}", Path ?? Name, child.Path ?? child.Name); } diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs index b8a0bf3315..2429ac42db 100644 --- a/MediaBrowser.Controller/IO/FileData.cs +++ b/MediaBrowser.Controller/IO/FileData.cs @@ -69,7 +69,7 @@ namespace MediaBrowser.Controller.IO if (string.IsNullOrEmpty(newPath)) { // invalid shortcut - could be old or target could just be unavailable - logger.LogWarning("Encountered invalid shortcut: " + fullName); + logger.LogWarning("Encountered invalid shortcut: {Path}", fullName); continue; } @@ -83,7 +83,7 @@ namespace MediaBrowser.Controller.IO } catch (Exception ex) { - logger.LogError(ex, "Error resolving shortcut from {path}", fullName); + logger.LogError(ex, "Error resolving shortcut from {Path}", fullName); } } else if (flattenFolderDepth > 0 && isDirectory) diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 5e7af23fc3..1a8b5bb4ee 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -144,7 +144,7 @@ namespace MediaBrowser.LocalMetadata.Savers } catch (Exception ex) { - Logger.LogError(ex, "Error setting hidden attribute on {path}", path); + Logger.LogError(ex, "Error setting hidden attribute on {Path}", path); } } diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 1022a3faed..5e19856111 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -215,7 +215,7 @@ namespace MediaBrowser.Providers.Manager catch (Exception ex) { result.ErrorMessage = ex.Message; - _logger.LogError(ex, "Error in {provider}", provider.Name); + _logger.LogError(ex, "Error in {Provider}", provider.Name); } } @@ -331,7 +331,7 @@ namespace MediaBrowser.Providers.Manager catch (Exception ex) { result.ErrorMessage = ex.Message; - _logger.LogError(ex, "Error in {provider}", provider.Name); + _logger.LogError(ex, "Error in {Provider}", provider.Name); } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index ffb3baeb1f..90d14a9731 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -713,7 +713,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - Logger.LogError(ex, "Error in {provider}", provider.Name); + Logger.LogError(ex, "Error in {Provider}", provider.Name); // If a local provider fails, consider that a failure refreshResult.ErrorMessage = ex.Message; @@ -785,7 +785,7 @@ namespace MediaBrowser.Providers.Manager catch (Exception ex) { refreshResult.ErrorMessage = ex.Message; - Logger.LogError(ex, "Error in {provider}", provider.Name); + Logger.LogError(ex, "Error in {Provider}", provider.Name); } } @@ -837,7 +837,7 @@ namespace MediaBrowser.Providers.Manager { refreshResult.Failures++; refreshResult.ErrorMessage = ex.Message; - Logger.LogError(ex, "Error in {provider}", provider.Name); + Logger.LogError(ex, "Error in {Provider}", provider.Name); } } diff --git a/MediaBrowser.XbmcMetadata/EntryPoint.cs b/MediaBrowser.XbmcMetadata/EntryPoint.cs index d02aea5566..935ff5f59f 100644 --- a/MediaBrowser.XbmcMetadata/EntryPoint.cs +++ b/MediaBrowser.XbmcMetadata/EntryPoint.cs @@ -71,7 +71,7 @@ namespace MediaBrowser.XbmcMetadata } catch (Exception ex) { - _logger.LogError(ex, "Error saving metadata for {path}", item.Path ?? item.Name); + _logger.LogError(ex, "Error saving metadata for {Path}", item.Path ?? item.Name); } } } diff --git a/jellyfin.ruleset b/jellyfin.ruleset index dfb9911704..3bced438cd 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -42,6 +42,8 @@ + + @@ -77,6 +79,8 @@ + + @@ -90,6 +94,8 @@ + + diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs index 8273653637..3396a94e59 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs @@ -40,7 +40,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(MediaTypeNames.Text.Html, response.Content.Headers.ContentType?.MediaType); StreamReader reader = new StreamReader(typeof(TestPlugin).Assembly.GetManifestResourceStream("Jellyfin.Server.Integration.Tests.TestPage.html")!); - Assert.Equal(await response.Content.ReadAsStringAsync(), reader.ReadToEnd()); + Assert.Equal(await response.Content.ReadAsStringAsync().ConfigureAwait(false), await reader.ReadToEndAsync().ConfigureAwait(false)); } [Fact] -- cgit v1.2.3 From ce1c36dbf2c652121e4b797dd432059243251785 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Nov 2021 14:26:19 +0000 Subject: Bump Mono.Nat from 3.0.1 to 3.0.2 Bumps [Mono.Nat](https://github.com/mono/Mono.Nat) from 3.0.1 to 3.0.2. - [Release notes](https://github.com/mono/Mono.Nat/releases) - [Commits](https://github.com/mono/Mono.Nat/compare/release-v3.0.1...release-v3.0.2) --- updated-dependencies: - dependency-name: Mono.Nat dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 03f9f50eae..042b8f71a2 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -30,7 +30,7 @@ - + -- cgit v1.2.3 From 6bd108877e3ab999203869188170eed04b2d64c3 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Tue, 9 Nov 2021 17:12:33 +0000 Subject: Translated using Weblate (Russian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ru/ --- Emby.Server.Implementations/Localization/Core/ru.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/ru.json b/Emby.Server.Implementations/Localization/Core/ru.json index 36f4e3e7c9..2d7163275c 100644 --- a/Emby.Server.Implementations/Localization/Core/ru.json +++ b/Emby.Server.Implementations/Localization/Core/ru.json @@ -31,7 +31,7 @@ "ItemRemovedWithName": "{0} - изъято из медиатеки", "LabelIpAddressValue": "IP-адрес: {0}", "LabelRunningTimeValue": "Длительность: {0}", - "Latest": "Последнее", + "Latest": "Крайнее", "MessageApplicationUpdated": "Jellyfin Server был обновлён", "MessageApplicationUpdatedTo": "Jellyfin Server был обновлён до {0}", "MessageNamedServerConfigurationUpdatedWithValue": "Конфигурация сервера (раздел {0}) была обновлена", -- cgit v1.2.3 From 1d19a5be617c191a731b76e556fae1e395eb3788 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 9 Nov 2021 22:29:33 +0100 Subject: Fix some warnings down to 580 --- Emby.Dlna/DlnaManager.cs | 19 +--- Emby.Dlna/Main/DlnaEntryPoint.cs | 7 +- Emby.Server.Implementations/Dto/DtoService.cs | 7 +- Emby.Server.Implementations/IO/LibraryMonitor.cs | 2 +- .../Library/LibraryManager.cs | 3 +- .../Library/Resolvers/Audio/MusicAlbumResolver.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/EmbyTV/EncodedRecorder.cs | 5 +- .../ScheduledTasks/ScheduledTaskWorker.cs | 10 +- .../Updates/InstallationManager.cs | 2 +- Jellyfin.Api/Controllers/DynamicHlsController.cs | 2 +- Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 6 +- .../Models/PlaybackDtos/TranscodingThrottler.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 4 +- .../MediaEncoding/IMediaEncoder.cs | 26 ----- .../Parsers/BaseItemXmlParser.cs | 2 +- .../Attachments/AttachmentExtractor.cs | 7 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 117 +-------------------- .../Subtitles/SubtitleEncoder.cs | 11 +- .../Parsers/SeriesNfoParser.cs | 2 +- jellyfin.ruleset | 4 + 21 files changed, 38 insertions(+), 204 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index f37d2d7d7b..277a0e678e 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -112,7 +112,7 @@ namespace Emby.Dlna if (profile == null) { - LogUnmatchedProfile(deviceInfo); + _logger.LogInformation("No matching device profile found. The default will need to be used. \n{@Profile}", deviceInfo); } else { @@ -122,23 +122,6 @@ namespace Emby.Dlna return profile; } - private void LogUnmatchedProfile(DeviceIdentification profile) - { - var builder = new StringBuilder(); - - builder.AppendLine("No matching device profile found. The default will need to be used."); - builder.Append("FriendlyName: ").AppendLine(profile.FriendlyName); - builder.Append("Manufacturer: ").AppendLine(profile.Manufacturer); - builder.Append("ManufacturerUrl: ").AppendLine(profile.ManufacturerUrl); - builder.Append("ModelDescription: ").AppendLine(profile.ModelDescription); - builder.Append("ModelName: ").AppendLine(profile.ModelName); - builder.Append("ModelNumber: ").AppendLine(profile.ModelNumber); - builder.Append("ModelUrl: ").AppendLine(profile.ModelUrl); - builder.Append("SerialNumber: ").AppendLine(profile.SerialNumber); - - _logger.LogInformation(builder.ToString()); - } - /// /// Attempts to match a device with a profile. /// Rules: diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index 8e89d9ae6a..722428c737 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -218,11 +218,6 @@ namespace Emby.Dlna.Main } } - private void LogMessage(string msg) - { - _logger.LogDebug(msg); - } - private void StartDeviceDiscovery(ISsdpCommunicationsServer communicationsServer) { try @@ -272,7 +267,7 @@ namespace Emby.Dlna.Main Environment.OSVersion.VersionString, _config.GetDlnaConfiguration().SendOnlyMatchedHost) { - LogFunction = LogMessage, + LogFunction = (msg) => _logger.LogDebug("{Msg}", msg), SupportPnpRootDevice = false }; diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index c6b32a52c9..67ecd04e0e 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -134,14 +134,11 @@ namespace Emby.Server.Implementations.Dto var dto = GetBaseItemDtoInternal(item, options, user, owner); if (item is LiveTvChannel tvChannel) { - var list = new List<(BaseItemDto, LiveTvChannel)>(1) { (dto, tvChannel) }; - LivetvManager.AddChannelInfo(list, options, user); + LivetvManager.AddChannelInfo(new[] { (dto, tvChannel) }, options, user); } else if (item is LiveTvProgram) { - var list = new List<(BaseItem, BaseItemDto)>(1) { (item, dto) }; - var task = LivetvManager.AddInfoToProgramDto(list, options.Fields, user); - Task.WaitAll(task); + LivetvManager.AddInfoToProgramDto(new[] { (item, dto) }, options.Fields, user).GetAwaiter().GetResult(); } if (item is IItemByName itemByName diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index 7ebc800b9a..b525f5a2f8 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -267,7 +267,7 @@ namespace Emby.Server.Implementations.IO if (_fileSystemWatchers.TryAdd(path, newWatcher)) { newWatcher.EnableRaisingEvents = true; - _logger.LogInformation("Watching directory " + path); + _logger.LogInformation("Watching directory {Path}", path); } else { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 2dbb569c63..559da7f5cc 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -333,8 +333,7 @@ namespace Emby.Server.Implementations.Library { try { - var task = BaseItem.ChannelManager.DeleteItem(item); - Task.WaitAll(task); + BaseItem.ChannelManager.DeleteItem(item).GetAwaiter().GetResult(); } catch (ArgumentException) { diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 60720dd2f7..9e3f622766 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -151,7 +151,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio { if (parser.IsMultiPart(path)) { - logger.LogDebug("Found multi-disc folder: " + path); + logger.LogDebug("Found multi-disc folder: {Path}", path); Interlocked.Increment(ref discSubfolderCount); } else diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 367f3cb9ed..644f9050d6 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -957,7 +957,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV public async Task GetChannelStreamWithDirectStreamProvider(string channelId, string streamId, List currentLiveStreams, CancellationToken cancellationToken) { - _logger.LogInformation("Streaming Channel " + channelId); + _logger.LogInformation("Streaming Channel {Id}", channelId); var result = string.IsNullOrEmpty(streamId) ? null : diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 8688688e92..5726d7158f 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -87,8 +87,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV ErrorDialog = false }; - var commandLineLogMessage = processStartInfo.FileName + " " + processStartInfo.Arguments; - _logger.LogInformation(commandLineLogMessage); + _logger.LogInformation("{Filename} {Arguments}", processStartInfo.FileName, processStartInfo.Arguments); var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "record-transcode-" + Guid.NewGuid() + ".txt"); Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); @@ -97,7 +96,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _logFileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); - await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); + await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + processStartInfo.FileName + " " + processStartInfo.Arguments + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); _process = new Process { diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index f2cdfeb16c..21a7f4f5f2 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -638,7 +638,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - _logger.LogInformation(Name + ": Cancelling"); + _logger.LogInformation("{Name}: Cancelling", Name); token.Cancel(); } catch (Exception ex) @@ -652,16 +652,16 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - _logger.LogInformation(Name + ": Waiting on Task"); + _logger.LogInformation("{Name}: Waiting on Task", Name); var exited = task.Wait(2000); if (exited) { - _logger.LogInformation(Name + ": Task exited"); + _logger.LogInformation("{Name}: Task exited", Name); } else { - _logger.LogInformation(Name + ": Timed out waiting for task to stop"); + _logger.LogInformation("{Name}: Timed out waiting for task to stop", Name); } } catch (Exception ex) @@ -674,7 +674,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - _logger.LogDebug(Name + ": Disposing CancellationToken"); + _logger.LogDebug("{Name}: Disposing CancellationToken", Name); token.Dispose(); } catch (Exception ex) diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 4a022c5dbc..ef95ebf943 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -571,7 +571,7 @@ namespace Emby.Server.Implementations.Updates ?? _pluginManager.Plugins.FirstOrDefault(p => p.Name.Equals(package.Name, StringComparison.OrdinalIgnoreCase) && p.Version.Equals(package.Version)); await PerformPackageInstallation(package, plugin?.Manifest.Status ?? PluginStatus.Active, cancellationToken).ConfigureAwait(false); - _logger.LogInformation(plugin == null ? "New plugin installed: {PluginName} {PluginVersion}" : "Plugin updated: {PluginName} {PluginVersion}", package.Name, package.Version); + _logger.LogInformation("Plugin {Action}: {PluginName} {PluginVersion}", plugin == null ? "installed" : "updated", package.Name, package.Version); return plugin != null; } diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 049fd503bd..caa3d23681 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1391,7 +1391,7 @@ namespace Jellyfin.Api.Controllers } else { - _logger.LogError("Invalid HLS segment container: " + segmentFormat); + _logger.LogError("Invalid HLS segment container: {SegmentFormat}", segmentFormat); } var maxMuxingQueueSize = _encodingOptions.MaxMuxingQueueSize > 128 diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index f435bbf00e..9d80070ebf 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -543,8 +543,7 @@ namespace Jellyfin.Api.Helpers state, cancellationTokenSource); - var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments; - _logger.LogInformation(commandLineLogMessage); + _logger.LogInformation("{Filename} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); var logFilePrefix = "FFmpeg.Transcode-"; if (state.VideoRequest != null @@ -562,8 +561,9 @@ namespace Jellyfin.Api.Helpers // FFmpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments; var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(request.Path + Environment.NewLine + Environment.NewLine + JsonSerializer.Serialize(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); - await logStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false); + await logStream.WriteAsync(commandLineLogMessageBytes, cancellationTokenSource.Token).ConfigureAwait(false); process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state); diff --git a/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs b/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs index 7b32d76ba7..0136d9f86c 100644 --- a/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs +++ b/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs @@ -197,7 +197,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos } } - _logger.LogDebug("No throttle data for " + path); + _logger.LogDebug("No throttle data for {Path}", path); return false; } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index ffd1c7f0a6..ec1ebaabec 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -425,7 +425,7 @@ namespace MediaBrowser.Controller.Entities { if (item.IsFileProtocol) { - Logger.LogDebug("Removed item: " + item.Path); + Logger.LogDebug("Removed item: {Path}", item.Path); item.SetParent(null); LibraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }, this, false); @@ -807,7 +807,7 @@ namespace MediaBrowser.Controller.Entities { if (this is not ICollectionFolder) { - Logger.LogDebug("Query requires post-filtering due to LinkedChildren. Type: " + GetType().Name); + Logger.LogDebug("{Type}: Query requires post-filtering due to LinkedChildren.", GetType().Name); return true; } } diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index e6511ca8d7..7d62fb6e13 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -100,32 +100,6 @@ namespace MediaBrowser.Controller.MediaEncoding /// Location of video image. Task ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, string outputExtension, CancellationToken cancellationToken); - /// - /// Extracts the video images on interval. - /// - /// Input file. - /// Video container type. - /// Media stream information. - /// Media source information. - /// Video 3D format. - /// Time interval. - /// Directory to write images. - /// Filename prefix to use. - /// Maximum width of image. - /// CancellationToken to use for operation. - /// A task. - Task ExtractVideoImagesOnInterval( - string inputFile, - string container, - MediaStream videoStream, - MediaSourceInfo mediaSource, - Video3DFormat? threedFormat, - TimeSpan interval, - string targetDirectory, - string filenamePrefix, - int? maxWidth, - CancellationToken cancellationToken); - /// /// Gets the media info. /// diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index 80eb454239..777fe67746 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -149,7 +149,7 @@ namespace MediaBrowser.LocalMetadata.Parsers } else { - Logger.LogWarning("Invalid Added value found: " + val); + Logger.LogWarning("Invalid Added value found: {Value}", val); } } diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index a524aeaa98..9ebc0d0cff 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -223,11 +223,10 @@ namespace MediaBrowser.MediaEncoding.Attachments if (failed) { - var msg = $"ffmpeg attachment extraction failed for {inputPath} to {outputPath}"; + _logger.LogError("ffmpeg attachment extraction failed for {InputPath} to {OutputPath}", inputPath, outputPath); - _logger.LogError(msg); - - throw new InvalidOperationException(msg); + throw new InvalidOperationException( + string.Format(CultureInfo.InvariantCulture, "ffmpeg attachment extraction failed for {0} to {1}", inputPath, outputPath)); } else { diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index fbc7ba72f0..a2bac7b49a 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -682,11 +682,9 @@ namespace MediaBrowser.MediaEncoding.Encoder if (exitCode == -1 || !file.Exists || file.Length == 0) { - var msg = string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputPath); + _logger.LogError("ffmpeg image extraction failed for {Path}", inputPath); - _logger.LogError(msg); - - throw new FfmpegException(msg); + throw new FfmpegException(string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputPath)); } return tempExtractPath; @@ -705,117 +703,6 @@ namespace MediaBrowser.MediaEncoding.Encoder return time.ToString(@"hh\:mm\:ss\.fff", CultureInfo.InvariantCulture); } - public async Task ExtractVideoImagesOnInterval( - string inputFile, - string container, - MediaStream videoStream, - MediaSourceInfo mediaSource, - Video3DFormat? threedFormat, - TimeSpan interval, - string targetDirectory, - string filenamePrefix, - int? maxWidth, - CancellationToken cancellationToken) - { - var inputArgument = GetInputArgument(inputFile, mediaSource); - - var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(CultureInfo.InvariantCulture); - - if (maxWidth.HasValue) - { - var maxWidthParam = maxWidth.Value.ToString(CultureInfo.InvariantCulture); - - vf += string.Format(CultureInfo.InvariantCulture, ",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam); - } - - Directory.CreateDirectory(targetDirectory); - var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg"); - - var args = string.Format(CultureInfo.InvariantCulture, "-i {0} -threads {3} -v quiet {2} -f image2 \"{1}\"", inputArgument, outputPath, vf, _threads); - - if (!string.IsNullOrWhiteSpace(container)) - { - var inputFormat = EncodingHelper.GetInputFormat(container); - if (!string.IsNullOrWhiteSpace(inputFormat)) - { - args = "-f " + inputFormat + " " + args; - } - } - - var processStartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - FileName = _ffmpegPath, - Arguments = args, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }; - - _logger.LogInformation(processStartInfo.FileName + " " + processStartInfo.Arguments); - - await _thumbnailResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - - bool ranToCompletion = false; - - var process = new Process - { - StartInfo = processStartInfo, - EnableRaisingEvents = true - }; - using (var processWrapper = new ProcessWrapper(process, this)) - { - try - { - StartProcess(processWrapper); - - // Need to give ffmpeg enough time to make all the thumbnails, which could be a while, - // but we still need to detect if the process hangs. - // Making the assumption that as long as new jpegs are showing up, everything is good. - - bool isResponsive = true; - int lastCount = 0; - - while (isResponsive) - { - if (await process.WaitForExitAsync(TimeSpan.FromSeconds(30)).ConfigureAwait(false)) - { - ranToCompletion = true; - break; - } - - cancellationToken.ThrowIfCancellationRequested(); - - var jpegCount = _fileSystem.GetFilePaths(targetDirectory) - .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase)); - - isResponsive = jpegCount > lastCount; - lastCount = jpegCount; - } - - if (!ranToCompletion) - { - StopProcess(processWrapper, 1000); - } - } - finally - { - _thumbnailResourcePool.Release(); - } - - var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; - - if (exitCode == -1) - { - var msg = string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputArgument); - - _logger.LogError(msg); - - throw new FfmpegException(msg); - } - } - } - private void StartProcess(ProcessWrapper process) { process.Process.Start(); diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 2b2de2ff6f..89365a516c 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -636,17 +636,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (failed) { - var msg = $"ffmpeg subtitle extraction failed for {inputPath} to {outputPath}"; + _logger.LogError("ffmpeg subtitle extraction failed for {InputPath} to {OutputPath}", inputPath, outputPath); - _logger.LogError(msg); - - throw new FfmpegException(msg); + throw new FfmpegException( + string.Format(CultureInfo.InvariantCulture, "ffmpeg subtitle extraction failed for {0} to {1}", inputPath, outputPath)); } else { - var msg = $"ffmpeg subtitle extraction completed for {inputPath} to {outputPath}"; - - _logger.LogInformation(msg); + _logger.LogInformation("ffmpeg subtitle extraction completed for {InputPath} to {OutputPath}", inputPath, outputPath); } if (string.Equals(outputCodec, "ass", StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs index 2c893ac9f0..3011d65a6d 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs @@ -103,7 +103,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers } else { - Logger.LogInformation("Unrecognized series status: " + status); + Logger.LogInformation("Unrecognized series status: {Status}", status); } } diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 3bced438cd..e14c1c4270 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -44,9 +44,13 @@ + + + + -- cgit v1.2.3 From 5265b3eee794762b4de39a68b5bfbf767faaac36 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 10 Nov 2021 22:34:54 +0100 Subject: Replace PBKDF2-SHA1 with PBKDF2-SHA512 This also migrates already created passwords on login Source for the number of iterations: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2 --- .../Cryptography/CryptographyProvider.cs | 90 +++++---- .../LiveTv/Listings/SchedulesDirect.cs | 3 +- .../Users/DefaultAuthenticationProvider.cs | 35 ++-- .../Users/UserManager.cs | 8 +- MediaBrowser.Common/Cryptography/Constants.cs | 18 -- .../Cryptography/CryptoExtensions.cs | 35 ---- MediaBrowser.Common/Cryptography/PasswordHash.cs | 219 --------------------- MediaBrowser.Model/Cryptography/Constants.cs | 23 +++ MediaBrowser.Model/Cryptography/ICryptoProvider.cs | 13 +- MediaBrowser.Model/Cryptography/PasswordHash.cs | 219 +++++++++++++++++++++ .../Cryptography/PasswordHashTests.cs | 169 ---------------- .../Cryptography/PasswordHashTests.cs | 169 ++++++++++++++++ 12 files changed, 488 insertions(+), 513 deletions(-) delete mode 100644 MediaBrowser.Common/Cryptography/Constants.cs delete mode 100644 MediaBrowser.Common/Cryptography/CryptoExtensions.cs delete mode 100644 MediaBrowser.Common/Cryptography/PasswordHash.cs create mode 100644 MediaBrowser.Model/Cryptography/Constants.cs create mode 100644 MediaBrowser.Model/Cryptography/PasswordHash.cs delete mode 100644 tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs create mode 100644 tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs index 673810c49d..e9c005cea4 100644 --- a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs +++ b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Security.Cryptography; +using System.Text; using MediaBrowser.Common.Extensions; using MediaBrowser.Model.Cryptography; -using static MediaBrowser.Common.Cryptography.Constants; +using static MediaBrowser.Model.Cryptography.Constants; namespace Emby.Server.Implementations.Cryptography { @@ -12,10 +14,7 @@ namespace Emby.Server.Implementations.Cryptography /// public class CryptographyProvider : ICryptoProvider { - // FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto - // Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1 - // there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one - // Please note the default method of PBKDF2 is not included, it cannot be used to generate hashes cleanly as it is actually a pbkdf with sha1 + // TODO: remove when not needed for backwards compat private static readonly HashSet _supportedHashMethods = new HashSet() { "MD5", @@ -35,60 +34,81 @@ namespace Emby.Server.Implementations.Cryptography }; /// - public string DefaultHashMethod => "PBKDF2"; + public string DefaultHashMethod => "PBKDF2-SHA512"; /// - public IEnumerable GetSupportedHashMethods() - => _supportedHashMethods; - - private byte[] PBKDF2(string method, byte[] bytes, byte[] salt, int iterations) + public PasswordHash CreatePasswordHash(ReadOnlySpan password) { - // downgrading for now as we need this library to be dotnetstandard compliant - // with this downgrade we'll add a check to make sure we're on the downgrade method at the moment - if (method != DefaultHashMethod) - { - throw new CryptographicException($"Cannot currently use PBKDF2 with requested hash method: {method}"); - } - - using var r = new Rfc2898DeriveBytes(bytes, salt, iterations); - return r.GetBytes(32); + byte[] salt = GenerateSalt(); + return new PasswordHash( + DefaultHashMethod, + Rfc2898DeriveBytes.Pbkdf2( + password, + salt, + DefaultIterations, + HashAlgorithmName.SHA512, + DefaultOutputLength), + salt, + new Dictionary + { + { "iterations", DefaultIterations.ToString(CultureInfo.InvariantCulture) } + }); } /// - public byte[] ComputeHash(string hashMethod, byte[] bytes, byte[] salt) + public bool Verify(PasswordHash hash, ReadOnlySpan password) { - if (hashMethod == DefaultHashMethod) + if (string.Equals(hash.Id, "PBKDF2", StringComparison.Ordinal)) { - return PBKDF2(hashMethod, bytes, salt, DefaultIterations); + return hash.Hash.SequenceEqual( + Rfc2898DeriveBytes.Pbkdf2( + password, + hash.Salt, + int.Parse(hash.Parameters["iterations"], CultureInfo.InvariantCulture), + HashAlgorithmName.SHA1, + 32)); } - if (!_supportedHashMethods.Contains(hashMethod)) + if (string.Equals(hash.Id, "PBKDF2-SHA512", StringComparison.Ordinal)) { - throw new CryptographicException($"Requested hash method is not supported: {hashMethod}"); + return hash.Hash.SequenceEqual( + Rfc2898DeriveBytes.Pbkdf2( + password, + hash.Salt, + int.Parse(hash.Parameters["iterations"], CultureInfo.InvariantCulture), + HashAlgorithmName.SHA512, + DefaultOutputLength)); } - using var h = HashAlgorithm.Create(hashMethod) ?? throw new ResourceNotFoundException($"Unknown hash method: {hashMethod}."); - if (salt.Length == 0) + if (!_supportedHashMethods.Contains(hash.Id)) { - return h.ComputeHash(bytes); + throw new CryptographicException($"Requested hash method is not supported: {hash.Id}"); } - byte[] salted = new byte[bytes.Length + salt.Length]; + using var h = HashAlgorithm.Create(hash.Id) ?? throw new ResourceNotFoundException($"Unknown hash method: {hash.Id}."); + var bytes = Encoding.UTF8.GetBytes(password.ToArray()); + if (hash.Salt.Length == 0) + { + return hash.Hash.SequenceEqual(h.ComputeHash(bytes)); + } + + byte[] salted = new byte[bytes.Length + hash.Salt.Length]; Array.Copy(bytes, salted, bytes.Length); - Array.Copy(salt, 0, salted, bytes.Length, salt.Length); - return h.ComputeHash(salted); + hash.Salt.CopyTo(salted.AsSpan(bytes.Length)); + return hash.Hash.SequenceEqual(h.ComputeHash(salted)); } - /// - public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt) - => PBKDF2(DefaultHashMethod, bytes, salt, DefaultIterations); - /// public byte[] GenerateSalt() => GenerateSalt(DefaultSaltLength); /// public byte[] GenerateSalt(int length) - => RandomNumberGenerator.GetBytes(length); + { + var salt = new byte[length]; + using var rng = RandomNumberGenerator.Create(); + rng.GetNonZeroBytes(salt); + return salt; + } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 1f963e4a29..615539db3c 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -11,6 +11,7 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Mime; +using System.Security.Cryptography; using System.Text; using System.Text.Json; using System.Threading; @@ -648,7 +649,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings CancellationToken cancellationToken) { using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/token"); - var hashedPasswordBytes = _cryptoProvider.ComputeHash("SHA1", Encoding.ASCII.GetBytes(password), Array.Empty()); + var hashedPasswordBytes = SHA1.HashData(Encoding.ASCII.GetBytes(password)); // TODO: remove ToLower when Convert.ToHexString supports lowercase // Schedules Direct requires the hex to be lowercase string hashedPassword = Convert.ToHexString(hashedPasswordBytes).ToLowerInvariant(); diff --git a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs index 6a78e7ee6f..7480a05c25 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs @@ -1,9 +1,6 @@ using System; -using System.Linq; -using System.Text; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using MediaBrowser.Common.Cryptography; using MediaBrowser.Controller.Authentication; using MediaBrowser.Model.Cryptography; @@ -61,35 +58,25 @@ namespace Jellyfin.Server.Implementations.Users } // Handle the case when the stored password is null, but the user tried to login with a password - if (resolvedUser.Password != null) + if (resolvedUser.Password == null) { - byte[] passwordBytes = Encoding.UTF8.GetBytes(password); - - PasswordHash readyHash = PasswordHash.Parse(resolvedUser.Password); - if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id) - || _cryptographyProvider.DefaultHashMethod == readyHash.Id) - { - byte[] calculatedHash = _cryptographyProvider.ComputeHash( - readyHash.Id, - passwordBytes, - readyHash.Salt.ToArray()); - - if (readyHash.Hash.SequenceEqual(calculatedHash)) - { - success = true; - } - } - else - { - throw new AuthenticationException($"Requested crypto method not available in provider: {readyHash.Id}"); - } + throw new AuthenticationException("Invalid username or password"); } + PasswordHash readyHash = PasswordHash.Parse(resolvedUser.Password); + success = _cryptographyProvider.Verify(readyHash, password); + if (!success) { throw new AuthenticationException("Invalid username or password"); } + // Migrate old hashes to the new default + if (!string.Equals(readyHash.Id, _cryptographyProvider.DefaultHashMethod, StringComparison.Ordinal)) + { + ChangePassword(resolvedUser, password); + } + return Task.FromResult(new ProviderAuthenticationResult { Username = username diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 8ca6e8d21b..3d0a51ff67 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -5,7 +5,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using Jellyfin.Data.Entities; @@ -13,7 +12,6 @@ using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Events.Users; using MediaBrowser.Common; -using MediaBrowser.Common.Cryptography; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Authentication; @@ -818,11 +816,7 @@ namespace Jellyfin.Server.Implementations.Users { // Check easy password var passwordHash = PasswordHash.Parse(user.EasyPassword); - var hash = _cryptoProvider.ComputeHash( - passwordHash.Id, - Encoding.UTF8.GetBytes(password), - passwordHash.Salt.ToArray()); - success = passwordHash.Hash.SequenceEqual(hash); + success = _cryptoProvider.Verify(passwordHash, password); } return (authenticationProvider, username, success); diff --git a/MediaBrowser.Common/Cryptography/Constants.cs b/MediaBrowser.Common/Cryptography/Constants.cs deleted file mode 100644 index 3541142327..0000000000 --- a/MediaBrowser.Common/Cryptography/Constants.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace MediaBrowser.Common.Cryptography -{ - /// - /// Class containing global constants for Jellyfin Cryptography. - /// - public static class Constants - { - /// - /// The default length for new salts. - /// - public const int DefaultSaltLength = 64; - - /// - /// The default amount of iterations for hashing passwords. - /// - public const int DefaultIterations = 1000; - } -} diff --git a/MediaBrowser.Common/Cryptography/CryptoExtensions.cs b/MediaBrowser.Common/Cryptography/CryptoExtensions.cs deleted file mode 100644 index 157b0ed100..0000000000 --- a/MediaBrowser.Common/Cryptography/CryptoExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using MediaBrowser.Model.Cryptography; -using static MediaBrowser.Common.Cryptography.Constants; - -namespace MediaBrowser.Common.Cryptography -{ - /// - /// Class containing extension methods for working with Jellyfin cryptography objects. - /// - public static class CryptoExtensions - { - /// - /// Creates a new instance. - /// - /// The instance used. - /// The password that will be hashed. - /// A instance with the hash method, hash, salt and number of iterations. - public static PasswordHash CreatePasswordHash(this ICryptoProvider cryptoProvider, string password) - { - byte[] salt = cryptoProvider.GenerateSalt(); - return new PasswordHash( - cryptoProvider.DefaultHashMethod, - cryptoProvider.ComputeHashWithDefaultMethod( - Encoding.UTF8.GetBytes(password), - salt), - salt, - new Dictionary - { - { "iterations", DefaultIterations.ToString(CultureInfo.InvariantCulture) } - }); - } - } -} diff --git a/MediaBrowser.Common/Cryptography/PasswordHash.cs b/MediaBrowser.Common/Cryptography/PasswordHash.cs deleted file mode 100644 index 0e20653029..0000000000 --- a/MediaBrowser.Common/Cryptography/PasswordHash.cs +++ /dev/null @@ -1,219 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Text; - -namespace MediaBrowser.Common.Cryptography -{ - // Defined from this hash storage spec - // https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md - // $[$=(,=)*][$[$]] - // with one slight amendment to ease the transition, we're writing out the bytes in hex - // rather than making them a BASE64 string with stripped padding - public class PasswordHash - { - private readonly Dictionary _parameters; - private readonly byte[] _salt; - private readonly byte[] _hash; - - public PasswordHash(string id, byte[] hash) - : this(id, hash, Array.Empty()) - { - } - - public PasswordHash(string id, byte[] hash, byte[] salt) - : this(id, hash, salt, new Dictionary()) - { - } - - public PasswordHash(string id, byte[] hash, byte[] salt, Dictionary parameters) - { - if (id == null) - { - throw new ArgumentNullException(nameof(id)); - } - - if (id.Length == 0) - { - throw new ArgumentException("String can't be empty", nameof(id)); - } - - Id = id; - _hash = hash; - _salt = salt; - _parameters = parameters; - } - - /// - /// Gets the symbolic name for the function used. - /// - /// Returns the symbolic name for the function used. - public string Id { get; } - - /// - /// Gets the additional parameters used by the hash function. - /// - public IReadOnlyDictionary Parameters => _parameters; - - /// - /// Gets the salt used for hashing the password. - /// - /// Returns the salt used for hashing the password. - public ReadOnlySpan Salt => _salt; - - /// - /// Gets the hashed password. - /// - /// Return the hashed password. - public ReadOnlySpan Hash => _hash; - - public static PasswordHash Parse(ReadOnlySpan hashString) - { - if (hashString.IsEmpty) - { - throw new ArgumentException("String can't be empty", nameof(hashString)); - } - - if (hashString[0] != '$') - { - throw new FormatException("Hash string must start with a $"); - } - - // Ignore first $ - hashString = hashString[1..]; - - int nextSegment = hashString.IndexOf('$'); - if (hashString.IsEmpty || nextSegment == 0) - { - throw new FormatException("Hash string must contain a valid id"); - } - else if (nextSegment == -1) - { - return new PasswordHash(hashString.ToString(), Array.Empty()); - } - - ReadOnlySpan id = hashString[..nextSegment]; - hashString = hashString[(nextSegment + 1)..]; - Dictionary? parameters = null; - - nextSegment = hashString.IndexOf('$'); - - // Optional parameters - ReadOnlySpan parametersSpan = nextSegment == -1 ? hashString : hashString[..nextSegment]; - if (parametersSpan.Contains('=')) - { - while (!parametersSpan.IsEmpty) - { - ReadOnlySpan parameter; - int index = parametersSpan.IndexOf(','); - if (index == -1) - { - parameter = parametersSpan; - parametersSpan = ReadOnlySpan.Empty; - } - else - { - parameter = parametersSpan[..index]; - parametersSpan = parametersSpan[(index + 1)..]; - } - - int splitIndex = parameter.IndexOf('='); - if (splitIndex == -1 || splitIndex == 0 || splitIndex == parameter.Length - 1) - { - throw new FormatException("Malformed parameter in password hash string"); - } - - (parameters ??= new Dictionary()).Add( - parameter[..splitIndex].ToString(), - parameter[(splitIndex + 1)..].ToString()); - } - - if (nextSegment == -1) - { - // parameters can't be null here - return new PasswordHash(id.ToString(), Array.Empty(), Array.Empty(), parameters!); - } - - hashString = hashString[(nextSegment + 1)..]; - nextSegment = hashString.IndexOf('$'); - } - - if (nextSegment == 0) - { - throw new FormatException("Hash string contains an empty segment"); - } - - byte[] hash; - byte[] salt; - - if (nextSegment == -1) - { - salt = Array.Empty(); - hash = Convert.FromHexString(hashString); - } - else - { - salt = Convert.FromHexString(hashString[..nextSegment]); - hashString = hashString[(nextSegment + 1)..]; - nextSegment = hashString.IndexOf('$'); - if (nextSegment != -1) - { - throw new FormatException("Hash string contains too many segments"); - } - - if (hashString.IsEmpty) - { - throw new FormatException("Hash segment is empty"); - } - - hash = Convert.FromHexString(hashString); - } - - return new PasswordHash(id.ToString(), hash, salt, parameters ?? new Dictionary()); - } - - private void SerializeParameters(StringBuilder stringBuilder) - { - if (_parameters.Count == 0) - { - return; - } - - stringBuilder.Append('$'); - foreach (var pair in _parameters) - { - stringBuilder.Append(pair.Key) - .Append('=') - .Append(pair.Value) - .Append(','); - } - - // Remove last ',' - stringBuilder.Length -= 1; - } - - /// - public override string ToString() - { - var str = new StringBuilder() - .Append('$') - .Append(Id); - SerializeParameters(str); - - if (_salt.Length != 0) - { - str.Append('$') - .Append(Convert.ToHexString(_salt)); - } - - if (_hash.Length != 0) - { - str.Append('$') - .Append(Convert.ToHexString(_hash)); - } - - return str.ToString(); - } - } -} diff --git a/MediaBrowser.Model/Cryptography/Constants.cs b/MediaBrowser.Model/Cryptography/Constants.cs new file mode 100644 index 0000000000..f2ebb5d3d1 --- /dev/null +++ b/MediaBrowser.Model/Cryptography/Constants.cs @@ -0,0 +1,23 @@ +namespace MediaBrowser.Model.Cryptography +{ + /// + /// Class containing global constants for Jellyfin Cryptography. + /// + public static class Constants + { + /// + /// The default length for new salts. + /// + public const int DefaultSaltLength = 128 / 8; + + /// + /// The default output length. + /// + public const int DefaultOutputLength = 512 / 8; + + /// + /// The default amount of iterations for hashing passwords. + /// + public const int DefaultIterations = 120000; + } +} diff --git a/MediaBrowser.Model/Cryptography/ICryptoProvider.cs b/MediaBrowser.Model/Cryptography/ICryptoProvider.cs index d8b7d848a2..6c521578c5 100644 --- a/MediaBrowser.Model/Cryptography/ICryptoProvider.cs +++ b/MediaBrowser.Model/Cryptography/ICryptoProvider.cs @@ -1,6 +1,6 @@ #pragma warning disable CS1591 -using System.Collections.Generic; +using System; namespace MediaBrowser.Model.Cryptography { @@ -8,11 +8,14 @@ namespace MediaBrowser.Model.Cryptography { string DefaultHashMethod { get; } - IEnumerable GetSupportedHashMethods(); + /// + /// Creates a new instance. + /// + /// The password that will be hashed. + /// A instance with the hash method, hash, salt and number of iterations. + PasswordHash CreatePasswordHash(ReadOnlySpan password); - byte[] ComputeHash(string hashMethod, byte[] bytes, byte[] salt); - - byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt); + bool Verify(PasswordHash hash, ReadOnlySpan password); byte[] GenerateSalt(); diff --git a/MediaBrowser.Model/Cryptography/PasswordHash.cs b/MediaBrowser.Model/Cryptography/PasswordHash.cs new file mode 100644 index 0000000000..eec5410411 --- /dev/null +++ b/MediaBrowser.Model/Cryptography/PasswordHash.cs @@ -0,0 +1,219 @@ +#pragma warning disable CS1591 + +using System; +using System.Collections.Generic; +using System.Text; + +namespace MediaBrowser.Model.Cryptography +{ + // Defined from this hash storage spec + // https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md + // $[$=(,=)*][$[$]] + // with one slight amendment to ease the transition, we're writing out the bytes in hex + // rather than making them a BASE64 string with stripped padding + public class PasswordHash + { + private readonly Dictionary _parameters; + private readonly byte[] _salt; + private readonly byte[] _hash; + + public PasswordHash(string id, byte[] hash) + : this(id, hash, Array.Empty()) + { + } + + public PasswordHash(string id, byte[] hash, byte[] salt) + : this(id, hash, salt, new Dictionary()) + { + } + + public PasswordHash(string id, byte[] hash, byte[] salt, Dictionary parameters) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + if (id.Length == 0) + { + throw new ArgumentException("String can't be empty", nameof(id)); + } + + Id = id; + _hash = hash; + _salt = salt; + _parameters = parameters; + } + + /// + /// Gets the symbolic name for the function used. + /// + /// Returns the symbolic name for the function used. + public string Id { get; } + + /// + /// Gets the additional parameters used by the hash function. + /// + public IReadOnlyDictionary Parameters => _parameters; + + /// + /// Gets the salt used for hashing the password. + /// + /// Returns the salt used for hashing the password. + public ReadOnlySpan Salt => _salt; + + /// + /// Gets the hashed password. + /// + /// Return the hashed password. + public ReadOnlySpan Hash => _hash; + + public static PasswordHash Parse(ReadOnlySpan hashString) + { + if (hashString.IsEmpty) + { + throw new ArgumentException("String can't be empty", nameof(hashString)); + } + + if (hashString[0] != '$') + { + throw new FormatException("Hash string must start with a $"); + } + + // Ignore first $ + hashString = hashString[1..]; + + int nextSegment = hashString.IndexOf('$'); + if (hashString.IsEmpty || nextSegment == 0) + { + throw new FormatException("Hash string must contain a valid id"); + } + else if (nextSegment == -1) + { + return new PasswordHash(hashString.ToString(), Array.Empty()); + } + + ReadOnlySpan id = hashString[..nextSegment]; + hashString = hashString[(nextSegment + 1)..]; + Dictionary? parameters = null; + + nextSegment = hashString.IndexOf('$'); + + // Optional parameters + ReadOnlySpan parametersSpan = nextSegment == -1 ? hashString : hashString[..nextSegment]; + if (parametersSpan.Contains('=')) + { + while (!parametersSpan.IsEmpty) + { + ReadOnlySpan parameter; + int index = parametersSpan.IndexOf(','); + if (index == -1) + { + parameter = parametersSpan; + parametersSpan = ReadOnlySpan.Empty; + } + else + { + parameter = parametersSpan[..index]; + parametersSpan = parametersSpan[(index + 1)..]; + } + + int splitIndex = parameter.IndexOf('='); + if (splitIndex == -1 || splitIndex == 0 || splitIndex == parameter.Length - 1) + { + throw new FormatException("Malformed parameter in password hash string"); + } + + (parameters ??= new Dictionary()).Add( + parameter[..splitIndex].ToString(), + parameter[(splitIndex + 1)..].ToString()); + } + + if (nextSegment == -1) + { + // parameters can't be null here + return new PasswordHash(id.ToString(), Array.Empty(), Array.Empty(), parameters!); + } + + hashString = hashString[(nextSegment + 1)..]; + nextSegment = hashString.IndexOf('$'); + } + + if (nextSegment == 0) + { + throw new FormatException("Hash string contains an empty segment"); + } + + byte[] hash; + byte[] salt; + + if (nextSegment == -1) + { + salt = Array.Empty(); + hash = Convert.FromHexString(hashString); + } + else + { + salt = Convert.FromHexString(hashString[..nextSegment]); + hashString = hashString[(nextSegment + 1)..]; + nextSegment = hashString.IndexOf('$'); + if (nextSegment != -1) + { + throw new FormatException("Hash string contains too many segments"); + } + + if (hashString.IsEmpty) + { + throw new FormatException("Hash segment is empty"); + } + + hash = Convert.FromHexString(hashString); + } + + return new PasswordHash(id.ToString(), hash, salt, parameters ?? new Dictionary()); + } + + private void SerializeParameters(StringBuilder stringBuilder) + { + if (_parameters.Count == 0) + { + return; + } + + stringBuilder.Append('$'); + foreach (var pair in _parameters) + { + stringBuilder.Append(pair.Key) + .Append('=') + .Append(pair.Value) + .Append(','); + } + + // Remove last ',' + stringBuilder.Length -= 1; + } + + /// + public override string ToString() + { + var str = new StringBuilder() + .Append('$') + .Append(Id); + SerializeParameters(str); + + if (_salt.Length != 0) + { + str.Append('$') + .Append(Convert.ToHexString(_salt)); + } + + if (_hash.Length != 0) + { + str.Append('$') + .Append(Convert.ToHexString(_hash)); + } + + return str.ToString(); + } + } +} diff --git a/tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs b/tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs deleted file mode 100644 index bfece97b6b..0000000000 --- a/tests/Jellyfin.Common.Tests/Cryptography/PasswordHashTests.cs +++ /dev/null @@ -1,169 +0,0 @@ -using System; -using System.Collections.Generic; -using MediaBrowser.Common.Cryptography; -using Xunit; - -namespace Jellyfin.Common.Tests.Cryptography -{ - public static class PasswordHashTests - { - [Fact] - public static void Ctor_Null_ThrowsArgumentNullException() - { - Assert.Throws(() => new PasswordHash(null!, Array.Empty())); - } - - [Fact] - public static void Ctor_Empty_ThrowsArgumentException() - { - Assert.Throws(() => new PasswordHash(string.Empty, Array.Empty())); - } - - public static TheoryData Parse_Valid_TestData() - { - var data = new TheoryData(); - // Id - data.Add( - "$PBKDF2", - new PasswordHash("PBKDF2", Array.Empty())); - - // Id + parameter - data.Add( - "$PBKDF2$iterations=1000", - new PasswordHash( - "PBKDF2", - Array.Empty(), - Array.Empty(), - new Dictionary() - { - { "iterations", "1000" }, - })); - - // Id + parameters - data.Add( - "$PBKDF2$iterations=1000,m=120", - new PasswordHash( - "PBKDF2", - Array.Empty(), - Array.Empty(), - new Dictionary() - { - { "iterations", "1000" }, - { "m", "120" } - })); - - // Id + hash - data.Add( - "$PBKDF2$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", - new PasswordHash( - "PBKDF2", - Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), - Array.Empty(), - new Dictionary())); - - // Id + salt + hash - data.Add( - "$PBKDF2$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", - new PasswordHash( - "PBKDF2", - Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), - Convert.FromHexString("69F420"), - new Dictionary())); - - // Id + parameter + hash - data.Add( - "$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", - new PasswordHash( - "PBKDF2", - Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), - Array.Empty(), - new Dictionary() - { - { "iterations", "1000" } - })); - // Id + parameters + hash - data.Add( - "$PBKDF2$iterations=1000,m=120$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", - new PasswordHash( - "PBKDF2", - Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), - Array.Empty(), - new Dictionary() - { - { "iterations", "1000" }, - { "m", "120" } - })); - // Id + parameters + salt + hash - data.Add( - "$PBKDF2$iterations=1000,m=120$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", - new PasswordHash( - "PBKDF2", - Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), - Convert.FromHexString("69F420"), - new Dictionary() - { - { "iterations", "1000" }, - { "m", "120" } - })); - return data; - } - - [Theory] - [MemberData(nameof(Parse_Valid_TestData))] - public static void Parse_Valid_Success(string passwordHashString, PasswordHash expected) - { - var passwordHash = PasswordHash.Parse(passwordHashString); - Assert.Equal(expected.Id, passwordHash.Id); - Assert.Equal(expected.Parameters, passwordHash.Parameters); - Assert.Equal(expected.Salt.ToArray(), passwordHash.Salt.ToArray()); - Assert.Equal(expected.Hash.ToArray(), passwordHash.Hash.ToArray()); - Assert.Equal(expected.ToString(), passwordHash.ToString()); - } - - [Theory] - [InlineData("$PBKDF2")] - [InlineData("$PBKDF2$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] - [InlineData("$PBKDF2$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] - [InlineData("$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] - [InlineData("$PBKDF2$iterations=1000,m=120$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] - [InlineData("$PBKDF2$iterations=1000,m=120$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] - [InlineData("$PBKDF2$iterations=1000,m=120")] - public static void ToString_Roundtrip_Success(string passwordHash) - { - Assert.Equal(passwordHash, PasswordHash.Parse(passwordHash).ToString()); - } - - [Fact] - public static void Parse_Null_ThrowsArgumentException() - { - Assert.Throws(() => PasswordHash.Parse(null)); - } - - [Fact] - public static void Parse_Empty_ThrowsArgumentException() - { - Assert.Throws(() => PasswordHash.Parse(string.Empty)); - } - - [Theory] - [InlineData("$")] // No id - [InlineData("$$")] // Empty segments - [InlineData("PBKDF2$")] // Doesn't start with $ - [InlineData("$PBKDF2$$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Empty segment - [InlineData("$PBKDF2$iterations=1000$$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Empty salt segment - [InlineData("$PBKDF2$iterations=1000$69F420$")] // Empty hash segment - [InlineData("$PBKDF2$=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter - [InlineData("$PBKDF2$=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter - [InlineData("$PBKDF2$iterations=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter - [InlineData("$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$")] // Ends on $ - [InlineData("$PBKDF2$iterations=1000$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$")] // Extra segment - [InlineData("$PBKDF2$iterations=1000$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$anotherone")] // Extra segment - [InlineData("$PBKDF2$iterations=1000$invalidstalt$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid salt - [InlineData("$PBKDF2$iterations=1000$69F420$invalid hash")] // Invalid hash - [InlineData("$PBKDF2$69F420$")] // Empty hash - public static void Parse_InvalidFormat_ThrowsFormatException(string passwordHash) - { - Assert.Throws(() => PasswordHash.Parse(passwordHash)); - } - } -} diff --git a/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs b/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs new file mode 100644 index 0000000000..6948280a3d --- /dev/null +++ b/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using MediaBrowser.Model.Cryptography; +using Xunit; + +namespace Jellyfin.Model.Tests.Cryptography +{ + public static class PasswordHashTests + { + [Fact] + public static void Ctor_Null_ThrowsArgumentNullException() + { + Assert.Throws(() => new PasswordHash(null!, Array.Empty())); + } + + [Fact] + public static void Ctor_Empty_ThrowsArgumentException() + { + Assert.Throws(() => new PasswordHash(string.Empty, Array.Empty())); + } + + public static TheoryData Parse_Valid_TestData() + { + var data = new TheoryData(); + // Id + data.Add( + "$PBKDF2", + new PasswordHash("PBKDF2", Array.Empty())); + + // Id + parameter + data.Add( + "$PBKDF2$iterations=1000", + new PasswordHash( + "PBKDF2", + Array.Empty(), + Array.Empty(), + new Dictionary() + { + { "iterations", "1000" }, + })); + + // Id + parameters + data.Add( + "$PBKDF2$iterations=1000,m=120", + new PasswordHash( + "PBKDF2", + Array.Empty(), + Array.Empty(), + new Dictionary() + { + { "iterations", "1000" }, + { "m", "120" } + })); + + // Id + hash + data.Add( + "$PBKDF2$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", + new PasswordHash( + "PBKDF2", + Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), + Array.Empty(), + new Dictionary())); + + // Id + salt + hash + data.Add( + "$PBKDF2$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", + new PasswordHash( + "PBKDF2", + Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), + Convert.FromHexString("69F420"), + new Dictionary())); + + // Id + parameter + hash + data.Add( + "$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", + new PasswordHash( + "PBKDF2", + Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), + Array.Empty(), + new Dictionary() + { + { "iterations", "1000" } + })); + // Id + parameters + hash + data.Add( + "$PBKDF2$iterations=1000,m=120$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", + new PasswordHash( + "PBKDF2", + Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), + Array.Empty(), + new Dictionary() + { + { "iterations", "1000" }, + { "m", "120" } + })); + // Id + parameters + salt + hash + data.Add( + "$PBKDF2$iterations=1000,m=120$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", + new PasswordHash( + "PBKDF2", + Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), + Convert.FromHexString("69F420"), + new Dictionary() + { + { "iterations", "1000" }, + { "m", "120" } + })); + return data; + } + + [Theory] + [MemberData(nameof(Parse_Valid_TestData))] + public static void Parse_Valid_Success(string passwordHashString, PasswordHash expected) + { + var passwordHash = PasswordHash.Parse(passwordHashString); + Assert.Equal(expected.Id, passwordHash.Id); + Assert.Equal(expected.Parameters, passwordHash.Parameters); + Assert.Equal(expected.Salt.ToArray(), passwordHash.Salt.ToArray()); + Assert.Equal(expected.Hash.ToArray(), passwordHash.Hash.ToArray()); + Assert.Equal(expected.ToString(), passwordHash.ToString()); + } + + [Theory] + [InlineData("$PBKDF2")] + [InlineData("$PBKDF2$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] + [InlineData("$PBKDF2$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] + [InlineData("$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] + [InlineData("$PBKDF2$iterations=1000,m=120$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] + [InlineData("$PBKDF2$iterations=1000,m=120$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] + [InlineData("$PBKDF2$iterations=1000,m=120")] + public static void ToString_Roundtrip_Success(string passwordHash) + { + Assert.Equal(passwordHash, PasswordHash.Parse(passwordHash).ToString()); + } + + [Fact] + public static void Parse_Null_ThrowsArgumentException() + { + Assert.Throws(() => PasswordHash.Parse(null)); + } + + [Fact] + public static void Parse_Empty_ThrowsArgumentException() + { + Assert.Throws(() => PasswordHash.Parse(string.Empty)); + } + + [Theory] + [InlineData("$")] // No id + [InlineData("$$")] // Empty segments + [InlineData("PBKDF2$")] // Doesn't start with $ + [InlineData("$PBKDF2$$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Empty segment + [InlineData("$PBKDF2$iterations=1000$$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Empty salt segment + [InlineData("$PBKDF2$iterations=1000$69F420$")] // Empty hash segment + [InlineData("$PBKDF2$=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter + [InlineData("$PBKDF2$=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter + [InlineData("$PBKDF2$iterations=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter + [InlineData("$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$")] // Ends on $ + [InlineData("$PBKDF2$iterations=1000$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$")] // Extra segment + [InlineData("$PBKDF2$iterations=1000$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$anotherone")] // Extra segment + [InlineData("$PBKDF2$iterations=1000$invalidstalt$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid salt + [InlineData("$PBKDF2$iterations=1000$69F420$invalid hash")] // Invalid hash + [InlineData("$PBKDF2$69F420$")] // Empty hash + public static void Parse_InvalidFormat_ThrowsFormatException(string passwordHash) + { + Assert.Throws(() => PasswordHash.Parse(passwordHash)); + } + } +} -- cgit v1.2.3 From d10de5b7f93511daa3cf239b4b4c34dc79000969 Mon Sep 17 00:00:00 2001 From: cvium Date: Wed, 10 Nov 2021 23:25:01 +0100 Subject: Try to use Width and Height from ImageInfo to determine aspect ratio --- Emby.Server.Implementations/Dto/DtoService.cs | 40 +++++++++++---------------- 1 file changed, 16 insertions(+), 24 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 67ecd04e0e..4193d00184 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -1398,41 +1398,33 @@ namespace Emby.Server.Implementations.Dto return null; } - ImageDimensions size; - - var defaultAspectRatio = item.GetDefaultPrimaryImageAspectRatio(); - - if (defaultAspectRatio > 0) - { - return defaultAspectRatio; - } - if (!imageInfo.IsLocalFile) { - return null; + return item.GetDefaultPrimaryImageAspectRatio(); } - try - { - size = _imageProcessor.GetImageDimensions(item, imageInfo); + var width = imageInfo.Width; + var height = imageInfo.Height; - if (size.Width <= 0 || size.Height <= 0) + // Fallback to the image processor if the image info is somehow incorrect + if (width <= 0 || height <= 0) + { + try { - return null; + var size = _imageProcessor.GetImageDimensions(item, imageInfo); + width = size.Width; + height = size.Height; + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to determine primary image aspect ratio for {ImagePath}", imageInfo.Path); + return item.GetDefaultPrimaryImageAspectRatio(); } - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to determine primary image aspect ratio for {0}", imageInfo.Path); - return null; } - var width = size.Width; - var height = size.Height; - if (width <= 0 || height <= 0) { - return null; + return item.GetDefaultPrimaryImageAspectRatio(); } return (double)width / height; -- cgit v1.2.3 From 0415d1ccef19c48a2eaa3c545648ce657f95cfb8 Mon Sep 17 00:00:00 2001 From: cvium Date: Wed, 10 Nov 2021 23:29:41 +0100 Subject: Reduce indentation --- Emby.Server.Implementations/Dto/DtoService.cs | 31 ++++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 4193d00184..f23f4a13f3 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -1406,28 +1406,29 @@ namespace Emby.Server.Implementations.Dto var width = imageInfo.Width; var height = imageInfo.Height; + if (width > 0 && height > 0) + { + return (double)width / height; + } + // Fallback to the image processor if the image info is somehow incorrect - if (width <= 0 || height <= 0) + try { - try - { - var size = _imageProcessor.GetImageDimensions(item, imageInfo); - width = size.Width; - height = size.Height; - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to determine primary image aspect ratio for {ImagePath}", imageInfo.Path); - return item.GetDefaultPrimaryImageAspectRatio(); - } + var size = _imageProcessor.GetImageDimensions(item, imageInfo); + width = size.Width; + height = size.Height; + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to determine primary image aspect ratio for {ImagePath}", imageInfo.Path); } - if (width <= 0 || height <= 0) + if (width > 0 && height > 0) { - return item.GetDefaultPrimaryImageAspectRatio(); + return (double)width / height; } - return (double)width / height; + return item.GetDefaultPrimaryImageAspectRatio(); } } } -- cgit v1.2.3 From 5d19c26d5966db3ff48c73f409290509815cd89a Mon Sep 17 00:00:00 2001 From: cvium Date: Wed, 10 Nov 2021 23:46:56 +0100 Subject: Simplify --- Emby.Server.Implementations/Dto/DtoService.cs | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index f23f4a13f3..ab5d452790 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -1403,31 +1403,21 @@ namespace Emby.Server.Implementations.Dto return item.GetDefaultPrimaryImageAspectRatio(); } - var width = imageInfo.Width; - var height = imageInfo.Height; - - if (width > 0 && height > 0) - { - return (double)width / height; - } - - // Fallback to the image processor if the image info is somehow incorrect try { var size = _imageProcessor.GetImageDimensions(item, imageInfo); - width = size.Width; - height = size.Height; + var width = size.Width; + var height = size.Height; + if (width > 0 && height > 0) + { + return (double)width / height; + } } catch (Exception ex) { _logger.LogError(ex, "Failed to determine primary image aspect ratio for {ImagePath}", imageInfo.Path); } - if (width > 0 && height > 0) - { - return (double)width / height; - } - return item.GetDefaultPrimaryImageAspectRatio(); } } -- cgit v1.2.3 From 26001fca934298f0694504963934fe77ab1ffcf8 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Fri, 12 Nov 2021 12:09:23 -0500 Subject: Added translation using Weblate (Belarusian) --- Emby.Server.Implementations/Localization/Core/be.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 Emby.Server.Implementations/Localization/Core/be.json (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/be.json b/Emby.Server.Implementations/Localization/Core/be.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/Emby.Server.Implementations/Localization/Core/be.json @@ -0,0 +1 @@ +{} -- cgit v1.2.3 From 412ae7f4d2b2146907f073f37adad8585678d9d8 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Fri, 12 Nov 2021 12:55:27 -0500 Subject: Added translation using Weblate (Zulu) --- Emby.Server.Implementations/Localization/Core/zu.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 Emby.Server.Implementations/Localization/Core/zu.json (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/zu.json b/Emby.Server.Implementations/Localization/Core/zu.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/Emby.Server.Implementations/Localization/Core/zu.json @@ -0,0 +1 @@ +{} -- cgit v1.2.3 From 1fbe1266e23267abb3e5905f60aebcb34cbac5ed Mon Sep 17 00:00:00 2001 From: WWWesten Date: Fri, 12 Nov 2021 12:56:18 -0500 Subject: Added translation using Weblate (Telugu) --- Emby.Server.Implementations/Localization/Core/te.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 Emby.Server.Implementations/Localization/Core/te.json (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/te.json b/Emby.Server.Implementations/Localization/Core/te.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/Emby.Server.Implementations/Localization/Core/te.json @@ -0,0 +1 @@ +{} -- cgit v1.2.3 From 5a65bc1e696b362760939107a989d24645676d4f Mon Sep 17 00:00:00 2001 From: cvium Date: Sat, 13 Nov 2021 14:37:26 +0100 Subject: Very light cleanup in applicationhost --- Emby.Server.Implementations/ApplicationHost.cs | 126 ++++++++-------------- Jellyfin.Api/Controllers/SystemController.cs | 5 +- MediaBrowser.Common/IApplicationHost.cs | 7 -- MediaBrowser.Controller/IServerApplicationHost.cs | 16 +-- 4 files changed, 52 insertions(+), 102 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 73919f306f..c17d355e52 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -3,6 +3,7 @@ #pragma warning disable CS1591 using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -118,7 +119,7 @@ namespace Emby.Server.Implementations /// /// The disposable parts. /// - private readonly List _disposableParts = new List(); + private readonly ConcurrentDictionary _disposableParts = new (); private readonly IFileSystem _fileSystemManager; private readonly IConfiguration _startupConfig; @@ -129,7 +130,6 @@ namespace Emby.Server.Implementations private List _creatingInstances; private IMediaEncoder _mediaEncoder; private ISessionManager _sessionManager; - private string[] _urlPrefixes; /// /// Gets or sets all concrete types. @@ -210,7 +210,7 @@ namespace Emby.Server.Implementations /// /// Gets the singleton instance. /// - public INetworkManager NetManager { get; internal set; } + public INetworkManager NetManager { get; private set; } /// /// Gets a value indicating whether this instance has changes that require the entire application to restart. @@ -232,16 +232,16 @@ namespace Emby.Server.Implementations protected ILoggerFactory LoggerFactory { get; } /// - /// Gets or sets the application paths. + /// Gets the application paths. /// /// The application paths. - protected IServerApplicationPaths ApplicationPaths { get; set; } + protected IServerApplicationPaths ApplicationPaths { get; } /// - /// Gets or sets the configuration manager. + /// Gets the configuration manager. /// /// The configuration manager. - public ServerConfigurationManager ConfigurationManager { get; set; } + public ServerConfigurationManager ConfigurationManager { get; } /// /// Gets or sets the service provider. @@ -344,22 +344,6 @@ namespace Emby.Server.Implementations .Replace(appPaths.InternalMetadataPath, appPaths.VirtualInternalMetadataPath, StringComparison.OrdinalIgnoreCase); } - /// - /// Creates an instance of type and resolves all constructor dependencies. - /// - /// The type. - /// System.Object. - public object CreateInstance(Type type) - => ActivatorUtilities.CreateInstance(ServiceProvider, type); - - /// - /// Creates an instance of type and resolves all constructor dependencies. - /// - /// The type. - /// T. - public T CreateInstance() - => ActivatorUtilities.CreateInstance(ServiceProvider); - /// /// Creates the instance safe. /// @@ -369,7 +353,7 @@ namespace Emby.Server.Implementations { _creatingInstances ??= new List(); - if (_creatingInstances.IndexOf(type) != -1) + if (_creatingInstances.Contains(type)) { Logger.LogError("DI Loop detected in the attempted creation of {Type}", type.FullName); foreach (var entry in _creatingInstances) @@ -379,7 +363,7 @@ namespace Emby.Server.Implementations _pluginManager.FailPlugin(type.Assembly); - throw new ExternalException("DI Loop detected."); + throw new TypeLoadException("DI Loop detected"); } try @@ -412,8 +396,15 @@ namespace Emby.Server.Implementations public IEnumerable GetExportTypes() { var currentType = typeof(T); - - return _allConcreteTypes.Where(i => currentType.IsAssignableFrom(i)); + var numberOfConcreteTypes = _allConcreteTypes.Length; + for (var i = 0; i < numberOfConcreteTypes; i++) + { + var type = _allConcreteTypes[i]; + if (currentType.IsAssignableFrom(type)) + { + yield return type; + } + } } /// @@ -428,9 +419,9 @@ namespace Emby.Server.Implementations if (manageLifetime) { - lock (_disposableParts) + foreach (var part in parts.OfType()) { - _disposableParts.AddRange(parts.OfType()); + _disposableParts.TryAdd(part, byte.MinValue); } } @@ -449,9 +440,9 @@ namespace Emby.Server.Implementations if (manageLifetime) { - lock (_disposableParts) + foreach (var part in parts.OfType()) { - _disposableParts.AddRange(parts.OfType()); + _disposableParts.TryAdd(part, byte.MinValue); } } @@ -563,7 +554,7 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(ConfigurationManager); serviceCollection.AddSingleton(ConfigurationManager); serviceCollection.AddSingleton(this); - serviceCollection.AddSingleton(_pluginManager); + serviceCollection.AddSingleton(_pluginManager); serviceCollection.AddSingleton(ApplicationPaths); serviceCollection.AddSingleton(_fileSystemManager); @@ -586,7 +577,7 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); serviceCollection.AddSingleton(this); - serviceCollection.AddSingleton(ApplicationPaths); + serviceCollection.AddSingleton(ApplicationPaths); serviceCollection.AddSingleton(); @@ -790,8 +781,6 @@ namespace Emby.Server.Implementations _pluginManager.CreatePlugins(); - _urlPrefixes = GetUrlPrefixes().ToArray(); - Resolve().AddParts( GetExports(), GetExports(), @@ -859,32 +848,12 @@ namespace Emby.Server.Implementations } } - private IEnumerable GetUrlPrefixes() - { - var hosts = new[] { "+" }; - - return hosts.SelectMany(i => - { - var prefixes = new List - { - "http://" + i + ":" + HttpPort + "/" - }; - - if (Certificate != null) - { - prefixes.Add("https://" + i + ":" + HttpsPort + "/"); - } - - return prefixes; - }); - } - /// /// Called when [configuration updated]. /// /// The sender. /// The instance containing the event data. - protected void OnConfigurationUpdated(object sender, EventArgs e) + private void OnConfigurationUpdated(object sender, EventArgs e) { var requiresRestart = false; var networkConfiguration = ConfigurationManager.GetNetworkConfiguration(); @@ -893,8 +862,8 @@ namespace Emby.Server.Implementations if (HttpPort != 0 && HttpsPort != 0) { // Need to restart if ports have changed - if (networkConfiguration.HttpServerPortNumber != HttpPort || - networkConfiguration.HttpsPortNumber != HttpsPort) + if (networkConfiguration.HttpServerPortNumber != HttpPort + || networkConfiguration.HttpsPortNumber != HttpsPort) { if (ConfigurationManager.Configuration.IsPortAuthorized) { @@ -906,11 +875,6 @@ namespace Emby.Server.Implementations } } - if (!_urlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase)) - { - requiresRestart = true; - } - if (ValidateSslCertificate(networkConfiguration)) { requiresRestart = true; @@ -952,7 +916,7 @@ namespace Emby.Server.Implementations } /// - /// Notifies that the kernel that a change has been made that requires a restart. + /// Notifies the kernel that a change has been made that requires a restart. /// public void NotifyPendingRestart() { @@ -1093,11 +1057,6 @@ namespace Emby.Server.Implementations }; } - public IEnumerable GetWakeOnLanInfo() - => NetManager.GetMacAddresses() - .Select(i => new WakeOnLanInfo(i)) - .ToList(); - public PublicSystemInfo GetPublicSystemInfo(HttpRequest request) { return new PublicSystemInfo @@ -1113,7 +1072,7 @@ namespace Emby.Server.Implementations } /// - public string GetSmartApiUrl(IPAddress remoteAddr, int? port = null) + public string GetSmartApiUrl(IPAddress remoteAddr) { // Published server ends with a / if (!string.IsNullOrEmpty(PublishedServerUrl)) @@ -1122,12 +1081,12 @@ namespace Emby.Server.Implementations return PublishedServerUrl.Trim('/'); } - string smart = NetManager.GetBindInterface(remoteAddr, out port); + string smart = NetManager.GetBindInterface(remoteAddr, out var port); return GetLocalApiUrl(smart.Trim('/'), null, port); } /// - public string GetSmartApiUrl(HttpRequest request, int? port = null) + public string GetSmartApiUrl(HttpRequest request) { // Return the host in the HTTP request as the API url if (ConfigurationManager.GetNetworkConfiguration().EnablePublishedServerUriByRequest) @@ -1148,12 +1107,12 @@ namespace Emby.Server.Implementations return PublishedServerUrl.Trim('/'); } - string smart = NetManager.GetBindInterface(request, out port); + string smart = NetManager.GetBindInterface(request, out var port); return GetLocalApiUrl(smart.Trim('/'), request.Scheme, port); } /// - public string GetSmartApiUrl(string hostname, int? port = null) + public string GetSmartApiUrl(string hostname) { // Published server ends with a / if (!string.IsNullOrEmpty(PublishedServerUrl)) @@ -1162,7 +1121,7 @@ namespace Emby.Server.Implementations return PublishedServerUrl.Trim('/'); } - string smart = NetManager.GetBindInterface(hostname, out port); + string smart = NetManager.GetBindInterface(hostname, out var port); return GetLocalApiUrl(smart.Trim('/'), null, port); } @@ -1258,12 +1217,15 @@ namespace Emby.Server.Implementations Logger.LogInformation("Disposing {Type}", type.Name); - var parts = _disposableParts.Distinct().Where(i => i.GetType() != type).ToList(); - _disposableParts.Clear(); - - foreach (var part in parts) + foreach (var (part, _) in _disposableParts) { - Logger.LogInformation("Disposing {Type}", part.GetType().Name); + var partType = part.GetType(); + if (partType == type) + { + continue; + } + + Logger.LogInformation("Disposing {Type}", partType.Name); try { @@ -1271,9 +1233,11 @@ namespace Emby.Server.Implementations } catch (Exception ex) { - Logger.LogError(ex, "Error disposing {Type}", part.GetType().Name); + Logger.LogError(ex, "Error disposing {Type}", partType.Name); } } + + _disposableParts.Clear(); } _disposed = true; diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index 904738bb45..2ff85fd2ae 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -212,10 +212,13 @@ namespace Jellyfin.Api.Controllers /// An with the WakeOnLan infos. [HttpGet("WakeOnLanInfo")] [Authorize(Policy = Policies.DefaultAuthorization)] + [Obsolete("This endpoint is obsolete.")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetWakeOnLanInfo() { - var result = _appHost.GetWakeOnLanInfo(); + var result = _network.GetMacAddresses() + .Select(i => new WakeOnLanInfo(i)) + .ToList(); return Ok(result); } } diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index e49ab41f4f..53683cdbdf 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -140,12 +140,5 @@ namespace MediaBrowser.Common /// /// Instance of the interface. void Init(IServiceCollection serviceCollection); - - /// - /// Creates the instance. - /// - /// The type. - /// System.Object. - object CreateInstance(Type type); } } diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 7da492af3c..8f8cf75a6c 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -42,11 +42,6 @@ namespace MediaBrowser.Controller /// The name of the friendly. string FriendlyName { get; } - /// - /// Gets the configured published server url. - /// - string PublishedServerUrl { get; } - /// /// Gets the system info. /// @@ -60,25 +55,22 @@ namespace MediaBrowser.Controller /// Gets a URL specific for the request. /// /// The instance. - /// Optional port number. /// An accessible URL. - string GetSmartApiUrl(HttpRequest request, int? port = null); + string GetSmartApiUrl(HttpRequest request); /// /// Gets a URL specific for the request. /// /// The remote of the connection. - /// Optional port number. /// An accessible URL. - string GetSmartApiUrl(IPAddress remoteAddr, int? port = null); + string GetSmartApiUrl(IPAddress remoteAddr); /// /// Gets a URL specific for the request. /// /// The hostname used in the connection. - /// Optional port number. /// An accessible URL. - string GetSmartApiUrl(string hostname, int? port = null); + string GetSmartApiUrl(string hostname); /// /// Gets an URL that can be used to access the API over LAN. @@ -103,8 +95,6 @@ namespace MediaBrowser.Controller /// The API URL. string GetLocalApiUrl(string hostname, string scheme = null, int? port = null); - IEnumerable GetWakeOnLanInfo(); - string ExpandVirtualPath(string path); string ReverseVirtualPath(string path); -- cgit v1.2.3 From 4a28f46cac30e2e1fabc84016d710bcd309a5344 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sat, 13 Nov 2021 07:27:28 -0700 Subject: Don't throw exception on unauthenticated requests --- Emby.Server.Implementations/HttpServer/Security/AuthService.cs | 2 +- Emby.Server.Implementations/HttpServer/WebSocketManager.cs | 7 ++++++- Jellyfin.Api/Auth/CustomAuthenticationHandler.cs | 5 +++++ tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index e2ad07177e..e7103ec958 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.HttpServer.Security if (!auth.HasToken) { - throw new AuthenticationException("Request does not contain a token."); + return auth; } if (!auth.IsAuthenticated) diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs index f86bfd7550..e99876dce3 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs @@ -35,7 +35,12 @@ namespace Emby.Server.Implementations.HttpServer /// public async Task WebSocketRequestHandler(HttpContext context) { - _ = await _authService.Authenticate(context.Request).ConfigureAwait(false); + var authorizationInfo = await _authService.Authenticate(context.Request).ConfigureAwait(false); + if (!authorizationInfo.IsAuthenticated) + { + throw new SecurityException("Token is required"); + } + try { _logger.LogInformation("WS {IP} request", context.Connection.RemoteIpAddress); diff --git a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs index 369e846aef..bd3e7d9e3e 100644 --- a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs +++ b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs @@ -45,6 +45,11 @@ namespace Jellyfin.Api.Auth try { var authorizationInfo = await _authService.Authenticate(Request).ConfigureAwait(false); + if (!authorizationInfo.HasToken) + { + return AuthenticateResult.NoResult(); + } + var role = UserRoles.User; if (authorizationInfo.IsApiKey || authorizationInfo.User.HasPermission(PermissionKind.IsAdministrator)) { diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs index cd03958b66..6f5c0ed0c8 100644 --- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs @@ -132,6 +132,8 @@ namespace Jellyfin.Api.Tests.Auth authorizationInfo.User.AddDefaultPreferences(); authorizationInfo.User.SetPermission(PermissionKind.IsAdministrator, isAdmin); authorizationInfo.IsApiKey = false; + authorizationInfo.HasToken = true; + authorizationInfo.Token = "fake-token"; _jellyfinAuthServiceMock.Setup( a => a.Authenticate( -- cgit v1.2.3 From 25f1cdbcb5026a62cea3b60be0f313c83e6b4d3a Mon Sep 17 00:00:00 2001 From: WWWesten Date: Sat, 13 Nov 2021 10:36:36 +0000 Subject: Translated using Weblate (Catalan) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/ --- Emby.Server.Implementations/Localization/Core/ca.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/ca.json b/Emby.Server.Implementations/Localization/Core/ca.json index db3c13d800..2dee5e327e 100644 --- a/Emby.Server.Implementations/Localization/Core/ca.json +++ b/Emby.Server.Implementations/Localization/Core/ca.json @@ -25,7 +25,7 @@ "HeaderLiveTV": "TV en Directe", "HeaderNextUp": "A continuació", "HeaderRecordingGroups": "Grups d'Enregistrament", - "HomeVideos": "Vídeos domèstics", + "HomeVideos": "Vídeos Domèstics", "Inherit": "Hereta", "ItemAddedWithName": "{0} ha estat afegit a la biblioteca", "ItemRemovedWithName": "{0} ha estat eliminat de la biblioteca", @@ -39,7 +39,7 @@ "MixedContent": "Contingut barrejat", "Movies": "Pel·lícules", "Music": "Música", - "MusicVideos": "Vídeos musicals", + "MusicVideos": "Vídeos Musicals", "NameInstallFailed": "Instalació de {0} fallida", "NameSeasonNumber": "Temporada {0}", "NameSeasonUnknown": "Temporada Desconeguda", -- cgit v1.2.3 From 14b5e85461d7617cb37d5b9ac793d80c327fd821 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Sat, 13 Nov 2021 10:28:50 +0000 Subject: Translated using Weblate (Belarusian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/be/ --- Emby.Server.Implementations/Localization/Core/be.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/be.json b/Emby.Server.Implementations/Localization/Core/be.json index 0967ef424b..56c4e7d39d 100644 --- a/Emby.Server.Implementations/Localization/Core/be.json +++ b/Emby.Server.Implementations/Localization/Core/be.json @@ -1 +1,4 @@ -{} +{ + "Sync": "Сінхранізацыя", + "Playlists": "Плэйліст" +} -- cgit v1.2.3 From 5254e74719e666ab9c02dbda25de6c0da9412d43 Mon Sep 17 00:00:00 2001 From: Haadiy Rozzaq Date: Sat, 13 Nov 2021 20:50:30 +0000 Subject: Translated using Weblate (Indonesian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/id/ --- Emby.Server.Implementations/Localization/Core/id.json | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/id.json b/Emby.Server.Implementations/Localization/Core/id.json index ba35138700..37d59abd90 100644 --- a/Emby.Server.Implementations/Localization/Core/id.json +++ b/Emby.Server.Implementations/Localization/Core/id.json @@ -7,10 +7,10 @@ "MessageApplicationUpdated": "Jellyfin Server sudah diperbarui", "Latest": "Terbaru", "LabelIpAddressValue": "Alamat IP: {0}", - "ItemRemovedWithName": "{0} sudah dikeluarkan dari pustaka", + "ItemRemovedWithName": "{0} sudah dihapus dari pustaka", "ItemAddedWithName": "{0} telah dimasukkan ke dalam pustaka", - "Inherit": "Warisan", - "HomeVideos": "Video Rumah", + "Inherit": "Warisi", + "HomeVideos": "Video Rumahan", "HeaderRecordingGroups": "Grup Rekaman", "HeaderNextUp": "Selanjutnya", "HeaderLiveTV": "TV Live", @@ -73,7 +73,7 @@ "NotificationOptionCameraImageUploaded": "Gambar kamera terunggah", "NotificationOptionApplicationUpdateInstalled": "Pembaruan aplikasi terpasang", "NotificationOptionApplicationUpdateAvailable": "Pembaruan aplikasi tersedia", - "NewVersionIsAvailable": "Versi baru dari Jellyfin Server tersedia untuk diunduh.", + "NewVersionIsAvailable": "Versi baru dari Jellyfin Server sudah tersedia untuk diunduh.", "NameSeasonUnknown": "Musim tak diketahui", "NameSeasonNumber": "Musim {0}", "NameInstallFailed": "{0} penginstalan gagal", @@ -117,5 +117,7 @@ "TaskCleanActivityLog": "Bersihkan Log Aktivitas", "Undefined": "Tidak terdefinisi", "Forced": "Dipaksa", - "Default": "Bawaan" + "Default": "Bawaan", + "TaskOptimizeDatabaseDescription": "Rapihkan basis data dan membersihkan ruang kosong. Menjalankan tugas ini setelah memindai pustaka atau melakukan perubahan lain yang menyiratkan modifikasi basis data dapat meningkatkan kinerja.", + "TaskOptimizeDatabase": "Optimalkan basis data" } -- cgit v1.2.3 From 551c6f02a221f751942a49fe4f0685c06d3b7fd0 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Mon, 15 Nov 2021 07:48:22 -0500 Subject: Added translation using Weblate (Assamese) --- Emby.Server.Implementations/Localization/Core/as.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 Emby.Server.Implementations/Localization/Core/as.json (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/as.json b/Emby.Server.Implementations/Localization/Core/as.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/Emby.Server.Implementations/Localization/Core/as.json @@ -0,0 +1 @@ +{} -- cgit v1.2.3 From 9c74103fbe151cad7ec0c2ddf4061afc9378b203 Mon Sep 17 00:00:00 2001 From: rimasx Date: Sun, 14 Nov 2021 20:09:22 +0000 Subject: Translated using Weblate (Estonian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/ --- Emby.Server.Implementations/Localization/Core/et.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Localization/Core/et.json b/Emby.Server.Implementations/Localization/Core/et.json index e5405e5154..626d76d6b7 100644 --- a/Emby.Server.Implementations/Localization/Core/et.json +++ b/Emby.Server.Implementations/Localization/Core/et.json @@ -114,5 +114,7 @@ "Artists": "Esitajad", "Application": "Rakendus", "AppDeviceValues": "Rakendus: {0}, seade: {1}", - "Albums": "Albumid" + "Albums": "Albumid", + "UserOfflineFromDevice": "{0} katkestas ühenduse {1}-ga", + "SubtitleDownloadFailureFromForItem": "Subtiitrite allalaadimine {0} > {1} nurjus" } -- cgit v1.2.3 From 4f45c526748132f3ce19fc8b357f498d8100671d Mon Sep 17 00:00:00 2001 From: cvium Date: Mon, 15 Nov 2021 15:56:02 +0100 Subject: Remove ILibraryManager as a dependency in resolvers etc. --- Emby.Server.Implementations/ApplicationHost.cs | 2 + .../Library/CoreResolutionIgnoreRule.cs | 13 +++-- .../Library/LibraryManager.cs | 47 +++++---------- .../Library/Resolvers/Audio/AudioResolver.cs | 67 +++++++++------------- .../Library/Resolvers/Audio/MusicAlbumResolver.cs | 30 ++++------ .../Library/Resolvers/Audio/MusicArtistResolver.cs | 19 ++---- .../Library/Resolvers/BaseVideoResolver.cs | 13 +++-- .../Library/Resolvers/GenericVideoResolver.cs | 6 +- .../Library/Resolvers/Movies/MovieResolver.cs | 23 ++++---- .../Library/Resolvers/PhotoAlbumResolver.cs | 11 ++-- .../Library/Resolvers/PhotoResolver.cs | 23 ++++---- .../Library/Resolvers/TV/EpisodeResolver.cs | 7 ++- .../Library/Resolvers/TV/SeasonResolver.cs | 30 +++++----- .../Library/Resolvers/TV/SeriesResolver.cs | 38 +++++++----- MediaBrowser.Controller/Library/ILibraryManager.cs | 20 ------- MediaBrowser.Controller/Library/ItemResolveArgs.cs | 35 +++++++++++ .../Library/EpisodeResolverTest.cs | 14 ++--- 17 files changed, 185 insertions(+), 213 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index c17d355e52..99ad9fdf48 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -19,6 +19,7 @@ using Emby.Dlna; using Emby.Dlna.Main; using Emby.Dlna.Ssdp; using Emby.Drawing; +using Emby.Naming.Common; using Emby.Notifications; using Emby.Photos; using Emby.Server.Implementations.Archiving; @@ -596,6 +597,7 @@ namespace Emby.Server.Implementations serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index bc5b4499fc..29758a0788 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -1,8 +1,9 @@ using System; using System.IO; +using Emby.Naming.Audio; +using Emby.Naming.Common; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.IO; @@ -13,17 +14,17 @@ namespace Emby.Server.Implementations.Library /// public class CoreResolutionIgnoreRule : IResolverIgnoreRule { - private readonly ILibraryManager _libraryManager; + private readonly NamingOptions _namingOptions; private readonly IServerApplicationPaths _serverApplicationPaths; /// /// Initializes a new instance of the class. /// - /// The library manager. + /// The naming options. /// The server application paths. - public CoreResolutionIgnoreRule(ILibraryManager libraryManager, IServerApplicationPaths serverApplicationPaths) + public CoreResolutionIgnoreRule(NamingOptions namingOptions, IServerApplicationPaths serverApplicationPaths) { - _libraryManager = libraryManager; + _namingOptions = namingOptions; _serverApplicationPaths = serverApplicationPaths; } @@ -78,7 +79,7 @@ namespace Emby.Server.Implementations.Library { // Don't resolve these into audio files if (Path.GetFileNameWithoutExtension(filename.AsSpan()).Equals(BaseItem.ThemeSongFileName, StringComparison.Ordinal) - && _libraryManager.IsAudioFile(filename)) + && AudioFileParser.IsAudioFile(filename, _namingOptions)) { return true; } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 559da7f5cc..778b6225e1 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -79,6 +79,7 @@ namespace Emby.Server.Implementations.Library private readonly IFileSystem _fileSystem; private readonly IItemRepository _itemRepository; private readonly IImageProcessor _imageProcessor; + private readonly NamingOptions _namingOptions; /// /// The _root folder sync lock. @@ -88,9 +89,6 @@ namespace Emby.Server.Implementations.Library private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24); - private NamingOptions _namingOptions; - private string[] _videoFileExtensions; - /// /// The _root folder. /// @@ -116,6 +114,7 @@ namespace Emby.Server.Implementations.Library /// The item repository. /// The image processor. /// The memory cache. + /// The naming options. public LibraryManager( IServerApplicationHost appHost, ILogger logger, @@ -130,7 +129,8 @@ namespace Emby.Server.Implementations.Library IMediaEncoder mediaEncoder, IItemRepository itemRepository, IImageProcessor imageProcessor, - IMemoryCache memoryCache) + IMemoryCache memoryCache, + NamingOptions namingOptions) { _appHost = appHost; _logger = logger; @@ -146,6 +146,7 @@ namespace Emby.Server.Implementations.Library _itemRepository = itemRepository; _imageProcessor = imageProcessor; _memoryCache = memoryCache; + _namingOptions = namingOptions; _configurationManager.ConfigurationUpdated += ConfigurationUpdated; @@ -2500,16 +2501,6 @@ namespace Emby.Server.Implementations.Library return RootFolder; } - /// - public bool IsVideoFile(string path) - { - return VideoResolver.IsVideoFile(path, GetNamingOptions()); - } - - /// - public bool IsAudioFile(string path) - => AudioFileParser.IsAudioFile(path, GetNamingOptions()); - /// public int? GetSeasonNumberFromPath(string path) => SeasonPathParser.Parse(path, true, true).SeasonNumber; @@ -2525,7 +2516,7 @@ namespace Emby.Server.Implementations.Library isAbsoluteNaming = null; } - var resolver = new EpisodeResolver(GetNamingOptions()); + var resolver = new EpisodeResolver(_namingOptions); var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd; @@ -2682,21 +2673,9 @@ namespace Emby.Server.Implementations.Library return changed; } - /// - public NamingOptions GetNamingOptions() - { - if (_namingOptions == null) - { - _namingOptions = new NamingOptions(); - _videoFileExtensions = _namingOptions.VideoFileExtensions; - } - - return _namingOptions; - } - public ItemLookupInfo ParseName(string name) { - var namingOptions = GetNamingOptions(); + var namingOptions = _namingOptions; var result = VideoResolver.CleanDateTime(name, namingOptions); return new ItemLookupInfo @@ -2708,11 +2687,11 @@ namespace Emby.Server.Implementations.Library public IEnumerable public class AudioResolver : ItemResolver, IMultiItemResolver { - private readonly ILibraryManager _libraryManager; + private readonly NamingOptions _namingOptions; - public AudioResolver(ILibraryManager libraryManager) + public AudioResolver(NamingOptions namingOptions) { - _libraryManager = libraryManager; + _namingOptions = namingOptions; } /// @@ -40,7 +43,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio string collectionType, IDirectoryService directoryService) { - var result = ResolveMultipleInternal(parent, files, collectionType, directoryService); + var result = ResolveMultipleInternal(parent, files, collectionType); if (result != null) { @@ -56,12 +59,11 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio private MultiItemResolverResult ResolveMultipleInternal( Folder parent, List files, - string collectionType, - IDirectoryService directoryService) + string collectionType) { if (string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase)) { - return ResolveMultipleAudio(parent, files, directoryService, false, collectionType, true); + return ResolveMultipleAudio(parent, files, true); } return null; @@ -87,14 +89,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio return null; } - var files = args.FileSystemChildren - .Where(i => !_libraryManager.IgnoreFile(i, args.Parent)) - .ToList(); - - return FindAudio(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false); + return FindAudioBook(args, false); } - if (_libraryManager.IsAudioFile(args.Path)) + if (AudioFileParser.IsAudioFile(args.Path, _namingOptions)) { var extension = Path.GetExtension(args.Path); @@ -107,7 +105,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio var isMixedCollectionType = string.IsNullOrEmpty(collectionType); // For conflicting extensions, give priority to videos - if (isMixedCollectionType && _libraryManager.IsVideoFile(args.Path)) + if (isMixedCollectionType && VideoResolver.IsVideoFile(args.Path, _namingOptions)) { return null; } @@ -141,29 +139,23 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio return null; } - private T FindAudio(ItemResolveArgs args, string path, Folder parent, List fileSystemEntries, IDirectoryService directoryService, string collectionType, bool parseName) - where T : MediaBrowser.Controller.Entities.Audio.Audio, new() + private AudioBook FindAudioBook(ItemResolveArgs args, bool parseName) { // TODO: Allow GetMultiDiscMovie in here - const bool supportsMultiVersion = false; + var result = ResolveMultipleAudio(args.Parent, args.GetActualFileSystemChildren(), parseName); - var result = ResolveMultipleAudio(parent, fileSystemEntries, directoryService, supportsMultiVersion, collectionType, parseName) ?? - new MultiItemResolverResult(); - - if (result.Items.Count == 1) + if (result == null || result.Items.Count != 1 || result.Items[0] is not AudioBook item) { - // If we were supporting this we'd be checking filesFromOtherItems - var item = (T)result.Items[0]; - item.IsInMixedFolder = false; - item.Name = Path.GetFileName(item.ContainingFolderPath); - return item; + return null; } - return null; + // If we were supporting this we'd be checking filesFromOtherItems + item.IsInMixedFolder = false; + item.Name = Path.GetFileName(item.ContainingFolderPath); + return item; } - private MultiItemResolverResult ResolveMultipleAudio(Folder parent, IEnumerable fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions, string collectionType, bool parseName) - where T : MediaBrowser.Controller.Entities.Audio.Audio, new() + private MultiItemResolverResult ResolveMultipleAudio(Folder parent, IEnumerable fileSystemEntries, bool parseName) { var files = new List(); var items = new List(); @@ -176,15 +168,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio { leftOver.Add(child); } - else if (!IsIgnored(child.Name)) + else { files.Add(child); } } - var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); - - var resolver = new AudioBookListResolver(namingOptions); + var resolver = new AudioBookListResolver(_namingOptions); var resolverResult = resolver.Resolve(files).ToList(); var result = new MultiItemResolverResult @@ -210,7 +200,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio var firstMedia = resolvedItem.Files[0]; - var libraryItem = new T + var libraryItem = new AudioBook { Path = firstMedia.Path, IsInMixedFolder = isInMixedFolder, @@ -230,12 +220,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio return result; } - private bool ContainsFile(List result, FileSystemMetadata file) + private static bool ContainsFile(IEnumerable result, FileSystemMetadata file) { return result.Any(i => ContainsFile(i, file)); } - private bool ContainsFile(AudioBookInfo result, FileSystemMetadata file) + private static bool ContainsFile(AudioBookInfo result, FileSystemMetadata file) { return result.Files.Any(i => ContainsFile(i, file)) || result.AlternateVersions.Any(i => ContainsFile(i, file)) || @@ -246,10 +236,5 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio { return string.Equals(result.Path, file.FullName, StringComparison.OrdinalIgnoreCase); } - - private static bool IsIgnored(string filename) - { - return false; - } } } diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 9e3f622766..a9819a3645 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Emby.Naming.Audio; +using Emby.Naming.Common; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; @@ -22,20 +23,17 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio public class MusicAlbumResolver : ItemResolver { private readonly ILogger _logger; - private readonly IFileSystem _fileSystem; - private readonly ILibraryManager _libraryManager; + private readonly NamingOptions _namingOptions; /// /// Initializes a new instance of the class. /// /// The logger. - /// The file system. - /// The library manager. - public MusicAlbumResolver(ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager) + /// The naming options. + public MusicAlbumResolver(ILogger logger, NamingOptions namingOptions) { _logger = logger; - _fileSystem = fileSystem; - _libraryManager = libraryManager; + _namingOptions = namingOptions; } /// @@ -87,7 +85,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio /// true if the provided path points to a music album, false otherwise. public bool IsMusicAlbum(string path, IDirectoryService directoryService) { - return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService, _logger, _fileSystem, _libraryManager); + return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService); } /// @@ -101,7 +99,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio if (args.IsDirectory) { // if (args.Parent is MusicArtist) return true; // saves us from testing children twice - if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, _libraryManager)) + if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService)) { return true; } @@ -116,13 +114,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio private bool ContainsMusic( IEnumerable list, bool allowSubfolders, - IDirectoryService directoryService, - ILogger logger, - IFileSystem fileSystem, - ILibraryManager libraryManager) + IDirectoryService directoryService) { // check for audio files before digging down into directories - var foundAudioFile = list.Any(fileSystemInfo => !fileSystemInfo.IsDirectory && libraryManager.IsAudioFile(fileSystemInfo.FullName)); + var foundAudioFile = list.Any(fileSystemInfo => !fileSystemInfo.IsDirectory && AudioFileParser.IsAudioFile(fileSystemInfo.FullName, _namingOptions)); if (foundAudioFile) { // at least one audio file exists @@ -137,21 +132,20 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio var discSubfolderCount = 0; - var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); - var parser = new AlbumParser(namingOptions); + var parser = new AlbumParser(_namingOptions); var directories = list.Where(fileSystemInfo => fileSystemInfo.IsDirectory); var result = Parallel.ForEach(directories, (fileSystemInfo, state) => { var path = fileSystemInfo.FullName; - var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager); + var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService); if (hasMusic) { if (parser.IsMultiPart(path)) { - logger.LogDebug("Found multi-disc folder: {Path}", path); + _logger.LogDebug("Found multi-disc folder: {Path}", path); Interlocked.Increment(ref discSubfolderCount); } else diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs index 3d2ae95d24..27e18be42c 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs @@ -3,6 +3,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Emby.Naming.Common; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; @@ -19,27 +20,19 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio public class MusicArtistResolver : ItemResolver { private readonly ILogger _logger; - private readonly IFileSystem _fileSystem; - private readonly ILibraryManager _libraryManager; - private readonly IServerConfigurationManager _config; + private NamingOptions _namingOptions; /// /// Initializes a new instance of the class. /// /// The logger for the created instances. - /// The file system. - /// The library manager. - /// The configuration manager. + /// The naming options. public MusicArtistResolver( ILogger logger, - IFileSystem fileSystem, - ILibraryManager libraryManager, - IServerConfigurationManager config) + NamingOptions namingOptions) { _logger = logger; - _fileSystem = fileSystem; - _libraryManager = libraryManager; - _config = config; + _namingOptions = namingOptions; } /// @@ -89,7 +82,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio var directoryService = args.DirectoryService; - var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager); + var albumResolver = new MusicAlbumResolver(_logger, _namingOptions); // If we contain an album assume we are an artist folder var directories = args.FileSystemChildren.Where(i => i.IsDirectory); diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs index 9ff99fa431..0ebf0e5302 100644 --- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs @@ -6,6 +6,7 @@ using System; using System.IO; using System.Linq; using DiscUtils.Udf; +using Emby.Naming.Common; using Emby.Naming.Video; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -21,12 +22,12 @@ namespace Emby.Server.Implementations.Library.Resolvers public abstract class BaseVideoResolver : MediaBrowser.Controller.Resolvers.ItemResolver where T : Video, new() { - protected BaseVideoResolver(ILibraryManager libraryManager) + protected BaseVideoResolver(NamingOptions namingOptions) { - LibraryManager = libraryManager; + NamingOptions = namingOptions; } - protected ILibraryManager LibraryManager { get; } + protected NamingOptions NamingOptions { get; } /// /// Resolves the specified args. @@ -48,7 +49,7 @@ namespace Emby.Server.Implementations.Library.Resolvers protected virtual TVideoType ResolveVideo(ItemResolveArgs args, bool parseName) where TVideoType : Video, new() { - var namingOptions = LibraryManager.GetNamingOptions(); + var namingOptions = NamingOptions; // If the path is a file check for a matching extensions if (args.IsDirectory) @@ -138,7 +139,7 @@ namespace Emby.Server.Implementations.Library.Resolvers return null; } - if (LibraryManager.IsVideoFile(args.Path) || videoInfo.IsStub) + if (VideoResolver.IsVideoFile(args.Path, NamingOptions) || videoInfo.IsStub) { var path = args.Path; @@ -267,7 +268,7 @@ namespace Emby.Server.Implementations.Library.Resolvers protected void Set3DFormat(Video video) { - var result = Format3DParser.Parse(video.Path, LibraryManager.GetNamingOptions()); + var result = Format3DParser.Parse(video.Path, NamingOptions); Set3DFormat(video, result.Is3D, result.Format3D); } diff --git a/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs index 9599faea4b..72341d9dbd 100644 --- a/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs @@ -2,16 +2,16 @@ #pragma warning disable CS1591 +using Emby.Naming.Common; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; namespace Emby.Server.Implementations.Library.Resolvers { public class GenericVideoResolver : BaseVideoResolver where T : Video, new() { - public GenericVideoResolver(ILibraryManager libraryManager) - : base(libraryManager) + public GenericVideoResolver(NamingOptions namingOptions) + : base(namingOptions) { } } diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index f3b6ef0a28..732be0fe5c 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using Emby.Naming.Common; using Emby.Naming.Video; using Jellyfin.Extensions; using MediaBrowser.Controller.Drawing; @@ -25,6 +26,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies public class MovieResolver : BaseVideoResolver