mirror of https://github.com/jellyfin/jellyfin.git
added collection type
This commit is contained in:
parent
3370fb072e
commit
dab5003d6b
|
@ -16,10 +16,11 @@ namespace MediaBrowser.Api.Library
|
||||||
/// Adds the virtual folder.
|
/// Adds the virtual folder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name.</param>
|
/// <param name="name">The name.</param>
|
||||||
|
/// <param name="collectionType">Type of the collection.</param>
|
||||||
/// <param name="user">The user.</param>
|
/// <param name="user">The user.</param>
|
||||||
/// <param name="appPaths">The app paths.</param>
|
/// <param name="appPaths">The app paths.</param>
|
||||||
/// <exception cref="System.ArgumentException">There is already a media collection with the name + name + .</exception>
|
/// <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);
|
name = FileSystem.GetValidFilename(name);
|
||||||
|
|
||||||
|
@ -32,6 +33,13 @@ namespace MediaBrowser.Api.Library
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(virtualFolderPath);
|
Directory.CreateDirectory(virtualFolderPath);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(collectionType))
|
||||||
|
{
|
||||||
|
var path = Path.Combine(virtualFolderPath, collectionType + ".collection");
|
||||||
|
|
||||||
|
File.Create(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -38,6 +38,12 @@ namespace MediaBrowser.Api.Library
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The name.</value>
|
/// <value>The name.</value>
|
||||||
public string Name { get; set; }
|
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")]
|
[Route("/Library/VirtualFolders/{Name}", "DELETE")]
|
||||||
|
@ -196,13 +202,13 @@ namespace MediaBrowser.Api.Library
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(request.UserId))
|
if (string.IsNullOrEmpty(request.UserId))
|
||||||
{
|
{
|
||||||
LibraryHelpers.AddVirtualFolder(request.Name, null, _appPaths);
|
LibraryHelpers.AddVirtualFolder(request.Name, request.CollectionType, null, _appPaths);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(new Guid(request.UserId));
|
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);
|
_libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
|
||||||
|
|
|
@ -125,15 +125,35 @@ namespace MediaBrowser.Api.UserLibrary
|
||||||
{
|
{
|
||||||
var name = DeSlugArtistName(request.Name, LibraryManager);
|
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
|
var counts = new ItemByNameCounts
|
||||||
{
|
{
|
||||||
TotalCount = items.Count,
|
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);
|
return ToOptimizedResult(counts);
|
||||||
|
|
|
@ -548,6 +548,19 @@ namespace MediaBrowser.Controller.Dto
|
||||||
{
|
{
|
||||||
SetGameProperties(dto, game);
|
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)
|
private void SetGameProperties(BaseItemDto dto, Game item)
|
||||||
|
|
|
@ -336,7 +336,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
// When resolving the root, we need it's grandchildren (children of user views)
|
// When resolving the root, we need it's grandchildren (children of user views)
|
||||||
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
|
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
|
// Need to remove subpaths that may have been resolved from shortcuts
|
||||||
// Example: if \\server\movies exists, then strip out \\server\movies\action
|
// Example: if \\server\movies exists, then strip out \\server\movies\action
|
||||||
|
@ -1111,6 +1111,24 @@ namespace MediaBrowser.Controller.Entities
|
||||||
throw new ArgumentNullException();
|
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 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))
|
if (string.Equals(person.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using MediaBrowser.Controller.Library;
|
||||||
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -6,7 +7,6 @@ using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
|
@ -29,6 +29,8 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string CollectionType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Allow different display preferences for each collection folder
|
/// Allow different display preferences for each collection folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -69,7 +71,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// Our children are actually just references to the ones in the physical root...
|
/// Our children are actually just references to the ones in the physical root...
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The actual children.</value>
|
/// <value>The actual children.</value>
|
||||||
protected override ConcurrentDictionary<Guid,BaseItem> ActualChildren
|
protected override ConcurrentDictionary<Guid, BaseItem> ActualChildren
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@ -91,7 +93,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
.Where(i => i.Path != null && resolveArgs.PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase))
|
.Where(i => i.Path != null && resolveArgs.PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase))
|
||||||
.SelectMany(c => c.Children);
|
.SelectMany(c => c.Children);
|
||||||
|
|
||||||
return new ConcurrentDictionary<Guid,BaseItem>(ourChildren.ToDictionary(i => i.Id));
|
return new ConcurrentDictionary<Guid, BaseItem>(ourChildren.ToDictionary(i => i.Id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Extensions;
|
|
||||||
using MediaBrowser.Common.Progress;
|
using MediaBrowser.Common.Progress;
|
||||||
using MediaBrowser.Controller.IO;
|
using MediaBrowser.Controller.IO;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
@ -8,6 +7,7 @@ using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Controller.Resolvers;
|
using MediaBrowser.Controller.Resolvers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -17,18 +17,22 @@ namespace MediaBrowser.Controller.IO
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
|
/// <param name="args">The args.</param>
|
||||||
/// <param name="searchPattern">The search pattern.</param>
|
/// <param name="searchPattern">The search pattern.</param>
|
||||||
/// <param name="flattenFolderDepth">The flatten folder depth.</param>
|
/// <param name="flattenFolderDepth">The flatten folder depth.</param>
|
||||||
/// <param name="resolveShortcuts">if set to <c>true</c> [resolve shortcuts].</param>
|
/// <param name="resolveShortcuts">if set to <c>true</c> [resolve shortcuts].</param>
|
||||||
/// <param name="args">The args.</param>
|
|
||||||
/// <returns>Dictionary{System.StringFileSystemInfo}.</returns>
|
/// <returns>Dictionary{System.StringFileSystemInfo}.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException">path</exception>
|
/// <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))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("path");
|
throw new ArgumentNullException("path");
|
||||||
}
|
}
|
||||||
|
if (args == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("args");
|
||||||
|
}
|
||||||
|
|
||||||
var entries = new DirectoryInfo(path).EnumerateFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
|
var entries = new DirectoryInfo(path).EnumerateFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
|
||||||
|
|
||||||
|
@ -60,16 +64,13 @@ namespace MediaBrowser.Controller.IO
|
||||||
var data = new DirectoryInfo(newPath);
|
var data = new DirectoryInfo(newPath);
|
||||||
|
|
||||||
// add to our physical locations
|
// add to our physical locations
|
||||||
if (args != null)
|
args.AddAdditionalLocation(newPath);
|
||||||
{
|
|
||||||
args.AddAdditionalLocation(newPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
dict[newPath] = data;
|
dict[newPath] = data;
|
||||||
}
|
}
|
||||||
else if (flattenFolderDepth > 0 && isDirectory)
|
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;
|
dict[child.Key] = child.Value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,5 +254,12 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
void ReportItemRemoved(BaseItem item);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -161,6 +161,13 @@ namespace MediaBrowser.Model.ApiClient
|
||||||
/// <returns>Task{ItemsResult}.</returns>
|
/// <returns>Task{ItemsResult}.</returns>
|
||||||
Task<ItemsResult> GetSimilarMoviesAsync(SimilarItemsQuery query);
|
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>
|
/// <summary>
|
||||||
/// Gets the similar series async.
|
/// Gets the similar series async.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,12 @@ namespace MediaBrowser.Model.Entities
|
||||||
/// <value>The locations.</value>
|
/// <value>The locations.</value>
|
||||||
public List<string> Locations { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="VirtualFolderInfo"/> class.
|
/// Initializes a new instance of the <see cref="VirtualFolderInfo"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
<Compile Include="Dto\ItemByNameCounts.cs" />
|
<Compile Include="Dto\ItemByNameCounts.cs" />
|
||||||
<Compile Include="Dto\ItemCounts.cs" />
|
<Compile Include="Dto\ItemCounts.cs" />
|
||||||
<Compile Include="Dto\StudioDto.cs" />
|
<Compile Include="Dto\StudioDto.cs" />
|
||||||
|
<Compile Include="Entities\CollectionType.cs" />
|
||||||
<Compile Include="Entities\ItemReview.cs" />
|
<Compile Include="Entities\ItemReview.cs" />
|
||||||
<Compile Include="Entities\MediaUrl.cs" />
|
<Compile Include="Entities\MediaUrl.cs" />
|
||||||
<Compile Include="Entities\MetadataFields.cs" />
|
<Compile Include="Entities\MetadataFields.cs" />
|
||||||
|
|
|
@ -102,7 +102,9 @@ namespace MediaBrowser.Providers.Savers
|
||||||
XmlSaverHelpers.Save(builder, xmlFilePath, new[]
|
XmlSaverHelpers.Save(builder, xmlFilePath, new[]
|
||||||
{
|
{
|
||||||
"IMDBrating",
|
"IMDBrating",
|
||||||
"Description"
|
"Description",
|
||||||
|
"Artist",
|
||||||
|
"Album"
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set last refreshed so that the provider doesn't trigger after the file save
|
// Set last refreshed so that the provider doesn't trigger after the file save
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
||||||
public async void RemoveTempIgnore(string path)
|
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.
|
// 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;
|
string val;
|
||||||
_tempIgnoredPaths.TryRemove(path, out val);
|
_tempIgnoredPaths.TryRemove(path, out val);
|
||||||
|
|
|
@ -487,7 +487,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
// When resolving the root, we need it's grandchildren (children of user views)
|
// When resolving the root, we need it's grandchildren (children of user views)
|
||||||
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
|
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
|
// Need to remove subpaths that may have been resolved from shortcuts
|
||||||
// Example: if \\server\movies exists, then strip out \\server\movies\action
|
// Example: if \\server\movies exists, then strip out \\server\movies\action
|
||||||
|
@ -1168,10 +1168,23 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
.Select(dir => new VirtualFolderInfo
|
.Select(dir => new VirtualFolderInfo
|
||||||
{
|
{
|
||||||
Name = Path.GetFileName(dir),
|
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>
|
/// <summary>
|
||||||
/// Gets the item by id.
|
/// Gets the item by id.
|
||||||
/// </summary>
|
/// </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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Resolvers;
|
using MediaBrowser.Controller.Resolvers;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
||||||
{
|
{
|
||||||
|
@ -37,7 +40,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
||||||
}
|
}
|
||||||
if (args.IsVf)
|
if (args.IsVf)
|
||||||
{
|
{
|
||||||
return new CollectionFolder();
|
return new CollectionFolder
|
||||||
|
{
|
||||||
|
CollectionType = GetCollectionType(args)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Folder();
|
return new Folder();
|
||||||
|
@ -45,6 +51,14 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
||||||
|
|
||||||
return null;
|
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>
|
/// <summary>
|
||||||
|
|
|
@ -18,10 +18,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
||||||
public class MovieResolver : BaseVideoResolver<Video>
|
public class MovieResolver : BaseVideoResolver<Video>
|
||||||
{
|
{
|
||||||
private IServerApplicationPaths ApplicationPaths { get; set; }
|
private IServerApplicationPaths ApplicationPaths { get; set; }
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
public MovieResolver(IServerApplicationPaths appPaths)
|
public MovieResolver(IServerApplicationPaths appPaths, ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
ApplicationPaths = appPaths;
|
ApplicationPaths = appPaths;
|
||||||
|
_libraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -73,19 +75,27 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A shortcut to help us resolve faster in some cases
|
var collectionType = args.Parent == null ? null : _libraryManager.FindCollectionType(args.Parent);
|
||||||
var isKnownMovie = args.ContainsMetaFileByName("movie.xml");
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
return FindMovie<MusicVideo>(args.Path, args.FileSystemChildren, isKnownMovie);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FindMovie<Movie>(args.Path, args.FileSystemChildren, isKnownMovie);
|
if (args.Path.IndexOf("[musicvideos]", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||||
|
string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -126,9 +136,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <param name="fileSystemEntries">The file system entries.</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>
|
/// <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()
|
where T : Video, new()
|
||||||
{
|
{
|
||||||
var movies = new List<T>();
|
var movies = new List<T>();
|
||||||
|
|
|
@ -896,16 +896,22 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
|
||||||
* Adds a virtual folder to either the default view or a user view
|
* Adds a virtual folder to either the default view or a user view
|
||||||
* @param {String} name
|
* @param {String} name
|
||||||
*/
|
*/
|
||||||
self.addVirtualFolder = function (name, userId) {
|
self.addVirtualFolder = function (name, type, userId) {
|
||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
throw new Error("null name");
|
throw new Error("null name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var options = {};
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
options.collectionType = type;
|
||||||
|
}
|
||||||
|
|
||||||
var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
|
var url = userId ? "Users/" + userId + "/VirtualFolders" : "Library/VirtualFolders";
|
||||||
|
|
||||||
url += "/" + name;
|
url += "/" + name;
|
||||||
url = self.getUrl(url);
|
url = self.getUrl(url, options);
|
||||||
|
|
||||||
return self.ajax({
|
return self.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<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.Common" version="3.9.54" targetFramework="net45" />
|
||||||
<package id="ServiceStack.Text" version="3.9.54" targetFramework="net45" />
|
<package id="ServiceStack.Text" version="3.9.54" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
Loading…
Reference in New Issue