< 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: 730
Uncovered lines: 0
Coverable lines: 730
Total lines: 913
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 9/14/2025 - 12:09:49 AM Line coverage: 100% (729/729) Total lines: 9129/17/2025 - 12:11:23 AM Line coverage: 100% (730/730) Total lines: 913

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        {
 67124            VideoFileExtensions =
 67125            [
 67126                ".001",
 67127                ".3g2",
 67128                ".3gp",
 67129                ".amv",
 67130                ".asf",
 67131                ".asx",
 67132                ".avi",
 67133                ".bin",
 67134                ".bivx",
 67135                ".divx",
 67136                ".dv",
 67137                ".dvr-ms",
 67138                ".f4v",
 67139                ".fli",
 67140                ".flv",
 67141                ".ifo",
 67142                ".img",
 67143                ".iso",
 67144                ".m2t",
 67145                ".m2ts",
 67146                ".m2v",
 67147                ".m4v",
 67148                ".mkv",
 67149                ".mk3d",
 67150                ".mov",
 67151                ".mp4",
 67152                ".mpe",
 67153                ".mpeg",
 67154                ".mpg",
 67155                ".mts",
 67156                ".mxf",
 67157                ".nrg",
 67158                ".nsv",
 67159                ".nuv",
 67160                ".ogg",
 67161                ".ogm",
 67162                ".ogv",
 67163                ".pva",
 67164                ".qt",
 67165                ".rec",
 67166                ".rm",
 67167                ".rmvb",
 67168                ".strm",
 67169                ".svq3",
 67170                ".tp",
 67171                ".ts",
 67172                ".ty",
 67173                ".viv",
 67174                ".vob",
 67175                ".vp3",
 67176                ".webm",
 67177                ".wmv",
 67178                ".wtv",
 67179                ".xvid"
 67180            ];
 81
 67182            VideoFlagDelimiters =
 67183            [
 67184                '(',
 67185                ')',
 67186                '-',
 67187                '.',
 67188                '_',
 67189                '[',
 67190                ']'
 67191            ];
 92
 67193            StubFileExtensions =
 67194            [
 67195                ".disc"
 67196            ];
 97
 67198            StubTypes =
 67199            [
 671100                new StubTypeRule(
 671101                    stubType: "dvd",
 671102                    token: "dvd"),
 671103
 671104                new StubTypeRule(
 671105                    stubType: "hddvd",
 671106                    token: "hddvd"),
 671107
 671108                new StubTypeRule(
 671109                    stubType: "bluray",
 671110                    token: "bluray"),
 671111
 671112                new StubTypeRule(
 671113                    stubType: "bluray",
 671114                    token: "brrip"),
 671115
 671116                new StubTypeRule(
 671117                    stubType: "bluray",
 671118                    token: "bd25"),
 671119
 671120                new StubTypeRule(
 671121                    stubType: "bluray",
 671122                    token: "bd50"),
 671123
 671124                new StubTypeRule(
 671125                    stubType: "vhs",
 671126                    token: "vhs"),
 671127
 671128                new StubTypeRule(
 671129                    stubType: "tv",
 671130                    token: "HDTV"),
 671131
 671132                new StubTypeRule(
 671133                    stubType: "tv",
 671134                    token: "PDTV"),
 671135
 671136                new StubTypeRule(
 671137                    stubType: "tv",
 671138                    token: "DSR")
 671139            ];
 140
 671141            VideoFileStackingRules =
 671142            [
 671143                new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])
 671144                new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])
 671145            ];
 146
 671147            CleanDateTimes =
 671148            [
 671149                @"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\
 671150                @"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\
 671151            ];
 152
 671153            CleanStrings =
 671154            [
 671155                @"^\s*(?<cleaned>.+?)[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|d
 671156                @"^(?<cleaned>.+?)(\[.*\])",
 671157                @"^\s*(?<cleaned>.+?)\WE[0-9]+(-|~)E?[0-9]+(\W|$)",
 671158                @"^\s*\[[^\]]+\](?!\.\w+$)\s*(?<cleaned>.+)",
 671159                @"^\s*(?<cleaned>.+?)\s+-\s+[0-9]+\s*$",
 671160                @"^\s*(?<cleaned>.+?)(([-._ ](trailer|sample))|-(scene|clip|behindthescenes|deleted|deletedscene|feature
 671161            ];
 162
 671163            SubtitleFileExtensions =
 671164            [
 671165                ".ass",
 671166                ".mks",
 671167                ".sami",
 671168                ".smi",
 671169                ".srt",
 671170                ".ssa",
 671171                ".sub",
 671172                ".sup",
 671173                ".vtt",
 671174            ];
 175
 671176            LyricFileExtensions =
 671177            [
 671178                ".lrc",
 671179                ".elrc",
 671180                ".txt"
 671181            ];
 182
 671183            AlbumStackingPrefixes =
 671184            [
 671185                "cd",
 671186                "digital media",
 671187                "disc",
 671188                "disk",
 671189                "vol",
 671190                "volume",
 671191                "part",
 671192                "act"
 671193            ];
 194
 671195            ArtistSubfolders =
 671196            [
 671197                "albums",
 671198                "broadcasts",
 671199                "bootlegs",
 671200                "compilations",
 671201                "dj-mixes",
 671202                "eps",
 671203                "live",
 671204                "mixtapes",
 671205                "others",
 671206                "remixes",
 671207                "singles",
 671208                "soundtracks",
 671209                "spokenwords",
 671210                "streets"
 671211            ];
 212
 671213            AudioFileExtensions =
 671214            [
 671215                ".669",
 671216                ".3gp",
 671217                ".aa",
 671218                ".aac",
 671219                ".aax",
 671220                ".ac3",
 671221                ".act",
 671222                ".adp",
 671223                ".adplug",
 671224                ".adx",
 671225                ".afc",
 671226                ".amf",
 671227                ".aif",
 671228                ".aiff",
 671229                ".alac",
 671230                ".amr",
 671231                ".ape",
 671232                ".ast",
 671233                ".au",
 671234                ".awb",
 671235                ".cda",
 671236                ".cue",
 671237                ".dmf",
 671238                ".dsf",
 671239                ".dsm",
 671240                ".dsp",
 671241                ".dts",
 671242                ".dvf",
 671243                ".eac3",
 671244                ".ec3",
 671245                ".far",
 671246                ".flac",
 671247                ".gdm",
 671248                ".gsm",
 671249                ".gym",
 671250                ".hps",
 671251                ".imf",
 671252                ".it",
 671253                ".m15",
 671254                ".m4a",
 671255                ".m4b",
 671256                ".mac",
 671257                ".med",
 671258                ".mka",
 671259                ".mmf",
 671260                ".mod",
 671261                ".mogg",
 671262                ".mp2",
 671263                ".mp3",
 671264                ".mpa",
 671265                ".mpc",
 671266                ".mpp",
 671267                ".mp+",
 671268                ".msv",
 671269                ".nmf",
 671270                ".nsf",
 671271                ".nsv",
 671272                ".oga",
 671273                ".ogg",
 671274                ".okt",
 671275                ".opus",
 671276                ".pls",
 671277                ".ra",
 671278                ".rf64",
 671279                ".rm",
 671280                ".s3m",
 671281                ".sfx",
 671282                ".shn",
 671283                ".sid",
 671284                ".stm",
 671285                ".strm",
 671286                ".ult",
 671287                ".uni",
 671288                ".vox",
 671289                ".wav",
 671290                ".wma",
 671291                ".wv",
 671292                ".xm",
 671293                ".xsp",
 671294                ".ymf"
 671295            ];
 296
 671297            MediaFlagDelimiters =
 671298            [
 671299                '.'
 671300            ];
 301
 671302            MediaForcedFlags =
 671303            [
 671304                "foreign",
 671305                "forced"
 671306            ];
 307
 671308            MediaDefaultFlags =
 671309            [
 671310                "default"
 671311            ];
 312
 671313            MediaHearingImpairedFlags =
 671314            [
 671315                "cc",
 671316                "hi",
 671317                "sdh"
 671318            ];
 319
 671320            EpisodeExpressions =
 671321            [
 671322                // *** Begin Kodi Standard Naming
 671323                // <!-- foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02 -->
 671324                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+))[^\\\/])*)?[Ss](?<s
 671325                {
 671326                    IsNamed = true
 671327                },
 671328                // <!-- foo.ep01, foo.EP_01 -->
 671329                new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
 671330                // <!-- foo.E01., foo.e01. -->
 671331                new EpisodeExpression(@"[^\\/]*?()\.?[Ee]([0-9]+)\.([^\\/]*)$"),
 671332                new EpisodeExpression("(?<year>[0-9]{4})[._ -](?<month>[0-9]{2})[._ -](?<day>[0-9]{2})", true)
 671333                {
 671334                    DateTimeFormats =
 671335                    [
 671336                        "yyyy.MM.dd",
 671337                        "yyyy-MM-dd",
 671338                        "yyyy_MM_dd",
 671339                        "yyyy MM dd"
 671340                    ]
 671341                },
 671342                new EpisodeExpression("(?<day>[0-9]{2})[._ -](?<month>[0-9]{2})[._ -](?<year>[0-9]{4})", true)
 671343                {
 671344                    DateTimeFormats =
 671345                    [
 671346                        "dd.MM.yyyy",
 671347                        "dd-MM-yyyy",
 671348                        "dd_MM_yyyy",
 671349                        "dd MM yyyy"
 671350                    ]
 671351                },
 671352
 671353                // This isn't a Kodi naming rule, but the expression below causes false episode numbers for
 671354                // Title Season X Episode X naming schemes.
 671355                // "Series Season X Episode X - Title.avi", "Series S03 E09.avi", "s3 e9 - Title.avi"
 671356                new EpisodeExpression(@".*[\\\/]((?<seriesname>[^\\/]+?)\s)?[Ss](?:eason)?\s*(?<seasonnumber>[0-9]+)\s+[
 671357                {
 671358                    IsNamed = true
 671359                },
 671360
 671361                // Not a Kodi rule as well, but the expression below also causes false positives,
 671362                // so we make sure this one gets tested first.
 671363                // "Foo Bar 889"
 671364                new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,4})(-(?<endin
 671365                {
 671366                    IsNamed = true
 671367                },
 671368
 671369                new EpisodeExpression(@"[\\\/\._ \[\(-]([0-9]+)x([0-9]+(?:(?:[a-i]|\.[1-9])(?![0-9]))?)([^\\\/]*)$")
 671370                {
 671371                    SupportsAbsoluteEpisodeNumbers = true
 671372                },
 671373
 671374                // Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names
 671375                // [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the se
 671376                new EpisodeExpression(@".*[\\\/]?.*?(\[.*?\])+.*?(?<seriesname>[-\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+
 671377                {
 671378                    IsNamed = true
 671379                },
 671380
 671381                // /server/anything_102.mp4
 671382                // /server/james.corden.2017.04.20.anne.hathaway.720p.hdtv.x264-crooks.mkv
 671383                // /server/anything_1996.11.14.mp4
 671384                new EpisodeExpression(@"[\\/._ -](?<seriesname>(?![0-9]+[0-9][0-9])([^\\\/_])*)[\\\/._ -](?<seasonnumber
 671385                {
 671386                    IsOptimistic = true,
 671387                    IsNamed = true,
 671388                    SupportsAbsoluteEpisodeNumbers = false
 671389                },
 671390                new EpisodeExpression(@"[\/._ -]p(?:ar)?t[_. -]()([ivx]+|[0-9]+)([._ -][^\/]*)$")
 671391                {
 671392                    SupportsAbsoluteEpisodeNumbers = true
 671393                },
 671394
 671395                // *** End Kodi Standard Naming
 671396
 671397                // "Episode 16", "Episode 16 - Title"
 671398                new EpisodeExpression(@"[Ee]pisode (?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))?[^\\\/]*$")
 671399                {
 671400                    IsNamed = true
 671401                },
 671402
 671403                new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]+)[xX](?<epnumber>[0-9]+)[^\\\/]*$")
 671404                {
 671405                    IsNamed = true
 671406                },
 671407
 671408                new EpisodeExpression(@".*(\\|\/)[sS](?<seasonnumber>[0-9]+)[x,X]?[eE](?<epnumber>[0-9]+)[^\\\/]*$")
 671409                {
 671410                    IsNamed = true
 671411                },
 671412
 671413                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<sea
 671414                {
 671415                    IsNamed = true
 671416                },
 671417
 671418                new EpisodeExpression(@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epn
 671419                {
 671420                    IsNamed = true
 671421                },
 671422
 671423                // "01.avi"
 671424                new EpisodeExpression(@".*[\\\/](?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))*\.\w+$")
 671425                {
 671426                    IsOptimistic = true,
 671427                    IsNamed = true
 671428                },
 671429
 671430                // "1-12 episode title"
 671431                new EpisodeExpression("([0-9]+)-([0-9]+)"),
 671432
 671433                // "01 - blah.avi", "01-blah.avi"
 671434                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\s?-\s?[^\\\/]*
 671435                {
 671436                    IsOptimistic = true,
 671437                    IsNamed = true
 671438                },
 671439
 671440                // "01.blah.avi"
 671441                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\.[^\\\/]+$")
 671442                {
 671443                    IsOptimistic = true,
 671444                    IsNamed = true
 671445                },
 671446
 671447                // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi",
 671448                new EpisodeExpression(@".*[\\\/][^\\\/]* - (?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\
 671449                {
 671450                    IsOptimistic = true,
 671451                    IsNamed = true
 671452                },
 671453
 671454                // "01 episode title.avi"
 671455                new EpisodeExpression(@"[Ss]eason[\._ ](?<seasonnumber>[0-9]+)[\\\/](?<epnumber>[0-9]{1,3})([^\\\/]*)$")
 671456                {
 671457                    IsOptimistic = true,
 671458                    IsNamed = true
 671459                },
 671460
 671461                // Series and season only expression
 671462                // "the show/season 1", "the show/s01"
 671463                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)\/[Ss](eason)?[\. _\-]*(?<seasonnumber>[0-9]+)")
 671464                {
 671465                    IsNamed = true
 671466                },
 671467
 671468                // Series and season only expression
 671469                // "the show S01", "the show season 1"
 671470                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)[\. _\-]+[sS](eason)?[\. _\-]*(?<seasonnumber>[0-9]
 671471                {
 671472                    IsNamed = true
 671473                },
 671474
 671475                // Anime style expression
 671476                // "[Group][Series Name][21][1080p][FLAC][HASH]"
 671477                // "[Group] Series Name [04][BDRIP]"
 671478                new EpisodeExpression(@"(?:\[(?:[^\]]+)\]\s*)?(?<seriesname>\[[^\]]+\]|[^[\]]+)\s*\[(?<epnumber>[0-9]+)\
 671479                {
 671480                    IsNamed = true
 671481                },
 671482            ];
 483
 671484            VideoExtraRules =
 671485            [
 671486                new ExtraRule(
 671487                    ExtraType.Trailer,
 671488                    ExtraRuleType.DirectoryName,
 671489                    "trailers",
 671490                    MediaType.Video),
 671491
 671492                new ExtraRule(
 671493                    ExtraType.ThemeVideo,
 671494                    ExtraRuleType.DirectoryName,
 671495                    "backdrops",
 671496                    MediaType.Video),
 671497
 671498                new ExtraRule(
 671499                    ExtraType.ThemeSong,
 671500                    ExtraRuleType.DirectoryName,
 671501                    "theme-music",
 671502                    MediaType.Audio),
 671503
 671504                new ExtraRule(
 671505                    ExtraType.BehindTheScenes,
 671506                    ExtraRuleType.DirectoryName,
 671507                    "behind the scenes",
 671508                    MediaType.Video),
 671509
 671510                new ExtraRule(
 671511                    ExtraType.DeletedScene,
 671512                    ExtraRuleType.DirectoryName,
 671513                    "deleted scenes",
 671514                    MediaType.Video),
 671515
 671516                new ExtraRule(
 671517                    ExtraType.Interview,
 671518                    ExtraRuleType.DirectoryName,
 671519                    "interviews",
 671520                    MediaType.Video),
 671521
 671522                new ExtraRule(
 671523                    ExtraType.Scene,
 671524                    ExtraRuleType.DirectoryName,
 671525                    "scenes",
 671526                    MediaType.Video),
 671527
 671528                new ExtraRule(
 671529                    ExtraType.Sample,
 671530                    ExtraRuleType.DirectoryName,
 671531                    "samples",
 671532                    MediaType.Video),
 671533
 671534                new ExtraRule(
 671535                    ExtraType.Short,
 671536                    ExtraRuleType.DirectoryName,
 671537                    "shorts",
 671538                    MediaType.Video),
 671539
 671540                new ExtraRule(
 671541                    ExtraType.Featurette,
 671542                    ExtraRuleType.DirectoryName,
 671543                    "featurettes",
 671544                    MediaType.Video),
 671545
 671546                new ExtraRule(
 671547                    ExtraType.Unknown,
 671548                    ExtraRuleType.DirectoryName,
 671549                    "extras",
 671550                    MediaType.Video),
 671551
 671552                new ExtraRule(
 671553                    ExtraType.Unknown,
 671554                    ExtraRuleType.DirectoryName,
 671555                    "extra",
 671556                    MediaType.Video),
 671557
 671558                new ExtraRule(
 671559                    ExtraType.Unknown,
 671560                    ExtraRuleType.DirectoryName,
 671561                    "other",
 671562                    MediaType.Video),
 671563
 671564                new ExtraRule(
 671565                    ExtraType.Clip,
 671566                    ExtraRuleType.DirectoryName,
 671567                    "clips",
 671568                    MediaType.Video),
 671569
 671570                new ExtraRule(
 671571                    ExtraType.Trailer,
 671572                    ExtraRuleType.Filename,
 671573                    "trailer",
 671574                    MediaType.Video),
 671575
 671576                new ExtraRule(
 671577                    ExtraType.Sample,
 671578                    ExtraRuleType.Filename,
 671579                    "sample",
 671580                    MediaType.Video),
 671581
 671582                new ExtraRule(
 671583                    ExtraType.ThemeSong,
 671584                    ExtraRuleType.Filename,
 671585                    "theme",
 671586                    MediaType.Audio),
 671587
 671588                new ExtraRule(
 671589                    ExtraType.Trailer,
 671590                    ExtraRuleType.Suffix,
 671591                    "-trailer",
 671592                    MediaType.Video),
 671593
 671594                new ExtraRule(
 671595                    ExtraType.Trailer,
 671596                    ExtraRuleType.Suffix,
 671597                    ".trailer",
 671598                    MediaType.Video),
 671599
 671600                new ExtraRule(
 671601                    ExtraType.Trailer,
 671602                    ExtraRuleType.Suffix,
 671603                    "_trailer",
 671604                    MediaType.Video),
 671605
 671606                new ExtraRule(
 671607                    ExtraType.Trailer,
 671608                    ExtraRuleType.Suffix,
 671609                    "- trailer",
 671610                    MediaType.Video),
 671611
 671612                new ExtraRule(
 671613                    ExtraType.Sample,
 671614                    ExtraRuleType.Suffix,
 671615                    "-sample",
 671616                    MediaType.Video),
 671617
 671618                new ExtraRule(
 671619                    ExtraType.Sample,
 671620                    ExtraRuleType.Suffix,
 671621                    ".sample",
 671622                    MediaType.Video),
 671623
 671624                new ExtraRule(
 671625                    ExtraType.Sample,
 671626                    ExtraRuleType.Suffix,
 671627                    "_sample",
 671628                    MediaType.Video),
 671629
 671630                new ExtraRule(
 671631                    ExtraType.Sample,
 671632                    ExtraRuleType.Suffix,
 671633                    "- sample",
 671634                    MediaType.Video),
 671635
 671636                new ExtraRule(
 671637                    ExtraType.Scene,
 671638                    ExtraRuleType.Suffix,
 671639                    "-scene",
 671640                    MediaType.Video),
 671641
 671642                new ExtraRule(
 671643                    ExtraType.Clip,
 671644                    ExtraRuleType.Suffix,
 671645                    "-clip",
 671646                    MediaType.Video),
 671647
 671648                new ExtraRule(
 671649                    ExtraType.Interview,
 671650                    ExtraRuleType.Suffix,
 671651                    "-interview",
 671652                    MediaType.Video),
 671653
 671654                new ExtraRule(
 671655                    ExtraType.BehindTheScenes,
 671656                    ExtraRuleType.Suffix,
 671657                    "-behindthescenes",
 671658                    MediaType.Video),
 671659
 671660                new ExtraRule(
 671661                    ExtraType.DeletedScene,
 671662                    ExtraRuleType.Suffix,
 671663                    "-deleted",
 671664                    MediaType.Video),
 671665
 671666                new ExtraRule(
 671667                    ExtraType.DeletedScene,
 671668                    ExtraRuleType.Suffix,
 671669                    "-deletedscene",
 671670                    MediaType.Video),
 671671
 671672                new ExtraRule(
 671673                    ExtraType.Featurette,
 671674                    ExtraRuleType.Suffix,
 671675                    "-featurette",
 671676                    MediaType.Video),
 671677
 671678                new ExtraRule(
 671679                    ExtraType.Short,
 671680                    ExtraRuleType.Suffix,
 671681                    "-short",
 671682                    MediaType.Video),
 671683
 671684                new ExtraRule(
 671685                    ExtraType.Unknown,
 671686                    ExtraRuleType.Suffix,
 671687                    "-extra",
 671688                    MediaType.Video),
 671689
 671690                new ExtraRule(
 671691                    ExtraType.Unknown,
 671692                    ExtraRuleType.Suffix,
 671693                    "-other",
 671694                    MediaType.Video)
 671695            ];
 696
 671697            AllExtrasTypesFolderNames = VideoExtraRules
 671698                .Where(i => i.RuleType == ExtraRuleType.DirectoryName)
 671699                .ToDictionary(i => i.Token, i => i.ExtraType, StringComparer.OrdinalIgnoreCase);
 700
 671701            Format3DRules =
 671702            [
 671703                // Kodi rules:
 671704                new Format3DRule(
 671705                    precedingToken: "3d",
 671706                    token: "hsbs"),
 671707
 671708                new Format3DRule(
 671709                    precedingToken: "3d",
 671710                    token: "sbs"),
 671711
 671712                new Format3DRule(
 671713                    precedingToken: "3d",
 671714                    token: "htab"),
 671715
 671716                new Format3DRule(
 671717                    precedingToken: "3d",
 671718                    token: "tab"),
 671719
 671720                 // Media Browser rules:
 671721                new Format3DRule("fsbs"),
 671722                new Format3DRule("hsbs"),
 671723                new Format3DRule("sbs"),
 671724                new Format3DRule("ftab"),
 671725                new Format3DRule("htab"),
 671726                new Format3DRule("tab"),
 671727                new Format3DRule("sbs3d"),
 671728                new Format3DRule("mvc")
 671729            ];
 730
 671731            AudioBookPartsExpressions =
 671732            [
 671733                // Detect specified chapters, like CH 01
 671734                @"ch(?:apter)?[\s_-]?(?<chapter>[0-9]+)",
 671735                // Detect specified parts, like Part 02
 671736                @"p(?:ar)?t[\s_-]?(?<part>[0-9]+)",
 671737                // Chapter is often beginning of filename
 671738                "^(?<chapter>[0-9]+)",
 671739                // Part if often ending of filename
 671740                "(?<!ch(?:apter) )(?<part>[0-9]+)$",
 671741                // Sometimes named as 0001_005 (chapter_part)
 671742                "(?<chapter>[0-9]+)_(?<part>[0-9]+)",
 671743                // Some audiobooks are ripped from cd's, and will be named by disk number.
 671744                @"dis(?:c|k)[\s_-]?(?<chapter>[0-9]+)"
 671745            ];
 746
 671747            AudioBookNamesExpressions =
 671748            [
 671749                // Detect year usually in brackets after name Batman (2020)
 671750                @"^(?<name>.+?)\s*\(\s*(?<year>[0-9]{4})\s*\)\s*$",
 671751                @"^\s*(?<name>[^ ].*?)\s*$"
 671752            ];
 753
 671754            MultipleEpisodeExpressions = new[]
 671755            {
 671756                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[eExX](?<endinge
 671757                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[xX][eE](?<endin
 671758                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )?[xXeE](?<endingepnumber>[
 671759                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})(-[xE]?[eE]?(?<endingepnumber>[0-9
 671760                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 671761                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 671762                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 671763                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 671764                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})((-| 
 671765                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})(-[xX
 671766            }.Select(i => new EpisodeExpression(i)
 671767            {
 671768                IsNamed = true
 671769            }).ToArray();
 770
 671771            Compile();
 671772        }
 773
 774        /// <summary>
 775        /// Gets or sets the folder name to extra types mapping.
 776        /// </summary>
 777        public Dictionary<string, ExtraType> AllExtrasTypesFolderNames { get; set; }
 778
 779        /// <summary>
 780        /// Gets or sets list of audio file extensions.
 781        /// </summary>
 782        public string[] AudioFileExtensions { get; set; }
 783
 784        /// <summary>
 785        /// Gets or sets list of external media flag delimiters.
 786        /// </summary>
 787        public char[] MediaFlagDelimiters { get; set; }
 788
 789        /// <summary>
 790        /// Gets or sets list of external media forced flags.
 791        /// </summary>
 792        public string[] MediaForcedFlags { get; set; }
 793
 794        /// <summary>
 795        /// Gets or sets list of external media default flags.
 796        /// </summary>
 797        public string[] MediaDefaultFlags { get; set; }
 798
 799        /// <summary>
 800        /// Gets or sets list of external media hearing impaired flags.
 801        /// </summary>
 802        public string[] MediaHearingImpairedFlags { get; set; }
 803
 804        /// <summary>
 805        /// Gets or sets list of album stacking prefixes.
 806        /// </summary>
 807        public string[] AlbumStackingPrefixes { get; set; }
 808
 809        /// <summary>
 810        /// Gets or sets list of artist subfolders.
 811        /// </summary>
 812        public string[] ArtistSubfolders { get; set; }
 813
 814        /// <summary>
 815        /// Gets or sets list of subtitle file extensions.
 816        /// </summary>
 817        public string[] SubtitleFileExtensions { get; set; }
 818
 819        /// <summary>
 820        /// Gets the list of lyric file extensions.
 821        /// </summary>
 822        public string[] LyricFileExtensions { get; }
 823
 824        /// <summary>
 825        /// Gets or sets list of episode regular expressions.
 826        /// </summary>
 827        public EpisodeExpression[] EpisodeExpressions { get; set; }
 828
 829        /// <summary>
 830        /// Gets or sets list of video file extensions.
 831        /// </summary>
 832        public string[] VideoFileExtensions { get; set; }
 833
 834        /// <summary>
 835        /// Gets or sets list of video stub file extensions.
 836        /// </summary>
 837        public string[] StubFileExtensions { get; set; }
 838
 839        /// <summary>
 840        /// Gets or sets list of raw audiobook parts regular expressions strings.
 841        /// </summary>
 842        public string[] AudioBookPartsExpressions { get; set; }
 843
 844        /// <summary>
 845        /// Gets or sets list of raw audiobook names regular expressions strings.
 846        /// </summary>
 847        public string[] AudioBookNamesExpressions { get; set; }
 848
 849        /// <summary>
 850        /// Gets or sets list of stub type rules.
 851        /// </summary>
 852        public StubTypeRule[] StubTypes { get; set; }
 853
 854        /// <summary>
 855        /// Gets or sets list of video flag delimiters.
 856        /// </summary>
 857        public char[] VideoFlagDelimiters { get; set; }
 858
 859        /// <summary>
 860        /// Gets or sets list of 3D Format rules.
 861        /// </summary>
 862        public Format3DRule[] Format3DRules { get; set; }
 863
 864        /// <summary>
 865        /// Gets the file stacking rules.
 866        /// </summary>
 867        public FileStackRule[] VideoFileStackingRules { get; }
 868
 869        /// <summary>
 870        /// Gets or sets list of raw clean DateTimes regular expressions strings.
 871        /// </summary>
 872        public string[] CleanDateTimes { get; set; }
 873
 874        /// <summary>
 875        /// Gets or sets list of raw clean strings regular expressions strings.
 876        /// </summary>
 877        public string[] CleanStrings { get; set; }
 878
 879        /// <summary>
 880        /// Gets or sets list of multi-episode regular expressions.
 881        /// </summary>
 882        public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
 883
 884        /// <summary>
 885        /// Gets or sets list of extra rules for videos.
 886        /// </summary>
 887        public ExtraRule[] VideoExtraRules { get; set; }
 888
 889        /// <summary>
 890        /// Gets list of clean datetime regular expressions.
 891        /// </summary>
 892        public Regex[] CleanDateTimeRegexes { get; private set; } = [];
 893
 894        /// <summary>
 895        /// Gets list of clean string regular expressions.
 896        /// </summary>
 897        public Regex[] CleanStringRegexes { get; private set; } = [];
 898
 899        /// <summary>
 900        /// Compiles raw regex strings into regexes.
 901        /// </summary>
 902        public void Compile()
 903        {
 672904            CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray();
 672905            CleanStringRegexes = CleanStrings.Select(Compile).ToArray();
 672906        }
 907
 908        private Regex Compile(string exp)
 909        {
 5376910            return new Regex(exp, RegexOptions.IgnoreCase | RegexOptions.Compiled);
 911        }
 912    }
 913}