aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/Library
diff options
context:
space:
mode:
authorLukePulverenti <luke.pulverenti@gmail.com>2013-03-03 01:58:04 -0500
committerLukePulverenti <luke.pulverenti@gmail.com>2013-03-03 01:58:04 -0500
commitac3a94f5a1dbb94b374e0160c344fcf99af9b696 (patch)
treef8b109c3bb5ebce964363e9df874bf3235259616 /MediaBrowser.Controller/Library
parent627b8370a89cbf9826898c2edfc46767dfb5272a (diff)
moved resolvers to implementations, trimmed nuget package a bit
Diffstat (limited to 'MediaBrowser.Controller/Library')
-rw-r--r--MediaBrowser.Controller/Library/EntityResolutionHelper.cs97
-rw-r--r--MediaBrowser.Controller/Library/IItemResolver.cs22
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs5
-rw-r--r--MediaBrowser.Controller/Library/IResolverIgnoreRule.cs10
-rw-r--r--MediaBrowser.Controller/Library/ResolverPriority.cs26
-rw-r--r--MediaBrowser.Controller/Library/TVUtils.cs286
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;
+ }
+ }
+}