mirror of https://github.com/jellyfin/jellyfin.git
commit
4cc3b2f0cc
|
@ -1,10 +1,10 @@
|
|||
using MediaBrowser.Api.Playback;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Session;
|
||||
using System;
|
||||
|
@ -39,6 +39,7 @@ namespace MediaBrowser.Api
|
|||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1);
|
||||
|
||||
|
@ -48,11 +49,12 @@ namespace MediaBrowser.Api
|
|||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="sessionManager">The session manager.</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;
|
||||
_sessionManager = sessionManager;
|
||||
_config = config;
|
||||
_fileSystem = fileSystem;
|
||||
|
||||
Instance = this;
|
||||
}
|
||||
|
@ -86,12 +88,12 @@ namespace MediaBrowser.Api
|
|||
/// </summary>
|
||||
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)
|
||||
.ToList())
|
||||
{
|
||||
File.Delete(file);
|
||||
_fileSystem.DeleteFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -462,7 +464,7 @@ namespace MediaBrowser.Api
|
|||
/// <param name="outputFilePath">The output file path.</param>
|
||||
private void DeleteProgressivePartialStreamFiles(string outputFilePath)
|
||||
{
|
||||
File.Delete(outputFilePath);
|
||||
_fileSystem.DeleteFile(outputFilePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -479,13 +481,13 @@ namespace MediaBrowser.Api
|
|||
.ToList();
|
||||
|
||||
Exception e = null;
|
||||
|
||||
|
||||
foreach (var file in filesToDelete)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Info("Deleting HLS file {0}", file);
|
||||
File.Delete(file);
|
||||
_fileSystem.DeleteFile(file);
|
||||
}
|
||||
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.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using ServiceStack.Text.Controller;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -21,7 +24,7 @@ namespace MediaBrowser.Api
|
|||
/// </summary>
|
||||
/// <value>The logger.</value>
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HTTP result factory.
|
||||
/// </summary>
|
||||
|
@ -35,6 +38,7 @@ namespace MediaBrowser.Api
|
|||
public IRequest Request { get; set; }
|
||||
|
||||
public ISessionContext SessionContext { get; set; }
|
||||
public IAuthorizationContext AuthorizationContext { get; set; }
|
||||
|
||||
public string GetHeader(string name)
|
||||
{
|
||||
|
@ -109,6 +113,37 @@ namespace MediaBrowser.Api
|
|||
private readonly char[] _dashReplaceChars = { '?', '/', '&' };
|
||||
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)
|
||||
{
|
||||
return libraryManager.GetArtist(DeSlugArtistName(name, libraryManager));
|
||||
|
@ -139,11 +174,11 @@ namespace MediaBrowser.Api
|
|||
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))
|
||||
{
|
||||
var folder = (Folder) libraryManager.GetItemById(new Guid(parentId));
|
||||
var folder = (Folder)libraryManager.GetItemById(new Guid(parentId));
|
||||
|
||||
if (userId.HasValue)
|
||||
{
|
||||
|
@ -154,10 +189,13 @@ namespace MediaBrowser.Api
|
|||
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)
|
||||
{
|
||||
|
@ -168,10 +206,16 @@ namespace MediaBrowser.Api
|
|||
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>
|
||||
|
@ -187,8 +231,9 @@ namespace MediaBrowser.Api
|
|||
return name;
|
||||
}
|
||||
|
||||
return libraryManager.RootFolder.RecursiveChildren
|
||||
.OfType<Audio>()
|
||||
return libraryManager.RootFolder
|
||||
.GetRecursiveChildren(i => i is IHasArtist)
|
||||
.Cast<IHasArtist>()
|
||||
.SelectMany(i => i.AllArtists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.FirstOrDefault(i =>
|
||||
|
@ -229,8 +274,8 @@ namespace MediaBrowser.Api
|
|||
return name;
|
||||
}
|
||||
|
||||
return libraryManager.RootFolder.GetRecursiveChildren()
|
||||
.OfType<Game>()
|
||||
return libraryManager.RootFolder
|
||||
.GetRecursiveChildren(i => i is Game)
|
||||
.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.FirstOrDefault(i =>
|
||||
|
@ -252,7 +297,8 @@ namespace MediaBrowser.Api
|
|||
return name;
|
||||
}
|
||||
|
||||
return libraryManager.RootFolder.GetRecursiveChildren()
|
||||
return libraryManager.RootFolder
|
||||
.GetRecursiveChildren()
|
||||
.SelectMany(i => i.Studios)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.FirstOrDefault(i =>
|
||||
|
@ -274,7 +320,8 @@ namespace MediaBrowser.Api
|
|||
return name;
|
||||
}
|
||||
|
||||
return libraryManager.RootFolder.GetRecursiveChildren()
|
||||
return libraryManager.RootFolder
|
||||
.GetRecursiveChildren()
|
||||
.SelectMany(i => i.People)
|
||||
.Select(i => i.Name)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
|
@ -287,6 +334,20 @@ namespace MediaBrowser.Api
|
|||
}) ?? 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>
|
||||
/// Gets the name of the item by.
|
||||
/// </summary>
|
||||
|
@ -294,7 +355,6 @@ namespace MediaBrowser.Api
|
|||
/// <param name="type">The type.</param>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <returns>Task{BaseItem}.</returns>
|
||||
/// <exception cref="System.ArgumentException"></exception>
|
||||
protected BaseItem GetItemByName(string name, string type, ILibraryManager libraryManager)
|
||||
{
|
||||
BaseItem item;
|
||||
|
|
|
@ -8,7 +8,12 @@ namespace MediaBrowser.Api
|
|||
public class GetBrandingOptions : IReturn<BrandingOptions>
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
[Route("/Branding/Css", "GET", Summary = "Gets custom css")]
|
||||
public class GetBrandingCss
|
||||
{
|
||||
}
|
||||
|
||||
public class BrandingService : BaseApiService
|
||||
{
|
||||
private readonly IConfigurationManager _config;
|
||||
|
@ -24,5 +29,12 @@ namespace MediaBrowser.Api
|
|||
|
||||
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)
|
||||
{
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var key = pathInfo.GetArgumentValue<string>(2);
|
||||
var key = GetPathValue(2);
|
||||
|
||||
var configurationType = _configurationManager.GetConfigurationType(key);
|
||||
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")]
|
||||
public string SendingUserId { get; set; }
|
||||
|
||||
[ApiMember(Name = "ExcludeLibraries", Description = "ExcludeLibraries", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||
public string ExcludedLibraries { get; set; }
|
||||
[ApiMember(Name = "EnabledLibraries", Description = "EnabledLibraries", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||
public string EnabledLibraries { get; set; }
|
||||
|
||||
[ApiMember(Name = "ExcludedChannels", Description = "ExcludedChannels", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||
public string ExcludedChannels { get; set; }
|
||||
[ApiMember(Name = "EnabledChannels", Description = "EnabledChannels", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||
public string EnabledChannels { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableLiveTv", Description = "EnableLiveTv", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
|
||||
public bool EnableLiveTv { get; set; }
|
||||
|
@ -91,12 +91,12 @@ namespace MediaBrowser.Api
|
|||
|
||||
public object Post(CreateConnectInvite request)
|
||||
{
|
||||
var excludeLibraries = (request.ExcludedLibraries ?? string.Empty)
|
||||
var enabledLibraries = (request.EnabledLibraries ?? string.Empty)
|
||||
.Split(',')
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||
.ToArray();
|
||||
|
||||
var excludedChannels = (request.ExcludedChannels ?? string.Empty)
|
||||
var enabledChannels = (request.EnabledChannels ?? string.Empty)
|
||||
.Split(',')
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||
.ToArray();
|
||||
|
@ -105,8 +105,8 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
ConnectUserName = request.ConnectUsername,
|
||||
SendingUserId = request.SendingUserId,
|
||||
ExcludedLibraries = excludeLibraries,
|
||||
ExcludedChannels = excludedChannels,
|
||||
EnabledLibraries = enabledLibraries,
|
||||
EnabledChannels = enabledChannels,
|
||||
EnableLiveTv = request.EnableLiveTv
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using MediaBrowser.Controller.Dlna;
|
||||
using ServiceStack;
|
||||
using ServiceStack.Text.Controller;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -19,19 +18,31 @@ namespace MediaBrowser.Api.Dlna
|
|||
public string UuId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Dlna/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.xml", "GET", Summary = "Gets dlna content directory xml")]
|
||||
[Route("/Dlna/{UuId}/contentdirectory/contentdirectory", "GET", Summary = "Gets dlna content directory xml")]
|
||||
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/connectionmanager/connectionmanager", "GET", Summary = "Gets dlna connection manager xml")]
|
||||
[Route("/Dlna/{UuId}/connectionmanager/connectionmanager.xml", "GET", Summary = "Gets dlna connection manager xml")]
|
||||
[Route("/Dlna/{UuId}/connectionmanager/connectionmanager", "GET", Summary = "Gets dlna connection manager xml")]
|
||||
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
|
||||
{
|
||||
[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; }
|
||||
}
|
||||
|
||||
[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
|
||||
{
|
||||
[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; }
|
||||
}
|
||||
|
||||
[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
|
||||
{
|
||||
[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; }
|
||||
}
|
||||
|
||||
[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
|
||||
{
|
||||
[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; }
|
||||
}
|
||||
|
||||
[Route("/Dlna/{UuId}/icons/{Filename}", "GET", Summary = "Gets a server icon")]
|
||||
[Route("/Dlna/icons/{Filename}", "GET", Summary = "Gets a server icon")]
|
||||
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")]
|
||||
public string Filename { get; set; }
|
||||
}
|
||||
|
@ -75,17 +106,21 @@ namespace MediaBrowser.Api.Dlna
|
|||
private readonly IDlnaManager _dlnaManager;
|
||||
private readonly IContentDirectory _contentDirectory;
|
||||
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;
|
||||
_contentDirectory = contentDirectory;
|
||||
_connectionManager = connectionManager;
|
||||
_mediaReceiverRegistrar = mediaReceiverRegistrar;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
@ -97,6 +132,13 @@ namespace MediaBrowser.Api.Dlna
|
|||
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)
|
||||
{
|
||||
var xml = _connectionManager.GetServiceXml(GetRequestHeaders());
|
||||
|
@ -104,6 +146,13 @@ namespace MediaBrowser.Api.Dlna
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var id = pathInfo.GetArgumentValue<string>(2);
|
||||
var id = GetPathValue(2);
|
||||
|
||||
using (var reader = new StreamReader(requestStream))
|
||||
{
|
||||
|
@ -172,6 +220,11 @@ namespace MediaBrowser.Api.Dlna
|
|||
return ProcessEventRequest(_connectionManager);
|
||||
}
|
||||
|
||||
public object Any(ProcessMediaReceiverRegistrarEventRequest request)
|
||||
{
|
||||
return ProcessEventRequest(_mediaReceiverRegistrar);
|
||||
}
|
||||
|
||||
private object ProcessEventRequest(IEventManager eventManager)
|
||||
{
|
||||
var subscriptionId = GetHeader("SID");
|
||||
|
|
|
@ -102,8 +102,8 @@ namespace MediaBrowser.Api
|
|||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetGameSystemSummaries request)
|
||||
{
|
||||
var gameSystems = GetAllLibraryItems(request.UserId, _userManager, _libraryManager)
|
||||
.OfType<GameSystem>()
|
||||
var gameSystems = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i is GameSystem)
|
||||
.Cast<GameSystem>()
|
||||
.ToList();
|
||||
|
||||
var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId.Value);
|
||||
|
@ -119,9 +119,8 @@ namespace MediaBrowser.Api
|
|||
|
||||
public object Get(GetPlayerIndex request)
|
||||
{
|
||||
var games = GetAllLibraryItems(request.UserId, _userManager, _libraryManager)
|
||||
.OfType<Game>()
|
||||
.ToList();
|
||||
var games = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i is Game)
|
||||
.Cast<Game>();
|
||||
|
||||
var lookup = games
|
||||
.ToLookup(i => i.PlayersSupported ?? -1)
|
||||
|
@ -150,9 +149,11 @@ namespace MediaBrowser.Api
|
|||
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);
|
||||
|
||||
|
@ -172,7 +173,9 @@ namespace MediaBrowser.Api
|
|||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetSimilarGames request)
|
||||
{
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
|
||||
_itemRepo,
|
||||
_libraryManager,
|
||||
_userDataRepository,
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace MediaBrowser.Api
|
||||
{
|
||||
public interface IHasDtoOptions : IHasItemFields
|
||||
|
@ -13,27 +9,4 @@ namespace MediaBrowser.Api
|
|||
|
||||
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.Entities;
|
||||
using ServiceStack;
|
||||
using ServiceStack.Text.Controller;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -396,8 +395,7 @@ namespace MediaBrowser.Api.Images
|
|||
|
||||
public object Get(GetItemByNameImage request)
|
||||
{
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var type = pathInfo.GetArgumentValue<string>(0);
|
||||
var type = GetPathValue(0);
|
||||
|
||||
var item = GetItemByName(request.Name, type, _libraryManager);
|
||||
|
||||
|
@ -406,8 +404,7 @@ namespace MediaBrowser.Api.Images
|
|||
|
||||
public object Head(GetItemByNameImage request)
|
||||
{
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var type = pathInfo.GetArgumentValue<string>(0);
|
||||
var type = GetPathValue(0);
|
||||
|
||||
var item = GetItemByName(request.Name, type, _libraryManager);
|
||||
|
||||
|
@ -420,10 +417,9 @@ namespace MediaBrowser.Api.Images
|
|||
/// <param name="request">The request.</param>
|
||||
public void Post(PostUserImage request)
|
||||
{
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
||||
var id = new Guid(GetPathValue(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);
|
||||
|
||||
|
@ -438,10 +434,9 @@ namespace MediaBrowser.Api.Images
|
|||
/// <param name="request">The request.</param>
|
||||
public void Post(PostItemImage request)
|
||||
{
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
||||
var id = new Guid(GetPathValue(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);
|
||||
|
||||
|
|
|
@ -205,7 +205,8 @@ namespace MediaBrowser.Api
|
|||
Logger = Logger,
|
||||
Request = Request,
|
||||
ResultFactory = ResultFactory,
|
||||
SessionContext = SessionContext
|
||||
SessionContext = SessionContext,
|
||||
AuthorizationContext = AuthorizationContext
|
||||
};
|
||||
|
||||
service.Post(new RefreshItem
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace MediaBrowser.Api
|
|||
var cancellationToken = CancellationToken.None;
|
||||
|
||||
var albums = _libraryManager.RootFolder
|
||||
.RecursiveChildren
|
||||
.GetRecursiveChildren()
|
||||
.OfType<MusicAlbum>()
|
||||
.Where(i => i.HasArtist(item.Name))
|
||||
.ToList();
|
||||
|
|
|
@ -215,7 +215,7 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
var folder = (Folder)item;
|
||||
|
||||
foreach (var child in folder.RecursiveChildren.ToList())
|
||||
foreach (var child in folder.GetRecursiveChildren())
|
||||
{
|
||||
child.IsLocked = newLockData;
|
||||
await child.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Library
|
|||
|
||||
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.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -226,6 +224,18 @@ namespace MediaBrowser.Api.Library
|
|||
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>
|
||||
/// Class LibraryService
|
||||
/// </summary>
|
||||
|
@ -272,8 +282,8 @@ namespace MediaBrowser.Api.Library
|
|||
items = items.Where(i => i.IsHidden == val).ToList();
|
||||
}
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = new ItemsResult
|
||||
{
|
||||
TotalRecordCount = items.Count,
|
||||
|
@ -289,6 +299,28 @@ namespace MediaBrowser.Api.Library
|
|||
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)
|
||||
{
|
||||
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 dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
BaseItem parent = item.Parent;
|
||||
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
if (user != null)
|
||||
|
@ -392,52 +424,43 @@ namespace MediaBrowser.Api.Library
|
|||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetItemCounts request)
|
||||
{
|
||||
var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager)
|
||||
.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 filteredItems = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, null, i => i.LocationType != LocationType.Virtual && FilterItem(i, request, request.UserId));
|
||||
|
||||
var counts = new ItemCounts
|
||||
{
|
||||
AlbumCount = albums.Count,
|
||||
EpisodeCount = episodes.Count,
|
||||
GameCount = games.Count,
|
||||
GameSystemCount = filteredItems.OfType<GameSystem>().Count(),
|
||||
MovieCount = movies.Count,
|
||||
SeriesCount = series.Count,
|
||||
SongCount = songs.Count,
|
||||
MusicVideoCount = musicVideos.Count,
|
||||
BoxSetCount = boxsets.Count,
|
||||
BookCount = books.Count,
|
||||
AlbumCount = filteredItems.Count(i => i is MusicAlbum),
|
||||
EpisodeCount = filteredItems.Count(i => i is Episode),
|
||||
GameCount = filteredItems.Count(i => i is Game),
|
||||
GameSystemCount = filteredItems.Count(i => i is GameSystem),
|
||||
MovieCount = filteredItems.Count(i => i is Movie),
|
||||
SeriesCount = filteredItems.Count(i => i is Series),
|
||||
SongCount = filteredItems.Count(i => i is Audio),
|
||||
MusicVideoCount = filteredItems.Count(i => i is MusicVideo),
|
||||
BoxSetCount = filteredItems.Count(i => i is BoxSet),
|
||||
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);
|
||||
}
|
||||
|
||||
private IEnumerable<T> FilterItems<T>(IEnumerable<T> items, GetItemCounts request, Guid userId)
|
||||
where T : BaseItem
|
||||
private bool FilterItem(BaseItem item, GetItemCounts request, Guid? userId)
|
||||
{
|
||||
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>
|
||||
|
@ -467,23 +490,9 @@ namespace MediaBrowser.Api.Library
|
|||
var auth = _authContext.GetAuthorizationInfo(Request);
|
||||
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
|
||||
}
|
||||
else if (item is ILiveTvRecording)
|
||||
{
|
||||
if (!user.Policy.EnableLiveTvManagement)
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!user.Policy.EnableContentDeletion)
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
|
||||
var task = _libraryManager.DeleteItem(item);
|
||||
|
@ -544,7 +553,7 @@ namespace MediaBrowser.Api.Library
|
|||
ThemeSongsResult = themeSongs,
|
||||
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)
|
||||
.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)
|
||||
.OrderBy(i => i.SortName)
|
||||
|
@ -711,13 +720,24 @@ namespace MediaBrowser.Api.Library
|
|||
|
||||
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(',');
|
||||
items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
if (includeTypes.Length > 0)
|
||||
{
|
||||
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
|
||||
.ToLookup(i => i.ProductionYear ?? -1)
|
||||
|
@ -732,23 +752,22 @@ namespace MediaBrowser.Api.Library
|
|||
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 item = string.IsNullOrEmpty(id)
|
||||
? (userId.HasValue
|
||||
? user.RootFolder
|
||||
: (Folder)_libraryManager.RootFolder)
|
||||
: _libraryManager.RootFolder)
|
||||
: _libraryManager.GetItemById(id);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = GetSoundtrackSongIds(item, inheritFromParent)
|
||||
.Select(_libraryManager.GetItemById)
|
||||
.OfType<MusicAlbum>()
|
||||
.SelectMany(i => i.RecursiveChildren)
|
||||
.OfType<Audio>()
|
||||
.SelectMany(i => i.GetRecursiveChildren(a => a is Audio))
|
||||
.OrderBy(i => i.SortName)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ using MediaBrowser.Controller;
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -18,7 +17,6 @@ namespace MediaBrowser.Api.Library
|
|||
/// Class GetDefaultVirtualFolders
|
||||
/// </summary>
|
||||
[Route("/Library/VirtualFolders", "GET")]
|
||||
[Route("/Users/{UserId}/VirtualFolders", "GET")]
|
||||
public class GetVirtualFolders : IReturn<List<VirtualFolderInfo>>
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -143,11 +141,6 @@ namespace MediaBrowser.Api.Library
|
|||
/// </summary>
|
||||
private readonly IServerApplicationPaths _appPaths;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
|
@ -156,27 +149,21 @@ namespace MediaBrowser.Api.Library
|
|||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LibraryStructureService"/> class.
|
||||
/// Initializes a new instance of the <see cref="LibraryStructureService" /> class.
|
||||
/// </summary>
|
||||
/// <param name="appPaths">The app paths.</param>
|
||||
/// <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)
|
||||
public LibraryStructureService(IServerApplicationPaths appPaths, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem)
|
||||
{
|
||||
if (appPaths == null)
|
||||
{
|
||||
throw new ArgumentNullException("appPaths");
|
||||
}
|
||||
|
||||
_userManager = userManager;
|
||||
_appPaths = appPaths;
|
||||
_libraryManager = libraryManager;
|
||||
_libraryMonitor = libraryMonitor;
|
||||
_fileSystem = fileSystem;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -186,20 +173,9 @@ namespace MediaBrowser.Api.Library
|
|||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetVirtualFolders request)
|
||||
{
|
||||
if (string.IsNullOrEmpty(request.UserId))
|
||||
{
|
||||
var result = _libraryManager.GetDefaultVirtualFolders().OrderBy(i => i.Name).ToList();
|
||||
var result = _libraryManager.GetVirtualFolders().OrderBy(i => i.Name).ToList();
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var result = _libraryManager.GetVirtualFolders(user).OrderBy(i => i.Name).ToList();
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -348,7 +324,7 @@ namespace MediaBrowser.Api.Library
|
|||
|
||||
try
|
||||
{
|
||||
Directory.Delete(path, true);
|
||||
_fileSystem.DeleteDirectory(path, true);
|
||||
|
||||
// Need to add a delay here or directory watchers may still pick up the changes
|
||||
var delayTask = Task.Delay(1000);
|
||||
|
|
|
@ -82,6 +82,10 @@
|
|||
<Compile Include="Playback\Hls\MpegDashService.cs" />
|
||||
<Compile Include="Playback\MediaInfoService.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="Subtitles\SubtitleService.cs" />
|
||||
<Compile Include="Movies\CollectionService.cs" />
|
||||
|
@ -110,7 +114,6 @@
|
|||
<Compile Include="NotificationsService.cs" />
|
||||
<Compile Include="PackageReviewService.cs" />
|
||||
<Compile Include="PackageService.cs" />
|
||||
<Compile Include="Playback\BifService.cs" />
|
||||
<Compile Include="Playback\Hls\BaseHlsService.cs" />
|
||||
<Compile Include="Playback\Hls\DynamicHlsService.cs" />
|
||||
<Compile Include="Playback\Hls\HlsSegmentService.cs" />
|
||||
|
@ -131,6 +134,8 @@
|
|||
<Compile Include="SearchService.cs" />
|
||||
<Compile Include="Session\SessionsService.cs" />
|
||||
<Compile Include="SimilarItemsHelper.cs" />
|
||||
<Compile Include="Sync\SyncJobWebSocketListener.cs" />
|
||||
<Compile Include="Sync\SyncJobsWebSocketListener.cs" />
|
||||
<Compile Include="Sync\SyncService.cs" />
|
||||
<Compile Include="System\ActivityLogService.cs" />
|
||||
<Compile Include="System\ActivityLogWebSocketListener.cs" />
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace MediaBrowser.Api.Movies
|
|||
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dto = _dtoService.GetBaseItemDto(item, dtoOptions);
|
||||
|
||||
|
|
|
@ -121,8 +121,7 @@ namespace MediaBrowser.Api.Movies
|
|||
{
|
||||
var user = _userManager.GetUserById(request.UserId.Value);
|
||||
|
||||
var movies = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId)
|
||||
.Where(i => i is Movie);
|
||||
IEnumerable<BaseItem> movies = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Movie);
|
||||
|
||||
movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies);
|
||||
|
||||
|
@ -157,7 +156,7 @@ namespace MediaBrowser.Api.Movies
|
|||
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
dtoOptions.Fields = request.GetItemFields().ToList();
|
||||
|
||||
|
@ -174,13 +173,11 @@ namespace MediaBrowser.Api.Movies
|
|||
(request.UserId.HasValue ? user.RootFolder :
|
||||
_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
|
||||
? _libraryManager.RootFolder.GetRecursiveChildren().Where(i => i.Id != item.Id)
|
||||
: user.RootFolder.GetRecursiveChildren(user).Where(i => i.Id != item.Id);
|
||||
|
||||
inputItems = inputItems.Where(includeInSearch);
|
||||
? _libraryManager.RootFolder.GetRecursiveChildren(filter)
|
||||
: user.RootFolder.GetRecursiveChildren(user, filter);
|
||||
|
||||
var list = inputItems.ToList();
|
||||
|
||||
|
@ -225,10 +222,12 @@ namespace MediaBrowser.Api.Movies
|
|||
{
|
||||
returnItems = returnItems.Take(request.Limit.Value);
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = new ItemsResult
|
||||
{
|
||||
Items = returnItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray(),
|
||||
Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
|
||||
|
||||
TotalRecordCount = items.Count
|
||||
};
|
||||
|
@ -351,7 +350,7 @@ namespace MediaBrowser.Api.Movies
|
|||
BaselineItemName = director,
|
||||
CategoryId = director.GetMD5().ToString("N"),
|
||||
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,
|
||||
CategoryId = name.GetMD5().ToString("N"),
|
||||
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,
|
||||
CategoryId = item.Id.ToString("N"),
|
||||
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>
|
||||
public object Get(GetSimilarTrailers request)
|
||||
{
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
|
||||
_itemRepo,
|
||||
_libraryManager,
|
||||
_userDataRepository,
|
||||
|
@ -119,9 +121,9 @@ namespace MediaBrowser.Api.Movies
|
|||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -50,7 +50,9 @@ namespace MediaBrowser.Api.Music
|
|||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetSimilarAlbums request)
|
||||
{
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
|
||||
_itemRepo,
|
||||
_libraryManager,
|
||||
_userDataRepository,
|
||||
|
@ -75,14 +77,14 @@ namespace MediaBrowser.Api.Music
|
|||
var album1 = (MusicAlbum)item1;
|
||||
var album2 = (MusicAlbum)item2;
|
||||
|
||||
var artists1 = album1.GetRecursiveChildren()
|
||||
.OfType<Audio>()
|
||||
var artists1 = album1.GetRecursiveChildren(i => i is IHasArtist)
|
||||
.Cast<IHasArtist>()
|
||||
.SelectMany(i => i.AllArtists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var artists2 = album2.GetRecursiveChildren()
|
||||
.OfType<Audio>()
|
||||
var artists2 = album2.GetRecursiveChildren(i => i is IHasArtist)
|
||||
.Cast<IHasArtist>()
|
||||
.SelectMany(i => i.AllArtists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||
|
|
|
@ -73,44 +73,44 @@ namespace MediaBrowser.Api.Music
|
|||
|
||||
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 items = _musicManager.GetInstantMixFromArtist(item.Name, user);
|
||||
var items = _musicManager.GetInstantMixFromItem(item, user);
|
||||
|
||||
return GetResult(items, user, 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 items = _musicManager.GetInstantMixFromGenres(new[] { item.Name }, user);
|
||||
var items = _musicManager.GetInstantMixFromItem(item, user);
|
||||
|
||||
return GetResult(items, user, 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 items = _musicManager.GetInstantMixFromSong(item, user);
|
||||
var items = _musicManager.GetInstantMixFromItem(item, user);
|
||||
|
||||
return GetResult(items, user, 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 items = _musicManager.GetInstantMixFromAlbum(album, user);
|
||||
var items = _musicManager.GetInstantMixFromItem(album, user);
|
||||
|
||||
return GetResult(items, user, request);
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ namespace MediaBrowser.Api.Music
|
|||
|
||||
var user = _userManager.GetUserById(request.UserId.Value);
|
||||
|
||||
var items = _musicManager.GetInstantMixFromPlaylist(playlist, user);
|
||||
var items = _musicManager.GetInstantMixFromItem(playlist, user);
|
||||
|
||||
return GetResult(items, user, request);
|
||||
}
|
||||
|
@ -146,8 +146,6 @@ namespace MediaBrowser.Api.Music
|
|||
|
||||
private object GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request)
|
||||
{
|
||||
var fields = request.GetItemFields().ToList();
|
||||
|
||||
var list = items.ToList();
|
||||
|
||||
var result = new ItemsResult
|
||||
|
@ -155,10 +153,9 @@ namespace MediaBrowser.Api.Music
|
|||
TotalRecordCount = list.Count
|
||||
};
|
||||
|
||||
var dtos = list.Take(request.Limit ?? list.Count)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, fields, user));
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
result.Items = dtos.ToArray();
|
||||
result.Items = _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user).ToArray();
|
||||
|
||||
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.IO;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
|
@ -66,14 +67,16 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
protected ILiveTvManager LiveTvManager { get; private set; }
|
||||
protected IDlnaManager DlnaManager { get; private set; }
|
||||
protected IDeviceManager DeviceManager { get; private set; }
|
||||
protected IChannelManager ChannelManager { get; private set; }
|
||||
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
||||
/// </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;
|
||||
ChannelManager = channelManager;
|
||||
DlnaManager = dlnaManager;
|
||||
|
@ -119,8 +122,8 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <returns>System.String.</returns>
|
||||
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 data = GetCommandLineArguments("dummy\\dummy", "dummyTranscodingId", state, false);
|
||||
|
@ -320,13 +323,13 @@ namespace MediaBrowser.Api.Playback
|
|||
switch (qualitySetting)
|
||||
{
|
||||
case EncodingQuality.HighSpeed:
|
||||
param += " -crf 23";
|
||||
param += " -subq 0 -crf 23";
|
||||
break;
|
||||
case EncodingQuality.HighQuality:
|
||||
param += " -crf 20";
|
||||
param += " -subq 3 -crf 20";
|
||||
break;
|
||||
case EncodingQuality.MaxQuality:
|
||||
param += " -crf 18";
|
||||
param += " -subq 6 -crf 18";
|
||||
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
|
||||
else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -426,10 +464,50 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
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)
|
||||
|
@ -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;
|
||||
|
||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
|
||||
|
@ -606,7 +689,7 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
|
||||
{
|
||||
var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.SubtitleStream.Language);
|
||||
var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath);
|
||||
|
||||
if (!string.IsNullOrEmpty(charenc))
|
||||
{
|
||||
|
@ -834,7 +917,7 @@ namespace MediaBrowser.Api.Playback
|
|||
{
|
||||
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;
|
||||
|
||||
|
@ -1183,6 +1266,22 @@ namespace MediaBrowser.Api.Playback
|
|||
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
|
||||
if (hasFixedResolution)
|
||||
{
|
||||
|
@ -1991,9 +2090,26 @@ namespace MediaBrowser.Api.Playback
|
|||
headers[key] = Request.Headers[key];
|
||||
}
|
||||
|
||||
state.DeviceProfile = string.IsNullOrWhiteSpace(state.Request.DeviceProfileId) ?
|
||||
DlnaManager.GetProfile(headers) :
|
||||
DlnaManager.GetProfile(state.Request.DeviceProfileId);
|
||||
if (!string.IsNullOrWhiteSpace(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;
|
||||
|
||||
|
|
|
@ -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.Net;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Net;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
||||
namespace MediaBrowser.Api.Playback.Hls
|
||||
{
|
||||
|
@ -23,8 +23,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
/// </summary>
|
||||
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)
|
||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, 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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
|
@ -62,38 +63,31 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
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, INetworkManager networkManager)
|
||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
|
||||
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)
|
||||
{
|
||||
NetworkManager = networkManager;
|
||||
}
|
||||
|
||||
public object Get(GetMasterHlsVideoStream request)
|
||||
{
|
||||
var result = GetAsync(request, "GET").Result;
|
||||
protected INetworkManager NetworkManager { get; private set; }
|
||||
|
||||
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 result;
|
||||
return GetAsync(request, "HEAD");
|
||||
}
|
||||
|
||||
public object Get(GetMainHlsVideoStream request)
|
||||
public Task<object> Get(GetMainHlsVideoStream request)
|
||||
{
|
||||
var result = GetPlaylistAsync(request, "main").Result;
|
||||
|
||||
return result;
|
||||
return GetPlaylistAsync(request, "main");
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -210,10 +204,10 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(file.FullName);
|
||||
FileSystem.DeleteFile(file.FullName);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Api.Playback.Hls
|
||||
{
|
||||
|
@ -66,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
@ -85,7 +81,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
|
@ -50,14 +51,13 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
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, INetworkManager networkManager)
|
||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
|
||||
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)
|
||||
{
|
||||
NetworkManager = networkManager;
|
||||
}
|
||||
|
||||
protected INetworkManager NetworkManager { get; private set; }
|
||||
|
||||
public object Get(GetMasterManifest request)
|
||||
{
|
||||
var result = GetAsync(request, "GET").Result;
|
||||
|
@ -489,7 +489,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
try
|
||||
{
|
||||
File.Delete(file.FullName);
|
||||
FileSystem.DeleteFile(file.FullName);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
|
@ -625,7 +625,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
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/
|
||||
|
||||
var threads = GetNumberOfThreads(state, false);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.IO;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
|
@ -57,8 +57,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
/// </summary>
|
||||
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)
|
||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, 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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -71,7 +70,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
@ -31,7 +32,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
/// </summary>
|
||||
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.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
@ -15,6 +15,7 @@ using ServiceStack.Web;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -28,8 +29,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
protected readonly IImageProcessor ImageProcessor;
|
||||
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)
|
||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
|
||||
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)
|
||||
{
|
||||
ImageProcessor = imageProcessor;
|
||||
HttpClient = httpClient;
|
||||
|
|
|
@ -2,6 +2,7 @@ using MediaBrowser.Common.IO;
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
@ -62,7 +63,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
/// </summary>
|
||||
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))
|
||||
{
|
||||
// Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
|
||||
format = " -f mp4 -movflags frag_keyframe+empty_moov";
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,10 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <param name="responseStream">The response stream.</param>
|
||||
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();
|
||||
}
|
||||
|
||||
var dtos = items
|
||||
.Select(i => _dtoService.GetBaseItemDto(i.Item2, request.GetItemFields().ToList(), user))
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = _dtoService.GetBaseItemDtos(items.Select(i => i.Item2), dtoOptions, user)
|
||||
.ToArray();
|
||||
|
||||
var index = 0;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Threading;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Security;
|
||||
using MediaBrowser.Common.Updates;
|
||||
|
@ -8,12 +7,12 @@ using MediaBrowser.Model.Entities;
|
|||
using MediaBrowser.Model.Plugins;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using ServiceStack.Text.Controller;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
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
|
||||
// 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(pathInfo.GetArgumentValue<string>(1));
|
||||
var id = new Guid(GetPathValue(1));
|
||||
|
||||
var plugin = _appHost.Plugins.First(p => p.Id == id);
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
namespace MediaBrowser.Api.Reports
|
||||
{
|
||||
public enum ReportFieldType
|
||||
{
|
||||
String,
|
||||
Boolean
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")]
|
||||
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>
|
||||
|
@ -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
|
||||
.Select(ScheduledTaskHelpers.GetTaskInfo)
|
||||
.ToList();
|
||||
|
@ -202,8 +224,7 @@ namespace MediaBrowser.Api.ScheduledTasks
|
|||
{
|
||||
// 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
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var id = pathInfo.GetArgumentValue<string>(1);
|
||||
var id = GetPathValue(1);
|
||||
|
||||
var task = TaskManager.ScheduledTasks.FirstOrDefault(i => string.Equals(i.Id, id));
|
||||
|
||||
|
|
|
@ -194,29 +194,24 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
var songs = album.GetRecursiveChildren().OfType<Audio>().ToList();
|
||||
result.SongCount = album.Tracks.Count();
|
||||
|
||||
result.SongCount = songs.Count;
|
||||
|
||||
result.Artists = songs.SelectMany(i => i.AllArtists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
result.AlbumArtist = songs.SelectMany(i => i.AlbumArtists).FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
result.Artists = album.Artists.ToArray();
|
||||
result.AlbumArtist = album.AlbumArtists.FirstOrDefault();
|
||||
}
|
||||
|
||||
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.Session;
|
||||
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")]
|
||||
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")]
|
||||
public bool SupportsUniqueIdentifier { get; set; }
|
||||
[ApiMember(Name = "SupportsPersistentIdentifier", Description = "Determines whether the device supports a unique identifier.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
|
||||
public bool SupportsPersistentIdentifier { get; set; }
|
||||
|
||||
public PostCapabilities()
|
||||
{
|
||||
SupportsPersistentIdentifier = true;
|
||||
}
|
||||
}
|
||||
|
||||
[Route("/Sessions/Capabilities/Full", "POST", Summary = "Updates capabilities for a device")]
|
||||
|
@ -556,7 +561,7 @@ namespace MediaBrowser.Api.Session
|
|||
|
||||
SupportsSync = request.SupportsSync,
|
||||
|
||||
SupportsUniqueIdentifier = request.SupportsUniqueIdentifier
|
||||
SupportsPersistentIdentifier = request.SupportsPersistentIdentifier
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ namespace MediaBrowser.Api
|
|||
/// <summary>
|
||||
/// Gets the similar items.
|
||||
/// </summary>
|
||||
/// <param name="dtoOptions">The dto options.</param>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="itemRepository">The item repository.</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="getSimilarityScore">The get similarity score.</param>
|
||||
/// <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;
|
||||
|
||||
|
@ -75,13 +76,13 @@ namespace MediaBrowser.Api
|
|||
(request.UserId.HasValue ? user.RootFolder :
|
||||
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
|
||||
? libraryManager.RootFolder.GetRecursiveChildren().Where(i => i.Id != item.Id)
|
||||
: user.RootFolder.GetRecursiveChildren(user).Where(i => i.Id != item.Id);
|
||||
? libraryManager.RootFolder.GetRecursiveChildren(filter)
|
||||
: user.RootFolder.GetRecursiveChildren(user, filter);
|
||||
|
||||
var items = GetSimilaritems(item, inputItems.Where(includeInSearch), getSimilarityScore)
|
||||
var items = GetSimilaritems(item, inputItems, getSimilarityScore)
|
||||
.ToList();
|
||||
|
||||
IEnumerable<BaseItem> returnItems = items;
|
||||
|
@ -93,7 +94,7 @@ namespace MediaBrowser.Api
|
|||
|
||||
var result = new ItemsResult
|
||||
{
|
||||
Items = returnItems.Select(i => dtoService.GetBaseItemDto(i, fields, user)).ToArray(),
|
||||
Items = dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
|
||||
|
||||
TotalRecordCount = items.Count
|
||||
};
|
||||
|
@ -164,7 +165,7 @@ namespace MediaBrowser.Api
|
|||
|
||||
// Find common keywords
|
||||
points += GetKeywords(item1).Where(i => GetKeywords(item2).Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
|
||||
|
||||
|
||||
// Find common studios
|
||||
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.EnableLocalizedGuids = true;
|
||||
_config.Configuration.MergeMetadataAndImagesByName = true;
|
||||
_config.Configuration.EnableStandaloneMetadata = true;
|
||||
_config.Configuration.EnableLibraryMetadataSubFolder = true;
|
||||
_config.SaveConfiguration();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.Net;
|
||||
using MediaBrowser.Controller.Sync;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Sync;
|
||||
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.")]
|
||||
public class GetSyncJobs : SyncJobQuery, IReturn<QueryResult<SyncJob>>
|
||||
{
|
||||
|
@ -85,6 +112,16 @@ namespace MediaBrowser.Api.Sync
|
|||
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.")]
|
||||
public class ReportOfflineActions : List<UserAction>, IReturnVoid
|
||||
{
|
||||
|
@ -169,11 +206,14 @@ namespace MediaBrowser.Api.Sync
|
|||
{
|
||||
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.");
|
||||
}
|
||||
|
||||
var task = _syncManager.ReportSyncJobItemTransferBeginning(request.Id);
|
||||
Task.WaitAll(task);
|
||||
|
||||
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)
|
||||
.Where(i => i != null)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions))
|
||||
.Where(i => i != null);
|
||||
|
||||
var dtos = _dtoService.GetBaseItemDtos(items, dtoOptions)
|
||||
.ToList();
|
||||
|
||||
result.Options = SyncHelper.GetSyncOptions(dtos);
|
||||
|
@ -243,5 +284,52 @@ namespace MediaBrowser.Api.Sync
|
|||
|
||||
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")]
|
||||
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")]
|
||||
|
@ -238,7 +252,9 @@ namespace MediaBrowser.Api
|
|||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetSimilarShows request)
|
||||
{
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
|
||||
_itemRepo,
|
||||
_libraryManager,
|
||||
_userDataManager,
|
||||
|
@ -254,10 +270,10 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId)
|
||||
.OfType<Episode>();
|
||||
var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is 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>()
|
||||
.ToList();
|
||||
|
||||
|
@ -270,9 +286,9 @@ namespace MediaBrowser.Api
|
|||
|
||||
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
|
||||
{
|
||||
|
@ -301,9 +317,9 @@ namespace MediaBrowser.Api
|
|||
|
||||
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
|
||||
{
|
||||
|
@ -365,9 +381,9 @@ namespace MediaBrowser.Api
|
|||
.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();
|
||||
|
||||
return new ItemsResult
|
||||
|
@ -411,7 +427,18 @@ namespace MediaBrowser.Api
|
|||
|
||||
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;
|
||||
|
||||
|
@ -424,14 +451,14 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
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
|
||||
|
@ -448,24 +475,27 @@ namespace MediaBrowser.Api
|
|||
episodes = episodes.Where(i => i.IsVirtualUnaired == val);
|
||||
}
|
||||
|
||||
IEnumerable<BaseItem> returnItems = episodes;
|
||||
|
||||
// This must be the last filter
|
||||
if (!string.IsNullOrEmpty(request.AdjacentTo))
|
||||
{
|
||||
episodes = UserViewBuilder.FilterForAdjacency(episodes, request.AdjacentTo)
|
||||
.Cast<Episode>();
|
||||
returnItems = UserViewBuilder.FilterForAdjacency(returnItems, request.AdjacentTo);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
return new ItemsResult
|
||||
{
|
||||
TotalRecordCount = returnItems.Length,
|
||||
Items = returnItems
|
||||
TotalRecordCount = dtos.Length,
|
||||
Items = dtos
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
var item = GetArtist(request.Name, LibraryManager);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
if (request.UserId.HasValue)
|
||||
{
|
||||
|
@ -130,8 +130,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
if (request is GetAlbumArtists)
|
||||
{
|
||||
return items
|
||||
.Where(i => !i.IsFolder)
|
||||
.OfType<IHasAlbumArtist>()
|
||||
.Where(i => !(i is MusicAlbum))
|
||||
.SelectMany(i => i.AlbumArtists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(name =>
|
||||
|
@ -150,8 +150,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
}
|
||||
|
||||
return items
|
||||
.Where(i => !i.IsFolder)
|
||||
.OfType<IHasArtist>()
|
||||
.Where(i => !(i is MusicAlbum))
|
||||
.SelectMany(i => i.AllArtists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(name =>
|
||||
|
|
|
@ -56,46 +56,52 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
protected ItemsResult GetResult(GetItemsByName request)
|
||||
{
|
||||
User user = null;
|
||||
BaseItem item;
|
||||
BaseItem parentItem;
|
||||
List<BaseItem> libraryItems;
|
||||
|
||||
if (request.UserId.HasValue)
|
||||
{
|
||||
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();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
item = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : LibraryManager.GetItemById(request.ParentId);
|
||||
|
||||
libraryItems = LibraryManager.RootFolder.RecursiveChildren.ToList();
|
||||
parentItem = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : LibraryManager.GetItemById(request.ParentId);
|
||||
libraryItems = LibraryManager.RootFolder.GetRecursiveChildren().ToList();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
items = request.Recursive ? folder.GetRecursiveChildren(user) : folder.GetChildren(user, true);
|
||||
items = request.Recursive ?
|
||||
folder.GetRecursiveChildren(user, filter) :
|
||||
folder.GetChildren(user, true).Where(filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
items = request.Recursive ? folder.GetRecursiveChildren() : folder.Children;
|
||||
items = request.Recursive ?
|
||||
folder.GetRecursiveChildren(filter) :
|
||||
folder.Children.Where(filter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
items = new[] { item };
|
||||
items = new[] { parentItem }.Where(filter);
|
||||
}
|
||||
|
||||
items = FilterItems(request, items);
|
||||
|
||||
var extractedItems = GetAllItems(request, items);
|
||||
|
||||
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 dtoOptions = request.GetDtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = tuples.Select(i => GetDto(i.Item1, user, dtoOptions, i.Item2));
|
||||
|
||||
|
@ -290,33 +296,41 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// Filters the items.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
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
|
||||
if (!string.IsNullOrEmpty(request.ExcludeItemTypes))
|
||||
if (excludeItemTypes.Length > 0)
|
||||
{
|
||||
var vals = request.ExcludeItemTypes.Split(',');
|
||||
items = items.Where(f => !vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
|
||||
if (excludeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Include item types
|
||||
if (!string.IsNullOrEmpty(request.IncludeItemTypes))
|
||||
if (includeItemTypes.Length > 0)
|
||||
{
|
||||
var vals = request.IncludeItemTypes.Split(',');
|
||||
items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
|
||||
if (!includeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Include MediaTypes
|
||||
if (!string.IsNullOrEmpty(request.MediaTypes))
|
||||
if (mediaTypes.Length > 0)
|
||||
{
|
||||
var vals = request.MediaTypes.Split(',');
|
||||
|
||||
items = items.Where(f => vals.Contains(f.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase));
|
||||
if (!mediaTypes.Contains(f.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
var item = GetGameGenre(request.Name, LibraryManager);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
if (request.UserId.HasValue)
|
||||
{
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
var item = GetGenre(request.Name, LibraryManager);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
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)]
|
||||
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")]
|
||||
public bool? IsMissing { get; set; }
|
||||
|
||||
|
@ -321,14 +319,14 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
var result = await GetItemsToSerialize(request, user, parentItem).ConfigureAwait(false);
|
||||
|
||||
var isFiltered = result.Item2;
|
||||
var dtoOptions = request.GetDtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
if (isFiltered)
|
||||
{
|
||||
return new ItemsResult
|
||||
{
|
||||
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 returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray();
|
||||
var returnItems = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user).ToArray();
|
||||
|
||||
return new ItemsResult
|
||||
{
|
||||
|
@ -396,52 +394,29 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
else if (request.Recursive)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
items = ((Folder)item).RecursiveChildren;
|
||||
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
|
||||
|
||||
items = _libraryManager.ReplaceVideosWithPrimaryVersions(items);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user));
|
||||
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||
}
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
var result = await ((Folder)item).GetItems(GetItemsQuery(request, user));
|
||||
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||
}
|
||||
|
||||
items = ((Folder)item).GetChildren(user, true);
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(result, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (request.IncludeIndexContainers)
|
||||
{
|
||||
var list = items.ToList();
|
||||
|
||||
var containers = list.Select(i => i.IndexContainer)
|
||||
.Where(i => i != null);
|
||||
|
||||
list.AddRange(containers);
|
||||
|
||||
items = list.Distinct();
|
||||
items = ((Folder)item).GetChildren(user, true);
|
||||
}
|
||||
|
||||
return new Tuple<QueryResult<BaseItem>, bool>(new QueryResult<BaseItem>
|
||||
|
@ -464,7 +439,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
SortBy = request.GetOrderBy(),
|
||||
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,
|
||||
StartIndex = request.StartIndex,
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
var item = GetMusicGenre(request.Name, LibraryManager);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
if (request.UserId.HasValue)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@ using MediaBrowser.Controller.Library;
|
|||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -86,7 +85,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
var item = GetPerson(request.Name, LibraryManager);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
if (request.UserId.HasValue)
|
||||
{
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
var item = GetStudio(request.Name, LibraryManager);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
if (request.UserId.HasValue)
|
||||
{
|
||||
|
|
|
@ -228,7 +228,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
public string UserId { get; set; }
|
||||
|
||||
[ApiMember(Name = "Limit", Description = "Limit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
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")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
|
||||
public GetLatestMedia()
|
||||
{
|
||||
Limit = 20;
|
||||
|
@ -304,74 +304,17 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
// Avoid implicitly captured closure
|
||||
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 list = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
{
|
||||
var vals = request.IncludeItemTypes.Split(',');
|
||||
libraryItems = libraryItems.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
GroupItems = request.GroupItems,
|
||||
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;
|
||||
|
||||
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 options = GetDtoOptions(request);
|
||||
|
||||
var dtos = list.Select(i =>
|
||||
{
|
||||
|
@ -394,15 +337,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
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)
|
||||
{
|
||||
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 dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
|
||||
.ToArray();
|
||||
|
@ -447,14 +381,13 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
// Get them from the child tree
|
||||
if (series != null)
|
||||
{
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
// Avoid implicitly captured closure
|
||||
var currentUser = user;
|
||||
|
||||
var dtos = series
|
||||
.GetRecursiveChildren()
|
||||
.Where(i => i is Episode && i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
|
||||
.GetRecursiveChildren(i => i is Episode && i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
|
||||
.OrderBy(i =>
|
||||
{
|
||||
if (i.PremiereDate.HasValue)
|
||||
|
@ -479,7 +412,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
// Get them from the db
|
||||
if (movie != null)
|
||||
{
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = movie.SpecialFeatureIds
|
||||
.Select(_libraryManager.GetItemById)
|
||||
|
@ -518,11 +451,10 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
trailerIds = hasTrailers.GetTrailerIds();
|
||||
}
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = trailerIds
|
||||
.Select(_libraryManager.GetItemById)
|
||||
.OrderBy(i => i.SortName)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||
|
||||
return dtos.ToList();
|
||||
|
@ -539,7 +471,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
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);
|
||||
|
||||
|
@ -557,7 +489,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
var item = user.RootFolder;
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
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 dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
|
||||
.ToArray();
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
var item = LibraryManager.GetYear(request.Year);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
if (request.UserId.HasValue)
|
||||
{
|
||||
|
|
|
@ -11,7 +11,6 @@ using MediaBrowser.Model.Connect;
|
|||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Users;
|
||||
using ServiceStack;
|
||||
using ServiceStack.Text.Controller;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -56,6 +55,21 @@ namespace MediaBrowser.Api
|
|||
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>
|
||||
/// Class DeleteUser
|
||||
/// </summary>
|
||||
|
@ -148,6 +162,32 @@ namespace MediaBrowser.Api
|
|||
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>
|
||||
/// Class UpdateUser
|
||||
/// </summary>
|
||||
|
@ -294,7 +334,7 @@ namespace MediaBrowser.Api
|
|||
.Select(i => _userManager.GetUserDto(i, Request.RemoteIp))
|
||||
.ToList();
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -313,7 +353,23 @@ namespace MediaBrowser.Api
|
|||
|
||||
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>
|
||||
|
@ -410,6 +466,8 @@ namespace MediaBrowser.Api
|
|||
|
||||
public async Task PostAsync(UpdateUserPassword request)
|
||||
{
|
||||
AssertCanUpdateUser(request.Id);
|
||||
|
||||
var user = _userManager.GetUserById(request.Id);
|
||||
|
||||
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>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
|
@ -449,14 +534,15 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
// 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
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
||||
var id = GetPathValue(1);
|
||||
|
||||
AssertCanUpdateUser(id);
|
||||
|
||||
var dtoUser = request;
|
||||
|
||||
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.RenameUser(user, dtoUser.Name);
|
||||
|
||||
|
@ -500,11 +586,29 @@ namespace MediaBrowser.Api
|
|||
|
||||
public void Post(UpdateUserConfiguration request)
|
||||
{
|
||||
AssertCanUpdateUser(request.Id);
|
||||
|
||||
var task = _userManager.UpdateConfiguration(request.Id, request);
|
||||
|
||||
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)
|
||||
{
|
||||
var task = UpdateUserPolicy(request);
|
||||
|
|
|
@ -5,7 +5,6 @@ using MediaBrowser.Controller.Entities;
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
|
@ -80,7 +79,7 @@ namespace MediaBrowser.Api
|
|||
: _libraryManager.RootFolder)
|
||||
: _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var video = (Video)item;
|
||||
|
||||
|
|
|
@ -475,7 +475,7 @@ namespace MediaBrowser.Common.Implementations
|
|||
SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager);
|
||||
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);
|
||||
|
||||
ZipClient = new ZipClient();
|
||||
|
|
|
@ -690,7 +690,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
|
|||
{
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
_fileSystem.DeleteFile(file);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
|
@ -270,8 +270,8 @@ namespace MediaBrowser.Common.Implementations.IO
|
|||
File.Copy(temp1, file2, true);
|
||||
File.Copy(temp2, file1, true);
|
||||
|
||||
File.Delete(temp1);
|
||||
File.Delete(temp2);
|
||||
DeleteFile(temp1);
|
||||
DeleteFile(temp2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -409,5 +409,25 @@ namespace MediaBrowser.Common.Implementations.IO
|
|||
|
||||
//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>
|
||||
</PropertyGroup>
|
||||
<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>
|
||||
<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 Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
|
||||
</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>
|
||||
<HintPath>..\packages\SimpleInjector.2.6.1\lib\net45\SimpleInjector.dll</HintPath>
|
||||
<HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.dll</HintPath>
|
||||
</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>
|
||||
<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 Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
|
|
|
@ -18,11 +18,64 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||
Logger = logger;
|
||||
}
|
||||
|
||||
private volatile List<string> _localIpAddresses;
|
||||
private readonly object _localIpAddressSyncLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the machine's local ip address
|
||||
/// </summary>
|
||||
/// <returns>IPAddress.</returns>
|
||||
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()
|
||||
.Where(i => !IPAddress.IsLoopback(i))
|
||||
|
@ -53,6 +106,11 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||
// Private address space:
|
||||
// http://en.wikipedia.org/wiki/Private_network
|
||||
|
||||
if (endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return Is172AddressPrivate(endpoint);
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
// 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("127.", StringComparison.OrdinalIgnoreCase) ||
|
||||
endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
|
||||
endpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) ||
|
||||
endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) ||
|
||||
endpoint.StartsWith("192.168", 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)
|
||||
{
|
||||
return IsInLocalNetworkInternal(endpoint, true);
|
||||
|
@ -122,7 +192,7 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<IPAddress> GetIpAddresses(string hostName)
|
||||
{
|
||||
return Dns.GetHostAddresses(hostName);
|
||||
|
|
|
@ -108,13 +108,9 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
/// </summary>
|
||||
private TaskResult _lastExecutionResult;
|
||||
/// <summary>
|
||||
/// The _last execution resultinitialized
|
||||
/// </summary>
|
||||
private bool _lastExecutionResultinitialized;
|
||||
/// <summary>
|
||||
/// The _last execution result sync lock
|
||||
/// </summary>
|
||||
private object _lastExecutionResultSyncLock = new object();
|
||||
private readonly object _lastExecutionResultSyncLock = new object();
|
||||
/// <summary>
|
||||
/// Gets the last execution result.
|
||||
/// </summary>
|
||||
|
@ -123,38 +119,39 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
{
|
||||
get
|
||||
{
|
||||
LazyInitializer.EnsureInitialized(ref _lastExecutionResult, ref _lastExecutionResultinitialized, ref _lastExecutionResultSyncLock, () =>
|
||||
if (_lastExecutionResult == null)
|
||||
{
|
||||
var path = GetHistoryFilePath();
|
||||
lock (_lastExecutionResultSyncLock)
|
||||
{
|
||||
if (_lastExecutionResult == null)
|
||||
{
|
||||
var path = GetHistoryFilePath();
|
||||
|
||||
try
|
||||
{
|
||||
return JsonSerializer.DeserializeFromFile<TaskResult>(path);
|
||||
try
|
||||
{
|
||||
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;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_lastExecutionResult = value;
|
||||
|
||||
_lastExecutionResultinitialized = value != null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,13 +224,9 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
/// </summary>
|
||||
private IEnumerable<ITaskTrigger> _triggers;
|
||||
/// <summary>
|
||||
/// The _triggers initialized
|
||||
/// </summary>
|
||||
private bool _triggersInitialized;
|
||||
/// <summary>
|
||||
/// The _triggers sync lock
|
||||
/// </summary>
|
||||
private object _triggersSyncLock = new object();
|
||||
private readonly object _triggersSyncLock = new object();
|
||||
/// <summary>
|
||||
/// Gets the triggers that define when the task will run
|
||||
/// </summary>
|
||||
|
@ -243,7 +236,16 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
{
|
||||
get
|
||||
{
|
||||
LazyInitializer.EnsureInitialized(ref _triggers, ref _triggersInitialized, ref _triggersSyncLock, LoadTriggers);
|
||||
if (_triggers == null)
|
||||
{
|
||||
lock (_triggersSyncLock)
|
||||
{
|
||||
if (_triggers == null)
|
||||
{
|
||||
_triggers = LoadTriggers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _triggers;
|
||||
}
|
||||
|
@ -262,8 +264,6 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
|
||||
_triggers = value.ToList();
|
||||
|
||||
_triggersInitialized = true;
|
||||
|
||||
ReloadTriggerEvents(false);
|
||||
|
||||
SaveTriggers(_triggers);
|
||||
|
@ -335,12 +335,30 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
trigger.Start(false);
|
||||
}
|
||||
|
||||
private Task _currentTask;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.InvalidOperationException">Cannot execute a Task that is already running</exception>
|
||||
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
|
||||
if (CurrentCancellationTokenSource != null)
|
||||
|
@ -544,6 +562,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
Id = Id
|
||||
};
|
||||
|
||||
var hasKey = ScheduledTask as IHasKey;
|
||||
if (hasKey != null)
|
||||
{
|
||||
result.Key = hasKey.Key;
|
||||
}
|
||||
|
||||
if (ex != null)
|
||||
{
|
||||
result.ErrorMessage = ex.Message;
|
||||
|
@ -579,14 +603,60 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
|
|||
{
|
||||
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
|
||||
{
|
||||
File.Delete(path);
|
||||
_fileSystem.DeleteFile(path);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
|
|
|
@ -76,7 +76,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
|
|||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
File.Delete(file.FullName);
|
||||
_fileSystem.DeleteFile(file.FullName);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Implementations.Security;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Common.Progress;
|
||||
|
@ -106,6 +107,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly ISecurityManager _securityManager;
|
||||
private readonly IConfigurationManager _config;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the application host.
|
||||
|
@ -113,7 +115,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
/// <value>The application host.</value>
|
||||
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)
|
||||
{
|
||||
|
@ -129,6 +131,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
_jsonSerializer = jsonSerializer;
|
||||
_securityManager = securityManager;
|
||||
_config = config;
|
||||
_fileSystem = fileSystem;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -570,7 +573,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
|
||||
try
|
||||
{
|
||||
File.Delete(tempFile);
|
||||
_fileSystem.DeleteFile(tempFile);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
@ -591,7 +594,7 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
// Remove it the quick way for now
|
||||
_applicationHost.RemovePlugin(plugin);
|
||||
|
||||
File.Delete(plugin.AssemblyFilePath);
|
||||
_fileSystem.DeleteFile(plugin.AssemblyFilePath);
|
||||
|
||||
OnPluginUninstalled(plugin);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NLog" version="3.1.0.0" targetFramework="net45" />
|
||||
<package id="SimpleInjector" version="2.6.1" targetFramework="net45" />
|
||||
<package id="NLog" version="3.2.0.0" targetFramework="net45" />
|
||||
<package id="SimpleInjector" version="2.7.0" targetFramework="net45" />
|
||||
</packages>
|
||||
|
|
|
@ -26,36 +26,6 @@ namespace MediaBrowser.Common.Extensions
|
|||
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)
|
||||
{
|
||||
return String.Concat(
|
||||
|
|
|
@ -133,5 +133,33 @@ namespace MediaBrowser.Common.IO
|
|||
/// <param name="path">The path.</param>
|
||||
/// <returns><c>true</c> if [is path file] [the specified path]; otherwise, <c>false</c>.</returns>
|
||||
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>
|
||||
/// <returns><c>true</c> if [is in local network] [the specified endpoint]; otherwise, <c>false</c>.</returns>
|
||||
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.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
|
@ -14,9 +15,19 @@ namespace MediaBrowser.Controller.Channels
|
|||
|
||||
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);
|
||||
|
@ -50,7 +61,22 @@ namespace MediaBrowser.Controller.Channels
|
|||
|
||||
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.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Users;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ namespace MediaBrowser.Controller.Channels
|
|||
return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
|
||||
}
|
||||
|
||||
public override string GetUserDataKey()
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
return ExternalId;
|
||||
}
|
||||
|
@ -89,5 +89,10 @@ namespace MediaBrowser.Controller.Channels
|
|||
|
||||
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.Configuration;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Users;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
|
@ -40,7 +39,7 @@ namespace MediaBrowser.Controller.Channels
|
|||
return false;
|
||||
}
|
||||
|
||||
public override string GetUserDataKey()
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
return ExternalId;
|
||||
}
|
||||
|
@ -76,5 +75,10 @@ namespace MediaBrowser.Controller.Channels
|
|||
{
|
||||
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.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Users;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
|
@ -28,8 +28,8 @@ namespace MediaBrowser.Controller.Channels
|
|||
public string OriginalImageUrl { get; set; }
|
||||
|
||||
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
|
||||
|
||||
public override string GetUserDataKey()
|
||||
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
if (ContentType == ChannelMediaContentType.MovieExtra)
|
||||
{
|
||||
|
@ -119,5 +119,10 @@ namespace MediaBrowser.Controller.Channels
|
|||
{
|
||||
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>
|
||||
/// <returns>Folder.</returns>
|
||||
Folder GetCollectionsFolder(string userId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collections.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>IEnumerable<BoxSet>.</returns>
|
||||
IEnumerable<BoxSet> GetCollections(User user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.Session;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -15,6 +14,10 @@ namespace MediaBrowser.Controller.Devices
|
|||
/// Occurs when [device options updated].
|
||||
/// </summary>
|
||||
event EventHandler<GenericEventArgs<DeviceInfo>> DeviceOptionsUpdated;
|
||||
/// <summary>
|
||||
/// Occurs when [camera image uploaded].
|
||||
/// </summary>
|
||||
event EventHandler<GenericEventArgs<CameraImageUploadInfo>> CameraImageUploaded;
|
||||
|
||||
/// <summary>
|
||||
/// Registers the device.
|
||||
|
|
|
@ -62,8 +62,9 @@ namespace MediaBrowser.Controller.Dlna
|
|||
/// </summary>
|
||||
/// <param name="headers">The headers.</param>
|
||||
/// <param name="serverUuId">The server uu identifier.</param>
|
||||
/// <param name="serverAddress">The server address.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetServerDescriptionXml(IDictionary<string, string> headers, string serverUuId);
|
||||
string GetServerDescriptionXml(IDictionary<string, string> headers, string serverUuId, string serverAddress);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the icon.
|
||||
|
|
|
@ -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 int ImageTypeLimit { get; set; }
|
||||
public bool EnableImages { get; set; }
|
||||
public string DeviceId { get; set; }
|
||||
|
||||
public DtoOptions()
|
||||
{
|
||||
|
|
|
@ -44,6 +44,17 @@ namespace MediaBrowser.Controller.Dto
|
|||
/// <param name="owner">The owner.</param>
|
||||
/// <returns>BaseItemDto.</returns>
|
||||
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>
|
||||
/// 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>
|
||||
/// The _virtual children
|
||||
/// </summary>
|
||||
|
@ -66,7 +71,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var path = ContainingFolderPath;
|
||||
|
||||
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager, directoryService)
|
||||
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths , directoryService)
|
||||
{
|
||||
FileInfo = new DirectoryInfo(path),
|
||||
Path = path,
|
||||
|
|
|
@ -4,11 +4,11 @@ using MediaBrowser.Model.Configuration;
|
|||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
|
@ -80,6 +80,15 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
protected override bool SupportsOwnedItems
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
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>
|
||||
/// Gets or sets the artist.
|
||||
/// </summary>
|
||||
|
@ -169,7 +185,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
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)
|
||||
|
@ -223,7 +239,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
{
|
||||
Id = i.Id.ToString("N"),
|
||||
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,
|
||||
Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path,
|
||||
RunTimeTicks = i.RunTimeTicks,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
|
@ -52,14 +52,14 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
}
|
||||
}
|
||||
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string AlbumArtist
|
||||
{
|
||||
get { return AlbumArtists.FirstOrDefault(); }
|
||||
}
|
||||
|
||||
public List<string> AlbumArtists { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tracks.
|
||||
/// </summary>
|
||||
|
@ -68,7 +68,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
{
|
||||
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.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
var id = this.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||
|
||||
|
@ -152,7 +152,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
return "MusicAlbum-Musicbrainz-" + id;
|
||||
}
|
||||
|
||||
return base.GetUserDataKey();
|
||||
return base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
|
@ -173,17 +173,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
id.ArtistProviderIds = artist.ProviderIds;
|
||||
}
|
||||
|
||||
id.SongInfos = RecursiveChildren.OfType<Audio>()
|
||||
id.SongInfos = GetRecursiveChildren(i => i is Audio)
|
||||
.Cast<Audio>()
|
||||
.Select(i => i.GetLookupInfo())
|
||||
.ToList();
|
||||
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public class MusicAlbumDisc : Folder
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
using System.Runtime.Serialization;
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
|
@ -19,7 +18,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
{
|
||||
public bool IsAccessedByName { get; set; }
|
||||
public List<string> ProductionLocations { get; set; }
|
||||
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool IsFolder
|
||||
{
|
||||
get
|
||||
|
@ -34,6 +34,11 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return !IsAccessedByName;
|
||||
}
|
||||
|
||||
protected override IEnumerable<BaseItem> ActualChildren
|
||||
{
|
||||
get
|
||||
|
@ -68,7 +73,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
return GetUserDataKey(this);
|
||||
}
|
||||
|
@ -78,6 +83,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// If the item is a folder, it returns the folder itself
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
[IgnoreDataMember]
|
||||
public override string ContainingFolderPath
|
||||
{
|
||||
get
|
||||
|
@ -90,6 +96,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// Gets a value indicating whether this instance is owned item.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool IsOwnedItem
|
||||
{
|
||||
get
|
||||
|
@ -122,89 +129,53 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
|
||||
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 others = items.Except(songs).ToList();
|
||||
|
||||
var totalItems = songs.Count + others.Count;
|
||||
var percentages = new Dictionary<Guid, double>(totalItems);
|
||||
|
||||
var tasks = new List<Task>();
|
||||
var numComplete = 0;
|
||||
|
||||
// Refresh songs
|
||||
foreach (var item in songs)
|
||||
{
|
||||
if (tasks.Count >= 2)
|
||||
{
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
tasks.Clear();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var innerProgress = new ActionableProgress<double>();
|
||||
|
||||
// Avoid implicitly captured closure
|
||||
var currentChild = item;
|
||||
innerProgress.RegisterAction(p =>
|
||||
{
|
||||
lock (percentages)
|
||||
{
|
||||
percentages[currentChild.Id] = p / 100;
|
||||
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var percent = percentages.Values.Sum();
|
||||
percent /= totalItems;
|
||||
percent *= 100;
|
||||
progress.Report(percent);
|
||||
}
|
||||
});
|
||||
|
||||
var taskChild = item;
|
||||
tasks.Add(Task.Run(async () => await RefreshItem(taskChild, refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken));
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= totalItems;
|
||||
progress.Report(percent * 100);
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
tasks.Clear();
|
||||
|
||||
// Refresh current item
|
||||
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
|
||||
// Refresh all non-songs
|
||||
foreach (var item in others)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// Avoid implicitly captured closure
|
||||
var currentChild = item;
|
||||
|
||||
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||
lock (percentages)
|
||||
{
|
||||
percentages[currentChild.Id] = 1;
|
||||
|
||||
var percent = percentages.Values.Sum();
|
||||
percent /= totalItems;
|
||||
percent *= 100;
|
||||
progress.Report(percent);
|
||||
}
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= totalItems;
|
||||
progress.Report(percent * 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()
|
||||
{
|
||||
var info = GetItemLookupInfo<ArtistInfo>();
|
||||
|
||||
info.SongInfos = RecursiveChildren.OfType<Audio>()
|
||||
info.SongInfos = GetRecursiveChildren(i => i is Audio)
|
||||
.Cast<Audio>()
|
||||
.Select(i => i.GetLookupInfo())
|
||||
.ToList();
|
||||
|
||||
|
@ -213,9 +184,16 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
|
||||
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
|
||||
{
|
||||
return inputItems.OfType<IHasArtist>()
|
||||
.Where(i => i.HasArtist(Name))
|
||||
.Cast<BaseItem>();
|
||||
return inputItems.Where(GetItemFilter());
|
||||
}
|
||||
|
||||
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.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
return "MusicGenre-" + Name;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// If the item is a folder, it returns the folder itself
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
[IgnoreDataMember]
|
||||
public override string ContainingFolderPath
|
||||
{
|
||||
get
|
||||
|
@ -38,10 +39,16 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
}
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is owned item.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool IsOwnedItem
|
||||
{
|
||||
get
|
||||
|
@ -52,7 +59,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
|
||||
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); }
|
||||
}
|
||||
|
||||
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>
|
||||
/// Gets or sets the date created.
|
||||
/// </summary>
|
||||
|
@ -268,6 +300,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
public static IChannelManager ChannelManager { get; set; }
|
||||
public static ICollectionManager CollectionManager { get; set; }
|
||||
public static IImageProcessor ImageProcessor { get; set; }
|
||||
public static IMediaSourceManager MediaSourceManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||
|
@ -359,7 +392,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ForcedSortName))
|
||||
if (!string.IsNullOrWhiteSpace(ForcedSortName))
|
||||
{
|
||||
return ForcedSortName;
|
||||
}
|
||||
|
@ -379,21 +412,19 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
public string GetInternalMetadataPath()
|
||||
{
|
||||
return GetInternalMetadataPath(ConfigurationManager.ApplicationPaths.InternalMetadataPath);
|
||||
var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath;
|
||||
|
||||
return GetInternalMetadataPath(basePath);
|
||||
}
|
||||
|
||||
protected virtual string GetInternalMetadataPath(string basePath)
|
||||
{
|
||||
var idString = Id.ToString("N");
|
||||
|
||||
return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString);
|
||||
}
|
||||
|
||||
public static string GetInternalMetadataPathForId(Guid id)
|
||||
{
|
||||
var idString = id.ToString("N");
|
||||
|
||||
var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath;
|
||||
if (ConfigurationManager.Configuration.EnableLibraryMetadataSubFolder)
|
||||
{
|
||||
basePath = System.IO.Path.Combine(basePath, "library");
|
||||
}
|
||||
|
||||
return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString);
|
||||
}
|
||||
|
@ -692,7 +723,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var requiresSave = false;
|
||||
|
||||
if (IsFolder || Parent != null)
|
||||
if (SupportsOwnedItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -724,6 +755,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
protected virtual bool SupportsOwnedItems
|
||||
{
|
||||
get { return IsFolder || Parent != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes owned items such as trailers, theme videos, special features, etc.
|
||||
/// Returns true or false indicating if changes were found.
|
||||
|
@ -889,11 +926,24 @@ namespace MediaBrowser.Controller.Entities
|
|||
get { return null; }
|
||||
}
|
||||
|
||||
private string _userDataKey;
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <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();
|
||||
}
|
||||
|
@ -905,6 +955,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
return current.IsInMixedFolder == newItem.IsInMixedFolder;
|
||||
}
|
||||
|
||||
public void AfterMetadataRefresh()
|
||||
{
|
||||
_sortName = null;
|
||||
_userDataKey = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the preferred metadata language.
|
||||
/// </summary>
|
||||
|
@ -1024,7 +1080,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
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;
|
||||
}
|
||||
|
@ -1033,6 +1090,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool IsAllowTagFilterEnforced()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the block unrated value.
|
||||
/// </summary>
|
||||
|
@ -1060,6 +1122,23 @@ namespace MediaBrowser.Controller.Entities
|
|||
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>
|
||||
/// Gets a value indicating whether this instance is folder.
|
||||
/// </summary>
|
||||
|
@ -1146,7 +1225,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
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))
|
||||
{
|
||||
|
@ -1164,7 +1243,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
}).FirstOrDefault();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1458,7 +1538,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
currentFile.Attributes &= ~FileAttributes.Hidden;
|
||||
}
|
||||
|
||||
currentFile.Delete();
|
||||
FileSystem.DeleteFile(currentFile.FullName);
|
||||
}
|
||||
|
||||
return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
|
||||
|
@ -1703,6 +1783,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
public virtual bool BeforeMetadataRefresh()
|
||||
{
|
||||
_userDataKey = null;
|
||||
_sortName = null;
|
||||
|
||||
var hasChanges = false;
|
||||
|
||||
if (string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(Path))
|
||||
|
|
|
@ -11,5 +11,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using MediaBrowser.Model.Configuration;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
|
@ -37,6 +38,13 @@ namespace MediaBrowser.Controller.Entities
|
|||
Tags = new List<string>();
|
||||
}
|
||||
|
||||
public override bool CanDownload()
|
||||
{
|
||||
var locationType = LocationType;
|
||||
return locationType != LocationType.Remote &&
|
||||
locationType != LocationType.Virtual;
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||
{
|
||||
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; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -86,7 +91,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var path = ContainingFolderPath;
|
||||
|
||||
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager, directoryService)
|
||||
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
|
||||
{
|
||||
FileInfo = new DirectoryInfo(path),
|
||||
Path = path,
|
||||
|
@ -121,12 +126,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
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>
|
||||
/// 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***
|
||||
|
@ -138,7 +137,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <param name="refreshOptions">The refresh options.</param>
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
/// <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();
|
||||
|
||||
|
@ -146,8 +145,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
if (!list.SequenceEqual(PhysicalLocationsList))
|
||||
{
|
||||
await UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
|
||||
return UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken);
|
||||
}
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -6,7 +6,6 @@ using MediaBrowser.Controller.Providers;
|
|||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MoreLinq;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
@ -15,13 +14,14 @@ using System.Linq;
|
|||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Class Folder
|
||||
/// </summary>
|
||||
public class Folder : BaseItem, IHasThemeMedia, IHasTags
|
||||
public class Folder : BaseItem, IHasThemeMedia, IHasTags, IHasPreferredMetadataLanguage
|
||||
{
|
||||
public static IUserManager UserManager { get; set; }
|
||||
public static IUserViewManager UserViewManager { get; set; }
|
||||
|
@ -30,6 +30,14 @@ namespace MediaBrowser.Controller.Entities
|
|||
public List<Guid> ThemeVideoIds { 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()
|
||||
{
|
||||
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>
|
||||
/// Gets or sets a value indicating whether this instance is physical root.
|
||||
/// </summary>
|
||||
|
@ -98,6 +119,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
public virtual List<LinkedChild> LinkedChildren { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
protected virtual bool SupportsShortcutChildren
|
||||
{
|
||||
get { return true; }
|
||||
|
@ -237,14 +259,13 @@ namespace MediaBrowser.Controller.Entities
|
|||
protected virtual IEnumerable<string> GetIndexByOptions()
|
||||
{
|
||||
return new List<string> {
|
||||
{LocalizedStrings.Instance.GetString("NoneDispPref")},
|
||||
{LocalizedStrings.Instance.GetString("PerformerDispPref")},
|
||||
{LocalizedStrings.Instance.GetString("GenreDispPref")},
|
||||
{LocalizedStrings.Instance.GetString("DirectorDispPref")},
|
||||
{LocalizedStrings.Instance.GetString("YearDispPref")},
|
||||
{LocalizedStrings.Instance.GetString("StudioDispPref")}
|
||||
{"None"},
|
||||
{"Performer"},
|
||||
{"Genre"},
|
||||
{"Director"},
|
||||
{"Year"},
|
||||
{"Studio"}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -275,7 +296,17 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
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)
|
||||
{
|
||||
if (this is ICollectionFolder)
|
||||
if (this is ICollectionFolder && !(this is BasePluginFolder))
|
||||
{
|
||||
if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) ||
|
||||
|
||||
// Backwards compatibility
|
||||
user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase))
|
||||
if (user.Policy.BlockedMediaFolders != null)
|
||||
{
|
||||
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>
|
||||
public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true)
|
||||
{
|
||||
return ValidateChildrenWithCancellationSupport(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);
|
||||
return ValidateChildrenInternal(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService);
|
||||
}
|
||||
|
||||
private Dictionary<Guid, BaseItem> GetActualChildrenDictionary()
|
||||
|
@ -540,50 +576,49 @@ namespace MediaBrowser.Controller.Entities
|
|||
var children = ActualChildren.ToList();
|
||||
|
||||
var percentages = new Dictionary<Guid, double>(children.Count);
|
||||
|
||||
var tasks = new List<Task>();
|
||||
var numComplete = 0;
|
||||
var count = children.Count;
|
||||
|
||||
foreach (var child in children)
|
||||
{
|
||||
if (tasks.Count >= 2)
|
||||
{
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
tasks.Clear();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Avoid implicitly captured closure
|
||||
var taskChild = child;
|
||||
|
||||
tasks.Add(Task.Run(async () => await RefreshChildMetadata(taskChild, refreshOptions, false, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken));
|
||||
await RefreshChildMetadata(child, refreshOptions, false, new Progress<double>(), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= count;
|
||||
percent *= 100;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -678,12 +713,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
path = System.IO.Path.GetDirectoryName(path);
|
||||
}
|
||||
|
||||
if (ContainsPath(LibraryManager.GetDefaultVirtualFolders(), originalPath))
|
||||
if (ContainsPath(LibraryManager.GetVirtualFolders(), originalPath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return UserManager.Users.Any(user => ContainsPath(LibraryManager.GetVirtualFolders(user), originalPath));
|
||||
return ContainsPath(LibraryManager.GetVirtualFolders(), originalPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -731,28 +766,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
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)
|
||||
{
|
||||
if (child.Id == Guid.Empty)
|
||||
|
@ -786,18 +799,31 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
var user = query.User;
|
||||
|
||||
var items = query.Recursive
|
||||
? GetRecursiveChildren(user)
|
||||
: GetChildren(user, true);
|
||||
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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>
|
||||
|
@ -822,11 +848,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
//the true root should return our users root folder children
|
||||
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)
|
||||
|
@ -839,31 +865,30 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
/// <param name="user">The user.</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="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>
|
||||
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))
|
||||
{
|
||||
if (child.IsVisible(user))
|
||||
{
|
||||
if (includeHidden || !child.IsHiddenFromUser(user))
|
||||
{
|
||||
list.Add(child);
|
||||
if (filter == null || filter(child))
|
||||
{
|
||||
result[child.Id] = child;
|
||||
}
|
||||
}
|
||||
|
||||
if (recursive && child.IsFolder)
|
||||
{
|
||||
var folder = (Folder)child;
|
||||
|
||||
if (folder.AddChildrenToList(user, includeLinkedChildren, list, includeHidden, true))
|
||||
{
|
||||
hasLinkedChildren = true;
|
||||
}
|
||||
folder.AddChildren(user, includeLinkedChildren, result, includeHidden, true, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -874,14 +899,13 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
if (child.IsVisible(user))
|
||||
{
|
||||
hasLinkedChildren = true;
|
||||
|
||||
list.Add(child);
|
||||
if (filter == null || filter(child))
|
||||
{
|
||||
result[child.Id] = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasLinkedChildren;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -891,18 +915,23 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
/// <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)
|
||||
{
|
||||
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>
|
||||
|
@ -910,10 +939,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
/// <returns>IList{BaseItem}.</returns>
|
||||
public IList<BaseItem> GetRecursiveChildren()
|
||||
{
|
||||
return GetRecursiveChildren(i => true);
|
||||
}
|
||||
|
||||
public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter)
|
||||
{
|
||||
var list = new List<BaseItem>();
|
||||
|
||||
AddChildrenToList(list, true, null);
|
||||
AddChildrenToList(list, true, filter);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
@ -1022,6 +1056,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
.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)
|
||||
{
|
||||
var changesFound = false;
|
||||
|
@ -1126,8 +1169,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
bool resetPosition)
|
||||
{
|
||||
// Sweep through recursively and update status
|
||||
var tasks = GetRecursiveChildren(user, true)
|
||||
.Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
||||
var tasks = GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
||||
.Select(c => c.MarkPlayed(user, datePlayed, resetPosition));
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
@ -1141,8 +1183,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
public override async Task MarkUnplayed(User user)
|
||||
{
|
||||
// Sweep through recursively and update status
|
||||
var tasks = GetRecursiveChildren(user, true)
|
||||
.Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
||||
var tasks = GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
||||
.Select(c => c.MarkUnplayed(user));
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
@ -1171,15 +1212,15 @@ namespace MediaBrowser.Controller.Entities
|
|||
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.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase));
|
||||
i.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase))
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public override bool IsPlayed(User user)
|
||||
{
|
||||
return GetRecursiveChildren(user)
|
||||
.Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
||||
return GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual)
|
||||
.All(i => i.IsPlayed(user));
|
||||
}
|
||||
|
||||
|
@ -1206,8 +1247,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
else
|
||||
{
|
||||
children = folder.GetRecursiveChildren(user)
|
||||
.Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual);
|
||||
children = folder.GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual);
|
||||
}
|
||||
|
||||
// Loop through each recursive child
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -38,6 +38,13 @@ namespace MediaBrowser.Controller.Entities
|
|||
public List<Guid> LocalTrailerIds { get; set; }
|
||||
public List<Guid> RemoteTrailerIds { get; set; }
|
||||
|
||||
public override bool CanDownload()
|
||||
{
|
||||
var locationType = LocationType;
|
||||
return locationType != LocationType.Remote &&
|
||||
locationType != LocationType.Virtual;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the tags.
|
||||
/// </summary>
|
||||
|
@ -88,7 +95,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
public List<string> MultiPartGameFiles { get; set; }
|
||||
|
||||
public override string GetUserDataKey()
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
var id = this.GetProviderId(MetadataProviders.Gamesdb);
|
||||
|
||||
|
@ -96,7 +103,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
return "Game-Gamesdb-" + id;
|
||||
}
|
||||
return base.GetUserDataKey();
|
||||
return base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDeletePaths()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
@ -10,7 +11,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
return "GameGenre-" + Name;
|
||||
}
|
||||
|
@ -20,6 +21,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// If the item is a folder, it returns the folder itself
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
[IgnoreDataMember]
|
||||
public override string ContainingFolderPath
|
||||
{
|
||||
get
|
||||
|
@ -32,6 +34,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets a value indicating whether this instance is owned item.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool IsOwnedItem
|
||||
{
|
||||
get
|
||||
|
@ -40,9 +43,19 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(GameSystemName))
|
||||
{
|
||||
return "GameSystem-" + GameSystemName;
|
||||
}
|
||||
return base.GetUserDataKey();
|
||||
return base.CreateUserDataKey();
|
||||
}
|
||||
|
||||
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.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -14,7 +15,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
return "Genre-" + Name;
|
||||
}
|
||||
|
@ -24,6 +25,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// If the item is a folder, it returns the folder itself
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
[IgnoreDataMember]
|
||||
public override string ContainingFolderPath
|
||||
{
|
||||
get
|
||||
|
@ -32,10 +34,16 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is owned item.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool IsOwnedItem
|
||||
{
|
||||
get
|
||||
|
@ -46,7 +54,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
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.
|
||||
/// </summary>
|
||||
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…
Reference in New Issue