diff options
| author | LukePulverenti <luke.pulverenti@gmail.com> | 2013-03-03 01:58:04 -0500 |
|---|---|---|
| committer | LukePulverenti <luke.pulverenti@gmail.com> | 2013-03-03 01:58:04 -0500 |
| commit | ac3a94f5a1dbb94b374e0160c344fcf99af9b696 (patch) | |
| tree | f8b109c3bb5ebce964363e9df874bf3235259616 /MediaBrowser.Controller/Library | |
| parent | 627b8370a89cbf9826898c2edfc46767dfb5272a (diff) | |
moved resolvers to implementations, trimmed nuget package a bit
Diffstat (limited to 'MediaBrowser.Controller/Library')
| -rw-r--r-- | MediaBrowser.Controller/Library/EntityResolutionHelper.cs | 97 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/IItemResolver.cs | 22 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/ILibraryManager.cs | 5 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/IResolverIgnoreRule.cs | 10 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/ResolverPriority.cs | 26 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/TVUtils.cs | 286 |
6 files changed, 443 insertions, 3 deletions
diff --git a/MediaBrowser.Controller/Library/EntityResolutionHelper.cs b/MediaBrowser.Controller/Library/EntityResolutionHelper.cs new file mode 100644 index 000000000..07e0b5a11 --- /dev/null +++ b/MediaBrowser.Controller/Library/EntityResolutionHelper.cs @@ -0,0 +1,97 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Controller.Library +{ + /// <summary> + /// Class EntityResolutionHelper + /// </summary> + public static class EntityResolutionHelper + { + /// <summary> + /// Any extension in this list is considered a video file - can be added to at runtime for extensibility + /// </summary> + public static List<string> VideoFileExtensions = new List<string> + { + ".mkv", + ".m2t", + ".m2ts", + ".img", + ".iso", + ".ts", + ".rmvb", + ".mov", + ".avi", + ".mpg", + ".mpeg", + ".wmv", + ".mp4", + ".divx", + ".dvr-ms", + ".wtv", + ".ogm", + ".ogv", + ".asf", + ".m4v", + ".flv", + ".f4v", + ".3gp", + ".webm" + }; + + /// <summary> + /// Determines whether [is video file] [the specified path]. + /// </summary> + /// <param name="path">The path.</param> + /// <returns><c>true</c> if [is video file] [the specified path]; otherwise, <c>false</c>.</returns> + public static bool IsVideoFile(string path) + { + var extension = Path.GetExtension(path) ?? string.Empty; + return VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase); + } + + /// <summary> + /// Ensures DateCreated and DateModified have values + /// </summary> + /// <param name="item">The item.</param> + /// <param name="args">The args.</param> + public static void EnsureDates(BaseItem item, ItemResolveArgs args) + { + if (!Path.IsPathRooted(item.Path)) + { + return; + } + + // See if a different path came out of the resolver than what went in + if (!args.Path.Equals(item.Path, StringComparison.OrdinalIgnoreCase)) + { + var childData = args.IsDirectory ? args.GetFileSystemEntryByPath(item.Path) : null; + + if (childData.HasValue) + { + item.DateCreated = childData.Value.CreationTimeUtc; + item.DateModified = childData.Value.LastWriteTimeUtc; + } + else + { + var fileData = FileSystem.GetFileData(item.Path); + + if (fileData.HasValue) + { + item.DateCreated = fileData.Value.CreationTimeUtc; + item.DateModified = fileData.Value.LastWriteTimeUtc; + } + } + } + else + { + item.DateCreated = args.FileInfo.CreationTimeUtc; + item.DateModified = args.FileInfo.LastWriteTimeUtc; + } + } + } +} diff --git a/MediaBrowser.Controller/Library/IItemResolver.cs b/MediaBrowser.Controller/Library/IItemResolver.cs new file mode 100644 index 000000000..721b787d3 --- /dev/null +++ b/MediaBrowser.Controller/Library/IItemResolver.cs @@ -0,0 +1,22 @@ +using MediaBrowser.Controller.Entities; + +namespace MediaBrowser.Controller.Library +{ + /// <summary> + /// Interface IItemResolver + /// </summary> + public interface IItemResolver + { + /// <summary> + /// Resolves the path. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>BaseItem.</returns> + BaseItem ResolvePath(ItemResolveArgs args); + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + ResolverPriority Priority { get; } + } +} diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 64070cb83..7ba60e921 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -1,6 +1,5 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; -using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; @@ -158,7 +157,7 @@ namespace MediaBrowser.Controller.Library /// <param name="pluginFolders">The plugin folders.</param> /// <param name="resolvers">The resolvers.</param> /// <param name="introProviders">The intro providers.</param> - void AddParts(IEnumerable<IResolutionIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders, - IEnumerable<IBaseItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders); + void AddParts(IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders, + IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders); } }
\ No newline at end of file diff --git a/MediaBrowser.Controller/Library/IResolverIgnoreRule.cs b/MediaBrowser.Controller/Library/IResolverIgnoreRule.cs new file mode 100644 index 000000000..c9c602089 --- /dev/null +++ b/MediaBrowser.Controller/Library/IResolverIgnoreRule.cs @@ -0,0 +1,10 @@ +namespace MediaBrowser.Controller.Library +{ + /// <summary> + /// Provides a base "rule" that anyone can use to have paths ignored by the resolver + /// </summary> + public interface IResolverIgnoreRule + { + bool ShouldIgnore(ItemResolveArgs args); + } +} diff --git a/MediaBrowser.Controller/Library/ResolverPriority.cs b/MediaBrowser.Controller/Library/ResolverPriority.cs new file mode 100644 index 000000000..1f266f371 --- /dev/null +++ b/MediaBrowser.Controller/Library/ResolverPriority.cs @@ -0,0 +1,26 @@ + +namespace MediaBrowser.Controller.Library +{ + /// <summary> + /// Enum ResolverPriority + /// </summary> + public enum ResolverPriority + { + /// <summary> + /// The first + /// </summary> + First = 1, + /// <summary> + /// The second + /// </summary> + Second = 2, + /// <summary> + /// The third + /// </summary> + Third = 3, + /// <summary> + /// The last + /// </summary> + Last = 4 + } +} diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs new file mode 100644 index 000000000..e0ef188b8 --- /dev/null +++ b/MediaBrowser.Controller/Library/TVUtils.cs @@ -0,0 +1,286 @@ +using MediaBrowser.Controller.IO; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace MediaBrowser.Controller.Library +{ + /// <summary> + /// Class TVUtils + /// </summary> + public static class TVUtils + { + /// <summary> + /// The TVDB API key + /// </summary> + public static readonly string TVDBApiKey = "B89CE93890E9419B"; + /// <summary> + /// The banner URL + /// </summary> + public static readonly string BannerUrl = "http://www.thetvdb.com/banners/"; + + /// <summary> + /// A season folder must contain one of these somewhere in the name + /// </summary> + private static readonly string[] SeasonFolderNames = new[] + { + "season", + "sæson", + "temporada", + "saison", + "staffel" + }; + + /// <summary> + /// 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 + /// </summary> + private static readonly Regex[] EpisodeExpressions = new[] + { + 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[] + { + 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 + + }; + + /// <summary> + /// Gets the season number from path. + /// </summary> + /// <param name="path">The path.</param> + /// <returns>System.Nullable{System.Int32}.</returns> + public static int? GetSeasonNumberFromPath(string path) + { + // Look for one of the season folder names + foreach (var 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> + /// <param name="path">The path.</param> + /// <returns>System.Nullable{System.Int32}.</returns> + private static int? GetSeasonNumberFromPathSubstring(string path) + { + int numericStart = -1; + int length = 0; + + // 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)); + } + + /// <summary> + /// Determines whether [is season folder] [the specified path]. + /// </summary> + /// <param name="path">The path.</param> + /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns> + public static bool IsSeasonFolder(string path) + { + return GetSeasonNumberFromPath(path) != null; + } + + /// <summary> + /// Determines whether [is series folder] [the specified path]. + /// </summary> + /// <param name="path">The path.</param> + /// <param name="fileSystemChildren">The file system children.</param> + /// <returns><c>true</c> if [is series folder] [the specified path]; otherwise, <c>false</c>.</returns> + public static bool IsSeriesFolder(string path, IEnumerable<WIN32_FIND_DATA> fileSystemChildren) + { + // A folder with more than 3 non-season folders in will not becounted as a series + var nonSeriesFolders = 0; + + foreach (var child in fileSystemChildren) + { + if (child.IsHidden || child.IsSystemFile) + { + continue; + } + + if (child.IsDirectory) + { + if (IsSeasonFolder(child.Path)) + { + return true; + } + + nonSeriesFolders++; + + if (nonSeriesFolders >= 3) + { + return false; + } + } + else + { + if (EntityResolutionHelper.IsVideoFile(child.Path) && + !string.IsNullOrEmpty(EpisodeNumberFromFile(child.Path, false))) + { + return true; + } + } + } + + return false; + } + + /// <summary> + /// Episodes the number from file. + /// </summary> + /// <param name="fullPath">The full path.</param> + /// <param name="isInSeason">if set to <c>true</c> [is in season].</param> + /// <returns>System.String.</returns> + public static string EpisodeNumberFromFile(string fullPath, bool isInSeason) + { + string fl = fullPath.ToLower(); + foreach (var r in EpisodeExpressions) + { + Match m = r.Match(fl); + if (m.Success) + return m.Groups["epnumber"].Value; + } + if (isInSeason) + { + var match = EpisodeExpressionsInASeasonFolder.Select(r => r.Match(fl)) + .FirstOrDefault(m => m.Success); + + if (match != null) + { + return match.Value; + } + } + + return null; + } + + /// <summary> + /// Seasons the number from episode file. + /// </summary> + /// <param name="fullPath">The full path.</param> + /// <returns>System.String.</returns> + public static string SeasonNumberFromEpisodeFile(string fullPath) + { + string fl = fullPath.ToLower(); + foreach (var r in EpisodeExpressions) + { + Match m = r.Match(fl); + if (m.Success) + { + Group g = m.Groups["seasonnumber"]; + if (g != null) + return g.Value; + return null; + } + } + return null; + } + + /// <summary> + /// Gets the air days. + /// </summary> + /// <param name="day">The day.</param> + /// <returns>List{DayOfWeek}.</returns> + public static List<DayOfWeek> GetAirDays(string day) + { + if (!string.IsNullOrWhiteSpace(day)) + { + if (day.Equals("Daily", StringComparison.OrdinalIgnoreCase)) + { + return new List<DayOfWeek> + { + DayOfWeek.Sunday, + DayOfWeek.Monday, + DayOfWeek.Tuesday, + DayOfWeek.Wednesday, + DayOfWeek.Thursday, + DayOfWeek.Friday, + DayOfWeek.Saturday + }; + } + + DayOfWeek value; + + if (Enum.TryParse(day, true, out value)) + { + return new List<DayOfWeek> + { + value + }; + } + + return new List<DayOfWeek> + { + }; + } + return null; + } + } +} |
