aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs6
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs6
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs52
-rw-r--r--MediaBrowser.Controller/Library/TVUtils.cs441
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj2
-rw-r--r--MediaBrowser.Controller/Resolvers/BaseVideoResolver.cs137
-rw-r--r--MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs263
8 files changed, 60 insertions, 849 deletions
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index be7867e06..cc0fc6812 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -306,7 +306,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path))
{
- IndexNumber = TVUtils.GetEpisodeNumberFromFile(Path, true);
+ IndexNumber = LibraryManager.GetEpisodeNumberFromFile(Path, true);
// If a change was made record it
if (IndexNumber.HasValue)
@@ -317,7 +317,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (!IndexNumberEnd.HasValue && !string.IsNullOrEmpty(Path))
{
- IndexNumberEnd = TVUtils.GetEndingEpisodeNumberFromFile(Path);
+ IndexNumberEnd = LibraryManager.GetEndingEpisodeNumberFromFile(Path);
// If a change was made record it
if (IndexNumberEnd.HasValue)
@@ -338,7 +338,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (!ParentIndexNumber.HasValue && !string.IsNullOrEmpty(Path))
{
- ParentIndexNumber = TVUtils.GetSeasonNumberFromEpisodeFile(Path);
+ ParentIndexNumber = LibraryManager.GetSeasonNumberFromEpisodeFile(Path);
}
// If a change was made record it
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index 542628196..2df90244c 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -298,7 +298,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path))
{
- IndexNumber = IndexNumber ?? TVUtils.GetSeasonNumberFromPath(Path);
+ IndexNumber = IndexNumber ?? LibraryManager.GetSeasonNumberFromPath(Path);
// If a change was made record it
if (IndexNumber.HasValue)
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 6550f43b4..f2484aab8 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -347,7 +347,7 @@ namespace MediaBrowser.Controller.Entities
{
if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
{
- return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsMultiPartFolder(i.FullName);
+ return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && LibraryManager.IsMultiPartFolder(i.FullName);
}
return false;
@@ -362,7 +362,7 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsVideoFile(i.FullName) && EntityResolutionHelper.IsMultiPartFile(i.Name);
+ return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && LibraryManager.IsVideoFile(i.FullName) && LibraryManager.IsMultiPartFile(i.Name);
});
}
@@ -472,7 +472,7 @@ namespace MediaBrowser.Controller.Entities
}
return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) &&
- EntityResolutionHelper.IsVideoFile(i.FullName) &&
+ LibraryManager.IsVideoFile(i.FullName) &&
i.Name.StartsWith(filenamePrefix + " - ", StringComparison.OrdinalIgnoreCase);
});
}
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index be43f4527..68b99e472 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -353,5 +353,57 @@ namespace MediaBrowser.Controller.Library
string viewType,
string sortName,
CancellationToken cancellationToken);
+
+ /// <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>
+ bool IsVideoFile(string path);
+
+ bool IsAudioFile(string path);
+
+ /// <summary>
+ /// Determines whether [is multi part file] [the specified path].
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if [is multi part file] [the specified path]; otherwise, <c>false</c>.</returns>
+ bool IsMultiPartFile(string path);
+
+ /// <summary>
+ /// Determines whether [is multi part folder] [the specified path].
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if [is multi part folder] [the specified path]; otherwise, <c>false</c>.</returns>
+ bool IsMultiPartFolder(string path);
+
+ /// <summary>
+ /// Gets the season number from path.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>System.Nullable&lt;System.Int32&gt;.</returns>
+ int? GetSeasonNumberFromPath(string path);
+
+ /// <summary>
+ /// Gets the season number from episode file.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>System.Nullable&lt;System.Int32&gt;.</returns>
+ int? GetSeasonNumberFromEpisodeFile(string path);
+
+ /// <summary>
+ /// Gets the ending episode number from file.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>System.Nullable&lt;System.Int32&gt;.</returns>
+ int? GetEndingEpisodeNumberFromFile(string path);
+
+ /// <summary>
+ /// Gets the episode number from file.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="considerSeasonless">if set to <c>true</c> [consider seasonless].</param>
+ /// <returns>System.Nullable&lt;System.Int32&gt;.</returns>
+ int? GetEpisodeNumberFromFile(string path, bool considerSeasonless);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs
index 314efcce5..f8039b2cf 100644
--- a/MediaBrowser.Controller/Library/TVUtils.cs
+++ b/MediaBrowser.Controller/Library/TVUtils.cs
@@ -1,14 +1,5 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Resolvers;
-using System;
+using System;
using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using MediaBrowser.Model.Logging;
namespace MediaBrowser.Controller.Library
{
@@ -27,436 +18,6 @@ namespace MediaBrowser.Controller.Library
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 =
- {
- "season",
- "sæson",
- "temporada",
- "saison",
- "staffel",
- "series",
- "сезон"
- };
-
- /// <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 Regex(
- @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)[sS](?<seasonnumber>\d{1,4})[x,X]?[eE](?<epnumber>\d{1,3})[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})[^\\\/]*$",
- RegexOptions.Compiled)
- };
- private static readonly Regex[] MultipleEpisodeExpressions =
- {
- new Regex(
- @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )\d{1,4}[eExX](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )\d{1,4}[xX][eE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})(-[xE]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )\d{1,4}[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )\d{1,4}[xX][eE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled),
- new Regex(
- @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
- RegexOptions.Compiled)
- };
-
- /// <summary>
- /// To avoid the following matching movies they are only valid when contained in a folder which has been matched as a being season, or the media type is TV series
- /// </summary>
- private static readonly Regex[] EpisodeExpressionsWithoutSeason =
- {
- new Regex(
- @".*[\\\/](?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\.\w+$",
- RegexOptions.Compiled),
- // "01.avi"
- new Regex(
- @".*(\\|\/)(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\s?-\s?[^\\\/]*$",
- RegexOptions.Compiled),
- // "01 - blah.avi", "01-blah.avi"
- new Regex(
- @".*(\\|\/)(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\.[^\\\/]+$",
- RegexOptions.Compiled),
- // "01.blah.avi"
- new Regex(
- @".*[\\\/][^\\\/]* - (?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*[^\\\/]*$",
- RegexOptions.Compiled),
- // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi", "blah 2 - 01 - blah"
- };
-
- /// <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)
- {
- var filename = Path.GetFileName(path);
-
- if (string.Equals(filename, "specials", StringComparison.OrdinalIgnoreCase))
- {
- return 0;
- }
-
- int val;
- if (int.TryParse(filename, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
- {
- return val;
- }
-
- if (filename.StartsWith("s", StringComparison.OrdinalIgnoreCase))
- {
- var testFilename = filename.Substring(1);
-
- if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
- {
- return val;
- }
- }
-
- // Look for one of the season folder names
- foreach (var name in SeasonFolderNames)
- {
- var index = filename.IndexOf(name, StringComparison.OrdinalIgnoreCase);
-
- if (index != -1)
- {
- return GetSeasonNumberFromPathSubstring(filename.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)
- {
- var numericStart = -1;
- var length = 0;
-
- // Find out where the numbers start, and then keep going until they end
- for (var 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), CultureInfo.InvariantCulture);
- }
-
- /// <summary>
- /// Determines whether [is season folder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="directoryService">The directory service.</param>
- /// <param name="fileSystem">The file system.</param>
- /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns>
- private static bool IsSeasonFolder(string path, IDirectoryService directoryService, IFileSystem fileSystem)
- {
- var seasonNumber = GetSeasonNumberFromPath(path);
- var hasSeasonNumber = seasonNumber != null;
-
- if (!hasSeasonNumber)
- {
- return false;
- }
-
- //// It's a season folder if it's named as such and does not contain any audio files, apart from theme.mp3
- //foreach (var fileSystemInfo in directoryService.GetFileSystemEntries(path))
- //{
- // var attributes = fileSystemInfo.Attributes;
-
- // if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
- // {
- // continue;
- // }
-
- // // Can't enforce this because files saved by Bitcasa are always marked System
- // //if ((attributes & FileAttributes.System) == FileAttributes.System)
- // //{
- // // continue;
- // //}
-
- // if ((attributes & FileAttributes.Directory) == FileAttributes.Directory)
- // {
- // //if (IsBadFolder(fileSystemInfo.Name))
- // //{
- // // return false;
- // //}
- // }
- // else
- // {
- // if (EntityResolutionHelper.IsAudioFile(fileSystemInfo.FullName) &&
- // !string.Equals(fileSystem.GetFileNameWithoutExtension(fileSystemInfo), BaseItem.ThemeSongFilename))
- // {
- // return false;
- // }
- // }
- //}
-
- return true;
- }
-
- /// <summary>
- /// Determines whether [is series folder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="considerSeasonlessEntries">if set to <c>true</c> [consider seasonless entries].</param>
- /// <param name="fileSystemChildren">The file system children.</param>
- /// <param name="directoryService">The directory service.</param>
- /// <param name="fileSystem">The file system.</param>
- /// <returns><c>true</c> if [is series folder] [the specified path]; otherwise, <c>false</c>.</returns>
- public static bool IsSeriesFolder(string path, bool considerSeasonlessEntries, IEnumerable<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService, IFileSystem fileSystem, ILogger logger)
- {
- // A folder with more than 3 non-season folders in will not becounted as a series
- var nonSeriesFolders = 0;
-
- foreach (var child in fileSystemChildren)
- {
- var attributes = child.Attributes;
-
- if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
- {
- //logger.Debug("Igoring series file or folder marked hidden: {0}", child.FullName);
- continue;
- }
-
- // Can't enforce this because files saved by Bitcasa are always marked System
- //if ((attributes & FileAttributes.System) == FileAttributes.System)
- //{
- // logger.Debug("Igoring series subfolder marked system: {0}", child.FullName);
- // continue;
- //}
-
- if ((attributes & FileAttributes.Directory) == FileAttributes.Directory)
- {
- if (IsSeasonFolder(child.FullName, directoryService, fileSystem))
- {
- //logger.Debug("{0} is a series because of season folder {1}.", path, child.FullName);
- return true;
- }
-
- if (IsBadFolder(child.Name))
- {
- logger.Debug("Invalid folder under series: {0}", child.FullName);
-
- nonSeriesFolders++;
- }
-
- if (nonSeriesFolders >= 3)
- {
- logger.Debug("{0} not a series due to 3 or more invalid folders.", path);
- return false;
- }
- }
- else
- {
- var fullName = child.FullName;
-
- if (EntityResolutionHelper.IsVideoFile(fullName) || EntityResolutionHelper.IsVideoPlaceHolder(fullName))
- {
- if (GetEpisodeNumberFromFile(fullName, considerSeasonlessEntries).HasValue)
- {
- return true;
- }
- }
- }
- }
-
- logger.Debug("{0} is not a series folder.", path);
- return false;
- }
-
- private static bool IsBadFolder(string name)
- {
- if (string.Equals(name, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(name, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
-
- return !EntityResolutionHelper.IgnoreFolders.Contains(name, StringComparer.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Episodes the number from file.
- /// </summary>
- /// <param name="fullPath">The full path.</param>
- /// <param name="considerSeasonlessNames">if set to <c>true</c> [is in season].</param>
- /// <returns>System.String.</returns>
- public static int? GetEpisodeNumberFromFile(string fullPath, bool considerSeasonlessNames)
- {
- string fl = fullPath.ToLower();
- foreach (var r in EpisodeExpressions)
- {
- Match m = r.Match(fl);
- if (m.Success)
- return ParseEpisodeNumber(m.Groups["epnumber"].Value);
- }
- if (considerSeasonlessNames)
- {
- var match = EpisodeExpressionsWithoutSeason.Select(r => r.Match(fl))
- .FirstOrDefault(m => m.Success);
-
- if (match != null)
- {
- return ParseEpisodeNumber(match.Groups["epnumber"].Value);
- }
- }
-
- return null;
- }
-
- public static int? GetEndingEpisodeNumberFromFile(string fullPath)
- {
- var fl = fullPath.ToLower();
- foreach (var r in MultipleEpisodeExpressions)
- {
- var m = r.Match(fl);
- if (m.Success && !string.IsNullOrEmpty(m.Groups["endingepnumber"].Value))
- return ParseEpisodeNumber(m.Groups["endingepnumber"].Value);
- }
- foreach (var r in EpisodeExpressionsWithoutSeason)
- {
- var m = r.Match(fl);
- if (m.Success && !string.IsNullOrEmpty(m.Groups["endingepnumber"].Value))
- return ParseEpisodeNumber(m.Groups["endingepnumber"].Value);
- }
- return null;
- }
-
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- private static int? ParseEpisodeNumber(string val)
- {
- int num;
-
- if (!string.IsNullOrEmpty(val) && int.TryParse(val, NumberStyles.Integer, UsCulture, out num))
- {
- return num;
- }
-
- return null;
- }
-
- /// <summary>
- /// Seasons the number from episode file.
- /// </summary>
- /// <param name="fullPath">The full path.</param>
- /// <returns>System.String.</returns>
- public static int? GetSeasonNumberFromEpisodeFile(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)
- {
- var val = g.Value;
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- int num;
-
- if (int.TryParse(val, NumberStyles.Integer, UsCulture, out num))
- {
- return num;
- }
- }
- }
- return null;
- }
- }
- return null;
- }
-
- public static string GetSeriesNameFromEpisodeFile(string fullPath)
- {
- var fl = fullPath.ToLower();
- foreach (var r in EpisodeExpressions)
- {
- var m = r.Match(fl);
- if (m.Success)
- {
- var g = m.Groups["seriesname"];
- if (g != null)
- {
- var val = g.Value;
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- return val;
- }
- }
- return null;
- }
- }
- return null;
- }
-
- /// <summary>
/// Gets the air days.
/// </summary>
/// <param name="day">The day.</param>
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 72a8f6016..0457ea72e 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -306,7 +306,6 @@
<Compile Include="MediaEncoding\MediaEncoderHelpers.cs" />
<Compile Include="Providers\MetadataProviderPriority.cs" />
<Compile Include="Resolvers\BaseItemResolver.cs" />
- <Compile Include="Resolvers\BaseVideoResolver.cs" />
<Compile Include="Resolvers\IItemResolver.cs" />
<Compile Include="Library\ILibraryManager.cs" />
<Compile Include="Library\IUserManager.cs" />
@@ -325,7 +324,6 @@
<Compile Include="Providers\IImageEnhancer.cs" />
<Compile Include="Providers\ProviderRefreshStatus.cs" />
<Compile Include="Resolvers\IResolverIgnoreRule.cs" />
- <Compile Include="Resolvers\EntityResolutionHelper.cs" />
<Compile Include="Resolvers\ResolverPriority.cs" />
<Compile Include="Library\TVUtils.cs" />
<Compile Include="Library\ItemResolveArgs.cs" />
diff --git a/MediaBrowser.Controller/Resolvers/BaseVideoResolver.cs b/MediaBrowser.Controller/Resolvers/BaseVideoResolver.cs
deleted file mode 100644
index 5725c6482..000000000
--- a/MediaBrowser.Controller/Resolvers/BaseVideoResolver.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-
-namespace MediaBrowser.Controller.Resolvers
-{
- /// <summary>
- /// Resolves a Path into a Video or Video subclass
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public abstract class BaseVideoResolver<T> : ItemResolver<T>
- where T : Video, new()
- {
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>`0.</returns>
- protected override T Resolve(ItemResolveArgs args)
- {
- return ResolveVideo<T>(args);
- }
-
- /// <summary>
- /// Resolves the video.
- /// </summary>
- /// <typeparam name="TVideoType">The type of the T video type.</typeparam>
- /// <param name="args">The args.</param>
- /// <returns>``0.</returns>
- protected TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args)
- where TVideoType : Video, new()
- {
- // If the path is a file check for a matching extensions
- if (!args.IsDirectory)
- {
- // http://wiki.xbmc.org/index.php?title=Media_stubs
- var isPlaceHolder = EntityResolutionHelper.IsVideoPlaceHolder(args.Path);
-
- var extension = Path.GetExtension(args.Path);
-
- var isShortcut = string.Equals(extension, ".strm", StringComparison.OrdinalIgnoreCase);
-
- if (EntityResolutionHelper.IsVideoFile(args.Path) || isPlaceHolder || isShortcut)
- {
- var type = string.Equals(extension, ".iso", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".img", StringComparison.OrdinalIgnoreCase) ?
- VideoType.Iso : VideoType.VideoFile;
-
- var path = args.Path;
-
- var video = new TVideoType
- {
- VideoType = type,
- Path = args.Path,
- IsInMixedFolder = true,
- IsPlaceHolder = isPlaceHolder,
- IsShortcut = isShortcut
- };
-
- if (isPlaceHolder)
- {
- if (args.Path.EndsWith("dvd.disc", StringComparison.OrdinalIgnoreCase))
- {
- video.VideoType = VideoType.Dvd;
- }
- else if (args.Path.EndsWith("hddvd.disc", StringComparison.OrdinalIgnoreCase))
- {
- video.VideoType = VideoType.HdDvd;
- }
- else if (args.Path.EndsWith("bluray.disc", StringComparison.OrdinalIgnoreCase) ||
- args.Path.EndsWith("brrip.disc", StringComparison.OrdinalIgnoreCase) ||
- args.Path.EndsWith("bd25.disc", StringComparison.OrdinalIgnoreCase) ||
- args.Path.EndsWith("bd50.disc", StringComparison.OrdinalIgnoreCase))
- {
- video.VideoType = VideoType.BluRay;
- }
- }
-
- return video;
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected override void SetInitialItemValues(T item, ItemResolveArgs args)
- {
- base.SetInitialItemValues(item, args);
-
- if (item.Path.IndexOf("[3d]", StringComparison.OrdinalIgnoreCase) != -1 || item.Path.IndexOf("[sbs3d]", StringComparison.OrdinalIgnoreCase) != -1)
- {
- item.Video3DFormat = Video3DFormat.HalfSideBySide;
- }
- else if (item.Path.IndexOf("[hsbs]", StringComparison.OrdinalIgnoreCase) != -1)
- {
- item.Video3DFormat = Video3DFormat.HalfSideBySide;
- }
- else if (item.Path.IndexOf("[fsbs]", StringComparison.OrdinalIgnoreCase) != -1)
- {
- item.Video3DFormat = Video3DFormat.FullSideBySide;
- }
- else if (item.Path.IndexOf("[ftab]", StringComparison.OrdinalIgnoreCase) != -1)
- {
- item.Video3DFormat = Video3DFormat.FullTopAndBottom;
- }
- else if (item.Path.IndexOf("[htab]", StringComparison.OrdinalIgnoreCase) != -1)
- {
- item.Video3DFormat = Video3DFormat.HalfTopAndBottom;
- }
- else
- {
- // Support Xbmc conventions:
- // http://wiki.xbmc.org/index.php?title=3D
- var name = Path.GetFileName(item.Path);
-
- name = name.Replace('.', ' ').Replace('_', ' ').Replace('-', ' ');
-
- if (name.IndexOf(" 3d hsbs ", StringComparison.OrdinalIgnoreCase) != -1 ||
- name.IndexOf(" 3d sbs ", StringComparison.OrdinalIgnoreCase) != -1)
- {
- item.Video3DFormat = Video3DFormat.HalfSideBySide;
- }
- else if (name.IndexOf(" 3d htab ", StringComparison.OrdinalIgnoreCase) != -1 ||
- name.IndexOf(" 3d tab ", StringComparison.OrdinalIgnoreCase) != -1)
- {
- item.Video3DFormat = Video3DFormat.HalfTopAndBottom;
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs b/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs
deleted file mode 100644
index d37301b9e..000000000
--- a/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs
+++ /dev/null
@@ -1,263 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-
-namespace MediaBrowser.Controller.Resolvers
-{
- /// <summary>
- /// Class EntityResolutionHelper
- /// </summary>
- public static class EntityResolutionHelper
- {
- /// <summary>
- /// Any folder named in this list will be ignored - can be added to at runtime for extensibility
- /// </summary>
- public static readonly List<string> IgnoreFolders = new List<string>
- {
- "metadata",
- "ps3_update",
- "ps3_vprm",
- "extrafanart",
- "extrathumbs",
- ".actors",
- ".wd_tv"
-
- };
-
- private static readonly Regex MultiFileRegex = new Regex(
- @"(.*?)([ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck]|d)[ _.-]*[0-9]+)(.*?)(\.[^.]+)$",
- RegexOptions.Compiled | RegexOptions.IgnoreCase);
-
- private static readonly Regex MultiFolderRegex = new Regex(
- @"(.*?)([ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck]|d)[ _.-]*[0-9]+)$",
- RegexOptions.Compiled | RegexOptions.IgnoreCase);
-
- /// <summary>
- /// Determines whether [is multi part file] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is multi part file] [the specified path]; otherwise, <c>false</c>.</returns>
- public static bool IsMultiPartFile(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- path = Path.GetFileName(path);
-
- return MultiFileRegex.Match(path).Success;
- }
-
- public static bool IsMultiPartFolder(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- path = Path.GetFileName(path);
-
- return MultiFolderRegex.Match(path).Success;
- }
-
- /// <summary>
- /// The audio file extensions
- /// </summary>
- public static readonly string[] AudioFileExtensions =
- {
- ".mp3",
- ".flac",
- ".wma",
- ".aac",
- ".acc",
- ".m4a",
- ".m4b",
- ".wav",
- ".ape",
- ".ogg",
- ".oga"
-
- //".asf",
- //".mp4"
- };
-
- private static readonly Dictionary<string, string> AudioFileExtensionsDictionary = AudioFileExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
-
- /// <summary>
- /// Determines whether [is audio file] [the specified args].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is audio file] [the specified args]; otherwise, <c>false</c>.</returns>
- public static bool IsAudioFile(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var extension = Path.GetExtension(path);
-
- if (string.IsNullOrEmpty(extension))
- {
- return false;
- }
-
- return AudioFileExtensionsDictionary.ContainsKey(extension);
- }
-
- /// <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)
- {
- return MimeTypes.IsVideoFile(path);
- }
-
- /// <summary>
- /// Determines whether [is place holder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is place holder] [the specified path]; otherwise, <c>false</c>.</returns>
- /// <exception cref="System.ArgumentNullException">path</exception>
- public static bool IsVideoPlaceHolder(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var extension = Path.GetExtension(path);
-
- return string.Equals(extension, ".disc", StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Determines whether [is multi disc album folder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is multi disc album folder] [the specified path]; otherwise, <c>false</c>.</returns>
- public static bool IsMultiDiscAlbumFolder(string path)
- {
- var filename = Path.GetFileName(path);
-
- if (string.IsNullOrWhiteSpace(filename))
- {
- return false;
- }
-
- // Normalize
- // Remove whitespace
- filename = filename.Replace("-", " ");
- filename = filename.Replace(".", " ");
- filename = filename.Replace("(", " ");
- filename = filename.Replace(")", " ");
- filename = Regex.Replace(filename, @"\s+", " ");
-
- var prefixes = new[] { "disc", "cd", "disk", "vol", "volume" };
-
- filename = filename.TrimStart();
-
- foreach (var prefix in prefixes)
- {
- if (filename.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) == 0)
- {
- var tmp = filename.Substring(prefix.Length);
-
- tmp = tmp.Trim().Split(' ').FirstOrDefault() ?? string.Empty;
-
- int val;
- if (int.TryParse(tmp, NumberStyles.Any, CultureInfo.InvariantCulture, out val))
- {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /// <summary>
- /// Ensures DateCreated and DateModified have values
- /// </summary>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- /// <param name="includeCreationTime">if set to <c>true</c> [include creation time].</param>
- public static void EnsureDates(IFileSystem fileSystem, BaseItem item, ItemResolveArgs args, bool includeCreationTime)
- {
- if (fileSystem == null)
- {
- throw new ArgumentNullException("fileSystem");
- }
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
- if (args == null)
- {
- throw new ArgumentNullException("args");
- }
-
- // See if a different path came out of the resolver than what went in
- if (!string.Equals(args.Path, item.Path, StringComparison.OrdinalIgnoreCase))
- {
- var childData = args.IsDirectory ? args.GetFileSystemEntryByPath(item.Path) : null;
-
- if (childData != null)
- {
- if (includeCreationTime)
- {
- SetDateCreated(item, fileSystem, childData);
- }
-
- item.DateModified = fileSystem.GetLastWriteTimeUtc(childData);
- }
- else
- {
- var fileData = fileSystem.GetFileSystemInfo(item.Path);
-
- if (fileData.Exists)
- {
- if (includeCreationTime)
- {
- SetDateCreated(item, fileSystem, fileData);
- }
- item.DateModified = fileSystem.GetLastWriteTimeUtc(fileData);
- }
- }
- }
- else
- {
- if (includeCreationTime)
- {
- SetDateCreated(item, fileSystem, args.FileInfo);
- }
- item.DateModified = fileSystem.GetLastWriteTimeUtc(args.FileInfo);
- }
- }
-
- private static void SetDateCreated(BaseItem item, IFileSystem fileSystem, FileSystemInfo info)
- {
- var config = BaseItem.ConfigurationManager.GetMetadataConfiguration();
-
- if (config.UseFileCreationTimeForDateAdded)
- {
- item.DateCreated = fileSystem.GetCreationTimeUtc(info);
- }
- else
- {
- item.DateCreated = DateTime.UtcNow;
- }
- }
- }
-}