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.Server.Implementations/Library | |
| parent | 627b8370a89cbf9826898c2edfc46767dfb5272a (diff) | |
moved resolvers to implementations, trimmed nuget package a bit
Diffstat (limited to 'MediaBrowser.Server.Implementations/Library')
15 files changed, 1079 insertions, 6 deletions
diff --git a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs new file mode 100644 index 000000000..98b8bea11 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -0,0 +1,55 @@ +using MediaBrowser.Controller.Library; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MediaBrowser.Server.Implementations.Library +{ + /// <summary> + /// Provides the core resolver ignore rules + /// </summary> + public class CoreResolutionIgnoreRule : IResolverIgnoreRule + { + /// <summary> + /// Any folder named in this list will be ignored - can be added to at runtime for extensibility + /// </summary> + private static readonly List<string> IgnoreFolders = new List<string> + { + "trailers", + "metadata", + "certificate", + "backup", + "ps3_update", + "ps3_vprm", + "adv_obj", + "extrafanart" + }; + + /// <summary> + /// Shoulds the ignore. + /// </summary> + /// <param name="args">The args.</param> + /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> + public bool ShouldIgnore(ItemResolveArgs args) + { + // Ignore hidden files and folders + if (args.IsHidden) + { + return true; + } + + if (args.IsDirectory) + { + var filename = args.FileInfo.cFileName; + + // Ignore any folders in our list + if (IgnoreFolders.Contains(filename, StringComparer.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index ba54b5d2b..e778b35df 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -6,10 +6,10 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.ScheduledTasks; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Server.Implementations.Library.Resolvers; using MoreLinq; using System; using System.Collections.Concurrent; @@ -37,7 +37,7 @@ namespace MediaBrowser.Server.Implementations.Library /// Gets the list of entity resolution ignore rules /// </summary> /// <value>The entity resolution ignore rules.</value> - private IEnumerable<IResolutionIgnoreRule> EntityResolutionIgnoreRules { get; set; } + private IEnumerable<IResolverIgnoreRule> EntityResolutionIgnoreRules { get; set; } /// <summary> /// Gets the list of BasePluginFolders added by plugins @@ -49,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.Library /// Gets the list of currently registered entity resolvers /// </summary> /// <value>The entity resolvers enumerable.</value> - private IEnumerable<IBaseItemResolver> EntityResolvers { get; set; } + private IEnumerable<IItemResolver> EntityResolvers { get; set; } #region LibraryChanged Event /// <summary> @@ -113,7 +113,7 @@ namespace MediaBrowser.Server.Implementations.Library /// <param name="pluginFolders">The plugin folders.</param> /// <param name="resolvers">The resolvers.</param> /// <param name="introProviders">The intro providers.</param> - public void AddParts(IEnumerable<IResolutionIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders, IEnumerable<IBaseItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders) + public void AddParts(IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IVirtualFolderCreator> pluginFolders, IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders) { EntityResolutionIgnoreRules = rules; PluginFolderCreators = pluginFolders; @@ -189,7 +189,14 @@ namespace MediaBrowser.Server.Implementations.Library /// <returns>BaseItem.</returns> public BaseItem ResolveItem(ItemResolveArgs args) { - return EntityResolvers.Select(r => r.ResolvePath(args)).FirstOrDefault(i => i != null); + var item = EntityResolvers.Select(r => r.ResolvePath(args)).FirstOrDefault(i => i != null); + + if (item != null) + { + ResolverHelper.SetInitialItemValues(item, args); + } + + return item; } /// <summary> @@ -237,7 +244,7 @@ namespace MediaBrowser.Server.Implementations.Library } // Check to see if we should resolve based on our contents - if (args.IsDirectory && !EntityResolutionHelper.ShouldResolvePathContents(args)) + if (args.IsDirectory && !ShouldResolvePathContents(args)) { return null; } @@ -246,6 +253,17 @@ namespace MediaBrowser.Server.Implementations.Library } /// <summary> + /// Determines whether a path should be ignored based on its contents - called after the contents have been read + /// </summary> + /// <param name="args">The args.</param> + /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> + private static bool ShouldResolvePathContents(ItemResolveArgs args) + { + // Ignore any folders containing a file called .ignore + return !args.ContainsFileSystemEntryByName(".ignore"); + } + + /// <summary> /// Resolves a set of files into a list of BaseItem /// </summary> /// <typeparam name="T"></typeparam> diff --git a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs new file mode 100644 index 000000000..aea34b0be --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs @@ -0,0 +1,82 @@ +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using System.IO; +using System.Text.RegularExpressions; + +namespace MediaBrowser.Server.Implementations.Library +{ + /// <summary> + /// Class ResolverHelper + /// </summary> + public static class ResolverHelper + { + /// <summary> + /// Sets the initial item values. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="args">The args.</param> + public static void SetInitialItemValues(BaseItem item, ItemResolveArgs args) + { + item.ResolveArgs = args; + + // If the resolver didn't specify this + if (string.IsNullOrEmpty(item.Path)) + { + item.Path = args.Path; + } + + // If the resolver didn't specify this + if (args.Parent != null) + { + item.Parent = args.Parent; + } + + item.Id = item.Path.GetMBId(item.GetType()); + item.DisplayMediaType = item.GetType().Name; + + // Make sure the item has a name + EnsureName(item); + + // Make sure DateCreated and DateModified have values + EntityResolutionHelper.EnsureDates(item, args); + } + + /// <summary> + /// Ensures the name. + /// </summary> + /// <param name="item">The item.</param> + private static void EnsureName(BaseItem item) + { + // If the subclass didn't supply a name, add it here + if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(item.Path)) + { + //we use our resolve args name here to get the name of the containg folder, not actual video file + item.Name = GetMBName(item.ResolveArgs.FileInfo.cFileName, item.ResolveArgs.FileInfo.IsDirectory); + } + } + + /// <summary> + /// The MB name regex + /// </summary> + private static readonly Regex MBNameRegex = new Regex("(\\[.*\\])", RegexOptions.Compiled); + + /// <summary> + /// Strip out attribute items and return just the name we will use for items + /// </summary> + /// <param name="path">Assumed to be a file or directory path</param> + /// <param name="isDirectory">if set to <c>true</c> [is directory].</param> + /// <returns>The cleaned name</returns> + private static string GetMBName(string path, bool isDirectory) + { + //first just get the file or directory name + var fn = isDirectory ? Path.GetFileName(path) : Path.GetFileNameWithoutExtension(path); + + //now - strip out anything inside brackets + fn = MBNameRegex.Replace(fn, string.Empty); + + return fn; + } + + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs new file mode 100644 index 000000000..f8e0acb5a --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs @@ -0,0 +1,80 @@ +using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Library; +using System; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio +{ + /// <summary> + /// Class AudioResolver + /// </summary> + public class AudioResolver : ItemResolver<Controller.Entities.Audio.Audio> + { + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override ResolverPriority Priority + { + get { return ResolverPriority.Last; } + } + + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>Entities.Audio.Audio.</returns> + protected override Controller.Entities.Audio.Audio Resolve(ItemResolveArgs args) + { + // Return audio if the path is a file and has a matching extension + + if (!args.IsDirectory) + { + if (IsAudioFile(args)) + { + return new Controller.Entities.Audio.Audio(); + } + } + + return null; + } + + /// <summary> + /// The audio file extensions + /// </summary> + public static readonly string[] AudioFileExtensions = new[] { + ".mp3", + ".flac", + ".wma", + ".aac", + ".acc", + ".m4a", + ".m4b", + ".wav", + ".ape", + ".ogg", + ".oga" + }; + + /// <summary> + /// Determines whether [is audio file] [the specified args]. + /// </summary> + /// <param name="args">The args.</param> + /// <returns><c>true</c> if [is audio file] [the specified args]; otherwise, <c>false</c>.</returns> + public static bool IsAudioFile(ItemResolveArgs args) + { + return AudioFileExtensions.Contains(Path.GetExtension(args.Path), StringComparer.OrdinalIgnoreCase); + } + + /// <summary> + /// Determines whether [is audio file] [the specified file]. + /// </summary> + /// <param name="file">The file.</param> + /// <returns><c>true</c> if [is audio file] [the specified file]; otherwise, <c>false</c>.</returns> + public static bool IsAudioFile(WIN32_FIND_DATA file) + { + return AudioFileExtensions.Contains(Path.GetExtension(file.Path), StringComparer.OrdinalIgnoreCase); + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs new file mode 100644 index 000000000..31016e2fc --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio +{ + /// <summary> + /// Class MusicAlbumResolver + /// </summary> + public class MusicAlbumResolver : ItemResolver<MusicAlbum> + { + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override ResolverPriority Priority + { + get { return ResolverPriority.Third; } // we need to be ahead of the generic folder resolver but behind the movie one + } + + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>MusicAlbum.</returns> + protected override MusicAlbum Resolve(ItemResolveArgs args) + { + if (!args.IsDirectory) return null; + + //Avoid mis-identifying top folders + if (args.Parent == null) return null; + if (args.Parent.IsRoot) return null; + + return IsMusicAlbum(args) ? new MusicAlbum() : null; + } + + + /// <summary> + /// Determine if the supplied file data points to a music album + /// </summary> + /// <param name="data">The data.</param> + /// <returns><c>true</c> if [is music album] [the specified data]; otherwise, <c>false</c>.</returns> + public static bool IsMusicAlbum(WIN32_FIND_DATA data) + { + return ContainsMusic(FileSystem.GetFiles(data.Path)); + } + + /// <summary> + /// Determine if the supplied reslove args should be considered a music album + /// </summary> + /// <param name="args">The args.</param> + /// <returns><c>true</c> if [is music album] [the specified args]; otherwise, <c>false</c>.</returns> + public static bool IsMusicAlbum(ItemResolveArgs args) + { + // Args points to an album if parent is an Artist folder or it directly contains music + if (args.IsDirectory) + { + //if (args.Parent is MusicArtist) return true; //saves us from testing children twice + if (ContainsMusic(args.FileSystemChildren)) return true; + } + + + return false; + } + + /// <summary> + /// Determine if the supplied list contains what we should consider music + /// </summary> + /// <param name="list">The list.</param> + /// <returns><c>true</c> if the specified list contains music; otherwise, <c>false</c>.</returns> + public static bool ContainsMusic(IEnumerable<WIN32_FIND_DATA> list) + { + // If list contains at least 2 audio files or at least one and no video files consider it to contain music + var foundAudio = 0; + var foundVideo = 0; + foreach (var file in list) + { + if (AudioResolver.IsAudioFile(file)) foundAudio++; + if (foundAudio >= 2) + { + return true; + } + if (EntityResolutionHelper.IsVideoFile(file.Path)) foundVideo++; + } + + // or a single audio file and no video files + if (foundAudio > 0 && foundVideo == 0) return true; + return false; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs new file mode 100644 index 000000000..e48ad96c6 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs @@ -0,0 +1,39 @@ +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using System.Linq; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio +{ + /// <summary> + /// Class MusicArtistResolver + /// </summary> + public class MusicArtistResolver : ItemResolver<MusicArtist> + { + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override ResolverPriority Priority + { + get { return ResolverPriority.Third; } // we need to be ahead of the generic folder resolver but behind the movie one + } + + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>MusicArtist.</returns> + protected override MusicArtist Resolve(ItemResolveArgs args) + { + if (!args.IsDirectory) return null; + + //Avoid mis-identifying top folders + if (args.Parent == null) return null; + if (args.Parent.IsRoot) return null; + + // If we contain an album assume we are an artist folder + return args.FileSystemChildren.Any(MusicAlbumResolver.IsMusicAlbum) ? new MusicArtist() : null; + } + + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseItemResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseItemResolver.cs new file mode 100644 index 000000000..a80a48290 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseItemResolver.cs @@ -0,0 +1,61 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers +{ + /// <summary> + /// Class ItemResolver + /// </summary> + /// <typeparam name="T"></typeparam> + public abstract class ItemResolver<T> : IItemResolver + where T : BaseItem, new() + { + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>`0.</returns> + protected virtual T Resolve(ItemResolveArgs args) + { + return null; + } + + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public virtual ResolverPriority Priority + { + get + { + return ResolverPriority.First; + } + } + + /// <summary> + /// Sets initial values on the newly resolved item + /// </summary> + /// <param name="item">The item.</param> + /// <param name="args">The args.</param> + protected virtual void SetInitialItemValues(T item, ItemResolveArgs args) + { + } + + /// <summary> + /// Resolves the path. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>BaseItem.</returns> + BaseItem IItemResolver.ResolvePath(ItemResolveArgs args) + { + var item = Resolve(args); + + if (item != null) + { + SetInitialItemValues(item, args); + } + + return item; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs new file mode 100644 index 000000000..c680af7d6 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs @@ -0,0 +1,69 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers +{ + /// <summary> + /// Class FolderResolver + /// </summary> + public class FolderResolver : FolderResolver<Folder> + { + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override ResolverPriority Priority + { + get { return ResolverPriority.Last; } + } + + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>Folder.</returns> + protected override Folder Resolve(ItemResolveArgs args) + { + if (args.IsDirectory) + { + if (args.IsPhysicalRoot) + { + return new AggregateFolder(); + } + if (args.IsRoot) + { + return new UserRootFolder(); //if we got here and still a root - must be user root + } + if (args.IsVf) + { + return new CollectionFolder(); + } + + return new Folder(); + } + + return null; + } + } + + /// <summary> + /// Class FolderResolver + /// </summary> + /// <typeparam name="TItemType">The type of the T item type.</typeparam> + public abstract class FolderResolver<TItemType> : ItemResolver<TItemType> + where TItemType : Folder, new() + { + /// <summary> + /// Sets the initial item values. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="args">The args.</param> + protected override void SetInitialItemValues(TItemType item, ItemResolveArgs args) + { + base.SetInitialItemValues(item, args); + + item.IsRoot = args.Parent == null; + item.IsPhysicalRoot = args.IsPhysicalRoot; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/LocalTrailerResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/LocalTrailerResolver.cs new file mode 100644 index 000000000..d0a0cd5c7 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/LocalTrailerResolver.cs @@ -0,0 +1,38 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using System; +using System.IO; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers +{ + /// <summary> + /// Class LocalTrailerResolver + /// </summary> + public class LocalTrailerResolver : VideoResolver<Trailer> + { + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>Trailer.</returns> + protected override Trailer Resolve(ItemResolveArgs args) + { + // Trailers are not Children, therefore this can never happen + if (args.Parent != null) + { + return null; + } + + // If the file is within a trailers folder, see if the VideoResolver returns something + if (!args.IsDirectory) + { + if (string.Equals(Path.GetFileName(Path.GetDirectoryName(args.Path)), BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase)) + { + return base.Resolve(args); + } + } + + return null; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs new file mode 100644 index 000000000..2f810d2a1 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs @@ -0,0 +1,41 @@ +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using System; +using System.IO; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies +{ + /// <summary> + /// Class BoxSetResolver + /// </summary> + public class BoxSetResolver : FolderResolver<BoxSet> + { + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>BoxSet.</returns> + protected override BoxSet Resolve(ItemResolveArgs args) + { + // It's a boxset if all of the following conditions are met: + // Is a Directory + // Contains [boxset] in the path + if (args.IsDirectory) + { + var filename = Path.GetFileName(args.Path); + + if (string.IsNullOrEmpty(filename)) + { + return null; + } + + if (filename.IndexOf("[boxset]", StringComparison.OrdinalIgnoreCase) != -1) + { + return new BoxSet(); + } + } + + return null; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs new file mode 100644 index 000000000..601ab6661 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -0,0 +1,208 @@ +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers.Movies; +using MediaBrowser.Model.Entities; +using System; +using System.Collections.Generic; +using System.IO; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies +{ + /// <summary> + /// Class MovieResolver + /// </summary> + public class MovieResolver : VideoResolver<Movie> + { + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override ResolverPriority Priority + { + get + { + // Give plugins a chance to catch iso's first + // Also since we have to loop through child files looking for videos, + // see if we can avoid some of that by letting other resolvers claim folders first + return ResolverPriority.Second; + } + } + + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>Movie.</returns> + protected override Movie Resolve(ItemResolveArgs args) + { + // Must be a directory and under a 'Movies' VF + if (args.IsDirectory) + { + // Avoid expensive tests against VF's and all their children by not allowing this + 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; + } + } + + // Optimization to avoid running all these tests against Top folders + if (args.Parent != null && args.Parent.IsRoot) + { + return null; + } + + // The movie must be a video file + return FindMovie(args); + } + + 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(Movie item, ItemResolveArgs args) + { + base.SetInitialItemValues(item, args); + + SetProviderIdFromPath(item); + } + + /// <summary> + /// Sets the provider id from path. + /// </summary> + /// <param name="item">The item.</param> + private void SetProviderIdFromPath(Movie item) + { + //we need to only look at the name of this actual item (not parents) + var justName = Path.GetFileName(item.Path); + + var id = justName.GetAttributeValue("tmdbid"); + + if (!string.IsNullOrEmpty(id)) + { + item.SetProviderId(MetadataProviders.Tmdb, id); + } + } + + /// <summary> + /// Finds a movie based on a child file system entries + /// </summary> + /// <param name="args">The args.</param> + /// <returns>Movie.</returns> + private Movie FindMovie(ItemResolveArgs args) + { + // Since the looping is expensive, this is an optimization to help us avoid it + if (args.ContainsMetaFileByName("series.xml") || args.Path.IndexOf("[tvdbid", StringComparison.OrdinalIgnoreCase) != -1) + { + return null; + } + + // Optimization to avoid having to resolve every file + bool? isKnownMovie = null; + + var movies = new List<Movie>(); + + // Loop through each child file/folder and see if we find a video + foreach (var child in args.FileSystemChildren) + { + if (child.IsDirectory) + { + if (IsDvdDirectory(child.cFileName)) + { + return new Movie + { + Path = args.Path, + VideoType = VideoType.Dvd + }; + } + if (IsBluRayDirectory(child.cFileName)) + { + return new Movie + { + Path = args.Path, + VideoType = VideoType.BluRay + }; + } + if (IsHdDvdDirectory(child.cFileName)) + { + return new Movie + { + Path = args.Path, + VideoType = VideoType.HdDvd + }; + } + + continue; + } + + var childArgs = new ItemResolveArgs + { + FileInfo = child, + Path = child.Path + }; + + var item = base.Resolve(childArgs); + + 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(MovieDbProvider.LOCAL_META_FILE_NAME) || args.Path.IndexOf("[tmdbid", StringComparison.OrdinalIgnoreCase) != -1; + } + + if (isKnownMovie.Value) + { + return item; + } + + movies.Add(item); + } + } + + // If there are multiple video files, return null, and let the VideoResolver catch them later as plain videos + return movies.Count == 1 ? movies[0] : null; + } + + /// <summary> + /// Determines whether [is DVD directory] [the specified directory name]. + /// </summary> + /// <param name="directoryName">Name of the directory.</param> + /// <returns><c>true</c> if [is DVD directory] [the specified directory name]; otherwise, <c>false</c>.</returns> + private bool IsDvdDirectory(string directoryName) + { + return directoryName.Equals("video_ts", StringComparison.OrdinalIgnoreCase); + } + /// <summary> + /// Determines whether [is hd DVD directory] [the specified directory name]. + /// </summary> + /// <param name="directoryName">Name of the directory.</param> + /// <returns><c>true</c> if [is hd DVD directory] [the specified directory name]; otherwise, <c>false</c>.</returns> + private bool IsHdDvdDirectory(string directoryName) + { + return directoryName.Equals("hvdvd_ts", StringComparison.OrdinalIgnoreCase); + } + /// <summary> + /// Determines whether [is blu ray directory] [the specified directory name]. + /// </summary> + /// <param name="directoryName">Name of the directory.</param> + /// <returns><c>true</c> if [is blu ray directory] [the specified directory name]; otherwise, <c>false</c>.</returns> + private bool IsBluRayDirectory(string directoryName) + { + return directoryName.Equals("bdmv", StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs new file mode 100644 index 000000000..6fa9711cc --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs @@ -0,0 +1,76 @@ +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; +using System; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV +{ + /// <summary> + /// Class EpisodeResolver + /// </summary> + public class EpisodeResolver : VideoResolver<Episode> + { + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>Episode.</returns> + protected override Episode Resolve(ItemResolveArgs args) + { + // If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something + if (args.Parent is Season || args.Parent is Series) + { + if (args.IsDirectory) + { + if (args.ContainsFileSystemEntryByName("video_ts")) + { + return new Episode + { + Path = args.Path, + VideoType = VideoType.Dvd + }; + } + if (args.ContainsFileSystemEntryByName("bdmv")) + { + return new Episode + { + Path = args.Path, + VideoType = VideoType.BluRay + }; + } + } + + return base.Resolve(args); + } + + 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(Episode item, ItemResolveArgs args) + { + base.SetInitialItemValues(item, args); + + //fill in our season and series ids + var season = args.Parent as Season; + if (season != null) + { + item.SeasonItemId = season.Id; + var series = season.Parent as Series; + if (series != null) + { + item.SeriesItemId = series.Id; + } + } + else + { + var series = args.Parent as Series; + item.SeriesItemId = series != null ? series.Id : Guid.Empty; + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs new file mode 100644 index 000000000..07fb2f486 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -0,0 +1,45 @@ +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using System; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV +{ + /// <summary> + /// Class SeasonResolver + /// </summary> + public class SeasonResolver : FolderResolver<Season> + { + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>Season.</returns> + protected override Season Resolve(ItemResolveArgs args) + { + if (args.Parent is Series && args.IsDirectory) + { + return new Season + { + IndexNumber = TVUtils.GetSeasonNumberFromPath(args.Path) + }; + } + + 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(Season item, ItemResolveArgs args) + { + base.SetInitialItemValues(item, args); + + var series = args.Parent as Series; + item.SeriesItemId = series != null ? series.Id : Guid.Empty; + + Season.AddMetadataFiles(args); + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs new file mode 100644 index 000000000..642e52363 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -0,0 +1,98 @@ +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; +using System; +using System.IO; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV +{ + /// <summary> + /// Class SeriesResolver + /// </summary> + public class SeriesResolver : FolderResolver<Series> + { + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override ResolverPriority Priority + { + get + { + return ResolverPriority.Second; + } + } + + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>Series.</returns> + protected override Series Resolve(ItemResolveArgs args) + { + if (args.IsDirectory) + { + // Avoid expensive tests against VF's and all their children by not allowing this + if (args.Parent == null || args.Parent.IsRoot) + { + return null; + } + + // Optimization to avoid running these tests against Seasons + if (args.Parent is Series) + { + return null; + } + + // It's a Series if any of the following conditions are met: + // series.xml exists + // [tvdbid= is present in the path + // TVUtils.IsSeriesFolder returns true + var filename = Path.GetFileName(args.Path); + + if (string.IsNullOrEmpty(filename)) + { + return null; + } + + if (args.ContainsMetaFileByName("series.xml") || filename.IndexOf("[tvdbid=", StringComparison.OrdinalIgnoreCase) != -1 || TVUtils.IsSeriesFolder(args.Path, args.FileSystemChildren)) + { + return new Series(); + } + } + + 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(Series item, ItemResolveArgs args) + { + base.SetInitialItemValues(item, args); + + Season.AddMetadataFiles(args); + + SetProviderIdFromPath(item, args.Path); + } + + /// <summary> + /// Sets the provider id from path. + /// </summary> + /// <param name="item">The item.</param> + private void SetProviderIdFromPath(Series item, string path) + { + var justName = Path.GetFileName(path); + + var id = justName.GetAttributeValue("tvdbid"); + + if (!string.IsNullOrEmpty(id)) + { + item.SetProviderId(MetadataProviders.Tvdb, id); + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs new file mode 100644 index 000000000..5a47f38cd --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs @@ -0,0 +1,71 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; +using System; +using System.IO; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers +{ + /// <summary> + /// Resolves a Path into a Video + /// </summary> + public class VideoResolver : VideoResolver<Video> + { + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override ResolverPriority Priority + { + get { return ResolverPriority.Last; } + } + } + + /// <summary> + /// Resolves a Path into a Video or Video subclass + /// </summary> + /// <typeparam name="T"></typeparam> + public abstract class VideoResolver<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) + { + // If the path is a file check for a matching extensions + if (!args.IsDirectory) + { + if (EntityResolutionHelper.IsVideoFile(args.Path)) + { + var extension = Path.GetExtension(args.Path); + + var type = string.Equals(extension, ".iso", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".img", StringComparison.OrdinalIgnoreCase) ? + VideoType.Iso : VideoType.VideoFile; + + return new T + { + VideoType = type, + Path = args.Path + }; + } + } + + 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); + + item.VideoFormat = item.Path.IndexOf("[3d]", StringComparison.OrdinalIgnoreCase) != -1 ? VideoFormat.Digital3D : item.Path.IndexOf("[sbs3d]", StringComparison.OrdinalIgnoreCase) != -1 ? VideoFormat.Sbs3D : VideoFormat.Standard; + } + } +} |
