< Summary - Jellyfin

Information
Class: Emby.Naming.Book.BookFileNameParser
Assembly: Emby.Naming
File(s): /srv/git/jellyfin/Emby.Naming/Book/BookFileNameParser.cs
Line coverage
96%
Covered lines: 31
Uncovered lines: 1
Coverable lines: 32
Total lines: 94
Line coverage: 96.8%
Branch coverage
72%
Covered branches: 29
Total branches: 40
Branch coverage: 72.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 3/26/2026 - 12:14:14 AM Line coverage: 0% (0/26) Branch coverage: 0% (0/26) Total lines: 756/18/2026 - 12:16:24 AM Line coverage: 96.8% (31/32) Branch coverage: 72.5% (29/40) Total lines: 94 3/26/2026 - 12:14:14 AM Line coverage: 0% (0/26) Branch coverage: 0% (0/26) Total lines: 756/18/2026 - 12:16:24 AM Line coverage: 96.8% (31/32) Branch coverage: 72.5% (29/40) Total lines: 94

Coverage delta

Coverage delta 97 -97

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
Parse(...)72.5%404095.45%

File(s)

/srv/git/jellyfin/Emby.Naming/Book/BookFileNameParser.cs

#LineLine coverage
 1using System;
 2using System.Text.RegularExpressions;
 3
 4namespace Emby.Naming.Book
 5{
 6    /// <summary>
 7    /// Helper class to retrieve basic metadata from a book filename.
 8    /// </summary>
 9    public static partial class BookFileNameParser
 10    {
 11        private const string NameMatchGroup = "name";
 12        private const string IndexMatchGroup = "index";
 13        private const string YearMatchGroup = "year";
 14        private const string SeriesNameMatchGroup = "seriesName";
 15
 116        private static readonly Regex[] _nameMatches =
 117        [
 118            // seriesName (seriesYear) #index (of count) (year) where only seriesName and index are required
 119            new Regex(@"^(?<seriesName>.+?)((\s\((?<seriesYear>[0-9]{4})\))?)\s#(?<index>[0-9]+)(?:\.0)?((\s\(of\s(?<cou
 120            new Regex(@"^(?<name>.+?)\s\((?<seriesName>.+?),\s#(?<index>[0-9]+)\)(?:\.0)?((\s\((?<year>[0-9]{4})\))?)$")
 121            new Regex(@"^(?<index>[0-9]+)(?:\.0)?\s\-\s(?<name>.+?)((\s\((?<year>[0-9]{4})\))?)$"),
 122            new Regex(@"(?<name>.*)\((?<year>[0-9]{4})\)"),
 123            // last resort matches the whole string as the name
 124            new Regex(@"(?<name>.*)")
 125        ];
 26
 27        [GeneratedRegex(@"^(?<name>.+?)(\sv(?<volume>[0-9]+))?(\sc(?<chapter>[0-9]+))?$")]
 28        private static partial Regex ComicRegex();
 29
 30        /// <summary>
 31        /// Parse a filename name to retrieve the book name, series name, index, and year.
 32        /// </summary>
 33        /// <param name="name">Book filename to parse for information.</param>
 34        /// <returns>Returns <see cref="BookFileNameParserResult"/> object.</returns>
 35        public static BookFileNameParserResult Parse(string? name)
 36        {
 1937            var result = new BookFileNameParserResult();
 38
 1939            if (name == null)
 40            {
 041                return result;
 42            }
 43
 13944            foreach (var regex in _nameMatches)
 45            {
 6046                var match = regex.Match(name);
 47
 6048                if (!match.Success)
 49                {
 50                    continue;
 51                }
 52
 1953                if (match.Groups.TryGetValue(NameMatchGroup, out Group? nameGroup) && nameGroup.Success)
 54                {
 1555                    var comicMatch = ComicRegex().Match(nameGroup.Value.Trim());
 56
 1557                    if (comicMatch.Success)
 58                    {
 1559                        if (comicMatch.Groups.TryGetValue("volume", out Group? volumeGroup) && volumeGroup.Success && in
 60                        {
 261                            result.ParentIndex = volume;
 62                        }
 63
 1564                        if (comicMatch.Groups.TryGetValue("chapter", out Group? chapterGroup) && chapterGroup.Success &&
 65                        {
 266                            result.Index = chapter;
 67                        }
 68                    }
 69
 1570                    result.Name = nameGroup.ValueSpan.Trim().ToString();
 71                }
 72
 1973                if (match.Groups.TryGetValue(IndexMatchGroup, out Group? indexGroup) && indexGroup.Success && int.TryPar
 74                {
 1175                    result.Index = index;
 76                }
 77
 1978                if (match.Groups.TryGetValue(YearMatchGroup, out Group? yearGroup) && yearGroup.Success && int.TryParse(
 79                {
 980                    result.Year = year;
 81                }
 82
 1983                if (match.Groups.TryGetValue(SeriesNameMatchGroup, out Group? seriesGroup) && seriesGroup.Success)
 84                {
 685                    result.SeriesName = seriesGroup.Value.Trim();
 86                }
 87
 688                break;
 89            }
 90
 1991            return result;
 92        }
 93    }
 94}

Methods/Properties

.cctor()
Parse(System.String)