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

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        {
 67524            VideoFileExtensions =
 67525            [
 67526                ".001",
 67527                ".3g2",
 67528                ".3gp",
 67529                ".amv",
 67530                ".asf",
 67531                ".asx",
 67532                ".avi",
 67533                ".bin",
 67534                ".bivx",
 67535                ".divx",
 67536                ".dv",
 67537                ".dvr-ms",
 67538                ".f4v",
 67539                ".fli",
 67540                ".flv",
 67541                ".ifo",
 67542                ".img",
 67543                ".iso",
 67544                ".m2t",
 67545                ".m2ts",
 67546                ".m2v",
 67547                ".m4v",
 67548                ".mkv",
 67549                ".mk3d",
 67550                ".mov",
 67551                ".mp4",
 67552                ".mpe",
 67553                ".mpeg",
 67554                ".mpg",
 67555                ".mts",
 67556                ".mxf",
 67557                ".nrg",
 67558                ".nsv",
 67559                ".nuv",
 67560                ".ogg",
 67561                ".ogm",
 67562                ".ogv",
 67563                ".pva",
 67564                ".qt",
 67565                ".rec",
 67566                ".rm",
 67567                ".rmvb",
 67568                ".strm",
 67569                ".svq3",
 67570                ".tp",
 67571                ".ts",
 67572                ".ty",
 67573                ".viv",
 67574                ".vob",
 67575                ".vp3",
 67576                ".webm",
 67577                ".wmv",
 67578                ".wtv",
 67579                ".xvid"
 67580            ];
 81
 67582            VideoFlagDelimiters =
 67583            [
 67584                '(',
 67585                ')',
 67586                '-',
 67587                '.',
 67588                '_',
 67589                '[',
 67590                ']'
 67591            ];
 92
 67593            StubFileExtensions =
 67594            [
 67595                ".disc"
 67596            ];
 97
 67598            StubTypes =
 67599            [
 675100                new StubTypeRule(
 675101                    stubType: "dvd",
 675102                    token: "dvd"),
 675103
 675104                new StubTypeRule(
 675105                    stubType: "hddvd",
 675106                    token: "hddvd"),
 675107
 675108                new StubTypeRule(
 675109                    stubType: "bluray",
 675110                    token: "bluray"),
 675111
 675112                new StubTypeRule(
 675113                    stubType: "bluray",
 675114                    token: "brrip"),
 675115
 675116                new StubTypeRule(
 675117                    stubType: "bluray",
 675118                    token: "bd25"),
 675119
 675120                new StubTypeRule(
 675121                    stubType: "bluray",
 675122                    token: "bd50"),
 675123
 675124                new StubTypeRule(
 675125                    stubType: "vhs",
 675126                    token: "vhs"),
 675127
 675128                new StubTypeRule(
 675129                    stubType: "tv",
 675130                    token: "HDTV"),
 675131
 675132                new StubTypeRule(
 675133                    stubType: "tv",
 675134                    token: "PDTV"),
 675135
 675136                new StubTypeRule(
 675137                    stubType: "tv",
 675138                    token: "DSR")
 675139            ];
 140
 675141            VideoFileStackingRules =
 675142            [
 675143                new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])
 675144                new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])
 675145            ];
 146
 675147            CleanDateTimes =
 675148            [
 675149                @"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\
 675150                @"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\
 675151            ];
 152
 675153            CleanStrings =
 675154            [
 675155                @"^\s*(?<cleaned>.+?)[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|d
 675156                @"^\s*(?<cleaned>.+?)((\s*\[[^\]]+\]\s*)+)(\.[^\s]+)?$",
 675157                @"^\s*(?<cleaned>.+?)\WE[0-9]+(-|~)E?[0-9]+(\W|$)",
 675158                @"^\s*\[[^\]]+\](?!\.\w+$)\s*(?<cleaned>.+)",
 675159                @"^\s*(?<cleaned>.+?)\s+-\s+[0-9]+\s*$",
 675160                @"^\s*(?<cleaned>.+?)(([-._ ](trailer|sample))|-(scene|clip|behindthescenes|deleted|deletedscene|feature
 675161            ];
 162
 675163            SubtitleFileExtensions =
 675164            [
 675165                ".ass",
 675166                ".mks",
 675167                ".sami",
 675168                ".smi",
 675169                ".srt",
 675170                ".ssa",
 675171                ".sub",
 675172                ".sup",
 675173                ".vtt",
 675174            ];
 175
 675176            LyricFileExtensions =
 675177            [
 675178                ".lrc",
 675179                ".elrc",
 675180                ".txt"
 675181            ];
 182
 675183            AlbumStackingPrefixes =
 675184            [
 675185                "cd",
 675186                "digital media",
 675187                "disc",
 675188                "disk",
 675189                "vol",
 675190                "volume",
 675191                "part",
 675192                "act"
 675193            ];
 194
 675195            ArtistSubfolders =
 675196            [
 675197                "albums",
 675198                "broadcasts",
 675199                "bootlegs",
 675200                "compilations",
 675201                "dj-mixes",
 675202                "eps",
 675203                "live",
 675204                "mixtapes",
 675205                "others",
 675206                "remixes",
 675207                "singles",
 675208                "soundtracks",
 675209                "spokenwords",
 675210                "streets"
 675211            ];
 212
 675213            AudioFileExtensions =
 675214            [
 675215                ".669",
 675216                ".3gp",
 675217                ".aa",
 675218                ".aac",
 675219                ".aax",
 675220                ".ac3",
 675221                ".act",
 675222                ".adp",
 675223                ".adplug",
 675224                ".adx",
 675225                ".afc",
 675226                ".amf",
 675227                ".aif",
 675228                ".aifc",
 675229                ".aiff",
 675230                ".alac",
 675231                ".amr",
 675232                ".ape",
 675233                ".ast",
 675234                ".au",
 675235                ".awb",
 675236                ".cda",
 675237                ".cue",
 675238                ".dmf",
 675239                ".dsf",
 675240                ".dsm",
 675241                ".dsp",
 675242                ".dts",
 675243                ".dvf",
 675244                ".eac3",
 675245                ".ec3",
 675246                ".far",
 675247                ".flac",
 675248                ".gdm",
 675249                ".gsm",
 675250                ".gym",
 675251                ".hps",
 675252                ".imf",
 675253                ".it",
 675254                ".m15",
 675255                ".m4a",
 675256                ".m4b",
 675257                ".mac",
 675258                ".med",
 675259                ".mka",
 675260                ".mmf",
 675261                ".mod",
 675262                ".mogg",
 675263                ".mp2",
 675264                ".mp3",
 675265                ".mpa",
 675266                ".mpc",
 675267                ".mpp",
 675268                ".mp+",
 675269                ".msv",
 675270                ".nmf",
 675271                ".nsf",
 675272                ".nsv",
 675273                ".oga",
 675274                ".ogg",
 675275                ".okt",
 675276                ".opus",
 675277                ".pls",
 675278                ".ra",
 675279                ".rf64",
 675280                ".rm",
 675281                ".s3m",
 675282                ".sfx",
 675283                ".shn",
 675284                ".sid",
 675285                ".stm",
 675286                ".strm",
 675287                ".ult",
 675288                ".uni",
 675289                ".vox",
 675290                ".wav",
 675291                ".wma",
 675292                ".wv",
 675293                ".xm",
 675294                ".xsp",
 675295                ".ymf"
 675296            ];
 297
 675298            MediaFlagDelimiters =
 675299            [
 675300                '.'
 675301            ];
 302
 675303            MediaForcedFlags =
 675304            [
 675305                "foreign",
 675306                "forced"
 675307            ];
 308
 675309            MediaDefaultFlags =
 675310            [
 675311                "default"
 675312            ];
 313
 675314            MediaHearingImpairedFlags =
 675315            [
 675316                "cc",
 675317                "hi",
 675318                "sdh"
 675319            ];
 320
 675321            EpisodeExpressions =
 675322            [
 675323                // *** Begin Kodi Standard Naming
 675324                // <!-- foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02 -->
 675325                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+))[^\\\/])*)?[Ss](?<s
 675326                {
 675327                    IsNamed = true
 675328                },
 675329                // <!-- foo.ep01, foo.EP_01 -->
 675330                new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
 675331                // <!-- foo.E01., foo.e01. -->
 675332                new EpisodeExpression(@"[^\\/]*?()\.?[Ee]([0-9]+)\.([^\\/]*)$"),
 675333                new EpisodeExpression("(?<year>[0-9]{4})[._ -](?<month>[0-9]{2})[._ -](?<day>[0-9]{2})", true)
 675334                {
 675335                    DateTimeFormats =
 675336                    [
 675337                        "yyyy.MM.dd",
 675338                        "yyyy-MM-dd",
 675339                        "yyyy_MM_dd",
 675340                        "yyyy MM dd"
 675341                    ]
 675342                },
 675343                new EpisodeExpression("(?<day>[0-9]{2})[._ -](?<month>[0-9]{2})[._ -](?<year>[0-9]{4})", true)
 675344                {
 675345                    DateTimeFormats =
 675346                    [
 675347                        "dd.MM.yyyy",
 675348                        "dd-MM-yyyy",
 675349                        "dd_MM_yyyy",
 675350                        "dd MM yyyy"
 675351                    ]
 675352                },
 675353
 675354                // This isn't a Kodi naming rule, but the expression below causes false episode numbers for
 675355                // Title Season X Episode X naming schemes.
 675356                // "Series Season X Episode X - Title.avi", "Series S03 E09.avi", "s3 e9 - Title.avi"
 675357                new EpisodeExpression(@".*[\\\/]((?<seriesname>[^\\/]+?)\s)?[Ss](?:eason)?\s*(?<seasonnumber>[0-9]+)\s+[
 675358                {
 675359                    IsNamed = true
 675360                },
 675361
 675362                // Not a Kodi rule as well, but the expression below also causes false positives,
 675363                // so we make sure this one gets tested first.
 675364                // "Foo Bar 889"
 675365                new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,4})(-(?<endin
 675366                {
 675367                    IsNamed = true
 675368                },
 675369
 675370                new EpisodeExpression(@"[\\\/\._ \[\(-]([0-9]+)x([0-9]+(?:(?:[a-i]|\.[1-9])(?![0-9]))?)([^\\\/]*)$")
 675371                {
 675372                    SupportsAbsoluteEpisodeNumbers = true
 675373                },
 675374
 675375                // Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names
 675376                // [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the se
 675377                new EpisodeExpression(@".*[\\\/]?.*?(\[.*?\])+.*?(?<seriesname>[-\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+
 675378                {
 675379                    IsNamed = true
 675380                },
 675381
 675382                // /server/anything_102.mp4
 675383                // /server/james.corden.2017.04.20.anne.hathaway.720p.hdtv.x264-crooks.mkv
 675384                // /server/anything_1996.11.14.mp4
 675385                new EpisodeExpression(@"[\\/._ -](?<seriesname>(?![0-9]+[0-9][0-9])([^\\\/_])*)[\\\/._ -](?<seasonnumber
 675386                {
 675387                    IsOptimistic = true,
 675388                    IsNamed = true,
 675389                    SupportsAbsoluteEpisodeNumbers = false
 675390                },
 675391                new EpisodeExpression(@"[\/._ -]p(?:ar)?t[_. -]()([ivx]+|[0-9]+)([._ -][^\/]*)$")
 675392                {
 675393                    SupportsAbsoluteEpisodeNumbers = true
 675394                },
 675395
 675396                // *** End Kodi Standard Naming
 675397
 675398                // "Episode 16", "Episode 16 - Title"
 675399                new EpisodeExpression(@"[Ee]pisode (?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))?[^\\\/]*$")
 675400                {
 675401                    IsNamed = true
 675402                },
 675403
 675404                new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]+)[xX](?<epnumber>[0-9]+)[^\\\/]*$")
 675405                {
 675406                    IsNamed = true
 675407                },
 675408
 675409                new EpisodeExpression(@".*(\\|\/)[sS](?<seasonnumber>[0-9]+)[x,X]?[eE](?<epnumber>[0-9]+)[^\\\/]*$")
 675410                {
 675411                    IsNamed = true
 675412                },
 675413
 675414                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<sea
 675415                {
 675416                    IsNamed = true
 675417                },
 675418
 675419                new EpisodeExpression(@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epn
 675420                {
 675421                    IsNamed = true
 675422                },
 675423
 675424                // "01.avi"
 675425                new EpisodeExpression(@".*[\\\/](?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))*\.\w+$")
 675426                {
 675427                    IsOptimistic = true,
 675428                    IsNamed = true
 675429                },
 675430
 675431                // "1-12 episode title"
 675432                new EpisodeExpression("([0-9]+)-([0-9]+)"),
 675433
 675434                // "01 - blah.avi", "01-blah.avi"
 675435                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\s?-\s?[^\\\/]*
 675436                {
 675437                    IsOptimistic = true,
 675438                    IsNamed = true
 675439                },
 675440
 675441                // "01.blah.avi"
 675442                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\.[^\\\/]+$")
 675443                {
 675444                    IsOptimistic = true,
 675445                    IsNamed = true
 675446                },
 675447
 675448                // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi",
 675449                new EpisodeExpression(@".*[\\\/][^\\\/]* - (?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\
 675450                {
 675451                    IsOptimistic = true,
 675452                    IsNamed = true
 675453                },
 675454
 675455                // "01 episode title.avi"
 675456                new EpisodeExpression(@"[Ss]eason[\._ ](?<seasonnumber>[0-9]+)[\\\/](?<epnumber>[0-9]{1,3})([^\\\/]*)$")
 675457                {
 675458                    IsOptimistic = true,
 675459                    IsNamed = true
 675460                },
 675461
 675462                // Series and season only expression
 675463                // "the show/season 1", "the show/s01"
 675464                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)\/[Ss](eason)?[\. _\-]*(?<seasonnumber>[0-9]+)")
 675465                {
 675466                    IsNamed = true
 675467                },
 675468
 675469                // Series and season only expression
 675470                // "the show S01", "the show season 1"
 675471                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)[\. _\-]+[sS](eason)?[\. _\-]*(?<seasonnumber>[0-9]
 675472                {
 675473                    IsNamed = true
 675474                },
 675475
 675476                // Anime style expression
 675477                // "[Group][Series Name][21][1080p][FLAC][HASH]"
 675478                // "[Group] Series Name [04][BDRIP]"
 675479                new EpisodeExpression(@"(?:\[(?:[^\]]+)\]\s*)?(?<seriesname>\[[^\]]+\]|[^[\]]+)\s*\[(?<epnumber>[0-9]+)\
 675480                {
 675481                    IsNamed = true
 675482                },
 675483            ];
 484
 675485            VideoExtraRules =
 675486            [
 675487                new ExtraRule(
 675488                    ExtraType.Trailer,
 675489                    ExtraRuleType.DirectoryName,
 675490                    "trailers",
 675491                    MediaType.Video),
 675492
 675493                new ExtraRule(
 675494                    ExtraType.ThemeVideo,
 675495                    ExtraRuleType.DirectoryName,
 675496                    "backdrops",
 675497                    MediaType.Video),
 675498
 675499                new ExtraRule(
 675500                    ExtraType.ThemeSong,
 675501                    ExtraRuleType.DirectoryName,
 675502                    "theme-music",
 675503                    MediaType.Audio),
 675504
 675505                new ExtraRule(
 675506                    ExtraType.BehindTheScenes,
 675507                    ExtraRuleType.DirectoryName,
 675508                    "behind the scenes",
 675509                    MediaType.Video),
 675510
 675511                new ExtraRule(
 675512                    ExtraType.DeletedScene,
 675513                    ExtraRuleType.DirectoryName,
 675514                    "deleted scenes",
 675515                    MediaType.Video),
 675516
 675517                new ExtraRule(
 675518                    ExtraType.Interview,
 675519                    ExtraRuleType.DirectoryName,
 675520                    "interviews",
 675521                    MediaType.Video),
 675522
 675523                new ExtraRule(
 675524                    ExtraType.Scene,
 675525                    ExtraRuleType.DirectoryName,
 675526                    "scenes",
 675527                    MediaType.Video),
 675528
 675529                new ExtraRule(
 675530                    ExtraType.Sample,
 675531                    ExtraRuleType.DirectoryName,
 675532                    "samples",
 675533                    MediaType.Video),
 675534
 675535                new ExtraRule(
 675536                    ExtraType.Short,
 675537                    ExtraRuleType.DirectoryName,
 675538                    "shorts",
 675539                    MediaType.Video),
 675540
 675541                new ExtraRule(
 675542                    ExtraType.Featurette,
 675543                    ExtraRuleType.DirectoryName,
 675544                    "featurettes",
 675545                    MediaType.Video),
 675546
 675547                new ExtraRule(
 675548                    ExtraType.Unknown,
 675549                    ExtraRuleType.DirectoryName,
 675550                    "extras",
 675551                    MediaType.Video),
 675552
 675553                new ExtraRule(
 675554                    ExtraType.Unknown,
 675555                    ExtraRuleType.DirectoryName,
 675556                    "extra",
 675557                    MediaType.Video),
 675558
 675559                new ExtraRule(
 675560                    ExtraType.Unknown,
 675561                    ExtraRuleType.DirectoryName,
 675562                    "other",
 675563                    MediaType.Video),
 675564
 675565                new ExtraRule(
 675566                    ExtraType.Clip,
 675567                    ExtraRuleType.DirectoryName,
 675568                    "clips",
 675569                    MediaType.Video),
 675570
 675571                new ExtraRule(
 675572                    ExtraType.Trailer,
 675573                    ExtraRuleType.Filename,
 675574                    "trailer",
 675575                    MediaType.Video),
 675576
 675577                new ExtraRule(
 675578                    ExtraType.Sample,
 675579                    ExtraRuleType.Filename,
 675580                    "sample",
 675581                    MediaType.Video),
 675582
 675583                new ExtraRule(
 675584                    ExtraType.ThemeSong,
 675585                    ExtraRuleType.Filename,
 675586                    "theme",
 675587                    MediaType.Audio),
 675588
 675589                new ExtraRule(
 675590                    ExtraType.Trailer,
 675591                    ExtraRuleType.Suffix,
 675592                    "-trailer",
 675593                    MediaType.Video),
 675594
 675595                new ExtraRule(
 675596                    ExtraType.Trailer,
 675597                    ExtraRuleType.Suffix,
 675598                    ".trailer",
 675599                    MediaType.Video),
 675600
 675601                new ExtraRule(
 675602                    ExtraType.Trailer,
 675603                    ExtraRuleType.Suffix,
 675604                    "_trailer",
 675605                    MediaType.Video),
 675606
 675607                new ExtraRule(
 675608                    ExtraType.Trailer,
 675609                    ExtraRuleType.Suffix,
 675610                    "- trailer",
 675611                    MediaType.Video),
 675612
 675613                new ExtraRule(
 675614                    ExtraType.Sample,
 675615                    ExtraRuleType.Suffix,
 675616                    "-sample",
 675617                    MediaType.Video),
 675618
 675619                new ExtraRule(
 675620                    ExtraType.Sample,
 675621                    ExtraRuleType.Suffix,
 675622                    ".sample",
 675623                    MediaType.Video),
 675624
 675625                new ExtraRule(
 675626                    ExtraType.Sample,
 675627                    ExtraRuleType.Suffix,
 675628                    "_sample",
 675629                    MediaType.Video),
 675630
 675631                new ExtraRule(
 675632                    ExtraType.Sample,
 675633                    ExtraRuleType.Suffix,
 675634                    "- sample",
 675635                    MediaType.Video),
 675636
 675637                new ExtraRule(
 675638                    ExtraType.Scene,
 675639                    ExtraRuleType.Suffix,
 675640                    "-scene",
 675641                    MediaType.Video),
 675642
 675643                new ExtraRule(
 675644                    ExtraType.Clip,
 675645                    ExtraRuleType.Suffix,
 675646                    "-clip",
 675647                    MediaType.Video),
 675648
 675649                new ExtraRule(
 675650                    ExtraType.Interview,
 675651                    ExtraRuleType.Suffix,
 675652                    "-interview",
 675653                    MediaType.Video),
 675654
 675655                new ExtraRule(
 675656                    ExtraType.BehindTheScenes,
 675657                    ExtraRuleType.Suffix,
 675658                    "-behindthescenes",
 675659                    MediaType.Video),
 675660
 675661                new ExtraRule(
 675662                    ExtraType.DeletedScene,
 675663                    ExtraRuleType.Suffix,
 675664                    "-deleted",
 675665                    MediaType.Video),
 675666
 675667                new ExtraRule(
 675668                    ExtraType.DeletedScene,
 675669                    ExtraRuleType.Suffix,
 675670                    "-deletedscene",
 675671                    MediaType.Video),
 675672
 675673                new ExtraRule(
 675674                    ExtraType.Featurette,
 675675                    ExtraRuleType.Suffix,
 675676                    "-featurette",
 675677                    MediaType.Video),
 675678
 675679                new ExtraRule(
 675680                    ExtraType.Short,
 675681                    ExtraRuleType.Suffix,
 675682                    "-short",
 675683                    MediaType.Video),
 675684
 675685                new ExtraRule(
 675686                    ExtraType.Unknown,
 675687                    ExtraRuleType.Suffix,
 675688                    "-extra",
 675689                    MediaType.Video),
 675690
 675691                new ExtraRule(
 675692                    ExtraType.Unknown,
 675693                    ExtraRuleType.Suffix,
 675694                    "-other",
 675695                    MediaType.Video)
 675696            ];
 697
 675698            AllExtrasTypesFolderNames = VideoExtraRules
 675699                .Where(i => i.RuleType == ExtraRuleType.DirectoryName)
 675700                .ToDictionary(i => i.Token, i => i.ExtraType, StringComparer.OrdinalIgnoreCase);
 701
 675702            Format3DRules =
 675703            [
 675704                // Kodi rules:
 675705                new Format3DRule(
 675706                    precedingToken: "3d",
 675707                    token: "hsbs"),
 675708
 675709                new Format3DRule(
 675710                    precedingToken: "3d",
 675711                    token: "sbs"),
 675712
 675713                new Format3DRule(
 675714                    precedingToken: "3d",
 675715                    token: "htab"),
 675716
 675717                new Format3DRule(
 675718                    precedingToken: "3d",
 675719                    token: "tab"),
 675720
 675721                 // Media Browser rules:
 675722                new Format3DRule("fsbs"),
 675723                new Format3DRule("hsbs"),
 675724                new Format3DRule("sbs"),
 675725                new Format3DRule("ftab"),
 675726                new Format3DRule("htab"),
 675727                new Format3DRule("tab"),
 675728                new Format3DRule("sbs3d"),
 675729                new Format3DRule("mvc")
 675730            ];
 731
 675732            AudioBookPartsExpressions =
 675733            [
 675734                // Detect specified chapters, like CH 01
 675735                @"ch(?:apter)?[\s_-]?(?<chapter>[0-9]+)",
 675736                // Detect specified parts, like Part 02
 675737                @"p(?:ar)?t[\s_-]?(?<part>[0-9]+)",
 675738                // Chapter is often beginning of filename
 675739                "^(?<chapter>[0-9]+)",
 675740                // Part if often ending of filename
 675741                "(?<!ch(?:apter) )(?<part>[0-9]+)$",
 675742                // Sometimes named as 0001_005 (chapter_part)
 675743                "(?<chapter>[0-9]+)_(?<part>[0-9]+)",
 675744                // Some audiobooks are ripped from cd's, and will be named by disk number.
 675745                @"dis(?:c|k)[\s_-]?(?<chapter>[0-9]+)"
 675746            ];
 747
 675748            AudioBookNamesExpressions =
 675749            [
 675750                // Detect year usually in brackets after name Batman (2020)
 675751                @"^(?<name>.+?)\s*\(\s*(?<year>[0-9]{4})\s*\)\s*$",
 675752                @"^\s*(?<name>[^ ].*?)\s*$"
 675753            ];
 754
 675755            MultipleEpisodeExpressions = new[]
 675756            {
 675757                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[eExX](?<endinge
 675758                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[xX][eE](?<endin
 675759                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )?[xXeE](?<endingepnumber>[
 675760                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})(-[xE]?[eE]?(?<endingepnumber>[0-9
 675761                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 675762                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 675763                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 675764                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 675765                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})((-| 
 675766                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})(-[xX
 675767            }.Select(i => new EpisodeExpression(i)
 675768            {
 675769                IsNamed = true
 675770            }).ToArray();
 771
 675772            Compile();
 675773        }
 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        {
 676905            CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray();
 676906            CleanStringRegexes = CleanStrings.Select(Compile).ToArray();
 676907        }
 908
 909        private Regex Compile(string exp)
 910        {
 5408911            return new Regex(exp, RegexOptions.IgnoreCase | RegexOptions.Compiled);
 912        }
 913    }
 914}