diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index 3e9a0926be..c51d9e7c01 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -37,11 +37,14 @@ namespace MediaBrowser.Api
private readonly ISessionManager _sessionManager;
+ public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1);
+
///
/// Initializes a new instance of the class.
///
/// The logger.
/// The application paths.
+ /// The session manager.
public ApiEntryPoint(ILogger logger, IServerApplicationPaths appPaths, ISessionManager sessionManager)
{
Logger = logger;
@@ -99,7 +102,7 @@ namespace MediaBrowser.Api
{
var jobCount = _activeTranscodingJobs.Count;
- Parallel.ForEach(_activeTranscodingJobs.ToList(), j => KillTranscodingJob(j, true));
+ Parallel.ForEach(_activeTranscodingJobs.ToList(), j => KillTranscodingJob(j, path => true));
// Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
if (jobCount > 0)
@@ -119,14 +122,12 @@ namespace MediaBrowser.Api
/// The path.
/// The type.
/// The process.
- /// The start time ticks.
/// The device id.
/// The state.
/// The cancellation token source.
public void OnTranscodeBeginning(string path,
TranscodingJobType type,
Process process,
- long? startTimeTicks,
string deviceId,
StreamState state,
CancellationTokenSource cancellationTokenSource)
@@ -139,7 +140,6 @@ namespace MediaBrowser.Api
Path = path,
Process = process,
ActiveRequestCount = 1,
- StartTimeTicks = startTimeTicks,
DeviceId = deviceId,
CancellationTokenSource = cancellationTokenSource
});
@@ -214,10 +214,15 @@ namespace MediaBrowser.Api
/// The type.
/// true if [has active transcoding job] [the specified path]; otherwise, false.
public bool HasActiveTranscodingJob(string path, TranscodingJobType type)
+ {
+ return GetTranscodingJob(path, type) != null;
+ }
+
+ public TranscodingJob GetTranscodingJob(string path, TranscodingJobType type)
{
lock (_activeTranscodingJobs)
{
- return _activeTranscodingJobs.Any(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
+ return _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && j.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
}
}
@@ -290,34 +295,70 @@ namespace MediaBrowser.Api
{
var job = (TranscodingJob)state;
- KillTranscodingJob(job, true);
+ KillTranscodingJob(job, path => true);
}
///
/// Kills the single transcoding job.
///
/// The device id.
- /// if set to true [delete files].
+ /// The delete files.
+ /// if set to true [acquire lock].
+ /// Task.
+ /// deviceId
/// sourcePath
- internal void KillTranscodingJobs(string deviceId, bool deleteFiles)
+ internal Task KillTranscodingJobs(string deviceId, Func deleteFiles, bool acquireLock)
{
if (string.IsNullOrEmpty(deviceId))
{
throw new ArgumentNullException("deviceId");
}
+ return KillTranscodingJobs(j => string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase), deleteFiles, acquireLock);
+ }
+
+ ///
+ /// Kills the transcoding jobs.
+ ///
+ /// The kill job.
+ /// The delete files.
+ /// if set to true [acquire lock].
+ /// Task.
+ /// deviceId
+ internal async Task KillTranscodingJobs(Func killJob, Func deleteFiles, bool acquireLock)
+ {
var jobs = new List();
lock (_activeTranscodingJobs)
{
// This is really only needed for HLS.
// Progressive streams can stop on their own reliably
- jobs.AddRange(_activeTranscodingJobs.Where(i => string.Equals(deviceId, i.DeviceId, StringComparison.OrdinalIgnoreCase)));
+ jobs.AddRange(_activeTranscodingJobs.Where(killJob));
}
- foreach (var job in jobs)
+ if (jobs.Count == 0)
{
- KillTranscodingJob(job, deleteFiles);
+ return;
+ }
+
+ if (acquireLock)
+ {
+ await TranscodingStartLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
+ }
+
+ try
+ {
+ foreach (var job in jobs)
+ {
+ KillTranscodingJob(job, deleteFiles);
+ }
+ }
+ finally
+ {
+ if (acquireLock)
+ {
+ TranscodingStartLock.Release();
+ }
}
}
@@ -325,8 +366,8 @@ namespace MediaBrowser.Api
/// Kills the transcoding job.
///
/// The job.
- /// if set to true [delete files].
- private void KillTranscodingJob(TranscodingJob job, bool deleteFiles)
+ /// The delete.
+ private void KillTranscodingJob(TranscodingJob job, Func delete)
{
lock (_activeTranscodingJobs)
{
@@ -378,7 +419,7 @@ namespace MediaBrowser.Api
}
}
- if (deleteFiles)
+ if (delete(job.Path))
{
DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
}
@@ -386,7 +427,7 @@ namespace MediaBrowser.Api
private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs)
{
- if (retryCount >= 8)
+ if (retryCount >= 10)
{
return;
}
@@ -440,6 +481,8 @@ namespace MediaBrowser.Api
.Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1)
.ToList();
+ Exception e = null;
+
foreach (var file in filesToDelete)
{
try
@@ -449,9 +492,15 @@ namespace MediaBrowser.Api
}
catch (IOException ex)
{
+ e = ex;
Logger.ErrorException("Error deleting HLS file {0}", ex, file);
}
}
+
+ if (e != null)
+ {
+ throw e;
+ }
}
}
@@ -486,12 +535,13 @@ namespace MediaBrowser.Api
/// The kill timer.
public Timer KillTimer { get; set; }
- public long? StartTimeTicks { get; set; }
public string DeviceId { get; set; }
public CancellationTokenSource CancellationTokenSource { get; set; }
public object ProcessLock = new object();
+
+ public bool HasExited { get; set; }
}
///
diff --git a/MediaBrowser.Api/AppThemeService.cs b/MediaBrowser.Api/AppThemeService.cs
index 4d8eed7ddb..87084e415a 100644
--- a/MediaBrowser.Api/AppThemeService.cs
+++ b/MediaBrowser.Api/AppThemeService.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Themes;
using MediaBrowser.Model.Themes;
using ServiceStack;
@@ -47,6 +48,7 @@ namespace MediaBrowser.Api
{
}
+ [Authenticated]
public class AppThemeService : BaseApiService
{
private readonly IAppThemeManager _themeManager;
@@ -92,7 +94,7 @@ namespace MediaBrowser.Api
var contentType = MimeTypes.GetMimeType(info.Path);
- return ToCachedResult(cacheGuid, info.DateModified, cacheDuration, () => _fileSystem.GetFileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read), contentType);
+ return ResultFactory.GetCachedResult(Request, cacheGuid, null, cacheDuration, () => _fileSystem.GetFileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read), contentType);
}
}
}
diff --git a/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs b/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs
deleted file mode 100644
index 6c56083cbf..0000000000
--- a/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs
+++ /dev/null
@@ -1,190 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Logging;
-using ServiceStack.Web;
-using System;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Api
-{
- public class AuthorizationRequestFilterAttribute : Attribute, IHasRequestFilter
- {
- //This property will be resolved by the IoC container
- ///
- /// Gets or sets the user manager.
- ///
- /// The user manager.
- public IUserManager UserManager { get; set; }
-
- public ISessionManager SessionManager { get; set; }
-
- ///
- /// Gets or sets the logger.
- ///
- /// The logger.
- public ILogger Logger { get; set; }
-
- ///
- /// The request filter is executed before the service.
- ///
- /// The http request wrapper
- /// The http response wrapper
- /// The request DTO
- public void RequestFilter(IRequest request, IResponse response, object requestDto)
- {
- //This code is executed before the service
- var auth = GetAuthorizationDictionary(request);
-
- if (auth != null)
- {
- User user = null;
-
- if (auth.ContainsKey("UserId"))
- {
- var userId = auth["UserId"];
-
- if (!string.IsNullOrEmpty(userId))
- {
- user = UserManager.GetUserById(new Guid(userId));
- }
- }
-
- string deviceId;
- string device;
- string client;
- string version;
-
- auth.TryGetValue("DeviceId", out deviceId);
- auth.TryGetValue("Device", out device);
- auth.TryGetValue("Client", out client);
- auth.TryGetValue("Version", out version);
-
- if (!string.IsNullOrEmpty(client) && !string.IsNullOrEmpty(deviceId) && !string.IsNullOrEmpty(device) && !string.IsNullOrEmpty(version))
- {
- var remoteEndPoint = request.RemoteIp;
-
- SessionManager.LogSessionActivity(client, version, deviceId, device, remoteEndPoint, user);
- }
- }
- }
-
- ///
- /// Gets the auth.
- ///
- /// The HTTP req.
- /// Dictionary{System.StringSystem.String}.
- private static Dictionary GetAuthorizationDictionary(IRequest httpReq)
- {
- var auth = httpReq.Headers["Authorization"];
-
- return GetAuthorization(auth);
- }
-
- public static User GetCurrentUser(IRequest httpReq, IUserManager userManager)
- {
- var info = GetAuthorization(httpReq);
-
- return string.IsNullOrEmpty(info.UserId) ? null :
- userManager.GetUserById(new Guid(info.UserId));
- }
-
- ///
- /// Gets the authorization.
- ///
- /// The HTTP req.
- /// Dictionary{System.StringSystem.String}.
- public static AuthorizationInfo GetAuthorization(IRequest httpReq)
- {
- var auth = GetAuthorizationDictionary(httpReq);
-
- string userId = null;
- string deviceId = null;
- string device = null;
- string client = null;
- string version = null;
-
- if (auth != null)
- {
- auth.TryGetValue("UserId", out userId);
- auth.TryGetValue("DeviceId", out deviceId);
- auth.TryGetValue("Device", out device);
- auth.TryGetValue("Client", out client);
- auth.TryGetValue("Version", out version);
- }
-
- return new AuthorizationInfo
- {
- Client = client,
- Device = device,
- DeviceId = deviceId,
- UserId = userId,
- Version = version
- };
- }
-
- ///
- /// Gets the authorization.
- ///
- /// The authorization header.
- /// Dictionary{System.StringSystem.String}.
- private static Dictionary GetAuthorization(string authorizationHeader)
- {
- if (authorizationHeader == null) return null;
-
- var parts = authorizationHeader.Split(' ');
-
- // There should be at least to parts
- if (parts.Length < 2) return null;
-
- // It has to be a digest request
- if (!string.Equals(parts[0], "MediaBrowser", StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- // Remove uptil the first space
- authorizationHeader = authorizationHeader.Substring(authorizationHeader.IndexOf(' '));
- parts = authorizationHeader.Split(',');
-
- var result = new Dictionary(StringComparer.OrdinalIgnoreCase);
-
- foreach (var item in parts)
- {
- var param = item.Trim().Split(new[] { '=' }, 2);
- result.Add(param[0], param[1].Trim(new[] { '"' }));
- }
-
- return result;
- }
-
- ///
- /// A new shallow copy of this filter is used on every request.
- ///
- /// IHasRequestFilter.
- public IHasRequestFilter Copy()
- {
- return this;
- }
-
- ///
- /// Order in which Request Filters are executed.
- /// <0 Executed before global request filters
- /// >0 Executed after global request filters
- ///
- /// The priority.
- public int Priority
- {
- get { return 0; }
- }
- }
-
- public class AuthorizationInfo
- {
- public string UserId;
- public string DeviceId;
- public string Device;
- public string Client;
- public string Version;
- }
-}
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index ca5b8b63a4..1af7054d95 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -14,8 +14,7 @@ namespace MediaBrowser.Api
///
/// Class BaseApiService
///
- [AuthorizationRequestFilter]
- public class BaseApiService : IHasResultFactory, IRestfulService
+ public class BaseApiService : IHasResultFactory, IRestfulService, IHasSession
{
///
/// Gets or sets the logger.
@@ -35,6 +34,8 @@ namespace MediaBrowser.Api
/// The request context.
public IRequest Request { get; set; }
+ public ISessionContext SessionContext { get; set; }
+
public string GetHeader(string name)
{
return Request.Headers[name];
@@ -82,33 +83,18 @@ namespace MediaBrowser.Api
///
/// Gets the session.
///
- /// The session manager.
/// SessionInfo.
- protected SessionInfo GetSession(ISessionManager sessionManager)
+ /// Session not found.
+ protected SessionInfo GetSession()
{
- var auth = AuthorizationRequestFilterAttribute.GetAuthorization(Request);
+ var session = SessionContext.GetSession(Request);
- return sessionManager.Sessions.First(i => string.Equals(i.DeviceId, auth.DeviceId) &&
- string.Equals(i.Client, auth.Client) &&
- string.Equals(i.ApplicationVersion, auth.Version));
- }
+ if (session == null)
+ {
+ throw new ArgumentException("Session not found.");
+ }
- ///
- /// To the cached result.
- ///
- ///
- /// The cache key.
- /// The last date modified.
- /// Duration of the cache.
- /// The factory fn.
- /// Type of the content.
- /// The response headers.
- /// System.Object.
- /// cacheKey
- protected object ToCachedResult(Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func factoryFn, string contentType, IDictionary responseHeaders = null)
- where T : class
- {
- return ResultFactory.GetCachedResult(Request, cacheKey, lastDateModified, cacheDuration, factoryFn, contentType, responseHeaders);
+ return session;
}
///
@@ -121,7 +107,7 @@ namespace MediaBrowser.Api
return ResultFactory.GetStaticFileResult(Request, path);
}
- private readonly char[] _dashReplaceChars = new[] { '?', '/' };
+ private readonly char[] _dashReplaceChars = { '?', '/' };
private const char SlugChar = '-';
protected MusicArtist GetArtist(string name, ILibraryManager libraryManager)
@@ -154,7 +140,7 @@ namespace MediaBrowser.Api
return libraryManager.GetPerson(DeSlugPersonName(name, libraryManager));
}
- protected IList GetAllLibraryItems(Guid? userId, IUserManager userManager, ILibraryManager libraryManager, string parentId = null)
+ protected IEnumerable GetAllLibraryItems(Guid? userId, IUserManager userManager, ILibraryManager libraryManager, string parentId = null)
{
if (!string.IsNullOrEmpty(parentId))
{
@@ -164,7 +150,12 @@ namespace MediaBrowser.Api
{
var user = userManager.GetUserById(userId.Value);
- return folder.GetRecursiveChildren(user).ToList();
+ if (user == null)
+ {
+ throw new ArgumentException("User not found");
+ }
+
+ return folder.GetRecursiveChildren(user);
}
return folder.GetRecursiveChildren();
@@ -173,7 +164,12 @@ namespace MediaBrowser.Api
{
var user = userManager.GetUserById(userId.Value);
- return userManager.GetUserById(userId.Value).RootFolder.GetRecursiveChildren(user, null);
+ if (user == null)
+ {
+ throw new ArgumentException("User not found");
+ }
+
+ return userManager.GetUserById(userId.Value).RootFolder.GetRecursiveChildren(user);
}
return libraryManager.RootFolder.GetRecursiveChildren();
@@ -234,7 +230,8 @@ namespace MediaBrowser.Api
return name;
}
- return libraryManager.RootFolder.GetRecursiveChildren(i => i is Game)
+ return libraryManager.RootFolder.GetRecursiveChildren()
+ .OfType()
.SelectMany(i => i.Genres)
.Distinct(StringComparer.OrdinalIgnoreCase)
.FirstOrDefault(i =>
diff --git a/MediaBrowser.Api/BrandingService.cs b/MediaBrowser.Api/BrandingService.cs
new file mode 100644
index 0000000000..4b49b411a8
--- /dev/null
+++ b/MediaBrowser.Api/BrandingService.cs
@@ -0,0 +1,28 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Branding;
+using ServiceStack;
+
+namespace MediaBrowser.Api
+{
+ [Route("/Branding/Configuration", "GET", Summary = "Gets branding configuration")]
+ public class GetBrandingOptions : IReturn
+ {
+ }
+
+ public class BrandingService : BaseApiService
+ {
+ private readonly IConfigurationManager _config;
+
+ public BrandingService(IConfigurationManager config)
+ {
+ _config = config;
+ }
+
+ public object Get(GetBrandingOptions request)
+ {
+ var result = _config.GetConfiguration("branding");
+
+ return ToOptimizedResult(result);
+ }
+ }
+}
diff --git a/MediaBrowser.Api/ChannelService.cs b/MediaBrowser.Api/ChannelService.cs
index d71db929fe..2dfa0918d6 100644
--- a/MediaBrowser.Api/ChannelService.cs
+++ b/MediaBrowser.Api/ChannelService.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -8,6 +9,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
+using System.Threading.Tasks;
namespace MediaBrowser.Api
{
@@ -172,7 +174,8 @@ namespace MediaBrowser.Api
[ApiMember(Name = "UserId", Description = "Optional attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string UserId { get; set; }
}
-
+
+ [Authenticated]
public class ChannelService : BaseApiService
{
private readonly IChannelManager _channelManager;
@@ -196,14 +199,14 @@ namespace MediaBrowser.Api
return ToOptimizedResult(result);
}
- public object Get(GetChannelFolder request)
+ public async Task
[Route("/System/Configuration", "GET", Summary = "Gets application configuration")]
+ [Authenticated]
public class GetConfiguration : IReturn
{
}
+ [Route("/System/Configuration/{Key}", "GET", Summary = "Gets a named configuration")]
+ [Authenticated]
+ public class GetNamedConfiguration
+ {
+ [ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Key { get; set; }
+ }
+
///
/// Class UpdateConfiguration
///
[Route("/System/Configuration", "POST", Summary = "Updates application configuration")]
+ [Authenticated]
public class UpdateConfiguration : ServerConfiguration, IReturnVoid
{
}
+ [Route("/System/Configuration/{Key}", "POST", Summary = "Updates named configuration")]
+ [Authenticated]
+ public class UpdateNamedConfiguration : IReturnVoid, IRequiresRequestStream
+ {
+ [ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Key { get; set; }
+
+ public Stream RequestStream { get; set; }
+ }
+
[Route("/System/Configuration/MetadataOptions/Default", "GET", Summary = "Gets a default MetadataOptions object")]
+ [Authenticated]
public class GetDefaultMetadataOptions : IReturn
{
}
[Route("/System/Configuration/MetadataPlugins", "GET", Summary = "Gets all available metadata plugins")]
+ [Authenticated]
public class GetMetadataPlugins : IReturn>
{
}
- [Route("/System/Configuration/VideoImageExtraction", "POST", Summary = "Updates image extraction for all types")]
- public class UpdateVideoImageExtraction : IReturnVoid
+ [Route("/System/Configuration/MetadataPlugins/Autoset", "POST")]
+ [Authenticated]
+ public class AutoSetMetadataOptions : IReturnVoid
{
- public bool Enabled { get; set; }
+
}
public class ConfigurationService : BaseApiService
@@ -63,13 +88,15 @@ namespace MediaBrowser.Api
private readonly IFileSystem _fileSystem;
private readonly IProviderManager _providerManager;
+ private readonly ILibraryManager _libraryManager;
- public ConfigurationService(IJsonSerializer jsonSerializer, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IProviderManager providerManager)
+ public ConfigurationService(IJsonSerializer jsonSerializer, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IProviderManager providerManager, ILibraryManager libraryManager)
{
_jsonSerializer = jsonSerializer;
_configurationManager = configurationManager;
_fileSystem = fileSystem;
_providerManager = providerManager;
+ _libraryManager = libraryManager;
}
///
@@ -88,6 +115,60 @@ namespace MediaBrowser.Api
return ToOptimizedResultUsingCache(cacheKey, dateModified, null, () => _configurationManager.Configuration);
}
+ public object Get(GetNamedConfiguration request)
+ {
+ var result = _configurationManager.GetConfiguration(request.Key);
+
+ return ToOptimizedResult(result);
+ }
+
+ const string XbmcMetadata = "Xbmc Nfo";
+ const string MediaBrowserMetadata = "Media Browser Xml";
+
+ public void Post(AutoSetMetadataOptions request)
+ {
+ var service = AutoDetectMetadataService();
+
+ Logger.Info("Setting preferred metadata format to " + service);
+
+ var serviceToDisable = string.Equals(service, XbmcMetadata) ?
+ MediaBrowserMetadata :
+ XbmcMetadata;
+
+ _configurationManager.DisableMetadataService(serviceToDisable);
+ _configurationManager.SaveConfiguration();
+ }
+
+ private string AutoDetectMetadataService()
+ {
+ try
+ {
+ var paths = _libraryManager.GetDefaultVirtualFolders()
+ .SelectMany(i => i.Locations)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .Select(i => new DirectoryInfo(i))
+ .ToList();
+
+ if (paths.SelectMany(i => i.EnumerateFiles("*.xml", SearchOption.AllDirectories))
+ .Any())
+ {
+ return XbmcMetadata;
+ }
+
+ if (paths.SelectMany(i => i.EnumerateFiles("*.xml", SearchOption.AllDirectories))
+ .Any(i => string.Equals(i.Name, "series.xml", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "movie.xml", StringComparison.OrdinalIgnoreCase)))
+ {
+ return MediaBrowserMetadata;
+ }
+ }
+ catch (Exception)
+ {
+
+ }
+
+ return XbmcMetadata;
+ }
+
///
/// Posts the specified configuraiton.
///
@@ -95,7 +176,6 @@ namespace MediaBrowser.Api
public void Post(UpdateConfiguration request)
{
// Silly, but we need to serialize and deserialize or the XmlSerializer will write the xml with an element name of UpdateConfiguration
-
var json = _jsonSerializer.SerializeToString(request);
var config = _jsonSerializer.DeserializeFromString(json);
@@ -103,6 +183,17 @@ namespace MediaBrowser.Api
_configurationManager.ReplaceConfiguration(config);
}
+ public void Post(UpdateNamedConfiguration request)
+ {
+ var pathInfo = PathInfo.Parse(Request.PathInfo);
+ var key = pathInfo.GetArgumentValue(2);
+
+ var configurationType = _configurationManager.GetConfigurationType(key);
+ var configuration = _jsonSerializer.DeserializeFromStream(request.RequestStream, configurationType);
+
+ _configurationManager.SaveConfiguration(key, configuration);
+ }
+
public object Get(GetDefaultMetadataOptions request)
{
return ToOptimizedSerializedResultUsingCache(new MetadataOptions());
@@ -112,71 +203,5 @@ namespace MediaBrowser.Api
{
return ToOptimizedSerializedResultUsingCache(_providerManager.GetAllMetadataPlugins().ToList());
}
-
- ///
- /// This is a temporary method used until image settings get broken out.
- ///
- ///
- public void Post(UpdateVideoImageExtraction request)
- {
- var config = _configurationManager.Configuration;
-
- EnableImageExtractionForType(typeof(Movie), config, request.Enabled);
- EnableImageExtractionForType(typeof(Episode), config, request.Enabled);
- EnableImageExtractionForType(typeof(AdultVideo), config, request.Enabled);
- EnableImageExtractionForType(typeof(MusicVideo), config, request.Enabled);
- EnableImageExtractionForType(typeof(Video), config, request.Enabled);
- EnableImageExtractionForType(typeof(Trailer), config, request.Enabled);
-
- _configurationManager.SaveConfiguration();
- }
-
- private void EnableImageExtractionForType(Type type, ServerConfiguration config, bool enabled)
- {
- var options = GetMetadataOptions(type, config);
-
- const string imageProviderName = "Screen Grabber";
-
- var contains = options.DisabledImageFetchers.Contains(imageProviderName, StringComparer.OrdinalIgnoreCase);
-
- if (!enabled && !contains)
- {
- var list = options.DisabledImageFetchers.ToList();
-
- list.Add(imageProviderName);
-
- options.DisabledImageFetchers = list.ToArray();
- }
- else if (enabled && contains)
- {
- var list = options.DisabledImageFetchers.ToList();
-
- list.Remove(imageProviderName);
-
- options.DisabledImageFetchers = list.ToArray();
- }
- }
-
- private MetadataOptions GetMetadataOptions(Type type, ServerConfiguration config)
- {
- var options = config.MetadataOptions
- .FirstOrDefault(i => string.Equals(i.ItemType, type.Name, StringComparison.OrdinalIgnoreCase));
-
- if (options == null)
- {
- var list = config.MetadataOptions.ToList();
-
- options = new MetadataOptions
- {
- ItemType = type.Name
- };
-
- list.Add(options);
-
- config.MetadataOptions = list.ToArray();
- }
-
- return options;
- }
}
}
diff --git a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs
deleted file mode 100644
index 6acecd342d..0000000000
--- a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs
+++ /dev/null
@@ -1,671 +0,0 @@
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Querying;
-using ServiceStack;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace MediaBrowser.Api.DefaultTheme
-{
- [Route("/MBT/DefaultTheme/Games", "GET")]
- public class GetGamesView : IReturn
- {
- [ApiMember(Name = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public Guid UserId { get; set; }
-
- [ApiMember(Name = "RecentlyPlayedGamesLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int RecentlyPlayedGamesLimit { get; set; }
-
- public string ParentId { get; set; }
- }
-
- [Route("/MBT/DefaultTheme/TV", "GET")]
- public class GetTvView : IReturn
- {
- [ApiMember(Name = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public Guid UserId { get; set; }
-
- [ApiMember(Name = "ComedyGenre", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string ComedyGenre { get; set; }
-
- [ApiMember(Name = "RomanceGenre", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string RomanceGenre { get; set; }
-
- [ApiMember(Name = "TopCommunityRating", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public double TopCommunityRating { get; set; }
-
- [ApiMember(Name = "NextUpEpisodeLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int NextUpEpisodeLimit { get; set; }
-
- [ApiMember(Name = "ResumableEpisodeLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int ResumableEpisodeLimit { get; set; }
-
- [ApiMember(Name = "LatestEpisodeLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int LatestEpisodeLimit { get; set; }
-
- public string ParentId { get; set; }
- }
-
- [Route("/MBT/DefaultTheme/Movies", "GET")]
- public class GetMovieView : IReturn
- {
- [ApiMember(Name = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public Guid UserId { get; set; }
-
- [ApiMember(Name = "FamilyGenre", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string FamilyGenre { get; set; }
-
- [ApiMember(Name = "ComedyGenre", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string ComedyGenre { get; set; }
-
- [ApiMember(Name = "RomanceGenre", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string RomanceGenre { get; set; }
-
- [ApiMember(Name = "LatestMoviesLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int LatestMoviesLimit { get; set; }
-
- [ApiMember(Name = "LatestTrailersLimit", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int LatestTrailersLimit { get; set; }
-
- public string ParentId { get; set; }
- }
-
- [Route("/MBT/DefaultTheme/Favorites", "GET")]
- public class GetFavoritesView : IReturn
- {
- [ApiMember(Name = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public Guid UserId { get; set; }
- }
-
- public class DefaultThemeService : BaseApiService
- {
- private readonly IUserManager _userManager;
- private readonly IDtoService _dtoService;
- private readonly ILogger _logger;
- private readonly ILibraryManager _libraryManager;
- private readonly IUserDataManager _userDataManager;
-
- private readonly IImageProcessor _imageProcessor;
- private readonly IItemRepository _itemRepo;
-
- public DefaultThemeService(IUserManager userManager, IDtoService dtoService, ILogger logger, ILibraryManager libraryManager, IImageProcessor imageProcessor, IUserDataManager userDataManager, IItemRepository itemRepo)
- {
- _userManager = userManager;
- _dtoService = dtoService;
- _logger = logger;
- _libraryManager = libraryManager;
- _imageProcessor = imageProcessor;
- _userDataManager = userDataManager;
- _itemRepo = itemRepo;
- }
-
- public object Get(GetFavoritesView request)
- {
- var user = _userManager.GetUserById(request.UserId);
-
- var allItems = user.RootFolder.GetRecursiveChildren(user)
- .ToList();
-
- var allFavoriteItems = allItems.Where(i => _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).IsFavorite)
- .ToList();
-
- var itemsWithImages = allFavoriteItems.Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath))
- .ToList();
-
- var itemsWithBackdrops = allFavoriteItems.Where(i => i.GetImages(ImageType.Backdrop).Any())
- .ToList();
-
- var view = new FavoritesView();
-
- var fields = new List();
-
- view.BackdropItems = FilterItemsForBackdropDisplay(itemsWithBackdrops)
- .Randomize("backdrop")
- .Take(10)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user))
- .ToList();
-
- var spotlightItems = itemsWithBackdrops.Randomize("spotlight")
- .Take(10)
- .ToList();
-
- view.SpotlightItems = spotlightItems
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user))
- .ToList();
-
- fields.Add(ItemFields.PrimaryImageAspectRatio);
-
- view.Albums = itemsWithImages
- .OfType()
- .Randomize()
- .Take(4)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user))
- .ToList();
-
- view.Books = itemsWithImages
- .OfType()
- .Randomize()
- .Take(6)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user))
- .ToList();
-
- view.Episodes = itemsWithImages
- .OfType()
- .Randomize()
- .Take(6)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user))
- .ToList();
-
- view.Games = itemsWithImages
- .OfType()
- .Randomize()
- .Take(6)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user))
- .ToList();
-
- view.Movies = itemsWithImages
- .OfType()
- .Randomize()
- .Take(6)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user))
- .ToList();
-
- view.Series = itemsWithImages
- .OfType()
- .Randomize()
- .Take(6)
- .Select(i => _dtoService.GetBaseItemDto(i, fields, user))
- .ToList();
-
- view.Songs = itemsWithImages
- .OfType