Added multi-disc movie support
This commit is contained in:
parent
e231bd4d32
commit
c5b00dec8e
|
@ -20,7 +20,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
{
|
||||
SpecialFeatureIds = new List<Guid>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Should be overridden to return the proper folder where metadata lives
|
||||
/// </summary>
|
||||
|
@ -30,7 +30,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
{
|
||||
get
|
||||
{
|
||||
return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso ? System.IO.Path.GetDirectoryName(Path) : Path;
|
||||
return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso || IsMultiPart ? System.IO.Path.GetDirectoryName(Path) : Path;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
{
|
||||
get
|
||||
{
|
||||
return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso;
|
||||
return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso || IsMultiPart;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
|
||||
return itemsChanged || results.Contains(true);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Loads the special features.
|
||||
/// </summary>
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
get
|
||||
{
|
||||
return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso ? System.IO.Path.GetDirectoryName(Path) : Path;
|
||||
return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso || IsMultiPart ? System.IO.Path.GetDirectoryName(Path) : Path;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
get
|
||||
{
|
||||
return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso;
|
||||
return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso || IsMultiPart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var allFiles = Directory.EnumerateFiles(rootPath, "*", SearchOption.AllDirectories).ToList();
|
||||
|
||||
return PlayableStreamFileNames.Select(name => allFiles.FirstOrDefault(f => string.Equals(System.IO.Path.GetFileName(f), name, System.StringComparison.OrdinalIgnoreCase)))
|
||||
return PlayableStreamFileNames.Select(name => allFiles.FirstOrDefault(f => string.Equals(System.IO.Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase)))
|
||||
.Where(f => !string.IsNullOrEmpty(f))
|
||||
.ToList();
|
||||
}
|
||||
|
@ -176,32 +176,38 @@ namespace MediaBrowser.Controller.Entities
|
|||
return new List<Video>();
|
||||
}
|
||||
|
||||
ItemResolveArgs resolveArgs;
|
||||
IEnumerable<FileSystemInfo> files;
|
||||
|
||||
try
|
||||
if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
|
||||
{
|
||||
resolveArgs = ResolveArgs;
|
||||
files = new DirectoryInfo(System.IO.Path.GetDirectoryName(Path))
|
||||
.EnumerateDirectories()
|
||||
.Where(i => !string.Equals(i.FullName, Path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsMultiPartFile(i.Name));
|
||||
}
|
||||
catch (IOException ex)
|
||||
else
|
||||
{
|
||||
Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path);
|
||||
return new List<Video>();
|
||||
}
|
||||
ItemResolveArgs resolveArgs;
|
||||
|
||||
if (!resolveArgs.IsDirectory)
|
||||
{
|
||||
return new List<Video>();
|
||||
}
|
||||
|
||||
var files = resolveArgs.FileSystemChildren.Where(i =>
|
||||
{
|
||||
if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
|
||||
try
|
||||
{
|
||||
return false;
|
||||
resolveArgs = ResolveArgs;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path);
|
||||
return new List<Video>();
|
||||
}
|
||||
|
||||
return !string.Equals(i.FullName, Path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsVideoFile(i.FullName) && EntityResolutionHelper.IsMultiPartFile(i.FullName);
|
||||
});
|
||||
files = resolveArgs.FileSystemChildren.Where(i =>
|
||||
{
|
||||
if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !string.Equals(i.FullName, Path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsVideoFile(i.FullName) && EntityResolutionHelper.IsMultiPartFile(i.Name);
|
||||
});
|
||||
}
|
||||
|
||||
return LibraryManager.ResolvePaths<Video>(files, null).Select(video =>
|
||||
{
|
||||
|
|
|
@ -48,7 +48,11 @@ namespace MediaBrowser.Controller.Resolvers
|
|||
|
||||
private static readonly Regex MultiFileRegex = new Regex(
|
||||
@"(.*?)([ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck]|d)[ _.-]*[0-9]+)(.*?)(\.[^.]+)$",
|
||||
RegexOptions.Compiled);
|
||||
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].
|
||||
|
@ -57,7 +61,7 @@ namespace MediaBrowser.Controller.Resolvers
|
|||
/// <returns><c>true</c> if [is multi part file] [the specified path]; otherwise, <c>false</c>.</returns>
|
||||
public static bool IsMultiPartFile(string path)
|
||||
{
|
||||
return MultiFileRegex.Match(path).Success;
|
||||
return MultiFileRegex.Match(path).Success || MultiFolderRegex.Match(path).Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -50,24 +50,21 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
if (args.IsDirectory)
|
||||
{
|
||||
// Avoid expensive tests against VF's and all their children by not allowing this
|
||||
if (args.Parent == null || args.Parent.IsRoot)
|
||||
if (args.Parent != null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the parent is not a boxset, the only other allowed parent type is Folder
|
||||
if (!(args.Parent is BoxSet))
|
||||
{
|
||||
if (args.Parent.GetType() != typeof(Folder))
|
||||
if (args.Parent.IsRoot)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Optimization to avoid running all these tests against Top folders
|
||||
if (args.Parent != null && args.Parent.IsRoot)
|
||||
{
|
||||
return null;
|
||||
// If the parent is not a boxset, the only other allowed parent type is Folder
|
||||
if (!(args.Parent is BoxSet))
|
||||
{
|
||||
if (args.Parent.GetType() != typeof(Folder))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since the looping is expensive, this is an optimization to help us avoid it
|
||||
|
@ -76,16 +73,20 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
return null;
|
||||
}
|
||||
|
||||
// A shortcut to help us resolve faster in some cases
|
||||
var isKnownMovie = args.ContainsMetaFileByName("movie.xml") || args.ContainsMetaFileByName("tmdb3.json") ||
|
||||
args.Path.IndexOf("[tmdbid", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
|
||||
if (args.Path.IndexOf("[trailers]", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return FindMovie<Trailer>(args);
|
||||
return FindMovie<Trailer>(args.Path, args.FileSystemChildren, isKnownMovie);
|
||||
}
|
||||
if (args.Path.IndexOf("[musicvideos]", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return FindMovie<MusicVideo>(args);
|
||||
return FindMovie<MusicVideo>(args.Path, args.FileSystemChildren, isKnownMovie);
|
||||
}
|
||||
|
||||
return FindMovie<Movie>(args);
|
||||
return FindMovie<Movie>(args.Path, args.FileSystemChildren, isKnownMovie);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -123,18 +124,20 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
/// <summary>
|
||||
/// Finds a movie based on a child file system entries
|
||||
/// </summary>
|
||||
/// <param name="args">The args.</param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="fileSystemEntries">The file system entries.</param>
|
||||
/// <param name="isKnownMovie">if set to <c>true</c> [is known movie].</param>
|
||||
/// <returns>Movie.</returns>
|
||||
private T FindMovie<T>(ItemResolveArgs args)
|
||||
where T : Video, new ()
|
||||
private T FindMovie<T>(string path, IEnumerable<FileSystemInfo> fileSystemEntries, bool isKnownMovie)
|
||||
where T : Video, new()
|
||||
{
|
||||
// Optimization to avoid having to resolve every file
|
||||
bool? isKnownMovie = null;
|
||||
|
||||
var movies = new List<T>();
|
||||
|
||||
var multiDiscFolders = new List<FileSystemInfo>();
|
||||
|
||||
// Loop through each child file/folder and see if we find a video
|
||||
foreach (var child in args.FileSystemChildren)
|
||||
foreach (var child in fileSystemEntries)
|
||||
{
|
||||
if ((child.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
|
||||
{
|
||||
|
@ -142,7 +145,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
{
|
||||
return new T
|
||||
{
|
||||
Path = args.Path,
|
||||
Path = path,
|
||||
VideoType = VideoType.Dvd
|
||||
};
|
||||
}
|
||||
|
@ -150,17 +153,14 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
{
|
||||
return new T
|
||||
{
|
||||
Path = args.Path,
|
||||
Path = path,
|
||||
VideoType = VideoType.BluRay
|
||||
};
|
||||
}
|
||||
if (IsHdDvdDirectory(child.Name))
|
||||
|
||||
if (EntityResolutionHelper.IsMultiPartFile(child.Name))
|
||||
{
|
||||
return new T
|
||||
{
|
||||
Path = args.Path,
|
||||
VideoType = VideoType.HdDvd
|
||||
};
|
||||
multiDiscFolders.Add(child);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
@ -183,12 +183,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
if (item != null)
|
||||
{
|
||||
// If we already know it's a movie, we can stop looping
|
||||
if (!isKnownMovie.HasValue)
|
||||
{
|
||||
isKnownMovie = args.ContainsMetaFileByName("movie.xml") || args.ContainsMetaFileByName("tmdb3.json") || args.Path.IndexOf("[tmdbid", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
}
|
||||
|
||||
if (isKnownMovie.Value)
|
||||
if (isKnownMovie)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
@ -202,9 +197,63 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
return GetMultiFileMovie(movies);
|
||||
}
|
||||
|
||||
return movies.Count == 1 ? movies[0] : null;
|
||||
if (movies.Count == 1)
|
||||
{
|
||||
return movies[0];
|
||||
}
|
||||
|
||||
if (multiDiscFolders.Count > 0)
|
||||
{
|
||||
return GetMultiDiscMovie<T>(multiDiscFolders);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the multi disc movie.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="folders">The folders.</param>
|
||||
/// <returns>``0.</returns>
|
||||
private T GetMultiDiscMovie<T>(List<FileSystemInfo> folders)
|
||||
where T : Video, new()
|
||||
{
|
||||
var videoType = VideoType.BluRay;
|
||||
|
||||
folders = folders.Where(i =>
|
||||
{
|
||||
var subfolders = Directory.GetDirectories(i.FullName).Select(Path.GetFileName).ToList();
|
||||
|
||||
if (subfolders.Any(IsDvdDirectory))
|
||||
{
|
||||
videoType = VideoType.Dvd;
|
||||
return true;
|
||||
}
|
||||
if (subfolders.Any(IsBluRayDirectory))
|
||||
{
|
||||
videoType = VideoType.BluRay;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}).OrderBy(i => i.FullName).ToList();
|
||||
|
||||
if (folders.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new T
|
||||
{
|
||||
Path = folders[0].FullName,
|
||||
|
||||
IsMultiPart = true,
|
||||
|
||||
VideoType = videoType
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the multi file movie.
|
||||
|
@ -216,7 +265,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
where T : Video, new()
|
||||
{
|
||||
var multiPartMovies = movies.OrderBy(i => i.Path)
|
||||
.Where(i => EntityResolutionHelper.IsMultiPartFile(i.Path))
|
||||
.Where(i => EntityResolutionHelper.IsMultiPartFile(i.Name))
|
||||
.ToList();
|
||||
|
||||
// They must all be part of the sequence
|
||||
|
|
|
@ -25,6 +25,33 @@ namespace MediaBrowser.Tests.Resolvers
|
|||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - pt 1.mkv"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - part 1.mkv"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - dvd 1.mkv"));
|
||||
|
||||
// Not case sensitive
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - Disc1.mkv"));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMultiPartFolders()
|
||||
{
|
||||
Assert.IsFalse(EntityResolutionHelper.IsMultiPartFile(@"blah blah"));
|
||||
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - cd1"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disc1"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disk1"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - pt1"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - part1"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - dvd1"));
|
||||
|
||||
// Add a space
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - cd 1"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disc 1"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - disk 1"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - pt 1"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - part 1"));
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - dvd 1"));
|
||||
|
||||
// Not case sensitive
|
||||
Assert.IsTrue(EntityResolutionHelper.IsMultiPartFile(@"blah blah - Disc1"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user