From 41c1c5f7bf71552b2babbd7c0066c9057c970559 Mon Sep 17 00:00:00 2001 From: KGT1 Date: Tue, 7 Oct 2025 09:52:30 +0000 Subject: [PATCH 01/24] remove global subtitle configuration --- .../Providers/SubtitleConfigurationFactory.cs | 21 --------- .../Providers/SubtitleOptions.cs | 36 --------------- .../MediaInfo/FFProbeVideoInfo.cs | 41 ++--------------- .../MediaInfo/SubtitleScheduledTask.cs | 46 ++++++------------- 4 files changed, 20 insertions(+), 124 deletions(-) delete mode 100644 MediaBrowser.Common/Providers/SubtitleConfigurationFactory.cs delete mode 100644 MediaBrowser.Model/Providers/SubtitleOptions.cs diff --git a/MediaBrowser.Common/Providers/SubtitleConfigurationFactory.cs b/MediaBrowser.Common/Providers/SubtitleConfigurationFactory.cs deleted file mode 100644 index 0445397ad8..0000000000 --- a/MediaBrowser.Common/Providers/SubtitleConfigurationFactory.cs +++ /dev/null @@ -1,21 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Providers; - -namespace MediaBrowser.Common.Providers -{ - public class SubtitleConfigurationFactory : IConfigurationFactory - { - /// - public IEnumerable GetConfigurations() - { - yield return new ConfigurationStore() - { - Key = "subtitles", - ConfigurationType = typeof(SubtitleOptions) - }; - } - } -} diff --git a/MediaBrowser.Model/Providers/SubtitleOptions.cs b/MediaBrowser.Model/Providers/SubtitleOptions.cs deleted file mode 100644 index 6ea1e14862..0000000000 --- a/MediaBrowser.Model/Providers/SubtitleOptions.cs +++ /dev/null @@ -1,36 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using System; - -namespace MediaBrowser.Model.Providers -{ - public class SubtitleOptions - { - public SubtitleOptions() - { - DownloadLanguages = Array.Empty(); - - SkipIfAudioTrackMatches = true; - RequirePerfectMatch = true; - } - - public bool SkipIfEmbeddedSubtitlesPresent { get; set; } - - public bool SkipIfAudioTrackMatches { get; set; } - - public string[] DownloadLanguages { get; set; } - - public bool DownloadMovieSubtitles { get; set; } - - public bool DownloadEpisodeSubtitles { get; set; } - - public string OpenSubtitlesUsername { get; set; } - - public string OpenSubtitlesPasswordHash { get; set; } - - public bool IsOpenSubtitleVipAccount { get; set; } - - public bool RequirePerfectMatch { get; set; } - } -} diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index bde23e842f..1512737d07 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; using Jellyfin.Extensions; -using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -25,7 +24,6 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Providers; using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.MediaInfo @@ -74,7 +72,6 @@ namespace MediaBrowser.Providers.MediaInfo _subtitleResolver = subtitleResolver; _mediaAttachmentRepository = mediaAttachmentRepository; _mediaStreamRepository = mediaStreamRepository; - _mediaStreamRepository = mediaStreamRepository; } public async Task ProbeVideo( @@ -549,47 +546,19 @@ namespace MediaBrowser.Providers.MediaInfo var enableSubtitleDownloading = options.MetadataRefreshMode == MetadataRefreshMode.Default || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh; - var subtitleOptions = _config.GetConfiguration("subtitles"); - var libraryOptions = _libraryManager.GetLibraryOptions(video); - string[] subtitleDownloadLanguages; - bool skipIfEmbeddedSubtitlesPresent; - bool skipIfAudioTrackMatches; - bool requirePerfectMatch; - bool enabled; - - if (libraryOptions.SubtitleDownloadLanguages is null) - { - subtitleDownloadLanguages = subtitleOptions.DownloadLanguages; - skipIfEmbeddedSubtitlesPresent = subtitleOptions.SkipIfEmbeddedSubtitlesPresent; - skipIfAudioTrackMatches = subtitleOptions.SkipIfAudioTrackMatches; - requirePerfectMatch = subtitleOptions.RequirePerfectMatch; - enabled = (subtitleOptions.DownloadEpisodeSubtitles && - video is Episode) || - (subtitleOptions.DownloadMovieSubtitles && - video is Movie); - } - else - { - subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages; - skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent; - skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches; - requirePerfectMatch = libraryOptions.RequirePerfectSubtitleMatch; - enabled = true; - } - - if (enableSubtitleDownloading && enabled) + if (enableSubtitleDownloading && libraryOptions.SubtitleDownloadLanguages is not null) { var downloadedLanguages = await new SubtitleDownloader( _logger, _subtitleManager).DownloadSubtitles( video, currentStreams.Concat(externalSubtitleStreams).ToList(), - skipIfEmbeddedSubtitlesPresent, - skipIfAudioTrackMatches, - requirePerfectMatch, - subtitleDownloadLanguages, + libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent, + libraryOptions.SkipSubtitlesIfAudioTrackMatches, + libraryOptions.RequirePerfectSubtitleMatch, + libraryOptions.SubtitleDownloadLanguages, libraryOptions.DisabledSubtitleFetchers, libraryOptions.SubtitleFetcherOrder, true, diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs index 1134baf92d..7188e9804e 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs @@ -8,14 +8,12 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; -using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Providers; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; @@ -57,16 +55,9 @@ namespace MediaBrowser.Providers.MediaInfo public bool IsLogged => true; - private SubtitleOptions GetOptions() - { - return _config.GetConfiguration("subtitles"); - } - /// public async Task ExecuteAsync(IProgress progress, CancellationToken cancellationToken) { - var options = GetOptions(); - var types = new[] { BaseItemKind.Episode, BaseItemKind.Movie }; var dict = new Dictionary(); @@ -81,17 +72,14 @@ namespace MediaBrowser.Providers.MediaInfo if (libraryOptions.SubtitleDownloadLanguages is null) { - subtitleDownloadLanguages = options.DownloadLanguages; - skipIfEmbeddedSubtitlesPresent = options.SkipIfEmbeddedSubtitlesPresent; - skipIfAudioTrackMatches = options.SkipIfAudioTrackMatches; - } - else - { - subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages; - skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent; - skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches; + // Skip this library if subtitle download languages are not configured + continue; } + subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages; + skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent; + skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches; + foreach (var lang in subtitleDownloadLanguages) { var query = new InternalItemsQuery @@ -144,7 +132,7 @@ namespace MediaBrowser.Providers.MediaInfo try { - await DownloadSubtitles(video as Video, options, cancellationToken).ConfigureAwait(false); + await DownloadSubtitles(video as Video, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -160,7 +148,7 @@ namespace MediaBrowser.Providers.MediaInfo } } - private async Task DownloadSubtitles(Video video, SubtitleOptions options, CancellationToken cancellationToken) + private async Task DownloadSubtitles(Video video, CancellationToken cancellationToken) { var mediaStreams = video.GetMediaStreams(); @@ -173,19 +161,15 @@ namespace MediaBrowser.Providers.MediaInfo if (libraryOptions.SubtitleDownloadLanguages is null) { - subtitleDownloadLanguages = options.DownloadLanguages; - skipIfEmbeddedSubtitlesPresent = options.SkipIfEmbeddedSubtitlesPresent; - skipIfAudioTrackMatches = options.SkipIfAudioTrackMatches; - requirePerfectMatch = options.RequirePerfectMatch; - } - else - { - subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages; - skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent; - skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches; - requirePerfectMatch = libraryOptions.RequirePerfectSubtitleMatch; + // Subtitle downloading is not configured for this library + return true; } + subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages; + skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent; + skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches; + requirePerfectMatch = libraryOptions.RequirePerfectSubtitleMatch; + var downloadedLanguages = await new SubtitleDownloader( _logger, _subtitleManager).DownloadSubtitles( From 73fd6721f62056bfaabd43b75d286c140a353657 Mon Sep 17 00:00:00 2001 From: MBR#0001 Date: Sat, 22 Nov 2025 17:39:43 +0100 Subject: [PATCH 02/24] Skip library if all subtitle providers are disabled --- .../MediaInfo/SubtitleScheduledTask.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs index 7188e9804e..8073919182 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs @@ -12,6 +12,7 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Tasks; @@ -26,19 +27,24 @@ namespace MediaBrowser.Providers.MediaInfo private readonly ISubtitleManager _subtitleManager; private readonly ILogger _logger; private readonly ILocalizationManager _localization; + private readonly ISubtitleProvider[] _subtitleProviders; public SubtitleScheduledTask( ILibraryManager libraryManager, IServerConfigurationManager config, ISubtitleManager subtitleManager, ILogger logger, - ILocalizationManager localization) + ILocalizationManager localization, + IEnumerable subtitleProviders) { _libraryManager = libraryManager; _config = config; _subtitleManager = subtitleManager; _logger = logger; _localization = localization; + _subtitleProviders = subtitleProviders + .OrderBy(i => i is IHasOrder hasOrder ? hasOrder.Order : 0) + .ToArray(); } public string Name => _localization.GetLocalizedString("TaskDownloadMissingSubtitles"); @@ -76,6 +82,12 @@ namespace MediaBrowser.Providers.MediaInfo continue; } + if (_subtitleProviders.All(provider => libraryOptions.DisabledSubtitleFetchers.Contains(provider.Name))) + { + // Skip this library if all subtitle providers are disabled + continue; + } + subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages; skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent; skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches; From 37d6101f022a943f3c6bbb09702c528aaf47767e Mon Sep 17 00:00:00 2001 From: Masood Date: Wed, 10 Dec 2025 18:11:03 +0530 Subject: [PATCH 03/24] Fix watched status resetting on re-watch --- Emby.Server.Implementations/Session/SessionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index cf2ca047cf..0a1a59f775 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -822,7 +822,7 @@ namespace Emby.Server.Implementations.Session { data.Played = true; } - else + else if (!data.Played) { data.Played = false; } From d757e12e1a47bcf59ce992a3db4dd321aa888ee8 Mon Sep 17 00:00:00 2001 From: Masood Date: Wed, 10 Dec 2025 18:26:23 +0530 Subject: [PATCH 04/24] Update CONTRIBUTORS.md --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 0a4114478f..235dc94ac8 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -281,3 +281,4 @@ - [Martin Reuter](https://github.com/reuterma24) - [Michael McElroy](https://github.com/mcmcelro) - [Soumyadip Auddy](https://github.com/SoumyadipAuddy) + - [MSalman5230](https://github.com/MSalman5230) From 113bd9af05864f300725ceb70123402cbf7a4ac7 Mon Sep 17 00:00:00 2001 From: Masood Date: Wed, 10 Dec 2025 18:50:20 +0530 Subject: [PATCH 05/24] Remove redundant assignment in playback start logic --- Emby.Server.Implementations/Session/SessionManager.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 0a1a59f775..d6880d7864 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -822,10 +822,6 @@ namespace Emby.Server.Implementations.Session { data.Played = true; } - else if (!data.Played) - { - data.Played = false; - } _userDataManager.SaveUserData(user, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None); } From d1f242bc097b1530de27d5e74f303ff06096c294 Mon Sep 17 00:00:00 2001 From: Masood Date: Wed, 10 Dec 2025 19:08:54 +0530 Subject: [PATCH 06/24] Update CONTRIBUTORS.md --- CONTRIBUTORS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 235dc94ac8..c499780274 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -205,6 +205,7 @@ - [theshoeshiner](https://github.com/theshoeshiner) - [TokerX](https://github.com/TokerX) - [GeneMarks](https://github.com/GeneMarks) + - [MSalman5230](https://github.com/MSalman5230) # Emby Contributors @@ -281,4 +282,4 @@ - [Martin Reuter](https://github.com/reuterma24) - [Michael McElroy](https://github.com/mcmcelro) - [Soumyadip Auddy](https://github.com/SoumyadipAuddy) - - [MSalman5230](https://github.com/MSalman5230) + From d4a46bc6291560b35a9b64fb88b68019f903d0ef Mon Sep 17 00:00:00 2001 From: MBR-0001 <55142207+MBR-0001@users.noreply.github.com> Date: Thu, 16 Apr 2026 22:32:14 +0200 Subject: [PATCH 07/24] Fix comparison --- MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs index 8073919182..f1582febf2 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Providers.MediaInfo continue; } - if (_subtitleProviders.All(provider => libraryOptions.DisabledSubtitleFetchers.Contains(provider.Name))) + if (_subtitleProviders.All(provider => libraryOptions.DisabledSubtitleFetchers.Contains(provider.Name, StringComparer.OrdinalIgnoreCase))) { // Skip this library if all subtitle providers are disabled continue; From 48b0029180d37cf20626ea2c19622db0d2b63278 Mon Sep 17 00:00:00 2001 From: Sebas Koetsier Date: Sat, 18 Apr 2026 15:38:17 +0200 Subject: [PATCH 08/24] fix: add image/jpg to MIME type extension lookup Although image/jpg is not a registered MIME type (RFC 2046 specifies image/jpeg), several external providers return image/jpg as the Content-Type for JPEG images: - TMDb API (thumbnail/episode images) - Schedules Direct EPG - Various other metadata providers Without this mapping, Jellyfin throws ArgumentException: 'Unable to determine image file extension from mime type image/jpg' This causes library scans to fail when saving episode thumbnails and other images from these providers, leading to repeated scan failures and cancelled library scans. PR #7052 previously added this but it was lost during the migration to FrozenDictionary. Issue #13568 reports the same bug in 10.10+. Fixes: jellyfin/jellyfin#13568 Related: jellyfin/jellyfin#7050, jellyfin/jellyfin#7052 --- MediaBrowser.Model/Net/MimeTypes.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs index 79f8675cbf..c0d1bc86e7 100644 --- a/MediaBrowser.Model/Net/MimeTypes.cs +++ b/MediaBrowser.Model/Net/MimeTypes.cs @@ -132,6 +132,7 @@ namespace MediaBrowser.Model.Net // Type image new("image/jpeg", ".jpg"), + new("image/jpg", ".jpg"), new("image/tiff", ".tiff"), new("image/x-png", ".png"), new("image/x-icon", ".ico"), From bd70e0ca343c334c03140e66f6c4b9df384187b7 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sun, 19 Apr 2026 18:41:39 +0200 Subject: [PATCH 09/24] Upgrade to xunit v3 --- Directory.Packages.props | 11 ++++----- .../Controllers/UserControllerTests.cs | 2 +- .../Jellyfin.Api.Tests.csproj | 5 ++-- .../Jellyfin.Common.Tests.csproj | 5 ++-- .../Jellyfin.Controller.Tests.csproj | 3 ++- .../Jellyfin.Extensions.Tests.csproj | 8 +++++-- .../Jellyfin.LiveTv.Tests.csproj | 4 ++-- .../Jellyfin.MediaEncoding.Hls.Tests.csproj | 6 ++++- ...lyfin.MediaEncoding.Keyframes.Tests.csproj | 6 ++++- .../Jellyfin.MediaEncoding.Tests.csproj | 5 ++-- .../Jellyfin.Model.Tests.csproj | 8 +++++-- .../Jellyfin.Naming.Tests.csproj | 3 ++- .../Jellyfin.Networking.Tests.csproj | 5 ++-- .../Jellyfin.Providers.Tests.csproj | 8 +++++-- .../IO/ManagedFileSystemTests.cs | 16 ++++++------- ...llyfin.Server.Implementations.Tests.csproj | 4 ++-- .../Plugins/PluginManagerTests.cs | 14 +++++------ .../Updates/InstallationManagerTests.cs | 9 ++++--- .../Controllers/ActivityLogControllerTests.cs | 2 +- .../Controllers/BrandingControllerTests.cs | 6 ++--- .../Controllers/DashboardControllerTests.cs | 16 ++++++------- .../Controllers/ItemsControllerTests.cs | 8 +++---- .../Controllers/LibraryControllerTests.cs | 6 ++--- .../LibraryStructureControllerTests.cs | 24 +++++++++---------- .../Controllers/LiveTvControllerTests.cs | 10 ++++---- .../Controllers/MediaInfoControllerTests.cs | 6 ++--- .../MediaStructureControllerTests.cs | 14 +++++------ .../Controllers/MusicGenreControllerTests.cs | 2 +- .../Controllers/PersonsControllerTests.cs | 2 +- .../Controllers/PlaystateControllerTests.cs | 8 +++---- .../Controllers/PluginsControllerTests.cs | 6 ++--- .../Controllers/StartupControllerTests.cs | 24 +++++++++---------- .../Controllers/UserControllerTests.cs | 16 ++++++------- .../Controllers/UserLibraryControllerTests.cs | 18 +++++++------- .../Controllers/VideosControllerTests.cs | 2 +- .../EncodedQueryStringTest.cs | 8 +++---- .../Jellyfin.Server.Integration.Tests.csproj | 10 +++++--- .../RobotsRedirectionMiddlewareTests.cs | 2 +- .../OpenApiSpecTests.cs | 5 ++-- .../Jellyfin.Server.Tests.csproj | 8 +++++-- .../Jellyfin.XbmcMetadata.Tests.csproj | 6 ++++- 41 files changed, 185 insertions(+), 146 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 68f89a0580..037db81b00 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,7 +6,7 @@ - + @@ -17,7 +17,7 @@ - + @@ -82,9 +82,8 @@ - - - - + + + diff --git a/tests/Jellyfin.Api.Tests/Controllers/UserControllerTests.cs b/tests/Jellyfin.Api.Tests/Controllers/UserControllerTests.cs index e95df16354..60ed740609 100644 --- a/tests/Jellyfin.Api.Tests/Controllers/UserControllerTests.cs +++ b/tests/Jellyfin.Api.Tests/Controllers/UserControllerTests.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; -using AutoFixture.Xunit2; +using AutoFixture.Xunit3; using Jellyfin.Api.Controllers; using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Common.Net; diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 6b84c4438f..253eab9d79 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -3,15 +3,16 @@ {A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D} + Exe - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index 8fef7fde05..f01d522e11 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -3,17 +3,18 @@ {DF194677-DFD3-42AF-9F75-D44D5A416478} + Exe - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj index 54d93b48cf..7db94f9c81 100644 --- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj +++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj @@ -3,12 +3,13 @@ {462584F7-5023-4019-9EAC-B98CA458C0A0} + Exe - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj index 0364898298..6921fc8a97 100644 --- a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj +++ b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj @@ -1,8 +1,12 @@ + + Exe + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -11,7 +15,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/tests/Jellyfin.LiveTv.Tests/Jellyfin.LiveTv.Tests.csproj b/tests/Jellyfin.LiveTv.Tests/Jellyfin.LiveTv.Tests.csproj index bdf6bc383a..a9b19e0104 100644 --- a/tests/Jellyfin.LiveTv.Tests/Jellyfin.LiveTv.Tests.csproj +++ b/tests/Jellyfin.LiveTv.Tests/Jellyfin.LiveTv.Tests.csproj @@ -1,6 +1,7 @@ net10.0 + Exe @@ -14,12 +15,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - 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 eab003715c..47a116ee42 100644 --- a/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Hls.Tests/Jellyfin.MediaEncoding.Hls.Tests.csproj @@ -1,8 +1,12 @@ + + Exe + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all 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 894bec6aa5..9a58c697f0 100644 --- a/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Keyframes.Tests/Jellyfin.MediaEncoding.Keyframes.Tests.csproj @@ -1,8 +1,12 @@ + + Exe + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj index 6b703e7416..c7065c670a 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -3,6 +3,7 @@ {28464062-0939-4AA7-9F7B-24DDDA61A7C0} + Exe @@ -14,11 +15,11 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj index 8345b610e5..9e2a9a8873 100644 --- a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj +++ b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj @@ -1,15 +1,19 @@ + + Exe + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj index 7c26494487..1f3e42077f 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -3,12 +3,13 @@ {3998657B-1CCC-49DD-A19F-275DC8495F57} + Exe - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj index 2d7f112109..09ba120a5e 100644 --- a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj +++ b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj @@ -3,17 +3,18 @@ {42816EA8-4511-4CBF-A9C7-7791D5DDDAE6} + Exe - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj index 1263043a51..990544b5a8 100644 --- a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj +++ b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj @@ -1,5 +1,9 @@ + + Exe + + PreserveNewest @@ -9,10 +13,10 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs b/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs index 6997b51ac8..c06279af2d 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs @@ -25,12 +25,12 @@ public class ManagedFileSystemTests public void MoveDirectory_SameFileSystem_Correct() => MoveDirectoryInternal(); - [SkippableFact] + [Fact] public void MoveDirectory_DifferentFileSystem_Correct() { const string DestinationParent = "/dev/shm"; - Skip.IfNot(Directory.Exists(DestinationParent)); + Assert.SkipUnless(Directory.Exists(DestinationParent), $"{DestinationParent} is not available"); MoveDirectoryInternal(DestinationParent); } @@ -57,7 +57,7 @@ public class ManagedFileSystemTests Directory.Delete(destinationDir, true); } - [SkippableTheory] + [Theory] [InlineData("/Volumes/Library/Sample/Music/Playlists/", "../Beethoven/Misc/Moonlight Sonata.mp3", "/Volumes/Library/Sample/Music/Beethoven/Misc/Moonlight Sonata.mp3")] [InlineData("/Volumes/Library/Sample/Music/Playlists/", "../../Beethoven/Misc/Moonlight Sonata.mp3", "/Volumes/Library/Sample/Beethoven/Misc/Moonlight Sonata.mp3")] [InlineData("/Volumes/Library/Sample/Music/Playlists/", "Beethoven/Misc/Moonlight Sonata.mp3", "/Volumes/Library/Sample/Music/Playlists/Beethoven/Misc/Moonlight Sonata.mp3")] @@ -67,13 +67,13 @@ public class ManagedFileSystemTests string filePath, string expectedAbsolutePath) { - Skip.If(OperatingSystem.IsWindows()); + Assert.SkipWhen(OperatingSystem.IsWindows(), "Unix-only test"); var generatedPath = _sut.MakeAbsolutePath(folderPath, filePath); Assert.Equal(expectedAbsolutePath, generatedPath); } - [SkippableTheory] + [Theory] [InlineData(@"C:\\Volumes\Library\Sample\Music\Playlists\", @"..\Beethoven\Misc\Moonlight Sonata.mp3", @"C:\Volumes\Library\Sample\Music\Beethoven\Misc\Moonlight Sonata.mp3")] [InlineData(@"C:\\Volumes\Library\Sample\Music\Playlists\", @"..\..\Beethoven\Misc\Moonlight Sonata.mp3", @"C:\Volumes\Library\Sample\Beethoven\Misc\Moonlight Sonata.mp3")] [InlineData(@"C:\\Volumes\Library\Sample\Music\Playlists\", @"Beethoven\Misc\Moonlight Sonata.mp3", @"C:\Volumes\Library\Sample\Music\Playlists\Beethoven\Misc\Moonlight Sonata.mp3")] @@ -83,7 +83,7 @@ public class ManagedFileSystemTests string filePath, string expectedAbsolutePath) { - Skip.IfNot(OperatingSystem.IsWindows()); + Assert.SkipUnless(OperatingSystem.IsWindows(), "Windows-only test"); var generatedPath = _sut.MakeAbsolutePath(folderPath, filePath); @@ -100,10 +100,10 @@ public class ManagedFileSystemTests Assert.Equal(expectedFileName, _sut.GetValidFilename(filename)); } - [SkippableFact] + [Fact] public void GetFileInfo_DanglingSymlink_ExistsFalse() { - Skip.If(OperatingSystem.IsWindows()); + Assert.SkipWhen(OperatingSystem.IsWindows(), "Unix-only test"); string testFileDir = Path.Combine(Path.GetTempPath(), "jellyfin-test-data"); string testFileName = Path.Combine(testFileDir, Path.GetRandomFileName() + "-danglingsym.link"); 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 4e2604e6e1..958ffb8b6e 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -3,6 +3,7 @@ {2E3A1B4B-4225-4AAA-8B29-0181A84E7AEE} + Exe @@ -16,12 +17,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs index 3d8ea15a31..ede9e61536 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Plugins/PluginManagerTests.cs @@ -192,13 +192,13 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins }; var metafilePath = Path.Combine(_pluginPath, "meta.json"); - await File.WriteAllTextAsync(metafilePath, JsonSerializer.Serialize(partial, _options)); + await File.WriteAllTextAsync(metafilePath, JsonSerializer.Serialize(partial, _options), TestContext.Current.CancellationToken); var pluginManager = new PluginManager(new NullLogger(), null!, null!, _tempPath, new Version(1, 0)); await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active); - var resultBytes = await File.ReadAllBytesAsync(metafilePath); + var resultBytes = await File.ReadAllBytesAsync(metafilePath, TestContext.Current.CancellationToken); var result = JsonSerializer.Deserialize(resultBytes, _options); Assert.NotNull(result); @@ -232,7 +232,7 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active); var metafilePath = Path.Combine(_pluginPath, "meta.json"); - var resultBytes = await File.ReadAllBytesAsync(metafilePath); + var resultBytes = await File.ReadAllBytesAsync(metafilePath, TestContext.Current.CancellationToken); var result = JsonSerializer.Deserialize(resultBytes, _options); Assert.NotNull(result); @@ -252,13 +252,13 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins }; var metafilePath = Path.Combine(_pluginPath, "meta.json"); - await File.WriteAllTextAsync(metafilePath, JsonSerializer.Serialize(partial, _options)); + await File.WriteAllTextAsync(metafilePath, JsonSerializer.Serialize(partial, _options), TestContext.Current.CancellationToken); var pluginManager = new PluginManager(new NullLogger(), null!, null!, _tempPath, new Version(1, 0)); await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active); - var resultBytes = await File.ReadAllBytesAsync(metafilePath); + var resultBytes = await File.ReadAllBytesAsync(metafilePath, TestContext.Current.CancellationToken); var result = JsonSerializer.Deserialize(resultBytes, _options); Assert.NotNull(result); @@ -278,13 +278,13 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins }; var metafilePath = Path.Combine(_pluginPath, "meta.json"); - await File.WriteAllTextAsync(metafilePath, JsonSerializer.Serialize(partial, _options)); + await File.WriteAllTextAsync(metafilePath, JsonSerializer.Serialize(partial, _options), TestContext.Current.CancellationToken); var pluginManager = new PluginManager(new NullLogger(), null!, null!, _tempPath, new Version(1, 0)); await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active); - var resultBytes = await File.ReadAllBytesAsync(metafilePath); + var resultBytes = await File.ReadAllBytesAsync(metafilePath, TestContext.Current.CancellationToken); var result = JsonSerializer.Deserialize(resultBytes, _options); Assert.NotNull(result); diff --git a/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs index f58a3276ba..92e10c9f92 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Updates/InstallationManagerTests.cs @@ -51,7 +51,8 @@ namespace Jellyfin.Server.Implementations.Tests.Updates PackageInfo[] packages = await _installationManager.GetPackages( "Jellyfin Stable", "https://repo.jellyfin.org/files/plugin/manifest.json", - false); + false, + TestContext.Current.CancellationToken); Assert.Equal(25, packages.Length); } @@ -62,7 +63,8 @@ namespace Jellyfin.Server.Implementations.Tests.Updates PackageInfo[] packages = await _installationManager.GetPackages( "Jellyfin Stable", "https://repo.jellyfin.org/files/plugin/manifest.json", - false); + false, + TestContext.Current.CancellationToken); packages = _installationManager.FilterPackages(packages, "Anime").ToArray(); Assert.Single(packages); @@ -74,7 +76,8 @@ namespace Jellyfin.Server.Implementations.Tests.Updates PackageInfo[] packages = await _installationManager.GetPackages( "Jellyfin Stable", "https://repo.jellyfin.org/files/plugin/manifest.json", - false); + false, + TestContext.Current.CancellationToken); packages = _installationManager.FilterPackages(packages, id: new Guid("a4df60c5-6ab4-412a-8f79-2cab93fb2bc5")).ToArray(); Assert.Single(packages); diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/ActivityLogControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/ActivityLogControllerTests.cs index 96ca96558d..ef084430e8 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/ActivityLogControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/ActivityLogControllerTests.cs @@ -21,7 +21,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers var client = _factory.CreateClient(); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); - var response = await client.GetAsync("System/ActivityLog/Entries"); + var response = await client.GetAsync("System/ActivityLog/Entries", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType); diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/BrandingControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/BrandingControllerTests.cs index 8761cf69bc..1973af3f25 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/BrandingControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/BrandingControllerTests.cs @@ -25,13 +25,13 @@ namespace Jellyfin.Server.Integration.Tests var client = _factory.CreateClient(); // Act - var response = await client.GetAsync("/Branding/Configuration"); + var response = await client.GetAsync("/Branding/Configuration", TestContext.Current.CancellationToken); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType); Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet); - await response.Content.ReadFromJsonAsync(); + await response.Content.ReadFromJsonAsync(TestContext.Current.CancellationToken); } [Theory] @@ -43,7 +43,7 @@ namespace Jellyfin.Server.Integration.Tests var client = _factory.CreateClient(); // Act - var response = await client.GetAsync(url); + var response = await client.GetAsync(url, TestContext.Current.CancellationToken); // Assert Assert.True(response.IsSuccessStatusCode); diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs index d92dbbd732..32bdc57265 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/DashboardControllerTests.cs @@ -27,7 +27,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers { var client = _factory.CreateClient(); - var response = await client.GetAsync("web/ConfigurationPage?name=ThisPageDoesntExists"); + var response = await client.GetAsync("web/ConfigurationPage?name=ThisPageDoesntExists", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } @@ -37,12 +37,12 @@ namespace Jellyfin.Server.Integration.Tests.Controllers { var client = _factory.CreateClient(); - var response = await client.GetAsync("/web/ConfigurationPage?name=TestPlugin"); + var response = await client.GetAsync("/web/ConfigurationPage?name=TestPlugin", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(MediaTypeNames.Text.Html, response.Content.Headers.ContentType?.MediaType); StreamReader reader = new StreamReader(typeof(TestPlugin).Assembly.GetManifestResourceStream("Jellyfin.Server.Integration.Tests.TestPage.html")!); - Assert.Equal(await response.Content.ReadAsStringAsync(), await reader.ReadToEndAsync()); + Assert.Equal(await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken), await reader.ReadToEndAsync(TestContext.Current.CancellationToken)); } [Fact] @@ -50,7 +50,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers { var client = _factory.CreateClient(); - var response = await client.GetAsync("/web/ConfigurationPage?name=BrokenPage"); + var response = await client.GetAsync("/web/ConfigurationPage?name=BrokenPage", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } @@ -61,11 +61,11 @@ namespace Jellyfin.Server.Integration.Tests.Controllers var client = _factory.CreateClient(); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); - var response = await client.GetAsync("/web/ConfigurationPages"); + var response = await client.GetAsync("/web/ConfigurationPages", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - _ = await response.Content.ReadFromJsonAsync(_jsonOptions); + _ = await response.Content.ReadFromJsonAsync(_jsonOptions, TestContext.Current.CancellationToken); // TODO: check content } @@ -75,13 +75,13 @@ namespace Jellyfin.Server.Integration.Tests.Controllers var client = _factory.CreateClient(); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); - var response = await client.GetAsync("/web/ConfigurationPages?enableInMainMenu=true"); + var response = await client.GetAsync("/web/ConfigurationPages?enableInMainMenu=true", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType); Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet); - var data = await response.Content.ReadFromJsonAsync(_jsonOptions); + var data = await response.Content.ReadFromJsonAsync(_jsonOptions, TestContext.Current.CancellationToken); Assert.NotNull(data); Assert.Empty(data); } diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/ItemsControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/ItemsControllerTests.cs index 64b9bd8e16..165e269814 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/ItemsControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/ItemsControllerTests.cs @@ -28,7 +28,7 @@ public sealed class ItemsControllerTests : IClassFixture>(_jsonOptions); + var items = await response.Content.ReadFromJsonAsync>(_jsonOptions, TestContext.Current.CancellationToken); Assert.NotNull(items); } } diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryControllerTests.cs index 6881a92101..edbb46b34c 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/LibraryControllerTests.cs @@ -34,7 +34,7 @@ public sealed class LibraryControllerTests : IClassFixture { private readonly JellyfinApplicationFactory _factory; @@ -40,7 +40,7 @@ public sealed class LibraryStructureControllerTests : IClassFixture(_jsonOptions) - .FirstOrDefaultAsync(x => string.Equals(x?.Name, "test", StringComparison.Ordinal)); + var library = await response.Content.ReadFromJsonAsAsyncEnumerable(_jsonOptions, TestContext.Current.CancellationToken) + .FirstOrDefaultAsync(x => string.Equals(x?.Name, "test", StringComparison.Ordinal), TestContext.Current.CancellationToken); Assert.NotNull(library); var options = library.LibraryOptions; @@ -99,7 +99,7 @@ public sealed class LibraryStructureControllerTests : IClassFixture(); + var responseBody = await response.Content.ReadFromJsonAsync(TestContext.Current.CancellationToken); Assert.NotNull(responseBody); Assert.Equal(body.Type, responseBody.Type); Assert.Equal(body.Url, responseBody.Url); @@ -72,7 +72,7 @@ public sealed class LiveTvControllerTests : IClassFixture()); - var response = await client.PostAsync("Library/VirtualFolders/Name?name=test&newName=+", postContent); + var response = await client.PostAsync("Library/VirtualFolders/Name?name=test&newName=+", postContent, TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } @@ -53,7 +53,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); using var postContent = new ByteArrayContent(Array.Empty()); - var response = await client.PostAsync("Library/VirtualFolders/Name?name=doesnt+exist&newName=test", postContent); + var response = await client.PostAsync("Library/VirtualFolders/Name?name=doesnt+exist&newName=test", postContent, TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } @@ -70,7 +70,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers Path = "/this/path/doesnt/exist" }; - var response = await client.PostAsJsonAsync("Library/VirtualFolders/Paths", data, _jsonOptions); + var response = await client.PostAsJsonAsync("Library/VirtualFolders/Paths", data, _jsonOptions, TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } @@ -87,7 +87,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers PathInfo = new MediaPathInfo("test") }; - var response = await client.PostAsJsonAsync("Library/VirtualFolders/Paths/Update", data, _jsonOptions); + var response = await client.PostAsJsonAsync("Library/VirtualFolders/Paths/Update", data, _jsonOptions, TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } @@ -98,7 +98,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers var client = _factory.CreateClient(); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); - var response = await client.DeleteAsync("Library/VirtualFolders/Paths?name=+"); + var response = await client.DeleteAsync("Library/VirtualFolders/Paths?name=+", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } @@ -109,7 +109,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers var client = _factory.CreateClient(); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); - var response = await client.DeleteAsync("Library/VirtualFolders/Paths?name=none&path=%2Fthis%2Fpath%2Fdoesnt%2Fexist"); + var response = await client.DeleteAsync("Library/VirtualFolders/Paths?name=none&path=%2Fthis%2Fpath%2Fdoesnt%2Fexist", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/MusicGenreControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/MusicGenreControllerTests.cs index f9982cf12b..3e14850613 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/MusicGenreControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/MusicGenreControllerTests.cs @@ -20,7 +20,7 @@ public sealed class MusicGenreControllerTests : IClassFixture var client = _factory.CreateClient(); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); - using var response = await client.GetAsync($"Persons/DoesntExist"); + using var response = await client.GetAsync($"Persons/DoesntExist", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } } diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/PlaystateControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/PlaystateControllerTests.cs index 3b9ed17787..db271fc5cd 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/PlaystateControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/PlaystateControllerTests.cs @@ -21,7 +21,7 @@ public class PlaystateControllerTests : IClassFixture(JsonDefaults.Options); + _ = await response.Content.ReadFromJsonAsync(JsonDefaults.Options, TestContext.Current.CancellationToken); } } diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs index c8ae2a88af..0e5d81a4d6 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/StartupControllerTests.cs @@ -8,11 +8,11 @@ using System.Threading.Tasks; using Jellyfin.Api.Models.StartupDtos; using Jellyfin.Extensions.Json; using Xunit; -using Xunit.Priority; +using Xunit.v3.Priority; namespace Jellyfin.Server.Integration.Tests.Controllers { - [TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)] + [TestCaseOrderer(typeof(PriorityOrderer))] public sealed class StartupControllerTests : IClassFixture { private readonly JellyfinApplicationFactory _factory; @@ -37,14 +37,14 @@ namespace Jellyfin.Server.Integration.Tests.Controllers PreferredMetadataLanguage = "nl" }; - using var postResponse = await client.PostAsJsonAsync("/Startup/Configuration", config, _jsonOptions); + using var postResponse = await client.PostAsJsonAsync("/Startup/Configuration", config, _jsonOptions, TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NoContent, postResponse.StatusCode); - using var getResponse = await client.GetAsync("/Startup/Configuration"); + using var getResponse = await client.GetAsync("/Startup/Configuration", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode); Assert.Equal(MediaTypeNames.Application.Json, getResponse.Content.Headers.ContentType?.MediaType); - var newConfig = await getResponse.Content.ReadFromJsonAsync(_jsonOptions); + var newConfig = await getResponse.Content.ReadFromJsonAsync(_jsonOptions, TestContext.Current.CancellationToken); Assert.Equal(config.ServerName, newConfig!.ServerName); Assert.Equal(config.UICulture, newConfig.UICulture); Assert.Equal(config.MetadataCountryCode, newConfig.MetadataCountryCode); @@ -57,11 +57,11 @@ namespace Jellyfin.Server.Integration.Tests.Controllers { var client = _factory.CreateClient(); - using var response = await client.GetAsync("/Startup/User"); + using var response = await client.GetAsync("/Startup/User", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType); - var user = await response.Content.ReadFromJsonAsync(_jsonOptions); + var user = await response.Content.ReadFromJsonAsync(_jsonOptions, TestContext.Current.CancellationToken); Assert.NotNull(user); Assert.NotNull(user.Name); Assert.NotEmpty(user.Name); @@ -80,14 +80,14 @@ namespace Jellyfin.Server.Integration.Tests.Controllers Password = "NewPassword" }; - var postResponse = await client.PostAsJsonAsync("/Startup/User", user, _jsonOptions); + var postResponse = await client.PostAsJsonAsync("/Startup/User", user, _jsonOptions, TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NoContent, postResponse.StatusCode); - var getResponse = await client.GetAsync("/Startup/User"); + var getResponse = await client.GetAsync("/Startup/User", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode); Assert.Equal(MediaTypeNames.Application.Json, getResponse.Content.Headers.ContentType?.MediaType); - var newUser = await getResponse.Content.ReadFromJsonAsync(_jsonOptions); + var newUser = await getResponse.Content.ReadFromJsonAsync(_jsonOptions, TestContext.Current.CancellationToken); Assert.NotNull(newUser); Assert.Equal(user.Name, newUser.Name); Assert.Null(newUser.Password); @@ -99,7 +99,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers { var client = _factory.CreateClient(); - var response = await client.PostAsync("/Startup/Complete", new ByteArrayContent(Array.Empty())); + var response = await client.PostAsync("/Startup/Complete", new ByteArrayContent(Array.Empty()), TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); } @@ -109,7 +109,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers { var client = _factory.CreateClient(); - using var response = await client.GetAsync("/Startup/User"); + using var response = await client.GetAsync("/Startup/User", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); } } diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs index 04d1b3dc27..7ea56be731 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserControllerTests.cs @@ -10,11 +10,11 @@ using Jellyfin.Api.Models.UserDtos; using Jellyfin.Extensions.Json; using MediaBrowser.Model.Dto; using Xunit; -using Xunit.Priority; +using Xunit.v3.Priority; namespace Jellyfin.Server.Integration.Tests.Controllers { - [TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)] + [TestCaseOrderer(typeof(PriorityOrderer))] public sealed class UserControllerTests : IClassFixture { private const string TestUsername = "testUser01"; @@ -41,9 +41,9 @@ namespace Jellyfin.Server.Integration.Tests.Controllers { var client = _factory.CreateClient(); - using var response = await client.GetAsync("Users/Public"); + using var response = await client.GetAsync("Users/Public", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - var users = await response.Content.ReadFromJsonAsync(_jsonOptions); + var users = await response.Content.ReadFromJsonAsync(_jsonOptions, TestContext.Current.CancellationToken); // User are hidden by default Assert.NotNull(users); Assert.Empty(users); @@ -56,9 +56,9 @@ namespace Jellyfin.Server.Integration.Tests.Controllers var client = _factory.CreateClient(); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client)); - using var response = await client.GetAsync("Users"); + using var response = await client.GetAsync("Users", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - var users = await response.Content.ReadFromJsonAsync(_jsonOptions); + var users = await response.Content.ReadFromJsonAsync(_jsonOptions, TestContext.Current.CancellationToken); Assert.NotNull(users); Assert.Single(users); } @@ -89,7 +89,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers using var response = await CreateUserByName(client, createRequest); Assert.Equal(HttpStatusCode.OK, response.StatusCode); - var user = await response.Content.ReadFromJsonAsync(_jsonOptions); + var user = await response.Content.ReadFromJsonAsync(_jsonOptions, TestContext.Current.CancellationToken); Assert.Equal(TestUsername, user!.Name); _testUserId = user.Id; @@ -128,7 +128,7 @@ namespace Jellyfin.Server.Integration.Tests.Controllers // access token can't be null here as the previous test populated it client.DefaultRequestHeaders.AddAuthHeader(_accessToken!); - using var response = await client.DeleteAsync($"User/{Guid.NewGuid()}"); + using var response = await client.DeleteAsync($"User/{Guid.NewGuid()}", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserLibraryControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserLibraryControllerTests.cs index 98ad28f5bd..6e4fccd735 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/UserLibraryControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/UserLibraryControllerTests.cs @@ -28,7 +28,7 @@ public sealed class UserLibraryControllerTests : IClassFixture(_jsonOptions); + var rootDto = await response.Content.ReadFromJsonAsync(_jsonOptions, TestContext.Current.CancellationToken); Assert.NotNull(rootDto); } @@ -99,9 +99,9 @@ public sealed class UserLibraryControllerTests : IClassFixture>(_jsonOptions); + var rootDto = await response.Content.ReadFromJsonAsync>(_jsonOptions, TestContext.Current.CancellationToken); Assert.NotNull(rootDto); } @@ -116,9 +116,9 @@ public sealed class UserLibraryControllerTests : IClassFixture(_jsonOptions); + var rootDto = await response.Content.ReadFromJsonAsync(_jsonOptions, TestContext.Current.CancellationToken); Assert.NotNull(rootDto); } } diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/VideosControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/VideosControllerTests.cs index 1916ced12c..e0630ff443 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/VideosControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/VideosControllerTests.cs @@ -21,7 +21,7 @@ public sealed class VideosControllerTests : IClassFixture + + Exe + + - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/tests/Jellyfin.Server.Integration.Tests/Middleware/RobotsRedirectionMiddlewareTests.cs b/tests/Jellyfin.Server.Integration.Tests/Middleware/RobotsRedirectionMiddlewareTests.cs index 1ea79f7deb..baeaf4d0cb 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Middleware/RobotsRedirectionMiddlewareTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Middleware/RobotsRedirectionMiddlewareTests.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Server.Integration.Tests.Middleware AllowAutoRedirect = false }); - var response = await client.GetAsync("robots.txt"); + var response = await client.GetAsync("robots.txt", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); Assert.Equal("web/robots.txt", response.Headers.Location?.ToString()); diff --git a/tests/Jellyfin.Server.Integration.Tests/OpenApiSpecTests.cs b/tests/Jellyfin.Server.Integration.Tests/OpenApiSpecTests.cs index 62cdd25aec..17a8a55222 100644 --- a/tests/Jellyfin.Server.Integration.Tests/OpenApiSpecTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/OpenApiSpecTests.cs @@ -3,7 +3,6 @@ using System.Reflection; using System.Threading.Tasks; using MediaBrowser.Model.IO; using Xunit; -using Xunit.Abstractions; namespace Jellyfin.Server.Integration.Tests { @@ -25,7 +24,7 @@ namespace Jellyfin.Server.Integration.Tests var client = _factory.CreateClient(); // Act - var response = await client.GetAsync("/api-docs/openapi.json"); + var response = await client.GetAsync("/api-docs/openapi.json", TestContext.Current.CancellationToken); // Assert response.EnsureSuccessStatusCode(); @@ -35,7 +34,7 @@ namespace Jellyfin.Server.Integration.Tests string outputPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "openapi.json")); _outputHelper.WriteLine("Writing OpenAPI Spec JSON to '{0}'.", outputPath); await using var fs = AsyncFile.Create(outputPath); - await response.Content.CopyToAsync(fs); + await response.Content.CopyToAsync(fs, TestContext.Current.CancellationToken); } } } diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index 21596e0ed2..3ad5310c6b 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -1,12 +1,16 @@ + + Exe + + - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj index 9fe0744de1..3b39fe72d6 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj +++ b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj @@ -1,5 +1,9 @@ + + Exe + + PreserveNewest @@ -9,7 +13,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 0d6484b7ec6509779d5affe52127a214d64dc7f4 Mon Sep 17 00:00:00 2001 From: John Corser Date: Sun, 19 Apr 2026 13:32:06 -0400 Subject: [PATCH 10/24] Include item path in provider error log messages Fixes #16622 - Error messages like 'Error in Probe Provider' now include the media file path, making it easier to identify which file caused the failure. --- MediaBrowser.Providers/Manager/ItemImageProvider.cs | 4 ++-- MediaBrowser.Providers/Manager/MetadataService.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index e0354dbdfa..727f481b65 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -255,7 +255,7 @@ namespace MediaBrowser.Providers.Manager catch (Exception ex) { result.ErrorMessage = ex.Message; - _logger.LogError(ex, "Error in {Provider}", provider.Name); + _logger.LogError(ex, "Error in {Provider} for {Item}", provider.Name, item.Path ?? item.Name); } } @@ -339,7 +339,7 @@ namespace MediaBrowser.Providers.Manager catch (Exception ex) { result.ErrorMessage = ex.Message; - _logger.LogError(ex, "Error in {Provider}", provider.Name); + _logger.LogError(ex, "Error in {Provider} for {Item}", provider.Name, item.Path ?? item.Name); } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index e9cb46eab5..abdfb1e3b7 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -820,7 +820,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - Logger.LogError(ex, "Error in {Provider}", provider.Name); + Logger.LogError(ex, "Error in {Provider} for {Item}", provider.Name, logName); // If a local provider fails, consider that a failure refreshResult.ErrorMessage = ex.Message; @@ -886,7 +886,7 @@ namespace MediaBrowser.Providers.Manager catch (Exception ex) { refreshResult.ErrorMessage = ex.Message; - Logger.LogError(ex, "Error in {Provider}", provider.Name); + Logger.LogError(ex, "Error in {Provider} for {Item}", provider.Name, logName); } } @@ -935,7 +935,7 @@ namespace MediaBrowser.Providers.Manager { refreshResult.Failures++; refreshResult.ErrorMessage = ex.Message; - Logger.LogError(ex, "Error in {Provider}", provider.Name); + Logger.LogError(ex, "Error in {Provider} for {Item}", provider.Name, logName); } } From 2df0b9d8210fdf3e799a9444191b355c7ee4379a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 23:38:25 +0000 Subject: [PATCH 11/24] Update danielpalme/ReportGenerator-GitHub-Action action to v5.5.6 --- .github/workflows/ci-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 9fdcaedf97..81f218b893 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -35,7 +35,7 @@ jobs: --verbosity minimal - name: Merge code coverage results - uses: danielpalme/ReportGenerator-GitHub-Action@7ae927204961589fcb0b0be245c51fbbc87cbca2 # v5.5.5 + uses: danielpalme/ReportGenerator-GitHub-Action@ee3806a36b8b2eb9594cb3e5fae045af7e5ead10 # v5.5.6 with: reports: "**/coverage.cobertura.xml" targetdir: "merged/" From ab8e3422dca94c5298dec647b81c31b61c5cc088 Mon Sep 17 00:00:00 2001 From: Phillycodes Date: Tue, 21 Apr 2026 01:43:54 -0400 Subject: [PATCH 12/24] Translated using Weblate (Haitian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ht/ --- Emby.Server.Implementations/Localization/Core/ht.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/ht.json b/Emby.Server.Implementations/Localization/Core/ht.json index f927d3173a..183c422a85 100644 --- a/Emby.Server.Implementations/Localization/Core/ht.json +++ b/Emby.Server.Implementations/Localization/Core/ht.json @@ -58,5 +58,8 @@ "ValueSpecialEpisodeName": "Spesyal - {0}", "VersionNumber": "Vesyon {0}", "TasksApplicationCategory": "Aplikasyon", - "TasksMaintenanceCategory": "Antretyen" + "TasksMaintenanceCategory": "Antretyen", + "AppDeviceValues": "Aplikasyon: {0}, Aparèy: {1}", + "AuthenticationSucceededWithUserName": "{0} otantifye avèk siksè", + "CameraImageUploadedFrom": "Une nouvelle image de la caméra a été téléchargée depuis {0}" } From cec9b51b4f32e252d8e4e224c0119355d8dded82 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 18:05:58 +0000 Subject: [PATCH 13/24] Update dependency dotnet-ef to v10.0.7 --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 3f7a9454c5..9b44eff4c6 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "dotnet-ef": { - "version": "10.0.6", + "version": "10.0.7", "commands": [ "dotnet-ef" ] From 50768923fbe00ae8f78fe50a8b864dcec1f6f4b3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 10:58:32 +0000 Subject: [PATCH 14/24] Update Microsoft --- Directory.Packages.props | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index d2b715d6aa..fc47dad42f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -26,28 +26,28 @@ - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -77,7 +77,7 @@ - + From 4bb1e2543fb22cac923aa4741d580aa3488fc049 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 12:41:53 +0000 Subject: [PATCH 15/24] Update dependency z440.atl.core to 7.13.0 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index fc47dad42f..5802ab6124 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -79,7 +79,7 @@ - + From 1691940c3f8e26de1b7f0f219c4d1f8aab09cd0a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 23:46:18 +0000 Subject: [PATCH 16/24] Update dependency Diacritics to 4.1.8 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 5802ab6124..74edd24781 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -14,7 +14,7 @@ - + From 64c8c83fae55dde93ec550a899c4e3dce0487659 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 24 Apr 2026 18:10:43 +0200 Subject: [PATCH 17/24] Remove all JF contributors from Emby list --- CONTRIBUTORS.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 01f968690f..0255f02256 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,5 +1,6 @@ # Jellyfin Contributors + - [0x25CBFC4F](https://github.com/0x25CBFC4F) - [1337joe](https://github.com/1337joe) - [97carmine](https://github.com/97carmine) - [Abbe98](https://github.com/Abbe98) @@ -14,7 +15,7 @@ - [bilde2910](https://github.com/bilde2910) - [bfayers](https://github.com/bfayers) - [BnMcG](https://github.com/BnMcG) - - [Bond-009](https://github.com/Bond-009) + - [Bond_009](https://github.com/Bond-009) - [brianjmurrell](https://github.com/brianjmurrell) - [bugfixin](https://github.com/bugfixin) - [chaosinnovator](https://github.com/chaosinnovator) @@ -31,6 +32,7 @@ - [DaveChild](https://github.com/DaveChild) - [DavidFair](https://github.com/DavidFair) - [Delgan](https://github.com/Delgan) + - [DerMaddis](https://github.com/dermaddis) - [Derpipose](https://github.com/Derpipose) - [dcrdev](https://github.com/dcrdev) - [dhartung](https://github.com/dhartung) @@ -54,6 +56,7 @@ - [geilername](https://github.com/geilername) - [GermanCoding](https://github.com/GermanCoding) - [gnattu](https://github.com/gnattu) + - [gnuyent](https://github.com/gnuyent) - [GodTamIt](https://github.com/GodTamIt) - [grafixeyehero](https://github.com/grafixeyehero) - [h1nk](https://github.com/h1nk) @@ -61,6 +64,7 @@ - [HelloWorld017](https://github.com/HelloWorld017) - [ikomhoog](https://github.com/ikomhoog) - [iwalton3](https://github.com/iwalton3) + - [Jakob Kukla](https://github.com/jakobkukla) - [jftuga](https://github.com/jftuga) - [jkhsjdhjs](https://github.com/jkhsjdhjs) - [jmshrv](https://github.com/jmshrv) @@ -69,8 +73,10 @@ - [JustAMan](https://github.com/JustAMan) - [justinfenn](https://github.com/justinfenn) - [JPVenson](https://github.com/JPVenson) + - [JPUC1143](https://github.com/Jpuc1143/) - [KerryRJ](https://github.com/KerryRJ) - [Larvitar](https://github.com/Larvitar) + - [lbenini](https://github.com/lbenini) - [LeoVerto](https://github.com/LeoVerto) - [Liggy](https://github.com/Liggy) - [lmaonator](https://github.com/lmaonator) @@ -83,15 +89,19 @@ - [marius-luca-87](https://github.com/marius-luca-87) - [mark-monteiro](https://github.com/mark-monteiro) - [MarkCiliaVincenti](https://github.com/MarkCiliaVincenti) + - [Martin Reuter](https://github.com/reuterma24) - [Matt07211](https://github.com/Matt07211) + - [Matthew Jones](https://github.com/matthew-jones-uk) - [Maxr1998](https://github.com/Maxr1998) - [mcarlton00](https://github.com/mcarlton00) + - [Michael McElroy](https://github.com/mcmcelro) - [mitchfizz05](https://github.com/mitchfizz05) - [mohd-akram](https://github.com/mohd-akram) - [MrTimscampi](https://github.com/MrTimscampi) - [n8225](https://github.com/n8225) - [Nalsai](https://github.com/Nalsai) - [Narfinger](https://github.com/Narfinger) + - [Nathan McCrina](https://github.com/nfmccrina) - [NathanPickard](https://github.com/NathanPickard) - [neilsb](https://github.com/neilsb) - [nevado](https://github.com/nevado) @@ -102,6 +112,7 @@ - [OancaAndrei](https://github.com/OancaAndrei) - [obradovichv](https://github.com/obradovichv) - [oddstr13](https://github.com/oddstr13) + - [olsh](https://github.com/olsh) - [orryverducci](https://github.com/orryverducci) - [petermcneil](https://github.com/petermcneil) - [Phlogi](https://github.com/Phlogi) @@ -112,6 +123,7 @@ - [RazeLighter777](https://github.com/RazeLighter777) - [redSpoutnik](https://github.com/redSpoutnik) - [ringmatter](https://github.com/ringmatter) + - [Robert Lützner](https://github.com/rluetzner) - [ryan-hartzell](https://github.com/ryan-hartzell) - [s0urcelab](https://github.com/s0urcelab) - [sachk](https://github.com/sachk) @@ -127,6 +139,7 @@ - [sl1288](https://github.com/sl1288) - [Smith00101010](https://github.com/Smith00101010) - [sorinyo2004](https://github.com/sorinyo2004) + - [Soumyadip Auddy](https://github.com/SoumyadipAuddy) - [sparky8251](https://github.com/sparky8251) - [spookbits](https://github.com/spookbits) - [ssenart](https://github.com/ssenart) @@ -149,6 +162,7 @@ - [twinkybot](https://github.com/twinkybot) - [Ullmie02](https://github.com/Ullmie02) - [Unhelpful](https://github.com/Unhelpful) + - [Utku Özdemir](https://github.com/utkuozdemir) - [viaregio](https://github.com/viaregio) - [vitorsemeano](https://github.com/vitorsemeano) - [voodoos](https://github.com/voodoos) @@ -276,17 +290,3 @@ - [tikuf](https://github.com/tikuf/) - [Tim Hobbs](https://github.com/timhobbs) - [SvenVandenbrande](https://github.com/SvenVandenbrande) - - [olsh](https://github.com/olsh) - - [lbenini](https://github.com/lbenini) - - [gnuyent](https://github.com/gnuyent) - - [Matthew Jones](https://github.com/matthew-jones-uk) - - [Jakob Kukla](https://github.com/jakobkukla) - - [Utku Özdemir](https://github.com/utkuozdemir) - - [JPUC1143](https://github.com/Jpuc1143/) - - [0x25CBFC4F](https://github.com/0x25CBFC4F) - - [Robert Lützner](https://github.com/rluetzner) - - [Nathan McCrina](https://github.com/nfmccrina) - - [Martin Reuter](https://github.com/reuterma24) - - [Michael McElroy](https://github.com/mcmcelro) - - [Soumyadip Auddy](https://github.com/SoumyadipAuddy) - - [DerMaddis](https://github.com/dermaddis) From a9117bcda4ba002f39f5e8073d6d6ed7e66a3c16 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sun, 26 Apr 2026 16:13:22 +0900 Subject: [PATCH 18/24] use decorators to improve openapi endpoint categories --- Jellyfin.Api/Controllers/ActivityLogController.cs | 1 + Jellyfin.Api/Controllers/ApiKeyController.cs | 1 + Jellyfin.Api/Controllers/ArtistsController.cs | 1 + Jellyfin.Api/Controllers/ChannelsController.cs | 1 + Jellyfin.Api/Controllers/ClientLogController.cs | 1 + Jellyfin.Api/Controllers/ConfigurationController.cs | 1 + Jellyfin.Api/Controllers/DevicesController.cs | 1 + Jellyfin.Api/Controllers/DisplayPreferencesController.cs | 1 + Jellyfin.Api/Controllers/GenresController.cs | 1 + Jellyfin.Api/Controllers/ItemsController.cs | 1 + Jellyfin.Api/Controllers/LyricsController.cs | 2 +- Jellyfin.Api/Controllers/MediaSegmentsController.cs | 1 + Jellyfin.Api/Controllers/MoviesController.cs | 3 ++- Jellyfin.Api/Controllers/MusicGenresController.cs | 1 + Jellyfin.Api/Controllers/PackageController.cs | 2 +- Jellyfin.Api/Controllers/PersonsController.cs | 1 + Jellyfin.Api/Controllers/PlaylistsController.cs | 1 + Jellyfin.Api/Controllers/PlaystateController.cs | 2 +- Jellyfin.Api/Controllers/PluginsController.cs | 2 +- Jellyfin.Api/Controllers/QuickConnectController.cs | 1 + Jellyfin.Api/Controllers/ScheduledTasksController.cs | 2 +- Jellyfin.Api/Controllers/StudiosController.cs | 1 + Jellyfin.Api/Controllers/SuggestionsController.cs | 1 + Jellyfin.Api/Controllers/TimeSyncController.cs | 1 + Jellyfin.Api/Controllers/TrailersController.cs | 1 + Jellyfin.Api/Controllers/TrickplayController.cs | 2 +- Jellyfin.Api/Controllers/TvShowsController.cs | 1 + Jellyfin.Api/Controllers/UniversalAudioController.cs | 1 + Jellyfin.Api/Controllers/UserViewsController.cs | 1 + Jellyfin.Api/Controllers/VideoAttachmentsController.cs | 1 + Jellyfin.Api/Controllers/VideosController.cs | 1 + Jellyfin.Api/Controllers/YearsController.cs | 1 + 32 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Jellyfin.Api/Controllers/ActivityLogController.cs b/Jellyfin.Api/Controllers/ActivityLogController.cs index 47d3f4b7f7..d6cc0e71a4 100644 --- a/Jellyfin.Api/Controllers/ActivityLogController.cs +++ b/Jellyfin.Api/Controllers/ActivityLogController.cs @@ -19,6 +19,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("System/ActivityLog")] [Authorize(Policy = Policies.RequiresElevation)] +[Tags("System")] public class ActivityLogController : BaseJellyfinApiController { private readonly IActivityManager _activityManager; diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs index 3363d7bad2..161479e4ca 100644 --- a/Jellyfin.Api/Controllers/ApiKeyController.cs +++ b/Jellyfin.Api/Controllers/ApiKeyController.cs @@ -14,6 +14,7 @@ namespace Jellyfin.Api.Controllers; /// Authentication controller. /// [Route("Auth")] +[Tags("Authentication")] public class ApiKeyController : BaseJellyfinApiController { private readonly IAuthenticationManager _authenticationManager; diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index 99b0fde06d..f97ab414ce 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -25,6 +25,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("Artists")] [Authorize] +[Tags("Artist")] public class ArtistsController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; diff --git a/Jellyfin.Api/Controllers/ChannelsController.cs b/Jellyfin.Api/Controllers/ChannelsController.cs index 0d85b3a0db..e46ef0e31d 100644 --- a/Jellyfin.Api/Controllers/ChannelsController.cs +++ b/Jellyfin.Api/Controllers/ChannelsController.cs @@ -25,6 +25,7 @@ namespace Jellyfin.Api.Controllers; /// Channels Controller. /// [Authorize] +[Tags("Channel")] public class ChannelsController : BaseJellyfinApiController { private readonly IChannelManager _channelManager; diff --git a/Jellyfin.Api/Controllers/ClientLogController.cs b/Jellyfin.Api/Controllers/ClientLogController.cs index 139888bde8..c213b87940 100644 --- a/Jellyfin.Api/Controllers/ClientLogController.cs +++ b/Jellyfin.Api/Controllers/ClientLogController.cs @@ -15,6 +15,7 @@ namespace Jellyfin.Api.Controllers; /// Client log controller. /// [Authorize] +[Tags("System")] public class ClientLogController : BaseJellyfinApiController { private const int MaxDocumentSize = 1_000_000; diff --git a/Jellyfin.Api/Controllers/ConfigurationController.cs b/Jellyfin.Api/Controllers/ConfigurationController.cs index 9e03fbeb06..ecd667b2e8 100644 --- a/Jellyfin.Api/Controllers/ConfigurationController.cs +++ b/Jellyfin.Api/Controllers/ConfigurationController.cs @@ -20,6 +20,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("System")] [Authorize] +[Tags("System")] public class ConfigurationController : BaseJellyfinApiController { private readonly IServerConfigurationManager _configurationManager; diff --git a/Jellyfin.Api/Controllers/DevicesController.cs b/Jellyfin.Api/Controllers/DevicesController.cs index 50050262f0..eadb8c9855 100644 --- a/Jellyfin.Api/Controllers/DevicesController.cs +++ b/Jellyfin.Api/Controllers/DevicesController.cs @@ -19,6 +19,7 @@ namespace Jellyfin.Api.Controllers; /// Devices Controller. /// [Authorize(Policy = Policies.RequiresElevation)] +[Tags("Device")] public class DevicesController : BaseJellyfinApiController { private readonly IDeviceManager _deviceManager; diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index ef54e9db54..61d40a7268 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -20,6 +20,7 @@ namespace Jellyfin.Api.Controllers; /// Display Preferences Controller. /// [Authorize] +[Tags("DisplayPreference")] public class DisplayPreferencesController : BaseJellyfinApiController { private readonly IDisplayPreferencesManager _displayPreferencesManager; diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index 456e643fd7..39c3f5abcf 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -25,6 +25,7 @@ namespace Jellyfin.Api.Controllers; /// The genres controller. /// [Authorize] +[Tags("Genre")] public class GenresController : BaseJellyfinApiController { private readonly IUserManager _userManager; diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 39760556a6..69cdba6afd 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -30,6 +30,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("")] [Authorize] +[Tags("Item")] public class ItemsController : BaseJellyfinApiController { private readonly IUserManager _userManager; diff --git a/Jellyfin.Api/Controllers/LyricsController.cs b/Jellyfin.Api/Controllers/LyricsController.cs index 8eb4cadf88..5a27b2719e 100644 --- a/Jellyfin.Api/Controllers/LyricsController.cs +++ b/Jellyfin.Api/Controllers/LyricsController.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Attributes; using Jellyfin.Api.Extensions; -using Jellyfin.Api.Helpers; using Jellyfin.Extensions; using MediaBrowser.Common.Api; using MediaBrowser.Controller.Entities.Audio; @@ -27,6 +26,7 @@ namespace Jellyfin.Api.Controllers; /// Lyrics controller. /// [Route("")] +[Tags("Lyric")] public class LyricsController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; diff --git a/Jellyfin.Api/Controllers/MediaSegmentsController.cs b/Jellyfin.Api/Controllers/MediaSegmentsController.cs index b8836d7cf1..65565826a4 100644 --- a/Jellyfin.Api/Controllers/MediaSegmentsController.cs +++ b/Jellyfin.Api/Controllers/MediaSegmentsController.cs @@ -20,6 +20,7 @@ namespace Jellyfin.Api.Controllers; /// Media Segments api. /// [Authorize] +[Tags("MediaSegment")] public class MediaSegmentsController : BaseJellyfinApiController { private readonly IMediaSegmentManager _mediaSegmentManager; diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs index ace9a06395..50d34d0656 100644 --- a/Jellyfin.Api/Controllers/MoviesController.cs +++ b/Jellyfin.Api/Controllers/MoviesController.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; @@ -18,6 +17,7 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Jellyfin.Api.Controllers; @@ -26,6 +26,7 @@ namespace Jellyfin.Api.Controllers; /// Movies controller. /// [Authorize] +[Tags("Movie")] public class MoviesController : BaseJellyfinApiController { private readonly IUserManager _userManager; diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index a6427df67a..48d4ebdc04 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -25,6 +25,7 @@ namespace Jellyfin.Api.Controllers; /// The music genres controller. /// [Authorize] +[Tags("MusicGenre")] public class MusicGenresController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 274e94ee6d..1f8f963f70 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; -using Jellyfin.Api.Constants; using MediaBrowser.Common.Api; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Configuration; @@ -19,6 +18,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("")] [Authorize(Policy = Policies.RequiresElevation)] +[Tags("Plugin")] public class PackageController : BaseJellyfinApiController { private readonly IInstallationManager _installationManager; diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs index 1811a219ac..8e7026341d 100644 --- a/Jellyfin.Api/Controllers/PersonsController.cs +++ b/Jellyfin.Api/Controllers/PersonsController.cs @@ -22,6 +22,7 @@ namespace Jellyfin.Api.Controllers; /// Persons controller. /// [Authorize] +[Tags("Person")] public class PersonsController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index 9679180937..048a49ffd4 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -29,6 +29,7 @@ namespace Jellyfin.Api.Controllers; /// Playlists controller. /// [Authorize] +[Tags("Playlist")] public class PlaylistsController : BaseJellyfinApiController { private readonly IPlaylistManager _playlistManager; diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index ade0906b34..b8361dfd88 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -6,7 +6,6 @@ using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Database.Implementations.Entities; -using Jellyfin.Extensions; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; @@ -25,6 +24,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("")] [Authorize] +[Tags("Session")] public class PlaystateController : BaseJellyfinApiController { private readonly IUserManager _userManager; diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index 53b7349e7d..e20efe90a9 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Text.Json; using System.Threading.Tasks; using Jellyfin.Api.Attributes; -using Jellyfin.Api.Constants; using Jellyfin.Extensions.Json; using MediaBrowser.Common.Api; using MediaBrowser.Common.Plugins; @@ -23,6 +22,7 @@ namespace Jellyfin.Api.Controllers; /// Plugins controller. /// [Authorize(Policy = Policies.RequiresElevation)] +[Tags("Plugin")] public class PluginsController : BaseJellyfinApiController { private readonly IInstallationManager _installationManager; diff --git a/Jellyfin.Api/Controllers/QuickConnectController.cs b/Jellyfin.Api/Controllers/QuickConnectController.cs index bdb2a4d20b..5c7b38e137 100644 --- a/Jellyfin.Api/Controllers/QuickConnectController.cs +++ b/Jellyfin.Api/Controllers/QuickConnectController.cs @@ -16,6 +16,7 @@ namespace Jellyfin.Api.Controllers; /// /// Quick connect controller. /// +[Tags("Authentication")] public class QuickConnectController : BaseJellyfinApiController { private readonly IQuickConnect _quickConnect; diff --git a/Jellyfin.Api/Controllers/ScheduledTasksController.cs b/Jellyfin.Api/Controllers/ScheduledTasksController.cs index 065466cbca..f122d0f5e5 100644 --- a/Jellyfin.Api/Controllers/ScheduledTasksController.cs +++ b/Jellyfin.Api/Controllers/ScheduledTasksController.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; -using Jellyfin.Api.Constants; using MediaBrowser.Common.Api; using MediaBrowser.Model.Tasks; using Microsoft.AspNetCore.Authorization; @@ -15,6 +14,7 @@ namespace Jellyfin.Api.Controllers; /// Scheduled Tasks Controller. /// [Authorize(Policy = Policies.RequiresElevation)] +[Tags("ScheduledTask")] public class ScheduledTasksController : BaseJellyfinApiController { private readonly ITaskManager _taskManager; diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs index ad08dc5f9b..a8feb206a4 100644 --- a/Jellyfin.Api/Controllers/StudiosController.cs +++ b/Jellyfin.Api/Controllers/StudiosController.cs @@ -22,6 +22,7 @@ namespace Jellyfin.Api.Controllers; /// Studios controller. /// [Authorize] +[Tags("Studio")] public class StudiosController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index e9e404076f..9c5515dd92 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -23,6 +23,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("")] [Authorize] +[Tags("Suggestion")] public class SuggestionsController : BaseJellyfinApiController { private readonly IDtoService _dtoService; diff --git a/Jellyfin.Api/Controllers/TimeSyncController.cs b/Jellyfin.Api/Controllers/TimeSyncController.cs index d7304cf426..fe6e11f9e2 100644 --- a/Jellyfin.Api/Controllers/TimeSyncController.cs +++ b/Jellyfin.Api/Controllers/TimeSyncController.cs @@ -9,6 +9,7 @@ namespace Jellyfin.Api.Controllers; /// The time sync controller. /// [Route("")] +[Tags("System")] public class TimeSyncController : BaseJellyfinApiController { /// diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index 3e4bac89a5..f8c5bd4b87 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -15,6 +15,7 @@ namespace Jellyfin.Api.Controllers; /// The trailers controller. /// [Authorize] +[Tags("Trailer")] public class TrailersController : BaseJellyfinApiController { private readonly ItemsController _itemsController; diff --git a/Jellyfin.Api/Controllers/TrickplayController.cs b/Jellyfin.Api/Controllers/TrickplayController.cs index c9f8b36768..d7a10ce5f6 100644 --- a/Jellyfin.Api/Controllers/TrickplayController.cs +++ b/Jellyfin.Api/Controllers/TrickplayController.cs @@ -5,7 +5,6 @@ using System.Text; using System.Threading.Tasks; using Jellyfin.Api.Attributes; using Jellyfin.Api.Extensions; -using Jellyfin.Api.Helpers; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Trickplay; @@ -21,6 +20,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("")] [Authorize] +[Tags("TrickPlay")] public class TrickplayController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index c86c9b8f61..e45a100b77 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -27,6 +27,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("Shows")] [Authorize] +[Tags("Show")] public class TvShowsController : BaseJellyfinApiController { private readonly IUserManager _userManager; diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index f4e0c86143..d4e9b234c5 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -29,6 +29,7 @@ namespace Jellyfin.Api.Controllers; /// The universal audio controller. /// [Route("")] +[Tags("Audio")] public class UniversalAudioController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index ed4bba2bb1..c1d06bad36 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -26,6 +26,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("")] [Authorize] +[Tags("UserView")] public class UserViewsController : BaseJellyfinApiController { private readonly IUserManager _userManager; diff --git a/Jellyfin.Api/Controllers/VideoAttachmentsController.cs b/Jellyfin.Api/Controllers/VideoAttachmentsController.cs index b67c6fdb7b..2c8b452c35 100644 --- a/Jellyfin.Api/Controllers/VideoAttachmentsController.cs +++ b/Jellyfin.Api/Controllers/VideoAttachmentsController.cs @@ -19,6 +19,7 @@ namespace Jellyfin.Api.Controllers; /// Attachments controller. /// [Route("Videos")] +[Tags("Video")] public class VideoAttachmentsController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 7854edc5ac..394a95ee5f 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -35,6 +35,7 @@ namespace Jellyfin.Api.Controllers; /// /// The videos controller. /// +[Tags("Video")] public class VideosController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index 685334a9f0..aa6464ee7a 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -26,6 +26,7 @@ namespace Jellyfin.Api.Controllers; /// Years controller. /// [Authorize] +[Tags("Year")] public class YearsController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; From a35787b82bc338d0c66040c73d7e280f9b40cddd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 13:58:51 +0000 Subject: [PATCH 19/24] Update dependency FsCheck.Xunit.v3 to 3.3.3 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 0ab507a2c8..9b073e67a5 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -17,7 +17,7 @@ - + From 9962fbbe2ed20a95dd1e9533fbc684070347f031 Mon Sep 17 00:00:00 2001 From: dwandw Date: Tue, 21 Apr 2026 02:27:11 +0000 Subject: [PATCH 20/24] fix: IPv6 prefixes not recognized as proxy https://github.com/jellyfin/jellyfin/issues/15710 --- CONTRIBUTORS.md | 1 + .../Extensions/ApiServiceCollectionExtensions.cs | 2 +- tests/Jellyfin.Server.Tests/ParseNetworkTests.cs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index eb2221f2b3..c42962786d 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -228,6 +228,7 @@ - [MarcoCoreDuo](https://github.com/MarcoCoreDuo) - [LiHRaM](https://github.com/LiHRaM) - [MSalman5230](https://github.com/MSalman5230) + - [dwandw](https://github.com/dwandw) # Emby Contributors diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index c71c193e2e..a498901481 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -312,7 +312,7 @@ namespace Jellyfin.Server.Extensions return; } - if (prefixLength == NetworkConstants.MinimumIPv4PrefixSize) + if ((addr.AddressFamily == AddressFamily.InterNetwork && prefixLength == NetworkConstants.MinimumIPv4PrefixSize) || (addr.AddressFamily == AddressFamily.InterNetworkV6 && prefixLength == NetworkConstants.MinimumIPv6PrefixSize)) { options.KnownProxies.Add(addr); } diff --git a/tests/Jellyfin.Server.Tests/ParseNetworkTests.cs b/tests/Jellyfin.Server.Tests/ParseNetworkTests.cs index 14f4c33b6b..e788f43b86 100644 --- a/tests/Jellyfin.Server.Tests/ParseNetworkTests.cs +++ b/tests/Jellyfin.Server.Tests/ParseNetworkTests.cs @@ -23,8 +23,8 @@ namespace Jellyfin.Server.Tests true, true, new string[] { "192.168.t", "127.0.0.1", "::1", "1234.1232.12.1234" }, - new IPAddress[] { IPAddress.Loopback }, - new IPNetwork[] { new IPNetwork(IPAddress.IPv6Loopback, 128) }); + new IPAddress[] { IPAddress.Loopback, IPAddress.IPv6Loopback }, + Array.Empty()); data.Add( true, @@ -37,8 +37,8 @@ namespace Jellyfin.Server.Tests true, true, new string[] { "::1" }, - Array.Empty(), - new IPNetwork[] { new IPNetwork(IPAddress.IPv6Loopback, 128) }); + new IPAddress[] { IPAddress.IPv6Loopback }, + Array.Empty()); data.Add( false, @@ -58,15 +58,15 @@ namespace Jellyfin.Server.Tests false, true, new string[] { "localhost" }, - Array.Empty(), - new IPNetwork[] { new IPNetwork(IPAddress.IPv6Loopback, 128) }); + new IPAddress[] { IPAddress.IPv6Loopback }, + Array.Empty()); data.Add( true, true, new string[] { "localhost" }, - new IPAddress[] { IPAddress.Loopback }, - new IPNetwork[] { new IPNetwork(IPAddress.IPv6Loopback, 128) }); + new IPAddress[] { IPAddress.Loopback, IPAddress.IPv6Loopback }, + Array.Empty()); return data; } From c59d3bb21a7a892a7e3c259843b001c57cfc18e0 Mon Sep 17 00:00:00 2001 From: dkanada Date: Mon, 27 Apr 2026 21:45:40 +0900 Subject: [PATCH 21/24] hide HLS controllers and update obsolete endpoints --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 1 + Jellyfin.Api/Controllers/HlsSegmentController.cs | 1 + Jellyfin.Api/Controllers/InstantMixController.cs | 2 ++ Jellyfin.Api/Controllers/LibraryController.cs | 14 -------------- Jellyfin.Api/Controllers/LiveTvController.cs | 16 ++-------------- .../Controllers/MusicGenresController.cs | 2 ++ Jellyfin.Api/Controllers/PlaystateController.cs | 3 +++ Jellyfin.Api/Controllers/PluginsController.cs | 1 - .../Plugins/Tmdb/Api/TmdbController.cs | 1 + 9 files changed, 12 insertions(+), 29 deletions(-) diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index c13da3ac7b..c059f5880d 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -38,6 +38,7 @@ namespace Jellyfin.Api.Controllers; /// [Route("")] [Authorize] +[ApiExplorerSettings(IgnoreApi = true)] public class DynamicHlsController : BaseJellyfinApiController { private const EncoderPreset DefaultVodEncoderPreset = EncoderPreset.veryfast; diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index 1927a332b2..b5365cd632 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -20,6 +20,7 @@ namespace Jellyfin.Api.Controllers; /// The hls segment controller. /// [Route("")] +[ApiExplorerSettings(IgnoreApi = true)] public class HlsSegmentController : BaseJellyfinApiController { private readonly IFileSystem _fileSystem; diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index 301954561d..f80d32d149 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -320,6 +320,7 @@ public class InstantMixController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [Obsolete("Use GetInstantMixFromArtists")] + [ApiExplorerSettings(IgnoreApi = true)] public ActionResult> GetInstantMixFromArtists2( [FromQuery, Required] Guid id, [FromQuery] Guid? userId, @@ -358,6 +359,7 @@ public class InstantMixController : BaseJellyfinApiController [HttpGet("MusicGenres/InstantMix")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [Obsolete("Use GetInstantMixFromMusicGenreByName")] public ActionResult> GetInstantMixFromMusicGenreById( [FromQuery, Required] Guid id, [FromQuery] Guid? userId, diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 558e1c6c80..6ef40a1898 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -113,20 +113,6 @@ public class LibraryController : BaseJellyfinApiController return PhysicalFile(item.Path, MimeTypes.GetMimeType(item.Path), true); } - /// - /// Gets critic review for an item. - /// - /// Critic reviews returned. - /// The list of critic reviews. - [HttpGet("Items/{itemId}/CriticReviews")] - [Authorize] - [Obsolete("This endpoint is obsolete.")] - [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult> GetCriticReviews() - { - return new QueryResult(); - } - /// /// Get theme songs for an item. /// diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 9a32a303a9..2879b0fe53 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -344,6 +344,7 @@ public class LiveTvController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.LiveTvAccess)] [Obsolete("This endpoint is obsolete.")] + [ApiExplorerSettings(IgnoreApi = true)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "channelId", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Imported from ServiceStack")] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "groupId", Justification = "Imported from ServiceStack")] @@ -387,6 +388,7 @@ public class LiveTvController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status200OK)] [Authorize(Policy = Policies.LiveTvAccess)] [Obsolete("This endpoint is obsolete.")] + [ApiExplorerSettings(IgnoreApi = true)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Imported from ServiceStack")] public ActionResult> GetRecordingGroups([FromQuery] Guid? userId) { @@ -944,20 +946,6 @@ public class LiveTvController : BaseJellyfinApiController return NoContent(); } - /// - /// Get recording group. - /// - /// Group id. - /// A . - [HttpGet("Recordings/Groups/{groupId}")] - [Authorize(Policy = Policies.LiveTvAccess)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [Obsolete("This endpoint is obsolete.")] - public ActionResult GetRecordingGroup([FromRoute, Required] Guid groupId) - { - return NotFound(); - } - /// /// Get guide info. /// diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index 48d4ebdc04..7af44f8bd6 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -73,6 +73,7 @@ public class MusicGenresController : BaseJellyfinApiController /// An containing the queryresult of music genres. [HttpGet] [Obsolete("Use GetGenres instead")] + [ApiExplorerSettings(IgnoreApi = true)] public ActionResult> GetMusicGenres( [FromQuery] int? startIndex, [FromQuery] int? limit, @@ -145,6 +146,7 @@ public class MusicGenresController : BaseJellyfinApiController /// An containing a with the music genre. [HttpGet("{genreName}")] [ProducesResponseType(StatusCodes.Status200OK)] + [Obsolete("Use GetGenre instead")] public ActionResult GetMusicGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId) { userId = RequestHelpers.GetUserId(User, userId); diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index b8361dfd88..aa22bdf6af 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -273,6 +273,7 @@ public class PlaystateController : BaseJellyfinApiController [HttpPost("PlayingItems/{itemId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [Obsolete("This endpoint is obsolete. Use ReportPlaybackStart instead")] + [ApiExplorerSettings(IgnoreApi = true)] public async Task OnPlaybackStart( [FromRoute, Required] Guid itemId, [FromQuery] string? mediaSourceId, @@ -352,6 +353,7 @@ public class PlaystateController : BaseJellyfinApiController [HttpPost("PlayingItems/{itemId}/Progress")] [ProducesResponseType(StatusCodes.Status204NoContent)] [Obsolete("This endpoint is obsolete. Use ReportPlaybackProgress instead")] + [ApiExplorerSettings(IgnoreApi = true)] public async Task OnPlaybackProgress( [FromRoute, Required] Guid itemId, [FromQuery] string? mediaSourceId, @@ -441,6 +443,7 @@ public class PlaystateController : BaseJellyfinApiController [HttpDelete("PlayingItems/{itemId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [Obsolete("This endpoint is obsolete. Use ReportPlaybackStop instead")] + [ApiExplorerSettings(IgnoreApi = true)] public async Task OnPlaybackStopped( [FromRoute, Required] Guid itemId, [FromQuery] string? mediaSourceId, diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index e20efe90a9..79e6536fb6 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -136,7 +136,6 @@ public class PluginsController : BaseJellyfinApiController [HttpDelete("{pluginId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - [Obsolete("Please use the UninstallPluginByVersion API.")] public ActionResult UninstallPlugin([FromRoute, Required] Guid pluginId) { // If no version is given, return the current instance. diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Api/TmdbController.cs b/MediaBrowser.Providers/Plugins/Tmdb/Api/TmdbController.cs index 3eacc4f0f0..590cf795de 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Api/TmdbController.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Api/TmdbController.cs @@ -14,6 +14,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Api [Authorize] [Route("[controller]")] [Produces(MediaTypeNames.Application.Json)] + [ApiExplorerSettings(IgnoreApi = true)] public class TmdbController : ControllerBase { private readonly TmdbClientManager _tmdbClientManager; From 035d8f06cc4c7f3bd1703620ac1cdcf9a319eb0f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 20:36:46 +0000 Subject: [PATCH 22/24] Update danielpalme/ReportGenerator-GitHub-Action action to v5.5.7 --- .github/workflows/ci-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 81f218b893..f0ecb166b4 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -35,7 +35,7 @@ jobs: --verbosity minimal - name: Merge code coverage results - uses: danielpalme/ReportGenerator-GitHub-Action@ee3806a36b8b2eb9594cb3e5fae045af7e5ead10 # v5.5.6 + uses: danielpalme/ReportGenerator-GitHub-Action@a003c8fb9ac008fd0fffd5faa4f7d3ecb52e0675 # v5.5.7 with: reports: "**/coverage.cobertura.xml" targetdir: "merged/" From e9af1588f280f03e0fd49307dd954b18955e74d0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 18:32:08 +0000 Subject: [PATCH 23/24] Update dependency Microsoft.NET.Test.Sdk to 18.5.1 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 9b073e67a5..dd523fef13 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -47,7 +47,7 @@ - + From bb12b122c355e52a14db7ca67747c74271c657d6 Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 29 Apr 2026 15:39:34 -0400 Subject: [PATCH 24/24] Backport pull request #16718 from jellyfin/release-10.11.z Allow HDR10 for VPP tonemapping Original-merge: 938c0435960345ac3d91e7705becfaf8edc57f17 Merged-by: Bond-009 Backported-by: Bond_009 --- .../MediaEncoding/EncodingHelper.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 9f7e35d1ea..117f376724 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -420,7 +420,9 @@ namespace MediaBrowser.Controller.MediaEncoding } return state.VideoStream.VideoRange == VideoRange.HDR - && IsDoviWithHdr10Bl(state.VideoStream); + && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10 + || IsHdr10Plus(state.VideoStream) + || IsDoviWithHdr10Bl(state.VideoStream)); } private bool IsVideoToolboxTonemapAvailable(EncodingJobInfo state, EncodingOptions options) @@ -435,8 +437,10 @@ namespace MediaBrowser.Controller.MediaEncoding // Certain DV profile 5 video works in Safari with direct playing, but the VideoToolBox does not produce correct mapping results with transcoding. // All other HDR formats working. return state.VideoStream.VideoRange == VideoRange.HDR - && (IsDoviWithHdr10Bl(state.VideoStream) - || state.VideoStream.VideoRangeType is VideoRangeType.HLG); + && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10 + || IsHdr10Plus(state.VideoStream) + || IsDoviWithHdr10Bl(state.VideoStream) + || state.VideoStream.VideoRangeType == VideoRangeType.HLG); } private bool IsVideoStreamHevcRext(EncodingJobInfo state)