diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-02-05 23:39:16 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-02-05 23:39:16 -0500 |
| commit | 821a3d29a228feaa3ac4d36c58ee478a405e0481 (patch) | |
| tree | 48925fa069c1b57cc3c126b58194740c191359c1 /MediaBrowser.Controller/Entities | |
| parent | 64eb8c82a3e82d84ac827aa35a55fdface9ac783 (diff) | |
converted movie providers to new system
Diffstat (limited to 'MediaBrowser.Controller/Entities')
| -rw-r--r-- | MediaBrowser.Controller/Entities/AdultVideo.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/AggregateFolder.cs | 65 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/BaseItem.cs | 558 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Book.cs | 19 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/CollectionFolder.cs | 66 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Folder.cs | 63 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Game.cs | 22 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/IHasImages.cs | 6 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Movies/Movie.cs | 81 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/TV/Episode.cs | 22 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/TV/Season.cs | 28 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/TV/Series.cs | 14 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Trailer.cs | 27 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Video.cs | 106 |
14 files changed, 363 insertions, 718 deletions
diff --git a/MediaBrowser.Controller/Entities/AdultVideo.cs b/MediaBrowser.Controller/Entities/AdultVideo.cs index f81cfa1f62..475d7bc54d 100644 --- a/MediaBrowser.Controller/Entities/AdultVideo.cs +++ b/MediaBrowser.Controller/Entities/AdultVideo.cs @@ -3,6 +3,10 @@ namespace MediaBrowser.Controller.Entities { public class AdultVideo : Video, IHasPreferredMetadataLanguage { + /// <summary> + /// Gets or sets the preferred metadata language. + /// </summary> + /// <value>The preferred metadata language.</value> public string PreferredMetadataLanguage { get; set; } /// <summary> diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 302842e7e8..ef455846e7 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -1,7 +1,11 @@ -using System; +using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Library; +using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities { @@ -11,6 +15,11 @@ namespace MediaBrowser.Controller.Entities /// </summary> public class AggregateFolder : Folder { + public AggregateFolder() + { + PhysicalLocationsList = new List<string>(); + } + /// <summary> /// We don't support manual shortcuts /// </summary> @@ -36,6 +45,60 @@ namespace MediaBrowser.Controller.Entities get { return _virtualChildren; } } + [IgnoreDataMember] + public override IEnumerable<string> PhysicalLocations + { + get + { + return PhysicalLocationsList; + } + } + + public List<string> PhysicalLocationsList { get; set; } + + protected override IEnumerable<FileSystemInfo> GetFileSystemChildren() + { + return CreateResolveArgs().FileSystemChildren; + } + + private ItemResolveArgs CreateResolveArgs() + { + var path = ContainingFolderPath; + + var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager) + { + FileInfo = new DirectoryInfo(path), + Path = path, + Parent = Parent + }; + + // Gather child folder and files + if (args.IsDirectory) + { + var isPhysicalRoot = args.IsPhysicalRoot; + + // When resolving the root, we need it's grandchildren (children of user views) + var flattenFolderDepth = isPhysicalRoot ? 2 : 0; + + var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf); + + // Need to remove subpaths that may have been resolved from shortcuts + // Example: if \\server\movies exists, then strip out \\server\movies\action + if (isPhysicalRoot) + { + var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Keys); + + fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName); + } + + args.FileSystemDictionary = fileSystemDictionary; + } + + PhysicalLocationsList = args.PhysicalLocations.ToList(); + + return args; + } + /// <summary> /// Adds the virtual child. /// </summary> diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 650a9bad09..de5516e299 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1,12 +1,10 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; @@ -103,6 +101,35 @@ namespace MediaBrowser.Controller.Entities protected internal bool IsOffline { get; set; } /// <summary> + /// Returns the folder containing the item. + /// If the item is a folder, it returns the folder itself + /// </summary> + [IgnoreDataMember] + public virtual string ContainingFolderPath + { + get + { + if (IsFolder) + { + return Path; + } + + return System.IO.Path.GetDirectoryName(Path); + } + } + + [IgnoreDataMember] + public bool IsOwnedItem + { + get + { + // Local trailer, special feature, theme video, etc. + // An item that belongs to another item but is not part of the Parent-Child tree + return !IsFolder && Parent == null; + } + } + + /// <summary> /// Gets or sets the type of the location. /// </summary> /// <value>The type of the location.</value> @@ -190,19 +217,6 @@ namespace MediaBrowser.Controller.Entities public List<MetadataFields> LockedFields { get; set; } /// <summary> - /// Should be overridden to return the proper folder where metadata lives - /// </summary> - /// <value>The meta location.</value> - [IgnoreDataMember] - public virtual string MetaLocation - { - get - { - return Path ?? ""; - } - } - - /// <summary> /// Gets the type of the media. /// </summary> /// <value>The type of the media.</value> @@ -215,160 +229,19 @@ namespace MediaBrowser.Controller.Entities } } - /// <summary> - /// The _resolve args - /// </summary> - private ItemResolveArgs _resolveArgs; - /// <summary> - /// We attach these to the item so that we only ever have to hit the file system once - /// (this includes the children of the containing folder) - /// </summary> - /// <value>The resolve args.</value> [IgnoreDataMember] - public ItemResolveArgs ResolveArgs + public virtual IEnumerable<string> PhysicalLocations { get { - if (_resolveArgs == null) - { - try - { - _resolveArgs = CreateResolveArgs(); - } - catch (IOException ex) - { - Logger.ErrorException("Error creating resolve args for {0}", ex, Path); - - IsOffline = true; + var locationType = LocationType; - throw; - } - } - - return _resolveArgs; - } - set - { - _resolveArgs = value; - } - } - - [IgnoreDataMember] - public IEnumerable<string> PhysicalLocations - { - get - { - return ResolveArgs.PhysicalLocations; - } - } - - /// <summary> - /// Resets the resolve args. - /// </summary> - /// <param name="pathInfo">The path info.</param> - public void ResetResolveArgs(FileSystemInfo pathInfo) - { - ResetResolveArgs(CreateResolveArgs(pathInfo)); - } - - /// <summary> - /// Resets the resolve args. - /// </summary> - public void ResetResolveArgs() - { - _resolveArgs = null; - } - - /// <summary> - /// Resets the resolve args. - /// </summary> - /// <param name="args">The args.</param> - public void ResetResolveArgs(ItemResolveArgs args) - { - _resolveArgs = args; - } - - /// <summary> - /// Creates ResolveArgs on demand - /// </summary> - /// <param name="pathInfo">The path info.</param> - /// <returns>ItemResolveArgs.</returns> - /// <exception cref="System.IO.IOException">Unable to retrieve file system info for + path</exception> - protected internal virtual ItemResolveArgs CreateResolveArgs(FileSystemInfo pathInfo = null) - { - var path = Path; - - var locationType = LocationType; - - if (locationType == LocationType.Remote || - locationType == LocationType.Virtual) - { - return new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager); - } - - var isDirectory = false; - - if (UseParentPathToCreateResolveArgs) - { - path = System.IO.Path.GetDirectoryName(path); - isDirectory = true; - } - - pathInfo = pathInfo ?? (isDirectory ? new DirectoryInfo(path) : FileSystem.GetFileSystemInfo(path)); - - if (pathInfo == null || !pathInfo.Exists) - { - throw new IOException("Unable to retrieve file system info for " + path); - } - - var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager) - { - FileInfo = pathInfo, - Path = path, - Parent = Parent - }; - - // Gather child folder and files - if (args.IsDirectory) - { - var isPhysicalRoot = args.IsPhysicalRoot; - - // When resolving the root, we need it's grandchildren (children of user views) - var flattenFolderDepth = isPhysicalRoot ? 2 : 0; - - var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf); - - // Need to remove subpaths that may have been resolved from shortcuts - // Example: if \\server\movies exists, then strip out \\server\movies\action - if (isPhysicalRoot) + if (locationType != LocationType.Remote && locationType != LocationType.Virtual) { - var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Keys); - - fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName); + return new string[] { }; } - args.FileSystemDictionary = fileSystemDictionary; - } - - //update our dates - EntityResolutionHelper.EnsureDates(FileSystem, this, args, false); - - IsOffline = false; - - return args; - } - - /// <summary> - /// Some subclasses will stop resolving at a directory and point their Path to a file within. This will help ensure the on-demand resolve args are identical to the - /// original ones. - /// </summary> - /// <value><c>true</c> if [use parent path to create resolve args]; otherwise, <c>false</c>.</value> - [IgnoreDataMember] - protected virtual bool UseParentPathToCreateResolveArgs - { - get - { - return false; + return new[] { Path }; } } @@ -583,122 +456,93 @@ namespace MediaBrowser.Controller.Entities /// Loads local trailers from the file system /// </summary> /// <returns>List{Video}.</returns> - private IEnumerable<Trailer> LoadLocalTrailers() - { - ItemResolveArgs resolveArgs; - - try - { - resolveArgs = ResolveArgs; - - if (!resolveArgs.IsDirectory) - { - return new List<Trailer>(); - } - } - catch (IOException ex) - { - Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path); - return new List<Trailer>(); - } - - var files = new List<FileSystemInfo>(); - - var folder = resolveArgs.GetFileSystemEntryByName(TrailerFolderName); - - // Path doesn't exist. No biggie - if (folder != null) - { - try - { - files.AddRange(new DirectoryInfo(folder.FullName).EnumerateFiles()); - } - catch (IOException ex) - { - Logger.ErrorException("Error loading trailers for {0}", ex, Name); - } - } - - // Support xbmc trailers (-trailer suffix on video file names) - files.AddRange(resolveArgs.FileSystemChildren.Where(i => - { - try - { - if ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) - { - if (System.IO.Path.GetFileNameWithoutExtension(i.Name).EndsWith(XbmcTrailerFileSuffix, StringComparison.OrdinalIgnoreCase) && !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - } - catch (IOException ex) - { - Logger.ErrorException("Error accessing path {0}", ex, i.FullName); - } - - return false; - })); - - return LibraryManager.ResolvePaths<Trailer>(files, null).Select(video => - { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = LibraryManager.GetItemById(video.Id) as Trailer; - - if (dbItem != null) - { - dbItem.ResetResolveArgs(video.ResolveArgs); - video = dbItem; - } - - return video; - - }).ToList(); + private IEnumerable<Trailer> LoadLocalTrailers(List<FileSystemInfo> fileSystemChildren) + { + return new List<Trailer>(); + //ItemResolveArgs resolveArgs; + + //try + //{ + // resolveArgs = ResolveArgs; + + // if (!resolveArgs.IsDirectory) + // { + // return new List<Trailer>(); + // } + //} + //catch (IOException ex) + //{ + // Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path); + // return new List<Trailer>(); + //} + + //var files = new List<FileSystemInfo>(); + + //var folder = resolveArgs.GetFileSystemEntryByName(TrailerFolderName); + + //// Path doesn't exist. No biggie + //if (folder != null) + //{ + // try + // { + // files.AddRange(new DirectoryInfo(folder.FullName).EnumerateFiles()); + // } + // catch (IOException ex) + // { + // Logger.ErrorException("Error loading trailers for {0}", ex, Name); + // } + //} + + //// Support xbmc trailers (-trailer suffix on video file names) + //files.AddRange(resolveArgs.FileSystemChildren.Where(i => + //{ + // try + // { + // if ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) + // { + // if (System.IO.Path.GetFileNameWithoutExtension(i.Name).EndsWith(XbmcTrailerFileSuffix, StringComparison.OrdinalIgnoreCase) && !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase)) + // { + // return true; + // } + // } + // } + // catch (IOException ex) + // { + // Logger.ErrorException("Error accessing path {0}", ex, i.FullName); + // } + + // return false; + //})); + + //return LibraryManager.ResolvePaths<Trailer>(files, null).Select(video => + //{ + // // Try to retrieve it from the db. If we don't find it, use the resolved version + // var dbItem = LibraryManager.GetItemById(video.Id) as Trailer; + + // if (dbItem != null) + // { + // video = dbItem; + // } + + // return video; + + //}).ToList(); } /// <summary> /// Loads the theme songs. /// </summary> /// <returns>List{Audio.Audio}.</returns> - private IEnumerable<Audio.Audio> LoadThemeSongs() + private IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemInfo> fileSystemChildren) { - ItemResolveArgs resolveArgs; - - try - { - resolveArgs = ResolveArgs; - - if (!resolveArgs.IsDirectory) - { - return new List<Audio.Audio>(); - } - } - catch (IOException ex) - { - Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path); - return new List<Audio.Audio>(); - } - - var files = new List<FileSystemInfo>(); - - var folder = resolveArgs.GetFileSystemEntryByName(ThemeSongsFolderName); - - // Path doesn't exist. No biggie - if (folder != null) - { - try - { - files.AddRange(new DirectoryInfo(folder.FullName).EnumerateFiles()); - } - catch (IOException ex) - { - Logger.ErrorException("Error loading theme songs for {0}", ex, Name); - } - } + var files = fileSystemChildren.OfType<DirectoryInfo>() + .Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase)) + .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)) + .ToList(); // Support plex/xbmc convention - files.AddRange(resolveArgs.FileSystemChildren - .Where(i => string.Equals(System.IO.Path.GetFileNameWithoutExtension(i.Name), ThemeSongFilename, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsAudioFile(i.Name)) + files.AddRange(fileSystemChildren.OfType<FileInfo>() + .Where(i => string.Equals(System.IO.Path.GetFileNameWithoutExtension(i.Name), ThemeSongFilename, StringComparison.OrdinalIgnoreCase)) ); return LibraryManager.ResolvePaths<Audio.Audio>(files, null).Select(audio => @@ -708,7 +552,6 @@ namespace MediaBrowser.Controller.Entities if (dbItem != null) { - dbItem.ResetResolveArgs(audio.ResolveArgs); audio = dbItem; } @@ -720,44 +563,11 @@ namespace MediaBrowser.Controller.Entities /// Loads the video backdrops. /// </summary> /// <returns>List{Video}.</returns> - private IEnumerable<Video> LoadThemeVideos() + private IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemInfo> fileSystemChildren) { - ItemResolveArgs resolveArgs; - - try - { - resolveArgs = ResolveArgs; - - if (!resolveArgs.IsDirectory) - { - return new List<Video>(); - } - } - catch (IOException ex) - { - Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path); - return new List<Video>(); - } - - var folder = resolveArgs.GetFileSystemEntryByName(ThemeVideosFolderName); - - // Path doesn't exist. No biggie - if (folder == null) - { - return new List<Video>(); - } - - IEnumerable<FileSystemInfo> files; - - try - { - files = new DirectoryInfo(folder.FullName).EnumerateFiles(); - } - catch (IOException ex) - { - Logger.ErrorException("Error loading video backdrops for {0}", ex, Name); - return new List<Video>(); - } + var files = fileSystemChildren.OfType<DirectoryInfo>() + .Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase)) + .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)); return LibraryManager.ResolvePaths<Video>(files, null).Select(item => { @@ -766,7 +576,6 @@ namespace MediaBrowser.Controller.Entities if (dbItem != null) { - dbItem.ResetResolveArgs(item.ResolveArgs); item = dbItem; } @@ -774,9 +583,9 @@ namespace MediaBrowser.Controller.Entities }).ToList(); } - public Task<bool> RefreshMetadata(CancellationToken cancellationToken, bool resetResolveArgs = true) + public Task RefreshMetadata(CancellationToken cancellationToken) { - return RefreshMetadata(new MetadataRefreshOptions { ResetResolveArgs = resetResolveArgs }, cancellationToken); + return RefreshMetadata(new MetadataRefreshOptions(), cancellationToken); } /// <summary> @@ -785,35 +594,24 @@ namespace MediaBrowser.Controller.Entities /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>true if a provider reports we changed</returns> - public async Task<bool> RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken) + public async Task RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken) { - if (options.ResetResolveArgs) + var locationType = LocationType; + + if (IsFolder || Parent != null) { - // Reload this - ResetResolveArgs(); - } + var files = locationType == LocationType.FileSystem || locationType == LocationType.Offline ? + GetFileSystemChildren().ToList() : + new List<FileSystemInfo>(); - await BeforeRefreshMetadata(options, cancellationToken).ConfigureAwait(false); + await BeforeRefreshMetadata(options, files, cancellationToken).ConfigureAwait(false); + } await ProviderManager.RefreshMetadata(this, options, cancellationToken).ConfigureAwait(false); - - return false; } - private readonly Task _cachedTask = Task.FromResult(true); - protected virtual Task BeforeRefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken) + protected virtual async Task BeforeRefreshMetadata(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - return _cachedTask; - } - - [Obsolete] - public virtual async Task<bool> RefreshMetadataDirect(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false) - { - // Refresh for the item - var itemRefreshTask = ProviderManager.ExecuteMetadataProviders(this, cancellationToken, forceRefresh); - - cancellationToken.ThrowIfCancellationRequested(); - var themeSongsChanged = false; var themeVideosChanged = false; @@ -825,102 +623,83 @@ namespace MediaBrowser.Controller.Entities var hasThemeMedia = this as IHasThemeMedia; if (hasThemeMedia != null) { - themeSongsChanged = await RefreshThemeSongs(hasThemeMedia, cancellationToken, forceSave, forceRefresh).ConfigureAwait(false); + if (!IsInMixedFolder) + { + themeSongsChanged = await RefreshThemeSongs(hasThemeMedia, options, fileSystemChildren, cancellationToken).ConfigureAwait(false); - themeVideosChanged = await RefreshThemeVideos(hasThemeMedia, cancellationToken, forceSave, forceRefresh).ConfigureAwait(false); + themeVideosChanged = await RefreshThemeVideos(hasThemeMedia, options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + } } var hasTrailers = this as IHasTrailers; if (hasTrailers != null) { - localTrailersChanged = await RefreshLocalTrailers(hasTrailers, cancellationToken, forceSave, forceRefresh).ConfigureAwait(false); + localTrailersChanged = await RefreshLocalTrailers(hasTrailers, options, fileSystemChildren, cancellationToken).ConfigureAwait(false); } } - - cancellationToken.ThrowIfCancellationRequested(); - - // Get the result from the item task - var updateReason = await itemRefreshTask.ConfigureAwait(false); - - var changed = updateReason.HasValue; - - if (changed || forceSave || themeSongsChanged || themeVideosChanged || localTrailersChanged) + + if (themeSongsChanged || themeVideosChanged || localTrailersChanged) { - cancellationToken.ThrowIfCancellationRequested(); - - await LibraryManager.UpdateItem(this, updateReason ?? ItemUpdateType.Unspecified, cancellationToken).ConfigureAwait(false); + options.ForceSave = true; } + } - return changed; + protected virtual IEnumerable<FileSystemInfo> GetFileSystemChildren() + { + var path = ContainingFolderPath; + + return new DirectoryInfo(path).EnumerateFileSystemInfos("*", SearchOption.TopDirectoryOnly); } - private async Task<bool> RefreshLocalTrailers(IHasTrailers item, CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false) + private async Task<bool> RefreshLocalTrailers(IHasTrailers item, MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - var newItems = LoadLocalTrailers().ToList(); + var newItems = LoadLocalTrailers(fileSystemChildren).ToList(); var newItemIds = newItems.Select(i => i.Id).ToList(); var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds); - var tasks = newItems.Select(i => i.RefreshMetadata(new MetadataRefreshOptions - { - ForceSave = forceSave, - ReplaceAllMetadata = forceRefresh, - ResetResolveArgs = false + var tasks = newItems.Select(i => i.RefreshMetadata(options, cancellationToken)); - }, cancellationToken)); - - var results = await Task.WhenAll(tasks).ConfigureAwait(false); + await Task.WhenAll(tasks).ConfigureAwait(false); item.LocalTrailerIds = newItemIds; - return itemsChanged || results.Contains(true); + return itemsChanged; } - private async Task<bool> RefreshThemeVideos(IHasThemeMedia item, CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false) + private async Task<bool> RefreshThemeVideos(IHasThemeMedia item, MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - var newThemeVideos = LoadThemeVideos().ToList(); + var newThemeVideos = LoadThemeVideos(fileSystemChildren).ToList(); var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToList(); var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds); - var tasks = newThemeVideos.Select(i => i.RefreshMetadata(new MetadataRefreshOptions - { - ForceSave = forceSave, - ReplaceAllMetadata = forceRefresh, - ResetResolveArgs = false - - }, cancellationToken)); + var tasks = newThemeVideos.Select(i => i.RefreshMetadata(options, cancellationToken)); - var results = await Task.WhenAll(tasks).ConfigureAwait(false); + await Task.WhenAll(tasks).ConfigureAwait(false); item.ThemeVideoIds = newThemeVideoIds; - return themeVideosChanged || results.Contains(true); + return themeVideosChanged; } /// <summary> /// Refreshes the theme songs. /// </summary> - private async Task<bool> RefreshThemeSongs(IHasThemeMedia item, CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false) + private async Task<bool> RefreshThemeSongs(IHasThemeMedia item, MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - var newThemeSongs = LoadThemeSongs().ToList(); + var newThemeSongs = LoadThemeSongs(fileSystemChildren).ToList(); var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList(); var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds); - var tasks = newThemeSongs.Select(i => i.RefreshMetadata(new MetadataRefreshOptions - { - ForceSave = forceSave, - ReplaceAllMetadata = forceRefresh, - ResetResolveArgs = false - - }, cancellationToken)); + var tasks = newThemeSongs.Select(i => i.RefreshMetadata(options, cancellationToken)); - var results = await Task.WhenAll(tasks).ConfigureAwait(false); + await Task.WhenAll(tasks).ConfigureAwait(false); item.ThemeSongIds = newThemeSongIds; - return themeSongsChanged || results.Contains(true); + return themeSongsChanged; } /// <summary> @@ -1655,27 +1434,8 @@ namespace MediaBrowser.Controller.Entities throw new ArgumentNullException("imagePath"); } - var locationType = LocationType; - - if (locationType == LocationType.Remote || - locationType == LocationType.Virtual) - { - return FileSystem.GetLastWriteTimeUtc(imagePath); - } - - var metaFileEntry = ResolveArgs.GetMetaFileByPath(imagePath); - - // If we didn't the metafile entry, check the Season - if (metaFileEntry == null) - { - if (Parent != null) - { - metaFileEntry = Parent.ResolveArgs.GetMetaFileByPath(imagePath); - } - } - // See if we can avoid a file system lookup by looking for the file in ResolveArgs - return metaFileEntry == null ? FileSystem.GetLastWriteTimeUtc(imagePath) : FileSystem.GetLastWriteTimeUtc(metaFileEntry); + return FileSystem.GetLastWriteTimeUtc(imagePath); } /// <summary> diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index 298941378e..28ccf687c6 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -29,25 +29,6 @@ namespace MediaBrowser.Controller.Entities /// <value>The preferred metadata country code.</value> public string PreferredMetadataCountryCode { get; set; } - /// <summary> - /// - /// </summary> - public override string MetaLocation - { - get - { - return System.IO.Path.GetDirectoryName(Path); - } - } - - protected override bool UseParentPathToCreateResolveArgs - { - get - { - return !IsInMixedFolder; - } - } - public Book() { Tags = new List<string>(); diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 6220bc4d51..9c6b609691 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -1,4 +1,6 @@ -using System; +using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Library; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -14,6 +16,11 @@ namespace MediaBrowser.Controller.Entities /// </summary> public class CollectionFolder : Folder, ICollectionFolder { + public CollectionFolder() + { + PhysicalLocationsList = new List<string>(); + } + /// <summary> /// Gets a value indicating whether this instance is virtual folder. /// </summary> @@ -42,6 +49,60 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override IEnumerable<string> PhysicalLocations + { + get + { + return PhysicalLocationsList; + } + } + + public List<string> PhysicalLocationsList { get; set; } + + protected override IEnumerable<FileSystemInfo> GetFileSystemChildren() + { + return CreateResolveArgs().FileSystemChildren; + } + + private ItemResolveArgs CreateResolveArgs() + { + var path = ContainingFolderPath; + + var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager) + { + FileInfo = new DirectoryInfo(path), + Path = path, + Parent = Parent + }; + + // Gather child folder and files + if (args.IsDirectory) + { + var isPhysicalRoot = args.IsPhysicalRoot; + + // When resolving the root, we need it's grandchildren (children of user views) + var flattenFolderDepth = isPhysicalRoot ? 2 : 0; + + var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf); + + // Need to remove subpaths that may have been resolved from shortcuts + // Example: if \\server\movies exists, then strip out \\server\movies\action + if (isPhysicalRoot) + { + var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Keys); + + fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName); + } + + args.FileSystemDictionary = fileSystemDictionary; + } + + PhysicalLocationsList = args.PhysicalLocations.ToList(); + + return args; + } + // Cache this since it will be used a lot /// <summary> /// The null task result @@ -59,13 +120,14 @@ namespace MediaBrowser.Controller.Entities /// <returns>Task.</returns> protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool? recursive = null, bool forceRefreshMetadata = false) { + CreateResolveArgs(); ResetDynamicChildren(); return NullTaskResult; } private List<LinkedChild> _linkedChildren; - + /// <summary> /// Our children are actually just references to the ones in the physical root... /// </summary> diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 02da2fe618..63a1c2babe 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; @@ -27,7 +28,7 @@ namespace MediaBrowser.Controller.Entities public List<Guid> ThemeSongIds { get; set; } public List<Guid> ThemeVideoIds { get; set; } - + public Folder() { LinkedChildren = new List<LinkedChild>(); @@ -379,7 +380,7 @@ namespace MediaBrowser.Controller.Entities } catch (IOException ex) { - nonCachedChildren = new BaseItem[] {}; + nonCachedChildren = new BaseItem[] { }; Logger.ErrorException("Error getting file system entries for {0}", ex, Path); } @@ -402,8 +403,6 @@ namespace MediaBrowser.Controller.Entities if (currentChildren.TryGetValue(child.Id, out currentChild)) { - currentChild.ResetResolveArgs(child.ResolveArgs); - //existing item - check if it has changed if (currentChild.HasChanged(child)) { @@ -411,7 +410,7 @@ namespace MediaBrowser.Controller.Entities if (currentChildLocationType != LocationType.Remote && currentChildLocationType != LocationType.Virtual) { - EntityResolutionHelper.EnsureDates(FileSystem, currentChild, child.ResolveArgs, false); + currentChild.DateModified = child.DateModified; } currentChild.IsInMixedFolder = child.IsInMixedFolder; @@ -539,8 +538,7 @@ namespace MediaBrowser.Controller.Entities await child.RefreshMetadata(new MetadataRefreshOptions { ForceSave = currentTuple.Item2, - ReplaceAllMetadata = forceRefreshMetadata, - ResetResolveArgs = false + ReplaceAllMetadata = forceRefreshMetadata }, cancellationToken).ConfigureAwait(false); } @@ -581,16 +579,6 @@ namespace MediaBrowser.Controller.Entities }); await ((Folder)child).ValidateChildren(innerProgress, cancellationToken, recursive, forceRefreshMetadata).ConfigureAwait(false); - - try - { - // Some folder providers are unable to refresh until children have been refreshed. - await child.RefreshMetadata(cancellationToken, resetResolveArgs: false).ConfigureAwait(false); - } - catch (IOException ex) - { - Logger.ErrorException("Error refreshing {0}", ex, child.Path ?? child.Name); - } } else { @@ -661,14 +649,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>IEnumerable{BaseItem}.</returns> protected virtual IEnumerable<BaseItem> GetNonCachedChildren() { - var resolveArgs = ResolveArgs; - - if (resolveArgs == null || resolveArgs.FileSystemDictionary == null) - { - Logger.Error("ResolveArgs null for {0}", Path); - } - - return LibraryManager.ResolvePaths<BaseItem>(resolveArgs.FileSystemChildren, this); + return LibraryManager.ResolvePaths<BaseItem>(GetFileSystemChildren(), this); } /// <summary> @@ -914,43 +895,29 @@ namespace MediaBrowser.Controller.Entities return item; } - protected override Task BeforeRefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken) + protected override Task BeforeRefreshMetadata(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { if (SupportsShortcutChildren && LocationType == LocationType.FileSystem) { - RefreshLinkedChildren(); + if (RefreshLinkedChildren(fileSystemChildren)) + { + options.ForceSave = true; + } } - return base.BeforeRefreshMetadata(options, cancellationToken); + return base.BeforeRefreshMetadata(options, fileSystemChildren, cancellationToken); } /// <summary> /// Refreshes the linked children. /// </summary> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - private bool RefreshLinkedChildren() + private bool RefreshLinkedChildren(IEnumerable<FileSystemInfo> fileSystemChildren) { - ItemResolveArgs resolveArgs; - - try - { - resolveArgs = ResolveArgs; - - if (!resolveArgs.IsDirectory) - { - return false; - } - } - catch (IOException ex) - { - Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path); - return false; - } - var currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList(); var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList(); - var newShortcutLinks = resolveArgs.FileSystemChildren + var newShortcutLinks = fileSystemChildren .Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory && FileSystem.IsShortcut(i.FullName)) .Select(i => { @@ -1058,7 +1025,7 @@ namespace MediaBrowser.Controller.Entities return this; } - if (locationType != LocationType.Virtual && ResolveArgs.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase)) + if (locationType != LocationType.Virtual && PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase)) { return this; } diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index da95b7c44e..1b51763623 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -80,17 +80,6 @@ namespace MediaBrowser.Controller.Entities public string GameSystem { get; set; } /// <summary> - /// - /// </summary> - public override string MetaLocation - { - get - { - return System.IO.Path.GetDirectoryName(Path); - } - } - - /// <summary> /// Gets or sets a value indicating whether this instance is multi part. /// </summary> /// <value><c>true</c> if this instance is multi part; otherwise, <c>false</c>.</value> @@ -101,17 +90,6 @@ namespace MediaBrowser.Controller.Entities /// </summary> public List<string> MultiPartGameFiles { get; set; } - /// <summary> - /// - /// </summary> - protected override bool UseParentPathToCreateResolveArgs - { - get - { - return !IsInMixedFolder; - } - } - public override string GetUserDataKey() { var id = this.GetProviderId(MetadataProviders.Gamesdb); diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index 1aa299c2af..51f25979cb 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -99,6 +99,12 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The backdrop image paths.</value> List<string> BackdropImagePaths { get; set; } + + /// <summary> + /// Gets a value indicating whether this instance is owned item. + /// </summary> + /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + bool IsOwnedItem { get; } } public static class HasImagesExtensions diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index a4e8853376..41a1969d65 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.Controller.Entities.Movies public List<Guid> ThemeSongIds { get; set; } public List<Guid> ThemeVideoIds { get; set; } - + /// <summary> /// Gets or sets the preferred metadata country code. /// </summary> @@ -29,7 +29,7 @@ namespace MediaBrowser.Controller.Entities.Movies public string PreferredMetadataCountryCode { get; set; } public string PreferredMetadataLanguage { get; set; } - + public Movie() { SpecialFeatureIds = new List<Guid>(); @@ -49,7 +49,7 @@ namespace MediaBrowser.Controller.Entities.Movies public List<Guid> LocalTrailerIds { get; set; } public List<string> Keywords { get; set; } - + public List<MediaUrl> RemoteTrailers { get; set; } /// <summary> @@ -103,88 +103,48 @@ namespace MediaBrowser.Controller.Entities.Movies return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey(); } - /// <summary> - /// Overrides the base implementation to refresh metadata for special features - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="forceSave">if set to <c>true</c> [is new item].</param> - /// <param name="forceRefresh">if set to <c>true</c> [force].</param> - /// <returns>Task{System.Boolean}.</returns> - public override async Task<bool> RefreshMetadataDirect(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false) + protected override async Task BeforeRefreshMetadata(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - // Kick off a task to refresh the main item - var result = await base.RefreshMetadataDirect(cancellationToken, forceSave, forceRefresh).ConfigureAwait(false); - - var specialFeaturesChanged = false; + await base.BeforeRefreshMetadata(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); // Must have a parent to have special features // In other words, it must be part of the Parent/Child tree if (LocationType == LocationType.FileSystem && Parent != null && !IsInMixedFolder) { - specialFeaturesChanged = await RefreshSpecialFeatures(cancellationToken, forceSave, forceRefresh).ConfigureAwait(false); - } + var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); - return specialFeaturesChanged || result; + if (specialFeaturesChanged) + { + options.ForceSave = true; + } + } } - private async Task<bool> RefreshSpecialFeatures(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true) + private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - var newItems = LoadSpecialFeatures().ToList(); + var newItems = LoadSpecialFeatures(fileSystemChildren).ToList(); var newItemIds = newItems.Select(i => i.Id).ToList(); var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds); - var tasks = newItems.Select(i => i.RefreshMetadata(new MetadataRefreshOptions - { - ForceSave = forceSave, - ReplaceAllMetadata = forceRefresh, - ResetResolveArgs = false - - }, cancellationToken)); + var tasks = newItems.Select(i => i.RefreshMetadata(options, cancellationToken)); - var results = await Task.WhenAll(tasks).ConfigureAwait(false); + await Task.WhenAll(tasks).ConfigureAwait(false); SpecialFeatureIds = newItemIds; - return itemsChanged || results.Contains(true); + return itemsChanged; } /// <summary> /// Loads the special features. /// </summary> /// <returns>IEnumerable{Video}.</returns> - private IEnumerable<Video> LoadSpecialFeatures() + private IEnumerable<Video> LoadSpecialFeatures(IEnumerable<FileSystemInfo> fileSystemChildren) { - FileSystemInfo folder; - - try - { - folder = ResolveArgs.GetFileSystemEntryByName("extras") ?? - ResolveArgs.GetFileSystemEntryByName("specials"); - } - catch (IOException ex) - { - Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path); - return new List<Video>(); - } - - // Path doesn't exist. No biggie - if (folder == null) - { - return new List<Video>(); - } - - IEnumerable<FileSystemInfo> files; - - try - { - files = new DirectoryInfo(folder.FullName).EnumerateFiles(); - } - catch (IOException ex) - { - Logger.ErrorException("Error loading special features for {0}", ex, Name); - return new List<Video>(); - } + var files = fileSystemChildren.OfType<DirectoryInfo>() + .Where(i => string.Equals(i.Name, "extras", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "specials", StringComparison.OrdinalIgnoreCase)) + .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)); return LibraryManager.ResolvePaths<Video>(files, null).Select(video => { @@ -193,7 +153,6 @@ namespace MediaBrowser.Controller.Entities.Movies if (dbItem != null) { - dbItem.ResetResolveArgs(video.ResolveArgs); video = dbItem; } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 3bdfc3c444..73726a4e28 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -12,28 +12,6 @@ namespace MediaBrowser.Controller.Entities.TV public class Episode : Video { /// <summary> - /// Episodes have a special Metadata folder - /// </summary> - /// <value>The meta location.</value> - [IgnoreDataMember] - public override string MetaLocation - { - get - { - return System.IO.Path.Combine(Parent.Path, "metadata"); - } - } - - [IgnoreDataMember] - protected override bool UseParentPathToCreateResolveArgs - { - get - { - return false; - } - } - - /// <summary> /// Gets the season in which it aired. /// </summary> /// <value>The aired season.</value> diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 2d781118eb..7444165603 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -132,34 +132,6 @@ namespace MediaBrowser.Controller.Entities.TV } /// <summary> - /// Add files from the metadata folder to ResolveArgs - /// </summary> - /// <param name="args">The args.</param> - public static void AddMetadataFiles(ItemResolveArgs args) - { - var folder = args.GetFileSystemEntryByName("metadata"); - - if (folder != null) - { - args.AddMetadataFiles(new DirectoryInfo(folder.FullName).EnumerateFiles()); - } - } - - /// <summary> - /// Creates ResolveArgs on demand - /// </summary> - /// <param name="pathInfo">The path info.</param> - /// <returns>ItemResolveArgs.</returns> - protected internal override ItemResolveArgs CreateResolveArgs(FileSystemInfo pathInfo = null) - { - var args = base.CreateResolveArgs(pathInfo); - - AddMetadataFiles(args); - - return args; - } - - /// <summary> /// Creates the name of the sort. /// </summary> /// <returns>System.String.</returns> diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 552a517de5..efb3c393b1 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -111,20 +111,6 @@ namespace MediaBrowser.Controller.Entities.TV }; } - /// <summary> - /// Creates ResolveArgs on demand - /// </summary> - /// <param name="pathInfo">The path info.</param> - /// <returns>ItemResolveArgs.</returns> - protected internal override ItemResolveArgs CreateResolveArgs(FileSystemInfo pathInfo = null) - { - var args = base.CreateResolveArgs(pathInfo); - - Season.AddMetadataFiles(args); - - return args; - } - [IgnoreDataMember] public bool ContainsEpisodesWithoutSeasonFolders { diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index f429a26771..d6d1934422 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -89,33 +89,6 @@ namespace MediaBrowser.Controller.Entities } } - /// <summary> - /// Should be overridden to return the proper folder where metadata lives - /// </summary> - /// <value>The meta location.</value> - [IgnoreDataMember] - public override string MetaLocation - { - get - { - if (!IsLocalTrailer) - { - return System.IO.Path.GetDirectoryName(Path); - } - - return base.MetaLocation; - } - } - - /// <summary> - /// Needed because the resolver stops at the trailer folder and we find the video inside. - /// </summary> - /// <value><c>true</c> if [use parent path to create resolve args]; otherwise, <c>false</c>.</value> - protected override bool UseParentPathToCreateResolveArgs - { - get { return !IsLocalTrailer; } - } - public override string GetUserDataKey() { var key = this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? this.GetProviderId(MetadataProviders.Tvcom); diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 9c94667669..de78068b38 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -84,33 +84,23 @@ namespace MediaBrowser.Controller.Entities /// <value>The aspect ratio.</value> public string AspectRatio { get; set; } - /// <summary> - /// Should be overridden to return the proper folder where metadata lives - /// </summary> - /// <value>The meta location.</value> [IgnoreDataMember] - public override string MetaLocation + public override string ContainingFolderPath { get { - return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso || IsMultiPart ? System.IO.Path.GetDirectoryName(Path) : Path; - } - } + if (IsMultiPart) + { + return System.IO.Path.GetDirectoryName(Path); + } - /// <summary> - /// Needed because the resolver stops at the movie folder and we find the video inside. - /// </summary> - /// <value><c>true</c> if [use parent path to create resolve args]; otherwise, <c>false</c>.</value> - protected override bool UseParentPathToCreateResolveArgs - { - get - { - if (IsInMixedFolder) + if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd || + VideoType == VideoType.HdDvd) { - return false; + return Path; } - return VideoType == VideoType.VideoFile || VideoType == VideoType.Iso || IsMultiPart; + return base.ContainingFolderPath; } } @@ -159,106 +149,73 @@ namespace MediaBrowser.Controller.Entities } } - /// <summary> - /// Overrides the base implementation to refresh metadata for local trailers - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="forceSave">if set to <c>true</c> [is new item].</param> - /// <param name="forceRefresh">if set to <c>true</c> [force].</param> - /// <returns>true if a provider reports we changed</returns> - public override async Task<bool> RefreshMetadataDirect(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false) + protected override async Task BeforeRefreshMetadata(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - // Kick off a task to refresh the main item - var result = await base.RefreshMetadataDirect(cancellationToken, forceSave, forceRefresh).ConfigureAwait(false); - - var additionalPartsChanged = false; + await base.BeforeRefreshMetadata(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); // Must have a parent to have additional parts // In other words, it must be part of the Parent/Child tree // The additional parts won't have additional parts themselves if (IsMultiPart && LocationType == LocationType.FileSystem && Parent != null) { - try - { - additionalPartsChanged = await RefreshAdditionalParts(cancellationToken, forceSave, forceRefresh).ConfigureAwait(false); - } - catch (IOException ex) + var additionalPartsChanged = await RefreshAdditionalParts(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + + if (additionalPartsChanged) { - Logger.ErrorException("Error loading additional parts for {0}.", ex, Name); + options.ForceSave = true; } } - - return additionalPartsChanged || result; } /// <summary> /// Refreshes the additional parts. /// </summary> + /// <param name="options">The options.</param> + /// <param name="fileSystemChildren">The file system children.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="forceSave">if set to <c>true</c> [force save].</param> - /// <param name="forceRefresh">if set to <c>true</c> [force refresh].</param> - /// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param> /// <returns>Task{System.Boolean}.</returns> - private async Task<bool> RefreshAdditionalParts(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true) + private async Task<bool> RefreshAdditionalParts(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - var newItems = LoadAdditionalParts().ToList(); + var newItems = LoadAdditionalParts(fileSystemChildren).ToList(); var newItemIds = newItems.Select(i => i.Id).ToList(); var itemsChanged = !AdditionalPartIds.SequenceEqual(newItemIds); - var tasks = newItems.Select(i => i.RefreshMetadata(new MetadataRefreshOptions - { - ForceSave = forceSave, - ReplaceAllMetadata = forceRefresh + var tasks = newItems.Select(i => i.RefreshMetadata(options, cancellationToken)); - }, cancellationToken)); - - var results = await Task.WhenAll(tasks).ConfigureAwait(false); + await Task.WhenAll(tasks).ConfigureAwait(false); AdditionalPartIds = newItemIds; - return itemsChanged || results.Contains(true); + return itemsChanged; } /// <summary> /// Loads the additional parts. /// </summary> /// <returns>IEnumerable{Video}.</returns> - private IEnumerable<Video> LoadAdditionalParts() + private IEnumerable<Video> LoadAdditionalParts(IEnumerable<FileSystemInfo> fileSystemChildren) { IEnumerable<FileSystemInfo> files; var path = Path; - if (string.IsNullOrEmpty(path)) - { - throw new ApplicationException(string.Format("Item {0} has a null path.", Name ?? Id.ToString())); - } - if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd) { - var parentPath = System.IO.Path.GetDirectoryName(path); - - if (string.IsNullOrEmpty(parentPath)) + files = fileSystemChildren.Where(i => { - throw new IOException("Unable to get parent path info from " + path); - } + if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory) + { + return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsVideoFile(i.FullName) && EntityResolutionHelper.IsMultiPartFile(i.Name); + } - files = new DirectoryInfo(parentPath) - .EnumerateDirectories() - .Where(i => !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsMultiPartFile(i.Name)); + return false; + }); } else { - var resolveArgs = ResolveArgs; - - if (resolveArgs == null) - { - throw new IOException("ResolveArgs are null for " + path); - } - - files = resolveArgs.FileSystemChildren.Where(i => + files = fileSystemChildren.Where(i => { if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory) { @@ -276,7 +233,6 @@ namespace MediaBrowser.Controller.Entities if (dbItem != null) { - dbItem.ResetResolveArgs(video.ResolveArgs); video = dbItem; } |
