< Summary - Jellyfin

Information
Class: Emby.Naming.TV.SeriesPathParser
Assembly: Emby.Naming
File(s): /srv/git/jellyfin/Emby.Naming/TV/SeriesPathParser.cs
Line coverage
100%
Covered lines: 23
Uncovered lines: 0
Coverable lines: 23
Total lines: 78
Line coverage: 100%
Branch coverage
86%
Covered branches: 26
Total branches: 30
Branch coverage: 86.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 5/12/2026 - 12:15:57 AM Line coverage: 100% (17/17) Branch coverage: 94.4% (17/18) Total lines: 605/20/2026 - 12:15:44 AM Line coverage: 100% (17/17) Branch coverage: 77.7% (14/18) Total lines: 6010/29/2026 - 12:17:11 AM Line coverage: 100% (23/23) Branch coverage: 86.6% (26/30) Total lines: 78 5/12/2026 - 12:15:57 AM Line coverage: 100% (17/17) Branch coverage: 94.4% (17/18) Total lines: 605/20/2026 - 12:15:44 AM Line coverage: 100% (17/17) Branch coverage: 77.7% (14/18) Total lines: 6010/29/2026 - 12:17:11 AM Line coverage: 100% (23/23) Branch coverage: 86.6% (26/30) Total lines: 78

Coverage delta

Coverage delta 17 -17

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Parse(...)91.66%1212100%
Parse(...)83.33%1818100%

File(s)

/srv/git/jellyfin/Emby.Naming/TV/SeriesPathParser.cs

#LineLine coverage
 1using Emby.Naming.Common;
 2
 3namespace Emby.Naming.TV
 4{
 5    /// <summary>
 6    /// Used to parse information about series from paths containing more information that only the series name.
 7    /// Uses the same regular expressions as the EpisodePathParser but have different success criteria.
 8    /// </summary>
 9    public static class SeriesPathParser
 10    {
 11        /// <summary>
 12        /// Parses information about series from path.
 13        /// </summary>
 14        /// <param name="options"><see cref="NamingOptions"/> object containing EpisodeExpressions and MultipleEpisodeEx
 15        /// <param name="path">Path.</param>
 16        /// <returns>Returns <see cref="SeriesPathParserResult"/> object.</returns>
 17        public static SeriesPathParserResult Parse(NamingOptions options, string path)
 18        {
 4219            SeriesPathParserResult? result = null;
 20
 210921            foreach (var expression in options.EpisodeExpressions)
 22            {
 23                // Optimistic expressions (bare numbers, "01.blah", etc.) are only meant for
 24                // episode parsing and produce false series names on release folder names like
 25                // "Silo.S03.1080p.WEB-DL..." (e.g. reading "264" as S02E64). Skip them here.
 102226                if (expression.IsOptimistic)
 27                {
 28                    continue;
 29                }
 30
 78231                var currentResult = Parse(path, expression);
 78232                if (currentResult.Success)
 33                {
 1934                    result = currentResult;
 1935                    break;
 36                }
 37            }
 38
 4239            if (result is not null)
 40            {
 1941                if (!string.IsNullOrEmpty(result.SeriesName))
 42                {
 1943                    result.SeriesName = result.SeriesName.Trim(' ', '_', '.', '-');
 44                }
 45            }
 46
 4247            return result ?? new SeriesPathParserResult();
 48        }
 49
 50        private static SeriesPathParserResult Parse(string name, EpisodeExpression expression)
 51        {
 78252            var result = new SeriesPathParserResult();
 53
 78254            var match = expression.Regex.Match(name);
 55
 78256            if (match.Success && match.Groups.Count >= 3)
 57            {
 2558                if (expression.IsNamed)
 59                {
 60                    // Reject implausible season numbers (e.g. resolutions like 1280x720
 61                    // read as S1280E720), mirroring EpisodePathParser.
 2362                    var seasonNumberGroup = match.Groups["seasonnumber"];
 2363                    if (seasonNumberGroup.Success
 2364                        && int.TryParse(seasonNumberGroup.ValueSpan, System.Globalization.NumberStyles.Integer, System.G
 2365                        && ((seasonNumber >= 200 && seasonNumber < 1928) || seasonNumber > 2500))
 66                    {
 267                        return result;
 68                    }
 69
 2170                    result.SeriesName = match.Groups["seriesname"].Value;
 2171                    result.Success = !string.IsNullOrEmpty(result.SeriesName) && !seasonNumberGroup.ValueSpan.IsEmpty;
 72                }
 73            }
 74
 78075            return result;
 76        }
 77    }
 78}