using System.Collections.Generic; using System.Text.RegularExpressions; using System.IO; using System.Linq; namespace MediaBrowser.TV { public static class TVUtils { private static readonly Regex[] seasonPathExpressions = new Regex[] { new Regex(@".+\\[s|S]eason\s?(?\d{1,2})$"), new Regex(@".+\\[s|S]æson\s?(?\d{1,2})$"), new Regex(@".+\\[t|T]emporada\s?(?\d{1,2})$"), new Regex(@".+\\[s|S]aison\s?(?\d{1,2})$"), new Regex(@".+\\[s|S]taffel\s?(?\d{1,2})$"), new Regex(@".+\\[s|S](?\d{1,2})$"), new Regex(@".+\\[s|S]eason\s?(?\d{1,2})[^\\]*$") }; /// /// Used to detect paths that represent episodes, need to make sure they don't also /// match movie titles like "2001 A Space..." /// Currently we limit the numbers here to 2 digits to try and avoid this /// /// /// The order here is important, if the order is changed some of the later /// ones might incorrectly match things that higher ones would have caught. /// The most restrictive expressions should appear first /// private static readonly Regex[] episodeExpressions = new Regex[] { new Regex(@".*\\[s|S]?(?\d{1,2})[x|X](?\d{1,3})[^\\]*$"), // 01x02 blah.avi S01x01 balh.avi new Regex(@".*\\[s|S](?\d{1,2})x?[e|E](?\d{1,3})[^\\]*$"), // S01E02 blah.avi, S01xE01 blah.avi new Regex(@".*\\(?[^\\]*)[s|S]?(?\d{1,2})[x|X](?\d{1,3})[^\\]*$"), // 01x02 blah.avi S01x01 balh.avi new Regex(@".*\\(?[^\\]*)[s|S](?\d{1,2})[x|X|\.]?[e|E](?\d{1,3})[^\\]*$") // S01E02 blah.avi, S01xE01 blah.avi }; /// /// To avoid the following matching movies they are only valid when contained in a folder which has been matched as a being season /// private static readonly Regex[] episodeExpressionsInASeasonFolder = new Regex[] { new Regex(@".*\\(?\d{1,2})\s?-\s?[^\\]*$"), // 01 - blah.avi, 01-blah.avi new Regex(@".*\\(?\d{1,2})[^\d\\]*[^\\]*$"), // 01.avi, 01.blah.avi "01 - 22 blah.avi" new Regex(@".*\\(?\d)(?\d{1,2})[^\d\\]+[^\\]*$"), // 01.avi, 01.blah.avi new Regex(@".*\\\D*\d+(?\d{2})") // hell0 - 101 - hello.avi }; public static bool IsSeasonFolder(string path) { path = path.ToLower(); return seasonPathExpressions.Any(r => r.IsMatch(path)); } public static bool IsSeriesFolder(string path, IEnumerable> fileSystemChildren) { foreach (var child in fileSystemChildren) { if (child.Value.HasFlag(FileAttributes.Directory)) { if (IsSeasonFolder(child.Key)) { return true; } } else { if (!string.IsNullOrEmpty(EpisodeNumberFromFile(child.Key, false))) { return true; } } } return false; } public static bool IsEpisode(string fullPath) { bool isInSeason = IsSeasonFolder(Path.GetDirectoryName(fullPath)); if (isInSeason) { return true; } else if (EpisodeNumberFromFile(fullPath, isInSeason) != null) { return true; } return false; } public static string EpisodeNumberFromFile(string fullPath, bool isInSeason) { string fl = fullPath.ToLower(); foreach (Regex r in episodeExpressions) { Match m = r.Match(fl); if (m.Success) return m.Groups["epnumber"].Value; } if (isInSeason) { foreach (Regex r in episodeExpressionsInASeasonFolder) { Match m = r.Match(fl); if (m.Success) return m.Groups["epnumber"].Value; } } return null; } } }