< 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: 747
Uncovered lines: 0
Coverable lines: 747
Total lines: 930
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 5/16/2026 - 12:15:55 AM Line coverage: 100% (739/739) Total lines: 9227/26/2026 - 12:17:51 AM Line coverage: 100% (741/741) Total lines: 92410/29/2026 - 12:17:11 AM Line coverage: 100% (747/747) Total lines: 930

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        {
 80424            VideoFileExtensions =
 80425            [
 80426                ".001",
 80427                ".3g2",
 80428                ".3gp",
 80429                ".amv",
 80430                ".asf",
 80431                ".asx",
 80432                ".avi",
 80433                ".bin",
 80434                ".bivx",
 80435                ".divx",
 80436                ".dv",
 80437                ".dvr-ms",
 80438                ".f4v",
 80439                ".fli",
 80440                ".flv",
 80441                ".ifo",
 80442                ".img",
 80443                ".iso",
 80444                ".m2t",
 80445                ".m2ts",
 80446                ".m2v",
 80447                ".m4v",
 80448                ".mkv",
 80449                ".mk3d",
 80450                ".mov",
 80451                ".mp4",
 80452                ".mpe",
 80453                ".mpeg",
 80454                ".mpg",
 80455                ".mts",
 80456                ".mxf",
 80457                ".nrg",
 80458                ".nsv",
 80459                ".nuv",
 80460                ".ogm",
 80461                ".ogv",
 80462                ".pva",
 80463                ".qt",
 80464                ".rec",
 80465                ".rm",
 80466                ".rmvb",
 80467                ".strm",
 80468                ".svq3",
 80469                ".tp",
 80470                ".ts",
 80471                ".ty",
 80472                ".viv",
 80473                ".vob",
 80474                ".vp3",
 80475                ".webm",
 80476                ".wmv",
 80477                ".wtv",
 80478                ".xvid"
 80479            ];
 80
 80481            VideoFlagDelimiters =
 80482            [
 80483                '(',
 80484                ')',
 80485                '-',
 80486                '.',
 80487                '_',
 80488                '[',
 80489                ']'
 80490            ];
 91
 80492            StubFileExtensions =
 80493            [
 80494                ".disc"
 80495            ];
 96
 80497            StubTypes =
 80498            [
 80499                new StubTypeRule(
 804100                    stubType: "dvd",
 804101                    token: "dvd"),
 804102
 804103                new StubTypeRule(
 804104                    stubType: "hddvd",
 804105                    token: "hddvd"),
 804106
 804107                new StubTypeRule(
 804108                    stubType: "bluray",
 804109                    token: "bluray"),
 804110
 804111                new StubTypeRule(
 804112                    stubType: "bluray",
 804113                    token: "brrip"),
 804114
 804115                new StubTypeRule(
 804116                    stubType: "bluray",
 804117                    token: "bd25"),
 804118
 804119                new StubTypeRule(
 804120                    stubType: "bluray",
 804121                    token: "bd50"),
 804122
 804123                new StubTypeRule(
 804124                    stubType: "vhs",
 804125                    token: "vhs"),
 804126
 804127                new StubTypeRule(
 804128                    stubType: "tv",
 804129                    token: "HDTV"),
 804130
 804131                new StubTypeRule(
 804132                    stubType: "tv",
 804133                    token: "PDTV"),
 804134
 804135                new StubTypeRule(
 804136                    stubType: "tv",
 804137                    token: "DSR")
 804138            ];
 139
 804140            VideoFileStackingRules =
 804141            [
 804142                new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])
 804143                new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])
 804144            ];
 145
 804146            CleanDateTimes =
 804147            [
 804148                @"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\
 804149                @"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\
 804150            ];
 151
 804152            CleanStrings =
 804153            [
 804154                @"^\s*(?<cleaned>.+?)[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|d
 804155                @"^\s*(?<cleaned>.+?)((\s*\[[^\]]+\]\s*)+)(\.[^\s]+)?$",
 804156                @"^\s*(?<cleaned>.+?)\WE[0-9]+(-|~)E?[0-9]+(\W|$)",
 804157                @"^\s*\[[^\]]+\](?!\.\w+$)\s*(?<cleaned>.+)",
 804158                @"^\s*(?<cleaned>.+?)\s+-\s+[0-9]+\s*$",
 804159                @"^\s*(?<cleaned>.+?)(([-._ ](trailer|sample))|-(scene|clip|behindthescenes|deleted|deletedscene|feature
 804160            ];
 161
 804162            SubtitleFileExtensions =
 804163            [
 804164                ".ass",
 804165                ".mks",
 804166                ".sami",
 804167                ".smi",
 804168                ".srt",
 804169                ".ssa",
 804170                ".sub",
 804171                ".sup",
 804172                ".vtt",
 804173            ];
 174
 804175            LyricFileExtensions =
 804176            [
 804177                ".lrc",
 804178                ".elrc",
 804179                ".txt"
 804180            ];
 181
 804182            AlbumStackingPrefixes =
 804183            [
 804184                "cd",
 804185                "digital media",
 804186                "disc",
 804187                "disk",
 804188                "vol",
 804189                "volume",
 804190                "part",
 804191                "act"
 804192            ];
 193
 804194            ArtistSubfolders =
 804195            [
 804196                "albums",
 804197                "broadcasts",
 804198                "bootlegs",
 804199                "compilations",
 804200                "dj-mixes",
 804201                "eps",
 804202                "live",
 804203                "mixtapes",
 804204                "others",
 804205                "remixes",
 804206                "singles",
 804207                "soundtracks",
 804208                "spokenwords",
 804209                "streets"
 804210            ];
 211
 804212            AudioFileExtensions =
 804213            [
 804214                ".669",
 804215                ".3gp",
 804216                ".aa",
 804217                ".aac",
 804218                ".aax",
 804219                ".ac3",
 804220                ".act",
 804221                ".adp",
 804222                ".adplug",
 804223                ".adx",
 804224                ".afc",
 804225                ".amf",
 804226                ".aif",
 804227                ".aifc",
 804228                ".aiff",
 804229                ".alac",
 804230                ".amr",
 804231                ".ape",
 804232                ".ast",
 804233                ".au",
 804234                ".awb",
 804235                ".cda",
 804236                ".cue",
 804237                ".dmf",
 804238                ".dsf",
 804239                ".dsm",
 804240                ".dsp",
 804241                ".dts",
 804242                ".dvf",
 804243                ".eac3",
 804244                ".ec3",
 804245                ".far",
 804246                ".flac",
 804247                ".gdm",
 804248                ".gsm",
 804249                ".gym",
 804250                ".hps",
 804251                ".imf",
 804252                ".it",
 804253                ".m15",
 804254                ".m4a",
 804255                ".m4b",
 804256                ".mac",
 804257                ".med",
 804258                ".mka",
 804259                ".mmf",
 804260                ".mod",
 804261                ".mogg",
 804262                ".mp2",
 804263                ".mp3",
 804264                ".mpa",
 804265                ".mpc",
 804266                ".mpp",
 804267                ".mp+",
 804268                ".msv",
 804269                ".nmf",
 804270                ".nsf",
 804271                ".nsv",
 804272                ".oga",
 804273                ".ogg",
 804274                ".okt",
 804275                ".opus",
 804276                ".pls",
 804277                ".ra",
 804278                ".rf64",
 804279                ".rm",
 804280                ".s3m",
 804281                ".sfx",
 804282                ".shn",
 804283                ".sid",
 804284                ".stm",
 804285                ".strm",
 804286                ".ult",
 804287                ".uni",
 804288                ".vox",
 804289                ".wav",
 804290                ".wma",
 804291                ".wv",
 804292                ".xm",
 804293                ".xsp",
 804294                ".ymf"
 804295            ];
 296
 804297            MediaFlagDelimiters =
 804298            [
 804299                '.'
 804300            ];
 301
 804302            MediaForcedFlags =
 804303            [
 804304                "foreign",
 804305                "forced"
 804306            ];
 307
 804308            MediaDefaultFlags =
 804309            [
 804310                "default"
 804311            ];
 312
 804313            MediaHearingImpairedFlags =
 804314            [
 804315                "cc",
 804316                "hi",
 804317                "sdh"
 804318            ];
 319
 804320            EpisodeExpressions =
 804321            [
 804322                // *** Begin Kodi Standard Naming
 804323                // <!-- foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02 -->
 804324                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+))[^\\\/])*)?[Ss](?<s
 804325                {
 804326                    IsNamed = true
 804327                },
 804328                // <!-- foo.ep01, foo.EP_01 -->
 804329                new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
 804330                // <!-- foo.E01., foo.e01. -->
 804331                new EpisodeExpression(@"[^\\/]*?()\.?[Ee]([0-9]+)\.([^\\/]*)$"),
 804332                new EpisodeExpression("(?<year>[0-9]{4})[._ -](?<month>[0-9]{2})[._ -](?<day>[0-9]{2})", true)
 804333                {
 804334                    DateTimeFormats =
 804335                    [
 804336                        "yyyy.MM.dd",
 804337                        "yyyy-MM-dd",
 804338                        "yyyy_MM_dd",
 804339                        "yyyy MM dd"
 804340                    ]
 804341                },
 804342                new EpisodeExpression("(?<day>[0-9]{2})[._ -](?<month>[0-9]{2})[._ -](?<year>[0-9]{4})", true)
 804343                {
 804344                    DateTimeFormats =
 804345                    [
 804346                        "dd.MM.yyyy",
 804347                        "dd-MM-yyyy",
 804348                        "dd_MM_yyyy",
 804349                        "dd MM yyyy"
 804350                    ]
 804351                },
 804352
 804353                // This isn't a Kodi naming rule, but the expression below causes false episode numbers for
 804354                // Title Season X Episode X naming schemes.
 804355                // "Series Season X Episode X - Title.avi", "Series S03 E09.avi", "s3 e9 - Title.avi"
 804356                new EpisodeExpression(@".*[\\\/]((?<seriesname>[^\\/]+?)\s)?[Ss](?:eason)?\s*(?<seasonnumber>[0-9]+)\s+[
 804357                {
 804358                    IsNamed = true
 804359                },
 804360
 804361                // Not a Kodi rule as well, but the expression below also causes false positives,
 804362                // so we make sure this one gets tested first.
 804363                // "Foo Bar 889"
 804364                // Names carrying an SxxEyy marker are excluded because the Kodi expression above already covers them.
 804365                // Without that guard this expression reads digits out of the title instead, turning
 804366                // "S01E01 1-23-45 [Bluray-1080p]" into episodes 1 through 45.
 804367                new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?![^\\\/]*[Ss][0-9]+[][ ._-]*[Ee][0-9]+)(?<seriesname>[\w
 804368                {
 804369                    IsNamed = true
 804370                },
 804371
 804372                new EpisodeExpression(@"[\\\/\._ \[\(-]([0-9]+)x([0-9]+(?:(?:[a-i]|\.[1-9])(?![0-9]))?)([^\\\/]*)$")
 804373                {
 804374                    SupportsAbsoluteEpisodeNumbers = true
 804375                },
 804376
 804377                // Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names
 804378                // [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the se
 804379                new EpisodeExpression(@".*[\\\/]?.*?(\[.*?\])+.*?(?<seriesname>[-\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+
 804380                {
 804381                    IsNamed = true
 804382                },
 804383
 804384                // "Name - 101.mkv", "Name - 101 [720p].mkv", "Name - 101 (2020).mkv"
 804385                // Handles absolute episode numbers with hyphen delimiter (common in anime)
 804386                // Without brackets (bracketed version handled above)
 804387                new EpisodeExpression(@".*[\\\/](?<seriesname>[^\\\/]+?)[\s_]+-[\s_]+(?<epnumber>[0-9]+)[\s_]*(?:\[.*?\]
 804388                {
 804389                    IsNamed = true
 804390                },
 804391
 804392                // /server/anything_102.mp4
 804393                // /server/james.corden.2017.04.20.anne.hathaway.720p.hdtv.x264-crooks.mkv
 804394                // /server/anything_1996.11.14.mp4
 804395                new EpisodeExpression(@"[\\/._ -](?<seriesname>(?![0-9]+[0-9][0-9])([^\\\/_])*)[\\\/._ -](?<seasonnumber
 804396                {
 804397                    IsOptimistic = true,
 804398                    IsNamed = true,
 804399                    SupportsAbsoluteEpisodeNumbers = false
 804400                },
 804401                new EpisodeExpression(@"[\/._ -]p(?:ar)?t[_. -]()([ivx]+|[0-9]+)([._ -][^\/]*)$")
 804402                {
 804403                    SupportsAbsoluteEpisodeNumbers = true
 804404                },
 804405
 804406                // *** End Kodi Standard Naming
 804407
 804408                // "Episode 16", "Episode 16 - Title"
 804409                new EpisodeExpression(@"[Ee]pisode (?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))?[^\\\/]*$")
 804410                {
 804411                    IsNamed = true
 804412                },
 804413
 804414                new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]+)[xX](?<epnumber>[0-9]+)[^\\\/]*$")
 804415                {
 804416                    IsNamed = true
 804417                },
 804418
 804419                new EpisodeExpression(@".*(\\|\/)[sS](?<seasonnumber>[0-9]+)[x,X]?[eE](?<epnumber>[0-9]+)[^\\\/]*$")
 804420                {
 804421                    IsNamed = true
 804422                },
 804423
 804424                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<sea
 804425                {
 804426                    IsNamed = true
 804427                },
 804428
 804429                new EpisodeExpression(@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epn
 804430                {
 804431                    IsNamed = true
 804432                },
 804433
 804434                // "01.avi"
 804435                new EpisodeExpression(@".*[\\\/](?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))*\.\w+$")
 804436                {
 804437                    IsOptimistic = true,
 804438                    IsNamed = true
 804439                },
 804440
 804441                // "1-12 episode title"
 804442                new EpisodeExpression("([0-9]+)-([0-9]+)"),
 804443
 804444                // "01 - blah.avi", "01-blah.avi"
 804445                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\s?-\s?[^\\\/]*
 804446                {
 804447                    IsOptimistic = true,
 804448                    IsNamed = true
 804449                },
 804450
 804451                // "01.blah.avi"
 804452                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\.[^\\\/]+$")
 804453                {
 804454                    IsOptimistic = true,
 804455                    IsNamed = true
 804456                },
 804457
 804458                // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi",
 804459                new EpisodeExpression(@".*[\\\/][^\\\/]* - (?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\
 804460                {
 804461                    IsOptimistic = true,
 804462                    IsNamed = true
 804463                },
 804464
 804465                // "01 episode title.avi"
 804466                new EpisodeExpression(@"[Ss]eason[\._ ](?<seasonnumber>[0-9]+)[\\\/](?<epnumber>[0-9]{1,3})([^\\\/]*)$")
 804467                {
 804468                    IsOptimistic = true,
 804469                    IsNamed = true
 804470                },
 804471
 804472                // Series and season only expression
 804473                // "the show/season 1", "the show/s01"
 804474                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)\/[Ss](eason)?[\. _\-]*(?<seasonnumber>[0-9]+)")
 804475                {
 804476                    IsNamed = true
 804477                },
 804478
 804479                // Series and season only expression
 804480                // "the show S01", "the show season 1"
 804481                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)[\. _\-]+[sS](eason)?[\. _\-]*(?<seasonnumber>[0-9]
 804482                {
 804483                    IsNamed = true
 804484                },
 804485
 804486                // Anime style expression
 804487                // "[Group][Series Name][21][1080p][FLAC][HASH]"
 804488                // "[Group] Series Name [04][BDRIP]"
 804489                new EpisodeExpression(@"(?:\[(?:[^\]]+)\]\s*)?(?<seriesname>\[[^\]]+\]|[^[\]]+)\s*\[(?<epnumber>[0-9]+)\
 804490                {
 804491                    IsNamed = true
 804492                },
 804493            ];
 494
 804495            VideoExtraRules =
 804496            [
 804497                new ExtraRule(
 804498                    ExtraType.Trailer,
 804499                    ExtraRuleType.DirectoryName,
 804500                    "trailers",
 804501                    MediaType.Video),
 804502
 804503                new ExtraRule(
 804504                    ExtraType.ThemeVideo,
 804505                    ExtraRuleType.DirectoryName,
 804506                    "backdrops",
 804507                    MediaType.Video),
 804508
 804509                new ExtraRule(
 804510                    ExtraType.ThemeSong,
 804511                    ExtraRuleType.DirectoryName,
 804512                    "theme-music",
 804513                    MediaType.Audio),
 804514
 804515                new ExtraRule(
 804516                    ExtraType.BehindTheScenes,
 804517                    ExtraRuleType.DirectoryName,
 804518                    "behind the scenes",
 804519                    MediaType.Video),
 804520
 804521                new ExtraRule(
 804522                    ExtraType.DeletedScene,
 804523                    ExtraRuleType.DirectoryName,
 804524                    "deleted scenes",
 804525                    MediaType.Video),
 804526
 804527                new ExtraRule(
 804528                    ExtraType.Interview,
 804529                    ExtraRuleType.DirectoryName,
 804530                    "interviews",
 804531                    MediaType.Video),
 804532
 804533                new ExtraRule(
 804534                    ExtraType.Scene,
 804535                    ExtraRuleType.DirectoryName,
 804536                    "scenes",
 804537                    MediaType.Video),
 804538
 804539                new ExtraRule(
 804540                    ExtraType.Sample,
 804541                    ExtraRuleType.DirectoryName,
 804542                    "samples",
 804543                    MediaType.Video),
 804544
 804545                new ExtraRule(
 804546                    ExtraType.Sample,
 804547                    ExtraRuleType.DirectoryName,
 804548                    "sample",
 804549                    MediaType.Video),
 804550
 804551                new ExtraRule(
 804552                    ExtraType.Short,
 804553                    ExtraRuleType.DirectoryName,
 804554                    "shorts",
 804555                    MediaType.Video),
 804556
 804557                new ExtraRule(
 804558                    ExtraType.Featurette,
 804559                    ExtraRuleType.DirectoryName,
 804560                    "featurettes",
 804561                    MediaType.Video),
 804562
 804563                new ExtraRule(
 804564                    ExtraType.Unknown,
 804565                    ExtraRuleType.DirectoryName,
 804566                    "extras",
 804567                    MediaType.Video),
 804568
 804569                new ExtraRule(
 804570                    ExtraType.Unknown,
 804571                    ExtraRuleType.DirectoryName,
 804572                    "extra",
 804573                    MediaType.Video),
 804574
 804575                new ExtraRule(
 804576                    ExtraType.Unknown,
 804577                    ExtraRuleType.DirectoryName,
 804578                    "other",
 804579                    MediaType.Video),
 804580
 804581                new ExtraRule(
 804582                    ExtraType.Clip,
 804583                    ExtraRuleType.DirectoryName,
 804584                    "clips",
 804585                    MediaType.Video),
 804586
 804587                new ExtraRule(
 804588                    ExtraType.Trailer,
 804589                    ExtraRuleType.Filename,
 804590                    "trailer",
 804591                    MediaType.Video),
 804592
 804593                new ExtraRule(
 804594                    ExtraType.Sample,
 804595                    ExtraRuleType.Filename,
 804596                    "sample",
 804597                    MediaType.Video),
 804598
 804599                new ExtraRule(
 804600                    ExtraType.ThemeSong,
 804601                    ExtraRuleType.Filename,
 804602                    "theme",
 804603                    MediaType.Audio),
 804604
 804605                new ExtraRule(
 804606                    ExtraType.Trailer,
 804607                    ExtraRuleType.Suffix,
 804608                    "-trailer",
 804609                    MediaType.Video),
 804610
 804611                new ExtraRule(
 804612                    ExtraType.Trailer,
 804613                    ExtraRuleType.Suffix,
 804614                    ".trailer",
 804615                    MediaType.Video),
 804616
 804617                new ExtraRule(
 804618                    ExtraType.Trailer,
 804619                    ExtraRuleType.Suffix,
 804620                    "_trailer",
 804621                    MediaType.Video),
 804622
 804623                new ExtraRule(
 804624                    ExtraType.Trailer,
 804625                    ExtraRuleType.Suffix,
 804626                    "- trailer",
 804627                    MediaType.Video),
 804628
 804629                new ExtraRule(
 804630                    ExtraType.Sample,
 804631                    ExtraRuleType.Suffix,
 804632                    "-sample",
 804633                    MediaType.Video),
 804634
 804635                new ExtraRule(
 804636                    ExtraType.Sample,
 804637                    ExtraRuleType.Suffix,
 804638                    ".sample",
 804639                    MediaType.Video),
 804640
 804641                new ExtraRule(
 804642                    ExtraType.Sample,
 804643                    ExtraRuleType.Suffix,
 804644                    "_sample",
 804645                    MediaType.Video),
 804646
 804647                new ExtraRule(
 804648                    ExtraType.Sample,
 804649                    ExtraRuleType.Suffix,
 804650                    "- sample",
 804651                    MediaType.Video),
 804652
 804653                new ExtraRule(
 804654                    ExtraType.Scene,
 804655                    ExtraRuleType.Suffix,
 804656                    "-scene",
 804657                    MediaType.Video),
 804658
 804659                new ExtraRule(
 804660                    ExtraType.Clip,
 804661                    ExtraRuleType.Suffix,
 804662                    "-clip",
 804663                    MediaType.Video),
 804664
 804665                new ExtraRule(
 804666                    ExtraType.Interview,
 804667                    ExtraRuleType.Suffix,
 804668                    "-interview",
 804669                    MediaType.Video),
 804670
 804671                new ExtraRule(
 804672                    ExtraType.BehindTheScenes,
 804673                    ExtraRuleType.Suffix,
 804674                    "-behindthescenes",
 804675                    MediaType.Video),
 804676
 804677                new ExtraRule(
 804678                    ExtraType.DeletedScene,
 804679                    ExtraRuleType.Suffix,
 804680                    "-deleted",
 804681                    MediaType.Video),
 804682
 804683                new ExtraRule(
 804684                    ExtraType.DeletedScene,
 804685                    ExtraRuleType.Suffix,
 804686                    "-deletedscene",
 804687                    MediaType.Video),
 804688
 804689                new ExtraRule(
 804690                    ExtraType.Featurette,
 804691                    ExtraRuleType.Suffix,
 804692                    "-featurette",
 804693                    MediaType.Video),
 804694
 804695                new ExtraRule(
 804696                    ExtraType.Short,
 804697                    ExtraRuleType.Suffix,
 804698                    "-short",
 804699                    MediaType.Video),
 804700
 804701                new ExtraRule(
 804702                    ExtraType.Unknown,
 804703                    ExtraRuleType.Suffix,
 804704                    "-extra",
 804705                    MediaType.Video),
 804706
 804707                new ExtraRule(
 804708                    ExtraType.Unknown,
 804709                    ExtraRuleType.Suffix,
 804710                    "-other",
 804711                    MediaType.Video)
 804712            ];
 713
 804714            AllExtrasTypesFolderNames = VideoExtraRules
 804715                .Where(i => i.RuleType == ExtraRuleType.DirectoryName)
 804716                .ToDictionary(i => i.Token, i => i.ExtraType, StringComparer.OrdinalIgnoreCase);
 717
 804718            Format3DRules =
 804719            [
 804720                // Kodi rules:
 804721                new Format3DRule(
 804722                    precedingToken: "3d",
 804723                    token: "hsbs"),
 804724
 804725                new Format3DRule(
 804726                    precedingToken: "3d",
 804727                    token: "sbs"),
 804728
 804729                new Format3DRule(
 804730                    precedingToken: "3d",
 804731                    token: "htab"),
 804732
 804733                new Format3DRule(
 804734                    precedingToken: "3d",
 804735                    token: "tab"),
 804736
 804737                 // Media Browser rules:
 804738                new Format3DRule("fsbs"),
 804739                new Format3DRule("hsbs"),
 804740                new Format3DRule("sbs"),
 804741                new Format3DRule("ftab"),
 804742                new Format3DRule("htab"),
 804743                new Format3DRule("tab"),
 804744                new Format3DRule("sbs3d"),
 804745                new Format3DRule("mvc")
 804746            ];
 747
 804748            AudioBookPartsExpressions =
 804749            [
 804750                // Detect specified chapters, like CH 01
 804751                @"ch(?:apter)?[\s_-]?(?<chapter>[0-9]+)",
 804752                // Detect specified parts, like Part 02
 804753                @"p(?:ar)?t[\s_-]?(?<part>[0-9]+)",
 804754                // Chapter is often beginning of filename
 804755                "^(?<chapter>[0-9]+)",
 804756                // Part if often ending of filename
 804757                "(?<!ch(?:apter) )(?<part>[0-9]+)$",
 804758                // Sometimes named as 0001_005 (chapter_part)
 804759                "(?<chapter>[0-9]+)_(?<part>[0-9]+)",
 804760                // Some audiobooks are ripped from cd's, and will be named by disk number.
 804761                @"dis(?:c|k)[\s_-]?(?<chapter>[0-9]+)"
 804762            ];
 763
 804764            AudioBookNamesExpressions =
 804765            [
 804766                // Detect year usually in brackets after name Batman (2020)
 804767                @"^(?<name>.+?)\s*\(\s*(?<year>[0-9]{4})\s*\)\s*$",
 804768                @"^\s*(?<name>[^ ].*?)\s*$"
 804769            ];
 770
 804771            MultipleEpisodeExpressions = new[]
 804772            {
 804773                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[eExX](?<endinge
 804774                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[xX][eE](?<endin
 804775                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )?[xXeE](?<endingepnumber>[
 804776                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})(-[xE]?[eE]?(?<endingepnumber>[0-9
 804777                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 804778                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 804779                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 804780                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 804781                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})((-| 
 804782                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})(-[xX
 804783            }.Select(i => new EpisodeExpression(i)
 804784            {
 804785                IsNamed = true
 804786            }).ToArray();
 787
 804788            Compile();
 804789        }
 790
 791        /// <summary>
 792        /// Gets or sets the folder name to extra types mapping.
 793        /// </summary>
 794        public Dictionary<string, ExtraType> AllExtrasTypesFolderNames { get; set; }
 795
 796        /// <summary>
 797        /// Gets or sets list of audio file extensions.
 798        /// </summary>
 799        public string[] AudioFileExtensions { get; set; }
 800
 801        /// <summary>
 802        /// Gets or sets list of external media flag delimiters.
 803        /// </summary>
 804        public char[] MediaFlagDelimiters { get; set; }
 805
 806        /// <summary>
 807        /// Gets or sets list of external media forced flags.
 808        /// </summary>
 809        public string[] MediaForcedFlags { get; set; }
 810
 811        /// <summary>
 812        /// Gets or sets list of external media default flags.
 813        /// </summary>
 814        public string[] MediaDefaultFlags { get; set; }
 815
 816        /// <summary>
 817        /// Gets or sets list of external media hearing impaired flags.
 818        /// </summary>
 819        public string[] MediaHearingImpairedFlags { get; set; }
 820
 821        /// <summary>
 822        /// Gets or sets list of album stacking prefixes.
 823        /// </summary>
 824        public string[] AlbumStackingPrefixes { get; set; }
 825
 826        /// <summary>
 827        /// Gets or sets list of artist subfolders.
 828        /// </summary>
 829        public string[] ArtistSubfolders { get; set; }
 830
 831        /// <summary>
 832        /// Gets or sets list of subtitle file extensions.
 833        /// </summary>
 834        public string[] SubtitleFileExtensions { get; set; }
 835
 836        /// <summary>
 837        /// Gets the list of lyric file extensions.
 838        /// </summary>
 839        public string[] LyricFileExtensions { get; }
 840
 841        /// <summary>
 842        /// Gets or sets list of episode regular expressions.
 843        /// </summary>
 844        public EpisodeExpression[] EpisodeExpressions { get; set; }
 845
 846        /// <summary>
 847        /// Gets or sets list of video file extensions.
 848        /// </summary>
 849        public string[] VideoFileExtensions { get; set; }
 850
 851        /// <summary>
 852        /// Gets or sets list of video stub file extensions.
 853        /// </summary>
 854        public string[] StubFileExtensions { get; set; }
 855
 856        /// <summary>
 857        /// Gets or sets list of raw audiobook parts regular expressions strings.
 858        /// </summary>
 859        public string[] AudioBookPartsExpressions { get; set; }
 860
 861        /// <summary>
 862        /// Gets or sets list of raw audiobook names regular expressions strings.
 863        /// </summary>
 864        public string[] AudioBookNamesExpressions { get; set; }
 865
 866        /// <summary>
 867        /// Gets or sets list of stub type rules.
 868        /// </summary>
 869        public StubTypeRule[] StubTypes { get; set; }
 870
 871        /// <summary>
 872        /// Gets or sets list of video flag delimiters.
 873        /// </summary>
 874        public char[] VideoFlagDelimiters { get; set; }
 875
 876        /// <summary>
 877        /// Gets or sets list of 3D Format rules.
 878        /// </summary>
 879        public Format3DRule[] Format3DRules { get; set; }
 880
 881        /// <summary>
 882        /// Gets the file stacking rules.
 883        /// </summary>
 884        public FileStackRule[] VideoFileStackingRules { get; }
 885
 886        /// <summary>
 887        /// Gets or sets list of raw clean DateTimes regular expressions strings.
 888        /// </summary>
 889        public string[] CleanDateTimes { get; set; }
 890
 891        /// <summary>
 892        /// Gets or sets list of raw clean strings regular expressions strings.
 893        /// </summary>
 894        public string[] CleanStrings { get; set; }
 895
 896        /// <summary>
 897        /// Gets or sets list of multi-episode regular expressions.
 898        /// </summary>
 899        public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
 900
 901        /// <summary>
 902        /// Gets or sets list of extra rules for videos.
 903        /// </summary>
 904        public ExtraRule[] VideoExtraRules { get; set; }
 905
 906        /// <summary>
 907        /// Gets list of clean datetime regular expressions.
 908        /// </summary>
 909        public Regex[] CleanDateTimeRegexes { get; private set; } = [];
 910
 911        /// <summary>
 912        /// Gets list of clean string regular expressions.
 913        /// </summary>
 914        public Regex[] CleanStringRegexes { get; private set; } = [];
 915
 916        /// <summary>
 917        /// Compiles raw regex strings into regexes.
 918        /// </summary>
 919        public void Compile()
 920        {
 805921            CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray();
 805922            CleanStringRegexes = CleanStrings.Select(Compile).ToArray();
 805923        }
 924
 925        private Regex Compile(string exp)
 926        {
 6440927            return new Regex(exp, RegexOptions.IgnoreCase | RegexOptions.Compiled);
 928        }
 929    }
 930}