diff options
20 files changed, 233 insertions, 38 deletions
diff --git a/MediaBrowser.Api/Library/LibraryHelpers.cs b/MediaBrowser.Api/Library/LibraryHelpers.cs index ab7449273..72cff4560 100644 --- a/MediaBrowser.Api/Library/LibraryHelpers.cs +++ b/MediaBrowser.Api/Library/LibraryHelpers.cs @@ -16,10 +16,11 @@ namespace MediaBrowser.Api.Library /// Adds the virtual folder. /// </summary> /// <param name="name">The name.</param> + /// <param name="collectionType">Type of the collection.</param> /// <param name="user">The user.</param> /// <param name="appPaths">The app paths.</param> /// <exception cref="System.ArgumentException">There is already a media collection with the name + name + .</exception> - public static void AddVirtualFolder(string name, User user, IServerApplicationPaths appPaths) + public static void AddVirtualFolder(string name, string collectionType, User user, IServerApplicationPaths appPaths) { name = FileSystem.GetValidFilename(name); @@ -32,6 +33,13 @@ namespace MediaBrowser.Api.Library } Directory.CreateDirectory(virtualFolderPath); + + if (!string.IsNullOrEmpty(collectionType)) + { + var path = Path.Combine(virtualFolderPath, collectionType + ".collection"); + + File.Create(path); + } } /// <summary> diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index 88fc8b0af..91018168b 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -38,6 +38,12 @@ namespace MediaBrowser.Api.Library /// </summary> /// <value>The name.</value> public string Name { get; set; } + + /// <summary> + /// Gets or sets the type of the collection. + /// </summary> + /// <value>The type of the collection.</value> + public string CollectionType { get; set; } } [Route("/Library/VirtualFolders/{Name}", "DELETE")] @@ -196,13 +202,13 @@ namespace MediaBrowser.Api.Library { if (string.IsNullOrEmpty(request.UserId)) { - LibraryHelpers.AddVirtualFolder(request.Name, null, _appPaths); + LibraryHelpers.AddVirtualFolder(request.Name, request.CollectionType, null, _appPaths); } else { var user = _userManager.GetUserById(new Guid(request.UserId)); - LibraryHelpers.AddVirtualFolder(request.Name, user, _appPaths); + LibraryHelpers.AddVirtualFolder(request.Name, request.CollectionType, user, _appPaths); } _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None); diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs index 7a027a052..f65de2e69 100644 --- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs +++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs @@ -125,15 +125,35 @@ namespace MediaBrowser.Api.UserLibrary { var name = DeSlugArtistName(request.Name, LibraryManager); - var items = GetItems(request.UserId).OfType<Audio>().Where(i => i.HasArtist(name)).ToList(); + var items = GetItems(request.UserId).Where(i => + { + var song = i as Audio; + + if (song != null) + { + return song.HasArtist(name); + } + + var musicVideo = i as MusicVideo; + + if (musicVideo != null) + { + return musicVideo.HasArtist(name); + } + + return false; + + }).ToList(); var counts = new ItemByNameCounts { TotalCount = items.Count, - SongCount = items.Count(), + SongCount = items.OfType<Audio>().Count(), + + AlbumCount = items.Select(i => i.Parent).OfType<MusicAlbum>().Distinct().Count(), - AlbumCount = items.Select(i => i.Parent).OfType<MusicAlbum>().Distinct().Count() + MusicVideoCount = items.OfType<MusicVideo>().Count(i => i.HasArtist(name)) }; return ToOptimizedResult(counts); diff --git a/MediaBrowser.Controller/Dto/DtoBuilder.cs b/MediaBrowser.Controller/Dto/DtoBuilder.cs index 7167447e4..85484d161 100644 --- a/MediaBrowser.Controller/Dto/DtoBuilder.cs +++ b/MediaBrowser.Controller/Dto/DtoBuilder.cs @@ -548,6 +548,19 @@ namespace MediaBrowser.Controller.Dto { SetGameProperties(dto, game); } + + var musicVideo = item as MusicVideo; + + if (musicVideo != null) + { + SetMusicVideoProperties(dto, musicVideo); + } + } + + private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item) + { + dto.Album = item.Album; + dto.Artists = string.IsNullOrEmpty(item.Artist) ? new string[] { } : new[] { item.Artist }; } private void SetGameProperties(BaseItemDto dto, Game item) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 154765325..c89a7f0b2 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -336,7 +336,7 @@ namespace MediaBrowser.Controller.Entities // When resolving the root, we need it's grandchildren (children of user views) var flattenFolderDepth = isPhysicalRoot ? 2 : 0; - args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, Logger, flattenFolderDepth: flattenFolderDepth, args: args, resolveShortcuts: isPhysicalRoot || args.IsVf); + args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, 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 @@ -1111,6 +1111,24 @@ namespace MediaBrowser.Controller.Entities throw new ArgumentNullException(); } + // Normalize + if (string.Equals(person.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase)) + { + person.Type = PersonType.GuestStar; + } + else if (string.Equals(person.Role, PersonType.Director, StringComparison.OrdinalIgnoreCase)) + { + person.Type = PersonType.Director; + } + else if (string.Equals(person.Role, PersonType.Producer, StringComparison.OrdinalIgnoreCase)) + { + person.Type = PersonType.Producer; + } + else if (string.Equals(person.Role, PersonType.Writer, StringComparison.OrdinalIgnoreCase)) + { + person.Type = PersonType.Writer; + } + // If the type is GuestStar and there's already an Actor entry, then update it to avoid dupes if (string.Equals(person.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index fa285a85f..507b6df8a 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -1,4 +1,5 @@ -using System; +using MediaBrowser.Controller.Library; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; @@ -6,7 +7,6 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Controller.Library; namespace MediaBrowser.Controller.Entities { @@ -29,6 +29,8 @@ namespace MediaBrowser.Controller.Entities } } + public string CollectionType { get; set; } + /// <summary> /// Allow different display preferences for each collection folder /// </summary> @@ -69,7 +71,7 @@ namespace MediaBrowser.Controller.Entities /// Our children are actually just references to the ones in the physical root... /// </summary> /// <value>The actual children.</value> - protected override ConcurrentDictionary<Guid,BaseItem> ActualChildren + protected override ConcurrentDictionary<Guid, BaseItem> ActualChildren { get { @@ -91,7 +93,7 @@ namespace MediaBrowser.Controller.Entities .Where(i => i.Path != null && resolveArgs.PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase)) .SelectMany(c => c.Children); - return new ConcurrentDictionary<Guid,BaseItem>(ourChildren.ToDictionary(i => i.Id)); + return new ConcurrentDictionary<Guid, BaseItem>(ourChildren.ToDictionary(i => i.Id)); } } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 77500808c..e46ec8d3b 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1,5 +1,4 @@ -using System.Collections; -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; @@ -8,6 +7,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; using System; +using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs index 306de1e3c..c1ca5336b 100644 --- a/MediaBrowser.Controller/IO/FileData.cs +++ b/MediaBrowser.Controller/IO/FileData.cs @@ -17,18 +17,22 @@ namespace MediaBrowser.Controller.IO /// </summary> /// <param name="path">The path.</param> /// <param name="logger">The logger.</param> + /// <param name="args">The args.</param> /// <param name="searchPattern">The search pattern.</param> /// <param name="flattenFolderDepth">The flatten folder depth.</param> /// <param name="resolveShortcuts">if set to <c>true</c> [resolve shortcuts].</param> - /// <param name="args">The args.</param> /// <returns>Dictionary{System.StringFileSystemInfo}.</returns> /// <exception cref="System.ArgumentNullException">path</exception> - public static Dictionary<string, FileSystemInfo> GetFilteredFileSystemEntries(string path, ILogger logger, string searchPattern = "*", int flattenFolderDepth = 0, bool resolveShortcuts = true, ItemResolveArgs args = null) + public static Dictionary<string, FileSystemInfo> GetFilteredFileSystemEntries(string path, ILogger logger, ItemResolveArgs args, string searchPattern = "*", int flattenFolderDepth = 0, bool resolveShortcuts = true) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } + if (args == null) + { + throw new ArgumentNullException("args"); + } var entries = new DirectoryInfo(path).EnumerateFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly); @@ -60,16 +64,13 @@ namespace MediaBrowser.Controller.IO var data = new DirectoryInfo(newPath); // add to our physical locations - if (args != null) - { - args.AddAdditionalLocation(newPath); - } + args.AddAdditionalLocation(newPath); dict[newPath] = data; } else if (flattenFolderDepth > 0 && isDirectory) { - foreach (var child in GetFilteredFileSystemEntries(fullName, logger, flattenFolderDepth: flattenFolderDepth - 1, resolveShortcuts: resolveShortcuts)) + foreach (var child in GetFilteredFileSystemEntries(fullName, logger, args, flattenFolderDepth: flattenFolderDepth - 1, resolveShortcuts: resolveShortcuts)) { dict[child.Key] = child.Value; } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index ddfec703c..f4165a630 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -254,5 +254,12 @@ namespace MediaBrowser.Controller.Library /// </summary> /// <param name="item">The item.</param> void ReportItemRemoved(BaseItem item); + + /// <summary> + /// Finds the type of the collection. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>System.String.</returns> + string FindCollectionType(BaseItem item); } }
\ No newline at end of file diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index 9c4a0f364..cf5225cae 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -162,6 +162,13 @@ namespace MediaBrowser.Model.ApiClient Task<ItemsResult> GetSimilarMoviesAsync(SimilarItemsQuery query); /// <summary> + /// Gets the similar trailers async. + /// </summary> + /// <param name="query">The query.</param> + /// <returns>Task{ItemsResult}.</returns> + Task<ItemsResult> GetSimilarTrailersAsync(SimilarItemsQuery query); + + /// <summary> /// Gets the similar series async. /// </summary> /// <param name="query">The query.</param> diff --git a/MediaBrowser.Model/Entities/CollectionType.cs b/MediaBrowser.Model/Entities/CollectionType.cs new file mode 100644 index 000000000..6d3a73aae --- /dev/null +++ b/MediaBrowser.Model/Entities/CollectionType.cs @@ -0,0 +1,20 @@ + +namespace MediaBrowser.Model.Entities +{ + public static class CollectionType + { + public const string Movies = "movies"; + + public const string TvShows = "tvshows"; + + public const string Music = "music"; + + public const string MusicVideos = "musicvideos"; + + public const string Trailers = "trailers"; + + public const string HomeVideos = "homevideos"; + + public const string BoxSets = "boxsets"; + } +} diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs index c322b7958..d440f97bd 100644 --- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs +++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs @@ -20,6 +20,12 @@ namespace MediaBrowser.Model.Entities public List<string> Locations { get; set; } /// <summary> + /// Gets or sets the type of the collection. + /// </summary> + /// <value>The type of the collection.</value> + public string CollectionType { get; set; } + + /// <summary> /// Initializes a new instance of the <see cref="VirtualFolderInfo"/> class. /// </summary> public VirtualFolderInfo() diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index f00bcdcae..7d820b036 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -53,6 +53,7 @@ <Compile Include="Dto\ItemByNameCounts.cs" /> <Compile Include="Dto\ItemCounts.cs" /> <Compile Include="Dto\StudioDto.cs" /> + <Compile Include="Entities\CollectionType.cs" /> <Compile Include="Entities\ItemReview.cs" /> <Compile Include="Entities\MediaUrl.cs" /> <Compile Include="Entities\MetadataFields.cs" /> diff --git a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs index 335851e28..66eeeed9e 100644 --- a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs @@ -102,7 +102,9 @@ namespace MediaBrowser.Providers.Savers XmlSaverHelpers.Save(builder, xmlFilePath, new[] { "IMDBrating", - "Description" + "Description", + "Artist", + "Album" }); // Set last refreshed so that the provider doesn't trigger after the file save diff --git a/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs b/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs index 5feb7b4b6..74186151e 100644 --- a/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs +++ b/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs @@ -64,7 +64,7 @@ namespace MediaBrowser.Server.Implementations.IO public async void RemoveTempIgnore(string path) { // This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called. - await Task.Delay(500).ConfigureAwait(false); + await Task.Delay(1000).ConfigureAwait(false); string val; _tempIgnoredPaths.TryRemove(path, out val); diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 810f54c26..c9fb95c86 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -487,7 +487,7 @@ namespace MediaBrowser.Server.Implementations.Library // When resolving the root, we need it's grandchildren (children of user views) var flattenFolderDepth = isPhysicalRoot ? 2 : 0; - args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, _logger, flattenFolderDepth: flattenFolderDepth, args: args, resolveShortcuts: isPhysicalRoot || args.IsVf); + args.FileSystemDictionary = FileData.GetFilteredFileSystemEntries(args.Path, _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 @@ -1168,10 +1168,23 @@ namespace MediaBrowser.Server.Implementations.Library .Select(dir => new VirtualFolderInfo { Name = Path.GetFileName(dir), - Locations = Directory.EnumerateFiles(dir, "*.lnk", SearchOption.TopDirectoryOnly).Select(FileSystem.ResolveShortcut).OrderBy(i => i).ToList() + + Locations = Directory.EnumerateFiles(dir, "*.lnk", SearchOption.TopDirectoryOnly) + .Select(FileSystem.ResolveShortcut) + .OrderBy(i => i) + .ToList(), + + CollectionType = GetCollectionType(dir) }); } + private string GetCollectionType(string path) + { + return new DirectoryInfo(path).EnumerateFiles("*.collection", SearchOption.TopDirectoryOnly) + .Select(i => Path.GetFileNameWithoutExtension(i.FullName)) + .FirstOrDefault(); + } + /// <summary> /// Gets the item by id. /// </summary> @@ -1405,5 +1418,47 @@ namespace MediaBrowser.Server.Implementations.Library } } } + + /// <summary> + /// Finds the type of the collection. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>System.String.</returns> + public string FindCollectionType(BaseItem item) + { + while (!(item.Parent is AggregateFolder) && item.Parent != null) + { + item = item.Parent; + } + + if (item == null) + { + return null; + } + + var collectionTypes = _userManager.Users + .Select(i => i.RootFolder) + .Distinct() + .SelectMany(i => i.Children) + .OfType<CollectionFolder>() + .Where(i => + { + try + { + return i.LocationType != LocationType.Remote && i.LocationType != LocationType.Virtual && + i.ResolveArgs.PhysicalLocations.Contains(item.Path); + } + catch (IOException ex) + { + _logger.ErrorException("Error getting resolve args for {0}", ex, i.Path); + return false; + } + }) + .Select(i => i.CollectionType) + .Where(i => !string.IsNullOrEmpty(i)) + .Distinct(); + + return collectionTypes.SingleOrDefault(); + } } } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs index ebe36c16e..2b498f32f 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs @@ -1,6 +1,9 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; +using System; +using System.IO; +using System.Linq; namespace MediaBrowser.Server.Implementations.Library.Resolvers { @@ -37,7 +40,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers } if (args.IsVf) { - return new CollectionFolder(); + return new CollectionFolder + { + CollectionType = GetCollectionType(args) + }; } return new Folder(); @@ -45,6 +51,14 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers return null; } + + private string GetCollectionType(ItemResolveArgs args) + { + return args.FileSystemChildren + .Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory && string.Equals(".collection", i.Extension, StringComparison.OrdinalIgnoreCase)) + .Select(i => Path.GetFileNameWithoutExtension(i.FullName)) + .FirstOrDefault(); + } } /// <summary> diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index f65e2a39a..278805069 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -18,10 +18,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies public class MovieResolver : BaseVideoResolver<Video> { private IServerApplicationPaths ApplicationPaths { get; set; } + private readonly ILibraryManager _libraryManager; - public MovieResolver(IServerApplicationPaths appPaths) + public MovieResolver(IServerApplicationPaths appPaths, ILibraryManager libraryManager) { ApplicationPaths = appPaths; + _libraryManager = libraryManager; } /// <summary> @@ -73,19 +75,27 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies return null; } - // A shortcut to help us resolve faster in some cases - var isKnownMovie = args.ContainsMetaFileByName("movie.xml"); + var collectionType = args.Parent == null ? null : _libraryManager.FindCollectionType(args.Parent); - if (args.Path.IndexOf("[trailers]", StringComparison.OrdinalIgnoreCase) != -1) + if (args.Path.IndexOf("[trailers]", StringComparison.OrdinalIgnoreCase) != -1 || + string.Equals(collectionType, CollectionType.Trailers, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Trailer>(args.Path, args.FileSystemChildren, isKnownMovie); + return FindMovie<Trailer>(args.Path, args.FileSystemChildren); } - if (args.Path.IndexOf("[musicvideos]", StringComparison.OrdinalIgnoreCase) != -1) + + if (args.Path.IndexOf("[musicvideos]", StringComparison.OrdinalIgnoreCase) != -1 || + string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<MusicVideo>(args.Path, args.FileSystemChildren, isKnownMovie); + return FindMovie<MusicVideo>(args.Path, args.FileSystemChildren); + } + + if (!string.IsNullOrEmpty(collectionType) && + !string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) + { + return null; } - return FindMovie<Movie>(args.Path, args.FileSystemChildren, isKnownMovie); + return FindMovie<Movie>(args.Path, args.FileSystemChildren); } return null; @@ -126,9 +136,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies /// <typeparam name="T"></typeparam> /// <param name="path">The path.</param> /// <param name="fileSystemEntries">The file system entries.</param> - /// <param name="isKnownMovie">if set to <c>true</c> [is known movie].</param> /// <returns>Movie.</returns> - private T FindMovie<T>(string path, IEnumerable<FileSystemInfo> fileSystemEntries, bool isKnownMovie) + private T FindMovie<T>(string path, IEnumerable<FileSystemInfo> fileSystemEntries) where T : Video, new() { var movies = new List<T>(); diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index 637e2e549..6228c9106 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -896,16 +896,22 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) { * Adds a virtual folder to either the default view or a user view * @param {String} name */ - self.addVirtualFolder = function (name, userId) { + self.addVirtualFolder = function (name, type, userId) { if (!name) { throw new Error("null name"); } + var options = {}; + + if (type) { + options.collectionType = type; + } + var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders"; url += "/" + name; - url = self.getUrl(url); + url = self.getUrl(url, options); return self.ajax({ type: "POST", diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 5dd14404a..cdfd8ba8f 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="MediaBrowser.ApiClient.Javascript" version="3.0.143" targetFramework="net45" /> + <package id="MediaBrowser.ApiClient.Javascript" version="3.0.144" targetFramework="net45" /> <package id="ServiceStack.Common" version="3.9.54" targetFramework="net45" /> <package id="ServiceStack.Text" version="3.9.54" targetFramework="net45" /> </packages>
\ No newline at end of file |
