From cafeedcadfa93259529a79cc417faccf20154bd1 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 8 Mar 2022 22:57:47 +0100 Subject: [PATCH 01/55] Rework SsdpHttpClient --- Emby.Dlna/PlayTo/Device.cs | 33 +++--- Emby.Dlna/PlayTo/DlnaHttpClient.cs | 105 ++++++++++++++++++ Emby.Dlna/PlayTo/SsdpHttpClient.cs | 141 ------------------------- Jellyfin.Server/Startup.cs | 17 +++ MediaBrowser.Common/Net/NamedClient.cs | 5 + 5 files changed, 144 insertions(+), 157 deletions(-) create mode 100644 Emby.Dlna/PlayTo/DlnaHttpClient.cs delete mode 100644 Emby.Dlna/PlayTo/SsdpHttpClient.cs diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 8eb90f4455..0b480f5ab0 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -235,7 +235,7 @@ namespace Emby.Dlna.PlayTo _logger.LogDebug("Setting mute"); var value = mute ? 1 : 0; - await new SsdpHttpClient(_httpClientFactory) + await new DlnaHttpClient(_logger, _httpClientFactory) .SendCommandAsync( Properties.BaseUrl, service, @@ -276,7 +276,7 @@ namespace Emby.Dlna.PlayTo // Remote control will perform better Volume = value; - await new SsdpHttpClient(_httpClientFactory) + await new DlnaHttpClient(_logger, _httpClientFactory) .SendCommandAsync( Properties.BaseUrl, service, @@ -303,7 +303,7 @@ namespace Emby.Dlna.PlayTo throw new InvalidOperationException("Unable to find service"); } - await new SsdpHttpClient(_httpClientFactory) + await new DlnaHttpClient(_logger, _httpClientFactory) .SendCommandAsync( Properties.BaseUrl, service, @@ -343,7 +343,7 @@ namespace Emby.Dlna.PlayTo } var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary); - await new SsdpHttpClient(_httpClientFactory) + await new DlnaHttpClient(_logger, _httpClientFactory) .SendCommandAsync( Properties.BaseUrl, service, @@ -400,7 +400,8 @@ namespace Emby.Dlna.PlayTo } var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary); - await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header, cancellationToken) + await new DlnaHttpClient(_logger, _httpClientFactory) + .SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header, cancellationToken) .ConfigureAwait(false); } @@ -428,7 +429,7 @@ namespace Emby.Dlna.PlayTo throw new InvalidOperationException("Unable to find service"); } - return new SsdpHttpClient(_httpClientFactory).SendCommandAsync( + return new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync( Properties.BaseUrl, service, command.Name, @@ -461,7 +462,7 @@ namespace Emby.Dlna.PlayTo var service = GetAvTransportService(); - await new SsdpHttpClient(_httpClientFactory) + await new DlnaHttpClient(_logger, _httpClientFactory) .SendCommandAsync( Properties.BaseUrl, service, @@ -485,7 +486,7 @@ namespace Emby.Dlna.PlayTo var service = GetAvTransportService(); - await new SsdpHttpClient(_httpClientFactory) + await new DlnaHttpClient(_logger, _httpClientFactory) .SendCommandAsync( Properties.BaseUrl, service, @@ -618,7 +619,7 @@ namespace Emby.Dlna.PlayTo return; } - var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync( + var result = await new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync( Properties.BaseUrl, service, command.Name, @@ -668,7 +669,7 @@ namespace Emby.Dlna.PlayTo return; } - var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync( + var result = await new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync( Properties.BaseUrl, service, command.Name, @@ -701,7 +702,7 @@ namespace Emby.Dlna.PlayTo return null; } - var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync( + var result = await new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync( Properties.BaseUrl, service, command.Name, @@ -747,7 +748,7 @@ namespace Emby.Dlna.PlayTo return null; } - var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync( + var result = await new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync( Properties.BaseUrl, service, command.Name, @@ -819,7 +820,7 @@ namespace Emby.Dlna.PlayTo return (false, null); } - var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync( + var result = await new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync( Properties.BaseUrl, service, command.Name, @@ -997,7 +998,7 @@ namespace Emby.Dlna.PlayTo string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl); - var httpClient = new SsdpHttpClient(_httpClientFactory); + var httpClient = new DlnaHttpClient(_logger, _httpClientFactory); var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false); if (document == null) @@ -1029,7 +1030,7 @@ namespace Emby.Dlna.PlayTo string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl); - var httpClient = new SsdpHttpClient(_httpClientFactory); + var httpClient = new DlnaHttpClient(_logger, _httpClientFactory); _logger.LogDebug("Dlna Device.GetRenderingProtocolAsync"); var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false); if (document == null) @@ -1064,7 +1065,7 @@ namespace Emby.Dlna.PlayTo public static async Task CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken) { - var ssdpHttpClient = new SsdpHttpClient(httpClientFactory); + var ssdpHttpClient = new DlnaHttpClient(logger, httpClientFactory); var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false); if (document == null) diff --git a/Emby.Dlna/PlayTo/DlnaHttpClient.cs b/Emby.Dlna/PlayTo/DlnaHttpClient.cs new file mode 100644 index 0000000000..623f4526c8 --- /dev/null +++ b/Emby.Dlna/PlayTo/DlnaHttpClient.cs @@ -0,0 +1,105 @@ +#pragma warning disable CS1591 + +using System; +using System.Globalization; +using System.Net.Http; +using System.Net.Mime; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using Emby.Dlna.Common; +using MediaBrowser.Common.Net; +using Microsoft.Extensions.Logging; + +namespace Emby.Dlna.PlayTo +{ + public class DlnaHttpClient + { + private readonly ILogger _logger; + private readonly IHttpClientFactory _httpClientFactory; + + public DlnaHttpClient(ILogger logger, IHttpClientFactory httpClientFactory) + { + _logger = logger; + _httpClientFactory = httpClientFactory; + } + + private static string NormalizeServiceUrl(string baseUrl, string serviceUrl) + { + // If it's already a complete url, don't stick anything onto the front of it + if (serviceUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + return serviceUrl; + } + + if (!serviceUrl.StartsWith('/')) + { + serviceUrl = "/" + serviceUrl; + } + + return baseUrl + serviceUrl; + } + + private async Task SendRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + using var response = await _httpClientFactory.CreateClient(NamedClient.Dlna).SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); + try + { + return await XDocument.LoadAsync( + stream, + LoadOptions.None, + cancellationToken).ConfigureAwait(false); + } + catch (XmlException ex) + { + _logger.LogError(ex, "Failed to parse response"); + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Malformed response:\n", await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false)); + } + + return null; + } + } + + public Task GetDataAsync(string url, CancellationToken cancellationToken) + { + using var request = new HttpRequestMessage(HttpMethod.Get, url); + return SendRequestAsync(request, cancellationToken); + } + + public Task SendCommandAsync( + string baseUrl, + DeviceService service, + string command, + string postData, + string? header = null, + CancellationToken cancellationToken = default) + { + using var request = new HttpRequestMessage(HttpMethod.Post, NormalizeServiceUrl(baseUrl, service.ControlUrl)) + { + Content = new StringContent(postData, Encoding.UTF8, MediaTypeNames.Text.Xml) + }; + + request.Headers.TryAddWithoutValidation( + "SOAPACTION", + string.Format( + CultureInfo.InvariantCulture, + "\"{0}#{1}\"", + service.ServiceType, + command)); + request.Headers.Pragma.ParseAdd("no-cache"); + + if (!string.IsNullOrEmpty(header)) + { + request.Headers.TryAddWithoutValidation("contentFeatures.dlna.org", header); + } + + return SendRequestAsync(request, cancellationToken); + } + } +} diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs deleted file mode 100644 index cade7b4c2c..0000000000 --- a/Emby.Dlna/PlayTo/SsdpHttpClient.cs +++ /dev/null @@ -1,141 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System; -using System.Globalization; -using System.Net.Http; -using System.Net.Mime; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Linq; -using Emby.Dlna.Common; -using MediaBrowser.Common.Net; - -namespace Emby.Dlna.PlayTo -{ - public class SsdpHttpClient - { - private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50"; - private const string FriendlyName = "Jellyfin"; - - private readonly IHttpClientFactory _httpClientFactory; - - public SsdpHttpClient(IHttpClientFactory httpClientFactory) - { - _httpClientFactory = httpClientFactory; - } - - public async Task SendCommandAsync( - string baseUrl, - DeviceService service, - string command, - string postData, - string header = null, - CancellationToken cancellationToken = default) - { - var url = NormalizeServiceUrl(baseUrl, service.ControlUrl); - using var response = await PostSoapDataAsync( - url, - $"\"{service.ServiceType}#{command}\"", - postData, - header, - cancellationToken) - .ConfigureAwait(false); - response.EnsureSuccessStatusCode(); - - await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - return await XDocument.LoadAsync( - stream, - LoadOptions.None, - cancellationToken).ConfigureAwait(false); - } - - private static string NormalizeServiceUrl(string baseUrl, string serviceUrl) - { - // If it's already a complete url, don't stick anything onto the front of it - if (serviceUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - return serviceUrl; - } - - if (!serviceUrl.StartsWith('/')) - { - serviceUrl = "/" + serviceUrl; - } - - return baseUrl + serviceUrl; - } - - public async Task SubscribeAsync( - string url, - string ip, - int port, - string localIp, - int eventport, - int timeOut = 3600) - { - using var options = new HttpRequestMessage(new HttpMethod("SUBSCRIBE"), url); - options.Headers.UserAgent.ParseAdd(USERAGENT); - 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(CultureInfo.InvariantCulture)); - - using var response = await _httpClientFactory.CreateClient(NamedClient.Default) - .SendAsync(options, HttpCompletionOption.ResponseHeadersRead) - .ConfigureAwait(false); - response.EnsureSuccessStatusCode(); - } - - public async Task GetDataAsync(string url, CancellationToken cancellationToken) - { - using var options = new HttpRequestMessage(HttpMethod.Get, url); - options.Headers.UserAgent.ParseAdd(USERAGENT); - options.Headers.TryAddWithoutValidation("FriendlyName.DLNA.ORG", FriendlyName); - using var response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - response.EnsureSuccessStatusCode(); - await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - try - { - return await XDocument.LoadAsync( - stream, - LoadOptions.None, - cancellationToken).ConfigureAwait(false); - } - catch - { - return null; - } - } - - private async Task PostSoapDataAsync( - string url, - string soapAction, - string postData, - string header, - CancellationToken cancellationToken) - { - if (soapAction[0] != '\"') - { - soapAction = $"\"{soapAction}\""; - } - - using var options = new HttpRequestMessage(HttpMethod.Post, url); - options.Headers.UserAgent.ParseAdd(USERAGENT); - options.Headers.TryAddWithoutValidation("SOAPACTION", soapAction); - options.Headers.TryAddWithoutValidation("Pragma", "no-cache"); - options.Headers.TryAddWithoutValidation("FriendlyName.DLNA.ORG", FriendlyName); - - if (!string.IsNullOrEmpty(header)) - { - options.Headers.TryAddWithoutValidation("contentFeatures.dlna.org", header); - } - - options.Content = new StringContent(postData, Encoding.UTF8, MediaTypeNames.Text.Xml); - - return await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index 8eb5f21960..2cb6d937a8 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -103,6 +104,22 @@ namespace Jellyfin.Server }) .ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate); + services.AddHttpClient(NamedClient.Dlna, c => + { + c.DefaultRequestHeaders.UserAgent.ParseAdd( + string.Format( + CultureInfo.InvariantCulture, + "{0}/{1} UPnP/1.1 {2}/{3}", + MediaBrowser.Common.System.OperatingSystem.Name, + Environment.OSVersion, + _serverApplicationHost.Name, + _serverApplicationHost.ApplicationVersionString)); + + c.DefaultRequestHeaders.Add("CPFN.UPNP.ORG", _serverApplicationHost.FriendlyName); // Required for UPnP DeviceArchitecture v2.0 + c.DefaultRequestHeaders.Add("FriendlyName.DLNA.ORG", _serverApplicationHost.FriendlyName); // REVIEW: where does this come from? + }) + .ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate); + services.AddHealthChecks() .AddDbContextCheck(); diff --git a/MediaBrowser.Common/Net/NamedClient.cs b/MediaBrowser.Common/Net/NamedClient.cs index 0f6161c328..a6cacd4f17 100644 --- a/MediaBrowser.Common/Net/NamedClient.cs +++ b/MediaBrowser.Common/Net/NamedClient.cs @@ -14,5 +14,10 @@ /// Gets the value for the MusicBrainz named http client. /// public const string MusicBrainz = nameof(MusicBrainz); + + /// + /// Gets the value for the DLNA named http client. + /// + public const string Dlna = nameof(Dlna); } } From 181b2760b8ce590c25cdb8fd57f44ac1aaa49984 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Thu, 26 May 2022 16:30:21 +0200 Subject: [PATCH 02/55] Revert UPnP version to 1.0 --- Jellyfin.Server/Startup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index 2cb6d937a8..1954a5c558 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -109,7 +109,7 @@ namespace Jellyfin.Server c.DefaultRequestHeaders.UserAgent.ParseAdd( string.Format( CultureInfo.InvariantCulture, - "{0}/{1} UPnP/1.1 {2}/{3}", + "{0}/{1} UPnP/1.0 {2}/{3}", MediaBrowser.Common.System.OperatingSystem.Name, Environment.OSVersion, _serverApplicationHost.Name, From 5b4e14940ea20c0afeea6c2031e34aa870786fe9 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 14 Jun 2022 16:43:48 +0200 Subject: [PATCH 03/55] Fix format string --- Emby.Dlna/PlayTo/DlnaHttpClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Dlna/PlayTo/DlnaHttpClient.cs b/Emby.Dlna/PlayTo/DlnaHttpClient.cs index 623f4526c8..62156d1833 100644 --- a/Emby.Dlna/PlayTo/DlnaHttpClient.cs +++ b/Emby.Dlna/PlayTo/DlnaHttpClient.cs @@ -59,7 +59,7 @@ namespace Emby.Dlna.PlayTo _logger.LogError(ex, "Failed to parse response"); if (_logger.IsEnabled(LogLevel.Debug)) { - _logger.LogDebug("Malformed response:\n", await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false)); + _logger.LogDebug("Malformed response: {Content}\n", await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false)); } return null; From e4088ba0bd1b10bca981a7e36e89fb2827e5dbe1 Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Sat, 18 Jun 2022 13:10:50 -0500 Subject: [PATCH 04/55] don't require a user id for items api call using api key --- Jellyfin.Api/Controllers/ItemsController.cs | 44 ++++++++++++++----- .../Controllers/TrailersController.cs | 7 +-- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 58caae9f85..7582c94cfe 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; @@ -9,6 +10,7 @@ using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -32,6 +34,7 @@ namespace Jellyfin.Api.Controllers private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localization; private readonly IDtoService _dtoService; + private readonly IAuthorizationContext _authContext; private readonly ILogger _logger; private readonly ISessionManager _sessionManager; @@ -42,6 +45,7 @@ namespace Jellyfin.Api.Controllers /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. + /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. public ItemsController( @@ -49,6 +53,7 @@ namespace Jellyfin.Api.Controllers ILibraryManager libraryManager, ILocalizationManager localization, IDtoService dtoService, + IAuthorizationContext authContext, ILogger logger, ISessionManager sessionManager) { @@ -56,6 +61,7 @@ namespace Jellyfin.Api.Controllers _libraryManager = libraryManager; _localization = localization; _dtoService = dtoService; + _authContext = authContext; _logger = logger; _sessionManager = sessionManager; } @@ -151,8 +157,8 @@ namespace Jellyfin.Api.Controllers /// A with the items. [HttpGet("Items")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetItems( - [FromQuery] Guid userId, + public async Task>> GetItems( + [FromQuery] Guid? userId, [FromQuery] string? maxOfficialRating, [FromQuery] bool? hasThemeSong, [FromQuery] bool? hasThemeVideo, @@ -238,7 +244,17 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true) { - var user = userId.Equals(default) ? null : _userManager.GetUserById(userId); + var auth = await _authContext.GetAuthorizationInfo(Request).ConfigureAwait(false); + + var user = !auth.IsApiKey && userId.HasValue && !userId.Equals(Guid.Empty) + ? _userManager.GetUserById(userId.Value) + : null; + + if (!auth.IsApiKey && user is null) + { + return BadRequest("userId is required"); + } + var dtoOptions = new DtoOptions { Fields = fields } .AddClientFields(Request) .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); @@ -270,20 +286,26 @@ namespace Jellyfin.Api.Controllers includeItemTypes = new[] { BaseItemKind.Playlist }; } - var enabledChannels = user!.GetPreferenceValues(PreferenceKind.EnabledChannels); + var enabledChannels = auth.IsApiKey + ? Array.Empty() + : user.GetPreferenceValues(PreferenceKind.EnabledChannels); - bool isInEnabledFolder = Array.IndexOf(user.GetPreferenceValues(PreferenceKind.EnabledFolders), item.Id) != -1 + bool isInEnabledFolder = auth.IsApiKey + || Array.IndexOf(user.GetPreferenceValues(PreferenceKind.EnabledFolders), item.Id) != -1 // Assume all folders inside an EnabledChannel are enabled || Array.IndexOf(enabledChannels, item.Id) != -1 // Assume all items inside an EnabledChannel are enabled || Array.IndexOf(enabledChannels, item.ChannelId) != -1; - var collectionFolders = _libraryManager.GetCollectionFolders(item); - foreach (var collectionFolder in collectionFolders) + if (!isInEnabledFolder) { - if (user.GetPreferenceValues(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id)) + var collectionFolders = _libraryManager.GetCollectionFolders(item); + foreach (var collectionFolder in collectionFolders) { - isInEnabledFolder = true; + if (user.GetPreferenceValues(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id)) + { + isInEnabledFolder = true; + } } } @@ -293,7 +315,7 @@ namespace Jellyfin.Api.Controllers && !user.HasPermission(PermissionKind.EnableAllChannels) && !string.Equals(collectionType, CollectionType.Folders, StringComparison.OrdinalIgnoreCase)) { - _logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Username, item.Name); + _logger.LogWarning("{UserName} is not permitted to access Library {ItemName}", user.Username, item.Name); return Unauthorized($"{user.Username} is not permitted to access Library {item.Name}."); } @@ -606,7 +628,7 @@ namespace Jellyfin.Api.Controllers /// A with the items. [HttpGet("Users/{userId}/Items")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetItemsByUserId( + public Task>> GetItemsByUserId( [FromRoute] Guid userId, [FromQuery] string? maxOfficialRating, [FromQuery] bool? hasThemeSong, diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index 790d6e64d8..78a493d225 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; @@ -31,7 +32,7 @@ namespace Jellyfin.Api.Controllers /// /// Finds movies and trailers similar to a given trailer. /// - /// The user id. + /// Optional user id. /// Optional filter by maximum official rating (PG, PG-13, TV-MA, etc). /// Optional filter by items with theme songs. /// Optional filter by items with theme videos. @@ -118,8 +119,8 @@ namespace Jellyfin.Api.Controllers /// A with the trailers. [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetTrailers( - [FromQuery] Guid userId, + public Task>> GetTrailers( + [FromQuery] Guid? userId, [FromQuery] string? maxOfficialRating, [FromQuery] bool? hasThemeSong, [FromQuery] bool? hasThemeVideo, From 82df4c32427410515e7347613c34bcfe034db58f Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Sat, 18 Jun 2022 13:15:05 -0500 Subject: [PATCH 05/55] update comments --- Jellyfin.Api/Controllers/ItemsController.cs | 2 +- Jellyfin.Api/Controllers/TrailersController.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 7582c94cfe..b3e2beb0f9 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -69,7 +69,7 @@ namespace Jellyfin.Api.Controllers /// /// Gets items based on a query. /// - /// The user id supplied as query parameter. + /// The user id supplied as query parameter; this is required when not using an API key. /// Optional filter by maximum official rating (PG, PG-13, TV-MA, etc). /// Optional filter by items with theme songs. /// Optional filter by items with theme videos. diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index 78a493d225..ea74c78736 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -32,7 +32,7 @@ namespace Jellyfin.Api.Controllers /// /// Finds movies and trailers similar to a given trailer. /// - /// Optional user id. + /// The user id supplied as query parameter; this is required when not using an API key. /// Optional filter by maximum official rating (PG, PG-13, TV-MA, etc). /// Optional filter by items with theme songs. /// Optional filter by items with theme videos. From d06fda43c18b8f600b15365b59d20b603fede141 Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Sat, 18 Jun 2022 13:19:00 -0500 Subject: [PATCH 06/55] use null-forgiving operator to suppress warnings --- Jellyfin.Api/Controllers/ItemsController.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index b3e2beb0f9..0b1ef00224 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -288,10 +288,10 @@ namespace Jellyfin.Api.Controllers var enabledChannels = auth.IsApiKey ? Array.Empty() - : user.GetPreferenceValues(PreferenceKind.EnabledChannels); + : user!.GetPreferenceValues(PreferenceKind.EnabledChannels); bool isInEnabledFolder = auth.IsApiKey - || Array.IndexOf(user.GetPreferenceValues(PreferenceKind.EnabledFolders), item.Id) != -1 + || Array.IndexOf(user!.GetPreferenceValues(PreferenceKind.EnabledFolders), item.Id) != -1 // Assume all folders inside an EnabledChannel are enabled || Array.IndexOf(enabledChannels, item.Id) != -1 // Assume all items inside an EnabledChannel are enabled @@ -302,7 +302,7 @@ namespace Jellyfin.Api.Controllers var collectionFolders = _libraryManager.GetCollectionFolders(item); foreach (var collectionFolder in collectionFolders) { - if (user.GetPreferenceValues(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id)) + if (user!.GetPreferenceValues(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id)) { isInEnabledFolder = true; } @@ -311,7 +311,7 @@ namespace Jellyfin.Api.Controllers if (item is not UserRootFolder && !isInEnabledFolder - && !user.HasPermission(PermissionKind.EnableAllFolders) + && !user!.HasPermission(PermissionKind.EnableAllFolders) && !user.HasPermission(PermissionKind.EnableAllChannels) && !string.Equals(collectionType, CollectionType.Folders, StringComparison.OrdinalIgnoreCase)) { From fc74c8eecf5bf0023ea59918260a4cdbe9ce787c Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Thu, 23 Jun 2022 09:19:29 -0500 Subject: [PATCH 07/55] tweak guid check Co-authored-by: Bond-009 --- Jellyfin.Api/Controllers/ItemsController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 0b1ef00224..bfa4f9fe72 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -246,7 +246,7 @@ namespace Jellyfin.Api.Controllers { var auth = await _authContext.GetAuthorizationInfo(Request).ConfigureAwait(false); - var user = !auth.IsApiKey && userId.HasValue && !userId.Equals(Guid.Empty) + var user = !auth.IsApiKey && userId.HasValue && !userId.Value.Equals(default) ? _userManager.GetUserById(userId.Value) : null; From 9ec42f8cf5cc4727f704f6a9b8e4e1c4aa8df04f Mon Sep 17 00:00:00 2001 From: Utku Ozdemir Date: Sun, 5 Jun 2022 02:38:22 +0200 Subject: [PATCH 08/55] fix: single video folder during photos lib scan Prevent a directory with a single video file to be detected as a movie directory when the library type is "Photos". Closes jellyfin/jellyfin#7825 Signed-off-by: Utku Ozdemir --- .../Library/Resolvers/Movies/MovieResolver.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index fe4ccd6acb..a60251dacd 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -464,7 +464,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies var result = ResolveVideos(parent, fileSystemEntries, SupportsMultiVersion, collectionType, parseName) ?? new MultiItemResolverResult(); - if (result.Items.Count == 1) + var isPhotosCollection = string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) + || string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase); + if (!isPhotosCollection && result.Items.Count == 1) { var videoPath = result.Items[0].Path; var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(videoPath, i.Name)); From d83b1c0f5a227303feb7b3c5af095cf0562d1795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Utku=20=C3=96zdemir?= Date: Sat, 11 Jun 2022 02:33:15 +0200 Subject: [PATCH 09/55] chore: add utkuozdemir to contributors.md Signed-off-by: Utku Ozdemir --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 87086a7280..a7d2b2e409 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -225,3 +225,4 @@ - [gnuyent](https://github.com/gnuyent) - [Matthew Jones](https://github.com/matthew-jones-uk) - [Jakob Kukla](https://github.com/jakobkukla) + - [Utku Özdemir](https://github.com/utkuozdemir) From ac5a4e62f439255d1e479d535f6459a7dd677923 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Mon, 11 Jul 2022 12:56:58 -0400 Subject: [PATCH 10/55] Move transcodes to be under CachePath Move transcodes to be under CachePath instead of ProgramDataPath. Since transcodes are ephemeral (they're cleaned up periodically and recreated if they don't exist), they're more like cache data than program data. Systems can (and oftentimes do) have the cache directory on a different disk, use a different type of file system, or have a different backup policy for the cache path because it contains ephemeral data. --- .../Configuration/EncodingConfigurationExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs b/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs index 89740ae084..70a4fe4098 100644 --- a/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs +++ b/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Common.Configuration var transcodingTempPath = configurationManager.GetEncodingOptions().TranscodingTempPath; if (string.IsNullOrEmpty(transcodingTempPath)) { - transcodingTempPath = Path.Combine(configurationManager.CommonApplicationPaths.ProgramDataPath, "transcodes"); + transcodingTempPath = Path.Combine(configurationManager.CommonApplicationPaths.CachePath, "transcodes"); } // Make sure the directory exists From 6e18c10e5103651f3b3861183dc1ff896741c001 Mon Sep 17 00:00:00 2001 From: Nicolas Viviani Date: Mon, 11 Jul 2022 22:38:32 +0000 Subject: [PATCH 11/55] 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 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json index 33e80f7ac9..46f637050a 100644 --- a/Emby.Server.Implementations/Localization/Core/fr.json +++ b/Emby.Server.Implementations/Localization/Core/fr.json @@ -92,11 +92,11 @@ "ValueHasBeenAddedToLibrary": "{0} a été ajouté à votre médiathèque", "ValueSpecialEpisodeName": "Spécial - {0}", "VersionNumber": "Version {0}", - "TasksChannelsCategory": "Chaines en ligne", + "TasksChannelsCategory": "Chaînes en ligne", "TaskDownloadMissingSubtitlesDescription": "Recherche les sous-titres manquants sur internet en se basant sur la configuration des métadonnées.", "TaskDownloadMissingSubtitles": "Télécharger les sous-titres manquants", - "TaskRefreshChannelsDescription": "Rafraîchit les informations des chaines en ligne.", - "TaskRefreshChannels": "Rafraîchir les chaines", + "TaskRefreshChannelsDescription": "Rafraîchit les informations des chaînes en ligne.", + "TaskRefreshChannels": "Rafraîchir les chaînes", "TaskCleanTranscodeDescription": "Supprime les fichiers transcodés de plus d'un jour.", "TaskCleanTranscode": "Nettoyer les dossier des transcodages", "TaskUpdatePluginsDescription": "Télécharge et installe les mises à jours des extensions configurées pour être mises à jour automatiquement.", @@ -119,7 +119,7 @@ "Undefined": "Non défini", "Forced": "Forcé", "Default": "Par défaut", - "TaskOptimizeDatabaseDescription": "Réduit les espaces vides/inutiles et compacte la base de données. Utiliser cette fonction après une mise à jour de la bibliothèque ou toute autre modification de la base de données peut améliorer les performances du serveur.", + "TaskOptimizeDatabaseDescription": "Réduit les espaces vides ou inutiles et compacte la base de données. Utiliser cette fonction après une mise à jour de la bibliothèque ou toute autre modification de la base de données peut améliorer les performances du serveur.", "TaskOptimizeDatabase": "Optimiser la base de données", "TaskKeyframeExtractorDescription": "Extrait les images clés des fichiers vidéo pour créer des listes de lecture HLS plus précises. Cette tâche peut durer très longtemps.", "TaskKeyframeExtractor": "Extracteur d'image clé", From 64c44baf2fa86cd7860f9d595a036a3eaa43b51d Mon Sep 17 00:00:00 2001 From: Maxim Titov Date: Tue, 12 Jul 2022 21:27:16 +0000 Subject: [PATCH 12/55] 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(-) diff --git a/Emby.Server.Implementations/Localization/Core/ru.json b/Emby.Server.Implementations/Localization/Core/ru.json index aff70ac69a..ea9a82d2bf 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}) была обновлена", From 40d3d8fb370c473d49fb4ca72c0ded5bda62a279 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Wed, 13 Jul 2022 21:00:23 -0600 Subject: [PATCH 13/55] bump Jellyfin to 10.9 --- Emby.Naming/Emby.Naming.csproj | 2 +- Jellyfin.Data/Jellyfin.Data.csproj | 2 +- MediaBrowser.Common/MediaBrowser.Common.csproj | 2 +- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 2 +- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 +- SharedVersion.cs | 4 ++-- build.yaml | 2 +- debian/changelog | 6 ++++++ debian/metapackage/jellyfin | 2 +- fedora/jellyfin.spec | 4 +++- src/Jellyfin.Extensions/Jellyfin.Extensions.csproj | 2 +- 11 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index cfbc1eef87..ca002b9816 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -36,7 +36,7 @@ Jellyfin Contributors Jellyfin.Naming - 10.8.0 + 10.9.0 https://github.com/jellyfin/jellyfin GPL-3.0-only diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 89799883fd..47499e038b 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -18,7 +18,7 @@ Jellyfin Contributors Jellyfin.Data - 10.8.0 + 10.9.0 https://github.com/jellyfin/jellyfin GPL-3.0-only diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index bbb797ab99..7a55f398a1 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -8,7 +8,7 @@ Jellyfin Contributors Jellyfin.Common - 10.8.0 + 10.9.0 https://github.com/jellyfin/jellyfin GPL-3.0-only diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 2368706fe1..d4e025a43e 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -8,7 +8,7 @@ Jellyfin Contributors Jellyfin.Controller - 10.8.0 + 10.9.0 https://github.com/jellyfin/jellyfin GPL-3.0-only diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index b4e93de19b..4f511f9960 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -8,7 +8,7 @@ Jellyfin Contributors Jellyfin.Model - 10.8.0 + 10.9.0 https://github.com/jellyfin/jellyfin GPL-3.0-only diff --git a/SharedVersion.cs b/SharedVersion.cs index 5e2f151a22..238ef83bdc 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -[assembly: AssemblyVersion("10.8.0")] -[assembly: AssemblyFileVersion("10.8.0")] +[assembly: AssemblyVersion("10.9.0")] +[assembly: AssemblyFileVersion("10.9.0")] diff --git a/build.yaml b/build.yaml index 18434ee003..3f676a5cfa 100644 --- a/build.yaml +++ b/build.yaml @@ -1,7 +1,7 @@ --- # We just wrap `build` so this is really it name: "jellyfin" -version: "10.8.0" +version: "10.9.0" packages: - debian.amd64 - debian.arm64 diff --git a/debian/changelog b/debian/changelog index 430594cac2..0d744c02a3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +jellyfin-server (10.9.0-1) unstable; urgency=medium + + * New upstream version 10.9.0; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.9.0 + + -- Jellyfin Packaging Team Wed, 13 Jul 2022 20:58:08 -0600 + jellyfin-server (10.8.0-1) unstable; urgency=medium * Forthcoming stable release diff --git a/debian/metapackage/jellyfin b/debian/metapackage/jellyfin index a9a0ae5b01..8787c3a496 100644 --- a/debian/metapackage/jellyfin +++ b/debian/metapackage/jellyfin @@ -5,7 +5,7 @@ Homepage: https://jellyfin.org Standards-Version: 3.9.2 Package: jellyfin -Version: 10.8.0 +Version: 10.9.0 Maintainer: Jellyfin Packaging Team Depends: jellyfin-server, jellyfin-web Description: Provides the Jellyfin Free Software Media System diff --git a/fedora/jellyfin.spec b/fedora/jellyfin.spec index 6b7967478b..13f21ea1ff 100644 --- a/fedora/jellyfin.spec +++ b/fedora/jellyfin.spec @@ -7,7 +7,7 @@ %endif Name: jellyfin -Version: 10.8.0 +Version: 10.9.0 Release: 1%{?dist} Summary: The Free Software Media System License: GPLv2 @@ -176,6 +176,8 @@ fi %systemd_postun_with_restart jellyfin.service %changelog +* Wed Jul 13 2022 Jellyfin Packaging Team +- New upstream version 10.9.0; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.9.0 * Mon Nov 29 2021 Brian J. Murrell - Add jellyfin-server-lowports.service drop-in in a server-lowports subpackage to allow binding to low ports diff --git a/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj b/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj index 23f5d7cda0..f99cb04065 100644 --- a/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj +++ b/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj @@ -13,7 +13,7 @@ Jellyfin Contributors Jellyfin.Extensions - 10.8.0 + 10.9.0 https://github.com/jellyfin/jellyfin GPL-3.0-only From 0d45ccc99c28e09a08806585d148ad4b29516566 Mon Sep 17 00:00:00 2001 From: MaZe3D Date: Thu, 14 Jul 2022 12:01:51 +0000 Subject: [PATCH 14/55] Translated using Weblate (German) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/ --- Emby.Server.Implementations/Localization/Core/de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/de.json b/Emby.Server.Implementations/Localization/Core/de.json index 722b81c8ac..9c278db4d2 100644 --- a/Emby.Server.Implementations/Localization/Core/de.json +++ b/Emby.Server.Implementations/Localization/Core/de.json @@ -121,7 +121,7 @@ "Default": "Standard", "TaskOptimizeDatabaseDescription": "Komprimiert die Datenbank und trimmt den freien Speicherplatz. Die Ausführung dieser Aufgabe nach dem Scannen der Bibliothek oder nach anderen Änderungen, die Datenbankänderungen implizieren, kann die Leistung verbessern.", "TaskOptimizeDatabase": "Datenbank optimieren", - "TaskKeyframeExtractorDescription": "Extrahiere Keyframes aus Videodateien, um präzisere HLS-Playlisten zu erzeugen. Diese Aufgabe kann sehr lange dauern.", + "TaskKeyframeExtractorDescription": "Extrahiere Keyframes aus Videodateien, um präzisere HLS-Playlisten zu erzeugen. Dieser Vorgang kann sehr lange dauern.", "TaskKeyframeExtractor": "Keyframe Extraktor", "External": "Extern" } From 81e164ebc8b7ca7fedbcedb49dc6db939dcde189 Mon Sep 17 00:00:00 2001 From: Nicolas Viviani Date: Mon, 18 Jul 2022 22:39:17 +0000 Subject: [PATCH 15/55] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fr/ --- .../Localization/Core/fr.json | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json index 46f637050a..648c878e9c 100644 --- a/Emby.Server.Implementations/Localization/Core/fr.json +++ b/Emby.Server.Implementations/Localization/Core/fr.json @@ -5,7 +5,7 @@ "Artists": "Artistes", "AuthenticationSucceededWithUserName": "{0} authentifié avec succès", "Books": "Livres", - "CameraImageUploadedFrom": "Une photo a été chargée depuis {0}", + "CameraImageUploadedFrom": "Une photo a été téléversée depuis {0}", "Channels": "Chaînes", "ChapterNameValue": "Chapitre {0}", "Collections": "Collections", @@ -42,13 +42,13 @@ "MusicVideos": "Clips musicaux", "NameInstallFailed": "{0} échec de l'installation", "NameSeasonNumber": "Saison {0}", - "NameSeasonUnknown": "Saison Inconnue", + "NameSeasonUnknown": "Saison inconnue", "NewVersionIsAvailable": "Une nouvelle version de Jellyfin Serveur est disponible au téléchargement.", "NotificationOptionApplicationUpdateAvailable": "Mise à jour de l'application disponible", "NotificationOptionApplicationUpdateInstalled": "Mise à jour de l'application installée", "NotificationOptionAudioPlayback": "Lecture audio démarrée", "NotificationOptionAudioPlaybackStopped": "Lecture audio arrêtée", - "NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été transférée", + "NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été téléversée", "NotificationOptionInstallationFailed": "Échec de l'installation", "NotificationOptionNewLibraryContent": "Nouveau contenu ajouté", "NotificationOptionPluginError": "Erreur d'extension", @@ -93,33 +93,33 @@ "ValueSpecialEpisodeName": "Spécial - {0}", "VersionNumber": "Version {0}", "TasksChannelsCategory": "Chaînes en ligne", - "TaskDownloadMissingSubtitlesDescription": "Recherche les sous-titres manquants sur internet en se basant sur la configuration des métadonnées.", + "TaskDownloadMissingSubtitlesDescription": "Recherche les sous-titres manquants sur Internet en se basant sur la configuration des métadonnées.", "TaskDownloadMissingSubtitles": "Télécharger les sous-titres manquants", - "TaskRefreshChannelsDescription": "Rafraîchit les informations des chaînes en ligne.", - "TaskRefreshChannels": "Rafraîchir les chaînes", + "TaskRefreshChannelsDescription": "Actualise les informations des chaînes en ligne.", + "TaskRefreshChannels": "Actualiser les chaînes", "TaskCleanTranscodeDescription": "Supprime les fichiers transcodés de plus d'un jour.", - "TaskCleanTranscode": "Nettoyer les dossier des transcodages", + "TaskCleanTranscode": "Nettoyer le dossier des transcodages", "TaskUpdatePluginsDescription": "Télécharge et installe les mises à jours des extensions configurées pour être mises à jour automatiquement.", "TaskUpdatePlugins": "Mettre à jour les extensions", - "TaskRefreshPeopleDescription": "Met à jour les métadonnées pour les acteurs et réalisateurs dans votre bibliothèque.", - "TaskRefreshPeople": "Rafraîchir les acteurs", + "TaskRefreshPeopleDescription": "Met à jour les métadonnées pour les acteurs et réalisateurs dans votre médiathèque.", + "TaskRefreshPeople": "Actualiser les acteurs", "TaskCleanLogsDescription": "Supprime les journaux de plus de {0} jours.", "TaskCleanLogs": "Nettoyer le répertoire des journaux", - "TaskRefreshLibraryDescription": "Scanne votre médiathèque pour trouver les nouveaux fichiers et rafraîchit les métadonnées.", + "TaskRefreshLibraryDescription": "Scanne votre médiathèque pour trouver les nouveaux fichiers et actualise les métadonnées.", "TaskRefreshLibrary": "Scanner la médiathèque", "TaskRefreshChapterImagesDescription": "Crée des vignettes pour les vidéos ayant des chapitres.", "TaskRefreshChapterImages": "Extraire les images de chapitre", "TaskCleanCacheDescription": "Supprime les fichiers de cache dont le système n'a plus besoin.", "TaskCleanCache": "Vider le répertoire cache", "TasksApplicationCategory": "Application", - "TasksLibraryCategory": "Bibliothèque", + "TasksLibraryCategory": "Médiathèque", "TasksMaintenanceCategory": "Maintenance", "TaskCleanActivityLogDescription": "Supprime les entrées du journal d'activité antérieures à l'âge configuré.", "TaskCleanActivityLog": "Nettoyer le journal d'activité", "Undefined": "Non défini", "Forced": "Forcé", "Default": "Par défaut", - "TaskOptimizeDatabaseDescription": "Réduit les espaces vides ou inutiles et compacte la base de données. Utiliser cette fonction après une mise à jour de la bibliothèque ou toute autre modification de la base de données peut améliorer les performances du serveur.", + "TaskOptimizeDatabaseDescription": "Réduit les espaces vides ou inutiles et compacte la base de données. Utiliser cette fonction après une mise à jour de la médiathèque ou toute autre modification de la base de données peut améliorer les performances du serveur.", "TaskOptimizeDatabase": "Optimiser la base de données", "TaskKeyframeExtractorDescription": "Extrait les images clés des fichiers vidéo pour créer des listes de lecture HLS plus précises. Cette tâche peut durer très longtemps.", "TaskKeyframeExtractor": "Extracteur d'image clé", From b7206b4816b5faf697035d2a80554069e452edfb Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Wed, 20 Jul 2022 19:29:06 -0400 Subject: [PATCH 16/55] Backport pull request #8013 from jellyfin/release-10.8.z Fix password change during parental control schedule Authored-by: David Ullmer Merged-by: Bond-009 Original-merge: 84a1674f391d344c251c2c949cb227a9318536eb --- Jellyfin.Api/Controllers/UserController.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 6d15d91858..82c8563a80 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -282,16 +282,19 @@ namespace Jellyfin.Api.Controllers } else { - var success = await _userManager.AuthenticateUser( - user.Username, - request.CurrentPw, - request.CurrentPw, - HttpContext.GetNormalizedRemoteIp().ToString(), - false).ConfigureAwait(false); - - if (success == null) + if (!HttpContext.User.IsInRole(UserRoles.Administrator)) { - return StatusCode(StatusCodes.Status403Forbidden, "Invalid user or password entered."); + var success = await _userManager.AuthenticateUser( + user.Username, + request.CurrentPw, + request.CurrentPw, + HttpContext.GetNormalizedRemoteIp().ToString(), + false).ConfigureAwait(false); + + if (success == null) + { + return StatusCode(StatusCodes.Status403Forbidden, "Invalid user or password entered."); + } } await _userManager.ChangePassword(user, request.NewPw).ConfigureAwait(false); From a9449d0f23db890d8a251504afa1b262dae2a513 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Wed, 20 Jul 2022 19:29:06 -0400 Subject: [PATCH 17/55] Backport pull request #8078 from jellyfin/release-10.8.z fix copy&paste error for requestedRangeTypes preventing stream copy Authored-by: Andy Walsh Merged-by: Bond-009 Original-merge: 47c2c536e45792ffe0b5c70d02758463e0c1d407 --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 6fb5c88740..684ea157fd 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1713,6 +1713,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Can't stream copy if we're burning in subtitles if (request.SubtitleStreamIndex.HasValue + && request.SubtitleStreamIndex.Value >= 0 && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) { return false; @@ -1760,7 +1761,7 @@ namespace MediaBrowser.Controller.MediaEncoding } var requestedRangeTypes = state.GetRequestedRangeTypes(videoStream.Codec); - if (requestedProfiles.Length > 0) + if (requestedRangeTypes.Length > 0) { if (string.IsNullOrEmpty(videoStream.VideoRangeType)) { From adc08b5b4c49a1f8b4e5588d184d06454c1d0791 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Wed, 20 Jul 2022 19:29:07 -0400 Subject: [PATCH 18/55] Backport pull request #8092 from jellyfin/release-10.8.z Change allow higher opus, vorbis transcode bitrates Authored-by: Andy Walsh Merged-by: Bond-009 Original-merge: 7ef9e95d75aff2f273c9a98ef83a4fb1df754dd5 --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 684ea157fd..91acca0a75 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2027,6 +2027,8 @@ namespace MediaBrowser.Controller.MediaEncoding { if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase) || string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase) + || string.Equals(audioCodec, "opus", StringComparison.OrdinalIgnoreCase) + || string.Equals(audioCodec, "vorbis", StringComparison.OrdinalIgnoreCase) || string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase) || string.Equals(audioCodec, "eac3", StringComparison.OrdinalIgnoreCase)) { From 924b0740b177f1ac4cc9d03866fd09705258ed91 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Wed, 20 Jul 2022 19:29:08 -0400 Subject: [PATCH 19/55] Backport pull request #8104 from jellyfin/release-10.8.z Add resolution text output for more resolutions Authored-by: Shadowghost Merged-by: Bond-009 Original-merge: 2b46917dcf7af970dc95d4ef0bbfebac7a520d25 --- MediaBrowser.Model/Entities/MediaStream.cs | 19 ++++++--- .../Entities/MediaStreamTests.cs | 40 ++++++++++++++----- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 58988b6fae..ce21707938 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -588,15 +588,22 @@ namespace MediaBrowser.Model.Entities return Width switch { - <= 720 when Height <= 480 => IsInterlaced ? "480i" : "480p", - // 720x576 (PAL) (768 when rescaled for square pixels) - <= 768 when Height <= 576 => IsInterlaced ? "576i" : "576p", - // 960x540 (sometimes 544 which is multiple of 16) + // 256x144 (16:9 square pixel format) + <= 256 when Height <= 144 => IsInterlaced ? "144i" : "144p", + // 426x240 (16:9 square pixel format) + <= 426 when Height <= 240 => IsInterlaced ? "240i" : "240p", + // 640x360 (16:9 square pixel format) + <= 640 when Height <= 360 => IsInterlaced ? "360i" : "360p", + // 854x480 (16:9 square pixel format) + <= 854 when Height <= 480 => IsInterlaced ? "480i" : "480p", + // 960x544 (16:9 square pixel format) <= 960 when Height <= 544 => IsInterlaced ? "540i" : "540p", + // 1024x576 (16:9 square pixel format) + <= 1024 when Height <= 576 => IsInterlaced ? "576i" : "576p", // 1280x720 <= 1280 when Height <= 962 => IsInterlaced ? "720i" : "720p", - // 1920x1080 - <= 1920 when Height <= 1440 => IsInterlaced ? "1080i" : "1080p", + // 2560x1080 (FHD ultra wide 21:9) using 1440px width to accomodate WQHD + <= 2560 when Height <= 1440 => IsInterlaced ? "1080i" : "1080p", // 4K <= 4096 when Height <= 3072 => "4K", // 8K diff --git a/tests/Jellyfin.Model.Tests/Entities/MediaStreamTests.cs b/tests/Jellyfin.Model.Tests/Entities/MediaStreamTests.cs index 9fcf8189f3..7c8a90605b 100644 --- a/tests/Jellyfin.Model.Tests/Entities/MediaStreamTests.cs +++ b/tests/Jellyfin.Model.Tests/Entities/MediaStreamTests.cs @@ -109,26 +109,37 @@ namespace Jellyfin.Model.Tests.Entities [InlineData(null, null, false, null)] [InlineData(null, 0, false, null)] [InlineData(0, null, false, null)] - [InlineData(640, 480, false, "480p")] - [InlineData(640, 480, true, "480i")] - [InlineData(720, 576, false, "576p")] - [InlineData(720, 576, true, "576i")] + [InlineData(256, 144, false, "144p")] + [InlineData(256, 144, true, "144i")] + [InlineData(426, 240, false, "240p")] + [InlineData(426, 240, true, "240i")] + [InlineData(640, 360, false, "360p")] + [InlineData(640, 360, true, "360i")] + [InlineData(854, 480, false, "480p")] + [InlineData(854, 480, true, "480i")] [InlineData(960, 540, false, "540p")] [InlineData(960, 540, true, "540i")] + [InlineData(1024, 576, false, "576p")] + [InlineData(1024, 576, true, "576i")] [InlineData(1280, 720, false, "720p")] [InlineData(1280, 720, true, "720i")] - [InlineData(1920, 1080, false, "1080p")] - [InlineData(1920, 1080, true, "1080i")] + [InlineData(2560, 1080, false, "1080p")] + [InlineData(2560, 1080, true, "1080i")] [InlineData(4096, 3072, false, "4K")] [InlineData(8192, 6144, false, "8K")] [InlineData(512, 384, false, "480p")] - [InlineData(576, 336, false, "480p")] - [InlineData(624, 352, false, "480p")] - [InlineData(640, 352, false, "480p")] + [InlineData(576, 336, false, "360p")] + [InlineData(576, 336, true, "360i")] + [InlineData(624, 352, false, "360p")] + [InlineData(640, 352, false, "360p")] + [InlineData(640, 480, false, "480p")] [InlineData(704, 396, false, "480p")] [InlineData(720, 404, false, "480p")] [InlineData(720, 480, false, "480p")] + [InlineData(720, 576, false, "576p")] [InlineData(768, 576, false, "576p")] + [InlineData(960, 544, false, "540p")] + [InlineData(960, 544, true, "540i")] [InlineData(960, 720, false, "720p")] [InlineData(1280, 528, false, "720p")] [InlineData(1280, 532, false, "720p")] @@ -140,6 +151,11 @@ namespace Jellyfin.Model.Tests.Entities [InlineData(1280, 696, false, "720p")] [InlineData(1280, 716, false, "720p")] [InlineData(1280, 718, false, "720p")] + [InlineData(1920, 1080, false, "1080p")] + [InlineData(1440, 1070, false, "1080p")] + [InlineData(1440, 1072, false, "1080p")] + [InlineData(1440, 1080, false, "1080p")] + [InlineData(1440, 1440, false, "1080p")] [InlineData(1912, 792, false, "1080p")] [InlineData(1916, 1076, false, "1080p")] [InlineData(1918, 1080, false, "1080p")] @@ -153,14 +169,16 @@ namespace Jellyfin.Model.Tests.Entities [InlineData(1920, 960, false, "1080p")] [InlineData(1920, 1024, false, "1080p")] [InlineData(1920, 1040, false, "1080p")] + [InlineData(1920, 1070, false, "1080p")] [InlineData(1920, 1072, false, "1080p")] - [InlineData(1440, 1072, false, "1080p")] - [InlineData(1440, 1080, false, "1080p")] + [InlineData(1920, 1440, false, "1080p")] [InlineData(3840, 1600, false, "4K")] [InlineData(3840, 1606, false, "4K")] [InlineData(3840, 1608, false, "4K")] [InlineData(3840, 2160, false, "4K")] + [InlineData(4090, 3070, false, "4K")] [InlineData(7680, 4320, false, "8K")] + [InlineData(8190, 6140, false, "8K")] public void GetResolutionText_Valid(int? width, int? height, bool interlaced, string expected) { var mediaStream = new MediaStream() From be3d57ad417060d74723582e0d2621665db246c7 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Wed, 20 Jul 2022 19:29:09 -0400 Subject: [PATCH 20/55] Backport pull request #8115 from jellyfin/release-10.8.z Update to dotnet 6.0.7 Authored-by: Cody Robibero Merged-by: Joshua M. Boniface Original-merge: d0fd23bb4b746ffc98fe76a790706ecfa3c19342 --- .../Emby.Server.Implementations.csproj | 2 +- Jellyfin.Api/Jellyfin.Api.csproj | 2 +- Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj | 4 ++-- .../Jellyfin.Server.Implementations.csproj | 8 ++++---- Jellyfin.Server/Jellyfin.Server.csproj | 4 ++-- .../MediaBrowser.MediaEncoding.csproj | 2 +- 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 | 2 +- .../Jellyfin.Server.Integration.Tests.csproj | 2 +- tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj | 2 +- 14 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index cd24cd8729..9e653590b2 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -29,7 +29,7 @@ - + diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index d037ba7123..309e3a9c5b 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -17,7 +17,7 @@ - + diff --git a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj index 94614b4c8c..b64a842927 100644 --- a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj +++ b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj @@ -18,8 +18,8 @@ - - + + diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index 71614dce5d..d7c27542f5 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -27,13 +27,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 0a507c9f96..e372742e06 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -37,8 +37,8 @@ - - + + diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 92c9fc1a00..afe4ff4e71 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -30,7 +30,7 @@ - + diff --git a/deployment/Dockerfile.centos.amd64 b/deployment/Dockerfile.centos.amd64 index 20847fd258..89c74aadbe 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/77d472e5-194c-421e-992d-e4ca1d08e6cc/56c61ac303ddf1b12026151f4f000a2b/dotnet-sdk-6.0.301-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/0e83f50a-0619-45e6-8f16-dc4f41d1bb16/e0de908b2f070ef9e7e3b6ddea9d268c/dotnet-sdk-6.0.302-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 5da6fbf774..2135d6f01f 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 make # Install DotNET SDK -RUN wget -q https://download.visualstudio.microsoft.com/download/pr/77d472e5-194c-421e-992d-e4ca1d08e6cc/56c61ac303ddf1b12026151f4f000a2b/dotnet-sdk-6.0.301-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/0e83f50a-0619-45e6-8f16-dc4f41d1bb16/e0de908b2f070ef9e7e3b6ddea9d268c/dotnet-sdk-6.0.302-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 34ef0c20de..24330f629e 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/77d472e5-194c-421e-992d-e4ca1d08e6cc/56c61ac303ddf1b12026151f4f000a2b/dotnet-sdk-6.0.301-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/0e83f50a-0619-45e6-8f16-dc4f41d1bb16/e0de908b2f070ef9e7e3b6ddea9d268c/dotnet-sdk-6.0.302-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 f3a7de56d7..507f446cc2 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/77d472e5-194c-421e-992d-e4ca1d08e6cc/56c61ac303ddf1b12026151f4f000a2b/dotnet-sdk-6.0.301-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/0e83f50a-0619-45e6-8f16-dc4f41d1bb16/e0de908b2f070ef9e7e3b6ddea9d268c/dotnet-sdk-6.0.302-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 fa21daf669..31513541cf 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/77d472e5-194c-421e-992d-e4ca1d08e6cc/56c61ac303ddf1b12026151f4f000a2b/dotnet-sdk-6.0.301-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/0e83f50a-0619-45e6-8f16-dc4f41d1bb16/e0de908b2f070ef9e7e3b6ddea9d268c/dotnet-sdk-6.0.302-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 a08220858e..1f1e2910aa 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -15,7 +15,7 @@ - + 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 07c5e94ded..e2a0fe89bc 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj +++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index 3e445e012a..fb90c69de9 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -10,7 +10,7 @@ - + From 8ccd9d8dfab5fa766467500beddd8041ebcdfb5c Mon Sep 17 00:00:00 2001 From: norikhwan-ali Date: Thu, 21 Jul 2022 14:14:16 +0000 Subject: [PATCH 21/55] Translated using Weblate (Malay) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ms/ --- Emby.Server.Implementations/Localization/Core/ms.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json index deb28970c0..3d54a5a950 100644 --- a/Emby.Server.Implementations/Localization/Core/ms.json +++ b/Emby.Server.Implementations/Localization/Core/ms.json @@ -61,7 +61,7 @@ "NotificationOptionVideoPlayback": "Ulangmain video bermula", "NotificationOptionVideoPlaybackStopped": "Ulangmain video dihentikan", "Photos": "Gambar-gambar", - "Playlists": "Senarai main", + "Playlists": "Senarai ulangmain", "Plugin": "Plugin", "PluginInstalledWithName": "{0} telah dipasang", "PluginUninstalledWithName": "{0} telah dinyahpasang", From 410871e14882fe8622c4d992658eb30f0c850a3e Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 24 Jul 2022 12:35:46 -0400 Subject: [PATCH 22/55] Backport pull request #7732 from jellyfin/release-10.8.z Fix to make web sockets close gracefully on server shutdown Authored-by: luke brown Merged-by: Cody Robibero Original-merge: ee22feb89a34632a4cc3a350733dd57c6be863ec --- .../ApplicationHost.cs | 46 ++++++++++++++++++- .../HttpServer/WebSocketConnection.cs | 33 ++++++++++++- .../Session/WebSocketController.cs | 19 +++++++- Jellyfin.Server/Program.cs | 2 +- .../Net/IWebSocketConnection.cs | 2 +- .../Session/SessionInfo.cs | 23 +++++++++- 6 files changed, 118 insertions(+), 7 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 32289625fe..bc55dc6b48 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -111,7 +111,7 @@ namespace Emby.Server.Implementations /// /// Class CompositionRoot. /// - public abstract class ApplicationHost : IServerApplicationHost, IDisposable + public abstract class ApplicationHost : IServerApplicationHost, IAsyncDisposable, IDisposable { /// /// The environment variable prefixes to log at server startup. @@ -1232,5 +1232,49 @@ namespace Emby.Server.Implementations _disposed = true; } + + public async ValueTask DisposeAsync() + { + await DisposeAsyncCore().ConfigureAwait(false); + Dispose(false); + GC.SuppressFinalize(this); + } + + /// + /// Used to perform asynchronous cleanup of managed resources or for cascading calls to . + /// + /// A ValueTask. + protected virtual async ValueTask DisposeAsyncCore() + { + var type = GetType(); + + Logger.LogInformation("Disposing {Type}", type.Name); + + foreach (var (part, _) in _disposableParts) + { + var partType = part.GetType(); + if (partType == type) + { + continue; + } + + Logger.LogInformation("Disposing {Type}", partType.Name); + + try + { + part.Dispose(); + } + catch (Exception ex) + { + Logger.LogError(ex, "Error disposing {Type}", partType.Name); + } + } + + // used for closing websockets + foreach (var session in _sessionManager.Sessions) + { + await session.DisposeAsync().ConfigureAwait(false); + } + } } } diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index b87f1bc226..818ccbb1b8 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.HttpServer /// /// Class WebSocketConnection. /// - public class WebSocketConnection : IWebSocketConnection, IDisposable + public class WebSocketConnection : IWebSocketConnection { /// /// The logger. @@ -36,6 +36,8 @@ namespace Emby.Server.Implementations.HttpServer /// private readonly WebSocket _socket; + private bool _disposed = false; + /// /// Initializes a new instance of the class. /// @@ -244,10 +246,39 @@ namespace Emby.Server.Implementations.HttpServer /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool dispose) { + if (_disposed) + { + return; + } + if (dispose) { _socket.Dispose(); } + + _disposed = true; + } + + /// + public async ValueTask DisposeAsync() + { + await DisposeAsyncCore().ConfigureAwait(false); + Dispose(false); + GC.SuppressFinalize(this); + } + + /// + /// Used to perform asynchronous cleanup of managed resources or for cascading calls to . + /// + /// A ValueTask. + protected virtual async ValueTask DisposeAsyncCore() + { + if (_socket.State == WebSocketState.Open) + { + await _socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "System Shutdown", CancellationToken.None).ConfigureAwait(false); + } + + _socket.Dispose(); } } } diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs index d21b6a929c..1f3248f075 100644 --- a/Emby.Server.Implementations/Session/WebSocketController.cs +++ b/Emby.Server.Implementations/Session/WebSocketController.cs @@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Session { - public sealed class WebSocketController : ISessionController, IDisposable + public sealed class WebSocketController : ISessionController, IAsyncDisposable, IDisposable { private readonly ILogger _logger; private readonly ISessionManager _sessionManager; @@ -99,6 +99,23 @@ namespace Emby.Server.Implementations.Session foreach (var socket in _sockets) { socket.Closed -= OnConnectionClosed; + socket.Dispose(); + } + + _disposed = true; + } + + public async ValueTask DisposeAsync() + { + if (_disposed) + { + return; + } + + foreach (var socket in _sockets) + { + socket.Closed -= OnConnectionClosed; + await socket.DisposeAsync().ConfigureAwait(false); } _disposed = true; diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 2bda8d2905..a6f0b705dc 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -243,7 +243,7 @@ namespace Jellyfin.Server } } - appHost.Dispose(); + await appHost.DisposeAsync().ConfigureAwait(false); } if (_restartOnShutdown) diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index 2c6483ae28..43c7ce3708 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { - public interface IWebSocketConnection + public interface IWebSocketConnection : IAsyncDisposable, IDisposable { /// /// Occurs when [closed]. diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index c2ca233868..b4520ae48f 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; using System.Threading; +using System.Threading.Tasks; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Session; @@ -17,7 +18,7 @@ namespace MediaBrowser.Controller.Session /// /// Class SessionInfo. /// - public sealed class SessionInfo : IDisposable + public sealed class SessionInfo : IAsyncDisposable, IDisposable { // 1 second private const long ProgressIncrement = 10000000; @@ -380,10 +381,28 @@ namespace MediaBrowser.Controller.Session { if (controller is IDisposable disposable) { - _logger.LogDebug("Disposing session controller {0}", disposable.GetType().Name); + _logger.LogDebug("Disposing session controller synchronously {TypeName}", disposable.GetType().Name); disposable.Dispose(); } } } + + public async ValueTask DisposeAsync() + { + _disposed = true; + + StopAutomaticProgress(); + + var controllers = SessionControllers.ToList(); + + foreach (var controller in controllers) + { + if (controller is IAsyncDisposable disposableAsync) + { + _logger.LogDebug("Disposing session controller asynchronously {TypeName}", disposableAsync.GetType().Name); + await disposableAsync.DisposeAsync().ConfigureAwait(false); + } + } + } } } From 76f7a80a97f19adc6126eaef02dc64fe9a581b48 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 24 Jul 2022 12:35:46 -0400 Subject: [PATCH 23/55] Backport pull request #8152 from jellyfin/release-10.8.z Fix support for rtsp streams over tcp Authored-by: Bill Thornton Merged-by: Cody Robibero Original-merge: b2fb96ffed73dd9fcbc90b4645577f860ad4daf1 --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 91acca0a75..15afde601d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -4970,7 +4970,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.InputProtocol == MediaProtocol.Rtsp) { - inputModifier += " -rtsp_transport tcp -rtsp_transport udp -rtsp_flags prefer_tcp"; + inputModifier += " -rtsp_transport tcp+udp -rtsp_flags prefer_tcp"; } if (!string.IsNullOrEmpty(state.InputAudioSync)) From bffda19bbc9d8fe95c864d7315a0c6f6a05d9d7d Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 24 Jul 2022 12:35:47 -0400 Subject: [PATCH 24/55] Backport pull request #8166 from jellyfin/release-10.8.z Bind @userid only when it's in the statement Authored-by: Joseph <1315585+joseph39@users.noreply.github.com> Merged-by: Claus Vium Original-merge: 057e8ef24061a969d4ca31b5b115e14d5ba76fe4 --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 4361440d75..1b176e60d7 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -4934,6 +4934,7 @@ SELECT key FROM UserDatas WHERE isFavorite=@IsFavorite AND userId=@UserId) AND Type = @InternalPersonType)"); statement?.TryBind("@IsFavorite", query.IsFavorite.Value); statement?.TryBind("@InternalPersonType", typeof(Person).FullName); + statement?.TryBind("@UserId", query.User.InternalId); } if (!query.ItemId.Equals(default)) @@ -4988,11 +4989,6 @@ AND Type = @InternalPersonType)"); statement?.TryBind("@NameContains", "%" + query.NameContains + "%"); } - if (query.User != null) - { - statement?.TryBind("@UserId", query.User.InternalId); - } - return whereClauses; } From ce1356b2f2009c246b47cbb27cd886a5025a1ba2 Mon Sep 17 00:00:00 2001 From: Pretendexxx Date: Sun, 24 Jul 2022 10:47:35 +0000 Subject: [PATCH 25/55] Translated using Weblate (Lithuanian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lt/ --- Emby.Server.Implementations/Localization/Core/lt-LT.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json index cb98d8e413..232b3ec934 100644 --- a/Emby.Server.Implementations/Localization/Core/lt-LT.json +++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json @@ -39,7 +39,7 @@ "MixedContent": "Mixed content", "Movies": "Filmai", "Music": "Muzika", - "MusicVideos": "Muzikiniai klipai", + "MusicVideos": "Muzikiniai vaizdo įrašai", "NameInstallFailed": "{0} diegimo klaida", "NameSeasonNumber": "Sezonas {0}", "NameSeasonUnknown": "Sezonas neatpažintas", From c69b2c849ade5bcebed9ab79a020895285f8fdc6 Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Sat, 30 Jul 2022 08:12:59 -0500 Subject: [PATCH 26/55] add comments --- Jellyfin.Api/Controllers/ItemsController.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index bfa4f9fe72..a61b952f00 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -246,10 +246,12 @@ namespace Jellyfin.Api.Controllers { var auth = await _authContext.GetAuthorizationInfo(Request).ConfigureAwait(false); + // if api key is used (auth.IsApiKey == true), then `user` will be null throughout this method var user = !auth.IsApiKey && userId.HasValue && !userId.Value.Equals(default) ? _userManager.GetUserById(userId.Value) : null; + // beyond this point, we're either using an api key or we have a valid user if (!auth.IsApiKey && user is null) { return BadRequest("userId is required"); @@ -290,6 +292,7 @@ namespace Jellyfin.Api.Controllers ? Array.Empty() : user!.GetPreferenceValues(PreferenceKind.EnabledChannels); + // api keys are always enabled for all folders bool isInEnabledFolder = auth.IsApiKey || Array.IndexOf(user!.GetPreferenceValues(PreferenceKind.EnabledFolders), item.Id) != -1 // Assume all folders inside an EnabledChannel are enabled @@ -302,6 +305,7 @@ namespace Jellyfin.Api.Controllers var collectionFolders = _libraryManager.GetCollectionFolders(item); foreach (var collectionFolder in collectionFolders) { + // api keys never enter this block, so user is never null if (user!.GetPreferenceValues(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id)) { isInEnabledFolder = true; @@ -309,6 +313,7 @@ namespace Jellyfin.Api.Controllers } } + // api keys are always enabled for all folders, so user is never null if (item is not UserRootFolder && !isInEnabledFolder && !user!.HasPermission(PermissionKind.EnableAllFolders) From 4358fd01147c30fa7cc96bebd229324c145dc6f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 12:01:12 +0000 Subject: [PATCH 27/55] Bump sharpcompress from 0.32.1 to 0.32.2 Bumps [sharpcompress](https://github.com/adamhathcock/sharpcompress) from 0.32.1 to 0.32.2. - [Release notes](https://github.com/adamhathcock/sharpcompress/releases) - [Commits](https://github.com/adamhathcock/sharpcompress/compare/0.32.1...0.32.2) --- updated-dependencies: - dependency-name: sharpcompress 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(-) diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 9e653590b2..5d20870016 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -32,7 +32,7 @@ - + From 3e24b8943da60008a06bec325c075c35142da4be Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Mon, 1 Aug 2022 14:25:41 -0400 Subject: [PATCH 28/55] Backport pull request #8061 from jellyfin/release-10.8.z Fix intel dx11-ocl interop taking too long to initialize on windows Authored-by: nyanmisaka Merged-by: Claus Vium Original-merge: 9854751137db1578c31f1b8cefcbb1a1bc1ff206 --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 15afde601d..f1f79a8633 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -4506,7 +4506,9 @@ namespace MediaBrowser.Controller.MediaEncoding if (isD3d11Supported && isCodecAvailable) { - return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty) + (isAv1 ? " -c:v av1" : string.Empty); + // set -threads 3 to intel d3d11va decoder explicitly. Lower threads may result in dead lock. + // on newer devices such as Xe, the larger the init_pool_size, the longer the initialization time for opencl to derive from d3d11. + return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty) + " -threads 3" + (isAv1 ? " -c:v av1" : string.Empty); } } else From 38eefbbafa381ea2d87efaa3328c5e273b902732 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Mon, 1 Aug 2022 14:25:42 -0400 Subject: [PATCH 29/55] Backport pull request #8087 from jellyfin/release-10.8.z feat: make subtitleeditparser generic Authored-by: Claus Vium Merged-by: Bond-009 Original-merge: 7323ccfc232d31797af3ceb8bad93cae1ea0898d --- .../ApplicationHost.cs | 4 +- .../Subtitles/AssParser.cs | 19 ----- .../Subtitles/ISubtitleParser.cs | 12 ++- .../Subtitles/SrtParser.cs | 19 ----- .../Subtitles/SsaParser.cs | 19 ----- .../Subtitles/SubtitleEditParser.cs | 85 ++++++++++++++++--- .../Subtitles/SubtitleEncoder.cs | 47 ++-------- .../Subtitles/AssParserTests.cs | 2 +- .../Subtitles/SrtParserTests.cs | 4 +- .../Subtitles/SsaParserTests.cs | 6 +- 10 files changed, 98 insertions(+), 119 deletions(-) delete mode 100644 MediaBrowser.MediaEncoding/Subtitles/AssParser.cs delete mode 100644 MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs delete mode 100644 MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index bc55dc6b48..91a16c199d 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -83,6 +83,7 @@ using MediaBrowser.Controller.SyncPlay; using MediaBrowser.Controller.TV; using MediaBrowser.LocalMetadata.Savers; using MediaBrowser.MediaEncoding.BdInfo; +using MediaBrowser.MediaEncoding.Subtitles; using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; @@ -634,7 +635,8 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs deleted file mode 100644 index 08ee5c72e5..0000000000 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.Logging; -using Nikse.SubtitleEdit.Core.SubtitleFormats; - -namespace MediaBrowser.MediaEncoding.Subtitles -{ - /// - /// Advanced SubStation Alpha subtitle parser. - /// - public class AssParser : SubtitleEditParser - { - /// - /// Initializes a new instance of the class. - /// - /// The logger. - public AssParser(ILogger logger) : base(logger) - { - } - } -} diff --git a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs index c0023ebf24..bd13437fb6 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs @@ -1,7 +1,6 @@ #pragma warning disable CS1591 using System.IO; -using System.Threading; using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles @@ -12,8 +11,15 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// Parses the specified stream. /// /// The stream. - /// The cancellation token. + /// The file extension. /// SubtitleTrackInfo. - SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken); + SubtitleTrackInfo Parse(Stream stream, string fileExtension); + + /// + /// Determines whether the file extension is supported by the parser. + /// + /// The file extension. + /// A value indicating whether the file extension is supported. + bool SupportsFileExtension(string fileExtension); } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs deleted file mode 100644 index 78d54ca51f..0000000000 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.Logging; -using Nikse.SubtitleEdit.Core.SubtitleFormats; - -namespace MediaBrowser.MediaEncoding.Subtitles -{ - /// - /// SubRip subtitle parser. - /// - public class SrtParser : SubtitleEditParser - { - /// - /// Initializes a new instance of the class. - /// - /// The logger. - public SrtParser(ILogger logger) : base(logger) - { - } - } -} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs deleted file mode 100644 index 17c2ae40e0..0000000000 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.Logging; -using Nikse.SubtitleEdit.Core.SubtitleFormats; - -namespace MediaBrowser.MediaEncoding.Subtitles -{ - /// - /// SubStation Alpha subtitle parser. - /// - public class SsaParser : SubtitleEditParser - { - /// - /// Initializes a new instance of the class. - /// - /// The logger. - public SsaParser(ILogger logger) : base(logger) - { - } - } -} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index 52c1b64677..eb8ff96246 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -1,12 +1,14 @@ +using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Threading; +using System.Reflection; using Jellyfin.Extensions; using MediaBrowser.Model.MediaInfo; using Microsoft.Extensions.Logging; using Nikse.SubtitleEdit.Core.Common; -using ILogger = Microsoft.Extensions.Logging.ILogger; +using Nikse.SubtitleEdit.Core.SubtitleFormats; using SubtitleFormat = Nikse.SubtitleEdit.Core.SubtitleFormats.SubtitleFormat; namespace MediaBrowser.MediaEncoding.Subtitles @@ -14,31 +16,57 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// /// SubStation Alpha subtitle parser. /// - /// The . - public abstract class SubtitleEditParser : ISubtitleParser - where T : SubtitleFormat, new() + public class SubtitleEditParser : ISubtitleParser { - private readonly ILogger _logger; + private readonly ILogger _logger; + private readonly Dictionary _subtitleFormats; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The logger. - protected SubtitleEditParser(ILogger logger) + public SubtitleEditParser(ILogger logger) { _logger = logger; + _subtitleFormats = GetSubtitleFormats() + .Where(subtitleFormat => !string.IsNullOrEmpty(subtitleFormat.Extension)) + .GroupBy(subtitleFormat => subtitleFormat.Extension.TrimStart('.'), StringComparer.OrdinalIgnoreCase) + .ToDictionary(g => g.Key, g => g.ToArray(), StringComparer.OrdinalIgnoreCase); } /// - public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) + public SubtitleTrackInfo Parse(Stream stream, string fileExtension) { var subtitle = new Subtitle(); - var subRip = new T(); var lines = stream.ReadAllLines().ToList(); - subRip.LoadSubtitle(subtitle, lines, "untitled"); - if (subRip.ErrorCount > 0) + + if (!_subtitleFormats.TryGetValue(fileExtension, out var subtitleFormats)) { - _logger.LogError("{ErrorCount} errors encountered while parsing subtitle", subRip.ErrorCount); + throw new ArgumentException($"Unsupported file extension: {fileExtension}", nameof(fileExtension)); + } + + foreach (var subtitleFormat in subtitleFormats) + { + _logger.LogDebug( + "Trying to parse '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser", + fileExtension, + subtitleFormat.Name); + subtitleFormat.LoadSubtitle(subtitle, lines, fileExtension); + if (subtitleFormat.ErrorCount == 0) + { + break; + } + + _logger.LogError( + "{ErrorCount} errors encountered while parsing '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser", + subtitleFormat.ErrorCount, + fileExtension, + subtitleFormat.Name); + } + + if (subtitle.Paragraphs.Count == 0) + { + throw new ArgumentException("Unsupported format: " + fileExtension); } var trackInfo = new SubtitleTrackInfo(); @@ -57,5 +85,36 @@ namespace MediaBrowser.MediaEncoding.Subtitles trackInfo.TrackEvents = trackEvents; return trackInfo; } + + /// + public bool SupportsFileExtension(string fileExtension) + => _subtitleFormats.ContainsKey(fileExtension); + + private IEnumerable GetSubtitleFormats() + { + var subtitleFormats = new List(); + var assembly = typeof(SubtitleFormat).Assembly; + + foreach (var type in assembly.GetTypes()) + { + if (!type.IsSubclassOf(typeof(SubtitleFormat)) || type.IsAbstract) + { + continue; + } + + try + { + // It shouldn't be null, but the exception is caught if it is + var subtitleFormat = (SubtitleFormat)Activator.CreateInstance(type, true)!; + subtitleFormats.Add(subtitleFormat); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to create instance of the subtitle format {SubtitleFormatType}", type.Name); + } + } + + return subtitleFormats; + } } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 7091af734a..50c4d92103 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -35,6 +35,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles private readonly IMediaEncoder _mediaEncoder; private readonly IHttpClientFactory _httpClientFactory; private readonly IMediaSourceManager _mediaSourceManager; + private readonly ISubtitleParser _subtitleParser; /// /// The _semaphoreLocks. @@ -48,7 +49,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles IFileSystem fileSystem, IMediaEncoder mediaEncoder, IHttpClientFactory httpClientFactory, - IMediaSourceManager mediaSourceManager) + IMediaSourceManager mediaSourceManager, + ISubtitleParser subtitleParser) { _logger = logger; _appPaths = appPaths; @@ -56,6 +58,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles _mediaEncoder = mediaEncoder; _httpClientFactory = httpClientFactory; _mediaSourceManager = mediaSourceManager; + _subtitleParser = subtitleParser; } private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); @@ -73,8 +76,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { - var reader = GetReader(inputFormat); - var trackInfo = reader.Parse(stream, cancellationToken); + var trackInfo = _subtitleParser.Parse(stream, inputFormat); FilterEvents(trackInfo, startTimeTicks, endTimeTicks, preserveOriginalTimestamps); @@ -233,7 +235,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec) .TrimStart('.'); - if (!TryGetReader(currentFormat, out _)) + // Fallback to ffmpeg conversion + if (!_subtitleParser.SupportsFileExtension(currentFormat)) { // Convert var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, ".srt"); @@ -243,44 +246,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles return new SubtitleInfo(outputPath, MediaProtocol.File, "srt", true); } - // It's possbile that the subtitleStream and mediaSource don't share the same protocol (e.g. .STRM file with local subs) + // It's possible that the subtitleStream and mediaSource don't share the same protocol (e.g. .STRM file with local subs) return new SubtitleInfo(subtitleStream.Path, _mediaSourceManager.GetPathProtocol(subtitleStream.Path), currentFormat, true); } - private bool TryGetReader(string format, [NotNullWhen(true)] out ISubtitleParser? value) - { - if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase)) - { - value = new SrtParser(_logger); - return true; - } - - if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase)) - { - value = new SsaParser(_logger); - return true; - } - - if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase)) - { - value = new AssParser(_logger); - return true; - } - - value = null; - return false; - } - - private ISubtitleParser GetReader(string format) - { - if (TryGetReader(format, out var reader)) - { - return reader; - } - - throw new ArgumentException("Unsupported format: " + format); - } - private bool TryGetWriter(string format, [NotNullWhen(true)] out ISubtitleWriter? value) { if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase)) diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs index 3775555dec..e14850eed7 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs @@ -15,7 +15,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example.ass")) { - var parsed = new AssParser(new NullLogger()).Parse(stream, CancellationToken.None); + var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, "ass"); Assert.Single(parsed.TrackEvents); var trackEvent = parsed.TrackEvents[0]; diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs index c07c9ea7db..0038b18736 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs @@ -15,7 +15,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example.srt")) { - var parsed = new SrtParser(new NullLogger()).Parse(stream, CancellationToken.None); + var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, "srt"); Assert.Equal(2, parsed.TrackEvents.Count); var trackEvent1 = parsed.TrackEvents[0]; @@ -37,7 +37,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example2.srt")) { - var parsed = new SrtParser(new NullLogger()).Parse(stream, CancellationToken.None); + var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, "srt"); Assert.Equal(2, parsed.TrackEvents.Count); var trackEvent1 = parsed.TrackEvents[0]; diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs index 56649db8f8..3b9a71690c 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs @@ -13,7 +13,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { public class SsaParserTests { - private readonly SsaParser _parser = new SsaParser(new NullLogger()); + private readonly SubtitleEditParser _parser = new SubtitleEditParser(new NullLogger()); [Theory] [MemberData(nameof(Parse_MultipleDialogues_TestData))] @@ -21,7 +21,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(ssa))) { - SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, CancellationToken.None); + SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, "ssa"); Assert.Equal(expectedSubtitleTrackEvents.Count, subtitleTrackInfo.TrackEvents.Count); @@ -76,7 +76,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example.ssa")) { - var parsed = _parser.Parse(stream, CancellationToken.None); + var parsed = _parser.Parse(stream, "ssa"); Assert.Single(parsed.TrackEvents); var trackEvent = parsed.TrackEvents[0]; From 38f6f589d96803d6f015a069ed7ad2bc958acf92 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Mon, 1 Aug 2022 14:25:43 -0400 Subject: [PATCH 30/55] Backport pull request #8127 from jellyfin/release-10.8.z Workaround for linux 5.18+ i915 hang at cost of performance Authored-by: Nyanmisaka Merged-by: Claus Vium Original-merge: 484427b4aa9b94a1864bc7dfc104fa52d6b38f0e --- .../MediaEncoding/EncodingHelper.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index f1f79a8633..1d65f9a345 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -35,6 +35,7 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly IMediaEncoder _mediaEncoder; private readonly ISubtitleEncoder _subtitleEncoder; private readonly IConfiguration _config; + private readonly Version _minKernelVersioni915Hang = new Version(5, 18); private static readonly string[] _videoProfilesH264 = new[] { @@ -1302,6 +1303,10 @@ namespace MediaBrowser.Controller.MediaEncoding // which will reduce overhead in performance intensive tasks such as 4k transcoding and tonemapping. var intelLowPowerHwEncoding = false; + // Workaround for linux 5.18+ i915 hang at cost of performance. + // https://github.com/intel/media-driver/issues/1456 + var enableWaFori915Hang = false; + if (string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { var isIntelVaapiDriver = _mediaEncoder.IsVaapiDeviceInteliHD || _mediaEncoder.IsVaapiDeviceInteli965; @@ -1317,6 +1322,20 @@ namespace MediaBrowser.Controller.MediaEncoding } else if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { + if (OperatingSystem.IsLinux() && Environment.OSVersion.Version >= _minKernelVersioni915Hang) + { + var vidDecoder = GetHardwareVideoDecoder(state, encodingOptions) ?? string.Empty; + var isIntelDecoder = vidDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase) + || vidDecoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase); + var doOclTonemap = _mediaEncoder.SupportsHwaccel("qsv") + && IsVaapiSupported(state) + && IsOpenclFullSupported() + && !IsVaapiVppTonemapAvailable(state, encodingOptions) + && IsHwTonemapAvailable(state, encodingOptions); + + enableWaFori915Hang = isIntelDecoder && doOclTonemap; + } + if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { intelLowPowerHwEncoding = encodingOptions.EnableIntelLowPowerH264HwEncoder; @@ -1325,6 +1344,10 @@ namespace MediaBrowser.Controller.MediaEncoding { intelLowPowerHwEncoding = encodingOptions.EnableIntelLowPowerHevcHwEncoder; } + else + { + enableWaFori915Hang = false; + } } if (intelLowPowerHwEncoding) @@ -1332,6 +1355,11 @@ namespace MediaBrowser.Controller.MediaEncoding param += " -low_power 1"; } + if (enableWaFori915Hang) + { + param += " -async_depth 1"; + } + var isVc1 = string.Equals(state.VideoStream?.Codec, "vc1", StringComparison.OrdinalIgnoreCase); var isLibX265 = string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase); From 0356a15056adc1ab5ec89c6a5045bb1ad73aeca4 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Mon, 1 Aug 2022 14:25:44 -0400 Subject: [PATCH 31/55] Backport pull request #8163 from jellyfin/release-10.8.z Don't refresh playlists on album refresh Authored-by: David Ullmer Merged-by: Claus Vium Original-merge: 444b0ea3105517900e869d73223b8bf984f28aa4 --- MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 03d1f33043..bd397bdd13 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -169,8 +169,8 @@ namespace MediaBrowser.Controller.Entities.Audio var childUpdateType = ItemUpdateType.None; - // Refresh songs - foreach (var item in items) + // Refresh songs only and not m3u files in album folder + foreach (var item in items.OfType /// The subscription identifier. /// The notification type. - /// The requested timeout as a sting. + /// The requested timeout as a string. /// The callback url. /// The response. EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl); @@ -25,7 +25,7 @@ namespace Emby.Dlna /// Creates the event subscription. /// /// The notification type. - /// The requested timeout as a sting. + /// The requested timeout as a string. /// The callback url. /// The response. EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl); diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 2843fb8f83..6796845525 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2529,7 +2529,7 @@ namespace Emby.Server.Implementations.Library } catch (Exception ex) { - _logger.LogError(ex, "Error reading the episode informations with ffprobe. Episode: {EpisodeInfo}", episodeInfo.Path); + _logger.LogError(ex, "Error reading the episode information with ffprobe. Episode: {EpisodeInfo}", episodeInfo.Path); } var changed = false; diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index a60251dacd..b2f388a667 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -387,7 +387,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies if (!string.IsNullOrEmpty(item.Path)) { - // check for imdb id - we use full media path, as we can assume, that this will match in any use case (wither id in parent dir or in file name) + // check for imdb id - we use full media path, as we can assume, that this will match in any use case (either id in parent dir or in file name) var imdbid = item.Path.AsSpan().GetAttributeValue("imdbid"); if (!string.IsNullOrWhiteSpace(imdbid)) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index 708ff52d79..be06356a4f 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -199,7 +199,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts if (string.IsNullOrWhiteSpace(numberString)) { // Using this as a fallback now as this leads to Problems with channels like "5 USA" - // where 5 isn't ment to be the channel number + // where 5 isn't meant to be the channel number // Check for channel number with the format from SatIp // #EXTINF:0,84. VOX Schweiz // #EXTINF:0,84.0 - VOX Schweiz diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index d25376297f..7f927e2709 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1242,7 +1242,7 @@ namespace Emby.Server.Implementations.Session if (item == null) { - _logger.LogError("A non-existant item Id {0} was passed into TranslateItemForPlayback", id); + _logger.LogError("A non-existent item Id {0} was passed into TranslateItemForPlayback", id); return Array.Empty(); } diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index a085ee546d..fccf50f60f 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -37,7 +37,7 @@ namespace Emby.Server.Implementations.Session private const float ForceKeepAliveFactor = 0.75f; /// - /// Lock used for accesing the KeepAlive cancellation token. + /// Lock used for accessing the KeepAlive cancellation token. /// private readonly object _keepAliveLock = new object(); diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index 54ac06276e..94f7a7b827 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -207,7 +207,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The dlna device profile id to utilize. /// The play session id. /// The segment container. - /// The segment lenght. + /// The segment length. /// The minimum number of segments. /// The media version id, if playing an alternate version. /// The device id of the client requesting. Used to stop encoding processes when needed. diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 1e8d038751..3ed80f6621 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -121,7 +121,7 @@ namespace Jellyfin.Api.Controllers /// Optional. The dlna device profile id to utilize. /// The play session id. /// The segment container. - /// The segment lenght. + /// The segment length. /// The minimum number of segments. /// The media version id, if playing an alternate version. /// The device id of the client requesting. Used to stop encoding processes when needed. @@ -1832,7 +1832,7 @@ namespace Jellyfin.Api.Controllers // Set the key frame params for video encoding to match the hls segment time. args += _encodingHelper.GetHlsVideoKeyFrameArguments(state, codec, state.SegmentLength, isEventPlaylist, startNumber); - // Currenly b-frames in libx265 breaks the FMP4-HLS playback on iOS, disable it for now. + // Currently b-frames in libx265 breaks the FMP4-HLS playback on iOS, disable it for now. if (string.Equals(codec, "libx265", StringComparison.OrdinalIgnoreCase)) { args += " -bf 0"; diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 07e113ad3e..3b1f7a52ab 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -60,9 +60,9 @@ namespace Jellyfin.Api.Controllers /// Optional. The maximum number of records to return. /// Optional. Supply a user id to search within a user's library or omit to search all. /// The search term to filter on. - /// If specified, only results with the specified item types are returned. This allows multiple, comma delimeted. - /// If specified, results with these item types are filtered out. This allows multiple, comma delimeted. - /// If specified, only results with the specified media types are returned. This allows multiple, comma delimeted. + /// If specified, only results with the specified item types are returned. This allows multiple, comma delimited. + /// If specified, results with these item types are filtered out. This allows multiple, comma delimited. + /// If specified, only results with the specified media types are returned. This allows multiple, comma delimited. /// If specified, only children of the parent are returned. /// Optional filter for movies. /// Optional filter for series. diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 82c8563a80..d1109bebc8 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -502,7 +502,7 @@ namespace Jellyfin.Api.Controllers if (isLocal) { - _logger.LogWarning("Password reset proccess initiated from outside the local network with IP: {IP}", ip); + _logger.LogWarning("Password reset process initiated from outside the local network with IP: {IP}", ip); } var result = await _userManager.StartForgotPasswordProcess(forgotPasswordRequest.EnteredUsername, isLocal).ConfigureAwait(false); diff --git a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs index 192f33ebd1..8182e3c9e8 100644 --- a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs +++ b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs @@ -169,7 +169,7 @@ namespace Jellyfin.Api.Models.StreamingDtos /// /// Disposes the stream state. /// - /// Whether the object is currently beeing disposed. + /// Whether the object is currently being disposed. protected virtual void Dispose(bool disposing) { if (_disposed) diff --git a/Jellyfin.Api/Models/SyncPlayDtos/RemoveFromPlaylistRequestDto.cs b/Jellyfin.Api/Models/SyncPlayDtos/RemoveFromPlaylistRequestDto.cs index 02ce5a0488..226a584e1d 100644 --- a/Jellyfin.Api/Models/SyncPlayDtos/RemoveFromPlaylistRequestDto.cs +++ b/Jellyfin.Api/Models/SyncPlayDtos/RemoveFromPlaylistRequestDto.cs @@ -17,9 +17,9 @@ namespace Jellyfin.Api.Models.SyncPlayDtos } /// - /// Gets or sets the playlist identifiers ot the items. Ignored when clearing the playlist. + /// Gets or sets the playlist identifiers of the items. Ignored when clearing the playlist. /// - /// The playlist identifiers ot the items. + /// The playlist identifiers of the items. public IReadOnlyList PlaylistItemIds { get; set; } /// diff --git a/Jellyfin.Drawing.Skia/SkiaHelper.cs b/Jellyfin.Drawing.Skia/SkiaHelper.cs index c001c32b8c..0478fc7c31 100644 --- a/Jellyfin.Drawing.Skia/SkiaHelper.cs +++ b/Jellyfin.Drawing.Skia/SkiaHelper.cs @@ -13,7 +13,7 @@ namespace Jellyfin.Drawing.Skia /// /// The current skia encoder. /// The list of image paths. - /// The current checked indes. + /// The current checked index. /// The new index. /// A valid bitmap, or null if no bitmap exists after currentIndex. public static SKBitmap? GetNextValidImage(SkiaEncoder skiaEncoder, IReadOnlyList paths, int currentIndex, out int newIndex) diff --git a/Jellyfin.Networking/Configuration/NetworkConfiguration.cs b/Jellyfin.Networking/Configuration/NetworkConfiguration.cs index 61db223d92..361dbc8142 100644 --- a/Jellyfin.Networking/Configuration/NetworkConfiguration.cs +++ b/Jellyfin.Networking/Configuration/NetworkConfiguration.cs @@ -193,7 +193,7 @@ namespace Jellyfin.Networking.Configuration public bool AutoDiscovery { get; set; } = true; /// - /// Gets or sets the filter for remote IP connectivity. Used in conjuntion with . + /// Gets or sets the filter for remote IP connectivity. Used in conjunction with . /// public string[] RemoteIPFilter { get; set; } = Array.Empty(); diff --git a/Jellyfin.Networking/Manager/NetworkManager.cs b/Jellyfin.Networking/Manager/NetworkManager.cs index 4b7b87814c..fd0665dbdd 100644 --- a/Jellyfin.Networking/Manager/NetworkManager.cs +++ b/Jellyfin.Networking/Manager/NetworkManager.cs @@ -944,7 +944,7 @@ namespace Jellyfin.Networking.Manager // Add virtual machine interface names to the list of bind exclusions, so that they are auto-excluded. if (config.IgnoreVirtualInterfaces) { - // each virtual interface name must be pre-pended with the exclusion symbol ! + // each virtual interface name must be prepended with the exclusion symbol ! var virtualInterfaceNames = config.VirtualInterfaceNames.Split(',').Select(p => "!" + p).ToArray(); if (lanAddresses.Length > 0) { diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index bd8df2facb..599d35da64 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -244,7 +244,7 @@ namespace MediaBrowser.Controller.Entities.TV /// /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// - /// true to replace metdata, false to not. + /// true to replace metadata, false to not. /// true if XXXX, false otherwise. public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index e5aae620ac..17e410fe13 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -194,7 +194,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Gets the name of the output video codec. /// - /// Encording state. + /// Encoding state. /// Encoding options. /// Encoder string. public string GetVideoEncoder(EncodingJobInfo state, EncodingOptions encodingOptions) @@ -1980,7 +1980,7 @@ namespace MediaBrowser.Controller.MediaEncoding } } - // Cap the max target bitrate to intMax/2 to satisify the bufsize=bitrate*2. + // Cap the max target bitrate to intMax/2 to satisfy the bufsize=bitrate*2. return Math.Min(bitrate ?? 0, int.MaxValue / 2); } diff --git a/MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs b/MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs index a0c38b3097..2164945560 100644 --- a/MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs +++ b/MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs @@ -549,7 +549,7 @@ namespace MediaBrowser.Controller.SyncPlay.GroupStates if (InitialState.Equals(GroupStateType.Playing)) { - // Group went from playing to waiting state and a pause request occured while waiting. + // Group went from playing to waiting state and a pause request occurred while waiting. var pauseRequest = new PauseGroupRequest(); pausedState.HandleRequest(pauseRequest, context, Type, session, cancellationToken); } diff --git a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs index 2f38d6adc3..619294e957 100644 --- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs +++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs @@ -27,9 +27,9 @@ namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests } /// - /// Gets the playlist identifiers ot the items. + /// Gets the playlist identifiers of the items. /// - /// The playlist identifiers ot the items. + /// The playlist identifiers of the items. public IReadOnlyList PlaylistItemIds { get; } /// diff --git a/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs b/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs index f49876cca4..3a7685f347 100644 --- a/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs +++ b/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs @@ -102,7 +102,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue } /// - /// Appends new items to the playlist. The specified order is mantained. + /// Appends new items to the playlist. The specified order is maintained. /// /// The items to add to the playlist. public void Queue(IReadOnlyList items) @@ -197,7 +197,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue } /// - /// Adds new items to the playlist right after the playing item. The specified order is mantained. + /// Adds new items to the playlist right after the playing item. The specified order is maintained. /// /// The items to add to the playlist. public void QueueNext(IReadOnlyList items) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 77b97c9b48..7f301a9d8b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -619,9 +619,9 @@ namespace MediaBrowser.MediaEncoding.Encoder Video3DFormat.HalfSideBySide => "crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1", // fsbs crop width in half,set the display aspect,crop out any black bars we may have made Video3DFormat.FullSideBySide => "crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1", - // htab crop heigh in half,scale to correct size, set the display aspect,crop out any black bars we may have made + // htab crop height in half,scale to correct size, set the display aspect,crop out any black bars we may have made Video3DFormat.HalfTopAndBottom => "crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1", - // ftab crop heigt in half, set the display aspect,crop out any black bars we may have made + // ftab crop height in half, set the display aspect,crop out any black bars we may have made Video3DFormat.FullTopAndBottom => "crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1", _ => "scale=trunc(iw*sar):ih" }; diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index 47c36494bd..c32c1c108c 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -157,7 +157,7 @@ namespace MediaBrowser.Model.Dlna flagValue |= DlnaFlags.ByteBasedSeek; } - // Time based seek is curently disabled when streaming. On LG CX3 adding DlnaFlags.TimeBasedSeek and orgPn causes the DLNA playback to fail (format not supported). Further investigations are needed before enabling the remaining code paths. + // Time based seek is currently disabled when streaming. On LG CX3 adding DlnaFlags.TimeBasedSeek and orgPn causes the DLNA playback to fail (format not supported). Further investigations are needed before enabling the remaining code paths. // else if (runtimeTicks.HasValue) // { // flagValue = flagValue | DlnaFlags.TimeBasedSeek; diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 094dc73b27..fdb84fa320 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -294,13 +294,13 @@ namespace MediaBrowser.Model.Dto public NameGuidPair[] GenreItems { get; set; } /// - /// Gets or sets wether the item has a logo, this will hold the Id of the Parent that has one. + /// Gets or sets whether the item has a logo, this will hold the Id of the Parent that has one. /// /// The parent logo item id. public Guid? ParentLogoItemId { get; set; } /// - /// Gets or sets wether the item has any backdrops, this will hold the Id of the Parent that has one. + /// Gets or sets whether the item has any backdrops, this will hold the Id of the Parent that has one. /// /// The parent backdrop item id. public Guid? ParentBackdropItemId { get; set; } @@ -506,7 +506,7 @@ namespace MediaBrowser.Model.Dto public string ParentLogoImageTag { get; set; } /// - /// Gets or sets wether the item has fan art, this will hold the Id of the Parent that has one. + /// Gets or sets whether the item has fan art, this will hold the Id of the Parent that has one. /// /// The parent art item id. public Guid? ParentArtItemId { get; set; } diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index ae8f3b0edf..90a60cf470 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -606,7 +606,7 @@ namespace MediaBrowser.Model.Entities <= 1024 when Height <= 576 => IsInterlaced ? "576i" : "576p", // 1280x720 <= 1280 when Height <= 962 => IsInterlaced ? "720i" : "720p", - // 2560x1080 (FHD ultra wide 21:9) using 1440px width to accomodate WQHD + // 2560x1080 (FHD ultra wide 21:9) using 1440px width to accommodate WQHD <= 2560 when Height <= 1440 => IsInterlaced ? "1080i" : "1080p", // 4K <= 4096 when Height <= 3072 => "4K", diff --git a/MediaBrowser.Model/SyncPlay/GroupStateType.cs b/MediaBrowser.Model/SyncPlay/GroupStateType.cs index 7aa454f928..96364cacc7 100644 --- a/MediaBrowser.Model/SyncPlay/GroupStateType.cs +++ b/MediaBrowser.Model/SyncPlay/GroupStateType.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Model.SyncPlay Idle = 0, /// - /// The group is in wating state. Playback is paused. Will start playing when users are ready. + /// The group is in waiting state. Playback is paused. Will start playing when users are ready. /// Waiting = 1, diff --git a/MediaBrowser.Model/Tasks/ITaskManager.cs b/MediaBrowser.Model/Tasks/ITaskManager.cs index a86bf2a1c8..13bebc479e 100644 --- a/MediaBrowser.Model/Tasks/ITaskManager.cs +++ b/MediaBrowser.Model/Tasks/ITaskManager.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Model.Tasks /// /// Cancels if running and queue. /// - /// An implementatin of . + /// An implementation of . /// Task options. void CancelIfRunningAndQueue(TaskOptions options) where T : IScheduledTask; @@ -30,21 +30,21 @@ namespace MediaBrowser.Model.Tasks /// /// Cancels if running and queue. /// - /// An implementatin of . + /// An implementation of . void CancelIfRunningAndQueue() where T : IScheduledTask; /// /// Cancels if running. /// - /// An implementatin of . + /// An implementation of . void CancelIfRunning() where T : IScheduledTask; /// /// Queues the scheduled task. /// - /// An implementatin of . + /// An implementation of . /// Task options. void QueueScheduledTask(TaskOptions options) where T : IScheduledTask; @@ -52,7 +52,7 @@ namespace MediaBrowser.Model.Tasks /// /// Queues the scheduled task. /// - /// An implementatin of . + /// An implementation of . void QueueScheduledTask() where T : IScheduledTask; diff --git a/MediaBrowser.Model/Tasks/ITaskTrigger.cs b/MediaBrowser.Model/Tasks/ITaskTrigger.cs index 8c3ec6626c..0536f4ef77 100644 --- a/MediaBrowser.Model/Tasks/ITaskTrigger.cs +++ b/MediaBrowser.Model/Tasks/ITaskTrigger.cs @@ -21,10 +21,10 @@ namespace MediaBrowser.Model.Tasks /// /// Stars waiting for the trigger action. /// - /// Result of the last run triggerd task. + /// Result of the last run triggered task. /// The . /// The name of the task. - /// Wheter or not this is is fired during startup. + /// Whether or not this is is fired during startup. void Start(TaskResult? lastResult, ILogger logger, string taskName, bool isApplicationStartup); /// diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 01ff473f0c..bbb33ddf0e 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -926,7 +926,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - _logger.LogError(ex, "Error in {0}.Suports", i.GetType().Name); + _logger.LogError(ex, "Error in {0}.Supports", i.GetType().Name); return false; } }); diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs index 4bf66c0988..915fb97fd2 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Music /// /// The Jellyfin user-agent is unrestricted but source IP must not exceed /// one request per second, therefore we rate limit to avoid throttling. - /// Be prudent, use a value slightly above the minimun required. + /// Be prudent, use a value slightly above the minimum required. /// https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting. /// private readonly long _musicBrainzQueryIntervalMs; diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index 09ff84044d..da348239a1 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -1330,7 +1330,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers }; /// - /// Used to split names of comma or pipe delimeted genres and people. + /// Used to split names of comma or pipe delimited genres and people. /// /// The value. /// IEnumerable{System.String}. diff --git a/src/Jellyfin.Extensions/SplitStringExtensions.cs b/src/Jellyfin.Extensions/SplitStringExtensions.cs index 1d1c377f56..a4dc9fc6b1 100644 --- a/src/Jellyfin.Extensions/SplitStringExtensions.cs +++ b/src/Jellyfin.Extensions/SplitStringExtensions.cs @@ -55,7 +55,7 @@ namespace Jellyfin.Extensions public static Enumerator Split(this ReadOnlySpan str, char separator) => new(str, separator); /// - /// Provides an enumerator for the substrings seperated by the separator. + /// Provides an enumerator for the substrings separated by the separator. /// [StructLayout(LayoutKind.Auto)] public ref struct Enumerator diff --git a/src/Jellyfin.Extensions/StringExtensions.cs b/src/Jellyfin.Extensions/StringExtensions.cs index dadc9f1d5c..59fb038a75 100644 --- a/src/Jellyfin.Extensions/StringExtensions.cs +++ b/src/Jellyfin.Extensions/StringExtensions.cs @@ -40,7 +40,7 @@ namespace Jellyfin.Extensions } /// - /// Checks wether or not the specified string has diacritics in it. + /// Checks whether or not the specified string has diacritics in it. /// /// The string to check. /// True if the string has diacritics, false otherwise. diff --git a/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs b/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs index 6948280a3d..162f53e567 100644 --- a/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs +++ b/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs @@ -152,9 +152,9 @@ namespace Jellyfin.Model.Tests.Cryptography [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$=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parameter + [InlineData("$PBKDF2$=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parameter + [InlineData("$PBKDF2$iterations=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parameter [InlineData("$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$")] // Ends on $ [InlineData("$PBKDF2$iterations=1000$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$")] // Extra segment [InlineData("$PBKDF2$iterations=1000$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$anotherone")] // Extra segment diff --git a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs index 6b93974373..52b0e5a955 100644 --- a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs +++ b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs @@ -393,7 +393,7 @@ namespace Jellyfin.Networking.Tests // User on external network, internal binding only - so assumption is a proxy forward, return external override. [InlineData("jellyfin.org", "192.168.1.0/24", "eth16", false, "0.0.0.0=http://helloworld.com", "http://helloworld.com")] - // User on external network, no binding - so result is the 1st external which is overriden. + // User on external network, no binding - so result is the 1st external which is overridden. [InlineData("jellyfin.org", "192.168.1.0/24", "", false, "0.0.0.0 = http://helloworld.com", "http://helloworld.com")] // User assumed to be internal, no binding - so result is the 1st internal. diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs index 3b3e38bd1f..e1d2bb2d58 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs @@ -18,7 +18,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect } /// - /// /token reponse. + /// /token response. /// [Fact] public void Deserialize_Token_Response_Live_Success() diff --git a/tests/Jellyfin.Server.Implementations.Tests/Test Data/Updates/manifest-stable.json b/tests/Jellyfin.Server.Implementations.Tests/Test Data/Updates/manifest-stable.json index b766e668e3..fa8fbd8d2c 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Test Data/Updates/manifest-stable.json +++ b/tests/Jellyfin.Server.Implementations.Tests/Test Data/Updates/manifest-stable.json @@ -253,7 +253,7 @@ "versions": [ { "version": "5.0.0.0", - "changelog": "Updated to use NextPVR API v5, no longer compatable with API v4.\n", + "changelog": "Updated to use NextPVR API v5, no longer compatible with API v4.\n", "targetAbi": "10.7.0.0", "sourceUrl": "https://repo.jellyfin.org/releases/plugin/nextpvr/nextpvr_5.0.0.0.zip", "checksum": "d70f694d14bf9462ba2b2ebe110068d3", From c3405d25fd969ddaf38958e2fe5e08a92f07c062 Mon Sep 17 00:00:00 2001 From: knackebrot Date: Mon, 13 Jun 2022 00:51:08 +0200 Subject: [PATCH 48/55] Make IgnoreDts configurable for M3U tuner --- Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs | 2 +- MediaBrowser.Model/LiveTv/TunerHostInfo.cs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 2a468e14dc..bcb42e1626 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -196,7 +196,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts IsInfiniteStream = true, IsRemote = isRemote, - IgnoreDts = true, + IgnoreDts = info.IgnoreDts, SupportsDirectPlay = supportsDirectPlay, SupportsDirectStream = supportsDirectStream, diff --git a/MediaBrowser.Model/LiveTv/TunerHostInfo.cs b/MediaBrowser.Model/LiveTv/TunerHostInfo.cs index 05576a0f8d..a832169c2a 100644 --- a/MediaBrowser.Model/LiveTv/TunerHostInfo.cs +++ b/MediaBrowser.Model/LiveTv/TunerHostInfo.cs @@ -8,6 +8,7 @@ namespace MediaBrowser.Model.LiveTv public TunerHostInfo() { AllowHWTranscoding = true; + IgnoreDts = true; } public string Id { get; set; } @@ -31,5 +32,7 @@ namespace MediaBrowser.Model.LiveTv public int TunerCount { get; set; } public string UserAgent { get; set; } + + public bool IgnoreDts { get; set; } } } From de98457332a1e25d38553dd11403704372213e15 Mon Sep 17 00:00:00 2001 From: Niels van Velzen Date: Wed, 17 Aug 2022 20:14:07 +0200 Subject: [PATCH 49/55] Fix operation name in SearchController and correct nullability for SearchHint --- Jellyfin.Api/Controllers/SearchController.cs | 8 ++- MediaBrowser.Model/Search/SearchHint.cs | 66 +++++++++++++++----- 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 07e113ad3e..138d8b8df4 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -79,7 +79,7 @@ namespace Jellyfin.Api.Controllers [HttpGet] [Description("Gets search hints based on a search term")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult Get( + public ActionResult GetSearchHints( [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] Guid? userId, @@ -140,7 +140,7 @@ namespace Jellyfin.Api.Controllers IndexNumber = item.IndexNumber, ParentIndexNumber = item.ParentIndexNumber, Id = item.Id, - Type = item.GetClientTypeName(), + Type = item.GetBaseItemKind(), MediaType = item.MediaType, MatchedTerm = hintInfo.MatchedTerm, RunTimeTicks = item.RunTimeTicks, @@ -149,8 +149,10 @@ namespace Jellyfin.Api.Controllers EndDate = item.EndDate }; - // legacy +#pragma warning disable CS0618 + // Kept for compatibility with older clients result.ItemId = result.Id; +#pragma warning restore CS0618 if (item.IsFolder) { diff --git a/MediaBrowser.Model/Search/SearchHint.cs b/MediaBrowser.Model/Search/SearchHint.cs index 983dbd2bc0..4696c3797b 100644 --- a/MediaBrowser.Model/Search/SearchHint.cs +++ b/MediaBrowser.Model/Search/SearchHint.cs @@ -1,8 +1,6 @@ -#nullable disable -#pragma warning disable CS1591 - using System; using System.Collections.Generic; +using Jellyfin.Data.Enums; namespace MediaBrowser.Model.Search { @@ -11,12 +9,28 @@ namespace MediaBrowser.Model.Search /// public class SearchHint { + /// + /// Initializes a new instance of the class. + /// + public SearchHint() + { + Name = string.Empty; + MatchedTerm = string.Empty; + MediaType = string.Empty; + Artists = Array.Empty(); + } + /// /// Gets or sets the item id. /// /// The item id. + [Obsolete("Use Id instead")] public Guid ItemId { get; set; } + /// + /// Gets or sets the item id. + /// + /// The item id. public Guid Id { get; set; } /// @@ -53,38 +67,42 @@ namespace MediaBrowser.Model.Search /// Gets or sets the image tag. /// /// The image tag. - public string PrimaryImageTag { get; set; } + public string? PrimaryImageTag { get; set; } /// /// Gets or sets the thumb image tag. /// /// The thumb image tag. - public string ThumbImageTag { get; set; } + public string? ThumbImageTag { get; set; } /// /// Gets or sets the thumb image item identifier. /// /// The thumb image item identifier. - public string ThumbImageItemId { get; set; } + public string? ThumbImageItemId { get; set; } /// /// Gets or sets the backdrop image tag. /// /// The backdrop image tag. - public string BackdropImageTag { get; set; } + public string? BackdropImageTag { get; set; } /// /// Gets or sets the backdrop image item identifier. /// /// The backdrop image item identifier. - public string BackdropImageItemId { get; set; } + public string? BackdropImageItemId { get; set; } /// /// Gets or sets the type. /// /// The type. - public string Type { get; set; } + public BaseItemKind Type { get; set; } + /// + /// Gets a value indicating whether this instance is folder. + /// + /// true if this instance is folder; otherwise, false. public bool? IsFolder { get; set; } /// @@ -99,31 +117,47 @@ namespace MediaBrowser.Model.Search /// The type of the media. public string MediaType { get; set; } + /// + /// Gets or sets the start date. + /// + /// The start date. public DateTime? StartDate { get; set; } + /// + /// Gets or sets the end date. + /// + /// The end date. public DateTime? EndDate { get; set; } /// /// Gets or sets the series. /// /// The series. - public string Series { get; set; } + public string? Series { get; set; } - public string Status { get; set; } + /// + /// Gets or sets the status. + /// + /// The status. + public string? Status { get; set; } /// /// Gets or sets the album. /// /// The album. - public string Album { get; set; } + public string? Album { get; set; } - public Guid AlbumId { get; set; } + /// + /// Gets or sets the album id. + /// + /// The album id. + public Guid? AlbumId { get; set; } /// /// Gets or sets the album artist. /// /// The album artist. - public string AlbumArtist { get; set; } + public string? AlbumArtist { get; set; } /// /// Gets or sets the artists. @@ -147,13 +181,13 @@ namespace MediaBrowser.Model.Search /// Gets or sets the channel identifier. /// /// The channel identifier. - public Guid ChannelId { get; set; } + public Guid? ChannelId { get; set; } /// /// Gets or sets the name of the channel. /// /// The name of the channel. - public string ChannelName { get; set; } + public string? ChannelName { get; set; } /// /// Gets or sets the primary image aspect ratio. From 893ac59668c3b3a117eab9a0582bd30ad82c9dd4 Mon Sep 17 00:00:00 2001 From: oncetemp Date: Fri, 19 Aug 2022 16:16:40 +0000 Subject: [PATCH 50/55] Translated using Weblate (Korean) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ko/ --- Emby.Server.Implementations/Localization/Core/ko.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/ko.json b/Emby.Server.Implementations/Localization/Core/ko.json index 50d019f906..186ec44d24 100644 --- a/Emby.Server.Implementations/Localization/Core/ko.json +++ b/Emby.Server.Implementations/Localization/Core/ko.json @@ -120,5 +120,8 @@ "Forced": "강제하기", "Default": "기본 설정", "TaskOptimizeDatabaseDescription": "데이터베이스를 압축하고 사용 가능한 공간을 늘립니다. 라이브러리를 검색한 후 이 작업을 실행하거나 데이터베이스 수정같은 비슷한 작업을 수행하면 성능이 향상될 수 있습니다.", - "TaskOptimizeDatabase": "데이터베이스 최적화" + "TaskOptimizeDatabase": "데이터베이스 최적화", + "TaskKeyframeExtractorDescription": "비디오 파일에서 키프레임을 추출하여 더 정확한 HLS 재생 목록을 만듭니다. 이 작업은 오랫동안 진행될 수 있습니다.", + "TaskKeyframeExtractor": "키프레임 추출", + "External": "외부" } From 7d48f97db9f6a5809a785417b834d47aa1cde896 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 22 Aug 2022 19:01:19 +0200 Subject: [PATCH 51/55] Fix regression in DlnaHttpClient ``` [18:53:50] [ERR] [25] Emby.Dlna.Main.DlnaEntryPoint: Error updating device info for 192.168.1.21 - Sonos Connect:Amp Berging System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.ObjectDisposedException: Cannot access a disposed object. Object name: 'System.Net.Http.StringContent'. at System.Net.Http.HttpContent.CheckDisposed() at System.Net.Http.HttpContent.CopyToAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) at System.Net.Http.HttpConnection.SendRequestContentAsync(HttpRequestMessage request, HttpContentWriteStream stream, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) --- End of inner exception stack trace --- at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.DecompressionHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.HttpClient.g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) at Emby.Dlna.PlayTo.DlnaHttpClient.SendRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /home/loma/dev/jellyfin/Emby.Dlna/PlayTo/DlnaHttpClient.cs:line 47 at Emby.Dlna.PlayTo.Device.GetTransportInfo(TransportCommands avCommands, CancellationToken cancellationToken) in /home/loma/dev/jellyfin/Emby.Dlna/PlayTo/Device.cs:line 705 at Emby.Dlna.PlayTo.Device.TimerCallback(Object sender) in /home/loma/dev/jellyfin/Emby.Dlna/PlayTo/Device.cs:line 521 ``` --- Emby.Dlna/PlayTo/DlnaHttpClient.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Emby.Dlna/PlayTo/DlnaHttpClient.cs b/Emby.Dlna/PlayTo/DlnaHttpClient.cs index 62156d1833..75ff542dd8 100644 --- a/Emby.Dlna/PlayTo/DlnaHttpClient.cs +++ b/Emby.Dlna/PlayTo/DlnaHttpClient.cs @@ -66,13 +66,15 @@ namespace Emby.Dlna.PlayTo } } - public Task GetDataAsync(string url, CancellationToken cancellationToken) + public async Task GetDataAsync(string url, CancellationToken cancellationToken) { using var request = new HttpRequestMessage(HttpMethod.Get, url); - return SendRequestAsync(request, cancellationToken); + + // Have to await here instead of returning the Task directly, otherwise request would be disposed too soon + return await SendRequestAsync(request, cancellationToken).ConfigureAwait(false); } - public Task SendCommandAsync( + public async Task SendCommandAsync( string baseUrl, DeviceService service, string command, @@ -99,7 +101,8 @@ namespace Emby.Dlna.PlayTo request.Headers.TryAddWithoutValidation("contentFeatures.dlna.org", header); } - return SendRequestAsync(request, cancellationToken); + // Have to await here instead of returning the Task directly, otherwise request would be disposed too soon + return await SendRequestAsync(request, cancellationToken).ConfigureAwait(false); } } } From d675a20540eed5d656ed40e245a2a736e421eb82 Mon Sep 17 00:00:00 2001 From: "Brian J. Murrell" Date: Wed, 24 Aug 2022 17:20:05 -0400 Subject: [PATCH 52/55] JELLYFIN_NOWEBAPP_OPT is now --nowebclient --noautorunwebapp has been renamed --nowebclient. --- fedora/jellyfin.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fedora/jellyfin.env b/fedora/jellyfin.env index 89cad1a2d3..1ccd8196fd 100644 --- a/fedora/jellyfin.env +++ b/fedora/jellyfin.env @@ -33,7 +33,7 @@ JELLYFIN_RESTART_OPT="--restartpath=/usr/libexec/jellyfin/restart.sh" #JELLYFIN_SERVICE_OPT="--service" # [OPTIONAL] run Jellyfin without the web app -#JELLYFIN_NOWEBAPP_OPT="--noautorunwebapp" +#JELLYFIN_NOWEBAPP_OPT="--nowebclient" # [OPTIONAL] run Jellyfin with ASP.NET Server Garbage Collection (uses more RAM and less CPU than Workstation GC) # 0 = Workstation From ab1913c49fcf98b8ce20ca7eff90f57142ff192a Mon Sep 17 00:00:00 2001 From: jan Date: Wed, 24 Aug 2022 14:24:54 +0000 Subject: [PATCH 53/55] Translated using Weblate (Slovenian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sl/ --- Emby.Server.Implementations/Localization/Core/sl-SI.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json index 30b24e9f0d..b2d7ce11df 100644 --- a/Emby.Server.Implementations/Localization/Core/sl-SI.json +++ b/Emby.Server.Implementations/Localization/Core/sl-SI.json @@ -122,5 +122,6 @@ "TaskOptimizeDatabaseDescription": "Stisne bazo podatkov in uredi prazen prostor. Zagon tega opravila po iskanju predstavnosti ali drugih spremembah ki vplivajo na bazo podatkov lahko izboljša hitrost delovanja.", "TaskOptimizeDatabase": "Optimiziraj bazo podatkov", "TaskKeyframeExtractor": "Ekstraktor ključnih sličic", - "External": "Zunanje" + "External": "Zunanji", + "TaskKeyframeExtractorDescription": "Iz video datoteke Izvleče ključne sličice, da ustvari bolj natančne sezname predvajanja HLS. Proces lahko traja dolgo časa." } From 2f67ee141e97df7cf621c089e1aadd2af1a76289 Mon Sep 17 00:00:00 2001 From: Alan Azar Date: Sat, 27 Aug 2022 16:20:20 +0000 Subject: [PATCH 54/55] Translated using Weblate (Burmese) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/my/ --- .../Localization/Core/my.json | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/my.json b/Emby.Server.Implementations/Localization/Core/my.json index 2642373fa9..198f7540c8 100644 --- a/Emby.Server.Implementations/Localization/Core/my.json +++ b/Emby.Server.Implementations/Localization/Core/my.json @@ -6,97 +6,97 @@ "Artists": "အနုပညာရှင်များ", "Albums": "သီချင်းအခွေများ", "TaskOptimizeDatabaseDescription": "ဒေတာဘေ့စ်ကို ကျစ်လစ်စေပြီး နေရာလွတ်များကို ဖြတ်တောက်ပေးသည်။ စာကြည့်တိုက်ကို စကင်န်ဖတ်ပြီးနောက် ဤလုပ်ငန်းကို လုပ်ဆောင်ခြင်း သို့မဟုတ် ဒေတာဘေ့စ်မွမ်းမံမှုများ စွမ်းဆောင်ရည်ကို မြှင့်တင်ပေးနိုင်သည်ဟု ရည်ညွှန်းသော အခြားပြောင်းလဲမှုများကို လုပ်ဆောင်ခြင်း။.", - "TaskOptimizeDatabase": "ဒေတာဘေ့စ်ကို အကောင်းဆုံးဖြစ်အောင်လုပ်ပါ။", + "TaskOptimizeDatabase": "ဒေတာဘေ့စ်ကို အကောင်းဆုံးဖြစ်အောင်လုပ်ပါ", "TaskDownloadMissingSubtitlesDescription": "မက်တာဒေတာ ဖွဲ့စည်းမှုပုံစံအပေါ် အခြေခံ၍ ပျောက်ဆုံးနေသော စာတန်းထိုးများအတွက် အင်တာနက်ကို ရှာဖွေသည်။", - "TaskDownloadMissingSubtitles": "ပျောက်ဆုံးနေသော စာတန်းထိုးများကို ဒေါင်းလုဒ်လုပ်ပါ။", + "TaskDownloadMissingSubtitles": "ပျောက်ဆုံးနေသော စာတန်းထိုးများကို ဒေါင်းလုဒ်လုပ်ပါ", "TaskRefreshChannelsDescription": "အင်တာနက်ချန်နယ်အချက်အလက်ကို ပြန်လည်စတင်သည်။", - "TaskRefreshChannels": "ချန်နယ်များကို ပြန်လည်စတင်ပါ။", + "TaskRefreshChannels": "ချန်နယ်များကို ပြန်လည်စတင်ပါ", "TaskCleanTranscodeDescription": "သက်တမ်း တစ်ရက်ထက်ပိုသော အသွင်ပြောင်းကုဒ်ဖိုင်များကို ဖျက်ပါ။", - "TaskCleanTranscode": "Transcode လမ်းညွှန်ကို သန့်ရှင်းပါ။", + "TaskCleanTranscode": "Transcode လမ်းညွှန်ကို သန့်ရှင်းပါ", "TaskUpdatePluginsDescription": "အလိုအလျောက် အပ်ဒိတ်လုပ်ရန် စီစဉ်ထားသော ပလပ်အင်များအတွက် အပ်ဒိတ်များကို ဒေါင်းလုဒ်လုပ်ပြီး ထည့်သွင်းပါ။", - "TaskUpdatePlugins": "ပလပ်အင်များကို အပ်ဒိတ်လုပ်ပါ။", + "TaskUpdatePlugins": "ပလပ်အင်များကို အပ်ဒိတ်လုပ်ပါ", "TaskRefreshPeopleDescription": "သင့်မီဒီယာစာကြည့်တိုက်ရှိ သရုပ်ဆောင်များနှင့် ဒါရိုက်တာများအတွက် မက်တာဒေတာကို အပ်ဒိတ်လုပ်ပါ။", - "TaskRefreshPeople": "လူများကို ပြန်လည်ဆန်းသစ်ပါ။", + "TaskRefreshPeople": "လူများကို ပြန်လည်ဆန်းသစ်ပါ", "TaskCleanLogsDescription": "{0} ရက်ထက်ပိုသော မှတ်တမ်းဖိုင်များကို ဖျက်သည်။", - "TaskCleanLogs": "မှတ်တမ်းလမ်းညွှန်ကို သန့်ရှင်းပါ။", + "TaskCleanLogs": "မှတ်တမ်းလမ်းညွှန်ကို သန့်ရှင်းပါ", "TaskRefreshLibraryDescription": "သင့်မီဒီယာဒစ်ဂျစ်တိုက်ကို ဖိုင်အသစ်များရှိမရှိ စကင်န်ဖတ်ပြီး ဖိုင်ရဲ့အကြောင်းအရာများ ကို ပြန်ပြုပြင်မွမ်းမံပါ။", - "TaskRefreshLibrary": "မီဒီယာစာကြည့်တိုက်ကို စကင်န်ဖတ်ပါ။", + "TaskRefreshLibrary": "မီဒီယာစာကြည့်တိုက်ကို စကင်န်ဖတ်ပါ", "TaskRefreshChapterImagesDescription": "အခန်းများပါရှိသော ဗီဒီယိုများအတွက် ပုံသေးများကို ဖန်တီးပါ။", - "TaskRefreshChapterImages": "အခန်းတစ်ခုစီ ပုံများကို ထုတ်ယူပါ။", + "TaskRefreshChapterImages": "အခန်းတစ်ခုစီ ပုံများကို ထုတ်ယူပါ", "TaskCleanCacheDescription": "စနစ်မှ မလိုအပ်တော့သော ကက်ရှ်ဖိုင်များကို ဖျက်ပါ။.", - "TaskCleanCache": "Cache Directory ကို ရှင်းပါ။", + "TaskCleanCache": "Cache Directory ကို ရှင်းပါ", "TaskCleanActivityLogDescription": "စီစဉ်သတ်မှတ်ထားသော အသက်ထက် ပိုကြီးသော လုပ်ဆောင်ချက်မှတ်တမ်းများကို ဖျက်ပါ။", - "TaskCleanActivityLog": "လုပ်ဆောင်ချက်မှတ်တမ်းကို ရှင်းလင်းပါ။", + "TaskCleanActivityLog": "လုပ်ဆောင်ချက်မှတ်တမ်းကို ရှင်းလင်းပါ", "TasksChannelsCategory": "အင်တာနက် ချန်နယ်လိုင်းများ", "TasksApplicationCategory": "အပလီကေးရှင်း", "TasksLibraryCategory": "မီဒီယာတိုက်", "TasksMaintenanceCategory": "ပြုပြင် ထိန်းသိမ်းခြင်း", "VersionNumber": "ဗားရှင်း {0}", "ValueSpecialEpisodeName": "အထူး- {0}", - "ValueHasBeenAddedToLibrary": "{0} ကို သင့်မီဒီယာဒစ်ဂျစ်တိုက်သို့ ပေါင်းထည့်လိုက်ပါပြီ။", + "ValueHasBeenAddedToLibrary": "{0} ကို သင့်မီဒီယာဒစ်ဂျစ်တိုက်သို့ ပေါင်းထည့်လိုက်ပါပြီ", "UserStoppedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ဖွင့်ပြီးပါပြီ", "UserStartedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ပြသနေသည်", "UserPolicyUpdatedWithName": "{0} အတွက် အသုံးပြုသူမူဝါဒကို အပ်ဒိတ်လုပ်ပြီးပါပြီ", "UserPasswordChangedWithName": "အသုံးပြုသူ {0} အတွက် စကားဝှက်ကို ပြောင်းထားသည်", "UserOnlineFromDevice": "{0} သည် {1} မှ အွန်လိုင်းဖြစ်သည်", "UserOfflineFromDevice": "{0} သည် {1} မှ ချိတ်ဆက်မှုပြတ်တောက်သွားသည်", - "UserLockedOutWithName": "အသုံးပြုသူ {0} အား လော့ခ်ချထားသည်။", + "UserLockedOutWithName": "အသုံးပြုသူ {0} အား လော့ခ်ချထားသည်", "UserDownloadingItemWithValues": "{0} သည် {1} ကို ဒေါင်းလုဒ်လုပ်နေသည်", - "UserDeletedWithName": "အသုံးပြုသူ {0} ကို ဖျက်လိုက်ပါပြီ။", - "UserCreatedWithName": "အသုံးပြုသူ {0} ကို ဖန်တီးပြီးပါပြီ။", + "UserDeletedWithName": "အသုံးပြုသူ {0} ကို ဖျက်လိုက်ပါပြီ", + "UserCreatedWithName": "အသုံးပြုသူ {0} ကို ဖန်တီးပြီးပါပြီ", "User": "အသုံးပြုသူ", "Undefined": "သတ်မှတ်မထားသော", "TvShows": "တီဗီ ဇာတ်လမ်းတွဲများ", "System": "စနစ်", "Sync": "ထပ်တူကျသည်။", - "SubtitleDownloadFailureFromForItem": "{1} အတွက် {0} မှ စာတန်းထိုးများ ဒေါင်းလုဒ်လုပ်ခြင်း မအောင်မြင်ပါ။", + "SubtitleDownloadFailureFromForItem": "{1} အတွက် {0} မှ စာတန်းထိုးများ ဒေါင်းလုဒ်လုပ်ခြင်း မအောင်မြင်ပါ", "StartupEmbyServerIsLoading": "Jellyfin ဆာဗာကို အသင့်ပြင်နေပါသည်။ ခဏနေ ထပ်စမ်းကြည့်ပါ။", "Songs": "သီချင်းများ", "Shows": "ဇာတ်လမ်းတွဲများ", - "ServerNameNeedsToBeRestarted": "{0} ကို ပြန်လည်စတင်ရန် လိုအပ်သည်။", - "ScheduledTaskStartedWithName": "{0} စတင်ခဲ့သည်။", - "ScheduledTaskFailedWithName": "{0} မအောင်မြင်ပါ။", + "ServerNameNeedsToBeRestarted": "{0} ကို ပြန်လည်စတင်ရန် လိုအပ်သည်", + "ScheduledTaskStartedWithName": "{0} စတင်ခဲ့သည်", + "ScheduledTaskFailedWithName": "{0} မအောင်မြင်ပါ", "ProviderValue": "ဝန်ဆောင်မှုပေးသူ- {0}", - "PluginUpdatedWithName": "ပလပ်ခ်အင် {0} ကို အပ်ဒိတ်လုပ်ထားသည်။", - "PluginUninstalledWithName": "ပလပ်ခ်အင် {0} ကို ဖြုတ်လိုက်ပါပြီ။", - "PluginInstalledWithName": "ပလပ်ခ်အင် {0} ကို ထည့်သွင်းခဲ့သည်။", + "PluginUpdatedWithName": "ပလပ်ခ်အင် {0} ကို အပ်ဒိတ်လုပ်ထားသည်", + "PluginUninstalledWithName": "ပလပ်ခ်အင် {0} ကို ဖြုတ်လိုက်ပါပြီ", + "PluginInstalledWithName": "ပလပ်ခ်အင် {0} ကို ထည့်သွင်းခဲ့သည်", "Plugin": "ပလပ်အင်", "Playlists": "အစီအစဉ်များ", "Photos": "ဓာတ်ပုံများ", - "NotificationOptionVideoPlaybackStopped": "ဗီဒီယိုဖွင့်ခြင်း ရပ်သွားသည်။", - "NotificationOptionVideoPlayback": "ဗီဒီယိုဖွင့်ခြင်း စတင်ပါပြီ။", - "NotificationOptionUserLockedOut": "အသုံးပြုသူ ဝင်ရန် တားမြစ်ခံရသည်။", + "NotificationOptionVideoPlaybackStopped": "ဗီဒီယိုဖွင့်ခြင်း ရပ်သွားသည်", + "NotificationOptionVideoPlayback": "ဗီဒီယိုဖွင့်ခြင်း စတင်ပါပြီ", + "NotificationOptionUserLockedOut": "အသုံးပြုသူ ဝင်ရန် တားမြစ်ခံရသည်", "NotificationOptionTaskFailed": "စီစဉ်ထားသော အလုပ်ပျက်ကွက်", - "NotificationOptionServerRestartRequired": "ဆာဗာ ပြန်လည်စတင်ရန် လိုအပ်သည်။", - "NotificationOptionPluginUpdateInstalled": "ပလပ်အင် အပ်ဒိတ် ထည့်သွင်းပြီးပါပြီ။", - "NotificationOptionPluginUninstalled": "ပလပ်အင်ကို ဖြုတ်လိုက်ပါပြီ။", - "NotificationOptionPluginInstalled": "ပလပ်အင် ထည့်သွင်းထားသည်။", - "NotificationOptionPluginError": "ပလပ်အင် ချို့ယွင်းခြင်း။", - "NotificationOptionNewLibraryContent": "အသစ်များ ထပ်ထည့်ထားပါတယ်။", - "NotificationOptionInstallationFailed": "ထည့်သွင်းမှု မအောင်မြင်ပါ။", - "NotificationOptionCameraImageUploaded": "ကင်မရာမှ ဓာတ်ပုံ အပ်လုဒ် ပြီးပါပြီ။", - "NotificationOptionAudioPlaybackStopped": "အသံဖိုင်ဖွင့်ခြင်း ရပ်သွားသည်။", - "NotificationOptionAudioPlayback": "အသံဖွင့်ခြင်း စတင်ပါပြီ။", - "NotificationOptionApplicationUpdateInstalled": "အပလီကေးရှင်း အပ်ဒိတ်ကို ထည့်သွင်းထားသည်။", - "NotificationOptionApplicationUpdateAvailable": "အပလီကေးရှင်း အပ်ဒိတ် ရနိုင်ပါပြီ။", + "NotificationOptionServerRestartRequired": "ဆာဗာ ပြန်လည်စတင်ရန် လိုအပ်သည်", + "NotificationOptionPluginUpdateInstalled": "ပလပ်အင် အပ်ဒိတ် ထည့်သွင်းပြီးပါပြီ", + "NotificationOptionPluginUninstalled": "ပလပ်အင်ကို ဖြုတ်လိုက်ပါပြီ", + "NotificationOptionPluginInstalled": "ပလပ်အင် ထည့်သွင်းထားသည်", + "NotificationOptionPluginError": "ပလပ်အင် ချို့ယွင်းခြင်း", + "NotificationOptionNewLibraryContent": "အသစ်များ ထပ်ထည့်ထားပါတယ်", + "NotificationOptionInstallationFailed": "ထည့်သွင်းမှု မအောင်မြင်ပါ", + "NotificationOptionCameraImageUploaded": "ကင်မရာမှ ဓာတ်ပုံ အပ်လုဒ် ပြီးပါပြီ", + "NotificationOptionAudioPlaybackStopped": "အသံဖိုင်ဖွင့်ခြင်း ရပ်သွားသည်", + "NotificationOptionAudioPlayback": "အသံဖွင့်ခြင်း စတင်ပါပြီ", + "NotificationOptionApplicationUpdateInstalled": "အပလီကေးရှင်း အပ်ဒိတ်ကို ထည့်သွင်းထားသည်", + "NotificationOptionApplicationUpdateAvailable": "အပလီကေးရှင်း အပ်ဒိတ် ရနိုင်ပါပြီ", "NewVersionIsAvailable": "Jellyfin Server ၏ ဗားရှင်းအသစ်ကို ဒေါင်းလုဒ်လုပ်နိုင်ပါပြီ။", "NameSeasonUnknown": "ဇာတ်လမ်းတွဲ အပိုင်းမသိ", "NameSeasonNumber": "ဇာတ်လမ်းတွဲ အပိုင်း {0}", - "NameInstallFailed": "{0} ထည့်သွင်းမှု မအောင်မြင်ပါ။", + "NameInstallFailed": "{0} ထည့်သွင်းမှု မအောင်မြင်ပါ", "MusicVideos": "ဂီတဗီဒီယိုများ", "Music": "တေးဂီတ", "Movies": "ရုပ်ရှင်များ", "MixedContent": "ရောနှောပါဝင်မှု", - "MessageServerConfigurationUpdated": "ဆာဗာဖွဲ့စည်းပုံကို အပ်ဒိတ်လုပ်ပြီးပါပြီ။", - "MessageNamedServerConfigurationUpdatedWithValue": "ဆာဗာဖွဲ့စည်းပုံကဏ္ဍ {0} ကို အပ်ဒိတ်လုပ်ပြီးပါပြီ။", + "MessageServerConfigurationUpdated": "ဆာဗာဖွဲ့စည်းပုံကို အပ်ဒိတ်လုပ်ပြီးပါပြီ", + "MessageNamedServerConfigurationUpdatedWithValue": "ဆာဗာဖွဲ့စည်းပုံကဏ္ဍ {0} ကို အပ်ဒိတ်လုပ်ပြီးပါပြီ", "MessageApplicationUpdatedTo": "Jellyfin ဆာဗာကို {0} သို့ အပ်ဒိတ်လုပ်ထားသည်", - "MessageApplicationUpdated": "Jellyfin ဆာဗာကို အပ်ဒိတ်လုပ်ပြီးပါပြီ။", + "MessageApplicationUpdated": "Jellyfin ဆာဗာကို အပ်ဒိတ်လုပ်ပြီးပါပြီ", "Latest": "နောက်ဆုံး", "LabelRunningTimeValue": "ကြာချိန် - {0}", "LabelIpAddressValue": "IP လိပ်စာ- {0}", - "ItemRemovedWithName": "{0} ကို ဒစ်ဂျစ်တိုက်မှ ဖယ်ရှားခဲ့သည်။", - "ItemAddedWithName": "{0} ကို စာကြည့်တိုက်သို့ ထည့်ထားသည်။", - "Inherit": "ဆက်ခံ၍ လုပ်ဆောင်သည်။", + "ItemRemovedWithName": "{0} ကို ဒစ်ဂျစ်တိုက်မှ ဖယ်ရှားခဲ့သည်", + "ItemAddedWithName": "{0} ကို စာကြည့်တိုက်သို့ ထည့်ထားသည်", + "Inherit": "ဆက်ခံ၍ လုပ်ဆောင်သည်", "HomeVideos": "ကိုယ်တိုင်ရိုက် ဗီဒီယိုများ", "HeaderRecordingGroups": "အသံဖမ်းအဖွဲ့များ", "HeaderNextUp": "နောက်ထပ်", @@ -106,18 +106,18 @@ "HeaderFavoriteEpisodes": "အကြိုက်ဆုံး ဇာတ်လမ်းအပိုင်းများ", "HeaderFavoriteArtists": "အကြိုက်ဆုံးအနုပညာရှင်များ", "HeaderFavoriteAlbums": "အကြိုက်ဆုံး အယ်လ်ဘမ်များ", - "HeaderContinueWatching": "ဆက်လက်ကြည့်ရှုပါ။", + "HeaderContinueWatching": "ဆက်လက်ကြည့်ရှုပါ", "HeaderAlbumArtists": "အယ်လ်ဘမ်အနုပညာရှင်များ", "Genres": "အမျိုးအစားများ", "Forced": "အတင်းအကြပ်", "Folders": "ဖိုလ်ဒါများ", "Favorites": "အကြိုက်ဆုံးများ", "FailedLoginAttemptWithUserName": "{0} မှ အကောင့်ဝင်ရန် မအောင်မြင်ပါ", - "DeviceOnlineWithName": "{0} ကို ချိတ်ဆက်ထားသည်။", - "DeviceOfflineWithName": "{0} နှင့် အဆက်ပြတ်သွားပါပြီ။", + "DeviceOnlineWithName": "{0} ကို ချိတ်ဆက်ထားသည်", + "DeviceOfflineWithName": "{0} နှင့် အဆက်ပြတ်သွားပါပြီ", "ChapterNameValue": "အခန်း {0}", - "CameraImageUploadedFrom": "ကင်မရာပုံအသစ်ကို {0} မှ ထည့်သွင်းလိုက်သည်။", - "AuthenticationSucceededWithUserName": "{0} စစ်မှန်ကြောင်း အောင်မြင်စွာ အတည်ပြုပြီးပါပြီ။", + "CameraImageUploadedFrom": "ကင်မရာပုံအသစ်ကို {0} မှ ထည့်သွင်းလိုက်သည်", + "AuthenticationSucceededWithUserName": "{0} အောင်မြင်စွာ စစ်မှန်ကြောင်း အတည်ပြုပြီးပါပြီ", "Application": "အပလီကေးရှင်း", "AppDeviceValues": "အက်ပ်- {0}၊ စက်- {1}", "External": "ပြင်ပ" From 2b285b787408417b4ae1f8e3f364b2e5e0a66207 Mon Sep 17 00:00:00 2001 From: JinYi-Tsinghua <109143373+JinYi-Tsinghua@users.noreply.github.com> Date: Mon, 29 Aug 2022 02:28:15 +0000 Subject: [PATCH 55/55] Add musl-linux-arm64 support in azure-pipelines-package.yml This is a supplement to pull request 8112 --- .ci/azure-pipelines-package.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.ci/azure-pipelines-package.yml b/.ci/azure-pipelines-package.yml index 19d65ea0c1..926d1d3224 100644 --- a/.ci/azure-pipelines-package.yml +++ b/.ci/azure-pipelines-package.yml @@ -26,6 +26,8 @@ jobs: BuildConfiguration: linux.amd64-musl Linux.arm64: BuildConfiguration: linux.arm64 + Linux.musl-linux-arm64: + BuildConfiguration: linux.musl-linux-arm64 Linux.armhf: BuildConfiguration: linux.armhf Windows.amd64: