< Summary - Jellyfin

Information
Class: Emby.Server.Implementations.Library.Resolvers.TV.SeasonResolver
Assembly: Emby.Server.Implementations
File(s): /srv/git/jellyfin/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
Line coverage
72%
Covered lines: 40
Uncovered lines: 15
Coverable lines: 55
Total lines: 134
Line coverage: 72.7%
Branch coverage
37%
Covered branches: 9
Total branches: 24
Branch coverage: 37.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 2/13/2026 - 12:11:21 AM Line coverage: 23.8% (10/42) Branch coverage: 9% (2/22) Total lines: 1005/7/2026 - 12:15:44 AM Line coverage: 72.7% (40/55) Branch coverage: 45.8% (11/24) Total lines: 1345/20/2026 - 12:15:44 AM Line coverage: 72.7% (40/55) Branch coverage: 37.5% (9/24) Total lines: 134 2/13/2026 - 12:11:21 AM Line coverage: 23.8% (10/42) Branch coverage: 9% (2/22) Total lines: 1005/7/2026 - 12:15:44 AM Line coverage: 72.7% (40/55) Branch coverage: 45.8% (11/24) Total lines: 1345/20/2026 - 12:15:44 AM Line coverage: 72.7% (40/55) Branch coverage: 37.5% (9/24) Total lines: 134

Coverage delta

Coverage delta 49 -49

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
Resolve(...)37.5%642458.97%
SetProviderIdFromPath(...)100%11100%

File(s)

/srv/git/jellyfin/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs

#LineLine coverage
 1#nullable disable
 2
 3using System;
 4using System.Globalization;
 5using System.IO;
 6using System.Linq;
 7using Emby.Naming.Common;
 8using Emby.Naming.TV;
 9using Emby.Server.Implementations.Library;
 10using MediaBrowser.Controller.Entities.TV;
 11using MediaBrowser.Controller.Library;
 12using MediaBrowser.Model.Entities;
 13using MediaBrowser.Model.Globalization;
 14using Microsoft.Extensions.Logging;
 15
 16namespace Emby.Server.Implementations.Library.Resolvers.TV
 17{
 18    /// <summary>
 19    /// Class SeasonResolver.
 20    /// </summary>
 21    public class SeasonResolver : GenericFolderResolver<Season>
 22    {
 23        private readonly ILocalizationManager _localization;
 24        private readonly ILogger<SeasonResolver> _logger;
 25        private readonly NamingOptions _namingOptions;
 26
 27        /// <summary>
 28        /// Initializes a new instance of the <see cref="SeasonResolver"/> class.
 29        /// </summary>
 30        /// <param name="namingOptions">The naming options.</param>
 31        /// <param name="localization">The localization.</param>
 32        /// <param name="logger">The logger.</param>
 3133        public SeasonResolver(
 3134            NamingOptions namingOptions,
 3135            ILocalizationManager localization,
 3136            ILogger<SeasonResolver> logger)
 37        {
 3138            _namingOptions = namingOptions;
 3139            _localization = localization;
 3140            _logger = logger;
 3141        }
 42
 43        /// <summary>
 44        /// Resolves the specified args.
 45        /// </summary>
 46        /// <param name="args">The args.</param>
 47        /// <returns>Season.</returns>
 48        protected override Season Resolve(ItemResolveArgs args)
 49        {
 2150            if (args.Parent is Series series && args.IsDirectory)
 51            {
 1052                var namingOptions = _namingOptions;
 53
 1054                var path = args.Path;
 55
 1056                var seasonParserResult = SeasonPathParser.Parse(path, series.ContainingFolderPath, true, true);
 57
 1058                var season = new Season
 1059                {
 1060                    IndexNumber = seasonParserResult.SeasonNumber,
 1061                    SeriesId = series.Id,
 1062                    SeriesName = series.Name,
 1063                    Path = seasonParserResult.IsSeasonFolder ? path : null
 1064                };
 65
 1066                if (!season.IndexNumber.HasValue || !seasonParserResult.IsSeasonFolder)
 67                {
 068                    var resolver = new Naming.TV.EpisodeResolver(namingOptions);
 69
 070                    var folderName = System.IO.Path.GetFileName(path);
 071                    var testPath = @"\\test\" + folderName;
 72
 073                    var episodeInfo = resolver.Resolve(testPath, true);
 74
 075                    if (episodeInfo?.EpisodeNumber is not null && episodeInfo.SeasonNumber.HasValue)
 76                    {
 077                        _logger.LogDebug(
 078                            "Found folder underneath series with episode number: {0}. Season {1}. Episode {2}",
 079                            path,
 080                            episodeInfo.SeasonNumber.Value,
 081                            episodeInfo.EpisodeNumber.Value);
 82
 083                        return null;
 84                    }
 85
 086                    var hasAnyVideo = Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
 087                        .Any(file => _namingOptions.VideoFileExtensions.Contains(Path.GetExtension(file)));
 88
 089                    if (!hasAnyVideo)
 90                    {
 091                        return null;
 92                    }
 93                }
 94
 1095                if (season.IndexNumber.HasValue && string.IsNullOrEmpty(season.Name))
 96                {
 1097                    var seasonNumber = season.IndexNumber.Value;
 1098                    season.Name = seasonNumber == 0 ?
 1099                        args.LibraryOptions.SeasonZeroDisplayName :
 10100                        string.Format(
 10101                            CultureInfo.InvariantCulture,
 10102                            _localization.GetLocalizedString("NameSeasonNumber"),
 10103                            seasonNumber,
 10104                            args.LibraryOptions.PreferredMetadataLanguage);
 105                }
 106
 10107                SetProviderIdFromPath(season, path);
 108
 10109                return season;
 110            }
 111
 11112            return null;
 113        }
 114
 115        /// <summary>
 116        /// Sets provider ids from the season folder name.
 117        /// </summary>
 118        /// <param name="item">The season.</param>
 119        /// <param name="path">The season folder path.</param>
 120        private static void SetProviderIdFromPath(Season item, string path)
 121        {
 10122            var justName = Path.GetFileName(path.AsSpan());
 123
 10124            var tvdbId = justName.GetAttributeValue("tvdbid");
 10125            item.TrySetProviderId(MetadataProvider.Tvdb, tvdbId);
 126
 10127            var tvmazeId = justName.GetAttributeValue("tvmazeid");
 10128            item.TrySetProviderId(MetadataProvider.TvMaze, tvmazeId);
 129
 10130            var tmdbId = justName.GetAttributeValue("tmdbid");
 10131            item.TrySetProviderId(MetadataProvider.Tmdb, tmdbId);
 10132        }
 133    }
 134}