|
@@ -1,4 +1,4 @@
|
|
|
-using System.Linq;
|
|
|
+using System;
|
|
|
using System.Text.RegularExpressions;
|
|
|
using MediaBrowser.Controller.IO;
|
|
|
|
|
@@ -6,15 +6,15 @@ namespace MediaBrowser.TV
|
|
|
{
|
|
|
public static class TVUtils
|
|
|
{
|
|
|
- private static readonly Regex[] seasonPathExpressions = new Regex[] {
|
|
|
- new Regex(@".+\\[s|S]eason\s?(?<seasonnumber>\d{1,2})$"),
|
|
|
- new Regex(@".+\\[s|S]æson\s?(?<seasonnumber>\d{1,2})$"),
|
|
|
- new Regex(@".+\\[t|T]emporada\s?(?<seasonnumber>\d{1,2})$"),
|
|
|
- new Regex(@".+\\[s|S]aison\s?(?<seasonnumber>\d{1,2})$"),
|
|
|
- new Regex(@".+\\[s|S]taffel\s?(?<seasonnumber>\d{1,2})$"),
|
|
|
- new Regex(@".+\\[s|S](?<seasonnumber>\d{1,2})$"),
|
|
|
- new Regex(@".+\\[s|S]eason\s?(?<seasonnumber>\d{1,2})[^\\]*$")
|
|
|
-
|
|
|
+ /// <summary>
|
|
|
+ /// A season folder must contain one of these somewhere in the name
|
|
|
+ /// </summary>
|
|
|
+ private static string[] SeasonFolderNames = new string[] {
|
|
|
+ "season",
|
|
|
+ "sæson",
|
|
|
+ "temporada",
|
|
|
+ "saison",
|
|
|
+ "staffel"
|
|
|
};
|
|
|
|
|
|
/// <summary>
|
|
@@ -28,27 +28,74 @@ namespace MediaBrowser.TV
|
|
|
/// The most restrictive expressions should appear first
|
|
|
/// </remarks>
|
|
|
private static readonly Regex[] episodeExpressions = new Regex[] {
|
|
|
- new Regex(@".*\\[s|S]?(?<seasonnumber>\d{1,2})[x|X](?<epnumber>\d{1,3})[^\\]*$"), // 01x02 blah.avi S01x01 balh.avi
|
|
|
- new Regex(@".*\\[s|S](?<seasonnumber>\d{1,2})x?[e|E](?<epnumber>\d{1,3})[^\\]*$"), // S01E02 blah.avi, S01xE01 blah.avi
|
|
|
- new Regex(@".*\\(?<seriesname>[^\\]*)[s|S]?(?<seasonnumber>\d{1,2})[x|X](?<epnumber>\d{1,3})[^\\]*$"), // 01x02 blah.avi S01x01 balh.avi
|
|
|
- new Regex(@".*\\(?<seriesname>[^\\]*)[s|S](?<seasonnumber>\d{1,2})[x|X|\.]?[e|E](?<epnumber>\d{1,3})[^\\]*$") // S01E02 blah.avi, S01xE01 blah.avi
|
|
|
+ new Regex(@".*\\[s|S]?(?<seasonnumber>\d{1,2})[x|X](?<epnumber>\d{1,3})[^\\]*$", RegexOptions.Compiled), // 01x02 blah.avi S01x01 balh.avi
|
|
|
+ new Regex(@".*\\[s|S](?<seasonnumber>\d{1,2})x?[e|E](?<epnumber>\d{1,3})[^\\]*$", RegexOptions.Compiled), // S01E02 blah.avi, S01xE01 blah.avi
|
|
|
+ new Regex(@".*\\(?<seriesname>[^\\]*)[s|S]?(?<seasonnumber>\d{1,2})[x|X](?<epnumber>\d{1,3})[^\\]*$", RegexOptions.Compiled), // 01x02 blah.avi S01x01 balh.avi
|
|
|
+ new Regex(@".*\\(?<seriesname>[^\\]*)[s|S](?<seasonnumber>\d{1,2})[x|X|\.]?[e|E](?<epnumber>\d{1,3})[^\\]*$", RegexOptions.Compiled) // S01E02 blah.avi, S01xE01 blah.avi
|
|
|
};
|
|
|
/// <summary>
|
|
|
/// To avoid the following matching movies they are only valid when contained in a folder which has been matched as a being season
|
|
|
/// </summary>
|
|
|
private static readonly Regex[] episodeExpressionsInASeasonFolder = new Regex[] {
|
|
|
- new Regex(@".*\\(?<epnumber>\d{1,2})\s?-\s?[^\\]*$"), // 01 - blah.avi, 01-blah.avi
|
|
|
- new Regex(@".*\\(?<epnumber>\d{1,2})[^\d\\]*[^\\]*$"), // 01.avi, 01.blah.avi "01 - 22 blah.avi"
|
|
|
- new Regex(@".*\\(?<seasonnumber>\d)(?<epnumber>\d{1,2})[^\d\\]+[^\\]*$"), // 01.avi, 01.blah.avi
|
|
|
- new Regex(@".*\\\D*\d+(?<epnumber>\d{2})") // hell0 - 101 - hello.avi
|
|
|
+ new Regex(@".*\\(?<epnumber>\d{1,2})\s?-\s?[^\\]*$", RegexOptions.Compiled), // 01 - blah.avi, 01-blah.avi
|
|
|
+ new Regex(@".*\\(?<epnumber>\d{1,2})[^\d\\]*[^\\]*$", RegexOptions.Compiled), // 01.avi, 01.blah.avi "01 - 22 blah.avi"
|
|
|
+ new Regex(@".*\\(?<seasonnumber>\d)(?<epnumber>\d{1,2})[^\d\\]+[^\\]*$", RegexOptions.Compiled), // 01.avi, 01.blah.avi
|
|
|
+ new Regex(@".*\\\D*\d+(?<epnumber>\d{2})", RegexOptions.Compiled) // hell0 - 101 - hello.avi
|
|
|
|
|
|
};
|
|
|
|
|
|
- public static bool IsSeasonFolder(string path)
|
|
|
+ public static int? GetSeasonNumberFromPath(string path)
|
|
|
+ {
|
|
|
+ // Look for one of the season folder names
|
|
|
+ foreach (string name in SeasonFolderNames)
|
|
|
+ {
|
|
|
+ int index = path.IndexOf(name, StringComparison.OrdinalIgnoreCase);
|
|
|
+
|
|
|
+ if (index != -1)
|
|
|
+ {
|
|
|
+ return GetSeasonNumberFromPathSubstring(path.Substring(index + name.Length));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Extracts the season number from the second half of the Season folder name (everything after "Season", or "Staffel")
|
|
|
+ /// </summary>
|
|
|
+ private static int? GetSeasonNumberFromPathSubstring(string path)
|
|
|
{
|
|
|
- path = path.ToLower();
|
|
|
+ int numericStart = -1;
|
|
|
+ int length = 0;
|
|
|
|
|
|
- return seasonPathExpressions.Any(r => r.IsMatch(path));
|
|
|
+ // Find out where the numbers start, and then keep going until they end
|
|
|
+ for (int i = 0; i < path.Length; i++)
|
|
|
+ {
|
|
|
+ if (char.IsNumber(path, i))
|
|
|
+ {
|
|
|
+ if (numericStart == -1)
|
|
|
+ {
|
|
|
+ numericStart = i;
|
|
|
+ }
|
|
|
+ length++;
|
|
|
+ }
|
|
|
+ else if (numericStart != -1)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (numericStart == -1)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return int.Parse(path.Substring(numericStart, length));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static bool IsSeasonFolder(string path)
|
|
|
+ {
|
|
|
+ return GetSeasonNumberFromPath(path) != null;
|
|
|
}
|
|
|
|
|
|
public static bool IsSeriesFolder(string path, WIN32_FIND_DATA[] fileSystemChildren)
|