diff options
10 files changed, 174 insertions, 19 deletions
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index 22212d287..35411935b 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -337,6 +337,28 @@ namespace MediaBrowser.Api.UserLibrary } /// <summary> + /// Class GetVideoBackdrops + /// </summary> + [Route("/Users/{UserId}/Items/{Id}/VideoBackdrops", "GET")] + [Api(Description = "Gets video backdrops for an item")] + public class GetVideoBackdrops : IReturn<VideoBackdropsResult> + { + /// <summary> + /// Gets or sets the user id. + /// </summary> + /// <value>The user id.</value> + [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public Guid UserId { get; set; } + + /// <summary> + /// Gets or sets the id. + /// </summary> + /// <value>The id.</value> + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } + + /// <summary> /// Class GetSpecialFeatures /// </summary> [Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET")] @@ -469,6 +491,34 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> /// <param name="request">The request.</param> /// <returns>System.Object.</returns> + public object Get(GetVideoBackdrops request) + { + var user = _userManager.GetUserById(request.UserId); + + var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id); + + // Get everything + var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); + + var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository); + + var items = item.VideoBackdrops.Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).AsParallel().Select(t => t.Result).ToArray(); + + var result = new VideoBackdropsResult + { + Items = items, + TotalRecordCount = items.Length, + OwnerId = DtoBuilder.GetClientItemId(item) + }; + + return ToOptimizedResult(result); + } + + /// <summary> + /// Gets the specified request. + /// </summary> + /// <param name="request">The request.</param> + /// <returns>System.Object.</returns> public object Get(GetItem request) { var user = _userManager.GetUserById(request.UserId); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index eca0ea462..8da67cb69 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -39,6 +39,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> public const string TrailerFolderName = "trailers"; public const string ThemeSongsFolderName = "theme-music"; + public const string VideoBackdropsFolderName = "backdrops"; /// <summary> /// Gets or sets the name. @@ -702,6 +703,28 @@ namespace MediaBrowser.Controller.Entities } } + private List<Video> _videoBackdrops; + private bool _videoBackdropsInitialized; + private object _videoBackdropsSyncLock = new object(); + [IgnoreDataMember] + public List<Video> VideoBackdrops + { + get + { + LazyInitializer.EnsureInitialized(ref _videoBackdrops, ref _videoBackdropsInitialized, ref _videoBackdropsSyncLock, LoadVideoBackdrops); + return _videoBackdrops; + } + private set + { + _videoBackdrops = value; + + if (value == null) + { + _videoBackdropsInitialized = false; + } + } + } + /// <summary> /// Loads local trailers from the file system /// </summary> @@ -819,6 +842,64 @@ namespace MediaBrowser.Controller.Entities } /// <summary> + /// Loads the video backdrops. + /// </summary> + /// <returns>List{Video}.</returns> + private List<Video> LoadVideoBackdrops() + { + ItemResolveArgs resolveArgs; + + try + { + resolveArgs = ResolveArgs; + } + catch (IOException ex) + { + Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path); + return new List<Video>(); + } + + if (!resolveArgs.IsDirectory) + { + return new List<Video>(); + } + + var folder = resolveArgs.GetFileSystemEntryByName(VideoBackdropsFolderName); + + // 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>(); + } + + return LibraryManager.ResolvePaths<Video>(files, null).Select(item => + { + // Try to retrieve it from the db. If we don't find it, use the resolved version + var dbItem = LibraryManager.RetrieveItem(item.Id) as Video; + + if (dbItem != null) + { + dbItem.ResolveArgs = item.ResolveArgs; + item = dbItem; + } + + return item; + }).ToList(); + } + + /// <summary> /// Overrides the base implementation to refresh metadata for local trailers /// </summary> /// <param name="cancellationToken">The cancellation token.</param> @@ -837,6 +918,7 @@ namespace MediaBrowser.Controller.Entities // Lazy load these again LocalTrailers = null; ThemeSongs = null; + VideoBackdrops = null; // Refresh for the item var itemRefreshTask = ProviderManager.ExecuteMetadataProviders(this, cancellationToken, forceRefresh, allowSlowProviders); @@ -847,12 +929,15 @@ namespace MediaBrowser.Controller.Entities var trailerTasks = LocalTrailers.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders)); var themeSongTasks = ThemeSongs.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders)); + + var videoBackdropTasks = VideoBackdrops.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders)); cancellationToken.ThrowIfCancellationRequested(); // Await the trailer tasks await Task.WhenAll(trailerTasks).ConfigureAwait(false); await Task.WhenAll(themeSongTasks).ConfigureAwait(false); + await Task.WhenAll(videoBackdropTasks).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); diff --git a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs index ec99a78a7..1d4d811b6 100644 --- a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs @@ -51,7 +51,7 @@ namespace MediaBrowser.Controller.Providers.Music /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> public override bool Supports(BaseItem item) { - return item is MusicArtist; + return false; } protected virtual bool SaveLocalMeta diff --git a/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs index df490f5b6..a3fad6e8a 100644 --- a/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs +++ b/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs @@ -55,13 +55,6 @@ namespace MediaBrowser.Controller.Providers.Music private async Task<LastfmGetAlbumResult> GetAlbumResult(BaseItem item, CancellationToken cancellationToken) { - var result = await GetAlbumResult(item.Parent.Name, item.Name, cancellationToken); - - if (result != null && result.album != null) - { - return result; - } - var folder = (Folder)item; // Get each song, distinct by the combination of AlbumArtist and Album @@ -69,7 +62,7 @@ namespace MediaBrowser.Controller.Providers.Music foreach (var song in songs.Where(song => !string.IsNullOrEmpty(song.Album) && !string.IsNullOrEmpty(song.AlbumArtist))) { - result = await GetAlbumResult(song.AlbumArtist, song.Album, cancellationToken).ConfigureAwait(false); + var result = await GetAlbumResult(song.AlbumArtist, song.Album, cancellationToken).ConfigureAwait(false); if (result != null && result.album != null) { @@ -77,7 +70,8 @@ namespace MediaBrowser.Controller.Providers.Music } } - return null; + // Try the folder name + return await GetAlbumResult(item.Parent.Name, item.Name, cancellationToken); } private async Task<LastfmGetAlbumResult> GetAlbumResult(string artist, string album, CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs index c846fcd97..8fabf2368 100644 --- a/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs +++ b/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs @@ -90,7 +90,7 @@ namespace MediaBrowser.Controller.Providers.Music public override bool Supports(BaseItem item) { - return item is MusicArtist; + return false; } } } diff --git a/MediaBrowser.Controller/Providers/Music/MusicArtistProviderFromJson.cs b/MediaBrowser.Controller/Providers/Music/MusicArtistProviderFromJson.cs index fe64c66b3..e3df46ed2 100644 --- a/MediaBrowser.Controller/Providers/Music/MusicArtistProviderFromJson.cs +++ b/MediaBrowser.Controller/Providers/Music/MusicArtistProviderFromJson.cs @@ -62,7 +62,7 @@ namespace MediaBrowser.Controller.Providers.Music public override bool Supports(BaseItem item) { - return item is MusicArtist; + return false; } public override bool RequiresInternet diff --git a/MediaBrowser.Model/Querying/ThemeSongsResult.cs b/MediaBrowser.Model/Querying/ThemeSongsResult.cs index d1319f6e1..f3a9f7a80 100644 --- a/MediaBrowser.Model/Querying/ThemeSongsResult.cs +++ b/MediaBrowser.Model/Querying/ThemeSongsResult.cs @@ -13,4 +13,13 @@ namespace MediaBrowser.Model.Querying /// <value>The owner id.</value> public string OwnerId { get; set; } } + + public class VideoBackdropsResult : ItemsResult + { + /// <summary> + /// Gets or sets the owner id. + /// </summary> + /// <value>The owner id.</value> + public string OwnerId { get; set; } + } } diff --git a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index cb49dd1e6..c6beef957 100644 --- a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -39,10 +39,12 @@ namespace MediaBrowser.Server.Implementations.Library { var parentFolderName = Path.GetFileName(Path.GetDirectoryName(args.Path)); - if (!string.Equals(parentFolderName, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(parentFolderName, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase) || string.Equals(parentFolderName, BaseItem.VideoBackdropsFolderName, StringComparison.OrdinalIgnoreCase)) { - return true; + return false; } + + return true; } if (args.IsDirectory) @@ -60,6 +62,11 @@ namespace MediaBrowser.Server.Implementations.Library return true; } + if (string.Equals(filename, BaseItem.VideoBackdropsFolderName, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + if (string.Equals(filename, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase)) { return true; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index ceb4f90cf..4323c3467 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -275,10 +275,12 @@ namespace MediaBrowser.Server.Implementations.Library var specialFeatures = items.OfType<Movie>().SelectMany(i => i.SpecialFeatures).ToList(); var localTrailers = items.SelectMany(i => i.LocalTrailers).ToList(); var themeSongs = items.SelectMany(i => i.ThemeSongs).ToList(); + var videoBackdrops = items.SelectMany(i => i.ThemeSongs).ToList(); items.AddRange(specialFeatures); items.AddRange(localTrailers); items.AddRange(themeSongs); + items.AddRange(videoBackdrops); // Need to use DistinctBy Id because there could be multiple instances with the same id // due to sharing the default library @@ -330,15 +332,22 @@ namespace MediaBrowser.Server.Implementations.Library foreach (var subItem in item.LocalTrailers) { // Prevent access to foreach variable in closure - var trailer1 = subItem; - LibraryItemsCache.AddOrUpdate(subItem.Id, subItem, delegate { return trailer1; }); + var copy = subItem; + LibraryItemsCache.AddOrUpdate(subItem.Id, subItem, delegate { return copy; }); } foreach (var subItem in item.ThemeSongs) { // Prevent access to foreach variable in closure - var trailer1 = subItem; - LibraryItemsCache.AddOrUpdate(subItem.Id, subItem, delegate { return trailer1; }); + var copy = subItem; + LibraryItemsCache.AddOrUpdate(subItem.Id, subItem, delegate { return copy; }); + } + + foreach (var subItem in item.VideoBackdrops) + { + // Prevent access to foreach variable in closure + var copy = subItem; + LibraryItemsCache.AddOrUpdate(subItem.Id, subItem, delegate { return copy; }); } var movie = item as Movie; diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs index ffb967fc1..8a7f596af 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; +using System.IO; using System.Linq; namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio @@ -33,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio if (args.Parent.IsRoot) return null; // If we contain an album assume we are an artist folder - return args.FileSystemChildren.Any(i => MusicAlbumResolver.IsMusicAlbum(i.FullName)) ? new MusicArtist() : null; + return args.FileSystemChildren.Where(i => i.Attributes.HasFlag(FileAttributes.Directory)).Any(i => MusicAlbumResolver.IsMusicAlbum(i.FullName)) ? new MusicArtist() : null; } } |
