aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/azure-pipelines-package.yml2
-rw-r--r--CONTRIBUTORS.md2
-rw-r--r--Emby.Dlna/Didl/DidlBuilder.cs2
-rw-r--r--Emby.Dlna/DlnaManager.cs2
-rw-r--r--Emby.Dlna/IDlnaEventManager.cs4
-rw-r--r--Emby.Dlna/PlayTo/Device.cs33
-rw-r--r--Emby.Dlna/PlayTo/DlnaHttpClient.cs108
-rw-r--r--Emby.Dlna/PlayTo/SsdpHttpClient.cs141
-rw-r--r--Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs12
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs2
-rw-r--r--Emby.Server.Implementations/Localization/Core/ko.json5
-rw-r--r--Emby.Server.Implementations/Localization/Core/mk.json26
-rw-r--r--Emby.Server.Implementations/Localization/Core/my.json98
-rw-r--r--Emby.Server.Implementations/Localization/Core/sl-SI.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/sr.json4
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs2
-rw-r--r--Emby.Server.Implementations/Session/SessionWebSocketListener.cs2
-rw-r--r--Jellyfin.Api/Attributes/HttpSubscribeAttribute.cs7
-rw-r--r--Jellyfin.Api/Attributes/HttpUnsubscribeAttribute.cs7
-rw-r--r--Jellyfin.Api/Controllers/AudioController.cs2
-rw-r--r--Jellyfin.Api/Controllers/DisplayPreferencesController.cs7
-rw-r--r--Jellyfin.Api/Controllers/DynamicHlsController.cs4
-rw-r--r--Jellyfin.Api/Controllers/ItemsController.cs53
-rw-r--r--Jellyfin.Api/Controllers/QuickConnectController.cs8
-rw-r--r--Jellyfin.Api/Controllers/SearchController.cs14
-rw-r--r--Jellyfin.Api/Controllers/TrailersController.cs7
-rw-r--r--Jellyfin.Api/Controllers/UniversalAudioController.cs89
-rw-r--r--Jellyfin.Api/Controllers/UserController.cs2
-rw-r--r--Jellyfin.Api/Models/StreamingDtos/StreamState.cs2
-rw-r--r--Jellyfin.Api/Models/SyncPlayDtos/RemoveFromPlaylistRequestDto.cs4
-rw-r--r--Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj2
-rw-r--r--Jellyfin.Drawing.Skia/SkiaEncoder.cs6
-rw-r--r--Jellyfin.Drawing.Skia/SkiaHelper.cs2
-rw-r--r--Jellyfin.Networking/Configuration/NetworkConfiguration.cs2
-rw-r--r--Jellyfin.Networking/Manager/NetworkManager.cs2
-rw-r--r--Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs2
-rw-r--r--Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs2
-rw-r--r--Jellyfin.Server.Implementations/Users/UserManager.cs8
-rw-r--r--Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs11
-rw-r--r--Jellyfin.Server/Jellyfin.Server.csproj2
-rw-r--r--Jellyfin.Server/Startup.cs17
-rw-r--r--MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs25
-rw-r--r--MediaBrowser.Common/Configuration/IApplicationPaths.cs2
-rw-r--r--MediaBrowser.Common/Net/NamedClient.cs5
-rw-r--r--MediaBrowser.Controller/Entities/BasePluginFolder.cs4
-rw-r--r--MediaBrowser.Controller/Entities/Extensions.cs8
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs2
-rw-r--r--MediaBrowser.Controller/IDisplayPreferencesManager.cs6
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs4
-rw-r--r--MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs2
-rw-r--r--MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs4
-rw-r--r--MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs4
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs4
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs4
-rw-r--r--MediaBrowser.Model/Configuration/UserConfiguration.cs16
-rw-r--r--MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs2
-rw-r--r--MediaBrowser.Model/Dto/BaseItemDto.cs6
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs2
-rw-r--r--MediaBrowser.Model/LiveTv/TunerHostInfo.cs3
-rw-r--r--MediaBrowser.Model/Search/SearchHint.cs66
-rw-r--r--MediaBrowser.Model/SyncPlay/GroupStateType.cs2
-rw-r--r--MediaBrowser.Model/Tasks/ITaskManager.cs10
-rw-r--r--MediaBrowser.Model/Tasks/ITaskTrigger.cs4
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs2
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs2
-rw-r--r--deployment/Dockerfile.linux.musl-linux-arm6426
-rwxr-xr-xdeployment/build.linux.musl-linux-arm6431
-rw-r--r--fedora/jellyfin.env2
-rw-r--r--src/Jellyfin.Extensions/SplitStringExtensions.cs2
-rw-r--r--src/Jellyfin.Extensions/StringExtensions.cs2
-rw-r--r--src/Jellyfin.MediaEncoding.Keyframes/FfProbe/FfProbeKeyframeExtractor.cs17
-rw-r--r--tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs2
-rw-r--r--tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj6
-rw-r--r--tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs8
-rw-r--r--tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedArrayModelBinderTests.cs8
-rw-r--r--tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj4
-rw-r--r--tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj6
-rw-r--r--tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj6
-rw-r--r--tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj2
-rw-r--r--tests/Jellyfin.Extensions.Tests/Json/Converters/JsonStringConverterTests.cs2
-rw-r--r--tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj4
-rw-r--r--tests/Jellyfin.MediaEncoding.Hls.Tests/Playlist/DynamicHlsPlaylistGeneratorTests.cs4
-rw-r--r--tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj4
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj6
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Subtitles/SubtitleEncoderTests.cs2
-rw-r--r--tests/Jellyfin.Model.Tests/Cryptography/PasswordHashTests.cs6
-rw-r--r--tests/Jellyfin.Model.Tests/Drawing/ImageFormatExtensionsTests.cs2
-rw-r--r--tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj6
-rw-r--r--tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj6
-rw-r--r--tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj6
-rw-r--r--tests/Jellyfin.Networking.Tests/NetworkParseTests.cs2
-rw-r--r--tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj6
-rw-r--r--tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs2
-rw-r--r--tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs2
-rw-r--r--tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs2
-rw-r--r--tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs2
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj6
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs2
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Sorting/IndexNumberComparerTests.cs2
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Sorting/ParentIndexNumberComparerTests.cs2
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Test Data/Updates/manifest-stable.json2
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs1
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs8
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs2
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj6
-rw-r--r--tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj6
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj6
111 files changed, 626 insertions, 510 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 a7d2b2e40..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)
@@ -157,6 +158,7 @@
- [jonas-resch](https://github.com/jonas-resch)
- [vgambier](https://github.com/vgambier)
- [MinecraftPlaye](https://github.com/MinecraftPlaye)
+ - [RealGreenDragon](https://github.com/RealGreenDragon)
# Emby Contributors
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/ko.json b/Emby.Server.Implementations/Localization/Core/ko.json
index 50d019f90..186ec44d2 100644
--- a/Emby.Server.Implementations/Localization/Core/ko.json
+++ b/Emby.Server.Implementations/Localization/Core/ko.json
@@ -120,5 +120,8 @@
"Forced": "강제하기",
"Default": "기본 설정",
"TaskOptimizeDatabaseDescription": "데이터베이스를 압축하고 사용 가능한 공간을 늘립니다. 라이브러리를 검색한 후 이 작업을 실행하거나 데이터베이스 수정같은 비슷한 작업을 수행하면 성능이 향상될 수 있습니다.",
- "TaskOptimizeDatabase": "데이터베이스 최적화"
+ "TaskOptimizeDatabase": "데이터베이스 최적화",
+ "TaskKeyframeExtractorDescription": "비디오 파일에서 키프레임을 추출하여 더 정확한 HLS 재생 목록을 만듭니다. 이 작업은 오랫동안 진행될 수 있습니다.",
+ "TaskKeyframeExtractor": "키프레임 추출",
+ "External": "외부"
}
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/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs
index 1d207d9ad..4d09070db 100644
--- a/Jellyfin.Api/Controllers/ItemsController.cs
+++ b/Jellyfin.Api/Controllers/ItemsController.cs
@@ -1,6 +1,7 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
+using System.Threading.Tasks;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Extensions;
using Jellyfin.Api.Helpers;
@@ -9,6 +10,7 @@ using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -32,6 +34,7 @@ namespace Jellyfin.Api.Controllers
private readonly ILibraryManager _libraryManager;
private readonly ILocalizationManager _localization;
private readonly IDtoService _dtoService;
+ private readonly IAuthorizationContext _authContext;
private readonly ILogger<ItemsController> _logger;
private readonly ISessionManager _sessionManager;
@@ -42,6 +45,7 @@ namespace Jellyfin.Api.Controllers
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
/// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
/// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
+ /// <param name="authContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param>
/// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
/// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param>
public ItemsController(
@@ -49,6 +53,7 @@ namespace Jellyfin.Api.Controllers
ILibraryManager libraryManager,
ILocalizationManager localization,
IDtoService dtoService,
+ IAuthorizationContext authContext,
ILogger<ItemsController> logger,
ISessionManager sessionManager)
{
@@ -56,6 +61,7 @@ namespace Jellyfin.Api.Controllers
_libraryManager = libraryManager;
_localization = localization;
_dtoService = dtoService;
+ _authContext = authContext;
_logger = logger;
_sessionManager = sessionManager;
}
@@ -63,7 +69,7 @@ namespace Jellyfin.Api.Controllers
/// <summary>
/// Gets items based on a query.
/// </summary>
- /// <param name="userId">The user id supplied as query parameter.</param>
+ /// <param name="userId">The user id supplied as query parameter; this is required when not using an API key.</param>
/// <param name="maxOfficialRating">Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).</param>
/// <param name="hasThemeSong">Optional filter by items with theme songs.</param>
/// <param name="hasThemeVideo">Optional filter by items with theme videos.</param>
@@ -151,8 +157,8 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the items.</returns>
[HttpGet("Items")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QueryResult<BaseItemDto>> GetItems(
- [FromQuery] Guid userId,
+ public async Task<ActionResult<QueryResult<BaseItemDto>>> GetItems(
+ [FromQuery] Guid? userId,
[FromQuery] string? maxOfficialRating,
[FromQuery] bool? hasThemeSong,
[FromQuery] bool? hasThemeVideo,
@@ -238,7 +244,19 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool enableTotalRecordCount = true,
[FromQuery] bool? enableImages = true)
{
- var user = userId.Equals(default) ? null : _userManager.GetUserById(userId);
+ var auth = await _authContext.GetAuthorizationInfo(Request).ConfigureAwait(false);
+
+ // if api key is used (auth.IsApiKey == true), then `user` will be null throughout this method
+ var user = !auth.IsApiKey && userId.HasValue && !userId.Value.Equals(default)
+ ? _userManager.GetUserById(userId.Value)
+ : null;
+
+ // beyond this point, we're either using an api key or we have a valid user
+ if (!auth.IsApiKey && user is null)
+ {
+ return BadRequest("userId is required");
+ }
+
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(Request)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
@@ -270,30 +288,39 @@ namespace Jellyfin.Api.Controllers
includeItemTypes = new[] { BaseItemKind.Playlist };
}
- var enabledChannels = user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledChannels);
+ var enabledChannels = auth.IsApiKey
+ ? Array.Empty<Guid>()
+ : user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledChannels);
- bool isInEnabledFolder = Array.IndexOf(user.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders), item.Id) != -1
+ // api keys are always enabled for all folders
+ bool isInEnabledFolder = auth.IsApiKey
+ || Array.IndexOf(user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders), item.Id) != -1
// Assume all folders inside an EnabledChannel are enabled
|| Array.IndexOf(enabledChannels, item.Id) != -1
// Assume all items inside an EnabledChannel are enabled
|| Array.IndexOf(enabledChannels, item.ChannelId) != -1;
- var collectionFolders = _libraryManager.GetCollectionFolders(item);
- foreach (var collectionFolder in collectionFolders)
+ if (!isInEnabledFolder)
{
- if (user.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id))
+ var collectionFolders = _libraryManager.GetCollectionFolders(item);
+ foreach (var collectionFolder in collectionFolders)
{
- isInEnabledFolder = true;
+ // api keys never enter this block, so user is never null
+ if (user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id))
+ {
+ isInEnabledFolder = true;
+ }
}
}
+ // api keys are always enabled for all folders, so user is never null
if (item is not UserRootFolder
&& !isInEnabledFolder
- && !user.HasPermission(PermissionKind.EnableAllFolders)
+ && !user!.HasPermission(PermissionKind.EnableAllFolders)
&& !user.HasPermission(PermissionKind.EnableAllChannels)
&& !string.Equals(collectionType, CollectionType.Folders, StringComparison.OrdinalIgnoreCase))
{
- _logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Username, item.Name);
+ _logger.LogWarning("{UserName} is not permitted to access Library {ItemName}", user.Username, item.Name);
return Unauthorized($"{user.Username} is not permitted to access Library {item.Name}.");
}
@@ -606,7 +633,7 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the items.</returns>
[HttpGet("Users/{userId}/Items")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QueryResult<BaseItemDto>> GetItemsByUserId(
+ public Task<ActionResult<QueryResult<BaseItemDto>>> GetItemsByUserId(
[FromRoute] Guid userId,
[FromQuery] string? maxOfficialRating,
[FromQuery] bool? hasThemeSong,
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 07e113ad3..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>
@@ -79,7 +79,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet]
[Description("Gets search hints based on a search term")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<SearchHintResult> Get(
+ public ActionResult<SearchHintResult> GetSearchHints(
[FromQuery] int? startIndex,
[FromQuery] int? limit,
[FromQuery] Guid? userId,
@@ -140,7 +140,7 @@ namespace Jellyfin.Api.Controllers
IndexNumber = item.IndexNumber,
ParentIndexNumber = item.ParentIndexNumber,
Id = item.Id,
- Type = item.GetClientTypeName(),
+ Type = item.GetBaseItemKind(),
MediaType = item.MediaType,
MatchedTerm = hintInfo.MatchedTerm,
RunTimeTicks = item.RunTimeTicks,
@@ -149,8 +149,10 @@ namespace Jellyfin.Api.Controllers
EndDate = item.EndDate
};
- // legacy
+#pragma warning disable CS0618
+ // Kept for compatibility with older clients
result.ItemId = result.Id;
+#pragma warning restore CS0618
if (item.IsFolder)
{
diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs
index 1c5aa9b8e..cf812fa23 100644
--- a/Jellyfin.Api/Controllers/TrailersController.cs
+++ b/Jellyfin.Api/Controllers/TrailersController.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading.Tasks;
using Jellyfin.Api.Constants;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Data.Enums;
@@ -31,7 +32,7 @@ namespace Jellyfin.Api.Controllers
/// <summary>
/// Finds movies and trailers similar to a given trailer.
/// </summary>
- /// <param name="userId">The user id.</param>
+ /// <param name="userId">The user id supplied as query parameter; this is required when not using an API key.</param>
/// <param name="maxOfficialRating">Optional filter by maximum official rating (PG, PG-13, TV-MA, etc).</param>
/// <param name="hasThemeSong">Optional filter by items with theme songs.</param>
/// <param name="hasThemeVideo">Optional filter by items with theme videos.</param>
@@ -118,8 +119,8 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the trailers.</returns>
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QueryResult<BaseItemDto>> GetTrailers(
- [FromQuery] Guid userId,
+ public Task<ActionResult<QueryResult<BaseItemDto>>> GetTrailers(
+ [FromQuery] Guid? userId,
[FromQuery] string? maxOfficialRating,
[FromQuery] bool? hasThemeSong,
[FromQuery] bool? hasThemeVideo,
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/Jellyfin.Drawing.Skia.csproj b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
index b64a84292..e2cdbb562 100644
--- a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
+++ b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
@@ -18,7 +18,7 @@
<ItemGroup>
<PackageReference Include="BlurHashSharp" Version="1.2.0" />
<PackageReference Include="BlurHashSharp.SkiaSharp" Version="1.2.0" />
- <PackageReference Include="SkiaSharp" Version="2.88.1-preview.79" />
+ <PackageReference Include="SkiaSharp" Version="2.88.1" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.1-preview.79" />
<PackageReference Include="SkiaSharp.Svg" Version="1.60.0" />
</ItemGroup>
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/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj
index e6bc3fe2b..4474a6d12 100644
--- a/Jellyfin.Server/Jellyfin.Server.csproj
+++ b/Jellyfin.Server/Jellyfin.Server.csproj
@@ -48,7 +48,7 @@
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.Graylog" Version="2.3.0" />
- <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.0" />
+ <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
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.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 6112fda68..115f085ff 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -574,7 +574,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
throw;
}
- var ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMinutes(5)).ConfigureAwait(false);
+ var ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMinutes(30)).ConfigureAwait(false);
if (!ranToCompletion)
{
@@ -746,7 +746,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
}
- internal readonly struct SubtitleInfo
+ public readonly struct SubtitleInfo
{
public SubtitleInfo(string path, MediaProtocol protocol, string format, bool isExternal)
{
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/Search/SearchHint.cs b/MediaBrowser.Model/Search/SearchHint.cs
index 983dbd2bc..4696c3797 100644
--- a/MediaBrowser.Model/Search/SearchHint.cs
+++ b/MediaBrowser.Model/Search/SearchHint.cs
@@ -1,8 +1,6 @@
-#nullable disable
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
+using Jellyfin.Data.Enums;
namespace MediaBrowser.Model.Search
{
@@ -12,11 +10,27 @@ namespace MediaBrowser.Model.Search
public class SearchHint
{
/// <summary>
+ /// Initializes a new instance of the <see cref="SearchHint" /> class.
+ /// </summary>
+ public SearchHint()
+ {
+ Name = string.Empty;
+ MatchedTerm = string.Empty;
+ MediaType = string.Empty;
+ Artists = Array.Empty<string>();
+ }
+
+ /// <summary>
/// Gets or sets the item id.
/// </summary>
/// <value>The item id.</value>
+ [Obsolete("Use Id instead")]
public Guid ItemId { get; set; }
+ /// <summary>
+ /// Gets or sets the item id.
+ /// </summary>
+ /// <value>The item id.</value>
public Guid Id { get; set; }
/// <summary>
@@ -53,38 +67,42 @@ namespace MediaBrowser.Model.Search
/// Gets or sets the image tag.
/// </summary>
/// <value>The image tag.</value>
- public string PrimaryImageTag { get; set; }
+ public string? PrimaryImageTag { get; set; }
/// <summary>
/// Gets or sets the thumb image tag.
/// </summary>
/// <value>The thumb image tag.</value>
- public string ThumbImageTag { get; set; }
+ public string? ThumbImageTag { get; set; }
/// <summary>
/// Gets or sets the thumb image item identifier.
/// </summary>
/// <value>The thumb image item identifier.</value>
- public string ThumbImageItemId { get; set; }
+ public string? ThumbImageItemId { get; set; }
/// <summary>
/// Gets or sets the backdrop image tag.
/// </summary>
/// <value>The backdrop image tag.</value>
- public string BackdropImageTag { get; set; }
+ public string? BackdropImageTag { get; set; }
/// <summary>
/// Gets or sets the backdrop image item identifier.
/// </summary>
/// <value>The backdrop image item identifier.</value>
- public string BackdropImageItemId { get; set; }
+ public string? BackdropImageItemId { get; set; }
/// <summary>
/// Gets or sets the type.
/// </summary>
/// <value>The type.</value>
- public string Type { get; set; }
+ public BaseItemKind Type { get; set; }
+ /// <summary>
+ /// Gets a value indicating whether this instance is folder.
+ /// </summary>
+ /// <value><c>true</c> if this instance is folder; otherwise, <c>false</c>.</value>
public bool? IsFolder { get; set; }
/// <summary>
@@ -99,31 +117,47 @@ namespace MediaBrowser.Model.Search
/// <value>The type of the media.</value>
public string MediaType { get; set; }
+ /// <summary>
+ /// Gets or sets the start date.
+ /// </summary>
+ /// <value>The start date.</value>
public DateTime? StartDate { get; set; }
+ /// <summary>
+ /// Gets or sets the end date.
+ /// </summary>
+ /// <value>The end date.</value>
public DateTime? EndDate { get; set; }
/// <summary>
/// Gets or sets the series.
/// </summary>
/// <value>The series.</value>
- public string Series { get; set; }
+ public string? Series { get; set; }
- public string Status { get; set; }
+ /// <summary>
+ /// Gets or sets the status.
+ /// </summary>
+ /// <value>The status.</value>
+ public string? Status { get; set; }
/// <summary>
/// Gets or sets the album.
/// </summary>
/// <value>The album.</value>
- public string Album { get; set; }
+ public string? Album { get; set; }
- public Guid AlbumId { get; set; }
+ /// <summary>
+ /// Gets or sets the album id.
+ /// </summary>
+ /// <value>The album id.</value>
+ public Guid? AlbumId { get; set; }
/// <summary>
/// Gets or sets the album artist.
/// </summary>
/// <value>The album artist.</value>
- public string AlbumArtist { get; set; }
+ public string? AlbumArtist { get; set; }
/// <summary>
/// Gets or sets the artists.
@@ -147,13 +181,13 @@ namespace MediaBrowser.Model.Search
/// Gets or sets the channel identifier.
/// </summary>
/// <value>The channel identifier.</value>
- public Guid ChannelId { get; set; }
+ public Guid? ChannelId { get; set; }
/// <summary>
/// Gets or sets the name of the channel.
/// </summary>
/// <value>The name of the channel.</value>
- public string ChannelName { get; set; }
+ public string? ChannelName { get; set; }
/// <summary>
/// Gets or sets the primary image aspect ratio.
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/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs
index 23c51999f..7c85ddd62 100644
--- a/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs
+++ b/tests/Jellyfin.Api.Tests/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandlerTests.cs
@@ -62,7 +62,7 @@ namespace Jellyfin.Api.Tests.Auth.DefaultAuthorizationPolicy
}
}
- private static TheoryData<string, Dictionary<string, string>> GetParts_ValidAuthHeader_Success_Data()
+ public static TheoryData<string, Dictionary<string, string>> GetParts_ValidAuthHeader_Success_Data()
{
var data = new TheoryData<string, Dictionary<string, string>>();
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
index 3e610ced9..97a549943 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -17,14 +17,14 @@
<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="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2" />
- <PackageReference Include="Moq" Version="4.18.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
</ItemGroup>
<!-- Code Analyzers -->
diff --git a/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs b/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs
index 3ae6ae5bd..e37c9d91f 100644
--- a/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs
+++ b/tests/Jellyfin.Api.Tests/ModelBinders/CommaDelimitedArrayModelBinderTests.cs
@@ -192,7 +192,9 @@ namespace Jellyfin.Api.Tests.ModelBinders
await modelBinder.BindModelAsync(bindingContextMock.Object);
Assert.True(bindingContextMock.Object.Result.IsModelSet);
- Assert.Empty((IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model);
+ var listResult = (IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model;
+ Assert.NotNull(listResult);
+ Assert.Empty(listResult);
}
[Fact]
@@ -220,7 +222,9 @@ namespace Jellyfin.Api.Tests.ModelBinders
await modelBinder.BindModelAsync(bindingContextMock.Object);
Assert.True(bindingContextMock.Object.Result.IsModelSet);
- Assert.Single((IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model);
+ var listResult = (IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model;
+ Assert.NotNull(listResult);
+ Assert.Single(listResult);
}
}
}
diff --git a/tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedArrayModelBinderTests.cs b/tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedArrayModelBinderTests.cs
index 938d19a15..7c05ee036 100644
--- a/tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedArrayModelBinderTests.cs
+++ b/tests/Jellyfin.Api.Tests/ModelBinders/PipeDelimitedArrayModelBinderTests.cs
@@ -192,7 +192,9 @@ namespace Jellyfin.Api.Tests.ModelBinders
await modelBinder.BindModelAsync(bindingContextMock.Object);
Assert.True(bindingContextMock.Object.Result.IsModelSet);
- Assert.Empty((IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model);
+ var listResult = (IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model;
+ Assert.NotNull(listResult);
+ Assert.Empty(listResult);
}
[Fact]
@@ -220,7 +222,9 @@ namespace Jellyfin.Api.Tests.ModelBinders
await modelBinder.BindModelAsync(bindingContextMock.Object);
Assert.True(bindingContextMock.Object.Result.IsModelSet);
- Assert.Single((IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model);
+ var listResult = (IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model;
+ Assert.NotNull(listResult);
+ Assert.Single(listResult);
}
}
}
diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
index 82d752901..77cdcfada 100644
--- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
+++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
@@ -12,8 +12,8 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
index da52b93fc..1496bc80c 100644
--- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
+++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
@@ -12,9 +12,9 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
- <PackageReference Include="Moq" Version="4.18.1" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
index a7ad79def..f450936f2 100644
--- a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
+++ b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
@@ -7,9 +7,9 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
- <PackageReference Include="Moq" Version="4.18.1" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
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.Extensions.Tests/Json/Converters/JsonStringConverterTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonStringConverterTests.cs
index 345f37cbe..77717af70 100644
--- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonStringConverterTests.cs
+++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonStringConverterTests.cs
@@ -32,7 +32,7 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
const string? input = "123";
const int output = 123;
var deserialized = JsonSerializer.Deserialize<int>(input, _jsonSerializerOptions);
- Assert.Equal(deserialized, output);
+ Assert.Equal(output, deserialized);
}
}
}
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..dae7722c3 100644
--- a/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj
+++ b/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj
@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
diff --git a/tests/Jellyfin.MediaEncoding.Hls.Tests/Playlist/DynamicHlsPlaylistGeneratorTests.cs b/tests/Jellyfin.MediaEncoding.Hls.Tests/Playlist/DynamicHlsPlaylistGeneratorTests.cs
index 79648c4f6..bbacdcd62 100644
--- a/tests/Jellyfin.MediaEncoding.Hls.Tests/Playlist/DynamicHlsPlaylistGeneratorTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Hls.Tests/Playlist/DynamicHlsPlaylistGeneratorTests.cs
@@ -53,7 +53,7 @@ namespace Jellyfin.MediaEncoding.Hls.Tests.Playlist
Assert.False(DynamicHlsPlaylistGenerator.IsExtractionAllowedForFile(filePath, allowedExtensions));
}
- private static TheoryData<int, long, double[]> ComputeEqualLengthSegments_Valid_Success_Data()
+ public static TheoryData<int, long, double[]> ComputeEqualLengthSegments_Valid_Success_Data()
{
var data = new TheoryData<int, long, double[]>
{
@@ -67,7 +67,7 @@ namespace Jellyfin.MediaEncoding.Hls.Tests.Playlist
return data;
}
- private static TheoryData<KeyframeData, int, double[]> ComputeSegments_Valid_Success_Data()
+ public static TheoryData<KeyframeData, int, double[]> ComputeSegments_Valid_Success_Data()
{
var data = new TheoryData<KeyframeData, int, double[]>
{
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..ea4788cb8 100644
--- a/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj
+++ b/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj
@@ -8,8 +8,8 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
index 3da515bfc..5914eea47 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
+++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
@@ -22,9 +22,9 @@
<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="Moq" Version="4.18.1" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SubtitleEncoderTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SubtitleEncoderTests.cs
index 639c364df..243127438 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SubtitleEncoderTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SubtitleEncoderTests.cs
@@ -12,7 +12,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests
{
public class SubtitleEncoderTests
{
- internal static TheoryData<MediaSourceInfo, MediaStream, SubtitleEncoder.SubtitleInfo> GetReadableFile_Valid_TestData()
+ public static TheoryData<MediaSourceInfo, MediaStream, SubtitleEncoder.SubtitleInfo> GetReadableFile_Valid_TestData()
{
var data = new TheoryData<MediaSourceInfo, MediaStream, SubtitleEncoder.SubtitleInfo>();
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/Drawing/ImageFormatExtensionsTests.cs b/tests/Jellyfin.Model.Tests/Drawing/ImageFormatExtensionsTests.cs
index 7c3a7ff6c..a5bdb42d8 100644
--- a/tests/Jellyfin.Model.Tests/Drawing/ImageFormatExtensionsTests.cs
+++ b/tests/Jellyfin.Model.Tests/Drawing/ImageFormatExtensionsTests.cs
@@ -7,7 +7,7 @@ namespace Jellyfin.Model.Drawing;
public static class ImageFormatExtensionsTests
{
- private static TheoryData<ImageFormat> GetAllImageFormats()
+ public static TheoryData<ImageFormat> GetAllImageFormats()
{
var theoryTypes = new TheoryData<ImageFormat>();
foreach (var x in Enum.GetValues<ImageFormat>())
diff --git a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj
index ad3cca77a..cef719cbd 100644
--- a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj
+++ b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj
@@ -7,9 +7,9 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
- <PackageReference Include="Moq" Version="4.18.1" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
index 04c69b130..a630ace15 100644
--- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
+++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
@@ -12,9 +12,9 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
- <PackageReference Include="Moq" Version="4.18.1" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj
index 8e5cbb282..75f0e688c 100644
--- a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj
+++ b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj
@@ -12,15 +12,15 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="FsCheck.Xunit" Version="2.16.5" />
- <PackageReference Include="Moq" Version="4.18.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
</ItemGroup>
<!-- Code Analyzers-->
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..465ea6b94 100644
--- a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj
+++ b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj
@@ -13,9 +13,9 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
- <PackageReference Include="Moq" Version="4.18.1" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
diff --git a/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs
index c0931dbcf..08b343cd8 100644
--- a/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs
+++ b/tests/Jellyfin.Providers.Tests/Manager/ItemImageProviderTests.cs
@@ -44,7 +44,7 @@ namespace Jellyfin.Providers.Tests.Manager
ValidateImages_Test(ImageType.Primary, 0, true, 0, false, 0);
}
- private static TheoryData<ImageType, int> GetImageTypesWithCount()
+ public static TheoryData<ImageType, int> GetImageTypesWithCount()
{
var theoryTypes = new TheoryData<ImageType, int>
{
diff --git a/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs b/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs
index b74b331b7..28b2e1d8f 100644
--- a/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs
+++ b/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs
@@ -132,7 +132,7 @@ namespace Jellyfin.Providers.Tests.Manager
Assert.True(TestMergeBaseItemData<Audio, SongInfo>(propName, oldValue, Array.Empty<string>(), null, true, out _));
}
- private static TheoryData<string, object, object> MergeBaseItemData_SimpleField_ReplacesAppropriately_TestData()
+ public static TheoryData<string, object, object> MergeBaseItemData_SimpleField_ReplacesAppropriately_TestData()
=> new()
{
{ "IndexNumber", 1, 2 },
diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs
index 91f61868b..57674bb7f 100644
--- a/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs
+++ b/tests/Jellyfin.Providers.Tests/MediaInfo/MediaInfoResolverTests.cs
@@ -209,7 +209,7 @@ public class MediaInfoResolverTests
Assert.Empty(streams);
}
- private static TheoryData<string, MediaStream[], MediaStream[]> GetExternalStreams_MergeMetadata_HandlesOverridesCorrectly_Data()
+ public static TheoryData<string, MediaStream[], MediaStream[]> GetExternalStreams_MergeMetadata_HandlesOverridesCorrectly_Data()
{
var data = new TheoryData<string, MediaStream[], MediaStream[]>();
diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs
index 7e88cdb20..6b2a05241 100644
--- a/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs
+++ b/tests/Jellyfin.Providers.Tests/MediaInfo/VideoImageProviderTests.cs
@@ -19,7 +19,7 @@ namespace Jellyfin.Providers.Tests.MediaInfo
{
public class VideoImageProviderTests
{
- private static TheoryData<Video> GetImage_UnsupportedInput_ReturnsNoImage_TestData()
+ public static TheoryData<Video> GetImage_UnsupportedInput_ReturnsNoImage_TestData()
{
return new()
{
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..27390c937 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
+++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
@@ -21,9 +21,9 @@
<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="Moq" Version="4.18.1" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
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/Sorting/IndexNumberComparerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Sorting/IndexNumberComparerTests.cs
index 164161800..18588bd67 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Sorting/IndexNumberComparerTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Sorting/IndexNumberComparerTests.cs
@@ -11,7 +11,7 @@ public class IndexNumberComparerTests
{
private readonly IBaseItemComparer _cmp = new IndexNumberComparer();
- private static TheoryData<BaseItem?, BaseItem?> Compare_GivenNull_ThrowsArgumentNullException_TestData()
+ public static TheoryData<BaseItem?, BaseItem?> Compare_GivenNull_ThrowsArgumentNullException_TestData()
=> new()
{
{ null, new Audio() },
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Sorting/ParentIndexNumberComparerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Sorting/ParentIndexNumberComparerTests.cs
index 7649e4df4..40f271d61 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Sorting/ParentIndexNumberComparerTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Sorting/ParentIndexNumberComparerTests.cs
@@ -12,7 +12,7 @@ public class ParentIndexNumberComparerTests
{
private readonly IBaseItemComparer _cmp = new ParentIndexNumberComparer();
- private static TheoryData<BaseItem?, BaseItem?> Compare_GivenNull_ThrowsArgumentNullException_TestData()
+ public static TheoryData<BaseItem?, BaseItem?> Compare_GivenNull_ThrowsArgumentNullException_TestData()
=> new()
{
{ null, new Audio() },
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/Controllers/DashboardControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs
index 0afb6f88d..52df1cd60 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs
@@ -83,6 +83,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
var res = await response.Content.ReadAsStreamAsync();
var data = await JsonSerializer.DeserializeAsync<ConfigurationPageInfo[]>(res, _jsonOpions);
+ Assert.NotNull(data);
Assert.Empty(data);
}
}
diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs
index e72dacfe0..0dd22644a 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs
@@ -62,7 +62,9 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
using var contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var user = await JsonSerializer.DeserializeAsync<StartupUserDto>(contentStream, _jsonOptions).ConfigureAwait(false);
- Assert.NotEmpty(user!.Name);
+ Assert.NotNull(user);
+ Assert.NotNull(user.Name);
+ Assert.NotEmpty(user.Name);
Assert.Null(user.Password);
}
@@ -87,7 +89,9 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
var contentStream = await getResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
var newUser = await JsonSerializer.DeserializeAsync<StartupUserDto>(contentStream, _jsonOptions).ConfigureAwait(false);
- Assert.Equal(user.Name, newUser!.Name);
+ Assert.NotNull(newUser);
+ Assert.Equal(user.Name, newUser.Name);
+ Assert.NotNull(newUser.Password);
Assert.NotEmpty(newUser.Password);
Assert.NotEqual(user.Password, newUser.Password);
}
diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs
index 9d34c39a2..2b825a93a 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs
@@ -46,6 +46,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
var users = await JsonSerializer.DeserializeAsync<UserDto[]>(
await response.Content.ReadAsStreamAsync().ConfigureAwait(false), _jsonOpions).ConfigureAwait(false);
// User are hidden by default
+ Assert.NotNull(users);
Assert.Empty(users);
}
@@ -60,6 +61,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var users = await JsonSerializer.DeserializeAsync<UserDto[]>(
await response.Content.ReadAsStreamAsync().ConfigureAwait(false), _jsonOpions).ConfigureAwait(false);
+ Assert.NotNull(users);
Assert.Single(users);
Assert.False(users![0].HasConfiguredPassword);
}
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..2be523a80 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj
+++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj
@@ -11,15 +11,15 @@
<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="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Xunit.Priority" Version="1.1.6" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
- <PackageReference Include="Moq" Version="4.18.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
</ItemGroup>
<ItemGroup>
diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
index f19e33061..e69f1f0e0 100644
--- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
+++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
@@ -12,14 +12,14 @@
<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="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2" />
- <PackageReference Include="Moq" Version="4.18.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
</ItemGroup>
<!-- Code Analyzers -->
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
index f3a3058ec..53921cb6e 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
@@ -13,9 +13,9 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
- <PackageReference Include="Moq" Version="4.18.1" />
- <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
+ <PackageReference Include="Moq" Version="4.18.2" />
+ <PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>