From 83d0dbdbcbe02382863dd48ad15b88ad2f48cb89 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Oct 2025 18:35:55 +0000 Subject: [PATCH 1/9] Update github/codeql-action action to v4.31.2 --- .github/workflows/ci-codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-codeql-analysis.yml b/.github/workflows/ci-codeql-analysis.yml index 53daf0991f..3cb35908bc 100644 --- a/.github/workflows/ci-codeql-analysis.yml +++ b/.github/workflows/ci-codeql-analysis.yml @@ -27,11 +27,11 @@ jobs: dotnet-version: '9.0.x' - name: Initialize CodeQL - uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: languages: ${{ matrix.language }} queries: +security-extended - name: Autobuild - uses: github/codeql-action/autobuild@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/autobuild@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 From ffe82be7a7a2ea6ab6d0e543f58ecd01df4085ef Mon Sep 17 00:00:00 2001 From: Jacky He Date: Fri, 31 Oct 2025 17:12:15 -0400 Subject: [PATCH 2/9] Translated using Weblate (Chinese (Traditional Han script, Hong Kong)) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hant_HK/ --- Emby.Server.Implementations/Localization/Core/zh-HK.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/zh-HK.json b/Emby.Server.Implementations/Localization/Core/zh-HK.json index 60af2274e4..c8800e256e 100644 --- a/Emby.Server.Implementations/Localization/Core/zh-HK.json +++ b/Emby.Server.Implementations/Localization/Core/zh-HK.json @@ -127,8 +127,8 @@ "HearingImpaired": "聽力障礙", "TaskRefreshTrickplayImages": "建立 Trickplay 圖像", "TaskRefreshTrickplayImagesDescription": "為已啟用 Trickplay 的媒體庫內的影片建立 Trickplay 預覽圖。", - "TaskExtractMediaSegments": "掃描媒體段落", - "TaskExtractMediaSegmentsDescription": "從MediaSegment中被允許的插件獲取媒體段落。", + "TaskExtractMediaSegments": "掃描媒體分段資訊", + "TaskExtractMediaSegmentsDescription": "從允許MediaSegment 功能的插件中獲取媒體片段。", "TaskDownloadMissingLyrics": "下載欠缺歌詞", "TaskDownloadMissingLyricsDescription": "下載歌詞", "TaskCleanCollectionsAndPlaylists": "整理媒體與播放清單", From 63f06aad9420b31a1cc79052b0408fb8c96e1c72 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:14:23 +0000 Subject: [PATCH 3/9] Update dependency Serilog.Sinks.Console to 6.1.1 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 12aab38288..5f11271c1e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -68,7 +68,7 @@ - + From 4258df4485c928e5a128bfb7c0149ba51b7b33af Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sun, 2 Nov 2025 21:58:41 -0500 Subject: [PATCH 4/9] Backport pull request #15247 from jellyfin/release-10.11.z Ignore initial delay in audio-only containers Original-merge: 6bf88c049e9f64ec5829d60d69eff3c3239a9528 Merged-by: crobibero Backported-by: Joshua M. Boniface --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 2614fe9956..fe6f855b5e 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1625,8 +1625,11 @@ public class DynamicHlsController : BaseJellyfinApiController var useLegacySegmentOption = _mediaEncoder.EncoderVersion < _minFFmpegHlsSegmentOptions; - // fMP4 needs this flag to write the audio packet DTS/PTS including the initial delay into MOOF::TRAF::TFDT - hlsArguments += $" {(useLegacySegmentOption ? "-hls_ts_options" : "-hls_segment_options")} movflags=+frag_discont"; + if (state.VideoStream is not null && state.IsOutputVideo) + { + // fMP4 needs this flag to write the audio packet DTS/PTS including the initial delay into MOOF::TRAF::TFDT + hlsArguments += $" {(useLegacySegmentOption ? "-hls_ts_options" : "-hls_segment_options")} movflags=+frag_discont"; + } segmentFormat = "fmp4" + outputFmp4HeaderArg; } From 1ccd10863e24485978a2f5fd7650b2bcf42168d3 Mon Sep 17 00:00:00 2001 From: thornbill Date: Sun, 2 Nov 2025 21:58:42 -0500 Subject: [PATCH 5/9] Backport pull request #15254 from jellyfin/release-10.11.z Update password reset to always return the same response structure Original-merge: 4ad31418753840ca76c52fc2aa56fa1a4235ca87 Merged-by: crobibero Backported-by: Joshua M. Boniface --- .../Users/DefaultPasswordResetProvider.cs | 40 +++++++++++-------- .../Users/UserManager.cs | 24 +++++------ .../Authentication/IPasswordResetProvider.cs | 5 +-- .../Users/ForgotPasswordAction.cs | 4 ++ 4 files changed, 41 insertions(+), 32 deletions(-) diff --git a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs index f20fb2d92d..49a9fda943 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Security.Cryptography; using System.Text.Json; @@ -92,33 +93,38 @@ namespace Jellyfin.Server.Implementations.Users } /// - public async Task StartForgotPasswordProcess(User user, bool isInNetwork) + public async Task StartForgotPasswordProcess(User? user, string enteredUsername, bool isInNetwork) { - byte[] bytes = new byte[4]; - RandomNumberGenerator.Fill(bytes); - string pin = BitConverter.ToString(bytes); - DateTime expireTime = DateTime.UtcNow.AddMinutes(30); - string filePath = _passwordResetFileBase + user.Id + ".json"; - SerializablePasswordReset spr = new SerializablePasswordReset - { - ExpirationDate = expireTime, - Pin = pin, - PinFile = filePath, - UserName = user.Username - }; + var usernameHash = enteredUsername.ToUpperInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture); + var pinFile = _passwordResetFileBase + usernameHash + ".json"; - FileStream fileStream = AsyncFile.Create(filePath); - await using (fileStream.ConfigureAwait(false)) + if (user is not null && isInNetwork) { - await JsonSerializer.SerializeAsync(fileStream, spr).ConfigureAwait(false); + byte[] bytes = new byte[4]; + RandomNumberGenerator.Fill(bytes); + string pin = BitConverter.ToString(bytes); + + SerializablePasswordReset spr = new SerializablePasswordReset + { + ExpirationDate = expireTime, + Pin = pin, + PinFile = pinFile, + UserName = user.Username + }; + + FileStream fileStream = AsyncFile.Create(pinFile); + await using (fileStream.ConfigureAwait(false)) + { + await JsonSerializer.SerializeAsync(fileStream, spr).ConfigureAwait(false); + } } return new ForgotPasswordResult { Action = ForgotPasswordAction.PinCode, PinExpirationDate = expireTime, - PinFile = filePath + PinFile = pinFile }; } diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index d0b41a7f6b..b534ccd1bd 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -508,23 +508,18 @@ namespace Jellyfin.Server.Implementations.Users public async Task StartForgotPasswordProcess(string enteredUsername, bool isInNetwork) { var user = string.IsNullOrWhiteSpace(enteredUsername) ? null : GetUserByName(enteredUsername); + var passwordResetProvider = GetPasswordResetProvider(user); + + var result = await passwordResetProvider + .StartForgotPasswordProcess(user, enteredUsername, isInNetwork) + .ConfigureAwait(false); if (user is not null && isInNetwork) { - var passwordResetProvider = GetPasswordResetProvider(user); - var result = await passwordResetProvider - .StartForgotPasswordProcess(user, isInNetwork) - .ConfigureAwait(false); - await UpdateUserAsync(user).ConfigureAwait(false); - return result; } - return new ForgotPasswordResult - { - Action = ForgotPasswordAction.InNetworkRequired, - PinFile = string.Empty - }; + return result; } /// @@ -760,8 +755,13 @@ namespace Jellyfin.Server.Implementations.Users return GetAuthenticationProviders(user)[0]; } - private IPasswordResetProvider GetPasswordResetProvider(User user) + private IPasswordResetProvider GetPasswordResetProvider(User? user) { + if (user is null) + { + return _defaultPasswordResetProvider; + } + return GetPasswordResetProviders(user)[0]; } diff --git a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs index 592ce99556..36cd5c5d14 100644 --- a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs +++ b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -15,11 +13,12 @@ namespace MediaBrowser.Controller.Authentication bool IsEnabled { get; } - Task StartForgotPasswordProcess(User user, bool isInNetwork); + Task StartForgotPasswordProcess(User? user, string enteredUsername, bool isInNetwork); Task RedeemPasswordResetPin(string pin); } +#nullable disable public class PasswordPinCreationResult { public string PinFile { get; set; } diff --git a/MediaBrowser.Model/Users/ForgotPasswordAction.cs b/MediaBrowser.Model/Users/ForgotPasswordAction.cs index f198476e3b..55907e6c84 100644 --- a/MediaBrowser.Model/Users/ForgotPasswordAction.cs +++ b/MediaBrowser.Model/Users/ForgotPasswordAction.cs @@ -1,11 +1,15 @@ #pragma warning disable CS1591 +using System; + namespace MediaBrowser.Model.Users { public enum ForgotPasswordAction { + [Obsolete("Returning different actions represents a security concern.")] ContactAdmin = 0, PinCode = 1, + [Obsolete("Returning different actions represents a security concern.")] InNetworkRequired = 2 } } From c9d93b0745381154d81023e0602bb8bbd7566418 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 2 Nov 2025 21:58:43 -0500 Subject: [PATCH 6/9] Backport pull request #15322 from jellyfin/release-10.11.z Fix legacy migration file checks Original-merge: da254ee968deca4d47f0f5d1164c5e883745ac60 Merged-by: crobibero Backported-by: Joshua M. Boniface --- .../Routines/MigrateActivityLogDb.cs | 2 +- .../Routines/MigrateAuthenticationDb.cs | 21 ++++++++++++++++++- .../Routines/MigrateDisplayPreferencesDb.cs | 18 ++++++++++++++++ .../Migrations/Routines/MigrateUserDb.cs | 2 +- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs index b36db347cd..8c8563190d 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs @@ -71,7 +71,7 @@ namespace Jellyfin.Server.Migrations.Routines if (row.GetInt32(0) == 0) { _logger.LogWarning("Table 'ActivityLog' doesn't exist in {ActivityLogPath}, nothing to migrate", activityLogPath); - break; + return; } } diff --git a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs index c6699c21df..0de775e03a 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs @@ -50,9 +50,28 @@ namespace Jellyfin.Server.Migrations.Routines public void Perform() { var dataPath = _appPaths.DataPath; - using (var connection = new SqliteConnection($"Filename={Path.Combine(dataPath, DbFilename)}")) + var dbFilePath = Path.Combine(dataPath, DbFilename); + + if (!File.Exists(dbFilePath)) + { + _logger.LogWarning("{Path} doesn't exist, nothing to migrate", dbFilePath); + return; + } + + using (var connection = new SqliteConnection($"Filename={dbFilePath}")) { connection.Open(); + + var tableQuery = connection.Query("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='Tokens';"); + foreach (var row in tableQuery) + { + if (row.GetInt32(0) == 0) + { + _logger.LogWarning("Table 'Tokens' doesn't exist in {Path}, nothing to migrate", dbFilePath); + return; + } + } + using var dbContext = _dbProvider.CreateDbContext(); var authenticatedDevices = connection.Query("SELECT * FROM Tokens"); diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs index 0d9952ce97..ffd06fea0d 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs @@ -78,9 +78,27 @@ namespace Jellyfin.Server.Migrations.Routines var displayPrefs = new HashSet(StringComparer.OrdinalIgnoreCase); var customDisplayPrefs = new HashSet(StringComparer.OrdinalIgnoreCase); var dbFilePath = Path.Combine(_paths.DataPath, DbFilename); + + if (!File.Exists(dbFilePath)) + { + _logger.LogWarning("{Path} doesn't exist, nothing to migrate", dbFilePath); + return; + } + using (var connection = new SqliteConnection($"Filename={dbFilePath}")) { connection.Open(); + + var tableQuery = connection.Query("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='userdisplaypreferences';"); + foreach (var row in tableQuery) + { + if (row.GetInt32(0) == 0) + { + _logger.LogWarning("Table 'userdisplaypreferences' doesn't exist in {Path}, nothing to migrate", dbFilePath); + return; + } + } + using var dbContext = _provider.CreateDbContext(); var results = connection.Query("SELECT * FROM userdisplaypreferences"); diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index c3f07c0899..8c3361ee16 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -75,7 +75,7 @@ public class MigrateUserDb : IMigrationRoutine if (row.GetInt32(0) == 0) { _logger.LogWarning("Table 'LocalUsersv2' doesn't exist in {UserDbPath}, nothing to migrate", userDbPath); - break; + return; } } From 871de372ff89597c9b1e9ca10ff52e2b0a8a7983 Mon Sep 17 00:00:00 2001 From: vinnyspb Date: Sun, 2 Nov 2025 21:58:44 -0500 Subject: [PATCH 7/9] Backport pull request #15325 from jellyfin/release-10.11.z Update file size when refreshing metadata Original-merge: f994dd62114b17c335d508c8e5709f24009eb16e Merged-by: crobibero Backported-by: Joshua M. Boniface --- MediaBrowser.Providers/Manager/MetadataService.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 1d83263c5e..4c83845992 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -229,6 +229,11 @@ namespace MediaBrowser.Providers.Manager if (file is not null) { item.DateModified = file.LastWriteTimeUtc; + + if (!file.IsDirectory) + { + item.Size = file.Length; + } } } From 87b02b13166b5dc8cd59e273e1c82339db940a27 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sun, 2 Nov 2025 21:58:45 -0500 Subject: [PATCH 8/9] Backport pull request #15326 from jellyfin/release-10.11.z Skip too large extracted season numbers Original-merge: e7dbb3afec3282c556e4fe35d9376ecaa4417171 Merged-by: crobibero Backported-by: Joshua M. Boniface --- Emby.Naming/TV/SeasonPathParser.cs | 6 ++++-- tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs index 90aae2d485..eafb09a6a3 100644 --- a/Emby.Naming/TV/SeasonPathParser.cs +++ b/Emby.Naming/TV/SeasonPathParser.cs @@ -113,8 +113,10 @@ namespace Emby.Naming.TV var numberString = match.Groups["seasonnumber"]; if (numberString.Success) { - var seasonNumber = int.Parse(numberString.Value, CultureInfo.InvariantCulture); - return (seasonNumber, true); + if (int.TryParse(numberString.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var seasonNumber)) + { + return (seasonNumber, true); + } } return (null, false); diff --git a/tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs b/tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs index 7671166ff4..0c3671f4fb 100644 --- a/tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs +++ b/tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs @@ -66,6 +66,9 @@ public class SeasonPathParserTests [InlineData("/Drive/SPECIALS", "/Drive", 0, true)] [InlineData("/Drive/Episode 1 Season 2", "/Drive", null, false)] [InlineData("/Drive/Episode 1 SEASON 2", "/Drive", null, false)] + [InlineData("/media/YouTube/Devyn Johnston/2024-01-24 4070 Ti SUPER in under 7 minutes", "/media/YouTube/Devyn Johnston", null, false)] + [InlineData("/media/YouTube/Devyn Johnston/2025-01-28 5090 vs 2 SFF Cases", "/media/YouTube/Devyn Johnston", null, false)] + [InlineData("/Drive/202401244070", "/Drive", null, false)] public void GetSeasonNumberFromPathTest(string path, string? parentPath, int? seasonNumber, bool isSeasonDirectory) { var result = SeasonPathParser.Parse(path, parentPath, true, true); From a7d039b7c63b0ea9c5bc69898baa1e69d9396908 Mon Sep 17 00:00:00 2001 From: evanreichard <30810613+evanreichard@users.noreply.github.com> Date: Sun, 2 Nov 2025 21:58:46 -0500 Subject: [PATCH 9/9] Backport pull request #15328 from jellyfin/release-10.11.z fix: in optimistic locking, key off table is locked Original-merge: b5f0199a25cc221ff86d112ed6968a5352277e32 Merged-by: crobibero Backported-by: Joshua M. Boniface --- .../Locking/OptimisticLockBehavior.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Locking/OptimisticLockBehavior.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Locking/OptimisticLockBehavior.cs index b90a2e056f..7bcc7eeca4 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/Locking/OptimisticLockBehavior.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/Locking/OptimisticLockBehavior.cs @@ -52,10 +52,14 @@ public class OptimisticLockBehavior : IEntityFrameworkCoreLockingBehavior _logger = logger; _writePolicy = Policy - .HandleInner(e => e.Message.Contains("database is locked", StringComparison.InvariantCultureIgnoreCase)) + .HandleInner(e => + e.Message.Contains("database is locked", StringComparison.InvariantCultureIgnoreCase) || + e.Message.Contains("database table is locked", StringComparison.InvariantCultureIgnoreCase)) .WaitAndRetry(sleepDurations.Length, backoffProvider, RetryHandle); _writeAsyncPolicy = Policy - .HandleInner(e => e.Message.Contains("database is locked", StringComparison.InvariantCultureIgnoreCase)) + .HandleInner(e => + e.Message.Contains("database is locked", StringComparison.InvariantCultureIgnoreCase) || + e.Message.Contains("database table is locked", StringComparison.InvariantCultureIgnoreCase)) .WaitAndRetryAsync(sleepDurations.Length, backoffProvider, RetryHandle); void RetryHandle(Exception exception, TimeSpan timespan, int retryNo, Context context)