2019-12-13 19:11:37 +00:00
|
|
|
#pragma warning disable CS1591
|
|
|
|
|
2019-01-13 19:54:44 +00:00
|
|
|
using System;
|
2018-09-12 17:26:21 +00:00
|
|
|
using System.Linq;
|
|
|
|
using System.Text.RegularExpressions;
|
2019-01-13 19:17:29 +00:00
|
|
|
using Emby.Naming.Video;
|
2019-12-06 19:40:06 +00:00
|
|
|
using MediaBrowser.Model.Entities;
|
2018-09-12 17:26:21 +00:00
|
|
|
|
2020-11-01 10:19:22 +00:00
|
|
|
// ReSharper disable StringLiteralTypo
|
|
|
|
|
2018-09-12 17:26:21 +00:00
|
|
|
namespace Emby.Naming.Common
|
|
|
|
{
|
|
|
|
public class NamingOptions
|
|
|
|
{
|
|
|
|
public NamingOptions()
|
|
|
|
{
|
2019-05-10 18:37:42 +00:00
|
|
|
VideoFileExtensions = new[]
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
".m4v",
|
|
|
|
".3gp",
|
|
|
|
".nsv",
|
|
|
|
".ts",
|
|
|
|
".ty",
|
|
|
|
".strm",
|
|
|
|
".rm",
|
|
|
|
".rmvb",
|
|
|
|
".ifo",
|
|
|
|
".mov",
|
|
|
|
".qt",
|
|
|
|
".divx",
|
|
|
|
".xvid",
|
|
|
|
".bivx",
|
|
|
|
".vob",
|
|
|
|
".nrg",
|
|
|
|
".img",
|
|
|
|
".iso",
|
|
|
|
".pva",
|
|
|
|
".wmv",
|
|
|
|
".asf",
|
|
|
|
".asx",
|
|
|
|
".ogm",
|
|
|
|
".m2v",
|
|
|
|
".avi",
|
|
|
|
".bin",
|
|
|
|
".dvr-ms",
|
|
|
|
".mpg",
|
|
|
|
".mpeg",
|
|
|
|
".mp4",
|
|
|
|
".mkv",
|
|
|
|
".avc",
|
|
|
|
".vp3",
|
|
|
|
".svq3",
|
|
|
|
".nuv",
|
|
|
|
".viv",
|
|
|
|
".dv",
|
|
|
|
".fli",
|
|
|
|
".flv",
|
|
|
|
".001",
|
|
|
|
".tp"
|
|
|
|
};
|
|
|
|
|
|
|
|
VideoFlagDelimiters = new[]
|
|
|
|
{
|
|
|
|
'(',
|
|
|
|
')',
|
|
|
|
'-',
|
|
|
|
'.',
|
|
|
|
'_',
|
|
|
|
'[',
|
|
|
|
']'
|
|
|
|
};
|
|
|
|
|
|
|
|
StubFileExtensions = new[]
|
|
|
|
{
|
|
|
|
".disc"
|
|
|
|
};
|
|
|
|
|
|
|
|
StubTypes = new[]
|
|
|
|
{
|
2020-11-01 09:47:31 +00:00
|
|
|
new StubTypeRule(
|
|
|
|
stubType: "dvd",
|
|
|
|
token: "dvd"),
|
|
|
|
|
|
|
|
new StubTypeRule(
|
|
|
|
stubType: "hddvd",
|
|
|
|
token: "hddvd"),
|
|
|
|
|
|
|
|
new StubTypeRule(
|
|
|
|
stubType: "bluray",
|
|
|
|
token: "bluray"),
|
|
|
|
|
|
|
|
new StubTypeRule(
|
|
|
|
stubType: "bluray",
|
|
|
|
token: "brrip"),
|
|
|
|
|
|
|
|
new StubTypeRule(
|
|
|
|
stubType: "bluray",
|
|
|
|
token: "bd25"),
|
|
|
|
|
|
|
|
new StubTypeRule(
|
|
|
|
stubType: "bluray",
|
|
|
|
token: "bd50"),
|
|
|
|
|
|
|
|
new StubTypeRule(
|
|
|
|
stubType: "vhs",
|
|
|
|
token: "vhs"),
|
|
|
|
|
|
|
|
new StubTypeRule(
|
|
|
|
stubType: "tv",
|
|
|
|
token: "HDTV"),
|
|
|
|
|
|
|
|
new StubTypeRule(
|
|
|
|
stubType: "tv",
|
|
|
|
token: "PDTV"),
|
|
|
|
|
|
|
|
new StubTypeRule(
|
|
|
|
stubType: "tv",
|
|
|
|
token: "DSR")
|
2018-09-12 17:26:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
VideoFileStackingExpressions = new[]
|
|
|
|
{
|
|
|
|
"(.*?)([ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck])[ _.-]*[0-9]+)(.*?)(\\.[^.]+)$",
|
|
|
|
"(.*?)([ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck])[ _.-]*[a-d])(.*?)(\\.[^.]+)$",
|
|
|
|
"(.*?)([ ._-]*[a-d])(.*?)(\\.[^.]+)$"
|
|
|
|
};
|
|
|
|
|
|
|
|
CleanDateTimes = new[]
|
|
|
|
{
|
2020-08-12 15:02:19 +00:00
|
|
|
@"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19[0-9]{2}|20[0-9]{2})*",
|
|
|
|
@"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19[0-9]{2}|20[0-9]{2})*"
|
2018-09-12 17:26:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
CleanStrings = new[]
|
|
|
|
{
|
2020-05-03 16:17:55 +00:00
|
|
|
@"[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|cd[1-9]|r3|r5|bd5|bd|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|480p|480i|576p|576i|720p|720i|1080p|1080i|2160p|hrhd|hrhdtv|hddvd|bluray|x264|h264|xvid|xvidvd|xxx|www.www|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
|
2018-09-12 17:26:21 +00:00
|
|
|
@"(\[.*\])"
|
|
|
|
};
|
|
|
|
|
|
|
|
SubtitleFileExtensions = new[]
|
|
|
|
{
|
|
|
|
".srt",
|
|
|
|
".ssa",
|
|
|
|
".ass",
|
|
|
|
".sub"
|
|
|
|
};
|
|
|
|
|
|
|
|
SubtitleFlagDelimiters = new[]
|
|
|
|
{
|
|
|
|
'.'
|
|
|
|
};
|
|
|
|
|
|
|
|
SubtitleForcedFlags = new[]
|
|
|
|
{
|
|
|
|
"foreign",
|
|
|
|
"forced"
|
|
|
|
};
|
|
|
|
|
|
|
|
SubtitleDefaultFlags = new[]
|
|
|
|
{
|
|
|
|
"default"
|
|
|
|
};
|
|
|
|
|
|
|
|
AlbumStackingPrefixes = new[]
|
|
|
|
{
|
|
|
|
"disc",
|
|
|
|
"cd",
|
|
|
|
"disk",
|
|
|
|
"vol",
|
|
|
|
"volume"
|
|
|
|
};
|
|
|
|
|
|
|
|
AudioFileExtensions = new[]
|
|
|
|
{
|
|
|
|
".nsv",
|
|
|
|
".m4a",
|
|
|
|
".flac",
|
|
|
|
".aac",
|
|
|
|
".strm",
|
|
|
|
".pls",
|
|
|
|
".rm",
|
|
|
|
".mpa",
|
|
|
|
".wav",
|
|
|
|
".wma",
|
|
|
|
".ogg",
|
|
|
|
".opus",
|
|
|
|
".mp3",
|
|
|
|
".mp2",
|
|
|
|
".mod",
|
|
|
|
".amf",
|
|
|
|
".669",
|
|
|
|
".dmf",
|
|
|
|
".dsm",
|
|
|
|
".far",
|
|
|
|
".gdm",
|
|
|
|
".imf",
|
|
|
|
".it",
|
|
|
|
".m15",
|
|
|
|
".med",
|
|
|
|
".okt",
|
|
|
|
".s3m",
|
|
|
|
".stm",
|
|
|
|
".sfx",
|
|
|
|
".ult",
|
|
|
|
".uni",
|
|
|
|
".xm",
|
|
|
|
".sid",
|
|
|
|
".ac3",
|
|
|
|
".dts",
|
|
|
|
".cue",
|
|
|
|
".aif",
|
|
|
|
".aiff",
|
|
|
|
".ape",
|
|
|
|
".mac",
|
|
|
|
".mpc",
|
|
|
|
".mp+",
|
|
|
|
".mpp",
|
|
|
|
".shn",
|
|
|
|
".wv",
|
|
|
|
".nsf",
|
|
|
|
".spc",
|
|
|
|
".gym",
|
|
|
|
".adplug",
|
|
|
|
".adx",
|
|
|
|
".dsp",
|
|
|
|
".adp",
|
|
|
|
".ymf",
|
|
|
|
".ast",
|
|
|
|
".afc",
|
|
|
|
".hps",
|
|
|
|
".xsp",
|
|
|
|
".acc",
|
|
|
|
".m4b",
|
|
|
|
".oga",
|
|
|
|
".dsf",
|
|
|
|
".mka"
|
|
|
|
};
|
|
|
|
|
|
|
|
EpisodeExpressions = new[]
|
|
|
|
{
|
|
|
|
// *** Begin Kodi Standard Naming
|
|
|
|
// <!-- foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02 -->
|
|
|
|
new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+))[^\\\/])*)?[Ss](?<seasonnumber>[0-9]+)[][ ._-]*[Ee](?<epnumber>[0-9]+)([^\\/]*)$")
|
|
|
|
{
|
|
|
|
IsNamed = true
|
2019-01-07 23:27:46 +00:00
|
|
|
},
|
2018-09-12 17:26:21 +00:00
|
|
|
// <!-- foo.ep01, foo.EP_01 -->
|
|
|
|
new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
|
|
|
|
new EpisodeExpression("([0-9]{4})[\\.-]([0-9]{2})[\\.-]([0-9]{2})", true)
|
|
|
|
{
|
2019-05-10 18:37:42 +00:00
|
|
|
DateTimeFormats = new[]
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
"yyyy.MM.dd",
|
|
|
|
"yyyy-MM-dd",
|
|
|
|
"yyyy_MM_dd"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
new EpisodeExpression("([0-9]{2})[\\.-]([0-9]{2})[\\.-]([0-9]{4})", true)
|
|
|
|
{
|
2019-05-10 18:37:42 +00:00
|
|
|
DateTimeFormats = new[]
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
"dd.MM.yyyy",
|
|
|
|
"dd-MM-yyyy",
|
|
|
|
"dd_MM_yyyy"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-11-09 19:26:56 +00:00
|
|
|
// This isn't a Kodi naming rule, but the expression below causes false positives,
|
|
|
|
// so we make sure this one gets tested first.
|
2019-11-08 18:59:48 +00:00
|
|
|
// "Foo Bar 889"
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\/x]*$")
|
2019-11-08 18:59:48 +00:00
|
|
|
{
|
|
|
|
IsNamed = true
|
|
|
|
},
|
|
|
|
|
2018-09-12 17:26:21 +00:00
|
|
|
new EpisodeExpression("[\\\\/\\._ \\[\\(-]([0-9]+)x([0-9]+(?:(?:[a-i]|\\.[1-9])(?![0-9]))?)([^\\\\/]*)$")
|
|
|
|
{
|
|
|
|
SupportsAbsoluteEpisodeNumbers = true
|
|
|
|
},
|
|
|
|
new EpisodeExpression(@"[\\\\/\\._ -](?<seriesname>(?![0-9]+[0-9][0-9])([^\\\/])*)[\\\\/\\._ -](?<seasonnumber>[0-9]+)(?<epnumber>[0-9][0-9](?:(?:[a-i]|\\.[1-9])(?![0-9]))?)([\\._ -][^\\\\/]*)$")
|
|
|
|
{
|
|
|
|
IsOptimistic = true,
|
|
|
|
IsNamed = true,
|
|
|
|
SupportsAbsoluteEpisodeNumbers = false
|
|
|
|
},
|
|
|
|
new EpisodeExpression("[\\/._ -]p(?:ar)?t[_. -]()([ivx]+|[0-9]+)([._ -][^\\/]*)$")
|
|
|
|
{
|
|
|
|
SupportsAbsoluteEpisodeNumbers = true
|
|
|
|
},
|
|
|
|
|
|
|
|
// *** End Kodi Standard Naming
|
|
|
|
|
2020-01-11 18:39:11 +00:00
|
|
|
// [bar] Foo - 1 [baz]
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[-\s_]+(?<epnumber>[0-9]+).*$")
|
2019-11-08 18:59:48 +00:00
|
|
|
{
|
|
|
|
IsNamed = true
|
2019-10-11 10:24:55 +00:00
|
|
|
},
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]+)[xX](?<epnumber>[0-9]+)[^\\\/]*$")
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
IsNamed = true
|
|
|
|
},
|
|
|
|
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*(\\|\/)[sS](?<seasonnumber>[0-9]+)[x,X]?[eE](?<epnumber>[0-9]+)[^\\\/]*$")
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
IsNamed = true
|
|
|
|
},
|
|
|
|
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]+))[^\\\/]*$")
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
IsNamed = true
|
|
|
|
},
|
|
|
|
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]+)[^\\\/]*$")
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
IsNamed = true
|
|
|
|
},
|
|
|
|
|
|
|
|
// "01.avi"
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*[\\\/](?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))*\.\w+$")
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
IsOptimistic = true,
|
|
|
|
IsNamed = true
|
|
|
|
},
|
|
|
|
|
|
|
|
// "1-12 episode title"
|
2019-05-10 18:37:42 +00:00
|
|
|
new EpisodeExpression(@"([0-9]+)-([0-9]+)"),
|
2018-09-12 17:26:21 +00:00
|
|
|
|
|
|
|
// "01 - blah.avi", "01-blah.avi"
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\s?-\s?[^\\\/]*$")
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
IsOptimistic = true,
|
|
|
|
IsNamed = true
|
|
|
|
},
|
|
|
|
|
|
|
|
// "01.blah.avi"
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\.[^\\\/]+$")
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
IsOptimistic = true,
|
|
|
|
IsNamed = true
|
|
|
|
},
|
|
|
|
|
|
|
|
// "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi", "blah 2 - 01 - blah"
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*[\\\/][^\\\/]* - (?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\/]*$")
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
IsOptimistic = true,
|
|
|
|
IsNamed = true
|
|
|
|
},
|
|
|
|
|
|
|
|
// "01 episode title.avi"
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@"[Ss]eason[\._ ](?<seasonnumber>[0-9]+)[\\\/](?<epnumber>[0-9]{1,3})([^\\\/]*)$")
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
IsOptimistic = true,
|
|
|
|
IsNamed = true
|
|
|
|
},
|
|
|
|
// "Episode 16", "Episode 16 - Title"
|
2020-07-20 12:14:15 +00:00
|
|
|
new EpisodeExpression(@".*[\\\/][^\\\/]* (?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\/]*$")
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
|
|
|
IsOptimistic = true,
|
|
|
|
IsNamed = true
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
EpisodeWithoutSeasonExpressions = new[]
|
|
|
|
{
|
|
|
|
@"[/\._ \-]()([0-9]+)(-[0-9]+)?"
|
|
|
|
};
|
|
|
|
|
|
|
|
EpisodeMultiPartExpressions = new[]
|
|
|
|
{
|
|
|
|
@"^[-_ex]+([0-9]+(?:(?:[a-i]|\\.[1-9])(?![0-9]))?)"
|
|
|
|
};
|
|
|
|
|
|
|
|
VideoExtraRules = new[]
|
|
|
|
{
|
2020-11-01 09:47:31 +00:00
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Trailer,
|
|
|
|
ExtraRuleType.Filename,
|
|
|
|
"trailer",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Trailer,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"-trailer",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Trailer,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
".trailer",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Trailer,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"_trailer",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Trailer,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
" trailer",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Sample,
|
|
|
|
ExtraRuleType.Filename,
|
|
|
|
"sample",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Sample,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"-sample",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Sample,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
".sample",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Sample,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"_sample",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Sample,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
" sample",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.ThemeSong,
|
|
|
|
ExtraRuleType.Filename,
|
|
|
|
"theme",
|
|
|
|
MediaType.Audio),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Scene,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"-scene",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Clip,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"-clip",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Interview,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"-interview",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.BehindTheScenes,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"-behindthescenes",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.DeletedScene,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"-deleted",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Clip,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"-featurette",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Clip,
|
|
|
|
ExtraRuleType.Suffix,
|
|
|
|
"-short",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.BehindTheScenes,
|
|
|
|
ExtraRuleType.DirectoryName,
|
|
|
|
"behind the scenes",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.DeletedScene,
|
|
|
|
ExtraRuleType.DirectoryName,
|
|
|
|
"deleted scenes",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Interview,
|
|
|
|
ExtraRuleType.DirectoryName,
|
|
|
|
"interviews",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Scene,
|
|
|
|
ExtraRuleType.DirectoryName,
|
|
|
|
"scenes",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Sample,
|
|
|
|
ExtraRuleType.DirectoryName,
|
|
|
|
"samples",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Clip,
|
|
|
|
ExtraRuleType.DirectoryName,
|
|
|
|
"shorts",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Clip,
|
|
|
|
ExtraRuleType.DirectoryName,
|
|
|
|
"featurettes",
|
|
|
|
MediaType.Video),
|
|
|
|
|
|
|
|
new ExtraRule(
|
|
|
|
ExtraType.Unknown,
|
|
|
|
ExtraRuleType.DirectoryName,
|
|
|
|
"extras",
|
|
|
|
MediaType.Video),
|
2018-09-12 17:26:21 +00:00
|
|
|
};
|
2019-05-10 18:37:42 +00:00
|
|
|
|
2018-09-12 17:26:21 +00:00
|
|
|
Format3DRules = new[]
|
|
|
|
{
|
|
|
|
// Kodi rules:
|
2020-11-01 09:47:31 +00:00
|
|
|
new Format3DRule(
|
2020-11-01 10:19:22 +00:00
|
|
|
precedingToken: "3d",
|
2020-11-01 09:47:31 +00:00
|
|
|
token: "hsbs"),
|
|
|
|
|
|
|
|
new Format3DRule(
|
2020-11-01 10:19:22 +00:00
|
|
|
precedingToken: "3d",
|
2020-11-01 09:47:31 +00:00
|
|
|
token: "sbs"),
|
|
|
|
|
|
|
|
new Format3DRule(
|
2020-11-01 10:19:22 +00:00
|
|
|
precedingToken: "3d",
|
2020-11-01 09:47:31 +00:00
|
|
|
token: "htab"),
|
|
|
|
|
|
|
|
new Format3DRule(
|
2020-11-01 10:19:22 +00:00
|
|
|
precedingToken: "3d",
|
2020-11-01 09:47:31 +00:00
|
|
|
token: "tab"),
|
|
|
|
|
|
|
|
// Media Browser rules:
|
|
|
|
new Format3DRule("fsbs"),
|
|
|
|
new Format3DRule("hsbs"),
|
|
|
|
new Format3DRule("sbs"),
|
|
|
|
new Format3DRule("ftab"),
|
|
|
|
new Format3DRule("htab"),
|
|
|
|
new Format3DRule("tab"),
|
|
|
|
new Format3DRule("sbs3d"),
|
|
|
|
new Format3DRule("mvc")
|
2018-09-12 17:26:21 +00:00
|
|
|
};
|
2020-11-01 09:47:31 +00:00
|
|
|
|
2018-09-12 17:26:21 +00:00
|
|
|
AudioBookPartsExpressions = new[]
|
|
|
|
{
|
|
|
|
// Detect specified chapters, like CH 01
|
2020-07-20 12:14:15 +00:00
|
|
|
@"ch(?:apter)?[\s_-]?(?<chapter>[0-9]+)",
|
2018-09-12 17:26:21 +00:00
|
|
|
// Detect specified parts, like Part 02
|
2020-07-20 12:14:15 +00:00
|
|
|
@"p(?:ar)?t[\s_-]?(?<part>[0-9]+)",
|
2018-09-12 17:26:21 +00:00
|
|
|
// Chapter is often beginning of filename
|
2020-07-20 12:14:15 +00:00
|
|
|
"^(?<chapter>[0-9]+)",
|
2018-09-12 17:26:21 +00:00
|
|
|
// Part if often ending of filename
|
2020-07-20 12:14:15 +00:00
|
|
|
"(?<part>[0-9]+)$",
|
2018-09-12 17:26:21 +00:00
|
|
|
// Sometimes named as 0001_005 (chapter_part)
|
2020-07-20 12:14:15 +00:00
|
|
|
"(?<chapter>[0-9]+)_(?<part>[0-9]+)",
|
2018-09-12 17:26:21 +00:00
|
|
|
// Some audiobooks are ripped from cd's, and will be named by disk number.
|
2020-07-20 12:14:15 +00:00
|
|
|
@"dis(?:c|k)[\s_-]?(?<chapter>[0-9]+)"
|
2018-09-12 17:26:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
var extensions = VideoFileExtensions.ToList();
|
|
|
|
|
|
|
|
extensions.AddRange(new[]
|
|
|
|
{
|
|
|
|
".mkv",
|
|
|
|
".m2t",
|
|
|
|
".m2ts",
|
|
|
|
".img",
|
|
|
|
".iso",
|
|
|
|
".mk3d",
|
|
|
|
".ts",
|
|
|
|
".rmvb",
|
|
|
|
".mov",
|
|
|
|
".avi",
|
|
|
|
".mpg",
|
|
|
|
".mpeg",
|
|
|
|
".wmv",
|
|
|
|
".mp4",
|
|
|
|
".divx",
|
|
|
|
".dvr-ms",
|
|
|
|
".wtv",
|
|
|
|
".ogm",
|
|
|
|
".ogv",
|
|
|
|
".asf",
|
|
|
|
".m4v",
|
|
|
|
".flv",
|
|
|
|
".f4v",
|
|
|
|
".3gp",
|
|
|
|
".webm",
|
|
|
|
".mts",
|
|
|
|
".m2v",
|
|
|
|
".rec",
|
|
|
|
".mxf"
|
|
|
|
});
|
|
|
|
|
2020-11-01 10:19:22 +00:00
|
|
|
MultipleEpisodeExpressions = new[]
|
2018-09-12 17:26:21 +00:00
|
|
|
{
|
2020-07-20 12:14:15 +00:00
|
|
|
@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[eExX](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
|
|
|
|
@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[xX][eE](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
|
|
|
|
@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )?[xXeE](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
|
|
|
|
@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})(-[xE]?[eE]?(?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
|
|
|
|
@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3}))((-| - )[0-9]{1,4}[xXeE](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
|
|
|
|
@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3}))((-| - )[0-9]{1,4}[xX][eE](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
|
|
|
|
@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3}))((-| - )?[xXeE](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
|
|
|
|
@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3}))(-[xX]?[eE]?(?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
|
|
|
|
@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})((-| - )?[xXeE](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
|
|
|
|
@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})(-[xX]?[eE]?(?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$"
|
2018-09-12 17:26:21 +00:00
|
|
|
}.Select(i => new EpisodeExpression(i)
|
2019-10-11 10:24:55 +00:00
|
|
|
{
|
|
|
|
IsNamed = true
|
|
|
|
}).ToArray();
|
2018-09-12 17:26:21 +00:00
|
|
|
|
|
|
|
VideoFileExtensions = extensions
|
|
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
|
|
.ToArray();
|
|
|
|
|
|
|
|
Compile();
|
|
|
|
}
|
|
|
|
|
2020-01-22 21:18:56 +00:00
|
|
|
public string[] AudioFileExtensions { get; set; }
|
|
|
|
|
|
|
|
public string[] AlbumStackingPrefixes { get; set; }
|
|
|
|
|
|
|
|
public string[] SubtitleFileExtensions { get; set; }
|
|
|
|
|
|
|
|
public char[] SubtitleFlagDelimiters { get; set; }
|
|
|
|
|
|
|
|
public string[] SubtitleForcedFlags { get; set; }
|
|
|
|
|
|
|
|
public string[] SubtitleDefaultFlags { get; set; }
|
|
|
|
|
|
|
|
public EpisodeExpression[] EpisodeExpressions { get; set; }
|
|
|
|
|
|
|
|
public string[] EpisodeWithoutSeasonExpressions { get; set; }
|
|
|
|
|
|
|
|
public string[] EpisodeMultiPartExpressions { get; set; }
|
|
|
|
|
|
|
|
public string[] VideoFileExtensions { get; set; }
|
|
|
|
|
|
|
|
public string[] StubFileExtensions { get; set; }
|
|
|
|
|
|
|
|
public string[] AudioBookPartsExpressions { get; set; }
|
|
|
|
|
|
|
|
public StubTypeRule[] StubTypes { get; set; }
|
|
|
|
|
|
|
|
public char[] VideoFlagDelimiters { get; set; }
|
|
|
|
|
|
|
|
public Format3DRule[] Format3DRules { get; set; }
|
|
|
|
|
|
|
|
public string[] VideoFileStackingExpressions { get; set; }
|
|
|
|
|
|
|
|
public string[] CleanDateTimes { get; set; }
|
|
|
|
|
|
|
|
public string[] CleanStrings { get; set; }
|
|
|
|
|
|
|
|
public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
|
|
|
|
|
|
|
|
public ExtraRule[] VideoExtraRules { get; set; }
|
|
|
|
|
2020-11-01 09:47:31 +00:00
|
|
|
public Regex[] VideoFileStackingRegexes { get; private set; } = Array.Empty<Regex>();
|
2020-01-22 21:18:56 +00:00
|
|
|
|
2020-11-01 09:47:31 +00:00
|
|
|
public Regex[] CleanDateTimeRegexes { get; private set; } = Array.Empty<Regex>();
|
2020-01-22 21:18:56 +00:00
|
|
|
|
2020-11-01 09:47:31 +00:00
|
|
|
public Regex[] CleanStringRegexes { get; private set; } = Array.Empty<Regex>();
|
2018-09-12 17:26:21 +00:00
|
|
|
|
2020-11-01 09:47:31 +00:00
|
|
|
public Regex[] EpisodeWithoutSeasonRegexes { get; private set; } = Array.Empty<Regex>();
|
2020-01-22 21:18:56 +00:00
|
|
|
|
2020-11-01 09:47:31 +00:00
|
|
|
public Regex[] EpisodeMultiPartRegexes { get; private set; } = Array.Empty<Regex>();
|
2018-09-12 17:26:21 +00:00
|
|
|
|
|
|
|
public void Compile()
|
|
|
|
{
|
|
|
|
VideoFileStackingRegexes = VideoFileStackingExpressions.Select(Compile).ToArray();
|
|
|
|
CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray();
|
|
|
|
CleanStringRegexes = CleanStrings.Select(Compile).ToArray();
|
|
|
|
EpisodeWithoutSeasonRegexes = EpisodeWithoutSeasonExpressions.Select(Compile).ToArray();
|
|
|
|
EpisodeMultiPartRegexes = EpisodeMultiPartExpressions.Select(Compile).ToArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
private Regex Compile(string exp)
|
|
|
|
{
|
|
|
|
return new Regex(exp, RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|