< Summary - Jellyfin

Information
Class: Jellyfin.Server.Migrations.Routines.FixLibrarySubtitleDownloadLanguages
Assembly: jellyfin
File(s): /srv/git/jellyfin/Jellyfin.Server/Migrations/Routines/FixLibrarySubtitleDownloadLanguages.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 29
Coverable lines: 29
Total lines: 105
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 22
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 3/2/2026 - 12:14:15 AM Line coverage: 0% (0/29) Branch coverage: 0% (0/20) Total lines: 1064/7/2026 - 12:14:03 AM Line coverage: 0% (0/29) Branch coverage: 0% (0/22) Total lines: 105 3/2/2026 - 12:14:15 AM Line coverage: 0% (0/29) Branch coverage: 0% (0/20) Total lines: 1064/7/2026 - 12:14:03 AM Line coverage: 0% (0/29) Branch coverage: 0% (0/22) Total lines: 105

Coverage delta

Coverage delta 1 -1

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
PerformAsync(...)0%506220%

File(s)

/srv/git/jellyfin/Jellyfin.Server/Migrations/Routines/FixLibrarySubtitleDownloadLanguages.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Threading;
 5using System.Threading.Tasks;
 6using Jellyfin.Server.ServerSetupApp;
 7using MediaBrowser.Controller.Entities;
 8using MediaBrowser.Controller.Library;
 9using MediaBrowser.Model.Globalization;
 10using Microsoft.Extensions.Logging;
 11
 12namespace Jellyfin.Server.Migrations.Routines;
 13
 14/// <summary>
 15/// Migration to fix broken library subtitle download languages.
 16/// </summary>
 17[JellyfinMigration("2026-02-06T20:00:00", nameof(FixLibrarySubtitleDownloadLanguages))]
 18internal class FixLibrarySubtitleDownloadLanguages : IAsyncMigrationRoutine
 19{
 20    private readonly ILocalizationManager _localizationManager;
 21    private readonly ILibraryManager _libraryManager;
 22    private readonly ILogger _logger;
 23
 24    /// <summary>
 25    /// Initializes a new instance of the <see cref="FixLibrarySubtitleDownloadLanguages"/> class.
 26    /// </summary>
 27    /// <param name="localizationManager">The Localization manager.</param>
 28    /// <param name="startupLogger">The startup logger for Startup UI integration.</param>
 29    /// <param name="libraryManager">The Library manager.</param>
 30    /// <param name="logger">The logger.</param>
 31    public FixLibrarySubtitleDownloadLanguages(
 32        ILocalizationManager localizationManager,
 33        IStartupLogger<FixLibrarySubtitleDownloadLanguages> startupLogger,
 34        ILibraryManager libraryManager,
 35        ILogger<FixLibrarySubtitleDownloadLanguages> logger)
 36    {
 037        _localizationManager = localizationManager;
 038        _libraryManager = libraryManager;
 039        _logger = startupLogger.With(logger);
 040    }
 41
 42    /// <inheritdoc />
 43    public Task PerformAsync(CancellationToken cancellationToken)
 44    {
 045        _logger.LogInformation("Starting to fix library subtitle download languages.");
 46
 047        var virtualFolders = _libraryManager.GetVirtualFolders(false);
 48
 049        foreach (var virtualFolder in virtualFolders)
 50        {
 051            var options = virtualFolder.LibraryOptions;
 052            if (options?.SubtitleDownloadLanguages is null || options.SubtitleDownloadLanguages.Length == 0)
 53            {
 54                continue;
 55            }
 56
 57            // Some virtual folders don't have a proper item id.
 058            if (!Guid.TryParse(virtualFolder.ItemId, out var folderId))
 59            {
 60                continue;
 61            }
 62
 063            var collectionFolder = _libraryManager.GetItemById<CollectionFolder>(folderId);
 064            if (collectionFolder is null)
 65            {
 066                _logger.LogWarning("Could not find collection folder for virtual folder '{LibraryName}' with id '{Folder
 067                continue;
 68            }
 69
 070            var fixedLanguages = new List<string>();
 71
 072            foreach (var language in options.SubtitleDownloadLanguages)
 73            {
 074                var foundLanguage = _localizationManager.FindLanguageInfo(language)?.ThreeLetterISOLanguageName;
 075                if (foundLanguage is not null)
 76                {
 77                    // Converted ISO 639-2/B to T (ger to deu)
 078                    if (!string.Equals(foundLanguage, language, StringComparison.OrdinalIgnoreCase))
 79                    {
 080                        _logger.LogInformation("Converted '{Language}' to '{ResolvedLanguage}' in library '{LibraryName}
 81                    }
 82
 083                    if (fixedLanguages.Contains(foundLanguage, StringComparer.OrdinalIgnoreCase))
 84                    {
 085                        _logger.LogInformation("Language '{Language}' already exists for library '{LibraryName}'. Skippi
 086                        continue;
 87                    }
 88
 089                    fixedLanguages.Add(foundLanguage);
 90                }
 91                else
 92                {
 093                    _logger.LogInformation("Could not resolve language '{Language}' in library '{LibraryName}'. Skipping
 94                }
 95            }
 96
 097            options.SubtitleDownloadLanguages = [.. fixedLanguages];
 098            collectionFolder.UpdateLibraryOptions(options);
 99        }
 100
 0101        _logger.LogInformation("Library subtitle download languages fixed.");
 102
 0103        return Task.CompletedTask;
 104    }
 105}