< Summary - Jellyfin

Information
Class: Emby.Server.Implementations.Library.Resolvers.TV.SeriesResolver
Assembly: Emby.Server.Implementations
File(s): /srv/git/jellyfin/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
Line coverage
9%
Covered lines: 7
Uncovered lines: 67
Coverable lines: 74
Total lines: 210
Line coverage: 9.4%
Branch coverage
10%
Covered branches: 4
Total branches: 38
Branch coverage: 10.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Priority()100%11100%
Resolve(...)16.66%495.58246.45%
IsSeriesFolder(...)0%210140%
IsSeasonFolder(...)100%210%
SetInitialItemValues(...)100%210%
SetProviderIdFromPath(...)100%210%

File(s)

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

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CS1591
 4
 5using System;
 6using System.Collections.Generic;
 7using System.IO;
 8using Emby.Naming.Common;
 9using Emby.Naming.TV;
 10using Emby.Naming.Video;
 11using Jellyfin.Data.Enums;
 12using MediaBrowser.Controller.Entities.TV;
 13using MediaBrowser.Controller.Library;
 14using MediaBrowser.Controller.Resolvers;
 15using MediaBrowser.Model.Entities;
 16using MediaBrowser.Model.IO;
 17using Microsoft.Extensions.Logging;
 18
 19namespace Emby.Server.Implementations.Library.Resolvers.TV
 20{
 21    /// <summary>
 22    /// Class SeriesResolver.
 23    /// </summary>
 24    public class SeriesResolver : GenericFolderResolver<Series>
 25    {
 26        private readonly ILogger<SeriesResolver> _logger;
 27        private readonly NamingOptions _namingOptions;
 28
 29        /// <summary>
 30        /// Initializes a new instance of the <see cref="SeriesResolver"/> class.
 31        /// </summary>
 32        /// <param name="logger">The logger.</param>
 33        /// <param name="namingOptions">The naming options.</param>
 2234        public SeriesResolver(ILogger<SeriesResolver> logger,  NamingOptions namingOptions)
 35        {
 2236            _logger = logger;
 2237            _namingOptions = namingOptions;
 2238        }
 39
 40        /// <summary>
 41        /// Gets the priority.
 42        /// </summary>
 43        /// <value>The priority.</value>
 2244        public override ResolverPriority Priority => ResolverPriority.Second;
 45
 46        /// <summary>
 47        /// Resolves the specified args.
 48        /// </summary>
 49        /// <param name="args">The args.</param>
 50        /// <returns>Series.</returns>
 51        protected override Series Resolve(ItemResolveArgs args)
 52        {
 353            if (args.IsDirectory)
 54            {
 055                if (args.HasParent<Series>() || args.HasParent<Season>())
 56                {
 057                    return null;
 58                }
 59
 060                var seriesInfo = Naming.TV.SeriesResolver.Resolve(_namingOptions, args.Path);
 61
 062                var collectionType = args.GetCollectionType();
 063                if (collectionType == CollectionType.tvshows)
 64                {
 65                    // TODO refactor into separate class or something, this is copied from LibraryManager.GetConfiguredC
 066                    var configuredContentType = args.GetConfiguredContentType();
 067                    if (configuredContentType != CollectionType.tvshows)
 68                    {
 069                        return new Series
 070                        {
 071                            Path = args.Path,
 072                            Name = seriesInfo.Name
 073                        };
 74                    }
 75                }
 076                else if (collectionType is null)
 77                {
 078                    if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
 79                    {
 080                        if (args.Parent is not null && args.Parent.IsRoot)
 81                        {
 82                            // For now, return null, but if we want to allow this in the future then add some additional
 083                            return null;
 84                        }
 85
 086                        return new Series
 087                        {
 088                            Path = args.Path,
 089                            Name = seriesInfo.Name
 090                        };
 91                    }
 92
 093                    if (args.Parent is not null && args.Parent.IsRoot)
 94                    {
 095                        return null;
 96                    }
 97
 098                    if (IsSeriesFolder(args.Path, args.FileSystemChildren, false))
 99                    {
 0100                        return new Series
 0101                        {
 0102                            Path = args.Path,
 0103                            Name = seriesInfo.Name
 0104                        };
 105                    }
 106                }
 107            }
 108
 3109            return null;
 110        }
 111
 112        private bool IsSeriesFolder(
 113            string path,
 114            IEnumerable<FileSystemMetadata> fileSystemChildren,
 115            bool isTvContentType)
 116        {
 0117            foreach (var child in fileSystemChildren)
 118            {
 0119                if (child.IsDirectory)
 120                {
 0121                    if (IsSeasonFolder(child.FullName, isTvContentType))
 122                    {
 0123                        _logger.LogDebug("{Path} is a series because of season folder {Dir}.", path, child.FullName);
 0124                        return true;
 125                    }
 126                }
 127                else
 128                {
 0129                    string fullName = child.FullName;
 0130                    if (VideoResolver.IsVideoFile(path, _namingOptions))
 131                    {
 0132                        if (isTvContentType)
 133                        {
 0134                            return true;
 135                        }
 136
 0137                        var namingOptions = _namingOptions;
 138
 0139                        var episodeResolver = new Naming.TV.EpisodeResolver(namingOptions);
 140
 0141                        var episodeInfo = episodeResolver.Resolve(fullName, false, true, false, fillExtendedInfo: false)
 0142                        if (episodeInfo is not null && episodeInfo.EpisodeNumber.HasValue)
 143                        {
 0144                            return true;
 145                        }
 146                    }
 147                }
 148            }
 149
 0150            _logger.LogDebug("{Path} is not a series folder.", path);
 0151            return false;
 0152        }
 153
 154        /// <summary>
 155        /// Determines whether [is season folder] [the specified path].
 156        /// </summary>
 157        /// <param name="path">The path.</param>
 158        /// <param name="isTvContentType">if set to <c>true</c> [is tv content type].</param>
 159        /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns>
 160        private static bool IsSeasonFolder(string path, bool isTvContentType)
 161        {
 0162            var seasonNumber = SeasonPathParser.Parse(path, isTvContentType, isTvContentType).SeasonNumber;
 163
 0164            return seasonNumber.HasValue;
 165        }
 166
 167        /// <summary>
 168        /// Sets the initial item values.
 169        /// </summary>
 170        /// <param name="item">The item.</param>
 171        /// <param name="args">The args.</param>
 172        protected override void SetInitialItemValues(Series item, ItemResolveArgs args)
 173        {
 0174            base.SetInitialItemValues(item, args);
 175
 0176            SetProviderIdFromPath(item, args.Path);
 0177        }
 178
 179        /// <summary>
 180        /// Sets the provider id from path.
 181        /// </summary>
 182        /// <param name="item">The item.</param>
 183        /// <param name="path">The path.</param>
 184        private static void SetProviderIdFromPath(Series item, string path)
 185        {
 0186            var justName = Path.GetFileName(path.AsSpan());
 187
 0188            var imdbId = justName.GetAttributeValue("imdbid");
 0189            item.TrySetProviderId(MetadataProvider.Imdb, imdbId);
 190
 0191            var tvdbId = justName.GetAttributeValue("tvdbid");
 0192            item.TrySetProviderId(MetadataProvider.Tvdb, tvdbId);
 193
 0194            var tvmazeId = justName.GetAttributeValue("tvmazeid");
 0195            item.TrySetProviderId(MetadataProvider.TvMaze, tvmazeId);
 196
 0197            var tmdbId = justName.GetAttributeValue("tmdbid");
 0198            item.TrySetProviderId(MetadataProvider.Tmdb, tmdbId);
 199
 0200            var anidbId = justName.GetAttributeValue("anidbid");
 0201            item.TrySetProviderId("AniDB", anidbId);
 202
 0203            var aniListId = justName.GetAttributeValue("anilistid");
 0204            item.TrySetProviderId("AniList", aniListId);
 205
 0206            var aniSearchId = justName.GetAttributeValue("anisearchid");
 0207            item.TrySetProviderId("AniSearch", aniSearchId);
 0208        }
 209    }
 210}