< Summary - Jellyfin

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

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

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

Coverage delta

Coverage delta 1 -1

Metrics

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

File(s)

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

#LineLine coverage
 1#pragma warning disable CA1819
 2
 3using System;
 4using System.Collections.Generic;
 5using System.Linq;
 6using System.Text.RegularExpressions;
 7using Emby.Naming.Video;
 8using MediaBrowser.Model.Entities;
 9
 10// ReSharper disable StringLiteralTypo
 11
 12namespace Emby.Naming.Common
 13{
 14    /// <summary>
 15    /// Big ugly class containing lot of different naming options that should be split and injected instead of passes ev
 16    /// </summary>
 17    public class NamingOptions
 18    {
 19        /// <summary>
 20        /// Initializes a new instance of the <see cref="NamingOptions"/> class.
 21        /// </summary>
 22        public NamingOptions()
 23        {
 72224            VideoFileExtensions =
 72225            [
 72226                ".001",
 72227                ".3g2",
 72228                ".3gp",
 72229                ".amv",
 72230                ".asf",
 72231                ".asx",
 72232                ".avi",
 72233                ".bin",
 72234                ".bivx",
 72235                ".divx",
 72236                ".dv",
 72237                ".dvr-ms",
 72238                ".f4v",
 72239                ".fli",
 72240                ".flv",
 72241                ".ifo",
 72242                ".img",
 72243                ".iso",
 72244                ".m2t",
 72245                ".m2ts",
 72246                ".m2v",
 72247                ".m4v",
 72248                ".mkv",
 72249                ".mk3d",
 72250                ".mov",
 72251                ".mp4",
 72252                ".mpe",
 72253                ".mpeg",
 72254                ".mpg",
 72255                ".mts",
 72256                ".mxf",
 72257                ".nrg",
 72258                ".nsv",
 72259                ".nuv",
 72260                ".ogg",
 72261                ".ogm",
 72262                ".ogv",
 72263                ".pva",
 72264                ".qt",
 72265                ".rec",
 72266                ".rm",
 72267                ".rmvb",
 72268                ".strm",
 72269                ".svq3",
 72270                ".tp",
 72271                ".ts",
 72272                ".ty",
 72273                ".viv",
 72274                ".vob",
 72275                ".vp3",
 72276                ".webm",
 72277                ".wmv",
 72278                ".wtv",
 72279                ".xvid"
 72280            ];
 81
 72282            VideoFlagDelimiters =
 72283            [
 72284                '(',
 72285                ')',
 72286                '-',
 72287                '.',
 72288                '_',
 72289                '[',
 72290                ']'
 72291            ];
 92
 72293            StubFileExtensions =
 72294            [
 72295                ".disc"
 72296            ];
 97
 72298            StubTypes =
 72299            [
 722100                new StubTypeRule(
 722101                    stubType: "dvd",
 722102                    token: "dvd"),
 722103
 722104                new StubTypeRule(
 722105                    stubType: "hddvd",
 722106                    token: "hddvd"),
 722107
 722108                new StubTypeRule(
 722109                    stubType: "bluray",
 722110                    token: "bluray"),
 722111
 722112                new StubTypeRule(
 722113                    stubType: "bluray",
 722114                    token: "brrip"),
 722115
 722116                new StubTypeRule(
 722117                    stubType: "bluray",
 722118                    token: "bd25"),
 722119
 722120                new StubTypeRule(
 722121                    stubType: "bluray",
 722122                    token: "bd50"),
 722123
 722124                new StubTypeRule(
 722125                    stubType: "vhs",
 722126                    token: "vhs"),
 722127
 722128                new StubTypeRule(
 722129                    stubType: "tv",
 722130                    token: "HDTV"),
 722131
 722132                new StubTypeRule(
 722133                    stubType: "tv",
 722134                    token: "PDTV"),
 722135
 722136                new StubTypeRule(
 722137                    stubType: "tv",
 722138                    token: "DSR")
 722139            ];
 140
 722141            VideoFileStackingRules =
 722142            [
 722143                new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])
 722144                new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])
 722145            ];
 146
 722147            CleanDateTimes =
 722148            [
 722149                @"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\
 722150                @"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\
 722151            ];
 152
 722153            CleanStrings =
 722154            [
 722155                @"^\s*(?<cleaned>.+?)[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|d
 722156                @"^\s*(?<cleaned>.+?)((\s*\[[^\]]+\]\s*)+)(\.[^\s]+)?$",
 722157                @"^\s*(?<cleaned>.+?)\WE[0-9]+(-|~)E?[0-9]+(\W|$)",
 722158                @"^\s*\[[^\]]+\](?!\.\w+$)\s*(?<cleaned>.+)",
 722159                @"^\s*(?<cleaned>.+?)\s+-\s+[0-9]+\s*$",
 722160                @"^\s*(?<cleaned>.+?)(([-._ ](trailer|sample))|-(scene|clip|behindthescenes|deleted|deletedscene|feature
 722161            ];
 162
 722163            SubtitleFileExtensions =
 722164            [
 722165                ".ass",
 722166                ".mks",
 722167                ".sami",
 722168                ".smi",
 722169                ".srt",
 722170                ".ssa",
 722171                ".sub",
 722172                ".sup",
 722173                ".vtt",
 722174            ];
 175
 722176            LyricFileExtensions =
 722177            [
 722178                ".lrc",
 722179                ".elrc",
 722180                ".txt"
 722181            ];
 182
 722183            AlbumStackingPrefixes =
 722184            [
 722185                "cd",
 722186                "digital media",
 722187                "disc",
 722188                "disk",
 722189                "vol",
 722190                "volume",
 722191                "part",
 722192                "act"
 722193            ];
 194
 722195            ArtistSubfolders =
 722196            [
 722197                "albums",
 722198                "broadcasts",
 722199                "bootlegs",
 722200                "compilations",
 722201                "dj-mixes",
 722202                "eps",
 722203                "live",
 722204                "mixtapes",
 722205                "others",
 722206                "remixes",
 722207                "singles",
 722208                "soundtracks",
 722209                "spokenwords",
 722210                "streets"
 722211            ];
 212
 722213            AudioFileExtensions =
 722214            [
 722215                ".669",
 722216                ".3gp",
 722217                ".aa",
 722218                ".aac",
 722219                ".aax",
 722220                ".ac3",
 722221                ".act",
 722222                ".adp",
 722223                ".adplug",
 722224                ".adx",
 722225                ".afc",
 722226                ".amf",
 722227                ".aif",
 722228                ".aifc",
 722229                ".aiff",
 722230                ".alac",
 722231                ".amr",
 722232                ".ape",
 722233                ".ast",
 722234                ".au",
 722235                ".awb",
 722236                ".cda",
 722237                ".cue",
 722238                ".dmf",
 722239                ".dsf",
 722240                ".dsm",
 722241                ".dsp",
 722242                ".dts",
 722243                ".dvf",
 722244                ".eac3",
 722245                ".ec3",
 722246                ".far",
 722247                ".flac",
 722248                ".gdm",
 722249                ".gsm",
 722250                ".gym",
 722251                ".hps",
 722252                ".imf",
 722253                ".it",
 722254                ".m15",
 722255                ".m4a",
 722256                ".m4b",
 722257                ".mac",
 722258                ".med",
 722259                ".mka",
 722260                ".mmf",
 722261                ".mod",
 722262                ".mogg",
 722263                ".mp2",
 722264                ".mp3",
 722265                ".mpa",
 722266                ".mpc",
 722267                ".mpp",
 722268                ".mp+",
 722269                ".msv",
 722270                ".nmf",
 722271                ".nsf",
 722272                ".nsv",
 722273                ".oga",
 722274                ".ogg",
 722275                ".okt",
 722276                ".opus",
 722277                ".pls",
 722278                ".ra",
 722279                ".rf64",
 722280                ".rm",
 722281                ".s3m",
 722282                ".sfx",
 722283                ".shn",
 722284                ".sid",
 722285                ".stm",
 722286                ".strm",
 722287                ".ult",
 722288                ".uni",
 722289                ".vox",
 722290                ".wav",
 722291                ".wma",
 722292                ".wv",
 722293                ".xm",
 722294                ".xsp",
 722295                ".ymf"
 722296            ];
 297
 722298            MediaFlagDelimiters =
 722299            [
 722300                '.'
 722301            ];
 302
 722303            MediaForcedFlags =
 722304            [
 722305                "foreign",
 722306                "forced"
 722307            ];
 308
 722309            MediaDefaultFlags =
 722310            [
 722311                "default"
 722312            ];
 313
 722314            MediaHearingImpairedFlags =
 722315            [
 722316                "cc",
 722317                "hi",
 722318                "sdh"
 722319            ];
 320
 722321            EpisodeExpressions =
 722322            [
 722323                // *** Begin Kodi Standard Naming
 722324                // <!-- foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02 -->
 722325                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+))[^\\\/])*)?[Ss](?<s
 722326                {
 722327                    IsNamed = true
 722328                },
 722329                // <!-- foo.ep01, foo.EP_01 -->
 722330                new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
 722331                // <!-- foo.E01., foo.e01. -->
 722332                new EpisodeExpression(@"[^\\/]*?()\.?[Ee]([0-9]+)\.([^\\/]*)$"),
 722333                new EpisodeExpression("(?<year>[0-9]{4})[._ -](?<month>[0-9]{2})[._ -](?<day>[0-9]{2})", true)
 722334                {
 722335                    DateTimeFormats =
 722336                    [
 722337                        "yyyy.MM.dd",
 722338                        "yyyy-MM-dd",
 722339                        "yyyy_MM_dd",
 722340                        "yyyy MM dd"
 722341                    ]
 722342                },
 722343                new EpisodeExpression("(?<day>[0-9]{2})[._ -](?<month>[0-9]{2})[._ -](?<year>[0-9]{4})", true)
 722344                {
 722345                    DateTimeFormats =
 722346                    [
 722347                        "dd.MM.yyyy",
 722348                        "dd-MM-yyyy",
 722349                        "dd_MM_yyyy",
 722350                        "dd MM yyyy"
 722351                    ]
 722352                },
 722353
 722354                // This isn't a Kodi naming rule, but the expression below causes false episode numbers for
 722355                // Title Season X Episode X naming schemes.
 722356                // "Series Season X Episode X - Title.avi", "Series S03 E09.avi", "s3 e9 - Title.avi"
 722357                new EpisodeExpression(@".*[\\\/]((?<seriesname>[^\\/]+?)\s)?[Ss](?:eason)?\s*(?<seasonnumber>[0-9]+)\s+[
 722358                {
 722359                    IsNamed = true
 722360                },
 722361
 722362                // Not a Kodi rule as well, but the expression below also causes false positives,
 722363                // so we make sure this one gets tested first.
 722364                // "Foo Bar 889"
 722365                new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,4})(-(?<endin
 722366                {
 722367                    IsNamed = true
 722368                },
 722369
 722370                new EpisodeExpression(@"[\\\/\._ \[\(-]([0-9]+)x([0-9]+(?:(?:[a-i]|\.[1-9])(?![0-9]))?)([^\\\/]*)$")
 722371                {
 722372                    SupportsAbsoluteEpisodeNumbers = true
 722373                },
 722374
 722375                // Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names
 722376                // [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the se
 722377                new EpisodeExpression(@".*[\\\/]?.*?(\[.*?\])+.*?(?<seriesname>[-\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+
 722378                {
 722379                    IsNamed = true
 722380                },
 722381
 722382                // "Name - 101.mkv", "Name - 101 [720p].mkv", "Name - 101 (2020).mkv"
 722383                // Handles absolute episode numbers with hyphen delimiter (common in anime)
 722384                // Without brackets (bracketed version handled above)
 722385                new EpisodeExpression(@".*[\\\/](?<seriesname>[^\\\/]+?)[\s_]+-[\s_]+(?<epnumber>[0-9]+)[\s_]*(?:\[.*?\]
 722386                {
 722387                    IsNamed = true
 722388                },
 722389
 722390                // /server/anything_102.mp4
 722391                // /server/james.corden.2017.04.20.anne.hathaway.720p.hdtv.x264-crooks.mkv
 722392                // /server/anything_1996.11.14.mp4
 722393                new EpisodeExpression(@"[\\/._ -](?<seriesname>(?![0-9]+[0-9][0-9])([^\\\/_])*)[\\\/._ -](?<seasonnumber
 722394                {
 722395                    IsOptimistic = true,
 722396                    IsNamed = true,
 722397                    SupportsAbsoluteEpisodeNumbers = false
 722398                },
 722399                new EpisodeExpression(@"[\/._ -]p(?:ar)?t[_. -]()([ivx]+|[0-9]+)([._ -][^\/]*)$")
 722400                {
 722401                    SupportsAbsoluteEpisodeNumbers = true
 722402                },
 722403
 722404                // *** End Kodi Standard Naming
 722405
 722406                // "Episode 16", "Episode 16 - Title"
 722407                new EpisodeExpression(@"[Ee]pisode (?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))?[^\\\/]*$")
 722408                {
 722409                    IsNamed = true
 722410                },
 722411
 722412                new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]+)[xX](?<epnumber>[0-9]+)[^\\\/]*$")
 722413                {
 722414                    IsNamed = true
 722415                },
 722416
 722417                new EpisodeExpression(@".*(\\|\/)[sS](?<seasonnumber>[0-9]+)[x,X]?[eE](?<epnumber>[0-9]+)[^\\\/]*$")
 722418                {
 722419                    IsNamed = true
 722420                },
 722421
 722422                new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<sea
 722423                {
 722424                    IsNamed = true
 722425                },
 722426
 722427                new EpisodeExpression(@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epn
 722428                {
 722429                    IsNamed = true
 722430                },
 722431
 722432                // "01.avi"
 722433                new EpisodeExpression(@".*[\\\/](?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))*\.\w+$")
 722434                {
 722435                    IsOptimistic = true,
 722436                    IsNamed = true
 722437                },
 722438
 722439                // "1-12 episode title"
 722440                new EpisodeExpression("([0-9]+)-([0-9]+)"),
 722441
 722442                // "01 - blah.avi", "01-blah.avi"
 722443                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\s?-\s?[^\\\/]*
 722444                {
 722445                    IsOptimistic = true,
 722446                    IsNamed = true
 722447                },
 722448
 722449                // "01.blah.avi"
 722450                new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\.[^\\\/]+$")
 722451                {
 722452                    IsOptimistic = true,
 722453                    IsNamed = true
 722454                },
 722455
 722456                // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi",
 722457                new EpisodeExpression(@".*[\\\/][^\\\/]* - (?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\
 722458                {
 722459                    IsOptimistic = true,
 722460                    IsNamed = true
 722461                },
 722462
 722463                // "01 episode title.avi"
 722464                new EpisodeExpression(@"[Ss]eason[\._ ](?<seasonnumber>[0-9]+)[\\\/](?<epnumber>[0-9]{1,3})([^\\\/]*)$")
 722465                {
 722466                    IsOptimistic = true,
 722467                    IsNamed = true
 722468                },
 722469
 722470                // Series and season only expression
 722471                // "the show/season 1", "the show/s01"
 722472                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)\/[Ss](eason)?[\. _\-]*(?<seasonnumber>[0-9]+)")
 722473                {
 722474                    IsNamed = true
 722475                },
 722476
 722477                // Series and season only expression
 722478                // "the show S01", "the show season 1"
 722479                new EpisodeExpression(@"(.*(\\|\/))*(?<seriesname>.+)[\. _\-]+[sS](eason)?[\. _\-]*(?<seasonnumber>[0-9]
 722480                {
 722481                    IsNamed = true
 722482                },
 722483
 722484                // Anime style expression
 722485                // "[Group][Series Name][21][1080p][FLAC][HASH]"
 722486                // "[Group] Series Name [04][BDRIP]"
 722487                new EpisodeExpression(@"(?:\[(?:[^\]]+)\]\s*)?(?<seriesname>\[[^\]]+\]|[^[\]]+)\s*\[(?<epnumber>[0-9]+)\
 722488                {
 722489                    IsNamed = true
 722490                },
 722491            ];
 492
 722493            VideoExtraRules =
 722494            [
 722495                new ExtraRule(
 722496                    ExtraType.Trailer,
 722497                    ExtraRuleType.DirectoryName,
 722498                    "trailers",
 722499                    MediaType.Video),
 722500
 722501                new ExtraRule(
 722502                    ExtraType.ThemeVideo,
 722503                    ExtraRuleType.DirectoryName,
 722504                    "backdrops",
 722505                    MediaType.Video),
 722506
 722507                new ExtraRule(
 722508                    ExtraType.ThemeSong,
 722509                    ExtraRuleType.DirectoryName,
 722510                    "theme-music",
 722511                    MediaType.Audio),
 722512
 722513                new ExtraRule(
 722514                    ExtraType.BehindTheScenes,
 722515                    ExtraRuleType.DirectoryName,
 722516                    "behind the scenes",
 722517                    MediaType.Video),
 722518
 722519                new ExtraRule(
 722520                    ExtraType.DeletedScene,
 722521                    ExtraRuleType.DirectoryName,
 722522                    "deleted scenes",
 722523                    MediaType.Video),
 722524
 722525                new ExtraRule(
 722526                    ExtraType.Interview,
 722527                    ExtraRuleType.DirectoryName,
 722528                    "interviews",
 722529                    MediaType.Video),
 722530
 722531                new ExtraRule(
 722532                    ExtraType.Scene,
 722533                    ExtraRuleType.DirectoryName,
 722534                    "scenes",
 722535                    MediaType.Video),
 722536
 722537                new ExtraRule(
 722538                    ExtraType.Sample,
 722539                    ExtraRuleType.DirectoryName,
 722540                    "samples",
 722541                    MediaType.Video),
 722542
 722543                new ExtraRule(
 722544                    ExtraType.Short,
 722545                    ExtraRuleType.DirectoryName,
 722546                    "shorts",
 722547                    MediaType.Video),
 722548
 722549                new ExtraRule(
 722550                    ExtraType.Featurette,
 722551                    ExtraRuleType.DirectoryName,
 722552                    "featurettes",
 722553                    MediaType.Video),
 722554
 722555                new ExtraRule(
 722556                    ExtraType.Unknown,
 722557                    ExtraRuleType.DirectoryName,
 722558                    "extras",
 722559                    MediaType.Video),
 722560
 722561                new ExtraRule(
 722562                    ExtraType.Unknown,
 722563                    ExtraRuleType.DirectoryName,
 722564                    "extra",
 722565                    MediaType.Video),
 722566
 722567                new ExtraRule(
 722568                    ExtraType.Unknown,
 722569                    ExtraRuleType.DirectoryName,
 722570                    "other",
 722571                    MediaType.Video),
 722572
 722573                new ExtraRule(
 722574                    ExtraType.Clip,
 722575                    ExtraRuleType.DirectoryName,
 722576                    "clips",
 722577                    MediaType.Video),
 722578
 722579                new ExtraRule(
 722580                    ExtraType.Trailer,
 722581                    ExtraRuleType.Filename,
 722582                    "trailer",
 722583                    MediaType.Video),
 722584
 722585                new ExtraRule(
 722586                    ExtraType.Sample,
 722587                    ExtraRuleType.Filename,
 722588                    "sample",
 722589                    MediaType.Video),
 722590
 722591                new ExtraRule(
 722592                    ExtraType.ThemeSong,
 722593                    ExtraRuleType.Filename,
 722594                    "theme",
 722595                    MediaType.Audio),
 722596
 722597                new ExtraRule(
 722598                    ExtraType.Trailer,
 722599                    ExtraRuleType.Suffix,
 722600                    "-trailer",
 722601                    MediaType.Video),
 722602
 722603                new ExtraRule(
 722604                    ExtraType.Trailer,
 722605                    ExtraRuleType.Suffix,
 722606                    ".trailer",
 722607                    MediaType.Video),
 722608
 722609                new ExtraRule(
 722610                    ExtraType.Trailer,
 722611                    ExtraRuleType.Suffix,
 722612                    "_trailer",
 722613                    MediaType.Video),
 722614
 722615                new ExtraRule(
 722616                    ExtraType.Trailer,
 722617                    ExtraRuleType.Suffix,
 722618                    "- trailer",
 722619                    MediaType.Video),
 722620
 722621                new ExtraRule(
 722622                    ExtraType.Sample,
 722623                    ExtraRuleType.Suffix,
 722624                    "-sample",
 722625                    MediaType.Video),
 722626
 722627                new ExtraRule(
 722628                    ExtraType.Sample,
 722629                    ExtraRuleType.Suffix,
 722630                    ".sample",
 722631                    MediaType.Video),
 722632
 722633                new ExtraRule(
 722634                    ExtraType.Sample,
 722635                    ExtraRuleType.Suffix,
 722636                    "_sample",
 722637                    MediaType.Video),
 722638
 722639                new ExtraRule(
 722640                    ExtraType.Sample,
 722641                    ExtraRuleType.Suffix,
 722642                    "- sample",
 722643                    MediaType.Video),
 722644
 722645                new ExtraRule(
 722646                    ExtraType.Scene,
 722647                    ExtraRuleType.Suffix,
 722648                    "-scene",
 722649                    MediaType.Video),
 722650
 722651                new ExtraRule(
 722652                    ExtraType.Clip,
 722653                    ExtraRuleType.Suffix,
 722654                    "-clip",
 722655                    MediaType.Video),
 722656
 722657                new ExtraRule(
 722658                    ExtraType.Interview,
 722659                    ExtraRuleType.Suffix,
 722660                    "-interview",
 722661                    MediaType.Video),
 722662
 722663                new ExtraRule(
 722664                    ExtraType.BehindTheScenes,
 722665                    ExtraRuleType.Suffix,
 722666                    "-behindthescenes",
 722667                    MediaType.Video),
 722668
 722669                new ExtraRule(
 722670                    ExtraType.DeletedScene,
 722671                    ExtraRuleType.Suffix,
 722672                    "-deleted",
 722673                    MediaType.Video),
 722674
 722675                new ExtraRule(
 722676                    ExtraType.DeletedScene,
 722677                    ExtraRuleType.Suffix,
 722678                    "-deletedscene",
 722679                    MediaType.Video),
 722680
 722681                new ExtraRule(
 722682                    ExtraType.Featurette,
 722683                    ExtraRuleType.Suffix,
 722684                    "-featurette",
 722685                    MediaType.Video),
 722686
 722687                new ExtraRule(
 722688                    ExtraType.Short,
 722689                    ExtraRuleType.Suffix,
 722690                    "-short",
 722691                    MediaType.Video),
 722692
 722693                new ExtraRule(
 722694                    ExtraType.Unknown,
 722695                    ExtraRuleType.Suffix,
 722696                    "-extra",
 722697                    MediaType.Video),
 722698
 722699                new ExtraRule(
 722700                    ExtraType.Unknown,
 722701                    ExtraRuleType.Suffix,
 722702                    "-other",
 722703                    MediaType.Video)
 722704            ];
 705
 722706            AllExtrasTypesFolderNames = VideoExtraRules
 722707                .Where(i => i.RuleType == ExtraRuleType.DirectoryName)
 722708                .ToDictionary(i => i.Token, i => i.ExtraType, StringComparer.OrdinalIgnoreCase);
 709
 722710            Format3DRules =
 722711            [
 722712                // Kodi rules:
 722713                new Format3DRule(
 722714                    precedingToken: "3d",
 722715                    token: "hsbs"),
 722716
 722717                new Format3DRule(
 722718                    precedingToken: "3d",
 722719                    token: "sbs"),
 722720
 722721                new Format3DRule(
 722722                    precedingToken: "3d",
 722723                    token: "htab"),
 722724
 722725                new Format3DRule(
 722726                    precedingToken: "3d",
 722727                    token: "tab"),
 722728
 722729                 // Media Browser rules:
 722730                new Format3DRule("fsbs"),
 722731                new Format3DRule("hsbs"),
 722732                new Format3DRule("sbs"),
 722733                new Format3DRule("ftab"),
 722734                new Format3DRule("htab"),
 722735                new Format3DRule("tab"),
 722736                new Format3DRule("sbs3d"),
 722737                new Format3DRule("mvc")
 722738            ];
 739
 722740            AudioBookPartsExpressions =
 722741            [
 722742                // Detect specified chapters, like CH 01
 722743                @"ch(?:apter)?[\s_-]?(?<chapter>[0-9]+)",
 722744                // Detect specified parts, like Part 02
 722745                @"p(?:ar)?t[\s_-]?(?<part>[0-9]+)",
 722746                // Chapter is often beginning of filename
 722747                "^(?<chapter>[0-9]+)",
 722748                // Part if often ending of filename
 722749                "(?<!ch(?:apter) )(?<part>[0-9]+)$",
 722750                // Sometimes named as 0001_005 (chapter_part)
 722751                "(?<chapter>[0-9]+)_(?<part>[0-9]+)",
 722752                // Some audiobooks are ripped from cd's, and will be named by disk number.
 722753                @"dis(?:c|k)[\s_-]?(?<chapter>[0-9]+)"
 722754            ];
 755
 722756            AudioBookNamesExpressions =
 722757            [
 722758                // Detect year usually in brackets after name Batman (2020)
 722759                @"^(?<name>.+?)\s*\(\s*(?<year>[0-9]{4})\s*\)\s*$",
 722760                @"^\s*(?<name>[^ ].*?)\s*$"
 722761            ];
 762
 722763            MultipleEpisodeExpressions = new[]
 722764            {
 722765                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[eExX](?<endinge
 722766                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[xX][eE](?<endin
 722767                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )?[xXeE](?<endingepnumber>[
 722768                @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})(-[xE]?[eE]?(?<endingepnumber>[0-9
 722769                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 722770                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 722771                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 722772                @".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[
 722773                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})((-| 
 722774                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})(-[xX
 722775            }.Select(i => new EpisodeExpression(i)
 722776            {
 722777                IsNamed = true
 722778            }).ToArray();
 779
 722780            Compile();
 722781        }
 782
 783        /// <summary>
 784        /// Gets or sets the folder name to extra types mapping.
 785        /// </summary>
 786        public Dictionary<string, ExtraType> AllExtrasTypesFolderNames { get; set; }
 787
 788        /// <summary>
 789        /// Gets or sets list of audio file extensions.
 790        /// </summary>
 791        public string[] AudioFileExtensions { get; set; }
 792
 793        /// <summary>
 794        /// Gets or sets list of external media flag delimiters.
 795        /// </summary>
 796        public char[] MediaFlagDelimiters { get; set; }
 797
 798        /// <summary>
 799        /// Gets or sets list of external media forced flags.
 800        /// </summary>
 801        public string[] MediaForcedFlags { get; set; }
 802
 803        /// <summary>
 804        /// Gets or sets list of external media default flags.
 805        /// </summary>
 806        public string[] MediaDefaultFlags { get; set; }
 807
 808        /// <summary>
 809        /// Gets or sets list of external media hearing impaired flags.
 810        /// </summary>
 811        public string[] MediaHearingImpairedFlags { get; set; }
 812
 813        /// <summary>
 814        /// Gets or sets list of album stacking prefixes.
 815        /// </summary>
 816        public string[] AlbumStackingPrefixes { get; set; }
 817
 818        /// <summary>
 819        /// Gets or sets list of artist subfolders.
 820        /// </summary>
 821        public string[] ArtistSubfolders { get; set; }
 822
 823        /// <summary>
 824        /// Gets or sets list of subtitle file extensions.
 825        /// </summary>
 826        public string[] SubtitleFileExtensions { get; set; }
 827
 828        /// <summary>
 829        /// Gets the list of lyric file extensions.
 830        /// </summary>
 831        public string[] LyricFileExtensions { get; }
 832
 833        /// <summary>
 834        /// Gets or sets list of episode regular expressions.
 835        /// </summary>
 836        public EpisodeExpression[] EpisodeExpressions { get; set; }
 837
 838        /// <summary>
 839        /// Gets or sets list of video file extensions.
 840        /// </summary>
 841        public string[] VideoFileExtensions { get; set; }
 842
 843        /// <summary>
 844        /// Gets or sets list of video stub file extensions.
 845        /// </summary>
 846        public string[] StubFileExtensions { get; set; }
 847
 848        /// <summary>
 849        /// Gets or sets list of raw audiobook parts regular expressions strings.
 850        /// </summary>
 851        public string[] AudioBookPartsExpressions { get; set; }
 852
 853        /// <summary>
 854        /// Gets or sets list of raw audiobook names regular expressions strings.
 855        /// </summary>
 856        public string[] AudioBookNamesExpressions { get; set; }
 857
 858        /// <summary>
 859        /// Gets or sets list of stub type rules.
 860        /// </summary>
 861        public StubTypeRule[] StubTypes { get; set; }
 862
 863        /// <summary>
 864        /// Gets or sets list of video flag delimiters.
 865        /// </summary>
 866        public char[] VideoFlagDelimiters { get; set; }
 867
 868        /// <summary>
 869        /// Gets or sets list of 3D Format rules.
 870        /// </summary>
 871        public Format3DRule[] Format3DRules { get; set; }
 872
 873        /// <summary>
 874        /// Gets the file stacking rules.
 875        /// </summary>
 876        public FileStackRule[] VideoFileStackingRules { get; }
 877
 878        /// <summary>
 879        /// Gets or sets list of raw clean DateTimes regular expressions strings.
 880        /// </summary>
 881        public string[] CleanDateTimes { get; set; }
 882
 883        /// <summary>
 884        /// Gets or sets list of raw clean strings regular expressions strings.
 885        /// </summary>
 886        public string[] CleanStrings { get; set; }
 887
 888        /// <summary>
 889        /// Gets or sets list of multi-episode regular expressions.
 890        /// </summary>
 891        public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
 892
 893        /// <summary>
 894        /// Gets or sets list of extra rules for videos.
 895        /// </summary>
 896        public ExtraRule[] VideoExtraRules { get; set; }
 897
 898        /// <summary>
 899        /// Gets list of clean datetime regular expressions.
 900        /// </summary>
 901        public Regex[] CleanDateTimeRegexes { get; private set; } = [];
 902
 903        /// <summary>
 904        /// Gets list of clean string regular expressions.
 905        /// </summary>
 906        public Regex[] CleanStringRegexes { get; private set; } = [];
 907
 908        /// <summary>
 909        /// Compiles raw regex strings into regexes.
 910        /// </summary>
 911        public void Compile()
 912        {
 723913            CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray();
 723914            CleanStringRegexes = CleanStrings.Select(Compile).ToArray();
 723915        }
 916
 917        private Regex Compile(string exp)
 918        {
 5784919            return new Regex(exp, RegexOptions.IgnoreCase | RegexOptions.Compiled);
 920        }
 921    }
 922}