NamingOptions.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. #pragma warning disable CS1591
  2. using System;
  3. using System.Linq;
  4. using System.Text.RegularExpressions;
  5. using Emby.Naming.Video;
  6. using MediaBrowser.Model.Entities;
  7. namespace Emby.Naming.Common
  8. {
  9. public class NamingOptions
  10. {
  11. public NamingOptions()
  12. {
  13. VideoFileExtensions = new[]
  14. {
  15. ".m4v",
  16. ".3gp",
  17. ".nsv",
  18. ".ts",
  19. ".ty",
  20. ".strm",
  21. ".rm",
  22. ".rmvb",
  23. ".ifo",
  24. ".mov",
  25. ".qt",
  26. ".divx",
  27. ".xvid",
  28. ".bivx",
  29. ".vob",
  30. ".nrg",
  31. ".img",
  32. ".iso",
  33. ".pva",
  34. ".wmv",
  35. ".asf",
  36. ".asx",
  37. ".ogm",
  38. ".m2v",
  39. ".avi",
  40. ".bin",
  41. ".dvr-ms",
  42. ".mpg",
  43. ".mpeg",
  44. ".mp4",
  45. ".mkv",
  46. ".avc",
  47. ".vp3",
  48. ".svq3",
  49. ".nuv",
  50. ".viv",
  51. ".dv",
  52. ".fli",
  53. ".flv",
  54. ".001",
  55. ".tp"
  56. };
  57. VideoFlagDelimiters = new[]
  58. {
  59. '(',
  60. ')',
  61. '-',
  62. '.',
  63. '_',
  64. '[',
  65. ']'
  66. };
  67. StubFileExtensions = new[]
  68. {
  69. ".disc"
  70. };
  71. StubTypes = new[]
  72. {
  73. new StubTypeRule
  74. {
  75. StubType = "dvd",
  76. Token = "dvd"
  77. },
  78. new StubTypeRule
  79. {
  80. StubType = "hddvd",
  81. Token = "hddvd"
  82. },
  83. new StubTypeRule
  84. {
  85. StubType = "bluray",
  86. Token = "bluray"
  87. },
  88. new StubTypeRule
  89. {
  90. StubType = "bluray",
  91. Token = "brrip"
  92. },
  93. new StubTypeRule
  94. {
  95. StubType = "bluray",
  96. Token = "bd25"
  97. },
  98. new StubTypeRule
  99. {
  100. StubType = "bluray",
  101. Token = "bd50"
  102. },
  103. new StubTypeRule
  104. {
  105. StubType = "vhs",
  106. Token = "vhs"
  107. },
  108. new StubTypeRule
  109. {
  110. StubType = "tv",
  111. Token = "HDTV"
  112. },
  113. new StubTypeRule
  114. {
  115. StubType = "tv",
  116. Token = "PDTV"
  117. },
  118. new StubTypeRule
  119. {
  120. StubType = "tv",
  121. Token = "DSR"
  122. }
  123. };
  124. VideoFileStackingExpressions = new[]
  125. {
  126. "(.*?)([ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck])[ _.-]*[0-9]+)(.*?)(\\.[^.]+)$",
  127. "(.*?)([ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck])[ _.-]*[a-d])(.*?)(\\.[^.]+)$",
  128. "(.*?)([ ._-]*[a-d])(.*?)(\\.[^.]+)$"
  129. };
  130. CleanDateTimes = new[]
  131. {
  132. @"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](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})*",
  133. @"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(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})*"
  134. };
  135. CleanStrings = new[]
  136. {
  137. @"[ _\,\.\(\)\[\]\-](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|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
  138. @"(\[.*\])"
  139. };
  140. SubtitleFileExtensions = new[]
  141. {
  142. ".srt",
  143. ".ssa",
  144. ".ass",
  145. ".sub"
  146. };
  147. SubtitleFlagDelimiters = new[]
  148. {
  149. '.'
  150. };
  151. SubtitleForcedFlags = new[]
  152. {
  153. "foreign",
  154. "forced"
  155. };
  156. SubtitleDefaultFlags = new[]
  157. {
  158. "default"
  159. };
  160. AlbumStackingPrefixes = new[]
  161. {
  162. "disc",
  163. "cd",
  164. "disk",
  165. "vol",
  166. "volume"
  167. };
  168. AudioFileExtensions = new[]
  169. {
  170. ".nsv",
  171. ".m4a",
  172. ".flac",
  173. ".aac",
  174. ".strm",
  175. ".pls",
  176. ".rm",
  177. ".mpa",
  178. ".wav",
  179. ".wma",
  180. ".ogg",
  181. ".opus",
  182. ".mp3",
  183. ".mp2",
  184. ".mod",
  185. ".amf",
  186. ".669",
  187. ".dmf",
  188. ".dsm",
  189. ".far",
  190. ".gdm",
  191. ".imf",
  192. ".it",
  193. ".m15",
  194. ".med",
  195. ".okt",
  196. ".s3m",
  197. ".stm",
  198. ".sfx",
  199. ".ult",
  200. ".uni",
  201. ".xm",
  202. ".sid",
  203. ".ac3",
  204. ".dts",
  205. ".cue",
  206. ".aif",
  207. ".aiff",
  208. ".ape",
  209. ".mac",
  210. ".mpc",
  211. ".mp+",
  212. ".mpp",
  213. ".shn",
  214. ".wv",
  215. ".nsf",
  216. ".spc",
  217. ".gym",
  218. ".adplug",
  219. ".adx",
  220. ".dsp",
  221. ".adp",
  222. ".ymf",
  223. ".ast",
  224. ".afc",
  225. ".hps",
  226. ".xsp",
  227. ".acc",
  228. ".m4b",
  229. ".oga",
  230. ".dsf",
  231. ".mka"
  232. };
  233. EpisodeExpressions = new[]
  234. {
  235. // *** Begin Kodi Standard Naming
  236. // <!-- foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02 -->
  237. new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+))[^\\\/])*)?[Ss](?<seasonnumber>[0-9]+)[][ ._-]*[Ee](?<epnumber>[0-9]+)([^\\/]*)$")
  238. {
  239. IsNamed = true
  240. },
  241. // <!-- foo.ep01, foo.EP_01 -->
  242. new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
  243. new EpisodeExpression("([0-9]{4})[\\.-]([0-9]{2})[\\.-]([0-9]{2})", true)
  244. {
  245. DateTimeFormats = new[]
  246. {
  247. "yyyy.MM.dd",
  248. "yyyy-MM-dd",
  249. "yyyy_MM_dd"
  250. }
  251. },
  252. new EpisodeExpression("([0-9]{2})[\\.-]([0-9]{2})[\\.-]([0-9]{4})", true)
  253. {
  254. DateTimeFormats = new[]
  255. {
  256. "dd.MM.yyyy",
  257. "dd-MM-yyyy",
  258. "dd_MM_yyyy"
  259. }
  260. },
  261. // This isn't a Kodi naming rule, but the expression below causes false positives,
  262. // so we make sure this one gets tested first.
  263. // "Foo Bar 889"
  264. new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\/x]*$")
  265. {
  266. IsNamed = true
  267. },
  268. new EpisodeExpression("[\\\\/\\._ \\[\\(-]([0-9]+)x([0-9]+(?:(?:[a-i]|\\.[1-9])(?![0-9]))?)([^\\\\/]*)$")
  269. {
  270. SupportsAbsoluteEpisodeNumbers = true
  271. },
  272. new EpisodeExpression(@"[\\\\/\\._ -](?<seriesname>(?![0-9]+[0-9][0-9])([^\\\/])*)[\\\\/\\._ -](?<seasonnumber>[0-9]+)(?<epnumber>[0-9][0-9](?:(?:[a-i]|\\.[1-9])(?![0-9]))?)([\\._ -][^\\\\/]*)$")
  273. {
  274. IsOptimistic = true,
  275. IsNamed = true,
  276. SupportsAbsoluteEpisodeNumbers = false
  277. },
  278. new EpisodeExpression("[\\/._ -]p(?:ar)?t[_. -]()([ivx]+|[0-9]+)([._ -][^\\/]*)$")
  279. {
  280. SupportsAbsoluteEpisodeNumbers = true
  281. },
  282. // *** End Kodi Standard Naming
  283. // [bar] Foo - 1 [baz]
  284. new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[-\s_]+(?<epnumber>[0-9]+).*$")
  285. {
  286. IsNamed = true
  287. },
  288. new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]+)[xX](?<epnumber>[0-9]+)[^\\\/]*$")
  289. {
  290. IsNamed = true
  291. },
  292. new EpisodeExpression(@".*(\\|\/)[sS](?<seasonnumber>[0-9]+)[x,X]?[eE](?<epnumber>[0-9]+)[^\\\/]*$")
  293. {
  294. IsNamed = true
  295. },
  296. new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![sS]?[0-9]{1,4}[xX][0-9]{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]+))[^\\\/]*$")
  297. {
  298. IsNamed = true
  299. },
  300. new EpisodeExpression(@".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]+)[^\\\/]*$")
  301. {
  302. IsNamed = true
  303. },
  304. // "01.avi"
  305. new EpisodeExpression(@".*[\\\/](?<epnumber>[0-9]+)(-(?<endingepnumber>[0-9]+))*\.\w+$")
  306. {
  307. IsOptimistic = true,
  308. IsNamed = true
  309. },
  310. // "1-12 episode title"
  311. new EpisodeExpression(@"([0-9]+)-([0-9]+)"),
  312. // "01 - blah.avi", "01-blah.avi"
  313. new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\s?-\s?[^\\\/]*$")
  314. {
  315. IsOptimistic = true,
  316. IsNamed = true
  317. },
  318. // "01.blah.avi"
  319. new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\.[^\\\/]+$")
  320. {
  321. IsOptimistic = true,
  322. IsNamed = true
  323. },
  324. // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi", "blah 2 - 01 - blah"
  325. new EpisodeExpression(@".*[\\\/][^\\\/]* - (?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\/]*$")
  326. {
  327. IsOptimistic = true,
  328. IsNamed = true
  329. },
  330. // "01 episode title.avi"
  331. new EpisodeExpression(@"[Ss]eason[\._ ](?<seasonnumber>[0-9]+)[\\\/](?<epnumber>[0-9]{1,3})([^\\\/]*)$")
  332. {
  333. IsOptimistic = true,
  334. IsNamed = true
  335. },
  336. // "Episode 16", "Episode 16 - Title"
  337. new EpisodeExpression(@".*[\\\/][^\\\/]* (?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*[^\\\/]*$")
  338. {
  339. IsOptimistic = true,
  340. IsNamed = true
  341. }
  342. };
  343. EpisodeWithoutSeasonExpressions = new[]
  344. {
  345. @"[/\._ \-]()([0-9]+)(-[0-9]+)?"
  346. };
  347. EpisodeMultiPartExpressions = new[]
  348. {
  349. @"^[-_ex]+([0-9]+(?:(?:[a-i]|\\.[1-9])(?![0-9]))?)"
  350. };
  351. VideoExtraRules = new[]
  352. {
  353. new ExtraRule
  354. {
  355. ExtraType = ExtraType.Trailer,
  356. RuleType = ExtraRuleType.Filename,
  357. Token = "trailer",
  358. MediaType = MediaType.Video
  359. },
  360. new ExtraRule
  361. {
  362. ExtraType = ExtraType.Trailer,
  363. RuleType = ExtraRuleType.Suffix,
  364. Token = "-trailer",
  365. MediaType = MediaType.Video
  366. },
  367. new ExtraRule
  368. {
  369. ExtraType = ExtraType.Trailer,
  370. RuleType = ExtraRuleType.Suffix,
  371. Token = ".trailer",
  372. MediaType = MediaType.Video
  373. },
  374. new ExtraRule
  375. {
  376. ExtraType = ExtraType.Trailer,
  377. RuleType = ExtraRuleType.Suffix,
  378. Token = "_trailer",
  379. MediaType = MediaType.Video
  380. },
  381. new ExtraRule
  382. {
  383. ExtraType = ExtraType.Trailer,
  384. RuleType = ExtraRuleType.Suffix,
  385. Token = " trailer",
  386. MediaType = MediaType.Video
  387. },
  388. new ExtraRule
  389. {
  390. ExtraType = ExtraType.Sample,
  391. RuleType = ExtraRuleType.Filename,
  392. Token = "sample",
  393. MediaType = MediaType.Video
  394. },
  395. new ExtraRule
  396. {
  397. ExtraType = ExtraType.Sample,
  398. RuleType = ExtraRuleType.Suffix,
  399. Token = "-sample",
  400. MediaType = MediaType.Video
  401. },
  402. new ExtraRule
  403. {
  404. ExtraType = ExtraType.Sample,
  405. RuleType = ExtraRuleType.Suffix,
  406. Token = ".sample",
  407. MediaType = MediaType.Video
  408. },
  409. new ExtraRule
  410. {
  411. ExtraType = ExtraType.Sample,
  412. RuleType = ExtraRuleType.Suffix,
  413. Token = "_sample",
  414. MediaType = MediaType.Video
  415. },
  416. new ExtraRule
  417. {
  418. ExtraType = ExtraType.Sample,
  419. RuleType = ExtraRuleType.Suffix,
  420. Token = " sample",
  421. MediaType = MediaType.Video
  422. },
  423. new ExtraRule
  424. {
  425. ExtraType = ExtraType.ThemeSong,
  426. RuleType = ExtraRuleType.Filename,
  427. Token = "theme",
  428. MediaType = MediaType.Audio
  429. },
  430. new ExtraRule
  431. {
  432. ExtraType = ExtraType.Scene,
  433. RuleType = ExtraRuleType.Suffix,
  434. Token = "-scene",
  435. MediaType = MediaType.Video
  436. },
  437. new ExtraRule
  438. {
  439. ExtraType = ExtraType.Clip,
  440. RuleType = ExtraRuleType.Suffix,
  441. Token = "-clip",
  442. MediaType = MediaType.Video
  443. },
  444. new ExtraRule
  445. {
  446. ExtraType = ExtraType.Interview,
  447. RuleType = ExtraRuleType.Suffix,
  448. Token = "-interview",
  449. MediaType = MediaType.Video
  450. },
  451. new ExtraRule
  452. {
  453. ExtraType = ExtraType.BehindTheScenes,
  454. RuleType = ExtraRuleType.Suffix,
  455. Token = "-behindthescenes",
  456. MediaType = MediaType.Video
  457. },
  458. new ExtraRule
  459. {
  460. ExtraType = ExtraType.DeletedScene,
  461. RuleType = ExtraRuleType.Suffix,
  462. Token = "-deleted",
  463. MediaType = MediaType.Video
  464. },
  465. new ExtraRule
  466. {
  467. ExtraType = ExtraType.Clip,
  468. RuleType = ExtraRuleType.Suffix,
  469. Token = "-featurette",
  470. MediaType = MediaType.Video
  471. },
  472. new ExtraRule
  473. {
  474. ExtraType = ExtraType.Clip,
  475. RuleType = ExtraRuleType.Suffix,
  476. Token = "-short",
  477. MediaType = MediaType.Video
  478. },
  479. new ExtraRule
  480. {
  481. ExtraType = ExtraType.BehindTheScenes,
  482. RuleType = ExtraRuleType.DirectoryName,
  483. Token = "behind the scenes",
  484. MediaType = MediaType.Video,
  485. },
  486. new ExtraRule
  487. {
  488. ExtraType = ExtraType.DeletedScene,
  489. RuleType = ExtraRuleType.DirectoryName,
  490. Token = "deleted scenes",
  491. MediaType = MediaType.Video,
  492. },
  493. new ExtraRule
  494. {
  495. ExtraType = ExtraType.Interview,
  496. RuleType = ExtraRuleType.DirectoryName,
  497. Token = "interviews",
  498. MediaType = MediaType.Video,
  499. },
  500. new ExtraRule
  501. {
  502. ExtraType = ExtraType.Scene,
  503. RuleType = ExtraRuleType.DirectoryName,
  504. Token = "scenes",
  505. MediaType = MediaType.Video,
  506. },
  507. new ExtraRule
  508. {
  509. ExtraType = ExtraType.Sample,
  510. RuleType = ExtraRuleType.DirectoryName,
  511. Token = "samples",
  512. MediaType = MediaType.Video,
  513. },
  514. new ExtraRule
  515. {
  516. ExtraType = ExtraType.Clip,
  517. RuleType = ExtraRuleType.DirectoryName,
  518. Token = "shorts",
  519. MediaType = MediaType.Video,
  520. },
  521. new ExtraRule
  522. {
  523. ExtraType = ExtraType.Clip,
  524. RuleType = ExtraRuleType.DirectoryName,
  525. Token = "featurettes",
  526. MediaType = MediaType.Video,
  527. },
  528. new ExtraRule
  529. {
  530. ExtraType = ExtraType.Unknown,
  531. RuleType = ExtraRuleType.DirectoryName,
  532. Token = "extras",
  533. MediaType = MediaType.Video,
  534. },
  535. };
  536. Format3DRules = new[]
  537. {
  538. // Kodi rules:
  539. new Format3DRule
  540. {
  541. PreceedingToken = "3d",
  542. Token = "hsbs"
  543. },
  544. new Format3DRule
  545. {
  546. PreceedingToken = "3d",
  547. Token = "sbs"
  548. },
  549. new Format3DRule
  550. {
  551. PreceedingToken = "3d",
  552. Token = "htab"
  553. },
  554. new Format3DRule
  555. {
  556. PreceedingToken = "3d",
  557. Token = "tab"
  558. },
  559. // Media Browser rules:
  560. new Format3DRule
  561. {
  562. Token = "fsbs"
  563. },
  564. new Format3DRule
  565. {
  566. Token = "hsbs"
  567. },
  568. new Format3DRule
  569. {
  570. Token = "sbs"
  571. },
  572. new Format3DRule
  573. {
  574. Token = "ftab"
  575. },
  576. new Format3DRule
  577. {
  578. Token = "htab"
  579. },
  580. new Format3DRule
  581. {
  582. Token = "tab"
  583. },
  584. new Format3DRule
  585. {
  586. Token = "sbs3d"
  587. },
  588. new Format3DRule
  589. {
  590. Token = "mvc"
  591. }
  592. };
  593. AudioBookPartsExpressions = new[]
  594. {
  595. // Detect specified chapters, like CH 01
  596. @"ch(?:apter)?[\s_-]?(?<chapter>[0-9]+)",
  597. // Detect specified parts, like Part 02
  598. @"p(?:ar)?t[\s_-]?(?<part>[0-9]+)",
  599. // Chapter is often beginning of filename
  600. "^(?<chapter>[0-9]+)",
  601. // Part if often ending of filename
  602. "(?<part>[0-9]+)$",
  603. // Sometimes named as 0001_005 (chapter_part)
  604. "(?<chapter>[0-9]+)_(?<part>[0-9]+)",
  605. // Some audiobooks are ripped from cd's, and will be named by disk number.
  606. @"dis(?:c|k)[\s_-]?(?<chapter>[0-9]+)"
  607. };
  608. var extensions = VideoFileExtensions.ToList();
  609. extensions.AddRange(new[]
  610. {
  611. ".mkv",
  612. ".m2t",
  613. ".m2ts",
  614. ".img",
  615. ".iso",
  616. ".mk3d",
  617. ".ts",
  618. ".rmvb",
  619. ".mov",
  620. ".avi",
  621. ".mpg",
  622. ".mpeg",
  623. ".wmv",
  624. ".mp4",
  625. ".divx",
  626. ".dvr-ms",
  627. ".wtv",
  628. ".ogm",
  629. ".ogv",
  630. ".asf",
  631. ".m4v",
  632. ".flv",
  633. ".f4v",
  634. ".3gp",
  635. ".webm",
  636. ".mts",
  637. ".m2v",
  638. ".rec",
  639. ".mxf"
  640. });
  641. MultipleEpisodeExpressions = new string[]
  642. {
  643. @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[eExX](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
  644. @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[xX][eE](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
  645. @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )?[xXeE](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
  646. @".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})(-[xE]?[eE]?(?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
  647. @".*(\\|\/)(?<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}))+[^\\\/]*$",
  648. @".*(\\|\/)(?<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}))+[^\\\/]*$",
  649. @".*(\\|\/)(?<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}))+[^\\\/]*$",
  650. @".*(\\|\/)(?<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}))+[^\\\/]*$",
  651. @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})((-| - )?[xXeE](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
  652. @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>[0-9]{1,4})[xX\.]?[eE](?<epnumber>[0-9]{1,3})(-[xX]?[eE]?(?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$"
  653. }.Select(i => new EpisodeExpression(i)
  654. {
  655. IsNamed = true
  656. }).ToArray();
  657. VideoFileExtensions = extensions
  658. .Distinct(StringComparer.OrdinalIgnoreCase)
  659. .ToArray();
  660. Compile();
  661. }
  662. public string[] AudioFileExtensions { get; set; }
  663. public string[] AlbumStackingPrefixes { get; set; }
  664. public string[] SubtitleFileExtensions { get; set; }
  665. public char[] SubtitleFlagDelimiters { get; set; }
  666. public string[] SubtitleForcedFlags { get; set; }
  667. public string[] SubtitleDefaultFlags { get; set; }
  668. public EpisodeExpression[] EpisodeExpressions { get; set; }
  669. public string[] EpisodeWithoutSeasonExpressions { get; set; }
  670. public string[] EpisodeMultiPartExpressions { get; set; }
  671. public string[] VideoFileExtensions { get; set; }
  672. public string[] StubFileExtensions { get; set; }
  673. public string[] AudioBookPartsExpressions { get; set; }
  674. public StubTypeRule[] StubTypes { get; set; }
  675. public char[] VideoFlagDelimiters { get; set; }
  676. public Format3DRule[] Format3DRules { get; set; }
  677. public string[] VideoFileStackingExpressions { get; set; }
  678. public string[] CleanDateTimes { get; set; }
  679. public string[] CleanStrings { get; set; }
  680. public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
  681. public ExtraRule[] VideoExtraRules { get; set; }
  682. public Regex[] VideoFileStackingRegexes { get; private set; }
  683. public Regex[] CleanDateTimeRegexes { get; private set; }
  684. public Regex[] CleanStringRegexes { get; private set; }
  685. public Regex[] EpisodeWithoutSeasonRegexes { get; private set; }
  686. public Regex[] EpisodeMultiPartRegexes { get; private set; }
  687. public void Compile()
  688. {
  689. VideoFileStackingRegexes = VideoFileStackingExpressions.Select(Compile).ToArray();
  690. CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray();
  691. CleanStringRegexes = CleanStrings.Select(Compile).ToArray();
  692. EpisodeWithoutSeasonRegexes = EpisodeWithoutSeasonExpressions.Select(Compile).ToArray();
  693. EpisodeMultiPartRegexes = EpisodeMultiPartExpressions.Select(Compile).ToArray();
  694. }
  695. private Regex Compile(string exp)
  696. {
  697. return new Regex(exp, RegexOptions.IgnoreCase | RegexOptions.Compiled);
  698. }
  699. }
  700. }