mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
commit
4cc3b2f0cc
@ -1,10 +1,10 @@
|
|||||||
using MediaBrowser.Api.Playback;
|
using MediaBrowser.Api.Playback;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Plugins;
|
using MediaBrowser.Controller.Plugins;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Session;
|
using MediaBrowser.Model.Session;
|
||||||
using System;
|
using System;
|
||||||
@ -39,6 +39,7 @@ namespace MediaBrowser.Api
|
|||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
|
||||||
private readonly ISessionManager _sessionManager;
|
private readonly ISessionManager _sessionManager;
|
||||||
|
private readonly IFileSystem _fileSystem;
|
||||||
|
|
||||||
public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1);
|
public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
@ -48,11 +49,12 @@ namespace MediaBrowser.Api
|
|||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
/// <param name="sessionManager">The session manager.</param>
|
/// <param name="sessionManager">The session manager.</param>
|
||||||
/// <param name="config">The configuration.</param>
|
/// <param name="config">The configuration.</param>
|
||||||
public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config)
|
public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config, IFileSystem fileSystem)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
_sessionManager = sessionManager;
|
_sessionManager = sessionManager;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
|
||||||
Instance = this;
|
Instance = this;
|
||||||
}
|
}
|
||||||
@ -86,12 +88,12 @@ namespace MediaBrowser.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void DeleteEncodedMediaCache()
|
private void DeleteEncodedMediaCache()
|
||||||
{
|
{
|
||||||
var path = Path.Combine(_config.ApplicationPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower());
|
var path = _config.ApplicationPaths.TranscodingTempPath;
|
||||||
|
|
||||||
foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
|
foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
|
||||||
.ToList())
|
.ToList())
|
||||||
{
|
{
|
||||||
File.Delete(file);
|
_fileSystem.DeleteFile(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,7 +464,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <param name="outputFilePath">The output file path.</param>
|
/// <param name="outputFilePath">The output file path.</param>
|
||||||
private void DeleteProgressivePartialStreamFiles(string outputFilePath)
|
private void DeleteProgressivePartialStreamFiles(string outputFilePath)
|
||||||
{
|
{
|
||||||
File.Delete(outputFilePath);
|
_fileSystem.DeleteFile(outputFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -479,13 +481,13 @@ namespace MediaBrowser.Api
|
|||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
Exception e = null;
|
Exception e = null;
|
||||||
|
|
||||||
foreach (var file in filesToDelete)
|
foreach (var file in filesToDelete)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Logger.Info("Deleting HLS file {0}", file);
|
Logger.Info("Deleting HLS file {0}", file);
|
||||||
File.Delete(file);
|
_fileSystem.DeleteFile(file);
|
||||||
}
|
}
|
||||||
catch (DirectoryNotFoundException)
|
catch (DirectoryNotFoundException)
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using ServiceStack.Text.Controller;
|
||||||
using ServiceStack.Web;
|
using ServiceStack.Web;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -21,7 +24,7 @@ namespace MediaBrowser.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The logger.</value>
|
/// <value>The logger.</value>
|
||||||
public ILogger Logger { get; set; }
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the HTTP result factory.
|
/// Gets or sets the HTTP result factory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -35,6 +38,7 @@ namespace MediaBrowser.Api
|
|||||||
public IRequest Request { get; set; }
|
public IRequest Request { get; set; }
|
||||||
|
|
||||||
public ISessionContext SessionContext { get; set; }
|
public ISessionContext SessionContext { get; set; }
|
||||||
|
public IAuthorizationContext AuthorizationContext { get; set; }
|
||||||
|
|
||||||
public string GetHeader(string name)
|
public string GetHeader(string name)
|
||||||
{
|
{
|
||||||
@ -109,6 +113,37 @@ namespace MediaBrowser.Api
|
|||||||
private readonly char[] _dashReplaceChars = { '?', '/', '&' };
|
private readonly char[] _dashReplaceChars = { '?', '/', '&' };
|
||||||
private const char SlugChar = '-';
|
private const char SlugChar = '-';
|
||||||
|
|
||||||
|
protected DtoOptions GetDtoOptions(object request)
|
||||||
|
{
|
||||||
|
var options = new DtoOptions();
|
||||||
|
|
||||||
|
options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
|
||||||
|
|
||||||
|
var hasFields = request as IHasItemFields;
|
||||||
|
if (hasFields != null)
|
||||||
|
{
|
||||||
|
options.Fields = hasFields.GetItemFields().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasDtoOptions = request as IHasDtoOptions;
|
||||||
|
if (hasDtoOptions != null)
|
||||||
|
{
|
||||||
|
options.EnableImages = hasDtoOptions.EnableImages ?? true;
|
||||||
|
|
||||||
|
if (hasDtoOptions.ImageTypeLimit.HasValue)
|
||||||
|
{
|
||||||
|
options.ImageTypeLimit = hasDtoOptions.ImageTypeLimit.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes))
|
||||||
|
{
|
||||||
|
options.ImageTypes = (hasDtoOptions.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
protected MusicArtist GetArtist(string name, ILibraryManager libraryManager)
|
protected MusicArtist GetArtist(string name, ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
return libraryManager.GetArtist(DeSlugArtistName(name, libraryManager));
|
return libraryManager.GetArtist(DeSlugArtistName(name, libraryManager));
|
||||||
@ -139,11 +174,11 @@ namespace MediaBrowser.Api
|
|||||||
return libraryManager.GetPerson(DeSlugPersonName(name, libraryManager));
|
return libraryManager.GetPerson(DeSlugPersonName(name, libraryManager));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IEnumerable<BaseItem> GetAllLibraryItems(Guid? userId, IUserManager userManager, ILibraryManager libraryManager, string parentId = null)
|
protected IList<BaseItem> GetAllLibraryItems(Guid? userId, IUserManager userManager, ILibraryManager libraryManager, string parentId, Func<BaseItem,bool> filter)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(parentId))
|
if (!string.IsNullOrEmpty(parentId))
|
||||||
{
|
{
|
||||||
var folder = (Folder) libraryManager.GetItemById(new Guid(parentId));
|
var folder = (Folder)libraryManager.GetItemById(new Guid(parentId));
|
||||||
|
|
||||||
if (userId.HasValue)
|
if (userId.HasValue)
|
||||||
{
|
{
|
||||||
@ -154,10 +189,13 @@ namespace MediaBrowser.Api
|
|||||||
throw new ArgumentException("User not found");
|
throw new ArgumentException("User not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
return folder.GetRecursiveChildren(user);
|
return folder
|
||||||
|
.GetRecursiveChildren(user, filter)
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return folder.GetRecursiveChildren();
|
return folder
|
||||||
|
.GetRecursiveChildren(filter);
|
||||||
}
|
}
|
||||||
if (userId.HasValue)
|
if (userId.HasValue)
|
||||||
{
|
{
|
||||||
@ -168,10 +206,16 @@ namespace MediaBrowser.Api
|
|||||||
throw new ArgumentException("User not found");
|
throw new ArgumentException("User not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
return userManager.GetUserById(userId.Value).RootFolder.GetRecursiveChildren(user);
|
return userManager
|
||||||
|
.GetUserById(userId.Value)
|
||||||
|
.RootFolder
|
||||||
|
.GetRecursiveChildren(user, filter)
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return libraryManager.RootFolder.GetRecursiveChildren();
|
return libraryManager
|
||||||
|
.RootFolder
|
||||||
|
.GetRecursiveChildren(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -187,8 +231,9 @@ namespace MediaBrowser.Api
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return libraryManager.RootFolder.RecursiveChildren
|
return libraryManager.RootFolder
|
||||||
.OfType<Audio>()
|
.GetRecursiveChildren(i => i is IHasArtist)
|
||||||
|
.Cast<IHasArtist>()
|
||||||
.SelectMany(i => i.AllArtists)
|
.SelectMany(i => i.AllArtists)
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.FirstOrDefault(i =>
|
.FirstOrDefault(i =>
|
||||||
@ -229,8 +274,8 @@ namespace MediaBrowser.Api
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return libraryManager.RootFolder.GetRecursiveChildren()
|
return libraryManager.RootFolder
|
||||||
.OfType<Game>()
|
.GetRecursiveChildren(i => i is Game)
|
||||||
.SelectMany(i => i.Genres)
|
.SelectMany(i => i.Genres)
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.FirstOrDefault(i =>
|
.FirstOrDefault(i =>
|
||||||
@ -252,7 +297,8 @@ namespace MediaBrowser.Api
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return libraryManager.RootFolder.GetRecursiveChildren()
|
return libraryManager.RootFolder
|
||||||
|
.GetRecursiveChildren()
|
||||||
.SelectMany(i => i.Studios)
|
.SelectMany(i => i.Studios)
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.FirstOrDefault(i =>
|
.FirstOrDefault(i =>
|
||||||
@ -274,7 +320,8 @@ namespace MediaBrowser.Api
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return libraryManager.RootFolder.GetRecursiveChildren()
|
return libraryManager.RootFolder
|
||||||
|
.GetRecursiveChildren()
|
||||||
.SelectMany(i => i.People)
|
.SelectMany(i => i.People)
|
||||||
.Select(i => i.Name)
|
.Select(i => i.Name)
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
@ -287,6 +334,20 @@ namespace MediaBrowser.Api
|
|||||||
}) ?? name;
|
}) ?? name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected string GetPathValue(int index)
|
||||||
|
{
|
||||||
|
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||||
|
var first = pathInfo.GetArgumentValue<string>(0);
|
||||||
|
|
||||||
|
// backwards compatibility
|
||||||
|
if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathInfo.GetArgumentValue<string>(index);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the item by.
|
/// Gets the name of the item by.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -294,7 +355,6 @@ namespace MediaBrowser.Api
|
|||||||
/// <param name="type">The type.</param>
|
/// <param name="type">The type.</param>
|
||||||
/// <param name="libraryManager">The library manager.</param>
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
/// <returns>Task{BaseItem}.</returns>
|
/// <returns>Task{BaseItem}.</returns>
|
||||||
/// <exception cref="System.ArgumentException"></exception>
|
|
||||||
protected BaseItem GetItemByName(string name, string type, ILibraryManager libraryManager)
|
protected BaseItem GetItemByName(string name, string type, ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
BaseItem item;
|
BaseItem item;
|
||||||
|
@ -8,7 +8,12 @@ namespace MediaBrowser.Api
|
|||||||
public class GetBrandingOptions : IReturn<BrandingOptions>
|
public class GetBrandingOptions : IReturn<BrandingOptions>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("/Branding/Css", "GET", Summary = "Gets custom css")]
|
||||||
|
public class GetBrandingCss
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public class BrandingService : BaseApiService
|
public class BrandingService : BaseApiService
|
||||||
{
|
{
|
||||||
private readonly IConfigurationManager _config;
|
private readonly IConfigurationManager _config;
|
||||||
@ -24,5 +29,12 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object Get(GetBrandingCss request)
|
||||||
|
{
|
||||||
|
var result = _config.GetConfiguration<BrandingOptions>("branding");
|
||||||
|
|
||||||
|
return ResultFactory.GetResult(result.CustomCss, "text/css");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,8 +143,7 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
public void Post(UpdateNamedConfiguration request)
|
public void Post(UpdateNamedConfiguration request)
|
||||||
{
|
{
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var key = GetPathValue(2);
|
||||||
var key = pathInfo.GetArgumentValue<string>(2);
|
|
||||||
|
|
||||||
var configurationType = _configurationManager.GetConfigurationType(key);
|
var configurationType = _configurationManager.GetConfigurationType(key);
|
||||||
var configuration = _jsonSerializer.DeserializeFromStream(request.RequestStream, configurationType);
|
var configuration = _jsonSerializer.DeserializeFromStream(request.RequestStream, configurationType);
|
||||||
|
@ -39,11 +39,11 @@ namespace MediaBrowser.Api
|
|||||||
[ApiMember(Name = "SendingUserId", Description = "Sending User Id", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
[ApiMember(Name = "SendingUserId", Description = "Sending User Id", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||||
public string SendingUserId { get; set; }
|
public string SendingUserId { get; set; }
|
||||||
|
|
||||||
[ApiMember(Name = "ExcludeLibraries", Description = "ExcludeLibraries", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
[ApiMember(Name = "EnabledLibraries", Description = "EnabledLibraries", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||||
public string ExcludedLibraries { get; set; }
|
public string EnabledLibraries { get; set; }
|
||||||
|
|
||||||
[ApiMember(Name = "ExcludedChannels", Description = "ExcludedChannels", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
[ApiMember(Name = "EnabledChannels", Description = "EnabledChannels", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||||
public string ExcludedChannels { get; set; }
|
public string EnabledChannels { get; set; }
|
||||||
|
|
||||||
[ApiMember(Name = "EnableLiveTv", Description = "EnableLiveTv", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
[ApiMember(Name = "EnableLiveTv", Description = "EnableLiveTv", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||||
public bool EnableLiveTv { get; set; }
|
public bool EnableLiveTv { get; set; }
|
||||||
@ -91,12 +91,12 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
public object Post(CreateConnectInvite request)
|
public object Post(CreateConnectInvite request)
|
||||||
{
|
{
|
||||||
var excludeLibraries = (request.ExcludedLibraries ?? string.Empty)
|
var enabledLibraries = (request.EnabledLibraries ?? string.Empty)
|
||||||
.Split(',')
|
.Split(',')
|
||||||
.Where(i => !string.IsNullOrWhiteSpace(i))
|
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var excludedChannels = (request.ExcludedChannels ?? string.Empty)
|
var enabledChannels = (request.EnabledChannels ?? string.Empty)
|
||||||
.Split(',')
|
.Split(',')
|
||||||
.Where(i => !string.IsNullOrWhiteSpace(i))
|
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
@ -105,8 +105,8 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
ConnectUserName = request.ConnectUsername,
|
ConnectUserName = request.ConnectUsername,
|
||||||
SendingUserId = request.SendingUserId,
|
SendingUserId = request.SendingUserId,
|
||||||
ExcludedLibraries = excludeLibraries,
|
EnabledLibraries = enabledLibraries,
|
||||||
ExcludedChannels = excludedChannels,
|
EnabledChannels = enabledChannels,
|
||||||
EnableLiveTv = request.EnableLiveTv
|
EnableLiveTv = request.EnableLiveTv
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using ServiceStack.Text.Controller;
|
|
||||||
using ServiceStack.Web;
|
using ServiceStack.Web;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -19,19 +18,31 @@ namespace MediaBrowser.Api.Dlna
|
|||||||
public string UuId { get; set; }
|
public string UuId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Dlna/contentdirectory/contentdirectory.xml", "GET", Summary = "Gets dlna content directory xml")]
|
[Route("/Dlna/{UuId}/contentdirectory/contentdirectory.xml", "GET", Summary = "Gets dlna content directory xml")]
|
||||||
[Route("/Dlna/contentdirectory/contentdirectory", "GET", Summary = "Gets dlna content directory xml")]
|
[Route("/Dlna/{UuId}/contentdirectory/contentdirectory", "GET", Summary = "Gets dlna content directory xml")]
|
||||||
public class GetContentDirectory
|
public class GetContentDirectory
|
||||||
{
|
{
|
||||||
|
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
|
public string UuId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Dlna/connectionmanager/connectionmanager.xml", "GET", Summary = "Gets dlna connection manager xml")]
|
[Route("/Dlna/{UuId}/connectionmanager/connectionmanager.xml", "GET", Summary = "Gets dlna connection manager xml")]
|
||||||
[Route("/Dlna/connectionmanager/connectionmanager", "GET", Summary = "Gets dlna connection manager xml")]
|
[Route("/Dlna/{UuId}/connectionmanager/connectionmanager", "GET", Summary = "Gets dlna connection manager xml")]
|
||||||
public class GetConnnectionManager
|
public class GetConnnectionManager
|
||||||
{
|
{
|
||||||
|
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
|
public string UuId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Dlna/contentdirectory/{UuId}/control", "POST", Summary = "Processes a control request")]
|
[Route("/Dlna/{UuId}/mediareceiverregistrar/mediareceiverregistrar.xml", "GET", Summary = "Gets dlna mediareceiverregistrar xml")]
|
||||||
|
[Route("/Dlna/{UuId}/mediareceiverregistrar/mediareceiverregistrar", "GET", Summary = "Gets dlna mediareceiverregistrar xml")]
|
||||||
|
public class GetMediaReceiverRegistrar
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
|
public string UuId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Dlna/{UuId}/contentdirectory/control", "POST", Summary = "Processes a control request")]
|
||||||
public class ProcessContentDirectoryControlRequest : IRequiresRequestStream
|
public class ProcessContentDirectoryControlRequest : IRequiresRequestStream
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
@ -40,7 +51,7 @@ namespace MediaBrowser.Api.Dlna
|
|||||||
public Stream RequestStream { get; set; }
|
public Stream RequestStream { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Dlna/connectionmanager/{UuId}/control", "POST", Summary = "Processes a control request")]
|
[Route("/Dlna/{UuId}/connectionmanager/control", "POST", Summary = "Processes a control request")]
|
||||||
public class ProcessConnectionManagerControlRequest : IRequiresRequestStream
|
public class ProcessConnectionManagerControlRequest : IRequiresRequestStream
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
@ -49,23 +60,43 @@ namespace MediaBrowser.Api.Dlna
|
|||||||
public Stream RequestStream { get; set; }
|
public Stream RequestStream { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Dlna/contentdirectory/{UuId}/events", Summary = "Processes an event subscription request")]
|
[Route("/Dlna/{UuId}/mediareceiverregistrar/control", "POST", Summary = "Processes a control request")]
|
||||||
|
public class ProcessMediaReceiverRegistrarControlRequest : IRequiresRequestStream
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
|
public string UuId { get; set; }
|
||||||
|
|
||||||
|
public Stream RequestStream { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Dlna/{UuId}/mediareceiverregistrar/events", Summary = "Processes an event subscription request")]
|
||||||
|
public class ProcessMediaReceiverRegistrarEventRequest
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
|
||||||
|
public string UuId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Dlna/{UuId}/contentdirectory/events", Summary = "Processes an event subscription request")]
|
||||||
public class ProcessContentDirectoryEventRequest
|
public class ProcessContentDirectoryEventRequest
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
|
||||||
public string UuId { get; set; }
|
public string UuId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Dlna/connectionmanager/{UuId}/events", Summary = "Processes an event subscription request")]
|
[Route("/Dlna/{UuId}/connectionmanager/events", Summary = "Processes an event subscription request")]
|
||||||
public class ProcessConnectionManagerEventRequest
|
public class ProcessConnectionManagerEventRequest
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
|
||||||
public string UuId { get; set; }
|
public string UuId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("/Dlna/{UuId}/icons/{Filename}", "GET", Summary = "Gets a server icon")]
|
||||||
[Route("/Dlna/icons/{Filename}", "GET", Summary = "Gets a server icon")]
|
[Route("/Dlna/icons/{Filename}", "GET", Summary = "Gets a server icon")]
|
||||||
public class GetIcon
|
public class GetIcon
|
||||||
{
|
{
|
||||||
|
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
|
public string UuId { get; set; }
|
||||||
|
|
||||||
[ApiMember(Name = "Filename", Description = "The icon filename", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
[ApiMember(Name = "Filename", Description = "The icon filename", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
public string Filename { get; set; }
|
public string Filename { get; set; }
|
||||||
}
|
}
|
||||||
@ -75,17 +106,21 @@ namespace MediaBrowser.Api.Dlna
|
|||||||
private readonly IDlnaManager _dlnaManager;
|
private readonly IDlnaManager _dlnaManager;
|
||||||
private readonly IContentDirectory _contentDirectory;
|
private readonly IContentDirectory _contentDirectory;
|
||||||
private readonly IConnectionManager _connectionManager;
|
private readonly IConnectionManager _connectionManager;
|
||||||
|
private readonly IMediaReceiverRegistrar _mediaReceiverRegistrar;
|
||||||
|
|
||||||
public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager)
|
public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IMediaReceiverRegistrar mediaReceiverRegistrar)
|
||||||
{
|
{
|
||||||
_dlnaManager = dlnaManager;
|
_dlnaManager = dlnaManager;
|
||||||
_contentDirectory = contentDirectory;
|
_contentDirectory = contentDirectory;
|
||||||
_connectionManager = connectionManager;
|
_connectionManager = connectionManager;
|
||||||
|
_mediaReceiverRegistrar = mediaReceiverRegistrar;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetDescriptionXml request)
|
public object Get(GetDescriptionXml request)
|
||||||
{
|
{
|
||||||
var xml = _dlnaManager.GetServerDescriptionXml(GetRequestHeaders(), request.UuId);
|
var url = Request.AbsoluteUri;
|
||||||
|
var serverAddress = url.Substring(0, url.IndexOf("/dlna/", StringComparison.OrdinalIgnoreCase));
|
||||||
|
var xml = _dlnaManager.GetServerDescriptionXml(GetRequestHeaders(), request.UuId, serverAddress);
|
||||||
|
|
||||||
return ResultFactory.GetResult(xml, "text/xml");
|
return ResultFactory.GetResult(xml, "text/xml");
|
||||||
}
|
}
|
||||||
@ -97,6 +132,13 @@ namespace MediaBrowser.Api.Dlna
|
|||||||
return ResultFactory.GetResult(xml, "text/xml");
|
return ResultFactory.GetResult(xml, "text/xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object Get(GetMediaReceiverRegistrar request)
|
||||||
|
{
|
||||||
|
var xml = _mediaReceiverRegistrar.GetServiceXml(GetRequestHeaders());
|
||||||
|
|
||||||
|
return ResultFactory.GetResult(xml, "text/xml");
|
||||||
|
}
|
||||||
|
|
||||||
public object Get(GetConnnectionManager request)
|
public object Get(GetConnnectionManager request)
|
||||||
{
|
{
|
||||||
var xml = _connectionManager.GetServiceXml(GetRequestHeaders());
|
var xml = _connectionManager.GetServiceXml(GetRequestHeaders());
|
||||||
@ -104,6 +146,13 @@ namespace MediaBrowser.Api.Dlna
|
|||||||
return ResultFactory.GetResult(xml, "text/xml");
|
return ResultFactory.GetResult(xml, "text/xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<object> Post(ProcessMediaReceiverRegistrarControlRequest request)
|
||||||
|
{
|
||||||
|
var response = await PostAsync(request.RequestStream, _mediaReceiverRegistrar).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return ResultFactory.GetResult(response.Xml, "text/xml");
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<object> Post(ProcessContentDirectoryControlRequest request)
|
public async Task<object> Post(ProcessContentDirectoryControlRequest request)
|
||||||
{
|
{
|
||||||
var response = await PostAsync(request.RequestStream, _contentDirectory).ConfigureAwait(false);
|
var response = await PostAsync(request.RequestStream, _contentDirectory).ConfigureAwait(false);
|
||||||
@ -120,8 +169,7 @@ namespace MediaBrowser.Api.Dlna
|
|||||||
|
|
||||||
private async Task<ControlResponse> PostAsync(Stream requestStream, IUpnpService service)
|
private async Task<ControlResponse> PostAsync(Stream requestStream, IUpnpService service)
|
||||||
{
|
{
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var id = GetPathValue(2);
|
||||||
var id = pathInfo.GetArgumentValue<string>(2);
|
|
||||||
|
|
||||||
using (var reader = new StreamReader(requestStream))
|
using (var reader = new StreamReader(requestStream))
|
||||||
{
|
{
|
||||||
@ -172,6 +220,11 @@ namespace MediaBrowser.Api.Dlna
|
|||||||
return ProcessEventRequest(_connectionManager);
|
return ProcessEventRequest(_connectionManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object Any(ProcessMediaReceiverRegistrarEventRequest request)
|
||||||
|
{
|
||||||
|
return ProcessEventRequest(_mediaReceiverRegistrar);
|
||||||
|
}
|
||||||
|
|
||||||
private object ProcessEventRequest(IEventManager eventManager)
|
private object ProcessEventRequest(IEventManager eventManager)
|
||||||
{
|
{
|
||||||
var subscriptionId = GetHeader("SID");
|
var subscriptionId = GetHeader("SID");
|
||||||
|
@ -102,8 +102,8 @@ namespace MediaBrowser.Api
|
|||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public object Get(GetGameSystemSummaries request)
|
public object Get(GetGameSystemSummaries request)
|
||||||
{
|
{
|
||||||
var gameSystems = GetAllLibraryItems(request.UserId, _userManager, _libraryManager)
|
var gameSystems = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i is GameSystem)
|
||||||
.OfType<GameSystem>()
|
.Cast<GameSystem>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId.Value);
|
var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId.Value);
|
||||||
@ -119,9 +119,8 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
public object Get(GetPlayerIndex request)
|
public object Get(GetPlayerIndex request)
|
||||||
{
|
{
|
||||||
var games = GetAllLibraryItems(request.UserId, _userManager, _libraryManager)
|
var games = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i is Game)
|
||||||
.OfType<Game>()
|
.Cast<Game>();
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var lookup = games
|
var lookup = games
|
||||||
.ToLookup(i => i.PlayersSupported ?? -1)
|
.ToLookup(i => i.PlayersSupported ?? -1)
|
||||||
@ -150,9 +149,11 @@ namespace MediaBrowser.Api
|
|||||||
DisplayName = system.Name
|
DisplayName = system.Name
|
||||||
};
|
};
|
||||||
|
|
||||||
var items = user == null ? system.RecursiveChildren : system.GetRecursiveChildren(user);
|
var items = user == null ?
|
||||||
|
system.GetRecursiveChildren(i => i is Game) :
|
||||||
|
system.GetRecursiveChildren(user, i => i is Game);
|
||||||
|
|
||||||
var games = items.OfType<Game>().ToList();
|
var games = items.Cast<Game>().ToList();
|
||||||
|
|
||||||
summary.ClientInstalledGameCount = games.Count(i => i.IsPlaceHolder);
|
summary.ClientInstalledGameCount = games.Count(i => i.IsPlaceHolder);
|
||||||
|
|
||||||
@ -172,7 +173,9 @@ namespace MediaBrowser.Api
|
|||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public object Get(GetSimilarGames request)
|
public object Get(GetSimilarGames request)
|
||||||
{
|
{
|
||||||
var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
|
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
|
||||||
_itemRepo,
|
_itemRepo,
|
||||||
_libraryManager,
|
_libraryManager,
|
||||||
_userDataRepository,
|
_userDataRepository,
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
using MediaBrowser.Controller.Dto;
|
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api
|
namespace MediaBrowser.Api
|
||||||
{
|
{
|
||||||
public interface IHasDtoOptions : IHasItemFields
|
public interface IHasDtoOptions : IHasItemFields
|
||||||
@ -13,27 +9,4 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
string EnableImageTypes { get; set; }
|
string EnableImageTypes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HasDtoOptionsExtensions
|
|
||||||
{
|
|
||||||
public static DtoOptions GetDtoOptions(this IHasDtoOptions request)
|
|
||||||
{
|
|
||||||
var options = new DtoOptions();
|
|
||||||
|
|
||||||
options.Fields = request.GetItemFields().ToList();
|
|
||||||
options.EnableImages = request.EnableImages ?? true;
|
|
||||||
|
|
||||||
if (request.ImageTypeLimit.HasValue)
|
|
||||||
{
|
|
||||||
options.ImageTypeLimit = request.ImageTypeLimit.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(request.EnableImageTypes))
|
|
||||||
{
|
|
||||||
options.ImageTypes = (request.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ using MediaBrowser.Model.Drawing;
|
|||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using ServiceStack.Text.Controller;
|
|
||||||
using ServiceStack.Web;
|
using ServiceStack.Web;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -396,8 +395,7 @@ namespace MediaBrowser.Api.Images
|
|||||||
|
|
||||||
public object Get(GetItemByNameImage request)
|
public object Get(GetItemByNameImage request)
|
||||||
{
|
{
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var type = GetPathValue(0);
|
||||||
var type = pathInfo.GetArgumentValue<string>(0);
|
|
||||||
|
|
||||||
var item = GetItemByName(request.Name, type, _libraryManager);
|
var item = GetItemByName(request.Name, type, _libraryManager);
|
||||||
|
|
||||||
@ -406,8 +404,7 @@ namespace MediaBrowser.Api.Images
|
|||||||
|
|
||||||
public object Head(GetItemByNameImage request)
|
public object Head(GetItemByNameImage request)
|
||||||
{
|
{
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var type = GetPathValue(0);
|
||||||
var type = pathInfo.GetArgumentValue<string>(0);
|
|
||||||
|
|
||||||
var item = GetItemByName(request.Name, type, _libraryManager);
|
var item = GetItemByName(request.Name, type, _libraryManager);
|
||||||
|
|
||||||
@ -420,10 +417,9 @@ namespace MediaBrowser.Api.Images
|
|||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
public void Post(PostUserImage request)
|
public void Post(PostUserImage request)
|
||||||
{
|
{
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var id = new Guid(GetPathValue(1));
|
||||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
|
||||||
|
|
||||||
request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue<string>(3), true);
|
request.Type = (ImageType)Enum.Parse(typeof(ImageType), GetPathValue(3), true);
|
||||||
|
|
||||||
var item = _userManager.GetUserById(id);
|
var item = _userManager.GetUserById(id);
|
||||||
|
|
||||||
@ -438,10 +434,9 @@ namespace MediaBrowser.Api.Images
|
|||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
public void Post(PostItemImage request)
|
public void Post(PostItemImage request)
|
||||||
{
|
{
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var id = new Guid(GetPathValue(1));
|
||||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
|
||||||
|
|
||||||
request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue<string>(3), true);
|
request.Type = (ImageType)Enum.Parse(typeof(ImageType), GetPathValue(3), true);
|
||||||
|
|
||||||
var item = _libraryManager.GetItemById(id);
|
var item = _libraryManager.GetItemById(id);
|
||||||
|
|
||||||
|
@ -205,7 +205,8 @@ namespace MediaBrowser.Api
|
|||||||
Logger = Logger,
|
Logger = Logger,
|
||||||
Request = Request,
|
Request = Request,
|
||||||
ResultFactory = ResultFactory,
|
ResultFactory = ResultFactory,
|
||||||
SessionContext = SessionContext
|
SessionContext = SessionContext,
|
||||||
|
AuthorizationContext = AuthorizationContext
|
||||||
};
|
};
|
||||||
|
|
||||||
service.Post(new RefreshItem
|
service.Post(new RefreshItem
|
||||||
|
@ -51,7 +51,7 @@ namespace MediaBrowser.Api
|
|||||||
var cancellationToken = CancellationToken.None;
|
var cancellationToken = CancellationToken.None;
|
||||||
|
|
||||||
var albums = _libraryManager.RootFolder
|
var albums = _libraryManager.RootFolder
|
||||||
.RecursiveChildren
|
.GetRecursiveChildren()
|
||||||
.OfType<MusicAlbum>()
|
.OfType<MusicAlbum>()
|
||||||
.Where(i => i.HasArtist(item.Name))
|
.Where(i => i.HasArtist(item.Name))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
@ -215,7 +215,7 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
var folder = (Folder)item;
|
var folder = (Folder)item;
|
||||||
|
|
||||||
foreach (var child in folder.RecursiveChildren.ToList())
|
foreach (var child in folder.GetRecursiveChildren())
|
||||||
{
|
{
|
||||||
child.IsLocked = newLockData;
|
child.IsLocked = newLockData;
|
||||||
await child.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
await child.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Library
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(shortcut))
|
if (!string.IsNullOrEmpty(shortcut))
|
||||||
{
|
{
|
||||||
File.Delete(shortcut);
|
fileSystem.DeleteFile(shortcut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,8 @@ using MediaBrowser.Controller.Entities.Audio;
|
|||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Controller.Playlists;
|
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
@ -226,6 +224,18 @@ namespace MediaBrowser.Api.Library
|
|||||||
public string TvdbId { get; set; }
|
public string TvdbId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("/Items/{Id}/Download", "GET", Summary = "Downloads item media")]
|
||||||
|
[Authenticated(Roles = "download")]
|
||||||
|
public class GetDownload
|
||||||
|
{
|
||||||
|
/// <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>
|
/// <summary>
|
||||||
/// Class LibraryService
|
/// Class LibraryService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -272,8 +282,8 @@ namespace MediaBrowser.Api.Library
|
|||||||
items = items.Where(i => i.IsHidden == val).ToList();
|
items = items.Where(i => i.IsHidden == val).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var result = new ItemsResult
|
var result = new ItemsResult
|
||||||
{
|
{
|
||||||
TotalRecordCount = items.Count,
|
TotalRecordCount = items.Count,
|
||||||
@ -289,6 +299,28 @@ namespace MediaBrowser.Api.Library
|
|||||||
Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None));
|
Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object Get(GetDownload request)
|
||||||
|
{
|
||||||
|
var item = _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
|
if (!item.CanDelete())
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Item does not support downloading");
|
||||||
|
}
|
||||||
|
|
||||||
|
var headers = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
// Quotes are valid in linux. They'll possibly cause issues here
|
||||||
|
var filename = Path.GetFileName(item.Path).Replace("\"", string.Empty);
|
||||||
|
headers["Content-Disposition"] = string.Format("attachment; filename=\"{0}\"", filename);
|
||||||
|
|
||||||
|
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
|
||||||
|
{
|
||||||
|
Path = item.Path,
|
||||||
|
ResponseHeaders = headers
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public object Get(GetFile request)
|
public object Get(GetFile request)
|
||||||
{
|
{
|
||||||
var item = _libraryManager.GetItemById(request.Id);
|
var item = _libraryManager.GetItemById(request.Id);
|
||||||
@ -344,10 +376,10 @@ namespace MediaBrowser.Api.Library
|
|||||||
|
|
||||||
var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
|
var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
BaseItem parent = item.Parent;
|
BaseItem parent = item.Parent;
|
||||||
|
|
||||||
while (parent != null)
|
while (parent != null)
|
||||||
{
|
{
|
||||||
if (user != null)
|
if (user != null)
|
||||||
@ -392,52 +424,43 @@ namespace MediaBrowser.Api.Library
|
|||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public object Get(GetItemCounts request)
|
public object Get(GetItemCounts request)
|
||||||
{
|
{
|
||||||
var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager)
|
var filteredItems = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i.LocationType != LocationType.Virtual && FilterItem(i, request, request.UserId));
|
||||||
.Where(i => i.LocationType != LocationType.Virtual)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var filteredItems = request.UserId.HasValue ? FilterItems(items, request, request.UserId.Value).ToList() : items;
|
|
||||||
|
|
||||||
var albums = filteredItems.OfType<MusicAlbum>().ToList();
|
|
||||||
var episodes = filteredItems.OfType<Episode>().ToList();
|
|
||||||
var games = filteredItems.OfType<Game>().ToList();
|
|
||||||
var movies = filteredItems.OfType<Movie>().ToList();
|
|
||||||
var musicVideos = filteredItems.OfType<MusicVideo>().ToList();
|
|
||||||
var boxsets = filteredItems.OfType<BoxSet>().ToList();
|
|
||||||
var books = filteredItems.OfType<Book>().ToList();
|
|
||||||
var songs = filteredItems.OfType<Audio>().ToList();
|
|
||||||
var series = filteredItems.OfType<Series>().ToList();
|
|
||||||
|
|
||||||
var counts = new ItemCounts
|
var counts = new ItemCounts
|
||||||
{
|
{
|
||||||
AlbumCount = albums.Count,
|
AlbumCount = filteredItems.Count(i => i is MusicAlbum),
|
||||||
EpisodeCount = episodes.Count,
|
EpisodeCount = filteredItems.Count(i => i is Episode),
|
||||||
GameCount = games.Count,
|
GameCount = filteredItems.Count(i => i is Game),
|
||||||
GameSystemCount = filteredItems.OfType<GameSystem>().Count(),
|
GameSystemCount = filteredItems.Count(i => i is GameSystem),
|
||||||
MovieCount = movies.Count,
|
MovieCount = filteredItems.Count(i => i is Movie),
|
||||||
SeriesCount = series.Count,
|
SeriesCount = filteredItems.Count(i => i is Series),
|
||||||
SongCount = songs.Count,
|
SongCount = filteredItems.Count(i => i is Audio),
|
||||||
MusicVideoCount = musicVideos.Count,
|
MusicVideoCount = filteredItems.Count(i => i is MusicVideo),
|
||||||
BoxSetCount = boxsets.Count,
|
BoxSetCount = filteredItems.Count(i => i is BoxSet),
|
||||||
BookCount = books.Count,
|
BookCount = filteredItems.Count(i => i is Book),
|
||||||
|
|
||||||
UniqueTypes = items.Select(i => i.GetClientTypeName()).Distinct().ToList()
|
UniqueTypes = filteredItems.Select(i => i.GetClientTypeName()).Distinct().ToList()
|
||||||
};
|
};
|
||||||
|
|
||||||
return ToOptimizedSerializedResultUsingCache(counts);
|
return ToOptimizedSerializedResultUsingCache(counts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<T> FilterItems<T>(IEnumerable<T> items, GetItemCounts request, Guid userId)
|
private bool FilterItem(BaseItem item, GetItemCounts request, Guid? userId)
|
||||||
where T : BaseItem
|
|
||||||
{
|
{
|
||||||
if (request.IsFavorite.HasValue)
|
if (userId.HasValue)
|
||||||
{
|
{
|
||||||
var val = request.IsFavorite.Value;
|
if (request.IsFavorite.HasValue)
|
||||||
|
{
|
||||||
|
var val = request.IsFavorite.Value;
|
||||||
|
|
||||||
items = items.Where(i => _userDataManager.GetUserData(userId, i.GetUserDataKey()).IsFavorite == val);
|
if (_userDataManager.GetUserData(userId.Value, item.GetUserDataKey()).IsFavorite != val)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -467,23 +490,9 @@ namespace MediaBrowser.Api.Library
|
|||||||
var auth = _authContext.GetAuthorizationInfo(Request);
|
var auth = _authContext.GetAuthorizationInfo(Request);
|
||||||
var user = _userManager.GetUserById(auth.UserId);
|
var user = _userManager.GetUserById(auth.UserId);
|
||||||
|
|
||||||
if (item is Playlist || item is BoxSet)
|
if (!item.CanDelete(user))
|
||||||
{
|
{
|
||||||
// For now this is allowed if user can see the playlist
|
throw new UnauthorizedAccessException();
|
||||||
}
|
|
||||||
else if (item is ILiveTvRecording)
|
|
||||||
{
|
|
||||||
if (!user.Policy.EnableLiveTvManagement)
|
|
||||||
{
|
|
||||||
throw new UnauthorizedAccessException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!user.Policy.EnableContentDeletion)
|
|
||||||
{
|
|
||||||
throw new UnauthorizedAccessException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var task = _libraryManager.DeleteItem(item);
|
var task = _libraryManager.DeleteItem(item);
|
||||||
@ -544,7 +553,7 @@ namespace MediaBrowser.Api.Library
|
|||||||
ThemeSongsResult = themeSongs,
|
ThemeSongsResult = themeSongs,
|
||||||
ThemeVideosResult = themeVideos,
|
ThemeVideosResult = themeVideos,
|
||||||
|
|
||||||
SoundtrackSongsResult = GetSoundtrackSongs(request.Id, request.UserId, request.InheritFromParent)
|
SoundtrackSongsResult = GetSoundtrackSongs(request, request.Id, request.UserId, request.InheritFromParent)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,7 +606,7 @@ namespace MediaBrowser.Api.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = themeSongIds.Select(_libraryManager.GetItemById)
|
var dtos = themeSongIds.Select(_libraryManager.GetItemById)
|
||||||
.OrderBy(i => i.SortName)
|
.OrderBy(i => i.SortName)
|
||||||
@ -667,7 +676,7 @@ namespace MediaBrowser.Api.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
|
var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
|
||||||
.OrderBy(i => i.SortName)
|
.OrderBy(i => i.SortName)
|
||||||
@ -711,13 +720,24 @@ namespace MediaBrowser.Api.Library
|
|||||||
|
|
||||||
public object Get(GetYearIndex request)
|
public object Get(GetYearIndex request)
|
||||||
{
|
{
|
||||||
IEnumerable<BaseItem> items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager);
|
var includeTypes = string.IsNullOrWhiteSpace(request.IncludeItemTypes)
|
||||||
|
? new string[] { }
|
||||||
|
: request.IncludeItemTypes.Split(',');
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(request.IncludeItemTypes))
|
Func<BaseItem, bool> filter = i =>
|
||||||
{
|
{
|
||||||
var vals = request.IncludeItemTypes.Split(',');
|
if (includeTypes.Length > 0)
|
||||||
items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
|
{
|
||||||
}
|
if (!includeTypes.Contains(i.GetType().Name, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
IEnumerable<BaseItem> items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, filter);
|
||||||
|
|
||||||
var lookup = items
|
var lookup = items
|
||||||
.ToLookup(i => i.ProductionYear ?? -1)
|
.ToLookup(i => i.ProductionYear ?? -1)
|
||||||
@ -732,23 +752,22 @@ namespace MediaBrowser.Api.Library
|
|||||||
return ToOptimizedSerializedResultUsingCache(lookup);
|
return ToOptimizedSerializedResultUsingCache(lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThemeMediaResult GetSoundtrackSongs(string id, Guid? userId, bool inheritFromParent)
|
public ThemeMediaResult GetSoundtrackSongs(GetThemeMedia request, string id, Guid? userId, bool inheritFromParent)
|
||||||
{
|
{
|
||||||
var user = userId.HasValue ? _userManager.GetUserById(userId.Value) : null;
|
var user = userId.HasValue ? _userManager.GetUserById(userId.Value) : null;
|
||||||
|
|
||||||
var item = string.IsNullOrEmpty(id)
|
var item = string.IsNullOrEmpty(id)
|
||||||
? (userId.HasValue
|
? (userId.HasValue
|
||||||
? user.RootFolder
|
? user.RootFolder
|
||||||
: (Folder)_libraryManager.RootFolder)
|
: _libraryManager.RootFolder)
|
||||||
: _libraryManager.GetItemById(id);
|
: _libraryManager.GetItemById(id);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = GetSoundtrackSongIds(item, inheritFromParent)
|
var dtos = GetSoundtrackSongIds(item, inheritFromParent)
|
||||||
.Select(_libraryManager.GetItemById)
|
.Select(_libraryManager.GetItemById)
|
||||||
.OfType<MusicAlbum>()
|
.OfType<MusicAlbum>()
|
||||||
.SelectMany(i => i.RecursiveChildren)
|
.SelectMany(i => i.GetRecursiveChildren(a => a is Audio))
|
||||||
.OfType<Audio>()
|
|
||||||
.OrderBy(i => i.SortName)
|
.OrderBy(i => i.SortName)
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ using MediaBrowser.Controller;
|
|||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -18,7 +17,6 @@ namespace MediaBrowser.Api.Library
|
|||||||
/// Class GetDefaultVirtualFolders
|
/// Class GetDefaultVirtualFolders
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Library/VirtualFolders", "GET")]
|
[Route("/Library/VirtualFolders", "GET")]
|
||||||
[Route("/Users/{UserId}/VirtualFolders", "GET")]
|
|
||||||
public class GetVirtualFolders : IReturn<List<VirtualFolderInfo>>
|
public class GetVirtualFolders : IReturn<List<VirtualFolderInfo>>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -143,11 +141,6 @@ namespace MediaBrowser.Api.Library
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IServerApplicationPaths _appPaths;
|
private readonly IServerApplicationPaths _appPaths;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The _user manager
|
|
||||||
/// </summary>
|
|
||||||
private readonly IUserManager _userManager;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _library manager
|
/// The _library manager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -156,27 +149,21 @@ namespace MediaBrowser.Api.Library
|
|||||||
private readonly ILibraryMonitor _libraryMonitor;
|
private readonly ILibraryMonitor _libraryMonitor;
|
||||||
|
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="LibraryStructureService"/> class.
|
/// Initializes a new instance of the <see cref="LibraryStructureService" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="appPaths">The app paths.</param>
|
public LibraryStructureService(IServerApplicationPaths appPaths, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem)
|
||||||
/// <param name="userManager">The user manager.</param>
|
|
||||||
/// <param name="libraryManager">The library manager.</param>
|
|
||||||
public LibraryStructureService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, ILogger logger)
|
|
||||||
{
|
{
|
||||||
if (appPaths == null)
|
if (appPaths == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("appPaths");
|
throw new ArgumentNullException("appPaths");
|
||||||
}
|
}
|
||||||
|
|
||||||
_userManager = userManager;
|
|
||||||
_appPaths = appPaths;
|
_appPaths = appPaths;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_libraryMonitor = libraryMonitor;
|
_libraryMonitor = libraryMonitor;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -186,20 +173,9 @@ namespace MediaBrowser.Api.Library
|
|||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public object Get(GetVirtualFolders request)
|
public object Get(GetVirtualFolders request)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(request.UserId))
|
var result = _libraryManager.GetVirtualFolders().OrderBy(i => i.Name).ToList();
|
||||||
{
|
|
||||||
var result = _libraryManager.GetDefaultVirtualFolders().OrderBy(i => i.Name).ToList();
|
|
||||||
|
|
||||||
return ToOptimizedSerializedResultUsingCache(result);
|
return ToOptimizedSerializedResultUsingCache(result);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
|
||||||
|
|
||||||
var result = _libraryManager.GetVirtualFolders(user).OrderBy(i => i.Name).ToList();
|
|
||||||
|
|
||||||
return ToOptimizedSerializedResultUsingCache(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -348,7 +324,7 @@ namespace MediaBrowser.Api.Library
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Directory.Delete(path, true);
|
_fileSystem.DeleteDirectory(path, true);
|
||||||
|
|
||||||
// Need to add a delay here or directory watchers may still pick up the changes
|
// Need to add a delay here or directory watchers may still pick up the changes
|
||||||
var delayTask = Task.Delay(1000);
|
var delayTask = Task.Delay(1000);
|
||||||
|
@ -82,6 +82,10 @@
|
|||||||
<Compile Include="Playback\Hls\MpegDashService.cs" />
|
<Compile Include="Playback\Hls\MpegDashService.cs" />
|
||||||
<Compile Include="Playback\MediaInfoService.cs" />
|
<Compile Include="Playback\MediaInfoService.cs" />
|
||||||
<Compile Include="PlaylistService.cs" />
|
<Compile Include="PlaylistService.cs" />
|
||||||
|
<Compile Include="Reports\ReportFieldType.cs" />
|
||||||
|
<Compile Include="Reports\ReportResult.cs" />
|
||||||
|
<Compile Include="Reports\ReportsService.cs" />
|
||||||
|
<Compile Include="Reports\ReportRequests.cs" />
|
||||||
<Compile Include="StartupWizardService.cs" />
|
<Compile Include="StartupWizardService.cs" />
|
||||||
<Compile Include="Subtitles\SubtitleService.cs" />
|
<Compile Include="Subtitles\SubtitleService.cs" />
|
||||||
<Compile Include="Movies\CollectionService.cs" />
|
<Compile Include="Movies\CollectionService.cs" />
|
||||||
@ -110,7 +114,6 @@
|
|||||||
<Compile Include="NotificationsService.cs" />
|
<Compile Include="NotificationsService.cs" />
|
||||||
<Compile Include="PackageReviewService.cs" />
|
<Compile Include="PackageReviewService.cs" />
|
||||||
<Compile Include="PackageService.cs" />
|
<Compile Include="PackageService.cs" />
|
||||||
<Compile Include="Playback\BifService.cs" />
|
|
||||||
<Compile Include="Playback\Hls\BaseHlsService.cs" />
|
<Compile Include="Playback\Hls\BaseHlsService.cs" />
|
||||||
<Compile Include="Playback\Hls\DynamicHlsService.cs" />
|
<Compile Include="Playback\Hls\DynamicHlsService.cs" />
|
||||||
<Compile Include="Playback\Hls\HlsSegmentService.cs" />
|
<Compile Include="Playback\Hls\HlsSegmentService.cs" />
|
||||||
@ -131,6 +134,8 @@
|
|||||||
<Compile Include="SearchService.cs" />
|
<Compile Include="SearchService.cs" />
|
||||||
<Compile Include="Session\SessionsService.cs" />
|
<Compile Include="Session\SessionsService.cs" />
|
||||||
<Compile Include="SimilarItemsHelper.cs" />
|
<Compile Include="SimilarItemsHelper.cs" />
|
||||||
|
<Compile Include="Sync\SyncJobWebSocketListener.cs" />
|
||||||
|
<Compile Include="Sync\SyncJobsWebSocketListener.cs" />
|
||||||
<Compile Include="Sync\SyncService.cs" />
|
<Compile Include="Sync\SyncService.cs" />
|
||||||
<Compile Include="System\ActivityLogService.cs" />
|
<Compile Include="System\ActivityLogService.cs" />
|
||||||
<Compile Include="System\ActivityLogWebSocketListener.cs" />
|
<Compile Include="System\ActivityLogWebSocketListener.cs" />
|
||||||
|
@ -71,7 +71,7 @@ namespace MediaBrowser.Api.Movies
|
|||||||
|
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dto = _dtoService.GetBaseItemDto(item, dtoOptions);
|
var dto = _dtoService.GetBaseItemDto(item, dtoOptions);
|
||||||
|
|
||||||
|
@ -121,8 +121,7 @@ namespace MediaBrowser.Api.Movies
|
|||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(request.UserId.Value);
|
var user = _userManager.GetUserById(request.UserId.Value);
|
||||||
|
|
||||||
var movies = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId)
|
IEnumerable<BaseItem> movies = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Movie);
|
||||||
.Where(i => i is Movie);
|
|
||||||
|
|
||||||
movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies);
|
movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies);
|
||||||
|
|
||||||
@ -157,7 +156,7 @@ namespace MediaBrowser.Api.Movies
|
|||||||
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
|
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
dtoOptions.Fields = request.GetItemFields().ToList();
|
dtoOptions.Fields = request.GetItemFields().ToList();
|
||||||
|
|
||||||
@ -174,13 +173,11 @@ namespace MediaBrowser.Api.Movies
|
|||||||
(request.UserId.HasValue ? user.RootFolder :
|
(request.UserId.HasValue ? user.RootFolder :
|
||||||
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
|
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var fields = request.GetItemFields().ToList();
|
Func<BaseItem, bool> filter = i => i.Id != item.Id && includeInSearch(i);
|
||||||
|
|
||||||
var inputItems = user == null
|
var inputItems = user == null
|
||||||
? _libraryManager.RootFolder.GetRecursiveChildren().Where(i => i.Id != item.Id)
|
? _libraryManager.RootFolder.GetRecursiveChildren(filter)
|
||||||
: user.RootFolder.GetRecursiveChildren(user).Where(i => i.Id != item.Id);
|
: user.RootFolder.GetRecursiveChildren(user, filter);
|
||||||
|
|
||||||
inputItems = inputItems.Where(includeInSearch);
|
|
||||||
|
|
||||||
var list = inputItems.ToList();
|
var list = inputItems.ToList();
|
||||||
|
|
||||||
@ -225,10 +222,12 @@ namespace MediaBrowser.Api.Movies
|
|||||||
{
|
{
|
||||||
returnItems = returnItems.Take(request.Limit.Value);
|
returnItems = returnItems.Take(request.Limit.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var result = new ItemsResult
|
var result = new ItemsResult
|
||||||
{
|
{
|
||||||
Items = returnItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray(),
|
Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
|
||||||
|
|
||||||
TotalRecordCount = items.Count
|
TotalRecordCount = items.Count
|
||||||
};
|
};
|
||||||
@ -351,7 +350,7 @@ namespace MediaBrowser.Api.Movies
|
|||||||
BaselineItemName = director,
|
BaselineItemName = director,
|
||||||
CategoryId = director.GetMD5().ToString("N"),
|
CategoryId = director.GetMD5().ToString("N"),
|
||||||
RecommendationType = type,
|
RecommendationType = type,
|
||||||
Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
|
Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).ToArray()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,7 +374,7 @@ namespace MediaBrowser.Api.Movies
|
|||||||
BaselineItemName = name,
|
BaselineItemName = name,
|
||||||
CategoryId = name.GetMD5().ToString("N"),
|
CategoryId = name.GetMD5().ToString("N"),
|
||||||
RecommendationType = type,
|
RecommendationType = type,
|
||||||
Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
|
Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).ToArray()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -399,7 +398,7 @@ namespace MediaBrowser.Api.Movies
|
|||||||
BaselineItemName = item.Name,
|
BaselineItemName = item.Name,
|
||||||
CategoryId = item.Id.ToString("N"),
|
CategoryId = item.Id.ToString("N"),
|
||||||
RecommendationType = type,
|
RecommendationType = type,
|
||||||
Items = similar.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
|
Items = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).ToArray()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,9 @@ namespace MediaBrowser.Api.Movies
|
|||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public object Get(GetSimilarTrailers request)
|
public object Get(GetSimilarTrailers request)
|
||||||
{
|
{
|
||||||
var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
|
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
|
||||||
_itemRepo,
|
_itemRepo,
|
||||||
_libraryManager,
|
_libraryManager,
|
||||||
_userDataRepository,
|
_userDataRepository,
|
||||||
@ -119,9 +121,9 @@ namespace MediaBrowser.Api.Movies
|
|||||||
|
|
||||||
var pagedItems = ApplyPaging(request, itemsArray);
|
var pagedItems = ApplyPaging(request, itemsArray);
|
||||||
|
|
||||||
var fields = request.GetItemFields().ToList();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray();
|
var returnItems = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user).ToArray();
|
||||||
|
|
||||||
return new ItemsResult
|
return new ItemsResult
|
||||||
{
|
{
|
||||||
|
@ -50,7 +50,9 @@ namespace MediaBrowser.Api.Music
|
|||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public object Get(GetSimilarAlbums request)
|
public object Get(GetSimilarAlbums request)
|
||||||
{
|
{
|
||||||
var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
|
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
|
||||||
_itemRepo,
|
_itemRepo,
|
||||||
_libraryManager,
|
_libraryManager,
|
||||||
_userDataRepository,
|
_userDataRepository,
|
||||||
@ -75,14 +77,14 @@ namespace MediaBrowser.Api.Music
|
|||||||
var album1 = (MusicAlbum)item1;
|
var album1 = (MusicAlbum)item1;
|
||||||
var album2 = (MusicAlbum)item2;
|
var album2 = (MusicAlbum)item2;
|
||||||
|
|
||||||
var artists1 = album1.GetRecursiveChildren()
|
var artists1 = album1.GetRecursiveChildren(i => i is IHasArtist)
|
||||||
.OfType<Audio>()
|
.Cast<IHasArtist>()
|
||||||
.SelectMany(i => i.AllArtists)
|
.SelectMany(i => i.AllArtists)
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var artists2 = album2.GetRecursiveChildren()
|
var artists2 = album2.GetRecursiveChildren(i => i is IHasArtist)
|
||||||
.OfType<Audio>()
|
.Cast<IHasArtist>()
|
||||||
.SelectMany(i => i.AllArtists)
|
.SelectMany(i => i.AllArtists)
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||||
|
@ -73,44 +73,44 @@ namespace MediaBrowser.Api.Music
|
|||||||
|
|
||||||
public object Get(GetInstantMixFromArtistId request)
|
public object Get(GetInstantMixFromArtistId request)
|
||||||
{
|
{
|
||||||
var item = (MusicArtist)_libraryManager.GetItemById(request.Id);
|
var item = _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var user = _userManager.GetUserById(request.UserId.Value);
|
var user = _userManager.GetUserById(request.UserId.Value);
|
||||||
|
|
||||||
var items = _musicManager.GetInstantMixFromArtist(item.Name, user);
|
var items = _musicManager.GetInstantMixFromItem(item, user);
|
||||||
|
|
||||||
return GetResult(items, user, request);
|
return GetResult(items, user, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetInstantMixFromMusicGenreId request)
|
public object Get(GetInstantMixFromMusicGenreId request)
|
||||||
{
|
{
|
||||||
var item = (MusicGenre)_libraryManager.GetItemById(request.Id);
|
var item = _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var user = _userManager.GetUserById(request.UserId.Value);
|
var user = _userManager.GetUserById(request.UserId.Value);
|
||||||
|
|
||||||
var items = _musicManager.GetInstantMixFromGenres(new[] { item.Name }, user);
|
var items = _musicManager.GetInstantMixFromItem(item, user);
|
||||||
|
|
||||||
return GetResult(items, user, request);
|
return GetResult(items, user, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetInstantMixFromSong request)
|
public object Get(GetInstantMixFromSong request)
|
||||||
{
|
{
|
||||||
var item = (Audio)_libraryManager.GetItemById(request.Id);
|
var item = _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var user = _userManager.GetUserById(request.UserId.Value);
|
var user = _userManager.GetUserById(request.UserId.Value);
|
||||||
|
|
||||||
var items = _musicManager.GetInstantMixFromSong(item, user);
|
var items = _musicManager.GetInstantMixFromItem(item, user);
|
||||||
|
|
||||||
return GetResult(items, user, request);
|
return GetResult(items, user, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetInstantMixFromAlbum request)
|
public object Get(GetInstantMixFromAlbum request)
|
||||||
{
|
{
|
||||||
var album = (MusicAlbum)_libraryManager.GetItemById(request.Id);
|
var album = _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var user = _userManager.GetUserById(request.UserId.Value);
|
var user = _userManager.GetUserById(request.UserId.Value);
|
||||||
|
|
||||||
var items = _musicManager.GetInstantMixFromAlbum(album, user);
|
var items = _musicManager.GetInstantMixFromItem(album, user);
|
||||||
|
|
||||||
return GetResult(items, user, request);
|
return GetResult(items, user, request);
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ namespace MediaBrowser.Api.Music
|
|||||||
|
|
||||||
var user = _userManager.GetUserById(request.UserId.Value);
|
var user = _userManager.GetUserById(request.UserId.Value);
|
||||||
|
|
||||||
var items = _musicManager.GetInstantMixFromPlaylist(playlist, user);
|
var items = _musicManager.GetInstantMixFromItem(playlist, user);
|
||||||
|
|
||||||
return GetResult(items, user, request);
|
return GetResult(items, user, request);
|
||||||
}
|
}
|
||||||
@ -146,8 +146,6 @@ namespace MediaBrowser.Api.Music
|
|||||||
|
|
||||||
private object GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request)
|
private object GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request)
|
||||||
{
|
{
|
||||||
var fields = request.GetItemFields().ToList();
|
|
||||||
|
|
||||||
var list = items.ToList();
|
var list = items.ToList();
|
||||||
|
|
||||||
var result = new ItemsResult
|
var result = new ItemsResult
|
||||||
@ -155,10 +153,9 @@ namespace MediaBrowser.Api.Music
|
|||||||
TotalRecordCount = list.Count
|
TotalRecordCount = list.Count
|
||||||
};
|
};
|
||||||
|
|
||||||
var dtos = list.Take(request.Limit ?? list.Count)
|
var dtoOptions = GetDtoOptions(request);
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i, fields, user));
|
|
||||||
|
|
||||||
result.Items = dtos.ToArray();
|
result.Items = _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user).ToArray();
|
||||||
|
|
||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Controller.Devices;
|
||||||
|
using MediaBrowser.Model.Extensions;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
@ -66,14 +67,16 @@ namespace MediaBrowser.Api.Playback
|
|||||||
|
|
||||||
protected ILiveTvManager LiveTvManager { get; private set; }
|
protected ILiveTvManager LiveTvManager { get; private set; }
|
||||||
protected IDlnaManager DlnaManager { get; private set; }
|
protected IDlnaManager DlnaManager { get; private set; }
|
||||||
|
protected IDeviceManager DeviceManager { get; private set; }
|
||||||
protected IChannelManager ChannelManager { get; private set; }
|
protected IChannelManager ChannelManager { get; private set; }
|
||||||
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder)
|
protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager)
|
||||||
{
|
{
|
||||||
|
DeviceManager = deviceManager;
|
||||||
SubtitleEncoder = subtitleEncoder;
|
SubtitleEncoder = subtitleEncoder;
|
||||||
ChannelManager = channelManager;
|
ChannelManager = channelManager;
|
||||||
DlnaManager = dlnaManager;
|
DlnaManager = dlnaManager;
|
||||||
@ -119,8 +122,8 @@ namespace MediaBrowser.Api.Playback
|
|||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private string GetOutputFilePath(StreamState state)
|
private string GetOutputFilePath(StreamState state)
|
||||||
{
|
{
|
||||||
var folder = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower());
|
var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath;
|
||||||
|
|
||||||
var outputFileExtension = GetOutputFileExtension(state);
|
var outputFileExtension = GetOutputFileExtension(state);
|
||||||
|
|
||||||
var data = GetCommandLineArguments("dummy\\dummy", "dummyTranscodingId", state, false);
|
var data = GetCommandLineArguments("dummy\\dummy", "dummyTranscodingId", state, false);
|
||||||
@ -320,13 +323,13 @@ namespace MediaBrowser.Api.Playback
|
|||||||
switch (qualitySetting)
|
switch (qualitySetting)
|
||||||
{
|
{
|
||||||
case EncodingQuality.HighSpeed:
|
case EncodingQuality.HighSpeed:
|
||||||
param += " -crf 23";
|
param += " -subq 0 -crf 23";
|
||||||
break;
|
break;
|
||||||
case EncodingQuality.HighQuality:
|
case EncodingQuality.HighQuality:
|
||||||
param += " -crf 20";
|
param += " -subq 3 -crf 20";
|
||||||
break;
|
break;
|
||||||
case EncodingQuality.MaxQuality:
|
case EncodingQuality.MaxQuality:
|
||||||
param += " -crf 18";
|
param += " -subq 6 -crf 18";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -349,6 +352,41 @@ namespace MediaBrowser.Api.Playback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// h264 (h264_qsv)
|
||||||
|
else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
switch (qualitySetting)
|
||||||
|
{
|
||||||
|
case EncodingQuality.HighSpeed:
|
||||||
|
param = "-preset 7";
|
||||||
|
break;
|
||||||
|
case EncodingQuality.HighQuality:
|
||||||
|
param = "-preset 4";
|
||||||
|
break;
|
||||||
|
case EncodingQuality.MaxQuality:
|
||||||
|
param = "-preset 1";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// h264 (libnvenc)
|
||||||
|
else if (string.Equals(videoCodec, "libnvenc", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
switch (qualitySetting)
|
||||||
|
{
|
||||||
|
case EncodingQuality.HighSpeed:
|
||||||
|
param = "-preset high-performance";
|
||||||
|
break;
|
||||||
|
case EncodingQuality.HighQuality:
|
||||||
|
param = "";
|
||||||
|
break;
|
||||||
|
case EncodingQuality.MaxQuality:
|
||||||
|
param = "-preset high-quality";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// webm
|
// webm
|
||||||
else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@ -426,10 +464,50 @@ namespace MediaBrowser.Api.Playback
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(state.VideoRequest.Level))
|
if (!string.IsNullOrEmpty(state.VideoRequest.Level))
|
||||||
{
|
{
|
||||||
param += " -level " + state.VideoRequest.Level;
|
// h264_qsv and libnvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
|
||||||
|
if (String.Equals(H264Encoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || String.Equals(H264Encoder, "libnvenc", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
switch (state.VideoRequest.Level)
|
||||||
|
{
|
||||||
|
case "30":
|
||||||
|
param += " -level 3";
|
||||||
|
break;
|
||||||
|
case "31":
|
||||||
|
param += " -level 3.1";
|
||||||
|
break;
|
||||||
|
case "32":
|
||||||
|
param += " -level 3.2";
|
||||||
|
break;
|
||||||
|
case "40":
|
||||||
|
param += " -level 4";
|
||||||
|
break;
|
||||||
|
case "41":
|
||||||
|
param += " -level 4.1";
|
||||||
|
break;
|
||||||
|
case "42":
|
||||||
|
param += " -level 4.2";
|
||||||
|
break;
|
||||||
|
case "50":
|
||||||
|
param += " -level 5";
|
||||||
|
break;
|
||||||
|
case "51":
|
||||||
|
param += " -level 5.1";
|
||||||
|
break;
|
||||||
|
case "52":
|
||||||
|
param += " -level 5.2";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
param += " -level " + state.VideoRequest.Level;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
param += " -level " + state.VideoRequest.Level;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return param;
|
return "-pix_fmt yuv420p " + param;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string GetAudioFilterParam(StreamState state, bool isHls)
|
protected string GetAudioFilterParam(StreamState state, bool isHls)
|
||||||
@ -567,6 +645,11 @@ namespace MediaBrowser.Api.Playback
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
filters[filters.Count - 1] += ":flags=fast_bilinear";
|
||||||
|
}
|
||||||
|
|
||||||
var output = string.Empty;
|
var output = string.Empty;
|
||||||
|
|
||||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
|
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
|
||||||
@ -606,7 +689,7 @@ namespace MediaBrowser.Api.Playback
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
|
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
|
||||||
{
|
{
|
||||||
var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.SubtitleStream.Language);
|
var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(charenc))
|
if (!string.IsNullOrEmpty(charenc))
|
||||||
{
|
{
|
||||||
@ -834,7 +917,7 @@ namespace MediaBrowser.Api.Playback
|
|||||||
{
|
{
|
||||||
if (SupportsThrottleWithStream)
|
if (SupportsThrottleWithStream)
|
||||||
{
|
{
|
||||||
var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/mediabrowser/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId;
|
var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId;
|
||||||
|
|
||||||
url += "&transcodingJobId=" + transcodingJobId;
|
url += "&transcodingJobId=" + transcodingJobId;
|
||||||
|
|
||||||
@ -1183,6 +1266,22 @@ namespace MediaBrowser.Api.Playback
|
|||||||
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
|
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// h264_qsv
|
||||||
|
if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "libnvenc", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (hasFixedResolution)
|
||||||
|
{
|
||||||
|
if (isHls)
|
||||||
|
{
|
||||||
|
return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format(" -b:v {0} -maxrate ({0}*1.2) -bufsize ({0}*2)", bitrate.Value.ToString(UsCulture));
|
||||||
|
}
|
||||||
|
|
||||||
// H264
|
// H264
|
||||||
if (hasFixedResolution)
|
if (hasFixedResolution)
|
||||||
{
|
{
|
||||||
@ -1991,9 +2090,26 @@ namespace MediaBrowser.Api.Playback
|
|||||||
headers[key] = Request.Headers[key];
|
headers[key] = Request.Headers[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
state.DeviceProfile = string.IsNullOrWhiteSpace(state.Request.DeviceProfileId) ?
|
if (!string.IsNullOrWhiteSpace(state.Request.DeviceProfileId))
|
||||||
DlnaManager.GetProfile(headers) :
|
{
|
||||||
DlnaManager.GetProfile(state.Request.DeviceProfileId);
|
state.DeviceProfile = DlnaManager.GetProfile(state.Request.DeviceProfileId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(state.Request.DeviceId))
|
||||||
|
{
|
||||||
|
var caps = DeviceManager.GetCapabilities(state.Request.DeviceId);
|
||||||
|
|
||||||
|
if (caps != null)
|
||||||
|
{
|
||||||
|
state.DeviceProfile = caps.DeviceProfile;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.DeviceProfile = DlnaManager.GetProfile(headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var profile = state.DeviceProfile;
|
var profile = state.DeviceProfile;
|
||||||
|
|
||||||
|
@ -1,186 +0,0 @@
|
|||||||
using MediaBrowser.Common.IO;
|
|
||||||
using MediaBrowser.Controller;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
|
||||||
using ServiceStack;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback
|
|
||||||
{
|
|
||||||
[Route("/Videos/{Id}/index.bif", "GET")]
|
|
||||||
public class GetBifFile
|
|
||||||
{
|
|
||||||
[ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
|
||||||
public string MediaSourceId { get; set; }
|
|
||||||
|
|
||||||
[ApiMember(Name = "MaxWidth", Description = "Optional. The maximum horizontal resolution of the encoded video.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
|
||||||
public int? MaxWidth { get; set; }
|
|
||||||
|
|
||||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
|
||||||
public string Id { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BifService : BaseApiService
|
|
||||||
{
|
|
||||||
private readonly IServerApplicationPaths _appPaths;
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
|
||||||
private readonly IFileSystem _fileSystem;
|
|
||||||
|
|
||||||
public BifService(IServerApplicationPaths appPaths, ILibraryManager libraryManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem)
|
|
||||||
{
|
|
||||||
_appPaths = appPaths;
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
_mediaEncoder = mediaEncoder;
|
|
||||||
_fileSystem = fileSystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Get(GetBifFile request)
|
|
||||||
{
|
|
||||||
return ToStaticFileResult(GetBifFile(request).Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetBifFile(GetBifFile request)
|
|
||||||
{
|
|
||||||
var widthVal = request.MaxWidth.HasValue ? request.MaxWidth.Value.ToString(CultureInfo.InvariantCulture) : string.Empty;
|
|
||||||
|
|
||||||
var item = _libraryManager.GetItemById(request.Id);
|
|
||||||
var mediaSources = ((IHasMediaSources)item).GetMediaSources(false).ToList();
|
|
||||||
var mediaSource = mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId)) ?? mediaSources.First();
|
|
||||||
|
|
||||||
var path = Path.Combine(_appPaths.ImageCachePath, "bif", request.Id, request.MediaSourceId, widthVal, "index.bif");
|
|
||||||
|
|
||||||
if (File.Exists(path))
|
|
||||||
{
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
var protocol = mediaSource.Protocol;
|
|
||||||
|
|
||||||
var inputPath = MediaEncoderHelpers.GetInputArgument(mediaSource.Path, protocol, null, mediaSource.PlayableStreamFileNames);
|
|
||||||
|
|
||||||
var semaphore = GetLock(path);
|
|
||||||
|
|
||||||
await semaphore.WaitAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (File.Exists(path))
|
|
||||||
{
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _mediaEncoder.ExtractVideoImagesOnInterval(inputPath, protocol, mediaSource.Video3DFormat,
|
|
||||||
TimeSpan.FromSeconds(10), Path.GetDirectoryName(path), "img_", request.MaxWidth, CancellationToken.None)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
var images = new DirectoryInfo(Path.GetDirectoryName(path))
|
|
||||||
.EnumerateFiles()
|
|
||||||
.Where(img => string.Equals(img.Extension, ".jpg", StringComparison.Ordinal))
|
|
||||||
.OrderBy(i => i.FullName)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
using (var fs = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
|
|
||||||
{
|
|
||||||
var magicNumber = new byte[] { 0x89, 0x42, 0x49, 0x46, 0x0d, 0x0a, 0x1a, 0x0a };
|
|
||||||
await fs.WriteAsync(magicNumber, 0, magicNumber.Length);
|
|
||||||
|
|
||||||
// version
|
|
||||||
var bytes = GetBytes(0);
|
|
||||||
await fs.WriteAsync(bytes, 0, bytes.Length);
|
|
||||||
|
|
||||||
// image count
|
|
||||||
bytes = GetBytes(images.Count);
|
|
||||||
await fs.WriteAsync(bytes, 0, bytes.Length);
|
|
||||||
|
|
||||||
// interval in ms
|
|
||||||
bytes = GetBytes(10000);
|
|
||||||
await fs.WriteAsync(bytes, 0, bytes.Length);
|
|
||||||
|
|
||||||
// reserved
|
|
||||||
for (var i = 20; i <= 63; i++)
|
|
||||||
{
|
|
||||||
bytes = new byte[] { 0x00 };
|
|
||||||
await fs.WriteAsync(bytes, 0, bytes.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the bif index
|
|
||||||
var index = 0;
|
|
||||||
long imageOffset = 64 + (8 * images.Count) + 8;
|
|
||||||
|
|
||||||
foreach (var img in images)
|
|
||||||
{
|
|
||||||
bytes = GetBytes(index);
|
|
||||||
await fs.WriteAsync(bytes, 0, bytes.Length);
|
|
||||||
|
|
||||||
bytes = GetBytes(imageOffset);
|
|
||||||
await fs.WriteAsync(bytes, 0, bytes.Length);
|
|
||||||
|
|
||||||
imageOffset += img.Length;
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes = new byte[] { 0xff, 0xff, 0xff, 0xff };
|
|
||||||
await fs.WriteAsync(bytes, 0, bytes.Length);
|
|
||||||
|
|
||||||
bytes = GetBytes(imageOffset);
|
|
||||||
await fs.WriteAsync(bytes, 0, bytes.Length);
|
|
||||||
|
|
||||||
// write the images
|
|
||||||
foreach (var img in images)
|
|
||||||
{
|
|
||||||
using (var imgStream = _fileSystem.GetFileStream(img.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
|
||||||
{
|
|
||||||
await imgStream.CopyToAsync(fs).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
semaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] GetBytes(int value)
|
|
||||||
{
|
|
||||||
byte[] bytes = BitConverter.GetBytes(value);
|
|
||||||
if (!BitConverter.IsLittleEndian)
|
|
||||||
Array.Reverse(bytes);
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] GetBytes(long value)
|
|
||||||
{
|
|
||||||
var intVal = Convert.ToInt32(value);
|
|
||||||
return GetBytes(intVal);
|
|
||||||
|
|
||||||
//byte[] bytes = BitConverter.GetBytes(value);
|
|
||||||
//if (BitConverter.IsLittleEndian)
|
|
||||||
// Array.Reverse(bytes);
|
|
||||||
//return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<string, SemaphoreSlim> SemaphoreLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the lock.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">The filename.</param>
|
|
||||||
/// <returns>System.Object.</returns>
|
|
||||||
private static SemaphoreSlim GetLock(string filename)
|
|
||||||
{
|
|
||||||
return SemaphoreLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +1,20 @@
|
|||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.IO;
|
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Devices;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
|
using MediaBrowser.Model.Extensions;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Net;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback.Hls
|
namespace MediaBrowser.Api.Playback.Hls
|
||||||
{
|
{
|
||||||
@ -23,8 +23,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseHlsService : BaseStreamingService
|
public abstract class BaseHlsService : BaseStreamingService
|
||||||
{
|
{
|
||||||
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder)
|
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager)
|
||||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Controller.Devices;
|
||||||
|
using MediaBrowser.Model.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
@ -62,38 +63,31 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
|
|
||||||
public class DynamicHlsService : BaseHlsService
|
public class DynamicHlsService : BaseHlsService
|
||||||
{
|
{
|
||||||
protected INetworkManager NetworkManager { get; private set; }
|
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager)
|
||||||
|
|
||||||
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, INetworkManager networkManager)
|
|
||||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
|
|
||||||
{
|
{
|
||||||
NetworkManager = networkManager;
|
NetworkManager = networkManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetMasterHlsVideoStream request)
|
protected INetworkManager NetworkManager { get; private set; }
|
||||||
{
|
|
||||||
var result = GetAsync(request, "GET").Result;
|
|
||||||
|
|
||||||
return result;
|
public Task<object> Get(GetMasterHlsVideoStream request)
|
||||||
|
{
|
||||||
|
return GetAsync(request, "GET");
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Head(GetMasterHlsVideoStream request)
|
public Task<object> Head(GetMasterHlsVideoStream request)
|
||||||
{
|
{
|
||||||
var result = GetAsync(request, "HEAD").Result;
|
return GetAsync(request, "HEAD");
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetMainHlsVideoStream request)
|
public Task<object> Get(GetMainHlsVideoStream request)
|
||||||
{
|
{
|
||||||
var result = GetPlaylistAsync(request, "main").Result;
|
return GetPlaylistAsync(request, "main");
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetDynamicHlsVideoSegment request)
|
public Task<object> Get(GetDynamicHlsVideoSegment request)
|
||||||
{
|
{
|
||||||
return GetDynamicSegment(request, request.SegmentId).Result;
|
return GetDynamicSegment(request, request.SegmentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<object> GetDynamicSegment(VideoStreamRequest request, string segmentId)
|
private async Task<object> GetDynamicSegment(VideoStreamRequest request, string segmentId)
|
||||||
@ -210,10 +204,10 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Delete(file.FullName);
|
FileSystem.DeleteFile(file.FullName);
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback.Hls
|
namespace MediaBrowser.Api.Playback.Hls
|
||||||
{
|
{
|
||||||
@ -66,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
{
|
{
|
||||||
var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
|
var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
|
||||||
|
|
||||||
file = Path.Combine(_appPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower(), file);
|
file = Path.Combine(_appPaths.TranscodingTempPath, file);
|
||||||
|
|
||||||
return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite);
|
return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite);
|
||||||
}
|
}
|
||||||
@ -85,7 +81,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
{
|
{
|
||||||
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
|
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
|
||||||
|
|
||||||
file = Path.Combine(_appPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower(), file);
|
file = Path.Combine(_appPaths.TranscodingTempPath, file);
|
||||||
|
|
||||||
return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite);
|
return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Devices;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
@ -50,14 +51,13 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
|
|
||||||
public class MpegDashService : BaseHlsService
|
public class MpegDashService : BaseHlsService
|
||||||
{
|
{
|
||||||
protected INetworkManager NetworkManager { get; private set; }
|
public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager)
|
||||||
|
|
||||||
public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, INetworkManager networkManager)
|
|
||||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
|
|
||||||
{
|
{
|
||||||
NetworkManager = networkManager;
|
NetworkManager = networkManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected INetworkManager NetworkManager { get; private set; }
|
||||||
|
|
||||||
public object Get(GetMasterManifest request)
|
public object Get(GetMasterManifest request)
|
||||||
{
|
{
|
||||||
var result = GetAsync(request, "GET").Result;
|
var result = GetAsync(request, "GET").Result;
|
||||||
@ -489,7 +489,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Delete(file.FullName);
|
FileSystem.DeleteFile(file.FullName);
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
@ -625,7 +625,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
|
|
||||||
protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
|
protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
|
||||||
{
|
{
|
||||||
// test url http://192.168.1.2:8096/mediabrowser/videos/233e8905d559a8f230db9bffd2ac9d6d/master.mpd?mediasourceid=233e8905d559a8f230db9bffd2ac9d6d&videocodec=h264&audiocodec=aac&maxwidth=1280&videobitrate=500000&audiobitrate=128000&profile=baseline&level=3
|
// test url http://192.168.1.2:8096/videos/233e8905d559a8f230db9bffd2ac9d6d/master.mpd?mediasourceid=233e8905d559a8f230db9bffd2ac9d6d&videocodec=h264&audiocodec=aac&maxwidth=1280&videobitrate=500000&audiobitrate=128000&profile=baseline&level=3
|
||||||
// Good info on i-frames http://blog.streamroot.io/encode-multi-bitrate-videos-mpeg-dash-mse-based-media-players/
|
// Good info on i-frames http://blog.streamroot.io/encode-multi-bitrate-videos-mpeg-dash-mse-based-media-players/
|
||||||
|
|
||||||
var threads = GetNumberOfThreads(state, false);
|
var threads = GetNumberOfThreads(state, false);
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Devices;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
@ -57,8 +57,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class VideoHlsService : BaseHlsService
|
public class VideoHlsService : BaseHlsService
|
||||||
{
|
{
|
||||||
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder)
|
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager)
|
||||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +70,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
{
|
{
|
||||||
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
|
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
|
||||||
|
|
||||||
file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower(), file);
|
file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, file);
|
||||||
|
|
||||||
return ResultFactory.GetStaticFileResult(Request, file);
|
return ResultFactory.GetStaticFileResult(Request, file);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Devices;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
@ -31,7 +32,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioService : BaseProgressiveStreamingService
|
public class AudioService : BaseProgressiveStreamingService
|
||||||
{
|
{
|
||||||
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, imageProcessor, httpClient)
|
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager, imageProcessor, httpClient)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using System.Linq;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.IO;
|
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Devices;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
@ -15,6 +15,7 @@ using ServiceStack.Web;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -28,8 +29,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||||||
protected readonly IImageProcessor ImageProcessor;
|
protected readonly IImageProcessor ImageProcessor;
|
||||||
protected readonly IHttpClient HttpClient;
|
protected readonly IHttpClient HttpClient;
|
||||||
|
|
||||||
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IImageProcessor imageProcessor, IHttpClient httpClient)
|
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager)
|
||||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
|
|
||||||
{
|
{
|
||||||
ImageProcessor = imageProcessor;
|
ImageProcessor = imageProcessor;
|
||||||
HttpClient = httpClient;
|
HttpClient = httpClient;
|
||||||
|
@ -2,6 +2,7 @@ using MediaBrowser.Common.IO;
|
|||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Devices;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
@ -62,7 +63,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class VideoService : BaseProgressiveStreamingService
|
public class VideoService : BaseProgressiveStreamingService
|
||||||
{
|
{
|
||||||
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, imageProcessor, httpClient)
|
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager, imageProcessor, httpClient)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +97,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||||||
|
|
||||||
if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
// Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
|
||||||
format = " -f mp4 -movflags frag_keyframe+empty_moov";
|
format = " -f mp4 -movflags frag_keyframe+empty_moov";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,10 @@ namespace MediaBrowser.Api.Playback
|
|||||||
/// <param name="responseStream">The response stream.</param>
|
/// <param name="responseStream">The response stream.</param>
|
||||||
public void WriteTo(Stream responseStream)
|
public void WriteTo(Stream responseStream)
|
||||||
{
|
{
|
||||||
_response.Content.CopyTo(responseStream, 819200);
|
using (_response)
|
||||||
|
{
|
||||||
|
_response.Content.CopyTo(responseStream, 819200);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,9 +151,10 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
items = items.Take(request.Limit.Value).ToArray();
|
items = items.Take(request.Limit.Value).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
var dtos = items
|
var dtoOptions = GetDtoOptions(request);
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i.Item2, request.GetItemFields().ToList(), user))
|
|
||||||
|
var dtos = _dtoService.GetBaseItemDtos(items.Select(i => i.Item2), dtoOptions, user)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var index = 0;
|
var index = 0;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Threading;
|
using MediaBrowser.Common;
|
||||||
using MediaBrowser.Common;
|
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Security;
|
using MediaBrowser.Common.Security;
|
||||||
using MediaBrowser.Common.Updates;
|
using MediaBrowser.Common.Updates;
|
||||||
@ -8,12 +7,12 @@ using MediaBrowser.Model.Entities;
|
|||||||
using MediaBrowser.Model.Plugins;
|
using MediaBrowser.Model.Plugins;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using ServiceStack.Text.Controller;
|
|
||||||
using ServiceStack.Web;
|
using ServiceStack.Web;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Api
|
namespace MediaBrowser.Api
|
||||||
@ -236,8 +235,7 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
||||||
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var id = new Guid(GetPathValue(1));
|
||||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
|
||||||
|
|
||||||
var plugin = _appHost.Plugins.First(p => p.Id == id);
|
var plugin = _appHost.Plugins.First(p => p.Id == id);
|
||||||
|
|
||||||
|
9
MediaBrowser.Api/Reports/ReportFieldType.cs
Normal file
9
MediaBrowser.Api/Reports/ReportFieldType.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public enum ReportFieldType
|
||||||
|
{
|
||||||
|
String,
|
||||||
|
Boolean
|
||||||
|
}
|
||||||
|
}
|
33
MediaBrowser.Api/Reports/ReportRequests.cs
Normal file
33
MediaBrowser.Api/Reports/ReportRequests.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using ServiceStack;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public class BaseReportRequest : IReturn<ReportResult>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specify this to localize the search to a specific item or folder. Omit to use the root.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The parent id.</value>
|
||||||
|
[ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
|
public string ParentId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Skips over a given number of items within the results. Use for paging.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The start index.</value>
|
||||||
|
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? StartIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of items to return
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The limit.</value>
|
||||||
|
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? Limit { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Reports/Items", "GET", Summary = "Gets reports based on library items")]
|
||||||
|
public class GetItemReport : BaseReportRequest
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
16
MediaBrowser.Api/Reports/ReportResult.cs
Normal file
16
MediaBrowser.Api/Reports/ReportResult.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public class ReportResult
|
||||||
|
{
|
||||||
|
public List<List<string>> Rows { get; set; }
|
||||||
|
public List<ReportFieldType> Columns { get; set; }
|
||||||
|
|
||||||
|
public ReportResult()
|
||||||
|
{
|
||||||
|
Rows = new List<List<string>>();
|
||||||
|
Columns = new List<ReportFieldType>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
MediaBrowser.Api/Reports/ReportsService.cs
Normal file
64
MediaBrowser.Api/Reports/ReportsService.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public class ReportsService : BaseApiService
|
||||||
|
{
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
public ReportsService(ILibraryManager libraryManager)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<object> Get(GetItemReport request)
|
||||||
|
{
|
||||||
|
var queryResult = await GetQueryResult(request).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var reportResult = GetReportResult(queryResult);
|
||||||
|
|
||||||
|
return ToOptimizedResult(reportResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportResult GetReportResult(QueryResult<BaseItem> queryResult)
|
||||||
|
{
|
||||||
|
var reportResult = new ReportResult();
|
||||||
|
|
||||||
|
// Fill rows and columns
|
||||||
|
|
||||||
|
return reportResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<QueryResult<BaseItem>> GetQueryResult(BaseReportRequest request)
|
||||||
|
{
|
||||||
|
// Placeholder in case needed later
|
||||||
|
User user = null;
|
||||||
|
|
||||||
|
var parentItem = string.IsNullOrEmpty(request.ParentId) ?
|
||||||
|
(user == null ? _libraryManager.RootFolder : user.RootFolder) :
|
||||||
|
_libraryManager.GetItemById(request.ParentId);
|
||||||
|
|
||||||
|
return ((Folder)parentItem).GetItems(GetItemsQuery(request, user));
|
||||||
|
}
|
||||||
|
|
||||||
|
private InternalItemsQuery GetItemsQuery(BaseReportRequest request, User user)
|
||||||
|
{
|
||||||
|
var query = new InternalItemsQuery
|
||||||
|
{
|
||||||
|
User = user,
|
||||||
|
CollapseBoxSetItems = false
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set query values based on request
|
||||||
|
|
||||||
|
// Example
|
||||||
|
//query.IncludeItemTypes = new[] {"Movie"};
|
||||||
|
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -32,6 +32,9 @@ namespace MediaBrowser.Api.ScheduledTasks
|
|||||||
{
|
{
|
||||||
[ApiMember(Name = "IsHidden", Description = "Optional filter tasks that are hidden, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "IsHidden", Description = "Optional filter tasks that are hidden, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||||
public bool? IsHidden { get; set; }
|
public bool? IsHidden { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "IsEnabled", Description = "Optional filter tasks that are enabled, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||||
|
public bool? IsEnabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -132,6 +135,25 @@ namespace MediaBrowser.Api.ScheduledTasks
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.IsEnabled.HasValue)
|
||||||
|
{
|
||||||
|
var val = request.IsEnabled.Value;
|
||||||
|
|
||||||
|
result = result.Where(i =>
|
||||||
|
{
|
||||||
|
var isEnabled = true;
|
||||||
|
|
||||||
|
var configurableTask = i.ScheduledTask as IConfigurableScheduledTask;
|
||||||
|
|
||||||
|
if (configurableTask != null)
|
||||||
|
{
|
||||||
|
isEnabled = configurableTask.IsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isEnabled == val;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var infos = result
|
var infos = result
|
||||||
.Select(ScheduledTaskHelpers.GetTaskInfo)
|
.Select(ScheduledTaskHelpers.GetTaskInfo)
|
||||||
.ToList();
|
.ToList();
|
||||||
@ -202,8 +224,7 @@ namespace MediaBrowser.Api.ScheduledTasks
|
|||||||
{
|
{
|
||||||
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
||||||
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var id = GetPathValue(1);
|
||||||
var id = pathInfo.GetArgumentValue<string>(1);
|
|
||||||
|
|
||||||
var task = TaskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, id));
|
var task = TaskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, id));
|
||||||
|
|
||||||
|
@ -194,29 +194,24 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
result.Series = season.Series.Name;
|
result.Series = season.Series.Name;
|
||||||
|
|
||||||
result.EpisodeCount = season.GetRecursiveChildren().Count(i => i is Episode);
|
result.EpisodeCount = season.GetRecursiveChildren(i => i is Episode).Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
var series = item as Series;
|
var series = item as Series;
|
||||||
|
|
||||||
if (series != null)
|
if (series != null)
|
||||||
{
|
{
|
||||||
result.EpisodeCount = series.GetRecursiveChildren().Count(i => i is Episode);
|
result.EpisodeCount = series.GetRecursiveChildren(i => i is Episode).Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
var album = item as MusicAlbum;
|
var album = item as MusicAlbum;
|
||||||
|
|
||||||
if (album != null)
|
if (album != null)
|
||||||
{
|
{
|
||||||
var songs = album.GetRecursiveChildren().OfType<Audio>().ToList();
|
result.SongCount = album.Tracks.Count();
|
||||||
|
|
||||||
result.SongCount = songs.Count;
|
result.Artists = album.Artists.ToArray();
|
||||||
|
result.AlbumArtist = album.AlbumArtists.FirstOrDefault();
|
||||||
result.Artists = songs.SelectMany(i => i.AllArtists)
|
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
result.AlbumArtist = songs.SelectMany(i => i.AlbumArtists).FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var song = item as Audio;
|
var song = item as Audio;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
@ -243,8 +243,13 @@ namespace MediaBrowser.Api.Session
|
|||||||
[ApiMember(Name = "SupportsSync", Description = "Determines whether sync is supported.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
|
[ApiMember(Name = "SupportsSync", Description = "Determines whether sync is supported.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
|
||||||
public bool SupportsSync { get; set; }
|
public bool SupportsSync { get; set; }
|
||||||
|
|
||||||
[ApiMember(Name = "SupportsUniqueIdentifier", Description = "Determines whether the device supports a unique identifier.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
|
[ApiMember(Name = "SupportsPersistentIdentifier", Description = "Determines whether the device supports a unique identifier.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
|
||||||
public bool SupportsUniqueIdentifier { get; set; }
|
public bool SupportsPersistentIdentifier { get; set; }
|
||||||
|
|
||||||
|
public PostCapabilities()
|
||||||
|
{
|
||||||
|
SupportsPersistentIdentifier = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Sessions/Capabilities/Full", "POST", Summary = "Updates capabilities for a device")]
|
[Route("/Sessions/Capabilities/Full", "POST", Summary = "Updates capabilities for a device")]
|
||||||
@ -556,7 +561,7 @@ namespace MediaBrowser.Api.Session
|
|||||||
|
|
||||||
SupportsSync = request.SupportsSync,
|
SupportsSync = request.SupportsSync,
|
||||||
|
|
||||||
SupportsUniqueIdentifier = request.SupportsUniqueIdentifier
|
SupportsPersistentIdentifier = request.SupportsPersistentIdentifier
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the similar items.
|
/// Gets the similar items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="dtoOptions">The dto options.</param>
|
||||||
/// <param name="userManager">The user manager.</param>
|
/// <param name="userManager">The user manager.</param>
|
||||||
/// <param name="itemRepository">The item repository.</param>
|
/// <param name="itemRepository">The item repository.</param>
|
||||||
/// <param name="libraryManager">The library manager.</param>
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
@ -67,7 +68,7 @@ namespace MediaBrowser.Api
|
|||||||
/// <param name="includeInSearch">The include in search.</param>
|
/// <param name="includeInSearch">The include in search.</param>
|
||||||
/// <param name="getSimilarityScore">The get similarity score.</param>
|
/// <param name="getSimilarityScore">The get similarity score.</param>
|
||||||
/// <returns>ItemsResult.</returns>
|
/// <returns>ItemsResult.</returns>
|
||||||
internal static ItemsResult GetSimilarItemsResult(IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, BaseItem, int> getSimilarityScore)
|
internal static ItemsResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, BaseItem, int> getSimilarityScore)
|
||||||
{
|
{
|
||||||
var user = request.UserId.HasValue ? userManager.GetUserById(request.UserId.Value) : null;
|
var user = request.UserId.HasValue ? userManager.GetUserById(request.UserId.Value) : null;
|
||||||
|
|
||||||
@ -75,13 +76,13 @@ namespace MediaBrowser.Api
|
|||||||
(request.UserId.HasValue ? user.RootFolder :
|
(request.UserId.HasValue ? user.RootFolder :
|
||||||
libraryManager.RootFolder) : libraryManager.GetItemById(request.Id);
|
libraryManager.RootFolder) : libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var fields = request.GetItemFields().ToList();
|
Func<BaseItem, bool> filter = i => i.Id != item.Id && includeInSearch(i);
|
||||||
|
|
||||||
var inputItems = user == null
|
var inputItems = user == null
|
||||||
? libraryManager.RootFolder.GetRecursiveChildren().Where(i => i.Id != item.Id)
|
? libraryManager.RootFolder.GetRecursiveChildren(filter)
|
||||||
: user.RootFolder.GetRecursiveChildren(user).Where(i => i.Id != item.Id);
|
: user.RootFolder.GetRecursiveChildren(user, filter);
|
||||||
|
|
||||||
var items = GetSimilaritems(item, inputItems.Where(includeInSearch), getSimilarityScore)
|
var items = GetSimilaritems(item, inputItems, getSimilarityScore)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
IEnumerable<BaseItem> returnItems = items;
|
IEnumerable<BaseItem> returnItems = items;
|
||||||
@ -93,7 +94,7 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
var result = new ItemsResult
|
var result = new ItemsResult
|
||||||
{
|
{
|
||||||
Items = returnItems.Select(i => dtoService.GetBaseItemDto(i, fields, user)).ToArray(),
|
Items = dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
|
||||||
|
|
||||||
TotalRecordCount = items.Count
|
TotalRecordCount = items.Count
|
||||||
};
|
};
|
||||||
@ -164,7 +165,7 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
// Find common keywords
|
// Find common keywords
|
||||||
points += GetKeywords(item1).Where(i => GetKeywords(item2).Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
|
points += GetKeywords(item1).Where(i => GetKeywords(item2).Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
|
||||||
|
|
||||||
// Find common studios
|
// Find common studios
|
||||||
points += item1.Studios.Where(i => item2.Studios.Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 3);
|
points += item1.Studios.Where(i => item2.Studios.Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 3);
|
||||||
|
|
||||||
|
@ -62,6 +62,9 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
_config.Configuration.IsStartupWizardCompleted = true;
|
_config.Configuration.IsStartupWizardCompleted = true;
|
||||||
_config.Configuration.EnableLocalizedGuids = true;
|
_config.Configuration.EnableLocalizedGuids = true;
|
||||||
|
_config.Configuration.MergeMetadataAndImagesByName = true;
|
||||||
|
_config.Configuration.EnableStandaloneMetadata = true;
|
||||||
|
_config.Configuration.EnableLibraryMetadataSubFolder = true;
|
||||||
_config.SaveConfiguration();
|
_config.SaveConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
120
MediaBrowser.Api/Sync/SyncJobWebSocketListener.cs
Normal file
120
MediaBrowser.Api/Sync/SyncJobWebSocketListener.cs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
using MediaBrowser.Controller.Net;
|
||||||
|
using MediaBrowser.Controller.Sync;
|
||||||
|
using MediaBrowser.Model.Events;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Sync;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Sync
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class SessionInfoWebSocketListener
|
||||||
|
/// </summary>
|
||||||
|
class SyncJobWebSocketListener : BasePeriodicWebSocketListener<CompleteSyncJobInfo, WebSocketListenerState>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
protected override string Name
|
||||||
|
{
|
||||||
|
get { return "SyncJob"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ISyncManager _syncManager;
|
||||||
|
private string _jobId;
|
||||||
|
|
||||||
|
public SyncJobWebSocketListener(ILogger logger, ISyncManager syncManager)
|
||||||
|
: base(logger)
|
||||||
|
{
|
||||||
|
_syncManager = syncManager;
|
||||||
|
_syncManager.SyncJobCancelled += _syncManager_SyncJobCancelled;
|
||||||
|
_syncManager.SyncJobUpdated += _syncManager_SyncJobUpdated;
|
||||||
|
_syncManager.SyncJobItemCreated += _syncManager_SyncJobItemCreated;
|
||||||
|
_syncManager.SyncJobItemUpdated += _syncManager_SyncJobItemUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _syncManager_SyncJobItemUpdated(object sender, GenericEventArgs<SyncJobItem> e)
|
||||||
|
{
|
||||||
|
if (string.Equals(e.Argument.Id, _jobId, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
SendData(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _syncManager_SyncJobItemCreated(object sender, GenericEventArgs<SyncJobItem> e)
|
||||||
|
{
|
||||||
|
if (string.Equals(e.Argument.Id, _jobId, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
SendData(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ParseMessageParams(string[] values)
|
||||||
|
{
|
||||||
|
base.ParseMessageParams(values);
|
||||||
|
|
||||||
|
if (values.Length > 0)
|
||||||
|
{
|
||||||
|
_jobId = values[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _syncManager_SyncJobUpdated(object sender, GenericEventArgs<SyncJob> e)
|
||||||
|
{
|
||||||
|
if (string.Equals(e.Argument.Id, _jobId, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
SendData(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _syncManager_SyncJobCancelled(object sender, GenericEventArgs<SyncJob> e)
|
||||||
|
{
|
||||||
|
if (string.Equals(e.Argument.Id, _jobId, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
SendData(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data to send.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">The state.</param>
|
||||||
|
/// <returns>Task{SystemInfo}.</returns>
|
||||||
|
protected override Task<CompleteSyncJobInfo> GetDataToSend(WebSocketListenerState state)
|
||||||
|
{
|
||||||
|
var job = _syncManager.GetJob(_jobId);
|
||||||
|
var items = _syncManager.GetJobItems(new SyncJobItemQuery
|
||||||
|
{
|
||||||
|
AddMetadata = true,
|
||||||
|
JobId = _jobId
|
||||||
|
});
|
||||||
|
|
||||||
|
var info = new CompleteSyncJobInfo
|
||||||
|
{
|
||||||
|
Job = job,
|
||||||
|
JobItems = items.Items.ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
return Task.FromResult(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool SendOnTimer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool dispose)
|
||||||
|
{
|
||||||
|
_syncManager.SyncJobCancelled -= _syncManager_SyncJobCancelled;
|
||||||
|
_syncManager.SyncJobUpdated -= _syncManager_SyncJobUpdated;
|
||||||
|
|
||||||
|
base.Dispose(dispose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
101
MediaBrowser.Api/Sync/SyncJobsWebSocketListener.cs
Normal file
101
MediaBrowser.Api/Sync/SyncJobsWebSocketListener.cs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
using MediaBrowser.Controller.Net;
|
||||||
|
using MediaBrowser.Controller.Sync;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Sync;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Sync
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class SessionInfoWebSocketListener
|
||||||
|
/// </summary>
|
||||||
|
class SyncJobsWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<SyncJob>, WebSocketListenerState>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name.</value>
|
||||||
|
protected override string Name
|
||||||
|
{
|
||||||
|
get { return "SyncJobs"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ISyncManager _syncManager;
|
||||||
|
private string _userId;
|
||||||
|
private string _targetId;
|
||||||
|
|
||||||
|
public SyncJobsWebSocketListener(ILogger logger, ISyncManager syncManager)
|
||||||
|
: base(logger)
|
||||||
|
{
|
||||||
|
_syncManager = syncManager;
|
||||||
|
_syncManager.SyncJobCancelled += _syncManager_SyncJobCancelled;
|
||||||
|
_syncManager.SyncJobCreated += _syncManager_SyncJobCreated;
|
||||||
|
_syncManager.SyncJobUpdated += _syncManager_SyncJobUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ParseMessageParams(string[] values)
|
||||||
|
{
|
||||||
|
base.ParseMessageParams(values);
|
||||||
|
|
||||||
|
if (values.Length > 0)
|
||||||
|
{
|
||||||
|
_userId = values[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.Length > 1)
|
||||||
|
{
|
||||||
|
_targetId = values[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _syncManager_SyncJobUpdated(object sender, Model.Events.GenericEventArgs<SyncJob> e)
|
||||||
|
{
|
||||||
|
SendData(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _syncManager_SyncJobCreated(object sender, Model.Events.GenericEventArgs<SyncJobCreationResult> e)
|
||||||
|
{
|
||||||
|
SendData(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _syncManager_SyncJobCancelled(object sender, Model.Events.GenericEventArgs<SyncJob> e)
|
||||||
|
{
|
||||||
|
SendData(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data to send.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">The state.</param>
|
||||||
|
/// <returns>Task{SystemInfo}.</returns>
|
||||||
|
protected override async Task<IEnumerable<SyncJob>> GetDataToSend(WebSocketListenerState state)
|
||||||
|
{
|
||||||
|
var jobs = await _syncManager.GetJobs(new SyncJobQuery
|
||||||
|
{
|
||||||
|
UserId = _userId,
|
||||||
|
TargetId = _targetId
|
||||||
|
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return jobs.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool SendOnTimer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool dispose)
|
||||||
|
{
|
||||||
|
_syncManager.SyncJobCancelled -= _syncManager_SyncJobCancelled;
|
||||||
|
_syncManager.SyncJobCreated -= _syncManager_SyncJobCreated;
|
||||||
|
_syncManager.SyncJobUpdated -= _syncManager_SyncJobUpdated;
|
||||||
|
|
||||||
|
base.Dispose(dispose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@
|
|||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Controller.Sync;
|
using MediaBrowser.Controller.Sync;
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Sync;
|
using MediaBrowser.Model.Sync;
|
||||||
using MediaBrowser.Model.Users;
|
using MediaBrowser.Model.Users;
|
||||||
@ -38,6 +37,34 @@ namespace MediaBrowser.Api.Sync
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("/Sync/JobItems/{Id}/Enable", "POST", Summary = "Enables a cancelled or queued sync job item")]
|
||||||
|
public class EnableSyncJobItem : IReturnVoid
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Sync/JobItems/{Id}/MarkForRemoval", "POST", Summary = "Marks a job item for removal")]
|
||||||
|
public class MarkJobItemForRemoval : IReturnVoid
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Sync/JobItems/{Id}/UnmarkForRemoval", "POST", Summary = "Unmarks a job item for removal")]
|
||||||
|
public class UnmarkJobItemForRemoval : IReturnVoid
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Sync/JobItems/{Id}", "DELETE", Summary = "Cancels a sync job item")]
|
||||||
|
public class CancelSyncJobItem : IReturnVoid
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[Route("/Sync/Jobs", "GET", Summary = "Gets sync jobs.")]
|
[Route("/Sync/Jobs", "GET", Summary = "Gets sync jobs.")]
|
||||||
public class GetSyncJobs : SyncJobQuery, IReturn<QueryResult<SyncJob>>
|
public class GetSyncJobs : SyncJobQuery, IReturn<QueryResult<SyncJob>>
|
||||||
{
|
{
|
||||||
@ -85,6 +112,16 @@ namespace MediaBrowser.Api.Sync
|
|||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("/Sync/JobItems/{Id}/AdditionalFiles", "GET", Summary = "Gets a sync job item file")]
|
||||||
|
public class GetSyncJobItemAdditionalFile
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[Route("/Sync/OfflineActions", "POST", Summary = "Reports an action that occurred while offline.")]
|
[Route("/Sync/OfflineActions", "POST", Summary = "Reports an action that occurred while offline.")]
|
||||||
public class ReportOfflineActions : List<UserAction>, IReturnVoid
|
public class ReportOfflineActions : List<UserAction>, IReturnVoid
|
||||||
{
|
{
|
||||||
@ -169,11 +206,14 @@ namespace MediaBrowser.Api.Sync
|
|||||||
{
|
{
|
||||||
var jobItem = _syncManager.GetJobItem(request.Id);
|
var jobItem = _syncManager.GetJobItem(request.Id);
|
||||||
|
|
||||||
if (jobItem.Status != SyncJobItemStatus.Transferring)
|
if (jobItem.Status < SyncJobItemStatus.ReadyToTransfer)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("The job item is not yet ready for transfer.");
|
throw new ArgumentException("The job item is not yet ready for transfer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var task = _syncManager.ReportSyncJobItemTransferBeginning(request.Id);
|
||||||
|
Task.WaitAll(task);
|
||||||
|
|
||||||
return ToStaticFileResult(jobItem.OutputPath);
|
return ToStaticFileResult(jobItem.OutputPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,10 +238,11 @@ namespace MediaBrowser.Api.Sync
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var dtos = request.ItemIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
var items = request.ItemIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
.Select(_libraryManager.GetItemById)
|
.Select(_libraryManager.GetItemById)
|
||||||
.Where(i => i != null)
|
.Where(i => i != null);
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions))
|
|
||||||
|
var dtos = _dtoService.GetBaseItemDtos(items, dtoOptions)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
result.Options = SyncHelper.GetSyncOptions(dtos);
|
result.Options = SyncHelper.GetSyncOptions(dtos);
|
||||||
@ -243,5 +284,52 @@ namespace MediaBrowser.Api.Sync
|
|||||||
|
|
||||||
Task.WaitAll(task);
|
Task.WaitAll(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object Get(GetSyncJobItemAdditionalFile request)
|
||||||
|
{
|
||||||
|
var jobItem = _syncManager.GetJobItem(request.Id);
|
||||||
|
|
||||||
|
if (jobItem.Status < SyncJobItemStatus.ReadyToTransfer)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("The job item is not yet ready for transfer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var file = jobItem.AdditionalFiles.FirstOrDefault(i => string.Equals(i.Name, request.Name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (file == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Sync job additional file not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToStaticFileResult(file.Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Post(EnableSyncJobItem request)
|
||||||
|
{
|
||||||
|
var task = _syncManager.ReEnableJobItem(request.Id);
|
||||||
|
|
||||||
|
Task.WaitAll(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(CancelSyncJobItem request)
|
||||||
|
{
|
||||||
|
var task = _syncManager.CancelJobItem(request.Id);
|
||||||
|
|
||||||
|
Task.WaitAll(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Post(MarkJobItemForRemoval request)
|
||||||
|
{
|
||||||
|
var task = _syncManager.MarkJobItemForRemoval(request.Id);
|
||||||
|
|
||||||
|
Task.WaitAll(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Post(UnmarkJobItemForRemoval request)
|
||||||
|
{
|
||||||
|
var task = _syncManager.UnmarkJobItemForRemoval(request.Id);
|
||||||
|
|
||||||
|
Task.WaitAll(task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,20 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public string AdjacentTo { get; set; }
|
public string AdjacentTo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Skips over a given number of items within the results. Use for paging.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The start index.</value>
|
||||||
|
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? StartIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of items to return
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The limit.</value>
|
||||||
|
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? Limit { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
|
[Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
|
||||||
@ -238,7 +252,9 @@ namespace MediaBrowser.Api
|
|||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
public object Get(GetSimilarShows request)
|
public object Get(GetSimilarShows request)
|
||||||
{
|
{
|
||||||
var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
|
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
|
||||||
_itemRepo,
|
_itemRepo,
|
||||||
_libraryManager,
|
_libraryManager,
|
||||||
_userDataManager,
|
_userDataManager,
|
||||||
@ -254,10 +270,10 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
var user = _userManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId)
|
var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Episode);
|
||||||
.OfType<Episode>();
|
|
||||||
|
|
||||||
var itemsList = _libraryManager.Sort(items, user, new[] { "PremiereDate", "AirTime", "SortName" }, SortOrder.Ascending)
|
var itemsList = _libraryManager
|
||||||
|
.Sort(items, user, new[] { "PremiereDate", "AirTime", "SortName" }, SortOrder.Ascending)
|
||||||
.Cast<Episode>()
|
.Cast<Episode>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@ -270,9 +286,9 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
var pagedItems = ApplyPaging(previousEpisodes, request.StartIndex, request.Limit);
|
var pagedItems = ApplyPaging(previousEpisodes, request.StartIndex, request.Limit);
|
||||||
|
|
||||||
var options = request.GetDtoOptions();
|
var options = GetDtoOptions(request);
|
||||||
|
|
||||||
var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, options, user)).ToArray();
|
var returnItems = _dtoService.GetBaseItemDtos(pagedItems, options, user).ToArray();
|
||||||
|
|
||||||
var result = new ItemsResult
|
var result = new ItemsResult
|
||||||
{
|
{
|
||||||
@ -301,9 +317,9 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
var user = _userManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
var options = request.GetDtoOptions();
|
var options = GetDtoOptions(request);
|
||||||
|
|
||||||
var returnItems = result.Items.Select(i => _dtoService.GetBaseItemDto(i, options, user)).ToArray();
|
var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user).ToArray();
|
||||||
|
|
||||||
return ToOptimizedSerializedResultUsingCache(new ItemsResult
|
return ToOptimizedSerializedResultUsingCache(new ItemsResult
|
||||||
{
|
{
|
||||||
@ -365,9 +381,9 @@ namespace MediaBrowser.Api
|
|||||||
.Cast<Season>();
|
.Cast<Season>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var fields = request.GetItemFields().ToList();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var returnItems = seasons.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
|
var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
return new ItemsResult
|
return new ItemsResult
|
||||||
@ -411,7 +427,18 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
IEnumerable<Episode> episodes;
|
IEnumerable<Episode> episodes;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(request.SeasonId))
|
if (!string.IsNullOrWhiteSpace(request.SeasonId))
|
||||||
|
{
|
||||||
|
var season = _libraryManager.GetItemById(new Guid(request.SeasonId)) as Season;
|
||||||
|
|
||||||
|
if (season == null)
|
||||||
|
{
|
||||||
|
throw new ResourceNotFoundException("No season exists with Id " + request.SeasonId);
|
||||||
|
}
|
||||||
|
|
||||||
|
episodes = season.GetEpisodes(user);
|
||||||
|
}
|
||||||
|
else if (request.Season.HasValue)
|
||||||
{
|
{
|
||||||
var series = _libraryManager.GetItemById(request.Id) as Series;
|
var series = _libraryManager.GetItemById(request.Id) as Series;
|
||||||
|
|
||||||
@ -424,14 +451,14 @@ namespace MediaBrowser.Api
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var season = _libraryManager.GetItemById(new Guid(request.SeasonId)) as Season;
|
var series = _libraryManager.GetItemById(request.Id) as Series;
|
||||||
|
|
||||||
if (season == null)
|
if (series == null)
|
||||||
{
|
{
|
||||||
throw new ResourceNotFoundException("No season exists with Id " + request.SeasonId);
|
throw new ResourceNotFoundException("No series exists with Id " + request.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
episodes = season.GetEpisodes(user);
|
episodes = series.GetEpisodes(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter after the fact in case the ui doesn't want them
|
// Filter after the fact in case the ui doesn't want them
|
||||||
@ -448,24 +475,27 @@ namespace MediaBrowser.Api
|
|||||||
episodes = episodes.Where(i => i.IsVirtualUnaired == val);
|
episodes = episodes.Where(i => i.IsVirtualUnaired == val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEnumerable<BaseItem> returnItems = episodes;
|
||||||
|
|
||||||
// This must be the last filter
|
// This must be the last filter
|
||||||
if (!string.IsNullOrEmpty(request.AdjacentTo))
|
if (!string.IsNullOrEmpty(request.AdjacentTo))
|
||||||
{
|
{
|
||||||
episodes = UserViewBuilder.FilterForAdjacency(episodes, request.AdjacentTo)
|
returnItems = UserViewBuilder.FilterForAdjacency(returnItems, request.AdjacentTo);
|
||||||
.Cast<Episode>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var fields = request.GetItemFields().ToList();
|
returnItems = _libraryManager.ReplaceVideosWithPrimaryVersions(returnItems);
|
||||||
|
|
||||||
episodes = _libraryManager.ReplaceVideosWithPrimaryVersions(episodes).Cast<Episode>();
|
var pagedItems = ApplyPaging(returnItems, request.StartIndex, request.Limit);
|
||||||
|
|
||||||
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var returnItems = episodes.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
|
var dtos = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
return new ItemsResult
|
return new ItemsResult
|
||||||
{
|
{
|
||||||
TotalRecordCount = returnItems.Length,
|
TotalRecordCount = dtos.Length,
|
||||||
Items = returnItems
|
Items = dtos
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
{
|
{
|
||||||
var item = GetArtist(request.Name, LibraryManager);
|
var item = GetArtist(request.Name, LibraryManager);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
if (request.UserId.HasValue)
|
if (request.UserId.HasValue)
|
||||||
{
|
{
|
||||||
@ -130,8 +130,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
if (request is GetAlbumArtists)
|
if (request is GetAlbumArtists)
|
||||||
{
|
{
|
||||||
return items
|
return items
|
||||||
|
.Where(i => !i.IsFolder)
|
||||||
.OfType<IHasAlbumArtist>()
|
.OfType<IHasAlbumArtist>()
|
||||||
.Where(i => !(i is MusicAlbum))
|
|
||||||
.SelectMany(i => i.AlbumArtists)
|
.SelectMany(i => i.AlbumArtists)
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.Select(name =>
|
.Select(name =>
|
||||||
@ -150,8 +150,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
}
|
}
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
.Where(i => !i.IsFolder)
|
||||||
.OfType<IHasArtist>()
|
.OfType<IHasArtist>()
|
||||||
.Where(i => !(i is MusicAlbum))
|
|
||||||
.SelectMany(i => i.AllArtists)
|
.SelectMany(i => i.AllArtists)
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.Select(name =>
|
.Select(name =>
|
||||||
|
@ -56,46 +56,52 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
protected ItemsResult GetResult(GetItemsByName request)
|
protected ItemsResult GetResult(GetItemsByName request)
|
||||||
{
|
{
|
||||||
User user = null;
|
User user = null;
|
||||||
BaseItem item;
|
BaseItem parentItem;
|
||||||
List<BaseItem> libraryItems;
|
List<BaseItem> libraryItems;
|
||||||
|
|
||||||
if (request.UserId.HasValue)
|
if (request.UserId.HasValue)
|
||||||
{
|
{
|
||||||
user = UserManager.GetUserById(request.UserId.Value);
|
user = UserManager.GetUserById(request.UserId.Value);
|
||||||
item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : LibraryManager.GetItemById(request.ParentId);
|
parentItem = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : LibraryManager.GetItemById(request.ParentId);
|
||||||
|
|
||||||
libraryItems = user.RootFolder.GetRecursiveChildren(user).ToList();
|
libraryItems = user.RootFolder.GetRecursiveChildren(user).ToList();
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
item = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : LibraryManager.GetItemById(request.ParentId);
|
parentItem = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : LibraryManager.GetItemById(request.ParentId);
|
||||||
|
libraryItems = LibraryManager.RootFolder.GetRecursiveChildren().ToList();
|
||||||
libraryItems = LibraryManager.RootFolder.RecursiveChildren.ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<BaseItem> items;
|
IEnumerable<BaseItem> items;
|
||||||
|
|
||||||
if (item.IsFolder)
|
var excludeItemTypes = request.GetExcludeItemTypes();
|
||||||
|
var includeItemTypes = request.GetIncludeItemTypes();
|
||||||
|
var mediaTypes = request.GetMediaTypes();
|
||||||
|
|
||||||
|
Func<BaseItem, bool> filter = i => FilterItem(request, i, excludeItemTypes, includeItemTypes, mediaTypes);
|
||||||
|
|
||||||
|
if (parentItem.IsFolder)
|
||||||
{
|
{
|
||||||
var folder = (Folder)item;
|
var folder = (Folder)parentItem;
|
||||||
|
|
||||||
if (request.UserId.HasValue)
|
if (request.UserId.HasValue)
|
||||||
{
|
{
|
||||||
items = request.Recursive ? folder.GetRecursiveChildren(user) : folder.GetChildren(user, true);
|
items = request.Recursive ?
|
||||||
|
folder.GetRecursiveChildren(user, filter) :
|
||||||
|
folder.GetChildren(user, true).Where(filter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
items = request.Recursive ? folder.GetRecursiveChildren() : folder.Children;
|
items = request.Recursive ?
|
||||||
|
folder.GetRecursiveChildren(filter) :
|
||||||
|
folder.Children.Where(filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
items = new[] { item };
|
items = new[] { parentItem }.Where(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
items = FilterItems(request, items);
|
|
||||||
|
|
||||||
var extractedItems = GetAllItems(request, items);
|
var extractedItems = GetAllItems(request, items);
|
||||||
|
|
||||||
var filteredItems = FilterItems(request, extractedItems, user);
|
var filteredItems = FilterItems(request, extractedItems, user);
|
||||||
@ -129,7 +135,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
var tuples = ibnItems.Select(i => new Tuple<TItemType, List<BaseItem>>(i, i.GetTaggedItems(libraryItems).ToList()));
|
var tuples = ibnItems.Select(i => new Tuple<TItemType, List<BaseItem>>(i, i.GetTaggedItems(libraryItems).ToList()));
|
||||||
|
|
||||||
var dtoOptions = request.GetDtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = tuples.Select(i => GetDto(i.Item1, user, dtoOptions, i.Item2));
|
var dtos = tuples.Select(i => GetDto(i.Item1, user, dtoOptions, i.Item2));
|
||||||
|
|
||||||
@ -290,33 +296,41 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
/// Filters the items.
|
/// Filters the items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
/// <param name="items">The items.</param>
|
/// <param name="f">The f.</param>
|
||||||
|
/// <param name="excludeItemTypes">The exclude item types.</param>
|
||||||
|
/// <param name="includeItemTypes">The include item types.</param>
|
||||||
|
/// <param name="mediaTypes">The media types.</param>
|
||||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
protected virtual IEnumerable<BaseItem> FilterItems(GetItemsByName request, IEnumerable<BaseItem> items)
|
protected bool FilterItem(GetItemsByName request, BaseItem f, string[] excludeItemTypes, string[] includeItemTypes, string[] mediaTypes)
|
||||||
{
|
{
|
||||||
// Exclude item types
|
// Exclude item types
|
||||||
if (!string.IsNullOrEmpty(request.ExcludeItemTypes))
|
if (excludeItemTypes.Length > 0)
|
||||||
{
|
{
|
||||||
var vals = request.ExcludeItemTypes.Split(',');
|
if (excludeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase))
|
||||||
items = items.Where(f => !vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include item types
|
// Include item types
|
||||||
if (!string.IsNullOrEmpty(request.IncludeItemTypes))
|
if (includeItemTypes.Length > 0)
|
||||||
{
|
{
|
||||||
var vals = request.IncludeItemTypes.Split(',');
|
if (!includeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase))
|
||||||
items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include MediaTypes
|
// Include MediaTypes
|
||||||
if (!string.IsNullOrEmpty(request.MediaTypes))
|
if (mediaTypes.Length > 0)
|
||||||
{
|
{
|
||||||
var vals = request.MediaTypes.Split(',');
|
if (!mediaTypes.Contains(f.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
items = items.Where(f => vals.Contains(f.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase));
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -69,7 +69,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
{
|
{
|
||||||
var item = GetGameGenre(request.Name, LibraryManager);
|
var item = GetGameGenre(request.Name, LibraryManager);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
if (request.UserId.HasValue)
|
if (request.UserId.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -74,7 +74,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
{
|
{
|
||||||
var item = GetGenre(request.Name, LibraryManager);
|
var item = GetGenre(request.Name, LibraryManager);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
if (request.UserId.HasValue)
|
if (request.UserId.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -169,8 +169,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
[ApiMember(Name = "ExcludeLocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
[ApiMember(Name = "ExcludeLocationTypes", Description = "Optional. If specified, results will be filtered based on LocationType. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
public string ExcludeLocationTypes { get; set; }
|
public string ExcludeLocationTypes { get; set; }
|
||||||
|
|
||||||
public bool IncludeIndexContainers { get; set; }
|
|
||||||
|
|
||||||
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
|
||||||
public bool? IsMissing { get; set; }
|
public bool? IsMissing { get; set; }
|
||||||
|
|
||||||
@ -321,14 +319,14 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
var result = await GetItemsToSerialize(request, user, parentItem).ConfigureAwait(false);
|
var result = await GetItemsToSerialize(request, user, parentItem).ConfigureAwait(false);
|
||||||
|
|
||||||
var isFiltered = result.Item2;
|
var isFiltered = result.Item2;
|
||||||
var dtoOptions = request.GetDtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
if (isFiltered)
|
if (isFiltered)
|
||||||
{
|
{
|
||||||
return new ItemsResult
|
return new ItemsResult
|
||||||
{
|
{
|
||||||
TotalRecordCount = result.Item1.TotalRecordCount,
|
TotalRecordCount = result.Item1.TotalRecordCount,
|
||||||
Items = result.Item1.Items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
|
Items = _dtoService.GetBaseItemDtos(result.Item1.Items, dtoOptions, user).ToArray()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,7 +360,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
var pagedItems = ApplyPaging(request, itemsArray);
|
var pagedItems = ApplyPaging(request, itemsArray);
|
||||||
|
|
||||||
var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray();
|
var returnItems = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user).ToArray();
|
||||||
|
|
||||||
return new ItemsResult
|
return new ItemsResult
|
||||||
{
|
{
|
||||||
@ -396,52 +394,29 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
else if (request.Recursive)
|
else if (request.Recursive)
|
||||||
{
|
{
|
||||||
if (user == null)
|
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
|
||||||
{
|
|
||||||
items = ((Folder)item).RecursiveChildren;
|
|
||||||
|
|
||||||
items = _libraryManager.ReplaceVideosWithPrimaryVersions(items);
|
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user));
|
|
||||||
|
|
||||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
items = ((Folder)item).Children;
|
var result = await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false);
|
||||||
|
|
||||||
items = _libraryManager.ReplaceVideosWithPrimaryVersions(items);
|
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
var userRoot = item as UserRootFolder;
|
||||||
|
|
||||||
|
if (userRoot == null)
|
||||||
{
|
{
|
||||||
var userRoot = item as UserRootFolder;
|
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
|
||||||
|
|
||||||
if (userRoot == null)
|
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||||
{
|
|
||||||
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user));
|
|
||||||
|
|
||||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
items = ((Folder)item).GetChildren(user, true);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (request.IncludeIndexContainers)
|
items = ((Folder)item).GetChildren(user, true);
|
||||||
{
|
|
||||||
var list = items.ToList();
|
|
||||||
|
|
||||||
var containers = list.Select(i => i.IndexContainer)
|
|
||||||
.Where(i => i != null);
|
|
||||||
|
|
||||||
list.AddRange(containers);
|
|
||||||
|
|
||||||
items = list.Distinct();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Tuple<QueryResult<BaseItem>, bool>(new QueryResult<BaseItem>
|
return new Tuple<QueryResult<BaseItem>, bool>(new QueryResult<BaseItem>
|
||||||
@ -464,7 +439,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
SortBy = request.GetOrderBy(),
|
SortBy = request.GetOrderBy(),
|
||||||
SortOrder = request.SortOrder ?? SortOrder.Ascending,
|
SortOrder = request.SortOrder ?? SortOrder.Ascending,
|
||||||
|
|
||||||
Filter = (i, u) => ApplyAdditionalFilters(request, i, u, true, _libraryManager),
|
Filter = i => ApplyAdditionalFilters(request, i, user, true, _libraryManager),
|
||||||
|
|
||||||
Limit = request.Limit,
|
Limit = request.Limit,
|
||||||
StartIndex = request.StartIndex,
|
StartIndex = request.StartIndex,
|
||||||
|
@ -69,7 +69,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
{
|
{
|
||||||
var item = GetMusicGenre(request.Name, LibraryManager);
|
var item = GetMusicGenre(request.Name, LibraryManager);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
if (request.UserId.HasValue)
|
if (request.UserId.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,6 @@ using MediaBrowser.Controller.Library;
|
|||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Querying;
|
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -86,7 +85,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
{
|
{
|
||||||
var item = GetPerson(request.Name, LibraryManager);
|
var item = GetPerson(request.Name, LibraryManager);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
if (request.UserId.HasValue)
|
if (request.UserId.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -73,7 +73,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
{
|
{
|
||||||
var item = GetStudio(request.Name, LibraryManager);
|
var item = GetStudio(request.Name, LibraryManager);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
if (request.UserId.HasValue)
|
if (request.UserId.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -228,7 +228,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The user id.</value>
|
/// <value>The user id.</value>
|
||||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
public Guid UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
|
|
||||||
[ApiMember(Name = "Limit", Description = "Limit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "Limit", Description = "Limit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
public int Limit { get; set; }
|
public int Limit { get; set; }
|
||||||
@ -259,7 +259,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public string EnableImageTypes { get; set; }
|
public string EnableImageTypes { get; set; }
|
||||||
|
|
||||||
public GetLatestMedia()
|
public GetLatestMedia()
|
||||||
{
|
{
|
||||||
Limit = 20;
|
Limit = 20;
|
||||||
@ -304,74 +304,17 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
var user = _userManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
var list = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||||
var libraryItems = string.IsNullOrEmpty(request.ParentId) && user != null ?
|
|
||||||
GetItemsConfiguredForLatest(user) :
|
|
||||||
GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId);
|
|
||||||
|
|
||||||
libraryItems = libraryItems.OrderByDescending(i => i.DateCreated)
|
|
||||||
.Where(i => i.LocationType != LocationType.Virtual);
|
|
||||||
|
|
||||||
|
|
||||||
//if (request.IsFolder.HasValue)
|
|
||||||
//{
|
|
||||||
//var val = request.IsFolder.Value;
|
|
||||||
libraryItems = libraryItems.Where(f => f.IsFolder == false);
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(request.IncludeItemTypes))
|
|
||||||
{
|
{
|
||||||
var vals = request.IncludeItemTypes.Split(',');
|
GroupItems = request.GroupItems,
|
||||||
libraryItems = libraryItems.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
|
IncludeItemTypes = (request.IncludeItemTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(),
|
||||||
}
|
IsPlayed = request.IsPlayed,
|
||||||
|
Limit = request.Limit,
|
||||||
|
ParentId = request.ParentId,
|
||||||
|
UserId = request.UserId
|
||||||
|
});
|
||||||
|
|
||||||
var currentUser = user;
|
var options = GetDtoOptions(request);
|
||||||
|
|
||||||
if (request.IsPlayed.HasValue)
|
|
||||||
{
|
|
||||||
var takeLimit = request.Limit * 20;
|
|
||||||
|
|
||||||
var val = request.IsPlayed.Value;
|
|
||||||
libraryItems = libraryItems.Where(f => f.IsPlayed(currentUser) == val)
|
|
||||||
.Take(takeLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
|
||||||
var items = libraryItems
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var list = new List<Tuple<BaseItem, List<BaseItem>>>();
|
|
||||||
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
// Only grab the index container for media
|
|
||||||
var container = item.IsFolder || !request.GroupItems ? null : item.LatestItemsIndexContainer;
|
|
||||||
|
|
||||||
if (container == null)
|
|
||||||
{
|
|
||||||
list.Add(new Tuple<BaseItem, List<BaseItem>>(null, new List<BaseItem> { item }));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var current = list.FirstOrDefault(i => i.Item1 != null && i.Item1.Id == container.Id);
|
|
||||||
|
|
||||||
if (current != null)
|
|
||||||
{
|
|
||||||
current.Item2.Add(item);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list.Add(new Tuple<BaseItem, List<BaseItem>>(container, new List<BaseItem> { item }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list.Count >= request.Limit)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var options = request.GetDtoOptions();
|
|
||||||
|
|
||||||
var dtos = list.Select(i =>
|
var dtos = list.Select(i =>
|
||||||
{
|
{
|
||||||
@ -394,15 +337,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
return ToOptimizedResult(dtos.ToList());
|
return ToOptimizedResult(dtos.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<BaseItem> GetItemsConfiguredForLatest(User user)
|
|
||||||
{
|
|
||||||
return user.RootFolder.GetChildren(user, true)
|
|
||||||
.OfType<Folder>()
|
|
||||||
.Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N")))
|
|
||||||
.SelectMany(i => i.GetRecursiveChildren(user))
|
|
||||||
.DistinctBy(i => i.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<object> Get(GetUserViews request)
|
public async Task<object> Get(GetUserViews request)
|
||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
var user = _userManager.GetUserById(request.UserId);
|
||||||
@ -420,7 +354,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
|
var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
|
var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
@ -447,14 +381,13 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
// Get them from the child tree
|
// Get them from the child tree
|
||||||
if (series != null)
|
if (series != null)
|
||||||
{
|
{
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
// Avoid implicitly captured closure
|
||||||
var currentUser = user;
|
var currentUser = user;
|
||||||
|
|
||||||
var dtos = series
|
var dtos = series
|
||||||
.GetRecursiveChildren()
|
.GetRecursiveChildren(i => i is Episode && i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
|
||||||
.Where(i => i is Episode && i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
|
|
||||||
.OrderBy(i =>
|
.OrderBy(i =>
|
||||||
{
|
{
|
||||||
if (i.PremiereDate.HasValue)
|
if (i.PremiereDate.HasValue)
|
||||||
@ -479,7 +412,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
// Get them from the db
|
// Get them from the db
|
||||||
if (movie != null)
|
if (movie != null)
|
||||||
{
|
{
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = movie.SpecialFeatureIds
|
var dtos = movie.SpecialFeatureIds
|
||||||
.Select(_libraryManager.GetItemById)
|
.Select(_libraryManager.GetItemById)
|
||||||
@ -518,11 +451,10 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
trailerIds = hasTrailers.GetTrailerIds();
|
trailerIds = hasTrailers.GetTrailerIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = trailerIds
|
var dtos = trailerIds
|
||||||
.Select(_libraryManager.GetItemById)
|
.Select(_libraryManager.GetItemById)
|
||||||
.OrderBy(i => i.SortName)
|
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||||
|
|
||||||
return dtos.ToList();
|
return dtos.ToList();
|
||||||
@ -539,7 +471,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id);
|
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
|
var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
|
||||||
|
|
||||||
@ -557,7 +489,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
var item = user.RootFolder;
|
var item = user.RootFolder;
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
|
var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
|
||||||
|
|
||||||
@ -577,7 +509,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
|
var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
|
var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
@ -73,7 +73,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
{
|
{
|
||||||
var item = LibraryManager.GetYear(request.Year);
|
var item = LibraryManager.GetYear(request.Year);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
if (request.UserId.HasValue)
|
if (request.UserId.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,6 @@ using MediaBrowser.Model.Connect;
|
|||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Users;
|
using MediaBrowser.Model.Users;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using ServiceStack.Text.Controller;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -56,6 +55,21 @@ namespace MediaBrowser.Api
|
|||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class GetUser
|
||||||
|
/// </summary>
|
||||||
|
[Route("/Users/{Id}/Offline", "GET", Summary = "Gets an offline user record by Id")]
|
||||||
|
[Authenticated]
|
||||||
|
public class GetOfflineUser : IReturn<UserDto>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the id.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The id.</value>
|
||||||
|
[ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class DeleteUser
|
/// Class DeleteUser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -148,6 +162,32 @@ namespace MediaBrowser.Api
|
|||||||
public bool ResetPassword { get; set; }
|
public bool ResetPassword { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class UpdateUserEasyPassword
|
||||||
|
/// </summary>
|
||||||
|
[Route("/Users/{Id}/EasyPassword", "POST", Summary = "Updates a user's easy password")]
|
||||||
|
[Authenticated]
|
||||||
|
public class UpdateUserEasyPassword : IReturnVoid
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the id.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The id.</value>
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the new password.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The new password.</value>
|
||||||
|
public string NewPassword { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether [reset password].
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if [reset password]; otherwise, <c>false</c>.</value>
|
||||||
|
public bool ResetPassword { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class UpdateUser
|
/// Class UpdateUser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -294,7 +334,7 @@ namespace MediaBrowser.Api
|
|||||||
.Select(i => _userManager.GetUserDto(i, Request.RemoteIp))
|
.Select(i => _userManager.GetUserDto(i, Request.RemoteIp))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return ToOptimizedSerializedResultUsingCache(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -313,7 +353,23 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
var result = _userManager.GetUserDto(user, Request.RemoteIp);
|
var result = _userManager.GetUserDto(user, Request.RemoteIp);
|
||||||
|
|
||||||
return ToOptimizedSerializedResultUsingCache(result);
|
return ToOptimizedResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Get(GetOfflineUser request)
|
||||||
|
{
|
||||||
|
var user = _userManager.GetUserById(request.Id);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new ResourceNotFoundException("User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
var auth = AuthorizationContext.GetAuthorizationInfo(Request);
|
||||||
|
|
||||||
|
var result = _userManager.GetOfflineUserDto(user, auth.DeviceId);
|
||||||
|
|
||||||
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -410,6 +466,8 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
public async Task PostAsync(UpdateUserPassword request)
|
public async Task PostAsync(UpdateUserPassword request)
|
||||||
{
|
{
|
||||||
|
AssertCanUpdateUser(request.Id);
|
||||||
|
|
||||||
var user = _userManager.GetUserById(request.Id);
|
var user = _userManager.GetUserById(request.Id);
|
||||||
|
|
||||||
if (user == null)
|
if (user == null)
|
||||||
@ -434,6 +492,33 @@ namespace MediaBrowser.Api
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Post(UpdateUserEasyPassword request)
|
||||||
|
{
|
||||||
|
var task = PostAsync(request);
|
||||||
|
Task.WaitAll(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PostAsync(UpdateUserEasyPassword request)
|
||||||
|
{
|
||||||
|
AssertCanUpdateUser(request.Id);
|
||||||
|
|
||||||
|
var user = _userManager.GetUserById(request.Id);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new ResourceNotFoundException("User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.ResetPassword)
|
||||||
|
{
|
||||||
|
await _userManager.ResetEasyPassword(user).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _userManager.ChangeEasyPassword(user, request.NewPassword).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Posts the specified request.
|
/// Posts the specified request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -449,14 +534,15 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
||||||
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
||||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
var id = GetPathValue(1);
|
||||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
|
||||||
|
AssertCanUpdateUser(id);
|
||||||
|
|
||||||
var dtoUser = request;
|
var dtoUser = request;
|
||||||
|
|
||||||
var user = _userManager.GetUserById(id);
|
var user = _userManager.GetUserById(id);
|
||||||
|
|
||||||
var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ?
|
var task = string.Equals(user.Name, dtoUser.Name, StringComparison.Ordinal) ?
|
||||||
_userManager.UpdateUser(user) :
|
_userManager.UpdateUser(user) :
|
||||||
_userManager.RenameUser(user, dtoUser.Name);
|
_userManager.RenameUser(user, dtoUser.Name);
|
||||||
|
|
||||||
@ -500,11 +586,29 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
public void Post(UpdateUserConfiguration request)
|
public void Post(UpdateUserConfiguration request)
|
||||||
{
|
{
|
||||||
|
AssertCanUpdateUser(request.Id);
|
||||||
|
|
||||||
var task = _userManager.UpdateConfiguration(request.Id, request);
|
var task = _userManager.UpdateConfiguration(request.Id, request);
|
||||||
|
|
||||||
Task.WaitAll(task);
|
Task.WaitAll(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AssertCanUpdateUser(string userId)
|
||||||
|
{
|
||||||
|
var auth = AuthorizationContext.GetAuthorizationInfo(Request);
|
||||||
|
|
||||||
|
// If they're going to update the record of another user, they must be an administrator
|
||||||
|
if (!string.Equals(userId, auth.UserId, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var authenticatedUser = _userManager.GetUserById(auth.UserId);
|
||||||
|
|
||||||
|
if (!authenticatedUser.Policy.IsAdministrator)
|
||||||
|
{
|
||||||
|
throw new SecurityException("Unauthorized access.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Post(UpdateUserPolicy request)
|
public void Post(UpdateUserPolicy request)
|
||||||
{
|
{
|
||||||
var task = UpdateUserPolicy(request);
|
var task = UpdateUserPolicy(request);
|
||||||
|
@ -5,7 +5,6 @@ using MediaBrowser.Controller.Entities;
|
|||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
@ -80,7 +79,7 @@ namespace MediaBrowser.Api
|
|||||||
: _libraryManager.RootFolder)
|
: _libraryManager.RootFolder)
|
||||||
: _libraryManager.GetItemById(request.Id);
|
: _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var dtoOptions = new DtoOptions();
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var video = (Video)item;
|
var video = (Video)item;
|
||||||
|
|
||||||
|
@ -475,7 +475,7 @@ namespace MediaBrowser.Common.Implementations
|
|||||||
SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager);
|
SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager);
|
||||||
RegisterSingleInstance(SecurityManager);
|
RegisterSingleInstance(SecurityManager);
|
||||||
|
|
||||||
InstallationManager = new InstallationManager(Logger, this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager);
|
InstallationManager = new InstallationManager(Logger, this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager);
|
||||||
RegisterSingleInstance(InstallationManager);
|
RegisterSingleInstance(InstallationManager);
|
||||||
|
|
||||||
ZipClient = new ZipClient();
|
ZipClient = new ZipClient();
|
||||||
|
@ -690,7 +690,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Delete(file);
|
_fileSystem.DeleteFile(file);
|
||||||
}
|
}
|
||||||
catch (IOException)
|
catch (IOException)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Model.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using System;
|
using System;
|
||||||
@ -270,8 +270,8 @@ namespace MediaBrowser.Common.Implementations.IO
|
|||||||
File.Copy(temp1, file2, true);
|
File.Copy(temp1, file2, true);
|
||||||
File.Copy(temp2, file1, true);
|
File.Copy(temp2, file1, true);
|
||||||
|
|
||||||
File.Delete(temp1);
|
DeleteFile(temp1);
|
||||||
File.Delete(temp2);
|
DeleteFile(temp2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -409,5 +409,25 @@ namespace MediaBrowser.Common.Implementations.IO
|
|||||||
|
|
||||||
//return Path.IsPathRooted(path);
|
//return Path.IsPathRooted(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeleteFile(string path, bool sendToRecycleBin)
|
||||||
|
{
|
||||||
|
File.Delete(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteDirectory(string path, bool recursive, bool sendToRecycleBin)
|
||||||
|
{
|
||||||
|
Directory.Delete(path, recursive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteFile(string path)
|
||||||
|
{
|
||||||
|
DeleteFile(path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteDirectory(string path, bool recursive)
|
||||||
|
{
|
||||||
|
DeleteDirectory(path, recursive, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,21 +48,21 @@
|
|||||||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="NLog, Version=3.1.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=3.2.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\NLog.3.1.0.0\lib\net45\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.3.2.0.0\lib\net45\NLog.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
|
<Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
|
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SimpleInjector, Version=2.6.1.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
<Reference Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\SimpleInjector.2.6.1\lib\net45\SimpleInjector.dll</HintPath>
|
<HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SimpleInjector.Diagnostics, Version=2.6.1.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
<Reference Include="SimpleInjector.Diagnostics, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\SimpleInjector.2.6.1\lib\net45\SimpleInjector.Diagnostics.dll</HintPath>
|
<HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.Diagnostics.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
@ -18,11 +18,64 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||||||
Logger = logger;
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private volatile List<string> _localIpAddresses;
|
||||||
|
private readonly object _localIpAddressSyncLock = new object();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the machine's local ip address
|
/// Gets the machine's local ip address
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>IPAddress.</returns>
|
/// <returns>IPAddress.</returns>
|
||||||
public IEnumerable<string> GetLocalIpAddresses()
|
public IEnumerable<string> GetLocalIpAddresses()
|
||||||
|
{
|
||||||
|
if (_localIpAddresses == null)
|
||||||
|
{
|
||||||
|
lock (_localIpAddressSyncLock)
|
||||||
|
{
|
||||||
|
if (_localIpAddresses == null)
|
||||||
|
{
|
||||||
|
var addresses = GetLocalIpAddressesInternal().ToList();
|
||||||
|
|
||||||
|
_localIpAddresses = addresses;
|
||||||
|
BindEvents();
|
||||||
|
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _localIpAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BindEvents()
|
||||||
|
{
|
||||||
|
NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
|
||||||
|
NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
|
||||||
|
|
||||||
|
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
|
||||||
|
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
|
||||||
|
{
|
||||||
|
Logger.Debug("NetworkAvailabilityChanged fired. Resetting cached network info.");
|
||||||
|
|
||||||
|
lock (_localIpAddressSyncLock)
|
||||||
|
{
|
||||||
|
_localIpAddresses = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Logger.Debug("NetworkAddressChanged fired. Resetting cached network info.");
|
||||||
|
|
||||||
|
lock (_localIpAddressSyncLock)
|
||||||
|
{
|
||||||
|
_localIpAddresses = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<string> GetLocalIpAddressesInternal()
|
||||||
{
|
{
|
||||||
var list = GetIPsDefault()
|
var list = GetIPsDefault()
|
||||||
.Where(i => !IPAddress.IsLoopback(i))
|
.Where(i => !IPAddress.IsLoopback(i))
|
||||||
@ -53,6 +106,11 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||||||
// Private address space:
|
// Private address space:
|
||||||
// http://en.wikipedia.org/wiki/Private_network
|
// http://en.wikipedia.org/wiki/Private_network
|
||||||
|
|
||||||
|
if (endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return Is172AddressPrivate(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
// If url was requested with computer name, we may see this
|
// If url was requested with computer name, we may see this
|
||||||
@ -61,11 +119,23 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||||||
endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) ||
|
endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) ||
|
||||||
endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
|
endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
|
||||||
endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
|
endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
|
||||||
endpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) ||
|
endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase) ||
|
||||||
endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase);
|
endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool Is172AddressPrivate(string endpoint)
|
||||||
|
{
|
||||||
|
for (var i = 16; i <= 31; i++)
|
||||||
|
{
|
||||||
|
if (endpoint.StartsWith("172." + i.ToString(CultureInfo.InvariantCulture) + ".", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsInLocalNetwork(string endpoint)
|
public bool IsInLocalNetwork(string endpoint)
|
||||||
{
|
{
|
||||||
return IsInLocalNetworkInternal(endpoint, true);
|
return IsInLocalNetworkInternal(endpoint, true);
|
||||||
@ -122,7 +192,7 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IPAddress> GetIpAddresses(string hostName)
|
public IEnumerable<IPAddress> GetIpAddresses(string hostName)
|
||||||
{
|
{
|
||||||
return Dns.GetHostAddresses(hostName);
|
return Dns.GetHostAddresses(hostName);
|
||||||
|
@ -108,13 +108,9 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private TaskResult _lastExecutionResult;
|
private TaskResult _lastExecutionResult;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _last execution resultinitialized
|
|
||||||
/// </summary>
|
|
||||||
private bool _lastExecutionResultinitialized;
|
|
||||||
/// <summary>
|
|
||||||
/// The _last execution result sync lock
|
/// The _last execution result sync lock
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _lastExecutionResultSyncLock = new object();
|
private readonly object _lastExecutionResultSyncLock = new object();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the last execution result.
|
/// Gets the last execution result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -123,38 +119,39 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
LazyInitializer.EnsureInitialized(ref _lastExecutionResult, ref _lastExecutionResultinitialized, ref _lastExecutionResultSyncLock, () =>
|
if (_lastExecutionResult == null)
|
||||||
{
|
{
|
||||||
var path = GetHistoryFilePath();
|
lock (_lastExecutionResultSyncLock)
|
||||||
|
{
|
||||||
|
if (_lastExecutionResult == null)
|
||||||
|
{
|
||||||
|
var path = GetHistoryFilePath();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return JsonSerializer.DeserializeFromFile<TaskResult>(path);
|
return JsonSerializer.DeserializeFromFile<TaskResult>(path);
|
||||||
|
}
|
||||||
|
catch (DirectoryNotFoundException)
|
||||||
|
{
|
||||||
|
// File doesn't exist. No biggie
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
// File doesn't exist. No biggie
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.ErrorException("Error deserializing {0}", ex, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (DirectoryNotFoundException)
|
}
|
||||||
{
|
|
||||||
// File doesn't exist. No biggie
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException)
|
|
||||||
{
|
|
||||||
// File doesn't exist. No biggie
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.ErrorException("Error deserializing {0}", ex, path);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return _lastExecutionResult;
|
return _lastExecutionResult;
|
||||||
}
|
}
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
_lastExecutionResult = value;
|
_lastExecutionResult = value;
|
||||||
|
|
||||||
_lastExecutionResultinitialized = value != null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,13 +224,9 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private IEnumerable<ITaskTrigger> _triggers;
|
private IEnumerable<ITaskTrigger> _triggers;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _triggers initialized
|
|
||||||
/// </summary>
|
|
||||||
private bool _triggersInitialized;
|
|
||||||
/// <summary>
|
|
||||||
/// The _triggers sync lock
|
/// The _triggers sync lock
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _triggersSyncLock = new object();
|
private readonly object _triggersSyncLock = new object();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the triggers that define when the task will run
|
/// Gets the triggers that define when the task will run
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -243,7 +236,16 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
LazyInitializer.EnsureInitialized(ref _triggers, ref _triggersInitialized, ref _triggersSyncLock, LoadTriggers);
|
if (_triggers == null)
|
||||||
|
{
|
||||||
|
lock (_triggersSyncLock)
|
||||||
|
{
|
||||||
|
if (_triggers == null)
|
||||||
|
{
|
||||||
|
_triggers = LoadTriggers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return _triggers;
|
return _triggers;
|
||||||
}
|
}
|
||||||
@ -262,8 +264,6 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||||||
|
|
||||||
_triggers = value.ToList();
|
_triggers = value.ToList();
|
||||||
|
|
||||||
_triggersInitialized = true;
|
|
||||||
|
|
||||||
ReloadTriggerEvents(false);
|
ReloadTriggerEvents(false);
|
||||||
|
|
||||||
SaveTriggers(_triggers);
|
SaveTriggers(_triggers);
|
||||||
@ -335,12 +335,30 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||||||
trigger.Start(false);
|
trigger.Start(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task _currentTask;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executes the task
|
/// Executes the task
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
/// <exception cref="System.InvalidOperationException">Cannot execute a Task that is already running</exception>
|
/// <exception cref="System.InvalidOperationException">Cannot execute a Task that is already running</exception>
|
||||||
public async Task Execute()
|
public async Task Execute()
|
||||||
|
{
|
||||||
|
var task = ExecuteInternal();
|
||||||
|
|
||||||
|
_currentTask = task;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await task.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_currentTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteInternal()
|
||||||
{
|
{
|
||||||
// Cancel the current execution, if any
|
// Cancel the current execution, if any
|
||||||
if (CurrentCancellationTokenSource != null)
|
if (CurrentCancellationTokenSource != null)
|
||||||
@ -544,6 +562,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||||||
Id = Id
|
Id = Id
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var hasKey = ScheduledTask as IHasKey;
|
||||||
|
if (hasKey != null)
|
||||||
|
{
|
||||||
|
result.Key = hasKey.Key;
|
||||||
|
}
|
||||||
|
|
||||||
if (ex != null)
|
if (ex != null)
|
||||||
{
|
{
|
||||||
result.ErrorMessage = ex.Message;
|
result.ErrorMessage = ex.Message;
|
||||||
@ -579,14 +603,60 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||||||
{
|
{
|
||||||
DisposeTriggers();
|
DisposeTriggers();
|
||||||
|
|
||||||
if (State == TaskState.Running)
|
var wassRunning = State == TaskState.Running;
|
||||||
|
var startTime = CurrentExecutionStartTime;
|
||||||
|
|
||||||
|
var token = CurrentCancellationTokenSource;
|
||||||
|
if (token != null)
|
||||||
{
|
{
|
||||||
OnTaskCompleted(CurrentExecutionStartTime, DateTime.UtcNow, TaskCompletionStatus.Aborted, null);
|
try
|
||||||
|
{
|
||||||
|
Logger.Debug(Name + ": Cancelling");
|
||||||
|
token.Cancel();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.ErrorException("Error calling CancellationToken.Cancel();", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var task = _currentTask;
|
||||||
|
if (task != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logger.Debug(Name + ": Waiting on Task");
|
||||||
|
var exited = Task.WaitAll(new[] { task }, 2000);
|
||||||
|
|
||||||
|
if (exited)
|
||||||
|
{
|
||||||
|
Logger.Debug(Name + ": Task exited");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Debug(Name + ": Timed out waiting for task to stop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.ErrorException("Error calling Task.WaitAll();", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentCancellationTokenSource != null)
|
if (token != null)
|
||||||
{
|
{
|
||||||
CurrentCancellationTokenSource.Dispose();
|
try
|
||||||
|
{
|
||||||
|
Logger.Debug(Name + ": Disposing CancellationToken");
|
||||||
|
token.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.ErrorException("Error calling CancellationToken.Dispose();", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wassRunning)
|
||||||
|
{
|
||||||
|
OnTaskCompleted(startTime, DateTime.UtcNow, TaskCompletionStatus.Aborted, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Delete(path);
|
_fileSystem.DeleteFile(path);
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
|
@ -76,7 +76,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
|
|||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
File.Delete(file.FullName);
|
_fileSystem.DeleteFile(file.FullName);
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Events;
|
using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Common.Implementations.Security;
|
using MediaBrowser.Common.Implementations.Security;
|
||||||
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Common.Plugins;
|
using MediaBrowser.Common.Plugins;
|
||||||
using MediaBrowser.Common.Progress;
|
using MediaBrowser.Common.Progress;
|
||||||
@ -106,6 +107,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
private readonly ISecurityManager _securityManager;
|
private readonly ISecurityManager _securityManager;
|
||||||
private readonly IConfigurationManager _config;
|
private readonly IConfigurationManager _config;
|
||||||
|
private readonly IFileSystem _fileSystem;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the application host.
|
/// Gets the application host.
|
||||||
@ -113,7 +115,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||||||
/// <value>The application host.</value>
|
/// <value>The application host.</value>
|
||||||
private readonly IApplicationHost _applicationHost;
|
private readonly IApplicationHost _applicationHost;
|
||||||
|
|
||||||
public InstallationManager(ILogger logger, IApplicationHost appHost, IApplicationPaths appPaths, IHttpClient httpClient, IJsonSerializer jsonSerializer, ISecurityManager securityManager, IConfigurationManager config)
|
public InstallationManager(ILogger logger, IApplicationHost appHost, IApplicationPaths appPaths, IHttpClient httpClient, IJsonSerializer jsonSerializer, ISecurityManager securityManager, IConfigurationManager config, IFileSystem fileSystem)
|
||||||
{
|
{
|
||||||
if (logger == null)
|
if (logger == null)
|
||||||
{
|
{
|
||||||
@ -129,6 +131,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||||||
_jsonSerializer = jsonSerializer;
|
_jsonSerializer = jsonSerializer;
|
||||||
_securityManager = securityManager;
|
_securityManager = securityManager;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
_fileSystem = fileSystem;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,7 +573,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Delete(tempFile);
|
_fileSystem.DeleteFile(tempFile);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
@ -591,7 +594,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||||||
// Remove it the quick way for now
|
// Remove it the quick way for now
|
||||||
_applicationHost.RemovePlugin(plugin);
|
_applicationHost.RemovePlugin(plugin);
|
||||||
|
|
||||||
File.Delete(plugin.AssemblyFilePath);
|
_fileSystem.DeleteFile(plugin.AssemblyFilePath);
|
||||||
|
|
||||||
OnPluginUninstalled(plugin);
|
OnPluginUninstalled(plugin);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="NLog" version="3.1.0.0" targetFramework="net45" />
|
<package id="NLog" version="3.2.0.0" targetFramework="net45" />
|
||||||
<package id="SimpleInjector" version="2.6.1" targetFramework="net45" />
|
<package id="SimpleInjector" version="2.7.0" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
||||||
|
@ -26,36 +26,6 @@ namespace MediaBrowser.Common.Extensions
|
|||||||
return Regex.Replace(htmlString, pattern, string.Empty).Trim();
|
return Regex.Replace(htmlString, pattern, string.Empty).Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Replaces the specified STR.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="str">The STR.</param>
|
|
||||||
/// <param name="oldValue">The old value.</param>
|
|
||||||
/// <param name="newValue">The new value.</param>
|
|
||||||
/// <param name="comparison">The comparison.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
public static string Replace(this string str, string oldValue, string newValue, StringComparison comparison)
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
|
|
||||||
var previousIndex = 0;
|
|
||||||
var index = str.IndexOf(oldValue, comparison);
|
|
||||||
|
|
||||||
while (index != -1)
|
|
||||||
{
|
|
||||||
sb.Append(str.Substring(previousIndex, index - previousIndex));
|
|
||||||
sb.Append(newValue);
|
|
||||||
index += oldValue.Length;
|
|
||||||
|
|
||||||
previousIndex = index;
|
|
||||||
index = str.IndexOf(oldValue, index, comparison);
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.Append(str.Substring(previousIndex));
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string RemoveDiacritics(this string text)
|
public static string RemoveDiacritics(this string text)
|
||||||
{
|
{
|
||||||
return String.Concat(
|
return String.Concat(
|
||||||
|
@ -133,5 +133,33 @@ namespace MediaBrowser.Common.IO
|
|||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <returns><c>true</c> if [is path file] [the specified path]; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if [is path file] [the specified path]; otherwise, <c>false</c>.</returns>
|
||||||
bool IsPathFile(string path);
|
bool IsPathFile(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path.</param>
|
||||||
|
/// <param name="sendToRecycleBin">if set to <c>true</c> [send to recycle bin].</param>
|
||||||
|
void DeleteFile(string path, bool sendToRecycleBin);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path.</param>
|
||||||
|
/// <param name="recursive">if set to <c>true</c> [recursive].</param>
|
||||||
|
/// <param name="sendToRecycleBin">if set to <c>true</c> [send to recycle bin].</param>
|
||||||
|
void DeleteDirectory(string path, bool recursive, bool sendToRecycleBin);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path.</param>
|
||||||
|
void DeleteFile(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path.</param>
|
||||||
|
/// <param name="recursive">if set to <c>true</c> [recursive].</param>
|
||||||
|
void DeleteDirectory(string path, bool recursive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,5 +51,12 @@ namespace MediaBrowser.Common.Net
|
|||||||
/// <param name="endpoint">The endpoint.</param>
|
/// <param name="endpoint">The endpoint.</param>
|
||||||
/// <returns><c>true</c> if [is in local network] [the specified endpoint]; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if [is in local network] [the specified endpoint]; otherwise, <c>false</c>.</returns>
|
||||||
bool IsInLocalNetwork(string endpoint);
|
bool IsInLocalNetwork(string endpoint);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a self signed certificate at the locatation specified by <paramref name="certificatePath"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="certificatePath">The path to generate the certificate.</param>
|
||||||
|
/// <param name="hostname">The common name for the certificate.</param>
|
||||||
|
void GenerateSelfSignedSslCertificate(string certificatePath, string hostname);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Channels
|
namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
@ -14,9 +15,19 @@ namespace MediaBrowser.Controller.Channels
|
|||||||
|
|
||||||
public override bool IsVisible(User user)
|
public override bool IsVisible(User user)
|
||||||
{
|
{
|
||||||
if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
|
if (user.Policy.BlockedChannels != null)
|
||||||
{
|
{
|
||||||
return false;
|
if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.IsVisible(user);
|
return base.IsVisible(user);
|
||||||
@ -50,7 +61,22 @@ namespace MediaBrowser.Controller.Channels
|
|||||||
|
|
||||||
protected override string GetInternalMetadataPath(string basePath)
|
protected override string GetInternalMetadataPath(string basePath)
|
||||||
{
|
{
|
||||||
return System.IO.Path.Combine(basePath, "channels", Id.ToString("N"), "metadata");
|
return GetInternalMetadataPath(basePath, Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetInternalMetadataPath(string basePath, Guid id)
|
||||||
|
{
|
||||||
|
return System.IO.Path.Combine(basePath, "channels", id.ToString("N"), "metadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool IsAllowTagFilterEnforced()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,10 @@ using MediaBrowser.Model.Channels;
|
|||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using MediaBrowser.Model.Users;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Channels
|
namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
@ -32,7 +32,7 @@ namespace MediaBrowser.Controller.Channels
|
|||||||
return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
|
return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
return ExternalId;
|
return ExternalId;
|
||||||
}
|
}
|
||||||
@ -89,5 +89,10 @@ namespace MediaBrowser.Controller.Channels
|
|||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
using System;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Model.Channels;
|
using MediaBrowser.Model.Channels;
|
||||||
using MediaBrowser.Model.Configuration;
|
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Model.Users;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Channels
|
namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
@ -40,7 +39,7 @@ namespace MediaBrowser.Controller.Channels
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
return ExternalId;
|
return ExternalId;
|
||||||
}
|
}
|
||||||
@ -76,5 +75,10 @@ namespace MediaBrowser.Controller.Channels
|
|||||||
{
|
{
|
||||||
return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N"));
|
return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ using MediaBrowser.Model.Channels;
|
|||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using MediaBrowser.Model.Users;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Channels
|
namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
@ -28,8 +28,8 @@ namespace MediaBrowser.Controller.Channels
|
|||||||
public string OriginalImageUrl { get; set; }
|
public string OriginalImageUrl { get; set; }
|
||||||
|
|
||||||
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
|
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
|
||||||
|
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
if (ContentType == ChannelMediaContentType.MovieExtra)
|
if (ContentType == ChannelMediaContentType.MovieExtra)
|
||||||
{
|
{
|
||||||
@ -119,5 +119,10 @@ namespace MediaBrowser.Controller.Channels
|
|||||||
{
|
{
|
||||||
return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N"));
|
return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,5 +60,12 @@ namespace MediaBrowser.Controller.Collections
|
|||||||
/// <param name="userId">The user identifier.</param>
|
/// <param name="userId">The user identifier.</param>
|
||||||
/// <returns>Folder.</returns>
|
/// <returns>Folder.</returns>
|
||||||
Folder GetCollectionsFolder(string userId);
|
Folder GetCollectionsFolder(string userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the collections.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <returns>IEnumerable<BoxSet>.</returns>
|
||||||
|
IEnumerable<BoxSet> GetCollections(User user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
MediaBrowser.Controller/Devices/CameraImageUploadInfo.cs
Normal file
10
MediaBrowser.Controller/Devices/CameraImageUploadInfo.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using MediaBrowser.Model.Devices;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Devices
|
||||||
|
{
|
||||||
|
public class CameraImageUploadInfo
|
||||||
|
{
|
||||||
|
public LocalFileInfo FileInfo { get; set; }
|
||||||
|
public DeviceInfo Device { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ using MediaBrowser.Model.Events;
|
|||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Session;
|
using MediaBrowser.Model.Session;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -15,6 +14,10 @@ namespace MediaBrowser.Controller.Devices
|
|||||||
/// Occurs when [device options updated].
|
/// Occurs when [device options updated].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event EventHandler<GenericEventArgs<DeviceInfo>> DeviceOptionsUpdated;
|
event EventHandler<GenericEventArgs<DeviceInfo>> DeviceOptionsUpdated;
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [camera image uploaded].
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<GenericEventArgs<CameraImageUploadInfo>> CameraImageUploaded;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers the device.
|
/// Registers the device.
|
||||||
|
@ -62,8 +62,9 @@ namespace MediaBrowser.Controller.Dlna
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="headers">The headers.</param>
|
/// <param name="headers">The headers.</param>
|
||||||
/// <param name="serverUuId">The server uu identifier.</param>
|
/// <param name="serverUuId">The server uu identifier.</param>
|
||||||
|
/// <param name="serverAddress">The server address.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
string GetServerDescriptionXml(IDictionary<string, string> headers, string serverUuId);
|
string GetServerDescriptionXml(IDictionary<string, string> headers, string serverUuId, string serverAddress);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the icon.
|
/// Gets the icon.
|
||||||
|
7
MediaBrowser.Controller/Dlna/IMediaReceiverRegistrar.cs
Normal file
7
MediaBrowser.Controller/Dlna/IMediaReceiverRegistrar.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Dlna
|
||||||
|
{
|
||||||
|
public interface IMediaReceiverRegistrar : IEventManager, IUpnpService
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Dto
|
|||||||
public List<ImageType> ImageTypes { get; set; }
|
public List<ImageType> ImageTypes { get; set; }
|
||||||
public int ImageTypeLimit { get; set; }
|
public int ImageTypeLimit { get; set; }
|
||||||
public bool EnableImages { get; set; }
|
public bool EnableImages { get; set; }
|
||||||
|
public string DeviceId { get; set; }
|
||||||
|
|
||||||
public DtoOptions()
|
public DtoOptions()
|
||||||
{
|
{
|
||||||
|
@ -44,6 +44,17 @@ namespace MediaBrowser.Controller.Dto
|
|||||||
/// <param name="owner">The owner.</param>
|
/// <param name="owner">The owner.</param>
|
||||||
/// <returns>BaseItemDto.</returns>
|
/// <returns>BaseItemDto.</returns>
|
||||||
BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null);
|
BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the base item dtos.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">The items.</param>
|
||||||
|
/// <param name="options">The options.</param>
|
||||||
|
/// <param name="user">The user.</param>
|
||||||
|
/// <param name="owner">The owner.</param>
|
||||||
|
/// <returns>IEnumerable<BaseItemDto>.</returns>
|
||||||
|
IEnumerable<BaseItemDto> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null,
|
||||||
|
BaseItem owner = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the chapter information dto.
|
/// Gets the chapter information dto.
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
|
||||||
{
|
|
||||||
[Obsolete]
|
|
||||||
public class AdultVideo : Video, IHasProductionLocations, IHasTaglines
|
|
||||||
{
|
|
||||||
public List<string> ProductionLocations { get; set; }
|
|
||||||
|
|
||||||
public List<string> Taglines { get; set; }
|
|
||||||
|
|
||||||
public AdultVideo()
|
|
||||||
{
|
|
||||||
Taglines = new List<string>();
|
|
||||||
ProductionLocations = new List<string>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,6 +32,11 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _virtual children
|
/// The _virtual children
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -66,7 +71,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
{
|
{
|
||||||
var path = ContainingFolderPath;
|
var path = ContainingFolderPath;
|
||||||
|
|
||||||
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager, directoryService)
|
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths , directoryService)
|
||||||
{
|
{
|
||||||
FileInfo = new DirectoryInfo(path),
|
FileInfo = new DirectoryInfo(path),
|
||||||
Path = path,
|
Path = path,
|
||||||
|
@ -4,11 +4,11 @@ using MediaBrowser.Model.Configuration;
|
|||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using MediaBrowser.Model.Users;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities.Audio
|
namespace MediaBrowser.Controller.Entities.Audio
|
||||||
{
|
{
|
||||||
@ -80,6 +80,15 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
protected override bool SupportsOwnedItems
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public override Folder LatestItemsIndexContainer
|
public override Folder LatestItemsIndexContainer
|
||||||
{
|
{
|
||||||
@ -104,6 +113,13 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDownload()
|
||||||
|
{
|
||||||
|
var locationType = LocationType;
|
||||||
|
return locationType != LocationType.Remote &&
|
||||||
|
locationType != LocationType.Virtual;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the artist.
|
/// Gets or sets the artist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -169,7 +185,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
var parent = FindParent<MusicAlbum>();
|
var parent = FindParent<MusicAlbum>();
|
||||||
|
|
||||||
@ -186,7 +202,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.GetUserDataKey();
|
return base.CreateUserDataKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||||
@ -223,7 +239,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
{
|
{
|
||||||
Id = i.Id.ToString("N"),
|
Id = i.Id.ToString("N"),
|
||||||
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
|
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
|
||||||
MediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(),
|
MediaStreams = MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(),
|
||||||
Name = i.Name,
|
Name = i.Name,
|
||||||
Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path,
|
Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path,
|
||||||
RunTimeTicks = i.RunTimeTicks,
|
RunTimeTicks = i.RunTimeTicks,
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using MediaBrowser.Model.Users;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities.Audio
|
namespace MediaBrowser.Controller.Entities.Audio
|
||||||
{
|
{
|
||||||
@ -52,14 +52,14 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> AlbumArtists { get; set; }
|
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public string AlbumArtist
|
public string AlbumArtist
|
||||||
{
|
{
|
||||||
get { return AlbumArtists.FirstOrDefault(); }
|
get { return AlbumArtists.FirstOrDefault(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<string> AlbumArtists { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the tracks.
|
/// Gets the tracks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -68,7 +68,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return RecursiveChildren.OfType<Audio>();
|
return GetRecursiveChildren(i => i is Audio).Cast<Audio>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
var id = this.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
var id = this.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
return "MusicAlbum-Musicbrainz-" + id;
|
return "MusicAlbum-Musicbrainz-" + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.GetUserDataKey();
|
return base.CreateUserDataKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||||
@ -173,17 +173,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
id.ArtistProviderIds = artist.ProviderIds;
|
id.ArtistProviderIds = artist.ProviderIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
id.SongInfos = RecursiveChildren.OfType<Audio>()
|
id.SongInfos = GetRecursiveChildren(i => i is Audio)
|
||||||
|
.Cast<Audio>()
|
||||||
.Select(i => i.GetLookupInfo())
|
.Select(i => i.GetLookupInfo())
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete]
|
|
||||||
public class MusicAlbumDisc : Folder
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
using System.Runtime.Serialization;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Common.Progress;
|
|
||||||
using MediaBrowser.Controller.Providers;
|
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Model.Users;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities.Audio
|
namespace MediaBrowser.Controller.Entities.Audio
|
||||||
{
|
{
|
||||||
@ -19,7 +18,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
{
|
{
|
||||||
public bool IsAccessedByName { get; set; }
|
public bool IsAccessedByName { get; set; }
|
||||||
public List<string> ProductionLocations { get; set; }
|
public List<string> ProductionLocations { get; set; }
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
public override bool IsFolder
|
public override bool IsFolder
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -34,6 +34,11 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
get { return true; }
|
get { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return !IsAccessedByName;
|
||||||
|
}
|
||||||
|
|
||||||
protected override IEnumerable<BaseItem> ActualChildren
|
protected override IEnumerable<BaseItem> ActualChildren
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -68,7 +73,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
return GetUserDataKey(this);
|
return GetUserDataKey(this);
|
||||||
}
|
}
|
||||||
@ -78,6 +83,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// If the item is a folder, it returns the folder itself
|
/// If the item is a folder, it returns the folder itself
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The containing folder path.</value>
|
/// <value>The containing folder path.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
public override string ContainingFolderPath
|
public override string ContainingFolderPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -90,6 +96,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// Gets a value indicating whether this instance is owned item.
|
/// Gets a value indicating whether this instance is owned item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
public override bool IsOwnedItem
|
public override bool IsOwnedItem
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -122,89 +129,53 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
|
|
||||||
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
|
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var items = RecursiveChildren.ToList();
|
var items = GetRecursiveChildren().ToList();
|
||||||
|
|
||||||
var songs = items.OfType<Audio>().ToList();
|
var songs = items.OfType<Audio>().ToList();
|
||||||
|
|
||||||
var others = items.Except(songs).ToList();
|
var others = items.Except(songs).ToList();
|
||||||
|
|
||||||
var totalItems = songs.Count + others.Count;
|
var totalItems = songs.Count + others.Count;
|
||||||
var percentages = new Dictionary<Guid, double>(totalItems);
|
var numComplete = 0;
|
||||||
|
|
||||||
var tasks = new List<Task>();
|
|
||||||
|
|
||||||
// Refresh songs
|
// Refresh songs
|
||||||
foreach (var item in songs)
|
foreach (var item in songs)
|
||||||
{
|
{
|
||||||
if (tasks.Count >= 2)
|
|
||||||
{
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
|
||||||
tasks.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
var innerProgress = new ActionableProgress<double>();
|
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
var currentChild = item;
|
|
||||||
innerProgress.RegisterAction(p =>
|
|
||||||
{
|
|
||||||
lock (percentages)
|
|
||||||
{
|
|
||||||
percentages[currentChild.Id] = p / 100;
|
|
||||||
|
|
||||||
var percent = percentages.Values.Sum();
|
numComplete++;
|
||||||
percent /= totalItems;
|
double percent = numComplete;
|
||||||
percent *= 100;
|
percent /= totalItems;
|
||||||
progress.Report(percent);
|
progress.Report(percent * 100);
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var taskChild = item;
|
|
||||||
tasks.Add(Task.Run(async () => await RefreshItem(taskChild, refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
|
||||||
tasks.Clear();
|
|
||||||
|
|
||||||
// Refresh current item
|
// Refresh current item
|
||||||
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// Refresh all non-songs
|
// Refresh all non-songs
|
||||||
foreach (var item in others)
|
foreach (var item in others)
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
|
||||||
var currentChild = item;
|
|
||||||
|
|
||||||
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
lock (percentages)
|
|
||||||
{
|
|
||||||
percentages[currentChild.Id] = 1;
|
|
||||||
|
|
||||||
var percent = percentages.Values.Sum();
|
numComplete++;
|
||||||
percent /= totalItems;
|
double percent = numComplete;
|
||||||
percent *= 100;
|
percent /= totalItems;
|
||||||
progress.Report(percent);
|
progress.Report(percent * 100);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
progress.Report(100);
|
progress.Report(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RefreshItem(BaseItem item, MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
progress.Report(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArtistInfo GetLookupInfo()
|
public ArtistInfo GetLookupInfo()
|
||||||
{
|
{
|
||||||
var info = GetItemLookupInfo<ArtistInfo>();
|
var info = GetItemLookupInfo<ArtistInfo>();
|
||||||
|
|
||||||
info.SongInfos = RecursiveChildren.OfType<Audio>()
|
info.SongInfos = GetRecursiveChildren(i => i is Audio)
|
||||||
|
.Cast<Audio>()
|
||||||
.Select(i => i.GetLookupInfo())
|
.Select(i => i.GetLookupInfo())
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@ -213,9 +184,16 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
|
|
||||||
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
|
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
|
||||||
{
|
{
|
||||||
return inputItems.OfType<IHasArtist>()
|
return inputItems.Where(GetItemFilter());
|
||||||
.Where(i => i.HasArtist(Name))
|
}
|
||||||
.Cast<BaseItem>();
|
|
||||||
|
public Func<BaseItem, bool> GetItemFilter()
|
||||||
|
{
|
||||||
|
return i =>
|
||||||
|
{
|
||||||
|
var hasArtist = i as IHasArtist;
|
||||||
|
return hasArtist != null && hasArtist.HasArtist(Name);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
return "MusicGenre-" + Name;
|
return "MusicGenre-" + Name;
|
||||||
}
|
}
|
||||||
@ -30,6 +30,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// If the item is a folder, it returns the folder itself
|
/// If the item is a folder, it returns the folder itself
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The containing folder path.</value>
|
/// <value>The containing folder path.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
public override string ContainingFolderPath
|
public override string ContainingFolderPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -38,10 +39,16 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this instance is owned item.
|
/// Gets a value indicating whether this instance is owned item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
public override bool IsOwnedItem
|
public override bool IsOwnedItem
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -52,7 +59,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
|
|
||||||
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
|
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
|
||||||
{
|
{
|
||||||
return inputItems.Where(i => (i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase));
|
return inputItems.Where(GetItemFilter());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<BaseItem, bool> GetItemFilter()
|
||||||
|
{
|
||||||
|
return i => (i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,6 +239,38 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
get { return this.GetImagePath(ImageType.Primary); }
|
get { return this.GetImagePath(ImageType.Primary); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool CanDelete()
|
||||||
|
{
|
||||||
|
var locationType = LocationType;
|
||||||
|
return locationType != LocationType.Remote &&
|
||||||
|
locationType != LocationType.Virtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool IsAuthorizedToDelete(User user)
|
||||||
|
{
|
||||||
|
return user.Policy.EnableContentDeletion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanDelete(User user)
|
||||||
|
{
|
||||||
|
return CanDelete() && IsAuthorizedToDelete(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool CanDownload()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool IsAuthorizedToDownload(User user)
|
||||||
|
{
|
||||||
|
return user.Policy.EnableContentDownloading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanDownload(User user)
|
||||||
|
{
|
||||||
|
return CanDownload() && IsAuthorizedToDownload(user);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the date created.
|
/// Gets or sets the date created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -268,6 +300,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
public static IChannelManager ChannelManager { get; set; }
|
public static IChannelManager ChannelManager { get; set; }
|
||||||
public static ICollectionManager CollectionManager { get; set; }
|
public static ICollectionManager CollectionManager { get; set; }
|
||||||
public static IImageProcessor ImageProcessor { get; set; }
|
public static IImageProcessor ImageProcessor { get; set; }
|
||||||
|
public static IMediaSourceManager MediaSourceManager { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||||
@ -359,7 +392,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(ForcedSortName))
|
if (!string.IsNullOrWhiteSpace(ForcedSortName))
|
||||||
{
|
{
|
||||||
return ForcedSortName;
|
return ForcedSortName;
|
||||||
}
|
}
|
||||||
@ -379,21 +412,19 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
public string GetInternalMetadataPath()
|
public string GetInternalMetadataPath()
|
||||||
{
|
{
|
||||||
return GetInternalMetadataPath(ConfigurationManager.ApplicationPaths.InternalMetadataPath);
|
var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath;
|
||||||
|
|
||||||
|
return GetInternalMetadataPath(basePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string GetInternalMetadataPath(string basePath)
|
protected virtual string GetInternalMetadataPath(string basePath)
|
||||||
{
|
{
|
||||||
var idString = Id.ToString("N");
|
var idString = Id.ToString("N");
|
||||||
|
|
||||||
return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString);
|
if (ConfigurationManager.Configuration.EnableLibraryMetadataSubFolder)
|
||||||
}
|
{
|
||||||
|
basePath = System.IO.Path.Combine(basePath, "library");
|
||||||
public static string GetInternalMetadataPathForId(Guid id)
|
}
|
||||||
{
|
|
||||||
var idString = id.ToString("N");
|
|
||||||
|
|
||||||
var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath;
|
|
||||||
|
|
||||||
return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString);
|
return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString);
|
||||||
}
|
}
|
||||||
@ -692,7 +723,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
var requiresSave = false;
|
var requiresSave = false;
|
||||||
|
|
||||||
if (IsFolder || Parent != null)
|
if (SupportsOwnedItems)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -724,6 +755,12 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
protected virtual bool SupportsOwnedItems
|
||||||
|
{
|
||||||
|
get { return IsFolder || Parent != null; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refreshes owned items such as trailers, theme videos, special features, etc.
|
/// Refreshes owned items such as trailers, theme videos, special features, etc.
|
||||||
/// Returns true or false indicating if changes were found.
|
/// Returns true or false indicating if changes were found.
|
||||||
@ -889,11 +926,24 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
get { return null; }
|
get { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string _userDataKey;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
public virtual string GetUserDataKey()
|
public string GetUserDataKey()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(_userDataKey))
|
||||||
|
{
|
||||||
|
var key = CreateUserDataKey();
|
||||||
|
_userDataKey = key;
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _userDataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
return Id.ToString();
|
return Id.ToString();
|
||||||
}
|
}
|
||||||
@ -905,6 +955,12 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
return current.IsInMixedFolder == newItem.IsInMixedFolder;
|
return current.IsInMixedFolder == newItem.IsInMixedFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AfterMetadataRefresh()
|
||||||
|
{
|
||||||
|
_sortName = null;
|
||||||
|
_userDataKey = null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the preferred metadata language.
|
/// Gets the preferred metadata language.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1024,7 +1080,8 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
if (hasTags != null)
|
if (hasTags != null)
|
||||||
{
|
{
|
||||||
if (user.Policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase)))
|
var policy = user.Policy;
|
||||||
|
if (policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1033,6 +1090,11 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual bool IsAllowTagFilterEnforced()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the block unrated value.
|
/// Gets the block unrated value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1060,6 +1122,23 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
return IsParentalAllowed(user);
|
return IsParentalAllowed(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool IsVisibleStandalone(User user)
|
||||||
|
{
|
||||||
|
if (!IsVisible(user))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parents.Any(i => !i.IsVisible(user)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Need some work here, e.g. is in user library, for channels, can user access channel, etc.
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this instance is folder.
|
/// Gets a value indicating whether this instance is folder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1146,7 +1225,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(info.ItemName) && !string.IsNullOrWhiteSpace(info.ItemType))
|
if (!string.IsNullOrWhiteSpace(info.ItemName) && !string.IsNullOrWhiteSpace(info.ItemType))
|
||||||
{
|
{
|
||||||
return LibraryManager.RootFolder.RecursiveChildren.FirstOrDefault(i =>
|
return LibraryManager.RootFolder.GetRecursiveChildren(i =>
|
||||||
{
|
{
|
||||||
if (string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@ -1164,7 +1243,8 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
|
||||||
|
}).FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -1458,7 +1538,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
currentFile.Attributes &= ~FileAttributes.Hidden;
|
currentFile.Attributes &= ~FileAttributes.Hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentFile.Delete();
|
FileSystem.DeleteFile(currentFile.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
|
return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
|
||||||
@ -1703,6 +1783,9 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool BeforeMetadataRefresh()
|
public virtual bool BeforeMetadataRefresh()
|
||||||
{
|
{
|
||||||
|
_userDataKey = null;
|
||||||
|
_sortName = null;
|
||||||
|
|
||||||
var hasChanges = false;
|
var hasChanges = false;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(Path))
|
if (string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(Path))
|
||||||
|
@ -11,5 +11,10 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
{
|
{
|
||||||
get { return null; }
|
get { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Users;
|
using MediaBrowser.Model.Users;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
namespace MediaBrowser.Controller.Entities
|
||||||
@ -37,6 +38,13 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
Tags = new List<string>();
|
Tags = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDownload()
|
||||||
|
{
|
||||||
|
var locationType = LocationType;
|
||||||
|
return locationType != LocationType.Remote &&
|
||||||
|
locationType != LocationType.Virtual;
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||||
{
|
{
|
||||||
return config.BlockUnratedItems.Contains(UnratedItem.Book);
|
return config.BlockUnratedItems.Contains(UnratedItem.Book);
|
||||||
|
@ -35,6 +35,11 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public string CollectionType { get; set; }
|
public string CollectionType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -86,7 +91,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
{
|
{
|
||||||
var path = ContainingFolderPath;
|
var path = ContainingFolderPath;
|
||||||
|
|
||||||
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager, directoryService)
|
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
|
||||||
{
|
{
|
||||||
FileInfo = new DirectoryInfo(path),
|
FileInfo = new DirectoryInfo(path),
|
||||||
Path = path,
|
Path = path,
|
||||||
@ -121,12 +126,6 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache this since it will be used a lot
|
|
||||||
/// <summary>
|
|
||||||
/// The null task result
|
|
||||||
/// </summary>
|
|
||||||
private static readonly Task NullTaskResult = Task.FromResult<object>(null);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes
|
/// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes
|
||||||
/// ***Currently does not contain logic to maintain items that are unavailable in the file system***
|
/// ***Currently does not contain logic to maintain items that are unavailable in the file system***
|
||||||
@ -138,7 +137,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// <param name="refreshOptions">The refresh options.</param>
|
/// <param name="refreshOptions">The refresh options.</param>
|
||||||
/// <param name="directoryService">The directory service.</param>
|
/// <param name="directoryService">The directory service.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
protected override async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
|
protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
var list = PhysicalLocationsList.ToList();
|
var list = PhysicalLocationsList.ToList();
|
||||||
|
|
||||||
@ -146,8 +145,10 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
if (!list.SequenceEqual(PhysicalLocationsList))
|
if (!list.SequenceEqual(PhysicalLocationsList))
|
||||||
{
|
{
|
||||||
await UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
|
return UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -6,7 +6,6 @@ using MediaBrowser.Controller.Providers;
|
|||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MoreLinq;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -15,13 +14,14 @@ 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.Model.Users;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class Folder
|
/// Class Folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Folder : BaseItem, IHasThemeMedia, IHasTags
|
public class Folder : BaseItem, IHasThemeMedia, IHasTags, IHasPreferredMetadataLanguage
|
||||||
{
|
{
|
||||||
public static IUserManager UserManager { get; set; }
|
public static IUserManager UserManager { get; set; }
|
||||||
public static IUserViewManager UserViewManager { get; set; }
|
public static IUserViewManager UserViewManager { get; set; }
|
||||||
@ -30,6 +30,14 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
public List<Guid> ThemeVideoIds { get; set; }
|
public List<Guid> ThemeVideoIds { get; set; }
|
||||||
public List<string> Tags { get; set; }
|
public List<string> Tags { get; set; }
|
||||||
|
|
||||||
|
public string PreferredMetadataLanguage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the preferred metadata country code.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The preferred metadata country code.</value>
|
||||||
|
public string PreferredMetadataCountryCode { get; set; }
|
||||||
|
|
||||||
public Folder()
|
public Folder()
|
||||||
{
|
{
|
||||||
LinkedChildren = new List<LinkedChild>();
|
LinkedChildren = new List<LinkedChild>();
|
||||||
@ -72,6 +80,19 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool IsAllowTagFilterEnforced()
|
||||||
|
{
|
||||||
|
if (this is ICollectionFolder)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this is UserView)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether this instance is physical root.
|
/// Gets or sets a value indicating whether this instance is physical root.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -98,6 +119,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
public virtual List<LinkedChild> LinkedChildren { get; set; }
|
public virtual List<LinkedChild> LinkedChildren { get; set; }
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
protected virtual bool SupportsShortcutChildren
|
protected virtual bool SupportsShortcutChildren
|
||||||
{
|
{
|
||||||
get { return true; }
|
get { return true; }
|
||||||
@ -237,14 +259,13 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
protected virtual IEnumerable<string> GetIndexByOptions()
|
protected virtual IEnumerable<string> GetIndexByOptions()
|
||||||
{
|
{
|
||||||
return new List<string> {
|
return new List<string> {
|
||||||
{LocalizedStrings.Instance.GetString("NoneDispPref")},
|
{"None"},
|
||||||
{LocalizedStrings.Instance.GetString("PerformerDispPref")},
|
{"Performer"},
|
||||||
{LocalizedStrings.Instance.GetString("GenreDispPref")},
|
{"Genre"},
|
||||||
{LocalizedStrings.Instance.GetString("DirectorDispPref")},
|
{"Director"},
|
||||||
{LocalizedStrings.Instance.GetString("YearDispPref")},
|
{"Year"},
|
||||||
{LocalizedStrings.Instance.GetString("StudioDispPref")}
|
{"Studio"}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -275,7 +296,17 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _children ?? (_children = LoadChildrenInternal());
|
if (_children == null)
|
||||||
|
{
|
||||||
|
lock (_childrenSyncLock)
|
||||||
|
{
|
||||||
|
if (_children == null)
|
||||||
|
{
|
||||||
|
_children = LoadChildrenInternal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _children;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,14 +332,24 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
public override bool IsVisible(User user)
|
public override bool IsVisible(User user)
|
||||||
{
|
{
|
||||||
if (this is ICollectionFolder)
|
if (this is ICollectionFolder && !(this is BasePluginFolder))
|
||||||
{
|
{
|
||||||
if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) ||
|
if (user.Policy.BlockedMediaFolders != null)
|
||||||
|
|
||||||
// Backwards compatibility
|
|
||||||
user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
return false;
|
if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) ||
|
||||||
|
|
||||||
|
// Backwards compatibility
|
||||||
|
user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,12 +386,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true)
|
public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true)
|
||||||
{
|
{
|
||||||
return ValidateChildrenWithCancellationSupport(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService);
|
return ValidateChildrenInternal(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService);
|
||||||
}
|
|
||||||
|
|
||||||
private Task ValidateChildrenWithCancellationSupport(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
|
|
||||||
{
|
|
||||||
return ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<Guid, BaseItem> GetActualChildrenDictionary()
|
private Dictionary<Guid, BaseItem> GetActualChildrenDictionary()
|
||||||
@ -540,50 +576,49 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
var children = ActualChildren.ToList();
|
var children = ActualChildren.ToList();
|
||||||
|
|
||||||
var percentages = new Dictionary<Guid, double>(children.Count);
|
var percentages = new Dictionary<Guid, double>(children.Count);
|
||||||
|
var numComplete = 0;
|
||||||
var tasks = new List<Task>();
|
var count = children.Count;
|
||||||
|
|
||||||
foreach (var child in children)
|
foreach (var child in children)
|
||||||
{
|
{
|
||||||
if (tasks.Count >= 2)
|
|
||||||
{
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
|
||||||
tasks.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
var innerProgress = new ActionableProgress<double>();
|
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
|
||||||
var currentChild = child;
|
|
||||||
innerProgress.RegisterAction(p =>
|
|
||||||
{
|
|
||||||
lock (percentages)
|
|
||||||
{
|
|
||||||
percentages[currentChild.Id] = p / 100;
|
|
||||||
|
|
||||||
var percent = percentages.Values.Sum();
|
|
||||||
percent /= children.Count;
|
|
||||||
percent *= 100;
|
|
||||||
progress.Report(percent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (child.IsFolder)
|
if (child.IsFolder)
|
||||||
{
|
{
|
||||||
|
var innerProgress = new ActionableProgress<double>();
|
||||||
|
|
||||||
|
// Avoid implicitly captured closure
|
||||||
|
var currentChild = child;
|
||||||
|
innerProgress.RegisterAction(p =>
|
||||||
|
{
|
||||||
|
lock (percentages)
|
||||||
|
{
|
||||||
|
percentages[currentChild.Id] = p / 100;
|
||||||
|
|
||||||
|
var innerPercent = percentages.Values.Sum();
|
||||||
|
innerPercent /= count;
|
||||||
|
innerPercent *= 100;
|
||||||
|
progress.Report(innerPercent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken)
|
await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Avoid implicitly captured closure
|
await RefreshChildMetadata(child, refreshOptions, false, new Progress<double>(), cancellationToken)
|
||||||
var taskChild = child;
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
tasks.Add(Task.Run(async () => await RefreshChildMetadata(taskChild, refreshOptions, false, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
numComplete++;
|
||||||
|
double percent = numComplete;
|
||||||
|
percent /= count;
|
||||||
|
percent *= 100;
|
||||||
|
|
||||||
|
progress.Report(percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
|
||||||
progress.Report(100);
|
progress.Report(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,7 +683,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await child.ValidateChildrenWithCancellationSupport(innerProgress, cancellationToken, true, false, null, directoryService)
|
await child.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -678,12 +713,12 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
path = System.IO.Path.GetDirectoryName(path);
|
path = System.IO.Path.GetDirectoryName(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ContainsPath(LibraryManager.GetDefaultVirtualFolders(), originalPath))
|
if (ContainsPath(LibraryManager.GetVirtualFolders(), originalPath))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return UserManager.Users.Any(user => ContainsPath(LibraryManager.GetVirtualFolders(user), originalPath));
|
return ContainsPath(LibraryManager.GetVirtualFolders(), originalPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -731,28 +766,6 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
return childrenItems;
|
return childrenItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the child.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="child">The child.</param>
|
|
||||||
/// <returns>BaseItem.</returns>
|
|
||||||
private BaseItem RetrieveChild(Guid child)
|
|
||||||
{
|
|
||||||
var item = LibraryManager.GetItemById(child);
|
|
||||||
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
if (item is IByReferenceItem)
|
|
||||||
{
|
|
||||||
return LibraryManager.GetOrAddByReferenceItem(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
item.Parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BaseItem RetrieveChild(BaseItem child)
|
private BaseItem RetrieveChild(BaseItem child)
|
||||||
{
|
{
|
||||||
if (child.Id == Guid.Empty)
|
if (child.Id == Guid.Empty)
|
||||||
@ -786,18 +799,31 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
{
|
{
|
||||||
var user = query.User;
|
var user = query.User;
|
||||||
|
|
||||||
var items = query.Recursive
|
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
|
||||||
? GetRecursiveChildren(user)
|
|
||||||
: GetChildren(user, true);
|
|
||||||
|
|
||||||
var result = SortAndFilter(items, query);
|
IEnumerable<BaseItem> items;
|
||||||
|
|
||||||
|
if (query.User == null)
|
||||||
|
{
|
||||||
|
items = query.Recursive
|
||||||
|
? GetRecursiveChildren(filter)
|
||||||
|
: Children.Where(filter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
items = query.Recursive
|
||||||
|
? GetRecursiveChildren(user, filter)
|
||||||
|
: GetChildren(user, true).Where(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = PostFilterAndSort(items, query);
|
||||||
|
|
||||||
return Task.FromResult(result);
|
return Task.FromResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items, InternalItemsQuery query)
|
protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return UserViewBuilder.SortAndFilter(items, this, null, query, LibraryManager, UserDataManager);
|
return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -822,11 +848,11 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
//the true root should return our users root folder children
|
//the true root should return our users root folder children
|
||||||
if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, includeLinkedChildren);
|
if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, includeLinkedChildren);
|
||||||
|
|
||||||
var list = new List<BaseItem>();
|
var result = new Dictionary<Guid, BaseItem>();
|
||||||
|
|
||||||
var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, includeHidden, false);
|
AddChildren(user, includeLinkedChildren, result, includeHidden, false, null);
|
||||||
|
|
||||||
return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list;
|
return result.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
protected virtual IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
||||||
@ -839,31 +865,30 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">The user.</param>
|
/// <param name="user">The user.</param>
|
||||||
/// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param>
|
/// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param>
|
||||||
/// <param name="list">The list.</param>
|
/// <param name="result">The result.</param>
|
||||||
/// <param name="includeHidden">if set to <c>true</c> [include hidden].</param>
|
/// <param name="includeHidden">if set to <c>true</c> [include hidden].</param>
|
||||||
/// <param name="recursive">if set to <c>true</c> [recursive].</param>
|
/// <param name="recursive">if set to <c>true</c> [recursive].</param>
|
||||||
|
/// <param name="filter">The filter.</param>
|
||||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||||
private bool AddChildrenToList(User user, bool includeLinkedChildren, List<BaseItem> list, bool includeHidden, bool recursive)
|
private void AddChildren(User user, bool includeLinkedChildren, Dictionary<Guid, BaseItem> result, bool includeHidden, bool recursive, Func<BaseItem, bool> filter)
|
||||||
{
|
{
|
||||||
var hasLinkedChildren = false;
|
|
||||||
|
|
||||||
foreach (var child in GetEligibleChildrenForRecursiveChildren(user))
|
foreach (var child in GetEligibleChildrenForRecursiveChildren(user))
|
||||||
{
|
{
|
||||||
if (child.IsVisible(user))
|
if (child.IsVisible(user))
|
||||||
{
|
{
|
||||||
if (includeHidden || !child.IsHiddenFromUser(user))
|
if (includeHidden || !child.IsHiddenFromUser(user))
|
||||||
{
|
{
|
||||||
list.Add(child);
|
if (filter == null || filter(child))
|
||||||
|
{
|
||||||
|
result[child.Id] = child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recursive && child.IsFolder)
|
if (recursive && child.IsFolder)
|
||||||
{
|
{
|
||||||
var folder = (Folder)child;
|
var folder = (Folder)child;
|
||||||
|
|
||||||
if (folder.AddChildrenToList(user, includeLinkedChildren, list, includeHidden, true))
|
folder.AddChildren(user, includeLinkedChildren, result, includeHidden, true, filter);
|
||||||
{
|
|
||||||
hasLinkedChildren = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -874,14 +899,13 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
{
|
{
|
||||||
if (child.IsVisible(user))
|
if (child.IsVisible(user))
|
||||||
{
|
{
|
||||||
hasLinkedChildren = true;
|
if (filter == null || filter(child))
|
||||||
|
{
|
||||||
list.Add(child);
|
result[child.Id] = child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasLinkedChildren;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -891,18 +915,23 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param>
|
/// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param>
|
||||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException"></exception>
|
/// <exception cref="System.ArgumentNullException"></exception>
|
||||||
public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true)
|
public IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true)
|
||||||
|
{
|
||||||
|
return GetRecursiveChildren(user, i => true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter)
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("user");
|
throw new ArgumentNullException("user");
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = new List<BaseItem>();
|
var result = new Dictionary<Guid, BaseItem>();
|
||||||
|
|
||||||
var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, false, true);
|
AddChildren(user, true, result, false, true, filter);
|
||||||
|
|
||||||
return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list;
|
return result.Values;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -910,10 +939,15 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>IList{BaseItem}.</returns>
|
/// <returns>IList{BaseItem}.</returns>
|
||||||
public IList<BaseItem> GetRecursiveChildren()
|
public IList<BaseItem> GetRecursiveChildren()
|
||||||
|
{
|
||||||
|
return GetRecursiveChildren(i => true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter)
|
||||||
{
|
{
|
||||||
var list = new List<BaseItem>();
|
var list = new List<BaseItem>();
|
||||||
|
|
||||||
AddChildrenToList(list, true, null);
|
AddChildrenToList(list, true, filter);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@ -1022,6 +1056,15 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
.Where(i => i.Item2 != null);
|
.Where(i => i.Item2 != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
protected override bool SupportsOwnedItems
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return base.SupportsOwnedItems || SupportsShortcutChildren;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
|
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var changesFound = false;
|
var changesFound = false;
|
||||||
@ -1126,8 +1169,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
bool resetPosition)
|
bool resetPosition)
|
||||||
{
|
{
|
||||||
// Sweep through recursively and update status
|
// Sweep through recursively and update status
|
||||||
var tasks = GetRecursiveChildren(user, true)
|
var tasks = GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
||||||
.Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
|
||||||
.Select(c => c.MarkPlayed(user, datePlayed, resetPosition));
|
.Select(c => c.MarkPlayed(user, datePlayed, resetPosition));
|
||||||
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||||
@ -1141,8 +1183,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
public override async Task MarkUnplayed(User user)
|
public override async Task MarkUnplayed(User user)
|
||||||
{
|
{
|
||||||
// Sweep through recursively and update status
|
// Sweep through recursively and update status
|
||||||
var tasks = GetRecursiveChildren(user, true)
|
var tasks = GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
||||||
.Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
|
||||||
.Select(c => c.MarkUnplayed(user));
|
.Select(c => c.MarkUnplayed(user));
|
||||||
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||||
@ -1171,15 +1212,15 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RecursiveChildren.FirstOrDefault(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) ||
|
return GetRecursiveChildren(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) ||
|
||||||
(!i.IsFolder && !i.IsInMixedFolder && string.Equals(i.ContainingFolderPath, path, StringComparison.OrdinalIgnoreCase)) ||
|
(!i.IsFolder && !i.IsInMixedFolder && string.Equals(i.ContainingFolderPath, path, StringComparison.OrdinalIgnoreCase)) ||
|
||||||
i.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase));
|
i.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase))
|
||||||
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsPlayed(User user)
|
public override bool IsPlayed(User user)
|
||||||
{
|
{
|
||||||
return GetRecursiveChildren(user)
|
return GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
||||||
.Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
|
||||||
.All(i => i.IsPlayed(user));
|
.All(i => i.IsPlayed(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1206,8 +1247,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
children = folder.GetRecursiveChildren(user)
|
children = folder.GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual);
|
||||||
.Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through each recursive child
|
// Loop through each recursive child
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Users;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MediaBrowser.Model.Users;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
@ -38,6 +38,13 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
public List<Guid> LocalTrailerIds { get; set; }
|
public List<Guid> LocalTrailerIds { get; set; }
|
||||||
public List<Guid> RemoteTrailerIds { get; set; }
|
public List<Guid> RemoteTrailerIds { get; set; }
|
||||||
|
|
||||||
|
public override bool CanDownload()
|
||||||
|
{
|
||||||
|
var locationType = LocationType;
|
||||||
|
return locationType != LocationType.Remote &&
|
||||||
|
locationType != LocationType.Virtual;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the tags.
|
/// Gets or sets the tags.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -88,7 +95,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string> MultiPartGameFiles { get; set; }
|
public List<string> MultiPartGameFiles { get; set; }
|
||||||
|
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
var id = this.GetProviderId(MetadataProviders.Gamesdb);
|
var id = this.GetProviderId(MetadataProviders.Gamesdb);
|
||||||
|
|
||||||
@ -96,7 +103,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
{
|
{
|
||||||
return "Game-Gamesdb-" + id;
|
return "Game-Gamesdb-" + id;
|
||||||
}
|
}
|
||||||
return base.GetUserDataKey();
|
return base.CreateUserDataKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<string> GetDeletePaths()
|
public override IEnumerable<string> GetDeletePaths()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
@ -10,7 +11,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
return "GameGenre-" + Name;
|
return "GameGenre-" + Name;
|
||||||
}
|
}
|
||||||
@ -20,6 +21,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// If the item is a folder, it returns the folder itself
|
/// If the item is a folder, it returns the folder itself
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The containing folder path.</value>
|
/// <value>The containing folder path.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
public override string ContainingFolderPath
|
public override string ContainingFolderPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -32,6 +34,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// Gets a value indicating whether this instance is owned item.
|
/// Gets a value indicating whether this instance is owned item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
public override bool IsOwnedItem
|
public override bool IsOwnedItem
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -40,9 +43,19 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
|
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
|
||||||
{
|
{
|
||||||
return inputItems.Where(i => (i is Game) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase));
|
return inputItems.Where(GetItemFilter());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<BaseItem, bool> GetItemFilter()
|
||||||
|
{
|
||||||
|
return i => (i is Game) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,13 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(GameSystemName))
|
if (!string.IsNullOrEmpty(GameSystemName))
|
||||||
{
|
{
|
||||||
return "GameSystem-" + GameSystemName;
|
return "GameSystem-" + GameSystemName;
|
||||||
}
|
}
|
||||||
return base.GetUserDataKey();
|
return base.CreateUserDataKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MediaBrowser.Controller.Entities.Audio;
|
using System.Runtime.Serialization;
|
||||||
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -14,7 +15,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
public override string GetUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
return "Genre-" + Name;
|
return "Genre-" + Name;
|
||||||
}
|
}
|
||||||
@ -24,6 +25,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// If the item is a folder, it returns the folder itself
|
/// If the item is a folder, it returns the folder itself
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The containing folder path.</value>
|
/// <value>The containing folder path.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
public override string ContainingFolderPath
|
public override string ContainingFolderPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -32,10 +34,16 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanDelete()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this instance is owned item.
|
/// Gets a value indicating whether this instance is owned item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
||||||
|
[IgnoreDataMember]
|
||||||
public override bool IsOwnedItem
|
public override bool IsOwnedItem
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -46,7 +54,12 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
|
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
|
||||||
{
|
{
|
||||||
return inputItems.Where(i => !(i is Game) && !(i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase));
|
return inputItems.Where(GetItemFilter());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<BaseItem, bool> GetItemFilter()
|
||||||
|
{
|
||||||
|
return i => !(i is Game) && !(i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,5 +54,10 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// Gets the item identities.
|
/// Gets the item identities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
List<IItemIdentity> Identities { get; set; }
|
List<IItemIdentity> Identities { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Afters the metadata refresh.
|
||||||
|
/// </summary>
|
||||||
|
void AfterMetadataRefresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user