< 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: 731
Uncovered lines: 0
Coverable lines: 731
Total lines: 914
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 11/28/2025 - 12:11:11 AM Line coverage: 100% (730/730) Total lines: 9133/3/2026 - 12:13:24 AM Line coverage: 100% (731/731) Total lines: 914

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                ".aifc",
 671229                ".aiff",
 671230                ".alac",
 671231                ".amr",
 671232                ".ape",
 671233                ".ast",
 671234                ".au",
 671235                ".awb",
 671236                ".cda",
 671237                ".cue",
 671238                ".dmf",
 671239                ".dsf",
 671240                ".dsm",
 671241                ".dsp",
 671242                ".dts",
 671243                ".dvf",
 671244                ".eac3",
 671245                ".ec3",
 671246                ".far",
 671247                ".flac",
 671248                ".gdm",
 671249                ".gsm",
 671250                ".gym",
 671251                ".hps",
 671252                ".imf",
 671253                ".it",
 671254                ".m15",
 671255                ".m4a",
 671256                ".m4b",
 671257                ".mac",
 671258                ".med",
 671259                ".mka",
 671260                ".mmf",
 671261                ".mod",
 671262                ".mogg",
 671263                ".mp2",
 671264                ".mp3",
 671265                ".mpa",
 671266                ".mpc",
 671267                ".mpp",
 671268                ".mp+",
 671269                ".msv",
 671270                ".nmf",
 671271                ".nsf",
 671272                ".nsv",
 671273                ".oga",
 671274                ".ogg",
 671275                ".okt",
 671276                ".opus",
 671277                ".pls",
 671278                ".ra",
 671279                ".rf64",
 671280                ".rm",
 671281                ".s3m",
 671282                ".sfx",
 671283                ".shn",
 671284                ".sid",
 671285                ".stm",
 671286                ".strm",
 671287                ".ult",
 671288                ".uni",
 671289                ".vox",
 671290                ".wav",
 671291                ".wma",
 671292                ".wv",
 671293                ".xm",
 671294                ".xsp",
 671295                ".ymf"
 671296            ];
 297
 671298            MediaFlagDelimiters =
 671299            [
 671300                '.'
 671301            ];
 302
 671303            MediaForcedFlags =
 671304            [
 671305                "foreign",
 671306                "forced"
 671307            ];
 308
 671309            MediaDefaultFlags =
 671310            [
 671311                "default"
 671312            ];
 313
 671314            MediaHearingImpairedFlags =
 671315            [
 671316                "cc",
 671317                "hi",
 671318                "sdh"
 671319            ];
 320
 671321            EpisodeExpressions =
 671322            [
 671323                // *** Begin Kodi Standard Naming
 671324                // <!-- foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02 -->
 671325                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+))[^\\\/])*)?[Ss](?<s
 671326                {
 671327                    IsNamed = true
 671328                },
 671329                // <!-- foo.ep01, foo.EP_01 -->
 671330                new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
 671331                // <!-- foo.E01., foo.e01. -->
 671332                new EpisodeExpression(@"[^\\/]*?()\.?[Ee]([0-9]+)\.([^\\/]*)$"),
 671333                new EpisodeExpression("(?<year>[0-9]{4})[._ -](?<month>[0-9]{2})[._ -](?<day>[0-9]{2})", true)
 671334                {
 671335                    DateTimeFormats =
 671336                    [
 671337                        "yyyy.MM.dd",
 671338                        "yyyy-MM-dd",
 671339                        "yyyy_MM_dd",
 671340                        "yyyy MM dd"
 671341                    ]
 671342                },
 671343                new EpisodeExpression("(?<day>[0-9]{2})[._ -](?<month>[0-9]{2})[._ -](?<year>[0-9]{4})", true)
 671344                {
 671345                    DateTimeFormats =
 671346                    [
 671347                        "dd.MM.yyyy",
 671348                        "dd-MM-yyyy",
 671349                        "dd_MM_yyyy",
 671350                        "dd MM yyyy"
 671351                    ]
 671352                },
 671353
 671354                // This isn't a Kodi naming rule, but the expression below causes false episode numbers for
 671355                // Title Season X Episode X naming schemes.
 671356                // "Series Season X Episode X - Title.avi", "Series S03 E09.avi", "s3 e9 - Title.avi"
 671357                new EpisodeExpression(@".*[\\\/]((?<seriesname>[^\\/]+?)\s)?[Ss](?:eason)?\s*(?<seasonnumber>[0-9]+)\s+[
 671358                {
 671359                    IsNamed = true
 671360                },
 671361
 671362                // Not a Kodi rule as well, but the expression below also causes false positives,
 671363                // so we make sure this one gets tested first.
 671364                // "Foo Bar 889"
 671365                new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,4})(-(?<endin
 671366                {
 671367                    IsNamed = true
 671368                },
 671369
 671370                new EpisodeExpression(@"[\\\/\._ \[\(-]([0-9]+)x([0-9]+(?:(?:[a-i]|\.[1-9])(?![0-9]))?)([^\\\/]*)$")
 671371                {
 671372                    SupportsAbsoluteEpisodeNumbers = true
 671373                },
 671374
 671375                // Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names
 671376                // [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the se
 671377                new EpisodeExpression(@".*[\\\/]?.*?(\[.*?\])+.*?(?<seriesname>[-\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+
 671378                {
 671379                    IsNamed = true
 671380                },
 671381
 671382                // /server/anything_102.mp4
 671383                // /server/james.corden.2017.04.20.anne.hathaway.720p.hdtv.x264-crooks.mkv
 671384                // /server/anything_1996.11.14.mp4
 671385                new EpisodeExpression(@"[\\/._ -](?<seriesname>(?![0-9]+[0-9][0-9])([^\\\/_])*)[\\\/._ -](?<seasonnumber
 671386                {
 671387                    IsOptimistic = true,
 671388                    IsNamed = true,
 671389                    SupportsAbsoluteEpisodeNumbers = false
 671390                },
 671391                new EpisodeExpression(@"[\/._ -]p(?:ar)?t[_. -]()([ivx]+|[0-9]+)([._ -][^\/]*)$")
 671392                {
 671393                    SupportsAbsoluteEpisodeNumbers = true
 671394                },
 671395
 671396                // *** End Kodi Standard Naming
 671397
 671398                // "Episode 16", "Episode 16 - Title"
 671399                new EpisodeExpression(@"[Ee]pisode (?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))?[^\\\/]*$")
 671400                {
 671401                    IsNamed = true
 671402                },
 671403
 671404                new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]+)[xX](?<epnumber>[0-9]+)[^\\\/]*$")
 671405                {
 671406                    IsNamed = true
 671407                },
 671408
 671409                new EpisodeExpression(@".*(\\|\/)[sS](?<seasonnumber>[0-9]+)[x,X]?[eE](?<epnumber>[0-9]+)[^\\\/]*$")
 671410                {
 671411                    IsNamed = true
 671412                },
 671413
 671414                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<sea
 671415                {
 671416                    IsNamed = true
 671417                },
 671418
 671419                new EpisodeExpression(@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epn
 671420                {
 671421                    IsNamed = true
 671422                },
 671423
 671424                // "01.avi"
 671425                new EpisodeExpression(@".*[\\\/](?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))*\.\w+$")
 671426                {
 671427                    IsOptimistic = true,
 671428                    IsNamed = true
 671429                },
 671430
 671431                // "1-12 episode title"
 671432                new EpisodeExpression("([0-9]+)-([0-9]+)"),
 671433
 671434                // "01 - blah.avi", "01-blah.avi"
 671435                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\s?-\s?[^\\\/]*
 671436                {
 671437                    IsOptimistic = true,
 671438                    IsNamed = true
 671439                },
 671440
 671441                // "01.blah.avi"
 671442                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\.[^\\\/]+$")
 671443                {
 671444                    IsOptimistic = true,
 671445                    IsNamed = true
 671446                },
 671447
 671448                // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi",
 671449                new EpisodeExpression(@".*[\\\/][^\\\/]* - (?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\
 671450                {
 671451                    IsOptimistic = true,
 671452                    IsNamed = true
 671453                },
 671454
 671455                // "01 episode title.avi"
 671456                new EpisodeExpression(@"[Ss]eason[\._ ](?<seasonnumber>[0-9]+)[\\\/](?<epnumber>[0-9]{1,3})([^\\\/]*)$")
 671457                {
 671458                    IsOptimistic = true,
 671459                    IsNamed = true
 671460                },
 671461
 671462                // Series and season only expression
 671463                // "the show/season 1", "the show/s01"
 671464                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)\/[Ss](eason)?[\. _\-]*(?<seasonnumber>[0-9]+)")
 671465                {
 671466                    IsNamed = true
 671467                },
 671468
 671469                // Series and season only expression
 671470                // "the show S01", "the show season 1"
 671471                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)[\. _\-]+[sS](eason)?[\. _\-]*(?<seasonnumber>[0-9]
 671472                {
 671473                    IsNamed = true
 671474                },
 671475
 671476                // Anime style expression
 671477                // "[Group][Series Name][21][1080p][FLAC][HASH]"
 671478                // "[Group] Series Name [04][BDRIP]"
 671479                new EpisodeExpression(@"(?:\[(?:[^\]]+)\]\s*)?(?<seriesname>\[[^\]]+\]|[^[\]]+)\s*\[(?<epnumber>[0-9]+)\
 671480                {
 671481                    IsNamed = true
 671482                },
 671483            ];
 484
 671485            VideoExtraRules =
 671486            [
 671487                new ExtraRule(
 671488                    ExtraType.Trailer,
 671489                    ExtraRuleType.DirectoryName,
 671490                    "trailers",
 671491                    MediaType.Video),
 671492
 671493                new ExtraRule(
 671494                    ExtraType.ThemeVideo,
 671495                    ExtraRuleType.DirectoryName,
 671496                    "backdrops",
 671497                    MediaType.Video),
 671498
 671499                new ExtraRule(
 671500                    ExtraType.ThemeSong,
 671501                    ExtraRuleType.DirectoryName,
 671502                    "theme-music",
 671503                    MediaType.Audio),
 671504
 671505                new ExtraRule(
 671506                    ExtraType.BehindTheScenes,
 671507                    ExtraRuleType.DirectoryName,
 671508                    "behind the scenes",
 671509                    MediaType.Video),
 671510
 671511                new ExtraRule(
 671512                    ExtraType.DeletedScene,
 671513                    ExtraRuleType.DirectoryName,
 671514                    "deleted scenes",
 671515                    MediaType.Video),
 671516
 671517                new ExtraRule(
 671518                    ExtraType.Interview,
 671519                    ExtraRuleType.DirectoryName,
 671520                    "interviews",
 671521                    MediaType.Video),
 671522
 671523                new ExtraRule(
 671524                    ExtraType.Scene,
 671525                    ExtraRuleType.DirectoryName,
 671526                    "scenes",
 671527                    MediaType.Video),
 671528
 671529                new ExtraRule(
 671530                    ExtraType.Sample,
 671531                    ExtraRuleType.DirectoryName,
 671532                    "samples",
 671533                    MediaType.Video),
 671534
 671535                new ExtraRule(
 671536                    ExtraType.Short,
 671537                    ExtraRuleType.DirectoryName,
 671538                    "shorts",
 671539                    MediaType.Video),
 671540
 671541                new ExtraRule(
 671542                    ExtraType.Featurette,
 671543                    ExtraRuleType.DirectoryName,
 671544                    "featurettes",
 671545                    MediaType.Video),
 671546
 671547                new ExtraRule(
 671548                    ExtraType.Unknown,
 671549                    ExtraRuleType.DirectoryName,
 671550                    "extras",
 671551                    MediaType.Video),
 671552
 671553                new ExtraRule(
 671554                    ExtraType.Unknown,
 671555                    ExtraRuleType.DirectoryName,
 671556                    "extra",
 671557                    MediaType.Video),
 671558
 671559                new ExtraRule(
 671560                    ExtraType.Unknown,
 671561                    ExtraRuleType.DirectoryName,
 671562                    "other",
 671563                    MediaType.Video),
 671564
 671565                new ExtraRule(
 671566                    ExtraType.Clip,
 671567                    ExtraRuleType.DirectoryName,
 671568                    "clips",
 671569                    MediaType.Video),
 671570
 671571                new ExtraRule(
 671572                    ExtraType.Trailer,
 671573                    ExtraRuleType.Filename,
 671574                    "trailer",
 671575                    MediaType.Video),
 671576
 671577                new ExtraRule(
 671578                    ExtraType.Sample,
 671579                    ExtraRuleType.Filename,
 671580                    "sample",
 671581                    MediaType.Video),
 671582
 671583                new ExtraRule(
 671584                    ExtraType.ThemeSong,
 671585                    ExtraRuleType.Filename,
 671586                    "theme",
 671587                    MediaType.Audio),
 671588
 671589                new ExtraRule(
 671590                    ExtraType.Trailer,
 671591                    ExtraRuleType.Suffix,
 671592                    "-trailer",
 671593                    MediaType.Video),
 671594
 671595                new ExtraRule(
 671596                    ExtraType.Trailer,
 671597                    ExtraRuleType.Suffix,
 671598                    ".trailer",
 671599                    MediaType.Video),
 671600
 671601                new ExtraRule(
 671602                    ExtraType.Trailer,
 671603                    ExtraRuleType.Suffix,
 671604                    "_trailer",
 671605                    MediaType.Video),
 671606
 671607                new ExtraRule(
 671608                    ExtraType.Trailer,
 671609                    ExtraRuleType.Suffix,
 671610                    "- trailer",
 671611                    MediaType.Video),
 671612
 671613                new ExtraRule(
 671614                    ExtraType.Sample,
 671615                    ExtraRuleType.Suffix,
 671616                    "-sample",
 671617                    MediaType.Video),
 671618
 671619                new ExtraRule(
 671620                    ExtraType.Sample,
 671621                    ExtraRuleType.Suffix,
 671622                    ".sample",
 671623                    MediaType.Video),
 671624
 671625                new ExtraRule(
 671626                    ExtraType.Sample,
 671627                    ExtraRuleType.Suffix,
 671628                    "_sample",
 671629                    MediaType.Video),
 671630
 671631                new ExtraRule(
 671632                    ExtraType.Sample,
 671633                    ExtraRuleType.Suffix,
 671634                    "- sample",
 671635                    MediaType.Video),
 671636
 671637                new ExtraRule(
 671638                    ExtraType.Scene,
 671639                    ExtraRuleType.Suffix,
 671640                    "-scene",
 671641                    MediaType.Video),
 671642
 671643                new ExtraRule(
 671644                    ExtraType.Clip,
 671645                    ExtraRuleType.Suffix,
 671646                    "-clip",
 671647                    MediaType.Video),
 671648
 671649                new ExtraRule(
 671650                    ExtraType.Interview,
 671651                    ExtraRuleType.Suffix,
 671652                    "-interview",
 671653                    MediaType.Video),
 671654
 671655                new ExtraRule(
 671656                    ExtraType.BehindTheScenes,
 671657                    ExtraRuleType.Suffix,
 671658                    "-behindthescenes",
 671659                    MediaType.Video),
 671660
 671661                new ExtraRule(
 671662                    ExtraType.DeletedScene,
 671663                    ExtraRuleType.Suffix,
 671664                    "-deleted",
 671665                    MediaType.Video),
 671666
 671667                new ExtraRule(
 671668                    ExtraType.DeletedScene,
 671669                    ExtraRuleType.Suffix,
 671670                    "-deletedscene",
 671671                    MediaType.Video),
 671672
 671673                new ExtraRule(
 671674                    ExtraType.Featurette,
 671675                    ExtraRuleType.Suffix,
 671676                    "-featurette",
 671677                    MediaType.Video),
 671678
 671679                new ExtraRule(
 671680                    ExtraType.Short,
 671681                    ExtraRuleType.Suffix,
 671682                    "-short",
 671683                    MediaType.Video),
 671684
 671685                new ExtraRule(
 671686                    ExtraType.Unknown,
 671687                    ExtraRuleType.Suffix,
 671688                    "-extra",
 671689                    MediaType.Video),
 671690
 671691                new ExtraRule(
 671692                    ExtraType.Unknown,
 671693                    ExtraRuleType.Suffix,
 671694                    "-other",
 671695                    MediaType.Video)
 671696            ];
 697
 671698            AllExtrasTypesFolderNames = VideoExtraRules
 671699                .Where(i => i.RuleType == ExtraRuleType.DirectoryName)
 671700                .ToDictionary(i => i.Token, i => i.ExtraType, StringComparer.OrdinalIgnoreCase);
 701
 671702            Format3DRules =
 671703            [
 671704                // Kodi rules:
 671705                new Format3DRule(
 671706                    precedingToken: "3d",
 671707                    token: "hsbs"),
 671708
 671709                new Format3DRule(
 671710                    precedingToken: "3d",
 671711                    token: "sbs"),
 671712
 671713                new Format3DRule(
 671714                    precedingToken: "3d",
 671715                    token: "htab"),
 671716
 671717                new Format3DRule(
 671718                    precedingToken: "3d",
 671719                    token: "tab"),
 671720
 671721                 // Media Browser rules:
 671722                new Format3DRule("fsbs"),
 671723                new Format3DRule("hsbs"),
 671724                new Format3DRule("sbs"),
 671725                new Format3DRule("ftab"),
 671726                new Format3DRule("htab"),
 671727                new Format3DRule("tab"),
 671728                new Format3DRule("sbs3d"),
 671729                new Format3DRule("mvc")
 671730            ];
 731
 671732            AudioBookPartsExpressions =
 671733            [
 671734                // Detect specified chapters, like CH 01
 671735                @"ch(?:apter)?[\s_-]?(?<chapter>[0-9]+)",
 671736                // Detect specified parts, like Part 02
 671737                @"p(?:ar)?t[\s_-]?(?<part>[0-9]+)",
 671738                // Chapter is often beginning of filename
 671739                "^(?<chapter>[0-9]+)",
 671740                // Part if often ending of filename
 671741                "(?<!ch(?:apter) )(?<part>[0-9]+)$",
 671742                // Sometimes named as 0001_005 (chapter_part)
 671743                "(?<chapter>[0-9]+)_(?<part>[0-9]+)",
 671744                // Some audiobooks are ripped from cd's, and will be named by disk number.
 671745                @"dis(?:c|k)[\s_-]?(?<chapter>[0-9]+)"
 671746            ];
 747
 671748            AudioBookNamesExpressions =
 671749            [
 671750                // Detect year usually in brackets after name Batman (2020)
 671751                @"^(?<name>.+?)\s*\(\s*(?<year>[0-9]{4})\s*\)\s*$",
 671752                @"^\s*(?<name>[^ ].*?)\s*$"
 671753            ];
 754
 671755            MultipleEpisodeExpressions = new[]
 671756            {
 671757                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[eExX](?<endinge
 671758                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[xX][eE](?<endin
 671759                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )?[xXeE](?<endingepnumber>[
 671760                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})(-[xE]?[eE]?(?<endingepnumber>[0-9
 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]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 671765                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})((-| 
 671766                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})(-[xX
 671767            }.Select(i => new EpisodeExpression(i)
 671768            {
 671769                IsNamed = true
 671770            }).ToArray();
 771
 671772            Compile();
 671773        }
 774
 775        /// <summary>
 776        /// Gets or sets the folder name to extra types mapping.
 777        /// </summary>
 778        public Dictionary<string, ExtraType> AllExtrasTypesFolderNames { get; set; }
 779
 780        /// <summary>
 781        /// Gets or sets list of audio file extensions.
 782        /// </summary>
 783        public string[] AudioFileExtensions { get; set; }
 784
 785        /// <summary>
 786        /// Gets or sets list of external media flag delimiters.
 787        /// </summary>
 788        public char[] MediaFlagDelimiters { get; set; }
 789
 790        /// <summary>
 791        /// Gets or sets list of external media forced flags.
 792        /// </summary>
 793        public string[] MediaForcedFlags { get; set; }
 794
 795        /// <summary>
 796        /// Gets or sets list of external media default flags.
 797        /// </summary>
 798        public string[] MediaDefaultFlags { get; set; }
 799
 800        /// <summary>
 801        /// Gets or sets list of external media hearing impaired flags.
 802        /// </summary>
 803        public string[] MediaHearingImpairedFlags { get; set; }
 804
 805        /// <summary>
 806        /// Gets or sets list of album stacking prefixes.
 807        /// </summary>
 808        public string[] AlbumStackingPrefixes { get; set; }
 809
 810        /// <summary>
 811        /// Gets or sets list of artist subfolders.
 812        /// </summary>
 813        public string[] ArtistSubfolders { get; set; }
 814
 815        /// <summary>
 816        /// Gets or sets list of subtitle file extensions.
 817        /// </summary>
 818        public string[] SubtitleFileExtensions { get; set; }
 819
 820        /// <summary>
 821        /// Gets the list of lyric file extensions.
 822        /// </summary>
 823        public string[] LyricFileExtensions { get; }
 824
 825        /// <summary>
 826        /// Gets or sets list of episode regular expressions.
 827        /// </summary>
 828        public EpisodeExpression[] EpisodeExpressions { get; set; }
 829
 830        /// <summary>
 831        /// Gets or sets list of video file extensions.
 832        /// </summary>
 833        public string[] VideoFileExtensions { get; set; }
 834
 835        /// <summary>
 836        /// Gets or sets list of video stub file extensions.
 837        /// </summary>
 838        public string[] StubFileExtensions { get; set; }
 839
 840        /// <summary>
 841        /// Gets or sets list of raw audiobook parts regular expressions strings.
 842        /// </summary>
 843        public string[] AudioBookPartsExpressions { get; set; }
 844
 845        /// <summary>
 846        /// Gets or sets list of raw audiobook names regular expressions strings.
 847        /// </summary>
 848        public string[] AudioBookNamesExpressions { get; set; }
 849
 850        /// <summary>
 851        /// Gets or sets list of stub type rules.
 852        /// </summary>
 853        public StubTypeRule[] StubTypes { get; set; }
 854
 855        /// <summary>
 856        /// Gets or sets list of video flag delimiters.
 857        /// </summary>
 858        public char[] VideoFlagDelimiters { get; set; }
 859
 860        /// <summary>
 861        /// Gets or sets list of 3D Format rules.
 862        /// </summary>
 863        public Format3DRule[] Format3DRules { get; set; }
 864
 865        /// <summary>
 866        /// Gets the file stacking rules.
 867        /// </summary>
 868        public FileStackRule[] VideoFileStackingRules { get; }
 869
 870        /// <summary>
 871        /// Gets or sets list of raw clean DateTimes regular expressions strings.
 872        /// </summary>
 873        public string[] CleanDateTimes { get; set; }
 874
 875        /// <summary>
 876        /// Gets or sets list of raw clean strings regular expressions strings.
 877        /// </summary>
 878        public string[] CleanStrings { get; set; }
 879
 880        /// <summary>
 881        /// Gets or sets list of multi-episode regular expressions.
 882        /// </summary>
 883        public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
 884
 885        /// <summary>
 886        /// Gets or sets list of extra rules for videos.
 887        /// </summary>
 888        public ExtraRule[] VideoExtraRules { get; set; }
 889
 890        /// <summary>
 891        /// Gets list of clean datetime regular expressions.
 892        /// </summary>
 893        public Regex[] CleanDateTimeRegexes { get; private set; } = [];
 894
 895        /// <summary>
 896        /// Gets list of clean string regular expressions.
 897        /// </summary>
 898        public Regex[] CleanStringRegexes { get; private set; } = [];
 899
 900        /// <summary>
 901        /// Compiles raw regex strings into regexes.
 902        /// </summary>
 903        public void Compile()
 904        {
 672905            CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray();
 672906            CleanStringRegexes = CleanStrings.Select(Compile).ToArray();
 672907        }
 908
 909        private Regex Compile(string exp)
 910        {
 5376911            return new Regex(exp, RegexOptions.IgnoreCase | RegexOptions.Compiled);
 912        }
 913    }
 914}