diff options
88 files changed, 458 insertions, 425 deletions
diff --git a/.ci/azure-pipelines-package.yml b/.ci/azure-pipelines-package.yml index 19d65ea0c..926d1d322 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: diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 9c08929e7..98acd4449 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -36,6 +36,7 @@ - [dmitrylyzo](https://github.com/dmitrylyzo) - [DMouse10462](https://github.com/DMouse10462) - [DrPandemic](https://github.com/DrPandemic) + - [eglia](https://github.com/eglia) - [EraYaN](https://github.com/EraYaN) - [escabe](https://github.com/escabe) - [excelite](https://github.com/excelite) diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index df6539a5a..8e3a335c6 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -446,7 +446,7 @@ namespace Emby.Dlna.Didl /// </summary> /// <remarks> /// If context is a season, this will return a string containing just episode number and name. - /// Otherwise the result will include series nams and season number. + /// Otherwise the result will include series names and season number. /// </remarks> /// <param name="episode">The episode.</param> /// <param name="context">Current context.</param> diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index fe78d74ee..74624334b 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -123,7 +123,7 @@ namespace Emby.Dlna /// <summary> /// Attempts to match a device with a profile. /// Rules: - /// - If the profile field has no value, the field matches irregardless of its contents. + /// - If the profile field has no value, the field matches regardless of its contents. /// - the profile field can be an exact match, or a reg exp. /// </summary> /// <param name="deviceInfo">The <see cref="DeviceIdentification"/> of the device.</param> diff --git a/Emby.Dlna/IDlnaEventManager.cs b/Emby.Dlna/IDlnaEventManager.cs index 33cf0896b..eea030d6d 100644 --- a/Emby.Dlna/IDlnaEventManager.cs +++ b/Emby.Dlna/IDlnaEventManager.cs @@ -16,7 +16,7 @@ namespace Emby.Dlna /// </summary> /// <param name="subscriptionId">The subscription identifier.</param> /// <param name="notificationType">The notification type.</param> - /// <param name="requestedTimeoutString">The requested timeout as a sting.</param> + /// <param name="requestedTimeoutString">The requested timeout as a string.</param> /// <param name="callbackUrl">The callback url.</param> /// <returns>The response.</returns> EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl); @@ -25,7 +25,7 @@ namespace Emby.Dlna /// Creates the event subscription. /// </summary> /// <param name="notificationType">The notification type.</param> - /// <param name="requestedTimeoutString">The requested timeout as a sting.</param> + /// <param name="requestedTimeoutString">The requested timeout as a string.</param> /// <param name="callbackUrl">The callback url.</param> /// <returns>The response.</returns> EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl); diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 8eb90f445..0b480f5ab 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<Device> 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 000000000..75ff542dd --- /dev/null +++ b/Emby.Dlna/PlayTo/DlnaHttpClient.cs @@ -0,0 +1,108 @@ +#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<XDocument?> 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: {Content}\n", await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false)); + } + + return null; + } + } + + public async Task<XDocument?> GetDataAsync(string url, CancellationToken cancellationToken) + { + using var request = new HttpRequestMessage(HttpMethod.Get, url); + + // 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 async Task<XDocument?> 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); + } + + // Have to await here instead of returning the Task directly, otherwise request would be disposed too soon + return await SendRequestAsync(request, cancellationToken).ConfigureAwait(false); + } + } +} diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs deleted file mode 100644 index cade7b4c2..000000000 --- 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<XDocument> 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<XDocument> 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<HttpResponseMessage> 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/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs index 2a4a8fb13..c42cec593 100644 --- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs +++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs @@ -365,11 +365,7 @@ namespace Emby.Server.Implementations.AppBase validatingStore.Validate(currentConfiguration, configuration); } - NamedConfigurationUpdating?.Invoke(this, new ConfigurationUpdateEventArgs - { - Key = key, - NewConfiguration = configuration - }); + NamedConfigurationUpdating?.Invoke(this, new ConfigurationUpdateEventArgs(key, configuration)); _configurations.AddOrUpdate(key, configuration, (_, _) => configuration); @@ -391,11 +387,7 @@ namespace Emby.Server.Implementations.AppBase /// <param name="configuration">The old configuration.</param> protected virtual void OnNamedConfigurationUpdated(string key, object configuration) { - NamedConfigurationUpdated?.Invoke(this, new ConfigurationUpdateEventArgs - { - Key = key, - NewConfiguration = configuration - }); + NamedConfigurationUpdated?.Invoke(this, new ConfigurationUpdateEventArgs(key, configuration)); } /// <inheritdoc /> diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 2843fb8f8..679684552 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 a60251dac..b2f388a66 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/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 2a468e14d..bcb42e162 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/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index 708ff52d7..be06356a4 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/Localization/Core/mk.json b/Emby.Server.Implementations/Localization/Core/mk.json index 279734c5e..3483a7f0c 100644 --- a/Emby.Server.Implementations/Localization/Core/mk.json +++ b/Emby.Server.Implementations/Localization/Core/mk.json @@ -66,7 +66,7 @@ "AuthenticationSucceededWithUserName": "{0} успешно поврзан", "Artists": "Изведувач", "Application": "Апликација", - "AppDeviceValues": "Аплиакција: {0}, Уред: {1}", + "AppDeviceValues": "Апликација: {0}, Уред: {1}", "Albums": "Албуми", "VersionNumber": "Верзија {0}", "ValueSpecialEpisodeName": "Специјално - {0}", @@ -100,5 +100,27 @@ "TasksMaintenanceCategory": "Одржување", "Undefined": "Недефинирано", "Forced": "Принудно", - "Default": "Зададено" + "Default": "Зададено", + "TaskKeyframeExtractorDescription": "Извлекува клучни рамки од видео фајлови за да се направат попрецизни HLS плејлисти. Оваа задача може да работи многу долго време.", + "TaskKeyframeExtractor": "Извлекувач на клучни рамки", + "TaskOptimizeDatabaseDescription": "Компактира датабазата и смалува празното место. Извршувањето на оваа задача по скенирање на библиотеката или правење други промени што прават модификации на датабазата може да подобри перформансите.", + "TaskOptimizeDatabase": "Оптимизирај датабаза", + "TaskDownloadMissingSubtitlesDescription": "Пребарува интернет за преводи што недостиваат според метадата конфигурација.", + "TaskDownloadMissingSubtitles": "Симни преводи што недостигаат", + "TaskRefreshChannelsDescription": "Ажурирај информации за интернет канали.", + "TaskRefreshChannels": "Ажурирај Канали", + "TaskCleanTranscodeDescription": "Избриши транскодирани фајлови постари од еден ден.", + "TaskCleanTranscode": "Исчисти Директориум за Транскодирање", + "TaskUpdatePluginsDescription": "Симни и инсталирај ажурирања за плагини што се конфигурирани за автоматско ажурирање.", + "TaskUpdatePlugins": "Ажурирај Плагини", + "TaskRefreshPeopleDescription": "Ажурирај метадата за акери и директори во вашата медиска библиотека.", + "TaskRefreshPeople": "Ажурирајте ги Луѓето", + "TaskCleanLogsDescription": "Избриши лог фајлови постари од {0} денови.", + "TaskCleanLogs": "Избриши Директориум на Логови", + "TaskRefreshLibraryDescription": "Скенирајте ја вашата медиска библиотека за нови фајлови и ажурирај метадата.", + "TaskRefreshLibrary": "Скенирај Медиумска Библиотека", + "TaskRefreshChapterImagesDescription": "Создава тамбнеил за видеата шти имаат поглавја.", + "TaskCleanActivityLogDescription": "Избришува логови на активности постари од определеното време.", + "TaskCleanActivityLog": "Избриши Лог на Активности", + "External": "Надворешен" } diff --git a/Emby.Server.Implementations/Localization/Core/my.json b/Emby.Server.Implementations/Localization/Core/my.json index 2642373fa..198f7540c 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": "ပြင်ပ" diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json index 30b24e9f0..b2d7ce11d 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." } diff --git a/Emby.Server.Implementations/Localization/Core/sr.json b/Emby.Server.Implementations/Localization/Core/sr.json index 781e93926..1be8867f4 100644 --- a/Emby.Server.Implementations/Localization/Core/sr.json +++ b/Emby.Server.Implementations/Localization/Core/sr.json @@ -86,7 +86,7 @@ "Channels": "Канали", "CameraImageUploadedFrom": "Нова фотографија је учитана са {0}", "Books": "Књиге", - "AuthenticationSucceededWithUserName": "{0} Успешна аутентикација", + "AuthenticationSucceededWithUserName": "{0} Успешна аутентификација", "Artists": "Извођачи", "Application": "Апликација", "AppDeviceValues": "Апликација: {0}, Уређај: {1}", @@ -118,7 +118,7 @@ "Undefined": "Недефинисано", "Forced": "Принудно", "Default": "Подразумевано", - "TaskOptimizeDatabase": "Оптимизуј датабазу", + "TaskOptimizeDatabase": "Оптимизуј банку података", "TaskOptimizeDatabaseDescription": "Сажима базу података и скраћује слободан простор. Покретање овог задатка након скенирања библиотеке или других промена које подразумевају измене базе података које могу побољшати перформансе.", "External": "Спољно", "TaskKeyframeExtractorDescription": "Екстрактује кљулне сличице из видео датотека да би креирао више преицзну HLS плеј-листу. Овај задатак може да потраје дуже време.", diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index d25376297..7f927e270 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<BaseItem>(); } diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index a085ee546..fccf50f60 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; /// <summary> - /// Lock used for accesing the KeepAlive cancellation token. + /// Lock used for accessing the KeepAlive cancellation token. /// </summary> private readonly object _keepAliveLock = new object(); diff --git a/Jellyfin.Api/Attributes/HttpSubscribeAttribute.cs b/Jellyfin.Api/Attributes/HttpSubscribeAttribute.cs index af8727552..7ac089a34 100644 --- a/Jellyfin.Api/Attributes/HttpSubscribeAttribute.cs +++ b/Jellyfin.Api/Attributes/HttpSubscribeAttribute.cs @@ -25,11 +25,6 @@ namespace Jellyfin.Api.Attributes /// <param name="template">The route template. May not be null.</param> public HttpSubscribeAttribute(string template) : base(_supportedMethods, template) - { - if (template == null) - { - throw new ArgumentNullException(nameof(template)); - } - } + => ArgumentNullException.ThrowIfNull(template, nameof(template)); } } diff --git a/Jellyfin.Api/Attributes/HttpUnsubscribeAttribute.cs b/Jellyfin.Api/Attributes/HttpUnsubscribeAttribute.cs index 1c0b70e71..16b3d0816 100644 --- a/Jellyfin.Api/Attributes/HttpUnsubscribeAttribute.cs +++ b/Jellyfin.Api/Attributes/HttpUnsubscribeAttribute.cs @@ -25,11 +25,6 @@ namespace Jellyfin.Api.Attributes /// <param name="template">The route template. May not be null.</param> public HttpUnsubscribeAttribute(string template) : base(_supportedMethods, template) - { - if (template == null) - { - throw new ArgumentNullException(nameof(template)); - } - } + => ArgumentNullException.ThrowIfNull(template, nameof(template)); } } diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index 54ac06276..94f7a7b82 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -207,7 +207,7 @@ namespace Jellyfin.Api.Controllers /// <param name="deviceProfileId">Optional. The dlna device profile id to utilize.</param> /// <param name="playSessionId">The play session id.</param> /// <param name="segmentContainer">The segment container.</param> - /// <param name="segmentLength">The segment lenght.</param> + /// <param name="segmentLength">The segment length.</param> /// <param name="minSegments">The minimum number of segments.</param> /// <param name="mediaSourceId">The media version id, if playing an alternate version.</param> /// <param name="deviceId">The device id of the client requesting. Used to stop encoding processes when needed.</param> diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index 27eb22339..64ee5680c 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -89,12 +89,9 @@ namespace Jellyfin.Api.Controllers // Load all custom display preferences var customDisplayPreferences = _displayPreferencesManager.ListCustomItemDisplayPreferences(displayPreferences.UserId, itemId, displayPreferences.Client); - if (customDisplayPreferences != null) + foreach (var (key, value) in customDisplayPreferences) { - foreach (var (key, value) in customDisplayPreferences) - { - dto.CustomPrefs.TryAdd(key, value); - } + dto.CustomPrefs.TryAdd(key, value); } // This will essentially be a noop if no changes have been made, but new prefs must be saved at least. diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 1e8d03875..3ed80f662 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -121,7 +121,7 @@ namespace Jellyfin.Api.Controllers /// <param name="deviceProfileId">Optional. The dlna device profile id to utilize.</param> /// <param name="playSessionId">The play session id.</param> /// <param name="segmentContainer">The segment container.</param> - /// <param name="segmentLength">The segment lenght.</param> + /// <param name="segmentLength">The segment length.</param> /// <param name="minSegments">The minimum number of segments.</param> /// <param name="mediaSourceId">The media version id, if playing an alternate version.</param> /// <param name="deviceId">The device id of the client requesting. Used to stop encoding processes when needed.</param> @@ -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/QuickConnectController.cs b/Jellyfin.Api/Controllers/QuickConnectController.cs index 87b78fe93..1df26355f 100644 --- a/Jellyfin.Api/Controllers/QuickConnectController.cs +++ b/Jellyfin.Api/Controllers/QuickConnectController.cs @@ -39,7 +39,7 @@ namespace Jellyfin.Api.Controllers /// <returns>Whether Quick Connect is enabled on the server or not.</returns> [HttpGet("Enabled")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult<bool> GetEnabled() + public ActionResult<bool> GetQuickConnectEnabled() { return _quickConnect.IsEnabled; } @@ -52,7 +52,7 @@ namespace Jellyfin.Api.Controllers /// <returns>A <see cref="QuickConnectResult"/> with a secret and code for future use or an error message.</returns> [HttpGet("Initiate")] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task<ActionResult<QuickConnectResult>> Initiate() + public async Task<ActionResult<QuickConnectResult>> InitiateQuickConnect() { try { @@ -75,7 +75,7 @@ namespace Jellyfin.Api.Controllers [HttpGet("Connect")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult<QuickConnectResult> Connect([FromQuery, Required] string secret) + public ActionResult<QuickConnectResult> GetQuickConnectState([FromQuery, Required] string secret) { try { @@ -102,7 +102,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] - public async Task<ActionResult<bool>> Authorize([FromQuery, Required] string code) + public async Task<ActionResult<bool>> AuthorizeQuickConnect([FromQuery, Required] string code) { var userId = ClaimHelpers.GetUserId(Request.HttpContext.User); if (!userId.HasValue) diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 138d8b8df..aeed0c0d6 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -60,9 +60,9 @@ namespace Jellyfin.Api.Controllers /// <param name="limit">Optional. The maximum number of records to return.</param> /// <param name="userId">Optional. Supply a user id to search within a user's library or omit to search all.</param> /// <param name="searchTerm">The search term to filter on.</param> - /// <param name="includeItemTypes">If specified, only results with the specified item types are returned. This allows multiple, comma delimeted.</param> - /// <param name="excludeItemTypes">If specified, results with these item types are filtered out. This allows multiple, comma delimeted.</param> - /// <param name="mediaTypes">If specified, only results with the specified media types are returned. This allows multiple, comma delimeted.</param> + /// <param name="includeItemTypes">If specified, only results with the specified item types are returned. This allows multiple, comma delimited.</param> + /// <param name="excludeItemTypes">If specified, results with these item types are filtered out. This allows multiple, comma delimited.</param> + /// <param name="mediaTypes">If specified, only results with the specified media types are returned. This allows multiple, comma delimited.</param> /// <param name="parentId">If specified, only children of the parent are returned.</param> /// <param name="isMovie">Optional filter for movies.</param> /// <param name="isSeries">Optional filter for series.</param> diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 6fcafd426..43b8e2414 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -10,13 +10,11 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.StreamingDtos; using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Session; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -31,7 +29,6 @@ namespace Jellyfin.Api.Controllers public class UniversalAudioController : BaseJellyfinApiController { private readonly IAuthorizationContext _authorizationContext; - private readonly IDeviceManager _deviceManager; private readonly ILibraryManager _libraryManager; private readonly ILogger<UniversalAudioController> _logger; private readonly MediaInfoHelper _mediaInfoHelper; @@ -42,7 +39,6 @@ namespace Jellyfin.Api.Controllers /// Initializes a new instance of the <see cref="UniversalAudioController"/> class. /// </summary> /// <param name="authorizationContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param> - /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> /// <param name="logger">Instance of the <see cref="ILogger{UniversalAudioController}"/> interface.</param> /// <param name="mediaInfoHelper">Instance of <see cref="MediaInfoHelper"/>.</param> @@ -50,7 +46,6 @@ namespace Jellyfin.Api.Controllers /// <param name="dynamicHlsHelper">Instance of <see cref="DynamicHlsHelper"/>.</param> public UniversalAudioController( IAuthorizationContext authorizationContext, - IDeviceManager deviceManager, ILibraryManager libraryManager, ILogger<UniversalAudioController> logger, MediaInfoHelper mediaInfoHelper, @@ -58,7 +53,6 @@ namespace Jellyfin.Api.Controllers DynamicHlsHelper dynamicHlsHelper) { _authorizationContext = authorizationContext; - _deviceManager = deviceManager; _libraryManager = libraryManager; _logger = logger; _mediaInfoHelper = mediaInfoHelper; @@ -123,70 +117,49 @@ namespace Jellyfin.Api.Controllers _logger.LogInformation("GetPostedPlaybackInfo profile: {@Profile}", deviceProfile); - if (deviceProfile == null) - { - var clientCapabilities = _deviceManager.GetCapabilities(authInfo.DeviceId); - if (clientCapabilities != null) - { - deviceProfile = clientCapabilities.DeviceProfile; - } - } - var info = await _mediaInfoHelper.GetPlaybackInfo( itemId, userId, mediaSourceId) .ConfigureAwait(false); - if (deviceProfile != null) - { - // set device specific data - var item = _libraryManager.GetItemById(itemId); - - foreach (var sourceInfo in info.MediaSources) - { - _mediaInfoHelper.SetDeviceSpecificData( - item, - sourceInfo, - deviceProfile, - authInfo, - maxStreamingBitrate ?? deviceProfile.MaxStreamingBitrate, - startTimeTicks ?? 0, - mediaSourceId ?? string.Empty, - null, - null, - maxAudioChannels, - info.PlaySessionId!, - userId ?? Guid.Empty, - true, - true, - true, - true, - true, - Request.HttpContext.GetNormalizedRemoteIp()); - } + // set device specific data + var item = _libraryManager.GetItemById(itemId); - _mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate); + foreach (var sourceInfo in info.MediaSources) + { + _mediaInfoHelper.SetDeviceSpecificData( + item, + sourceInfo, + deviceProfile, + authInfo, + maxStreamingBitrate ?? deviceProfile.MaxStreamingBitrate, + startTimeTicks ?? 0, + mediaSourceId ?? string.Empty, + null, + null, + maxAudioChannels, + info.PlaySessionId!, + userId ?? Guid.Empty, + true, + true, + true, + true, + true, + Request.HttpContext.GetNormalizedRemoteIp()); } - if (info.MediaSources != null) + _mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate); + + foreach (var source in info.MediaSources) { - foreach (var source in info.MediaSources) - { - _mediaInfoHelper.NormalizeMediaSourceContainer(source, deviceProfile!, DlnaProfileType.Video); - } + _mediaInfoHelper.NormalizeMediaSourceContainer(source, deviceProfile, DlnaProfileType.Video); } - var mediaSource = info.MediaSources![0]; - if (mediaSource.SupportsDirectPlay && mediaSource.Protocol == MediaProtocol.Http) + var mediaSource = info.MediaSources[0]; + if (mediaSource.SupportsDirectPlay && mediaSource.Protocol == MediaProtocol.Http && enableRedirection && mediaSource.IsRemote && enableRemoteMedia.HasValue && enableRemoteMedia.Value) { - if (enableRedirection) - { - if (mediaSource.IsRemote && enableRemoteMedia.HasValue && enableRemoteMedia.Value) - { - return Redirect(mediaSource.Path); - } - } + return Redirect(mediaSource.Path); } var isStatic = mediaSource.SupportsDirectStream; @@ -249,7 +222,7 @@ namespace Jellyfin.Api.Controllers BreakOnNonKeyFrames = breakOnNonKeyFrames, AudioSampleRate = maxAudioSampleRate, MaxAudioChannels = maxAudioChannels, - AudioBitRate = isStatic ? (int?)null : (audioBitRate ?? maxStreamingBitrate), + AudioBitRate = isStatic ? null : (audioBitRate ?? maxStreamingBitrate), MaxAudioBitDepth = maxAudioBitDepth, AudioChannels = maxAudioChannels, CopyTimestamps = true, diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 82c8563a8..d1109bebc 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 192f33ebd..8182e3c9e 100644 --- a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs +++ b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs @@ -169,7 +169,7 @@ namespace Jellyfin.Api.Models.StreamingDtos /// <summary> /// Disposes the stream state. /// </summary> - /// <param name="disposing">Whether the object is currently beeing disposed.</param> + /// <param name="disposing">Whether the object is currently being disposed.</param> 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 02ce5a048..226a584e1 100644 --- a/Jellyfin.Api/Models/SyncPlayDtos/RemoveFromPlaylistRequestDto.cs +++ b/Jellyfin.Api/Models/SyncPlayDtos/RemoveFromPlaylistRequestDto.cs @@ -17,9 +17,9 @@ namespace Jellyfin.Api.Models.SyncPlayDtos } /// <summary> - /// 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. /// </summary> - /// <value>The playlist identifiers ot the items.</value> + /// <value>The playlist identifiers of the items.</value> public IReadOnlyList<Guid> PlaylistItemIds { get; set; } /// <summary> diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index 687528231..13f155f35 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -145,9 +145,11 @@ namespace Jellyfin.Drawing.Skia /// <exception cref="SkiaCodecException">The file at the specified path could not be used to generate a codec.</exception> public string GetImageBlurHash(int xComp, int yComp, string path) { - if (path == null) + ArgumentNullException.ThrowIfNull(path, nameof(path)); + + if (path.Length == 0) { - throw new ArgumentNullException(nameof(path)); + throw new ArgumentException("String can't be empty", nameof(path)); } var extension = Path.GetExtension(path.AsSpan()).TrimStart('.'); diff --git a/Jellyfin.Drawing.Skia/SkiaHelper.cs b/Jellyfin.Drawing.Skia/SkiaHelper.cs index c001c32b8..0478fc7c3 100644 --- a/Jellyfin.Drawing.Skia/SkiaHelper.cs +++ b/Jellyfin.Drawing.Skia/SkiaHelper.cs @@ -13,7 +13,7 @@ namespace Jellyfin.Drawing.Skia /// </summary> /// <param name="skiaEncoder">The current skia encoder.</param> /// <param name="paths">The list of image paths.</param> - /// <param name="currentIndex">The current checked indes.</param> + /// <param name="currentIndex">The current checked index.</param> /// <param name="newIndex">The new index.</param> /// <returns>A valid bitmap, or null if no bitmap exists after <c>currentIndex</c>.</returns> public static SKBitmap? GetNextValidImage(SkiaEncoder skiaEncoder, IReadOnlyList<string> paths, int currentIndex, out int newIndex) diff --git a/Jellyfin.Networking/Configuration/NetworkConfiguration.cs b/Jellyfin.Networking/Configuration/NetworkConfiguration.cs index 61db223d9..361dbc814 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; /// <summary> - /// Gets or sets the filter for remote IP connectivity. Used in conjuntion with <seealso cref="IsRemoteIPFilterBlacklist"/>. + /// Gets or sets the filter for remote IP connectivity. Used in conjunction with <seealso cref="IsRemoteIPFilterBlacklist"/>. /// </summary> public string[] RemoteIPFilter { get; set; } = Array.Empty<string>(); diff --git a/Jellyfin.Networking/Manager/NetworkManager.cs b/Jellyfin.Networking/Manager/NetworkManager.cs index 4b7b87814..fd0665dbd 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/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs index 5e84255f9..4fda8f5a4 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs @@ -67,7 +67,7 @@ namespace Jellyfin.Server.Implementations.Users else if (string.Equals( spr.Pin.Replace("-", string.Empty, StringComparison.Ordinal), pin.Replace("-", string.Empty, StringComparison.Ordinal), - StringComparison.OrdinalIgnoreCase)) + StringComparison.Ordinal)) { var resetUser = userManager.GetUserByName(spr.UserName) ?? throw new ResourceNotFoundException($"User with a username of {spr.UserName} not found"); diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs index f5d38db20..65edb30ad 100644 --- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs +++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs @@ -79,7 +79,7 @@ namespace Jellyfin.Server.Implementations.Users } /// <inheritdoc /> - public void SetCustomItemDisplayPreferences(Guid userId, Guid itemId, string client, Dictionary<string, string> customPreferences) + public void SetCustomItemDisplayPreferences(Guid userId, Guid itemId, string client, Dictionary<string, string?> customPreferences) { var existingPrefs = _dbContext.CustomItemDisplayPreferences .AsQueryable() diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 2100fa6d5..6a2ef74dd 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -326,10 +326,10 @@ namespace Jellyfin.Server.Implementations.Users EnableNextEpisodeAutoPlay = user.EnableNextEpisodeAutoPlay, RememberSubtitleSelections = user.RememberSubtitleSelections, SubtitleLanguagePreference = user.SubtitleLanguagePreference ?? string.Empty, - OrderedViews = user.GetPreference(PreferenceKind.OrderedViews), - GroupedFolders = user.GetPreference(PreferenceKind.GroupedFolders), - MyMediaExcludes = user.GetPreference(PreferenceKind.MyMediaExcludes), - LatestItemsExcludes = user.GetPreference(PreferenceKind.LatestItemExcludes) + OrderedViews = user.GetPreferenceValues<Guid>(PreferenceKind.OrderedViews), + GroupedFolders = user.GetPreferenceValues<Guid>(PreferenceKind.GroupedFolders), + MyMediaExcludes = user.GetPreferenceValues<Guid>(PreferenceKind.MyMediaExcludes), + LatestItemsExcludes = user.GetPreferenceValues<Guid>(PreferenceKind.LatestItemExcludes) }, Policy = new UserPolicy { diff --git a/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs b/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs index 7e7e4ca95..28ed3894f 100644 --- a/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs +++ b/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs @@ -69,15 +69,8 @@ namespace Jellyfin.Server.Infrastructure /// <inheritdoc /> protected override Task WriteFileAsync(ActionContext context, PhysicalFileResult result, RangeItemHeaderValue? range, long rangeLength) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (result == null) - { - throw new ArgumentNullException(nameof(result)); - } + ArgumentNullException.ThrowIfNull(context, nameof(context)); + ArgumentNullException.ThrowIfNull(result, nameof(result)); if (range != null && rangeLength == 0) { diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index 8eb5f2196..1954a5c55 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.0 {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<JellyfinDb>(); diff --git a/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs b/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs index 2df87d879..90b1ff70c 100644 --- a/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs +++ b/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs @@ -1,22 +1,33 @@ -#nullable disable -#pragma warning disable CS1591 - using System; namespace MediaBrowser.Common.Configuration { + /// <summary> + /// <see cref="EventArgs" /> for the ConfigurationUpdated event. + /// </summary> public class ConfigurationUpdateEventArgs : EventArgs { /// <summary> - /// Gets or sets the key. + /// Initializes a new instance of the <see cref="ConfigurationUpdateEventArgs"/> class. + /// </summary> + /// <param name="key">The configuration key.</param> + /// <param name="newConfiguration">The new configuration.</param> + public ConfigurationUpdateEventArgs(string key, object newConfiguration) + { + Key = key; + NewConfiguration = newConfiguration; + } + + /// <summary> + /// Gets the key. /// </summary> /// <value>The key.</value> - public string Key { get; set; } + public string Key { get; } /// <summary> - /// Gets or sets the new configuration. + /// Gets the new configuration. /// </summary> /// <value>The new configuration.</value> - public object NewConfiguration { get; set; } + public object NewConfiguration { get; } } } diff --git a/MediaBrowser.Common/Configuration/IApplicationPaths.cs b/MediaBrowser.Common/Configuration/IApplicationPaths.cs index 1370e6d79..57c654667 100644 --- a/MediaBrowser.Common/Configuration/IApplicationPaths.cs +++ b/MediaBrowser.Common/Configuration/IApplicationPaths.cs @@ -1,5 +1,3 @@ -#nullable disable - namespace MediaBrowser.Common.Configuration { /// <summary> diff --git a/MediaBrowser.Common/Net/NamedClient.cs b/MediaBrowser.Common/Net/NamedClient.cs index 0f6161c32..a6cacd4f1 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. /// </summary> public const string MusicBrainz = nameof(MusicBrainz); + + /// <summary> + /// Gets the value for the DLNA named http client. + /// </summary> + public const string Dlna = nameof(Dlna); } } diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs index 272a37df1..afafaf1c2 100644 --- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs +++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System.Text.Json.Serialization; @@ -13,7 +11,7 @@ namespace MediaBrowser.Controller.Entities public abstract class BasePluginFolder : Folder, ICollectionFolder { [JsonIgnore] - public virtual string CollectionType => null; + public virtual string? CollectionType => null; [JsonIgnore] public override bool SupportsInheritedParentImages => false; diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs index 9ce8eebe3..14534aa50 100644 --- a/MediaBrowser.Controller/Entities/Extensions.cs +++ b/MediaBrowser.Controller/Entities/Extensions.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Linq; using Jellyfin.Extensions; @@ -19,9 +17,11 @@ namespace MediaBrowser.Controller.Entities /// <param name="url">Trailer URL.</param> public static void AddTrailerUrl(this BaseItem item, string url) { - if (string.IsNullOrEmpty(url)) + ArgumentNullException.ThrowIfNull(url, nameof(url)); + + if (url.Length == 0) { - throw new ArgumentNullException(nameof(url)); + throw new ArgumentException("String can't be empty", nameof(url)); } var current = item.RemoteTrailers.FirstOrDefault(i => string.Equals(i.Url, url, StringComparison.OrdinalIgnoreCase)); diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index bd8df2fac..599d35da6 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -244,7 +244,7 @@ namespace MediaBrowser.Controller.Entities.TV /// <summary> /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// </summary> - /// <param name="replaceAllMetadata"><c>true</c> to replace metdata, <c>false</c> to not.</param> + /// <param name="replaceAllMetadata"><c>true</c> to replace metadata, <c>false</c> to not.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> public override bool BeforeMetadataRefresh(bool replaceAllMetadata) { diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs index 1678d5067..10c0f56e0 100644 --- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs +++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Generic; using Jellyfin.Data.Entities; @@ -50,7 +48,7 @@ namespace MediaBrowser.Controller /// <param name="itemId">The item id.</param> /// <param name="client">The client string.</param> /// <returns>The dictionary of custom item display preferences.</returns> - Dictionary<string, string> ListCustomItemDisplayPreferences(Guid userId, Guid itemId, string client); + Dictionary<string, string?> ListCustomItemDisplayPreferences(Guid userId, Guid itemId, string client); /// <summary> /// Sets the custom item display preference for the user and client. @@ -59,7 +57,7 @@ namespace MediaBrowser.Controller /// <param name="itemId">The item id.</param> /// <param name="client">The client id.</param> /// <param name="customPreferences">A dictionary of custom item display preferences.</param> - void SetCustomItemDisplayPreferences(Guid userId, Guid itemId, string client, Dictionary<string, string> customPreferences); + void SetCustomItemDisplayPreferences(Guid userId, Guid itemId, string client, Dictionary<string, string?> customPreferences); /// <summary> /// Saves changes made to the database. diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index e5aae620a..17e410fe1 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -194,7 +194,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Gets the name of the output video codec. /// </summary> - /// <param name="state">Encording state.</param> + /// <param name="state">Encoding state.</param> /// <param name="encodingOptions">Encoding options.</param> /// <returns>Encoder string.</returns> 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 a0c38b309..216494556 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 2f38d6adc..619294e95 100644 --- a/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs +++ b/MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs @@ -27,9 +27,9 @@ namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests } /// <summary> - /// Gets the playlist identifiers ot the items. + /// Gets the playlist identifiers of the items. /// </summary> - /// <value>The playlist identifiers ot the items.</value> + /// <value>The playlist identifiers of the items.</value> public IReadOnlyList<Guid> PlaylistItemIds { get; } /// <summary> diff --git a/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs b/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs index f49876cca..3a7685f34 100644 --- a/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs +++ b/MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs @@ -102,7 +102,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue } /// <summary> - /// Appends new items to the playlist. The specified order is mantained. + /// Appends new items to the playlist. The specified order is maintained. /// </summary> /// <param name="items">The items to add to the playlist.</param> public void Queue(IReadOnlyList<Guid> items) @@ -197,7 +197,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue } /// <summary> - /// 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. /// </summary> /// <param name="items">The items to add to the playlist.</param> public void QueueNext(IReadOnlyList<Guid> items) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 77b97c9b4..7f301a9d8 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/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 81359462c..94f354660 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -22,10 +22,10 @@ namespace MediaBrowser.Model.Configuration HidePlayedInLatest = true; PlayDefaultAudioTrack = true; - LatestItemsExcludes = Array.Empty<string>(); - OrderedViews = Array.Empty<string>(); - MyMediaExcludes = Array.Empty<string>(); - GroupedFolders = Array.Empty<string>(); + LatestItemsExcludes = Array.Empty<Guid>(); + OrderedViews = Array.Empty<Guid>(); + MyMediaExcludes = Array.Empty<Guid>(); + GroupedFolders = Array.Empty<Guid>(); } /// <summary> @@ -48,7 +48,7 @@ namespace MediaBrowser.Model.Configuration public bool DisplayMissingEpisodes { get; set; } - public string[] GroupedFolders { get; set; } + public Guid[] GroupedFolders { get; set; } public SubtitlePlaybackMode SubtitleMode { get; set; } @@ -56,11 +56,11 @@ namespace MediaBrowser.Model.Configuration public bool EnableLocalPassword { get; set; } - public string[] OrderedViews { get; set; } + public Guid[] OrderedViews { get; set; } - public string[] LatestItemsExcludes { get; set; } + public Guid[] LatestItemsExcludes { get; set; } - public string[] MyMediaExcludes { get; set; } + public Guid[] MyMediaExcludes { get; set; } public bool HidePlayedInLatest { get; set; } diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index 47c36494b..c32c1c108 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 094dc73b2..fdb84fa32 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; } /// <summary> - /// 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. /// </summary> /// <value>The parent logo item id.</value> public Guid? ParentLogoItemId { get; set; } /// <summary> - /// 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. /// </summary> /// <value>The parent backdrop item id.</value> public Guid? ParentBackdropItemId { get; set; } @@ -506,7 +506,7 @@ namespace MediaBrowser.Model.Dto public string ParentLogoImageTag { get; set; } /// <summary> - /// 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. /// </summary> /// <value>The parent art item id.</value> public Guid? ParentArtItemId { get; set; } diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index ae8f3b0ed..90a60cf47 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/LiveTv/TunerHostInfo.cs b/MediaBrowser.Model/LiveTv/TunerHostInfo.cs index 05576a0f8..a832169c2 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; } } } diff --git a/MediaBrowser.Model/SyncPlay/GroupStateType.cs b/MediaBrowser.Model/SyncPlay/GroupStateType.cs index 7aa454f92..96364cacc 100644 --- a/MediaBrowser.Model/SyncPlay/GroupStateType.cs +++ b/MediaBrowser.Model/SyncPlay/GroupStateType.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Model.SyncPlay Idle = 0, /// <summary> - /// 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. /// </summary> Waiting = 1, diff --git a/MediaBrowser.Model/Tasks/ITaskManager.cs b/MediaBrowser.Model/Tasks/ITaskManager.cs index a86bf2a1c..13bebc479 100644 --- a/MediaBrowser.Model/Tasks/ITaskManager.cs +++ b/MediaBrowser.Model/Tasks/ITaskManager.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Model.Tasks /// <summary> /// Cancels if running and queue. /// </summary> - /// <typeparam name="T">An implementatin of <see cref="IScheduledTask" />.</typeparam> + /// <typeparam name="T">An implementation of <see cref="IScheduledTask" />.</typeparam> /// <param name="options">Task options.</param> void CancelIfRunningAndQueue<T>(TaskOptions options) where T : IScheduledTask; @@ -30,21 +30,21 @@ namespace MediaBrowser.Model.Tasks /// <summary> /// Cancels if running and queue. /// </summary> - /// <typeparam name="T">An implementatin of <see cref="IScheduledTask" />.</typeparam> + /// <typeparam name="T">An implementation of <see cref="IScheduledTask" />.</typeparam> void CancelIfRunningAndQueue<T>() where T : IScheduledTask; /// <summary> /// Cancels if running. /// </summary> - /// <typeparam name="T">An implementatin of <see cref="IScheduledTask" />.</typeparam> + /// <typeparam name="T">An implementation of <see cref="IScheduledTask" />.</typeparam> void CancelIfRunning<T>() where T : IScheduledTask; /// <summary> /// Queues the scheduled task. /// </summary> - /// <typeparam name="T">An implementatin of <see cref="IScheduledTask" />.</typeparam> + /// <typeparam name="T">An implementation of <see cref="IScheduledTask" />.</typeparam> /// <param name="options">Task options.</param> void QueueScheduledTask<T>(TaskOptions options) where T : IScheduledTask; @@ -52,7 +52,7 @@ namespace MediaBrowser.Model.Tasks /// <summary> /// Queues the scheduled task. /// </summary> - /// <typeparam name="T">An implementatin of <see cref="IScheduledTask" />.</typeparam> + /// <typeparam name="T">An implementation of <see cref="IScheduledTask" />.</typeparam> void QueueScheduledTask<T>() where T : IScheduledTask; diff --git a/MediaBrowser.Model/Tasks/ITaskTrigger.cs b/MediaBrowser.Model/Tasks/ITaskTrigger.cs index 8c3ec6626..0536f4ef7 100644 --- a/MediaBrowser.Model/Tasks/ITaskTrigger.cs +++ b/MediaBrowser.Model/Tasks/ITaskTrigger.cs @@ -21,10 +21,10 @@ namespace MediaBrowser.Model.Tasks /// <summary> /// Stars waiting for the trigger action. /// </summary> - /// <param name="lastResult">Result of the last run triggerd task.</param> + /// <param name="lastResult">Result of the last run triggered task.</param> /// <param name="logger">The <see cref="ILogger"/>.</param> /// <param name="taskName">The name of the task.</param> - /// <param name="isApplicationStartup">Wheter or not this is is fired during startup.</param> + /// <param name="isApplicationStartup">Whether or not this is is fired during startup.</param> void Start(TaskResult? lastResult, ILogger logger, string taskName, bool isApplicationStartup); /// <summary> diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 01ff473f0..bbb33ddf0 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 4bf66c098..915fb97fd 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Music /// <summary> /// 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. /// </summary> private readonly long _musicBrainzQueryIntervalMs; diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index 09ff84044..da348239a 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -1330,7 +1330,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers }; /// <summary> - /// Used to split names of comma or pipe delimeted genres and people. + /// Used to split names of comma or pipe delimited genres and people. /// </summary> /// <param name="value">The value.</param> /// <returns>IEnumerable{System.String}.</returns> diff --git a/deployment/Dockerfile.linux.musl-linux-arm64 b/deployment/Dockerfile.linux.musl-linux-arm64 new file mode 100644 index 000000000..2da72e4ae --- /dev/null +++ b/deployment/Dockerfile.linux.musl-linux-arm64 @@ -0,0 +1,26 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim +# Docker build arguments +ARG SOURCE_DIR=/jellyfin +ARG ARTIFACT_DIR=/dist +# Docker run environment +ENV SOURCE_DIR=/jellyfin +ENV ARTIFACT_DIR=/dist +ENV DEB_BUILD_OPTIONS=noddebs +ENV ARCH=arm64 +ENV IS_DOCKER=YES + +# Prepare Debian build environment +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts unzip \ + mmv libcurl4-openssl-dev libfontconfig1-dev \ + libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 + +# Link to docker-build script +RUN ln -sf ${SOURCE_DIR}/deployment/build.linux.musl-linux-arm64 /build.sh + +VOLUME ${SOURCE_DIR}/ + +VOLUME ${ARTIFACT_DIR}/ + +ENTRYPOINT ["/build.sh"] diff --git a/deployment/build.linux.musl-linux-arm64 b/deployment/build.linux.musl-linux-arm64 new file mode 100755 index 000000000..38826ae7f --- /dev/null +++ b/deployment/build.linux.musl-linux-arm64 @@ -0,0 +1,31 @@ +#!/bin/bash + +#= Generic Linux musl-linux-arm64 .tar.gz + +set -o errexit +set -o xtrace + +# Move to source directory +pushd ${SOURCE_DIR} + +# Get version +if [[ ${IS_UNSTABLE} == 'yes' ]]; then + version="${BUILD_ID}" +else + version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )" +fi + +# Build archives +dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-musl-arm64 --output dist/jellyfin-server_${version}/ -p:DebugSymbols=false -p:DebugType=none -p:UseAppHost=true +tar -czf jellyfin-server_${version}_linux-arm64-musl.tar.gz -C dist jellyfin-server_${version} +rm -rf dist/jellyfin-server_${version} + +# Move the artifacts out +mkdir -p ${ARTIFACT_DIR}/ +mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ + +if [[ ${IS_DOCKER} == YES ]]; then + chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} +fi + +popd diff --git a/fedora/jellyfin.env b/fedora/jellyfin.env index 89cad1a2d..1ccd8196f 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 diff --git a/src/Jellyfin.Extensions/SplitStringExtensions.cs b/src/Jellyfin.Extensions/SplitStringExtensions.cs index 1d1c377f5..a4dc9fc6b 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<char> str, char separator) => new(str, separator); /// <summary> - /// Provides an enumerator for the substrings seperated by the separator. + /// Provides an enumerator for the substrings separated by the separator. /// </summary> [StructLayout(LayoutKind.Auto)] public ref struct Enumerator diff --git a/src/Jellyfin.Extensions/StringExtensions.cs b/src/Jellyfin.Extensions/StringExtensions.cs index dadc9f1d5..59fb038a7 100644 --- a/src/Jellyfin.Extensions/StringExtensions.cs +++ b/src/Jellyfin.Extensions/StringExtensions.cs @@ -40,7 +40,7 @@ namespace Jellyfin.Extensions } /// <summary> - /// Checks wether or not the specified string has diacritics in it. + /// Checks whether or not the specified string has diacritics in it. /// </summary> /// <param name="text">The string to check.</param> /// <returns>True if the string has diacritics, false otherwise.</returns> diff --git a/src/Jellyfin.MediaEncoding.Keyframes/FfProbe/FfProbeKeyframeExtractor.cs b/src/Jellyfin.MediaEncoding.Keyframes/FfProbe/FfProbeKeyframeExtractor.cs index 320604e10..79aa8a354 100644 --- a/src/Jellyfin.MediaEncoding.Keyframes/FfProbe/FfProbeKeyframeExtractor.cs +++ b/src/Jellyfin.MediaEncoding.Keyframes/FfProbe/FfProbeKeyframeExtractor.cs @@ -11,7 +11,7 @@ namespace Jellyfin.MediaEncoding.Keyframes.FfProbe; /// </summary> public static class FfProbeKeyframeExtractor { - private const string DefaultArguments = "-v error -skip_frame nokey -show_entries format=duration -show_entries stream=duration -show_entries packet=pts_time,flags -select_streams v -of csv \"{0}\""; + private const string DefaultArguments = "-fflags +genpts -v error -skip_frame nokey -show_entries format=duration -show_entries stream=duration -show_entries packet=pts_time,flags -select_streams v -of csv \"{0}\""; /// <summary> /// Extracts the keyframes using the ffprobe executable at the specified path. @@ -62,12 +62,17 @@ public static class FfProbeKeyframeExtractor var rest = line[(firstComma + 1)..]; if (lineType.Equals("packet", StringComparison.OrdinalIgnoreCase)) { - if (rest.EndsWith(",K_")) + // Split time and flags from the packet line. Example line: packet,7169.079000,K_ + var secondComma = rest.IndexOf(','); + var ptsTime = rest[..secondComma]; + var flags = rest[(secondComma + 1)..]; + if (flags.StartsWith("K_")) { - // Trim the flags from the packet line. Example line: packet,7169.079000,K_ - var keyframe = double.Parse(rest[..^3], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture); - // Have to manually convert to ticks to avoid rounding errors as TimeSpan is only precise down to 1 ms when converting double. - keyframes.Add(Convert.ToInt64(keyframe * TimeSpan.TicksPerSecond)); + if (double.TryParse(ptsTime, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var keyframe)) + { + // Have to manually convert to ticks to avoid rounding errors as TimeSpan is only precise down to 1 ms when converting double. + keyframes.Add(Convert.ToInt64(keyframe * TimeSpan.TicksPerSecond)); + } } } else if (lineType.Equals("stream", StringComparison.OrdinalIgnoreCase)) diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 3e610ced9..262ef8024 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -17,7 +17,7 @@ <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.8" /> <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PrivateAssets>all</PrivateAssets> diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index 82d752901..fec70c0e0 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -12,7 +12,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PrivateAssets>all</PrivateAssets> diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj index da52b93fc..4eac60897 100644 --- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj +++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj @@ -12,7 +12,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="Moq" Version="4.18.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> diff --git a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj index a7ad79def..5797648a8 100644 --- a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj +++ b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj @@ -7,7 +7,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="Moq" Version="4.18.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> diff --git a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj index 9f0f1c4de..dfe765583 100644 --- a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj +++ b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj @@ -7,7 +7,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> diff --git a/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj b/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj index 21206fb71..6d4dfd09f 100644 --- a/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj @@ -7,7 +7,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> diff --git a/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj b/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj index 67fb00b1c..3f49a5288 100644 --- a/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj @@ -8,7 +8,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj index 3da515bfc..0e0f0490b 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -22,7 +22,7 @@ <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> <PackageReference Include="coverlet.collector" Version="3.1.2" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="Moq" Version="4.18.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> diff --git a/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs b/tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs index 6948280a3..162f53e56 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.Model.Tests/Jellyfin.Model.Tests.csproj b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj index ad3cca77a..6edfbd50f 100644 --- a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj +++ b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj @@ -7,7 +7,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="Moq" Version="4.18.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj index 04c69b130..d4037c024 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -12,7 +12,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="Moq" Version="4.18.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> diff --git a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj index 8e5cbb282..909c14d0b 100644 --- a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj +++ b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj @@ -12,7 +12,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PrivateAssets>all</PrivateAssets> diff --git a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs index 6b9397437..52b0e5a95 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.Providers.Tests/Jellyfin.Providers.Tests.csproj b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj index 7bbd21048..2dac3dfb1 100644 --- a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj +++ b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj @@ -13,7 +13,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="Moq" Version="4.18.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index 086da7f43..49ab03c00 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -21,7 +21,7 @@ <ItemGroup> <PackageReference Include="AutoFixture" Version="4.17.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="Moq" Version="4.18.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs index 3b3e38bd1..e1d2bb2d5 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 } /// <summary> - /// /token reponse. + /// /token response. /// </summary> [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 b766e668e..fa8fbd8d2 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", 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 9d6776b07..fdab02d7b 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj +++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj @@ -11,7 +11,7 @@ <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.8" /> <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PrivateAssets>all</PrivateAssets> diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index f19e33061..4b11dc1bc 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -12,7 +12,7 @@ <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.8" /> <PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PrivateAssets>all</PrivateAssets> diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj index f3a3058ec..d3119771d 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj +++ b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj @@ -13,7 +13,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" /> <PackageReference Include="Moq" Version="4.18.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> |
