< Summary - Jellyfin

Information
Class: Emby.Naming.Common.NamingOptions
Assembly: Emby.Naming
File(s): /srv/git/jellyfin/Emby.Naming/Common/NamingOptions.cs
Line coverage
100%
Covered lines: 739
Uncovered lines: 0
Coverable lines: 739
Total lines: 922
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 1/23/2026 - 12:11:06 AM Line coverage: 100% (730/730) Total lines: 9133/3/2026 - 12:13:24 AM Line coverage: 100% (731/731) Total lines: 9145/5/2026 - 12:15:44 AM Line coverage: 100% (739/739) Total lines: 922

Coverage delta

Coverage delta 1 -1

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
Compile()100%11100%
Compile(...)100%11100%

File(s)

/srv/git/jellyfin/Emby.Naming/Common/NamingOptions.cs

#LineLine coverage
 1#pragma warning disable CA1819
 2
 3using System;
 4using System.Collections.Generic;
 5using System.Linq;
 6using System.Text.RegularExpressions;
 7using Emby.Naming.Video;
 8using MediaBrowser.Model.Entities;
 9
 10// ReSharper disable StringLiteralTypo
 11
 12namespace Emby.Naming.Common
 13{
 14    /// <summary>
 15    /// Big ugly class containing lot of different naming options that should be split and injected instead of passes ev
 16    /// </summary>
 17    public class NamingOptions
 18    {
 19        /// <summary>
 20        /// Initializes a new instance of the <see cref="NamingOptions"/> class.
 21        /// </summary>
 22        public NamingOptions()
 23        {
 69024            VideoFileExtensions =
 69025            [
 69026                ".001",
 69027                ".3g2",
 69028                ".3gp",
 69029                ".amv",
 69030                ".asf",
 69031                ".asx",
 69032                ".avi",
 69033                ".bin",
 69034                ".bivx",
 69035                ".divx",
 69036                ".dv",
 69037                ".dvr-ms",
 69038                ".f4v",
 69039                ".fli",
 69040                ".flv",
 69041                ".ifo",
 69042                ".img",
 69043                ".iso",
 69044                ".m2t",
 69045                ".m2ts",
 69046                ".m2v",
 69047                ".m4v",
 69048                ".mkv",
 69049                ".mk3d",
 69050                ".mov",
 69051                ".mp4",
 69052                ".mpe",
 69053                ".mpeg",
 69054                ".mpg",
 69055                ".mts",
 69056                ".mxf",
 69057                ".nrg",
 69058                ".nsv",
 69059                ".nuv",
 69060                ".ogg",
 69061                ".ogm",
 69062                ".ogv",
 69063                ".pva",
 69064                ".qt",
 69065                ".rec",
 69066                ".rm",
 69067                ".rmvb",
 69068                ".strm",
 69069                ".svq3",
 69070                ".tp",
 69071                ".ts",
 69072                ".ty",
 69073                ".viv",
 69074                ".vob",
 69075                ".vp3",
 69076                ".webm",
 69077                ".wmv",
 69078                ".wtv",
 69079                ".xvid"
 69080            ];
 81
 69082            VideoFlagDelimiters =
 69083            [
 69084                '(',
 69085                ')',
 69086                '-',
 69087                '.',
 69088                '_',
 69089                '[',
 69090                ']'
 69091            ];
 92
 69093            StubFileExtensions =
 69094            [
 69095                ".disc"
 69096            ];
 97
 69098            StubTypes =
 69099            [
 690100                new StubTypeRule(
 690101                    stubType: "dvd",
 690102                    token: "dvd"),
 690103
 690104                new StubTypeRule(
 690105                    stubType: "hddvd",
 690106                    token: "hddvd"),
 690107
 690108                new StubTypeRule(
 690109                    stubType: "bluray",
 690110                    token: "bluray"),
 690111
 690112                new StubTypeRule(
 690113                    stubType: "bluray",
 690114                    token: "brrip"),
 690115
 690116                new StubTypeRule(
 690117                    stubType: "bluray",
 690118                    token: "bd25"),
 690119
 690120                new StubTypeRule(
 690121                    stubType: "bluray",
 690122                    token: "bd50"),
 690123
 690124                new StubTypeRule(
 690125                    stubType: "vhs",
 690126                    token: "vhs"),
 690127
 690128                new StubTypeRule(
 690129                    stubType: "tv",
 690130                    token: "HDTV"),
 690131
 690132                new StubTypeRule(
 690133                    stubType: "tv",
 690134                    token: "PDTV"),
 690135
 690136                new StubTypeRule(
 690137                    stubType: "tv",
 690138                    token: "DSR")
 690139            ];
 140
 690141            VideoFileStackingRules =
 690142            [
 690143                new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])
 690144                new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])
 690145            ];
 146
 690147            CleanDateTimes =
 690148            [
 690149                @"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\
 690150                @"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\
 690151            ];
 152
 690153            CleanStrings =
 690154            [
 690155                @"^\s*(?<cleaned>.+?)[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|d
 690156                @"^\s*(?<cleaned>.+?)((\s*\[[^\]]+\]\s*)+)(\.[^\s]+)?$",
 690157                @"^\s*(?<cleaned>.+?)\WE[0-9]+(-|~)E?[0-9]+(\W|$)",
 690158                @"^\s*\[[^\]]+\](?!\.\w+$)\s*(?<cleaned>.+)",
 690159                @"^\s*(?<cleaned>.+?)\s+-\s+[0-9]+\s*$",
 690160                @"^\s*(?<cleaned>.+?)(([-._ ](trailer|sample))|-(scene|clip|behindthescenes|deleted|deletedscene|feature
 690161            ];
 162
 690163            SubtitleFileExtensions =
 690164            [
 690165                ".ass",
 690166                ".mks",
 690167                ".sami",
 690168                ".smi",
 690169                ".srt",
 690170                ".ssa",
 690171                ".sub",
 690172                ".sup",
 690173                ".vtt",
 690174            ];
 175
 690176            LyricFileExtensions =
 690177            [
 690178                ".lrc",
 690179                ".elrc",
 690180                ".txt"
 690181            ];
 182
 690183            AlbumStackingPrefixes =
 690184            [
 690185                "cd",
 690186                "digital media",
 690187                "disc",
 690188                "disk",
 690189                "vol",
 690190                "volume",
 690191                "part",
 690192                "act"
 690193            ];
 194
 690195            ArtistSubfolders =
 690196            [
 690197                "albums",
 690198                "broadcasts",
 690199                "bootlegs",
 690200                "compilations",
 690201                "dj-mixes",
 690202                "eps",
 690203                "live",
 690204                "mixtapes",
 690205                "others",
 690206                "remixes",
 690207                "singles",
 690208                "soundtracks",
 690209                "spokenwords",
 690210                "streets"
 690211            ];
 212
 690213            AudioFileExtensions =
 690214            [
 690215                ".669",
 690216                ".3gp",
 690217                ".aa",
 690218                ".aac",
 690219                ".aax",
 690220                ".ac3",
 690221                ".act",
 690222                ".adp",
 690223                ".adplug",
 690224                ".adx",
 690225                ".afc",
 690226                ".amf",
 690227                ".aif",
 690228                ".aifc",
 690229                ".aiff",
 690230                ".alac",
 690231                ".amr",
 690232                ".ape",
 690233                ".ast",
 690234                ".au",
 690235                ".awb",
 690236                ".cda",
 690237                ".cue",
 690238                ".dmf",
 690239                ".dsf",
 690240                ".dsm",
 690241                ".dsp",
 690242                ".dts",
 690243                ".dvf",
 690244                ".eac3",
 690245                ".ec3",
 690246                ".far",
 690247                ".flac",
 690248                ".gdm",
 690249                ".gsm",
 690250                ".gym",
 690251                ".hps",
 690252                ".imf",
 690253                ".it",
 690254                ".m15",
 690255                ".m4a",
 690256                ".m4b",
 690257                ".mac",
 690258                ".med",
 690259                ".mka",
 690260                ".mmf",
 690261                ".mod",
 690262                ".mogg",
 690263                ".mp2",
 690264                ".mp3",
 690265                ".mpa",
 690266                ".mpc",
 690267                ".mpp",
 690268                ".mp+",
 690269                ".msv",
 690270                ".nmf",
 690271                ".nsf",
 690272                ".nsv",
 690273                ".oga",
 690274                ".ogg",
 690275                ".okt",
 690276                ".opus",
 690277                ".pls",
 690278                ".ra",
 690279                ".rf64",
 690280                ".rm",
 690281                ".s3m",
 690282                ".sfx",
 690283                ".shn",
 690284                ".sid",
 690285                ".stm",
 690286                ".strm",
 690287                ".ult",
 690288                ".uni",
 690289                ".vox",
 690290                ".wav",
 690291                ".wma",
 690292                ".wv",
 690293                ".xm",
 690294                ".xsp",
 690295                ".ymf"
 690296            ];
 297
 690298            MediaFlagDelimiters =
 690299            [
 690300                '.'
 690301            ];
 302
 690303            MediaForcedFlags =
 690304            [
 690305                "foreign",
 690306                "forced"
 690307            ];
 308
 690309            MediaDefaultFlags =
 690310            [
 690311                "default"
 690312            ];
 313
 690314            MediaHearingImpairedFlags =
 690315            [
 690316                "cc",
 690317                "hi",
 690318                "sdh"
 690319            ];
 320
 690321            EpisodeExpressions =
 690322            [
 690323                // *** Begin Kodi Standard Naming
 690324                // <!-- foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02 -->
 690325                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+))[^\\\/])*)?[Ss](?<s
 690326                {
 690327                    IsNamed = true
 690328                },
 690329                // <!-- foo.ep01, foo.EP_01 -->
 690330                new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
 690331                // <!-- foo.E01., foo.e01. -->
 690332                new EpisodeExpression(@"[^\\/]*?()\.?[Ee]([0-9]+)\.([^\\/]*)$"),
 690333                new EpisodeExpression("(?<year>[0-9]{4})[._ -](?<month>[0-9]{2})[._ -](?<day>[0-9]{2})", true)
 690334                {
 690335                    DateTimeFormats =
 690336                    [
 690337                        "yyyy.MM.dd",
 690338                        "yyyy-MM-dd",
 690339                        "yyyy_MM_dd",
 690340                        "yyyy MM dd"
 690341                    ]
 690342                },
 690343                new EpisodeExpression("(?<day>[0-9]{2})[._ -](?<month>[0-9]{2})[._ -](?<year>[0-9]{4})", true)
 690344                {
 690345                    DateTimeFormats =
 690346                    [
 690347                        "dd.MM.yyyy",
 690348                        "dd-MM-yyyy",
 690349                        "dd_MM_yyyy",
 690350                        "dd MM yyyy"
 690351                    ]
 690352                },
 690353
 690354                // This isn't a Kodi naming rule, but the expression below causes false episode numbers for
 690355                // Title Season X Episode X naming schemes.
 690356                // "Series Season X Episode X - Title.avi", "Series S03 E09.avi", "s3 e9 - Title.avi"
 690357                new EpisodeExpression(@".*[\\\/]((?<seriesname>[^\\/]+?)\s)?[Ss](?:eason)?\s*(?<seasonnumber>[0-9]+)\s+[
 690358                {
 690359                    IsNamed = true
 690360                },
 690361
 690362                // Not a Kodi rule as well, but the expression below also causes false positives,
 690363                // so we make sure this one gets tested first.
 690364                // "Foo Bar 889"
 690365                new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,4})(-(?<endin
 690366                {
 690367                    IsNamed = true
 690368                },
 690369
 690370                new EpisodeExpression(@"[\\\/\._ \[\(-]([0-9]+)x([0-9]+(?:(?:[a-i]|\.[1-9])(?![0-9]))?)([^\\\/]*)$")
 690371                {
 690372                    SupportsAbsoluteEpisodeNumbers = true
 690373                },
 690374
 690375                // Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names
 690376                // [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the se
 690377                new EpisodeExpression(@".*[\\\/]?.*?(\[.*?\])+.*?(?<seriesname>[-\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+
 690378                {
 690379                    IsNamed = true
 690380                },
 690381
 690382                // "Name - 101.mkv", "Name - 101 [720p].mkv", "Name - 101 (2020).mkv"
 690383                // Handles absolute episode numbers with hyphen delimiter (common in anime)
 690384                // Without brackets (bracketed version handled above)
 690385                new EpisodeExpression(@".*[\\\/](?<seriesname>[^\\\/]+?)[\s_]+-[\s_]+(?<epnumber>[0-9]+)[\s_]*(?:\[.*?\]
 690386                {
 690387                    IsNamed = true
 690388                },
 690389
 690390                // /server/anything_102.mp4
 690391                // /server/james.corden.2017.04.20.anne.hathaway.720p.hdtv.x264-crooks.mkv
 690392                // /server/anything_1996.11.14.mp4
 690393                new EpisodeExpression(@"[\\/._ -](?<seriesname>(?![0-9]+[0-9][0-9])([^\\\/_])*)[\\\/._ -](?<seasonnumber
 690394                {
 690395                    IsOptimistic = true,
 690396                    IsNamed = true,
 690397                    SupportsAbsoluteEpisodeNumbers = false
 690398                },
 690399                new EpisodeExpression(@"[\/._ -]p(?:ar)?t[_. -]()([ivx]+|[0-9]+)([._ -][^\/]*)$")
 690400                {
 690401                    SupportsAbsoluteEpisodeNumbers = true
 690402                },
 690403
 690404                // *** End Kodi Standard Naming
 690405
 690406                // "Episode 16", "Episode 16 - Title"
 690407                new EpisodeExpression(@"[Ee]pisode (?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))?[^\\\/]*$")
 690408                {
 690409                    IsNamed = true
 690410                },
 690411
 690412                new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]+)[xX](?<epnumber>[0-9]+)[^\\\/]*$")
 690413                {
 690414                    IsNamed = true
 690415                },
 690416
 690417                new EpisodeExpression(@".*(\\|\/)[sS](?<seasonnumber>[0-9]+)[x,X]?[eE](?<epnumber>[0-9]+)[^\\\/]*$")
 690418                {
 690419                    IsNamed = true
 690420                },
 690421
 690422                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<sea
 690423                {
 690424                    IsNamed = true
 690425                },
 690426
 690427                new EpisodeExpression(@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epn
 690428                {
 690429                    IsNamed = true
 690430                },
 690431
 690432                // "01.avi"
 690433                new EpisodeExpression(@".*[\\\/](?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))*\.\w+$")
 690434                {
 690435                    IsOptimistic = true,
 690436                    IsNamed = true
 690437                },
 690438
 690439                // "1-12 episode title"
 690440                new EpisodeExpression("([0-9]+)-([0-9]+)"),
 690441
 690442                // "01 - blah.avi", "01-blah.avi"
 690443                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\s?-\s?[^\\\/]*
 690444                {
 690445                    IsOptimistic = true,
 690446                    IsNamed = true
 690447                },
 690448
 690449                // "01.blah.avi"
 690450                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\.[^\\\/]+$")
 690451                {
 690452                    IsOptimistic = true,
 690453                    IsNamed = true
 690454                },
 690455
 690456                // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi",
 690457                new EpisodeExpression(@".*[\\\/][^\\\/]* - (?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\
 690458                {
 690459                    IsOptimistic = true,
 690460                    IsNamed = true
 690461                },
 690462
 690463                // "01 episode title.avi"
 690464                new EpisodeExpression(@"[Ss]eason[\._ ](?<seasonnumber>[0-9]+)[\\\/](?<epnumber>[0-9]{1,3})([^\\\/]*)$")
 690465                {
 690466                    IsOptimistic = true,
 690467                    IsNamed = true
 690468                },
 690469
 690470                // Series and season only expression
 690471                // "the show/season 1", "the show/s01"
 690472                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)\/[Ss](eason)?[\. _\-]*(?<seasonnumber>[0-9]+)")
 690473                {
 690474                    IsNamed = true
 690475                },
 690476
 690477                // Series and season only expression
 690478                // "the show S01", "the show season 1"
 690479                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)[\. _\-]+[sS](eason)?[\. _\-]*(?<seasonnumber>[0-9]
 690480                {
 690481                    IsNamed = true
 690482                },
 690483
 690484                // Anime style expression
 690485                // "[Group][Series Name][21][1080p][FLAC][HASH]"
 690486                // "[Group] Series Name [04][BDRIP]"
 690487                new EpisodeExpression(@"(?:\[(?:[^\]]+)\]\s*)?(?<seriesname>\[[^\]]+\]|[^[\]]+)\s*\[(?<epnumber>[0-9]+)\
 690488                {
 690489                    IsNamed = true
 690490                },
 690491            ];
 492
 690493            VideoExtraRules =
 690494            [
 690495                new ExtraRule(
 690496                    ExtraType.Trailer,
 690497                    ExtraRuleType.DirectoryName,
 690498                    "trailers",
 690499                    MediaType.Video),
 690500
 690501                new ExtraRule(
 690502                    ExtraType.ThemeVideo,
 690503                    ExtraRuleType.DirectoryName,
 690504                    "backdrops",
 690505                    MediaType.Video),
 690506
 690507                new ExtraRule(
 690508                    ExtraType.ThemeSong,
 690509                    ExtraRuleType.DirectoryName,
 690510                    "theme-music",
 690511                    MediaType.Audio),
 690512
 690513                new ExtraRule(
 690514                    ExtraType.BehindTheScenes,
 690515                    ExtraRuleType.DirectoryName,
 690516                    "behind the scenes",
 690517                    MediaType.Video),
 690518
 690519                new ExtraRule(
 690520                    ExtraType.DeletedScene,
 690521                    ExtraRuleType.DirectoryName,
 690522                    "deleted scenes",
 690523                    MediaType.Video),
 690524
 690525                new ExtraRule(
 690526                    ExtraType.Interview,
 690527                    ExtraRuleType.DirectoryName,
 690528                    "interviews",
 690529                    MediaType.Video),
 690530
 690531                new ExtraRule(
 690532                    ExtraType.Scene,
 690533                    ExtraRuleType.DirectoryName,
 690534                    "scenes",
 690535                    MediaType.Video),
 690536
 690537                new ExtraRule(
 690538                    ExtraType.Sample,
 690539                    ExtraRuleType.DirectoryName,
 690540                    "samples",
 690541                    MediaType.Video),
 690542
 690543                new ExtraRule(
 690544                    ExtraType.Short,
 690545                    ExtraRuleType.DirectoryName,
 690546                    "shorts",
 690547                    MediaType.Video),
 690548
 690549                new ExtraRule(
 690550                    ExtraType.Featurette,
 690551                    ExtraRuleType.DirectoryName,
 690552                    "featurettes",
 690553                    MediaType.Video),
 690554
 690555                new ExtraRule(
 690556                    ExtraType.Unknown,
 690557                    ExtraRuleType.DirectoryName,
 690558                    "extras",
 690559                    MediaType.Video),
 690560
 690561                new ExtraRule(
 690562                    ExtraType.Unknown,
 690563                    ExtraRuleType.DirectoryName,
 690564                    "extra",
 690565                    MediaType.Video),
 690566
 690567                new ExtraRule(
 690568                    ExtraType.Unknown,
 690569                    ExtraRuleType.DirectoryName,
 690570                    "other",
 690571                    MediaType.Video),
 690572
 690573                new ExtraRule(
 690574                    ExtraType.Clip,
 690575                    ExtraRuleType.DirectoryName,
 690576                    "clips",
 690577                    MediaType.Video),
 690578
 690579                new ExtraRule(
 690580                    ExtraType.Trailer,
 690581                    ExtraRuleType.Filename,
 690582                    "trailer",
 690583                    MediaType.Video),
 690584
 690585                new ExtraRule(
 690586                    ExtraType.Sample,
 690587                    ExtraRuleType.Filename,
 690588                    "sample",
 690589                    MediaType.Video),
 690590
 690591                new ExtraRule(
 690592                    ExtraType.ThemeSong,
 690593                    ExtraRuleType.Filename,
 690594                    "theme",
 690595                    MediaType.Audio),
 690596
 690597                new ExtraRule(
 690598                    ExtraType.Trailer,
 690599                    ExtraRuleType.Suffix,
 690600                    "-trailer",
 690601                    MediaType.Video),
 690602
 690603                new ExtraRule(
 690604                    ExtraType.Trailer,
 690605                    ExtraRuleType.Suffix,
 690606                    ".trailer",
 690607                    MediaType.Video),
 690608
 690609                new ExtraRule(
 690610                    ExtraType.Trailer,
 690611                    ExtraRuleType.Suffix,
 690612                    "_trailer",
 690613                    MediaType.Video),
 690614
 690615                new ExtraRule(
 690616                    ExtraType.Trailer,
 690617                    ExtraRuleType.Suffix,
 690618                    "- trailer",
 690619                    MediaType.Video),
 690620
 690621                new ExtraRule(
 690622                    ExtraType.Sample,
 690623                    ExtraRuleType.Suffix,
 690624                    "-sample",
 690625                    MediaType.Video),
 690626
 690627                new ExtraRule(
 690628                    ExtraType.Sample,
 690629                    ExtraRuleType.Suffix,
 690630                    ".sample",
 690631                    MediaType.Video),
 690632
 690633                new ExtraRule(
 690634                    ExtraType.Sample,
 690635                    ExtraRuleType.Suffix,
 690636                    "_sample",
 690637                    MediaType.Video),
 690638
 690639                new ExtraRule(
 690640                    ExtraType.Sample,
 690641                    ExtraRuleType.Suffix,
 690642                    "- sample",
 690643                    MediaType.Video),
 690644
 690645                new ExtraRule(
 690646                    ExtraType.Scene,
 690647                    ExtraRuleType.Suffix,
 690648                    "-scene",
 690649                    MediaType.Video),
 690650
 690651                new ExtraRule(
 690652                    ExtraType.Clip,
 690653                    ExtraRuleType.Suffix,
 690654                    "-clip",
 690655                    MediaType.Video),
 690656
 690657                new ExtraRule(
 690658                    ExtraType.Interview,
 690659                    ExtraRuleType.Suffix,
 690660                    "-interview",
 690661                    MediaType.Video),
 690662
 690663                new ExtraRule(
 690664                    ExtraType.BehindTheScenes,
 690665                    ExtraRuleType.Suffix,
 690666                    "-behindthescenes",
 690667                    MediaType.Video),
 690668
 690669                new ExtraRule(
 690670                    ExtraType.DeletedScene,
 690671                    ExtraRuleType.Suffix,
 690672                    "-deleted",
 690673                    MediaType.Video),
 690674
 690675                new ExtraRule(
 690676                    ExtraType.DeletedScene,
 690677                    ExtraRuleType.Suffix,
 690678                    "-deletedscene",
 690679                    MediaType.Video),
 690680
 690681                new ExtraRule(
 690682                    ExtraType.Featurette,
 690683                    ExtraRuleType.Suffix,
 690684                    "-featurette",
 690685                    MediaType.Video),
 690686
 690687                new ExtraRule(
 690688                    ExtraType.Short,
 690689                    ExtraRuleType.Suffix,
 690690                    "-short",
 690691                    MediaType.Video),
 690692
 690693                new ExtraRule(
 690694                    ExtraType.Unknown,
 690695                    ExtraRuleType.Suffix,
 690696                    "-extra",
 690697                    MediaType.Video),
 690698
 690699                new ExtraRule(
 690700                    ExtraType.Unknown,
 690701                    ExtraRuleType.Suffix,
 690702                    "-other",
 690703                    MediaType.Video)
 690704            ];
 705
 690706            AllExtrasTypesFolderNames = VideoExtraRules
 690707                .Where(i => i.RuleType == ExtraRuleType.DirectoryName)
 690708                .ToDictionary(i => i.Token, i => i.ExtraType, StringComparer.OrdinalIgnoreCase);
 709
 690710            Format3DRules =
 690711            [
 690712                // Kodi rules:
 690713                new Format3DRule(
 690714                    precedingToken: "3d",
 690715                    token: "hsbs"),
 690716
 690717                new Format3DRule(
 690718                    precedingToken: "3d",
 690719                    token: "sbs"),
 690720
 690721                new Format3DRule(
 690722                    precedingToken: "3d",
 690723                    token: "htab"),
 690724
 690725                new Format3DRule(
 690726                    precedingToken: "3d",
 690727                    token: "tab"),
 690728
 690729                 // Media Browser rules:
 690730                new Format3DRule("fsbs"),
 690731                new Format3DRule("hsbs"),
 690732                new Format3DRule("sbs"),
 690733                new Format3DRule("ftab"),
 690734                new Format3DRule("htab"),
 690735                new Format3DRule("tab"),
 690736                new Format3DRule("sbs3d"),
 690737                new Format3DRule("mvc")
 690738            ];
 739
 690740            AudioBookPartsExpressions =
 690741            [
 690742                // Detect specified chapters, like CH 01
 690743                @"ch(?:apter)?[\s_-]?(?<chapter>[0-9]+)",
 690744                // Detect specified parts, like Part 02
 690745                @"p(?:ar)?t[\s_-]?(?<part>[0-9]+)",
 690746                // Chapter is often beginning of filename
 690747                "^(?<chapter>[0-9]+)",
 690748                // Part if often ending of filename
 690749                "(?<!ch(?:apter) )(?<part>[0-9]+)$",
 690750                // Sometimes named as 0001_005 (chapter_part)
 690751                "(?<chapter>[0-9]+)_(?<part>[0-9]+)",
 690752                // Some audiobooks are ripped from cd's, and will be named by disk number.
 690753                @"dis(?:c|k)[\s_-]?(?<chapter>[0-9]+)"
 690754            ];
 755
 690756            AudioBookNamesExpressions =
 690757            [
 690758                // Detect year usually in brackets after name Batman (2020)
 690759                @"^(?<name>.+?)\s*\(\s*(?<year>[0-9]{4})\s*\)\s*$",
 690760                @"^\s*(?<name>[^ ].*?)\s*$"
 690761            ];
 762
 690763            MultipleEpisodeExpressions = new[]
 690764            {
 690765                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[eExX](?<endinge
 690766                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[xX][eE](?<endin
 690767                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )?[xXeE](?<endingepnumber>[
 690768                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})(-[xE]?[eE]?(?<endingepnumber>[0-9
 690769                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 690770                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 690771                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 690772                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 690773                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})((-| 
 690774                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})(-[xX
 690775            }.Select(i => new EpisodeExpression(i)
 690776            {
 690777                IsNamed = true
 690778            }).ToArray();
 779
 690780            Compile();
 690781        }
 782
 783        /// <summary>
 784        /// Gets or sets the folder name to extra types mapping.
 785        /// </summary>
 786        public Dictionary<string, ExtraType> AllExtrasTypesFolderNames { get; set; }
 787
 788        /// <summary>
 789        /// Gets or sets list of audio file extensions.
 790        /// </summary>
 791        public string[] AudioFileExtensions { get; set; }
 792
 793        /// <summary>
 794        /// Gets or sets list of external media flag delimiters.
 795        /// </summary>
 796        public char[] MediaFlagDelimiters { get; set; }
 797
 798        /// <summary>
 799        /// Gets or sets list of external media forced flags.
 800        /// </summary>
 801        public string[] MediaForcedFlags { get; set; }
 802
 803        /// <summary>
 804        /// Gets or sets list of external media default flags.
 805        /// </summary>
 806        public string[] MediaDefaultFlags { get; set; }
 807
 808        /// <summary>
 809        /// Gets or sets list of external media hearing impaired flags.
 810        /// </summary>
 811        public string[] MediaHearingImpairedFlags { get; set; }
 812
 813        /// <summary>
 814        /// Gets or sets list of album stacking prefixes.
 815        /// </summary>
 816        public string[] AlbumStackingPrefixes { get; set; }
 817
 818        /// <summary>
 819        /// Gets or sets list of artist subfolders.
 820        /// </summary>
 821        public string[] ArtistSubfolders { get; set; }
 822
 823        /// <summary>
 824        /// Gets or sets list of subtitle file extensions.
 825        /// </summary>
 826        public string[] SubtitleFileExtensions { get; set; }
 827
 828        /// <summary>
 829        /// Gets the list of lyric file extensions.
 830        /// </summary>
 831        public string[] LyricFileExtensions { get; }
 832
 833        /// <summary>
 834        /// Gets or sets list of episode regular expressions.
 835        /// </summary>
 836        public EpisodeExpression[] EpisodeExpressions { get; set; }
 837
 838        /// <summary>
 839        /// Gets or sets list of video file extensions.
 840        /// </summary>
 841        public string[] VideoFileExtensions { get; set; }
 842
 843        /// <summary>
 844        /// Gets or sets list of video stub file extensions.
 845        /// </summary>
 846        public string[] StubFileExtensions { get; set; }
 847
 848        /// <summary>
 849        /// Gets or sets list of raw audiobook parts regular expressions strings.
 850        /// </summary>
 851        public string[] AudioBookPartsExpressions { get; set; }
 852
 853        /// <summary>
 854        /// Gets or sets list of raw audiobook names regular expressions strings.
 855        /// </summary>
 856        public string[] AudioBookNamesExpressions { get; set; }
 857
 858        /// <summary>
 859        /// Gets or sets list of stub type rules.
 860        /// </summary>
 861        public StubTypeRule[] StubTypes { get; set; }
 862
 863        /// <summary>
 864        /// Gets or sets list of video flag delimiters.
 865        /// </summary>
 866        public char[] VideoFlagDelimiters { get; set; }
 867
 868        /// <summary>
 869        /// Gets or sets list of 3D Format rules.
 870        /// </summary>
 871        public Format3DRule[] Format3DRules { get; set; }
 872
 873        /// <summary>
 874        /// Gets the file stacking rules.
 875        /// </summary>
 876        public FileStackRule[] VideoFileStackingRules { get; }
 877
 878        /// <summary>
 879        /// Gets or sets list of raw clean DateTimes regular expressions strings.
 880        /// </summary>
 881        public string[] CleanDateTimes { get; set; }
 882
 883        /// <summary>
 884        /// Gets or sets list of raw clean strings regular expressions strings.
 885        /// </summary>
 886        public string[] CleanStrings { get; set; }
 887
 888        /// <summary>
 889        /// Gets or sets list of multi-episode regular expressions.
 890        /// </summary>
 891        public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
 892
 893        /// <summary>
 894        /// Gets or sets list of extra rules for videos.
 895        /// </summary>
 896        public ExtraRule[] VideoExtraRules { get; set; }
 897
 898        /// <summary>
 899        /// Gets list of clean datetime regular expressions.
 900        /// </summary>
 901        public Regex[] CleanDateTimeRegexes { get; private set; } = [];
 902
 903        /// <summary>
 904        /// Gets list of clean string regular expressions.
 905        /// </summary>
 906        public Regex[] CleanStringRegexes { get; private set; } = [];
 907
 908        /// <summary>
 909        /// Compiles raw regex strings into regexes.
 910        /// </summary>
 911        public void Compile()
 912        {
 691913            CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray();
 691914            CleanStringRegexes = CleanStrings.Select(Compile).ToArray();
 691915        }
 916
 917        private Regex Compile(string exp)
 918        {
 5528919            return new Regex(exp, RegexOptions.IgnoreCase | RegexOptions.Compiled);
 920        }
 921    }
 922}