From 2536011247de55c75e8b1f893e23b606e4200159 Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Fri, 10 Aug 2012 09:07:58 -0400 Subject: Added the ability for the server to handle byte-range requests, and also added a static file handler to utilize it --- .../Net/Handlers/StaticFileHandler.cs | 282 +++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs (limited to 'MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs') diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs new file mode 100644 index 0000000000..9c99121529 --- /dev/null +++ b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using MediaBrowser.Common.Logging; + +namespace MediaBrowser.Common.Net.Handlers +{ + public class StaticFileHandler : BaseHandler + { + public string Path + { + get + { + return QueryString["path"]; + } + } + + private bool FileStreamDiscovered = false; + private FileStream _FileStream = null; + private FileStream FileStream + { + get + { + if (!FileStreamDiscovered) + { + try + { + _FileStream = File.OpenRead(Path); + } + catch (FileNotFoundException) + { + StatusCode = 404; + } + catch (DirectoryNotFoundException) + { + StatusCode = 404; + } + catch (UnauthorizedAccessException) + { + StatusCode = 403; + } + finally + { + FileStreamDiscovered = true; + } + } + + return _FileStream; + } + } + + protected override bool SupportsByteRangeRequests + { + get + { + return true; + } + } + + public override bool CompressResponse + { + get + { + string contentType = ContentType; + + // Can't compress these + if (IsRangeRequest) + { + return false; + } + + // Don't compress media + if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // It will take some work to support compression within this handler + return false; + } + } + + protected override long? GetTotalContentLength() + { + try + { + return FileStream.Length; + } + catch + { + return base.GetTotalContentLength(); + } + } + + protected override DateTime? GetLastDateModified() + { + try + { + return File.GetLastWriteTime(Path); + } + catch + { + return base.GetLastDateModified(); + } + } + + protected override bool IsAsyncHandler + { + get + { + return true; + } + } + + public override string ContentType + { + get + { + return MimeTypes.GetMimeType(Path); + } + } + + protected async override void WriteResponseToOutputStream(Stream stream) + { + try + { + if (FileStream != null) + { + if (IsRangeRequest) + { + KeyValuePair requestedRange = RequestedRanges.First(); + + // If the requested range is "0-" and we know the total length, we can optimize by avoiding having to buffer the content into memory + if (requestedRange.Value == null && TotalContentLength != null) + { + await ServeCompleteRangeRequest(requestedRange, stream); + } + else if (TotalContentLength.HasValue) + { + // This will have to buffer a portion of the content into memory + await ServePartialRangeRequestWithKnownTotalContentLength(requestedRange, stream); + } + else + { + // This will have to buffer the entire content into memory + await ServePartialRangeRequestWithUnknownTotalContentLength(requestedRange, stream); + } + } + else + { + await FileStream.CopyToAsync(stream); + } + } + } + catch (Exception ex) + { + Logger.LogException("WriteResponseToOutputStream", ex); + } + finally + { + if (FileStream != null) + { + FileStream.Dispose(); + } + + DisposeResponseStream(); + } + } + + /// + /// Handles a range request of "bytes=0-" + /// This will serve the complete content and add the content-range header + /// + private async Task ServeCompleteRangeRequest(KeyValuePair requestedRange, Stream responseStream) + { + long totalContentLength = TotalContentLength.Value; + + long rangeStart = requestedRange.Key; + long rangeEnd = totalContentLength - 1; + long rangeLength = 1 + rangeEnd - rangeStart; + + // Content-Length is the length of what we're serving, not the original content + HttpListenerContext.Response.ContentLength64 = rangeLength; + HttpListenerContext.Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength); + + if (rangeStart > 0) + { + FileStream.Position = rangeStart; + } + + await FileStream.CopyToAsync(responseStream); + } + + /// + /// Serves a partial range request where the total content length is not known + /// + private async Task ServePartialRangeRequestWithUnknownTotalContentLength(KeyValuePair requestedRange, Stream responseStream) + { + // Read the entire stream so that we can determine the length + byte[] bytes = await ReadBytes(FileStream, 0, null); + + long totalContentLength = bytes.LongLength; + + long rangeStart = requestedRange.Key; + long rangeEnd = requestedRange.Value ?? (totalContentLength - 1); + long rangeLength = 1 + rangeEnd - rangeStart; + + // Content-Length is the length of what we're serving, not the original content + HttpListenerContext.Response.ContentLength64 = rangeLength; + HttpListenerContext.Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength); + + await responseStream.WriteAsync(bytes, Convert.ToInt32(rangeStart), Convert.ToInt32(rangeLength)); + } + + /// + /// Serves a partial range request where the total content length is already known + /// + private async Task ServePartialRangeRequestWithKnownTotalContentLength(KeyValuePair requestedRange, Stream responseStream) + { + long totalContentLength = TotalContentLength.Value; + long rangeStart = requestedRange.Key; + long rangeEnd = requestedRange.Value ?? (totalContentLength - 1); + long rangeLength = 1 + rangeEnd - rangeStart; + + // Only read the bytes we need + byte[] bytes = await ReadBytes(FileStream, Convert.ToInt32(rangeStart), Convert.ToInt32(rangeLength)); + + // Content-Length is the length of what we're serving, not the original content + HttpListenerContext.Response.ContentLength64 = rangeLength; + + HttpListenerContext.Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength); + + await responseStream.WriteAsync(bytes, 0, Convert.ToInt32(rangeLength)); + } + + /// + /// Reads bytes from a stream + /// + /// The input stream + /// The starting position + /// The number of bytes to read, or null to read to the end. + private async Task ReadBytes(Stream input, int start, int? count) + { + if (start > 0) + { + input.Position = start; + } + + if (count == null) + { + byte[] buffer = new byte[16 * 1024]; + + using (MemoryStream ms = new MemoryStream()) + { + int read; + while ((read = await input.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + await ms.WriteAsync(buffer, 0, read); + } + return ms.ToArray(); + } + } + else + { + byte[] buffer = new byte[count.Value]; + + using (MemoryStream ms = new MemoryStream()) + { + int read = await input.ReadAsync(buffer, 0, buffer.Length); + + await ms.WriteAsync(buffer, 0, read); + + return ms.ToArray(); + } + } + + } + } +} -- cgit v1.2.3 From fbf3916bcec3ff6ba9e34d9756f0583ac90ea0ab Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Fri, 10 Aug 2012 09:18:30 -0400 Subject: Added an audio handler --- MediaBrowser.Api/HttpHandlers/AudioHandler.cs | 45 ++++++++++++++++++++++ MediaBrowser.Api/MediaBrowser.Api.csproj | 1 + MediaBrowser.Api/Plugin.cs | 6 ++- .../Net/Handlers/StaticFileHandler.cs | 2 +- 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 MediaBrowser.Api/HttpHandlers/AudioHandler.cs (limited to 'MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs') diff --git a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs new file mode 100644 index 0000000000..8ebaf04bcd --- /dev/null +++ b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs @@ -0,0 +1,45 @@ +using System; +using MediaBrowser.Common.Net.Handlers; +using MediaBrowser.Controller; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.Api.HttpHandlers +{ + public class AudioHandler : StaticFileHandler + { + private BaseItem _LibraryItem; + /// + /// Gets the library item that will be played, if any + /// + private BaseItem LibraryItem + { + get + { + if (_LibraryItem == null) + { + string id = QueryString["id"]; + + if (!string.IsNullOrEmpty(id)) + { + _LibraryItem = Kernel.Instance.GetItemById(Guid.Parse(id)); + } + } + + return _LibraryItem; + } + } + + public override string Path + { + get + { + if (LibraryItem != null) + { + return LibraryItem.Path; + } + + return base.Path; + } + } + } +} diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 4560f70a15..33c209cd43 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -47,6 +47,7 @@ + diff --git a/MediaBrowser.Api/Plugin.cs b/MediaBrowser.Api/Plugin.cs index fe061a48b0..02546c6936 100644 --- a/MediaBrowser.Api/Plugin.cs +++ b/MediaBrowser.Api/Plugin.cs @@ -44,7 +44,7 @@ namespace MediaBrowser.Api else if (localPath.EndsWith("/api/image", StringComparison.OrdinalIgnoreCase)) { return new ImageHandler(); - } + } else if (localPath.EndsWith("/api/users", StringComparison.OrdinalIgnoreCase)) { return new UsersHandler(); @@ -89,6 +89,10 @@ namespace MediaBrowser.Api { return new StaticFileHandler(); } + else if (localPath.EndsWith("/api/audio", StringComparison.OrdinalIgnoreCase)) + { + return new AudioHandler(); + } return null; } diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs index 9c99121529..9bffd8e597 100644 --- a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Common.Net.Handlers { public class StaticFileHandler : BaseHandler { - public string Path + public virtual string Path { get { -- cgit v1.2.3 From 692d9dc3311e928b678a87072d96fe8ab064b02a Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Fri, 10 Aug 2012 23:06:08 -0400 Subject: Allow StaticFileHandler Path to be changed --- MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs') diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs index 9bffd8e597..35d38fb4a7 100644 --- a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs @@ -10,12 +10,22 @@ namespace MediaBrowser.Common.Net.Handlers { public class StaticFileHandler : BaseHandler { + private string _Path; public virtual string Path { get { + if (!string.IsNullOrWhiteSpace(_Path)) + { + return _Path; + } + return QueryString["path"]; } + set + { + _Path = value; + } } private bool FileStreamDiscovered = false; -- cgit v1.2.3 From 24d2c441b3d265026ee77297ea4b7a3ffb47918b Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Sat, 11 Aug 2012 14:07:07 -0400 Subject: Re-worked async actions in BaseHandler, and changed AudioBitRate to AudioBitRates. --- MediaBrowser.Api/HttpHandlers/AudioHandler.cs | 244 ++++++++++----------- MediaBrowser.Api/HttpHandlers/ImageHandler.cs | 8 +- MediaBrowser.Api/HttpHandlers/JsonHandler.cs | 8 +- MediaBrowser.Api/HttpHandlers/VideoHandler.cs | 62 ++++++ MediaBrowser.Api/MediaBrowser.Api.csproj | 4 + MediaBrowser.Api/Plugin.cs | 4 + MediaBrowser.Api/ffmpeg/readme.txt | 3 + .../Net/Handlers/BaseEmbeddedResourceHandler.cs | 5 +- MediaBrowser.Common/Net/Handlers/BaseHandler.cs | 37 ++-- .../Net/Handlers/StaticFileHandler.cs | 12 +- 10 files changed, 224 insertions(+), 163 deletions(-) create mode 100644 MediaBrowser.Api/HttpHandlers/VideoHandler.cs create mode 100644 MediaBrowser.Api/ffmpeg/readme.txt (limited to 'MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs') diff --git a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs index a4afe1a1db..61f6e7fbc7 100644 --- a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Net; +using System.Threading.Tasks; using MediaBrowser.Common.Logging; using MediaBrowser.Common.Net; using MediaBrowser.Common.Net.Handlers; @@ -12,54 +13,8 @@ using MediaBrowser.Model.Entities; namespace MediaBrowser.Api.HttpHandlers { - public class AudioHandler : BaseHandler + public class AudioHandler : BaseMediaHandler - + diff --git a/MediaBrowser.Common/Configuration/ApplicationPaths.cs b/MediaBrowser.Common/Configuration/ApplicationPaths.cs index dc87749cfb..efe6f0c9e0 100644 --- a/MediaBrowser.Common/Configuration/ApplicationPaths.cs +++ b/MediaBrowser.Common/Configuration/ApplicationPaths.cs @@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Configuration; using System.IO; -using System.ComponentModel.Composition; -using System.ComponentModel.Composition.Hosting; -using System.Configuration; using System.Reflection; namespace MediaBrowser.Common.Configuration diff --git a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs index 89803d8d74..f9ef065ecc 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs @@ -185,7 +185,7 @@ namespace MediaBrowser.Common.Net.Handlers } } - public virtual void ProcessRequest(HttpListenerContext ctx) + public virtual async Task ProcessRequest(HttpListenerContext ctx) { HttpListenerContext = ctx; @@ -196,46 +196,61 @@ namespace MediaBrowser.Common.Net.Handlers ctx.Response.KeepAlive = true; - if (SupportsByteRangeRequests && IsRangeRequest) + try { - ctx.Response.Headers["Accept-Ranges"] = "bytes"; - } - - // Set the initial status code - // When serving a range request, we need to return status code 206 to indicate a partial response body - StatusCode = SupportsByteRangeRequests && IsRangeRequest ? 206 : 200; + if (SupportsByteRangeRequests && IsRangeRequest) + { + ctx.Response.Headers["Accept-Ranges"] = "bytes"; + } - ctx.Response.ContentType = ContentType; + // Set the initial status code + // When serving a range request, we need to return status code 206 to indicate a partial response body + StatusCode = SupportsByteRangeRequests && IsRangeRequest ? 206 : 200; - TimeSpan cacheDuration = CacheDuration; + ctx.Response.ContentType = ContentType; - if (ctx.Request.Headers.AllKeys.Contains("If-Modified-Since")) - { - DateTime ifModifiedSince; + TimeSpan cacheDuration = CacheDuration; - if (DateTime.TryParse(ctx.Request.Headers["If-Modified-Since"].Replace(" GMT", string.Empty), out ifModifiedSince)) + if (ctx.Request.Headers.AllKeys.Contains("If-Modified-Since")) { - // If the cache hasn't expired yet just return a 304 - if (IsCacheValid(ifModifiedSince, cacheDuration, LastDateModified)) + DateTime ifModifiedSince; + + if (DateTime.TryParse(ctx.Request.Headers["If-Modified-Since"].Replace(" GMT", string.Empty), out ifModifiedSince)) { - StatusCode = 304; + // If the cache hasn't expired yet just return a 304 + if (IsCacheValid(ifModifiedSince, cacheDuration, LastDateModified)) + { + StatusCode = 304; + } } } - } - if (StatusCode == 200 || StatusCode == 206) + PrepareResponse(); + + if (IsResponseValid) + { + await ProcessUncachedRequest(ctx, cacheDuration); + } + else + { + ctx.Response.StatusCode = StatusCode; + ctx.Response.SendChunked = false; + } + } + catch (Exception ex) { - ProcessUncachedResponse(ctx, cacheDuration); + // It might be too late if some response data has already been transmitted, but try to set this + ctx.Response.StatusCode = 500; + + Logger.LogException(ex); } - else + finally { - ctx.Response.StatusCode = StatusCode; - ctx.Response.SendChunked = false; DisposeResponseStream(); } } - private async void ProcessUncachedResponse(HttpListenerContext ctx, TimeSpan cacheDuration) + private async Task ProcessUncachedRequest(HttpListenerContext ctx, TimeSpan cacheDuration) { long? totalContentLength = TotalContentLength; @@ -269,7 +284,7 @@ namespace MediaBrowser.Common.Net.Handlers // Set the status code ctx.Response.StatusCode = StatusCode; - if (StatusCode == 200 || StatusCode == 206) + if (IsResponseValid) { // Finally, write the response data Stream outputStream = ctx.Response.OutputStream; @@ -288,23 +303,11 @@ namespace MediaBrowser.Common.Net.Handlers outputStream = CompressedStream; } - try - { - await WriteResponseToOutputStream(outputStream); - } - catch (Exception ex) - { - Logger.LogException(ex); - } - finally - { - DisposeResponseStream(); - } + await WriteResponseToOutputStream(outputStream); } else { ctx.Response.SendChunked = false; - DisposeResponseStream(); } } @@ -317,9 +320,16 @@ namespace MediaBrowser.Common.Net.Handlers response.Headers[HttpResponseHeader.LastModified] = lastModified.ToString("r"); } + /// + /// Gives subclasses a chance to do and prep work, and also to validate data and set an error status code, if needed + /// + protected virtual void PrepareResponse() + { + } + protected abstract Task WriteResponseToOutputStream(Stream stream); - private void DisposeResponseStream() + protected virtual void DisposeResponseStream() { if (CompressedStream != null) { @@ -366,5 +376,13 @@ namespace MediaBrowser.Common.Net.Handlers { return null; } + + private bool IsResponseValid + { + get + { + return StatusCode == 200 || StatusCode == 206; + } + } } } \ No newline at end of file diff --git a/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs index 30113198b9..03de398c90 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs @@ -1,11 +1,58 @@ - +using System.IO; +using System.Threading.Tasks; +using MediaBrowser.Common.Serialization; + namespace MediaBrowser.Common.Net.Handlers { public abstract class BaseJsonHandler : BaseHandler { public override string ContentType { - get { return "application/json"; } + get { return MimeTypes.JsonMimeType; } + } + + private bool _ObjectToSerializeEnsured = false; + private object _ObjectToSerialize; + + private void EnsureObjectToSerialize() + { + if (!_ObjectToSerializeEnsured) + { + _ObjectToSerialize = GetObjectToSerialize(); + + if (_ObjectToSerialize == null) + { + StatusCode = 404; + } + + _ObjectToSerializeEnsured = true; + } + } + + private object ObjectToSerialize + { + get + { + EnsureObjectToSerialize(); + return _ObjectToSerialize; + } + } + + protected abstract object GetObjectToSerialize(); + + protected override void PrepareResponse() + { + base.PrepareResponse(); + + EnsureObjectToSerialize(); + } + + protected override Task WriteResponseToOutputStream(Stream stream) + { + return Task.Run(() => + { + JsonSerializer.SerializeToStream(ObjectToSerialize, stream); + }); } } } diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs index 3eb908938f..5656f92739 100644 --- a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs @@ -28,37 +28,44 @@ namespace MediaBrowser.Common.Net.Handlers } } - private bool FileStreamDiscovered = false; - private FileStream _FileStream = null; - private FileStream FileStream + private bool _SourceStreamEnsured = false; + private Stream _SourceStream = null; + private Stream SourceStream { get { - if (!FileStreamDiscovered) + EnsureSourceStream(); + return _SourceStream; + } + } + + private void EnsureSourceStream() + { + if (!_SourceStreamEnsured) + { + try { - try - { - _FileStream = File.OpenRead(Path); - } - catch (FileNotFoundException) - { - StatusCode = 404; - } - catch (DirectoryNotFoundException) - { - StatusCode = 404; - } - catch (UnauthorizedAccessException) - { - StatusCode = 403; - } - finally - { - FileStreamDiscovered = true; - } + _SourceStream = File.OpenRead(Path); + } + catch (FileNotFoundException ex) + { + StatusCode = 404; + Logger.LogException(ex); + } + catch (DirectoryNotFoundException ex) + { + StatusCode = 404; + Logger.LogException(ex); + } + catch (UnauthorizedAccessException ex) + { + StatusCode = 403; + Logger.LogException(ex); + } + finally + { + _SourceStreamEnsured = true; } - - return _FileStream; } } @@ -74,14 +81,14 @@ namespace MediaBrowser.Common.Net.Handlers { get { - string contentType = ContentType; - // Can't compress these if (IsRangeRequest) { return false; } + string contentType = ContentType; + // Don't compress media if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) { @@ -95,26 +102,19 @@ namespace MediaBrowser.Common.Net.Handlers protected override long? GetTotalContentLength() { - try - { - return FileStream.Length; - } - catch - { - return base.GetTotalContentLength(); - } + return SourceStream.Length; } protected override DateTime? GetLastDateModified() { - try - { - return File.GetLastWriteTime(Path); - } - catch + EnsureSourceStream(); + + if (SourceStream == null) { - return base.GetLastDateModified(); + return null; } + + return File.GetLastWriteTime(Path); } public override string ContentType @@ -125,48 +125,48 @@ namespace MediaBrowser.Common.Net.Handlers } } + protected override void PrepareResponse() + { + base.PrepareResponse(); + + EnsureSourceStream(); + } + protected async override Task WriteResponseToOutputStream(Stream stream) { - try + if (IsRangeRequest) { - if (FileStream != null) + KeyValuePair requestedRange = RequestedRanges.First(); + + // If the requested range is "0-" and we know the total length, we can optimize by avoiding having to buffer the content into memory + if (requestedRange.Value == null && TotalContentLength != null) { - if (IsRangeRequest) - { - KeyValuePair requestedRange = RequestedRanges.First(); - - // If the requested range is "0-" and we know the total length, we can optimize by avoiding having to buffer the content into memory - if (requestedRange.Value == null && TotalContentLength != null) - { - await ServeCompleteRangeRequest(requestedRange, stream); - } - else if (TotalContentLength.HasValue) - { - // This will have to buffer a portion of the content into memory - await ServePartialRangeRequestWithKnownTotalContentLength(requestedRange, stream); - } - else - { - // This will have to buffer the entire content into memory - await ServePartialRangeRequestWithUnknownTotalContentLength(requestedRange, stream); - } - } - else - { - await FileStream.CopyToAsync(stream); - } + await ServeCompleteRangeRequest(requestedRange, stream); + } + else if (TotalContentLength.HasValue) + { + // This will have to buffer a portion of the content into memory + await ServePartialRangeRequestWithKnownTotalContentLength(requestedRange, stream); + } + else + { + // This will have to buffer the entire content into memory + await ServePartialRangeRequestWithUnknownTotalContentLength(requestedRange, stream); } } - catch (Exception ex) + else { - Logger.LogException("WriteResponseToOutputStream", ex); + await SourceStream.CopyToAsync(stream); } - finally + } + + protected override void DisposeResponseStream() + { + base.DisposeResponseStream(); + + if (SourceStream != null) { - if (FileStream != null) - { - FileStream.Dispose(); - } + SourceStream.Dispose(); } } @@ -188,10 +188,10 @@ namespace MediaBrowser.Common.Net.Handlers if (rangeStart > 0) { - FileStream.Position = rangeStart; + SourceStream.Position = rangeStart; } - await FileStream.CopyToAsync(responseStream); + await SourceStream.CopyToAsync(responseStream); } /// @@ -200,7 +200,7 @@ namespace MediaBrowser.Common.Net.Handlers private async Task ServePartialRangeRequestWithUnknownTotalContentLength(KeyValuePair requestedRange, Stream responseStream) { // Read the entire stream so that we can determine the length - byte[] bytes = await ReadBytes(FileStream, 0, null); + byte[] bytes = await ReadBytes(SourceStream, 0, null); long totalContentLength = bytes.LongLength; @@ -226,7 +226,7 @@ namespace MediaBrowser.Common.Net.Handlers long rangeLength = 1 + rangeEnd - rangeStart; // Only read the bytes we need - byte[] bytes = await ReadBytes(FileStream, Convert.ToInt32(rangeStart), Convert.ToInt32(rangeLength)); + byte[] bytes = await ReadBytes(SourceStream, Convert.ToInt32(rangeStart), Convert.ToInt32(rangeLength)); // Content-Length is the length of what we're serving, not the original content HttpListenerContext.Response.ContentLength64 = rangeLength; diff --git a/MediaBrowser.Common/Net/MimeTypes.cs b/MediaBrowser.Common/Net/MimeTypes.cs index a49cbaa98c..41df463f71 100644 --- a/MediaBrowser.Common/Net/MimeTypes.cs +++ b/MediaBrowser.Common/Net/MimeTypes.cs @@ -5,6 +5,8 @@ namespace MediaBrowser.Common.Net { public static class MimeTypes { + public static string JsonMimeType = "application/json"; + public static string GetMimeType(string path) { string ext = Path.GetExtension(path); diff --git a/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs b/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs index de9a94b034..38b8584fc0 100644 --- a/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Controller.Xml /// /// Provides a base class for parsing metadata xml /// - public abstract class BaseItemXmlParser + public class BaseItemXmlParser where T : BaseItem, new() { /// @@ -215,6 +215,32 @@ namespace MediaBrowser.Controller.Xml break; } + case "TMDbId": + string tmdb = reader.ReadString(); + if (!string.IsNullOrWhiteSpace(tmdb)) + { + item.SetProviderId(MetadataProviders.Tmdb, tmdb); + } + break; + + case "TVcomId": + string TVcomId = reader.ReadString(); + if (!string.IsNullOrWhiteSpace(TVcomId)) + { + item.SetProviderId(MetadataProviders.Tvcom, TVcomId); + } + break; + + case "IMDB_ID": + case "IMDB": + case "IMDbId": + string IMDbId = reader.ReadString(); + if (!string.IsNullOrWhiteSpace(IMDbId)) + { + item.SetProviderId(MetadataProviders.Imdb, IMDbId); + } + break; + case "Genres": FetchFromGenresNode(reader.ReadSubtree(), item); break; diff --git a/MediaBrowser.Model/Entities/ApiBaseItem.cs b/MediaBrowser.Model/Entities/ApiBaseItem.cs index e6bd716547..e40fdc25f8 100644 --- a/MediaBrowser.Model/Entities/ApiBaseItem.cs +++ b/MediaBrowser.Model/Entities/ApiBaseItem.cs @@ -11,14 +11,9 @@ namespace MediaBrowser.Model.Entities public class ApiBaseItem : BaseItem { // TV Series - public string TvdbId { get; set; } public string Status { get; set; } public IEnumerable AirDays { get; set; } public string AirTime { get; set; } - - // Movie - public string TmdbId { get; set; } - public string ImdbId { get; set; } } /// @@ -49,6 +44,8 @@ namespace MediaBrowser.Model.Entities return Type.Equals(type, StringComparison.OrdinalIgnoreCase); } + public IEnumerable People { get; set; } + /// /// If the item does not have a logo, this will hold the Id of the Parent that has one. /// diff --git a/MediaBrowser.Model/Entities/BaseItem.cs b/MediaBrowser.Model/Entities/BaseItem.cs index c6de496bdd..322bac564c 100644 --- a/MediaBrowser.Model/Entities/BaseItem.cs +++ b/MediaBrowser.Model/Entities/BaseItem.cs @@ -33,6 +33,7 @@ namespace MediaBrowser.Model.Entities public string Overview { get; set; } public string Tagline { get; set; } + [IgnoreDataMember] public IEnumerable People { get; set; } public IEnumerable Studios { get; set; } @@ -56,5 +57,49 @@ namespace MediaBrowser.Model.Entities public IEnumerable public class GenreHandler : BaseJsonHandler> { - protected override IBNItem GetObjectToSerialize() + protected override async Task> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); @@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers string name = QueryString["name"]; - return GetGenre(parent, user, name); + return await GetGenre(parent, user, name); } /// /// Gets a Genre /// - private IBNItem GetGenre(Folder parent, User user, string name) + private async Task> GetGenre(Folder parent, User user, string name) { int count = 0; @@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers // Get the original entity so that we can also supply the PrimaryImagePath return new IBNItem() { - Item = Kernel.Instance.ItemController.GetGenre(name), + Item = await Kernel.Instance.ItemController.GetGenre(name), BaseItemCount = count }; } diff --git a/MediaBrowser.Api/HttpHandlers/GenresHandler.cs b/MediaBrowser.Api/HttpHandlers/GenresHandler.cs index 1134eb5689..cd68f1eaa9 100644 --- a/MediaBrowser.Api/HttpHandlers/GenresHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/GenresHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.DTO; @@ -10,20 +11,20 @@ namespace MediaBrowser.Api.HttpHandlers { public class GenresHandler : BaseJsonHandler>> { - protected override IEnumerable> GetObjectToSerialize() + protected override async Task>> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); User user = Kernel.Instance.Users.First(u => u.Id == userId); - return GetAllGenres(parent, user); + return await GetAllGenres(parent, user); } /// /// Gets all genres from all recursive children of a folder /// The CategoryInfo class is used to keep track of the number of times each genres appears /// - private IEnumerable> GetAllGenres(Folder parent, User user) + private async Task>> GetAllGenres(Folder parent, User user) { Dictionary data = new Dictionary(); @@ -52,25 +53,9 @@ namespace MediaBrowser.Api.HttpHandlers } } - // Now go through the dictionary and create a Category for each genre - List> list = new List>(); + IEnumerable entities = await Task.WhenAll(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetGenre(key); })); - foreach (string key in data.Keys) - { - // Get the original entity so that we can also supply the PrimaryImagePath - Genre entity = Kernel.Instance.ItemController.GetGenre(key); - - if (entity != null) - { - list.Add(new IBNItem() - { - Item = entity, - BaseItemCount = data[key] - }); - } - } - - return list; + return entities.Select(e => new IBNItem() { Item = e, BaseItemCount = data[e.Name] }); } } } diff --git a/MediaBrowser.Api/HttpHandlers/ImageHandler.cs b/MediaBrowser.Api/HttpHandlers/ImageHandler.cs index 8264380980..4a6b2a4817 100644 --- a/MediaBrowser.Api/HttpHandlers/ImageHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/ImageHandler.cs @@ -13,39 +13,57 @@ namespace MediaBrowser.Api.HttpHandlers public class ImageHandler : BaseHandler { private string _ImagePath = null; - private string ImagePath + private async Task GetImagePath() { - get + if (_ImagePath == null) { - if (_ImagePath == null) - { - _ImagePath = GetImagePath(); - } - - return _ImagePath; + _ImagePath = await DiscoverImagePath(); } + + return _ImagePath; } - private Stream _SourceStream = null; - private Stream SourceStream + private async Task DiscoverImagePath() { - get + string path = QueryString["path"] ?? string.Empty; + + if (!string.IsNullOrEmpty(path)) { - EnsureSourceStream(); + return path; + } - return _SourceStream; + string personName = QueryString["personname"]; + + if (!string.IsNullOrEmpty(personName)) + { + Person person = await Kernel.Instance.ItemController.GetPerson(personName); + + return person.PrimaryImagePath; } + + BaseItem item = ApiService.GetItemById(QueryString["id"]); + + string imageIndex = QueryString["index"]; + int index = string.IsNullOrEmpty(imageIndex) ? 0 : int.Parse(imageIndex); + + return GetImagePathFromTypes(item, ImageType, index); } + private Stream _SourceStream = null; + private async Task GetSourceStream() + { + await EnsureSourceStream(); + return _SourceStream; + } private bool _SourceStreamEnsured = false; - private void EnsureSourceStream() + private async Task EnsureSourceStream() { if (!_SourceStreamEnsured) { try { - _SourceStream = File.OpenRead(ImagePath); + _SourceStream = File.OpenRead(await GetImagePath()); } catch (FileNotFoundException ex) { @@ -68,20 +86,17 @@ namespace MediaBrowser.Api.HttpHandlers } } } - - public override string ContentType + + public async override Task GetContentType() { - get - { - EnsureSourceStream(); + await EnsureSourceStream(); - if (SourceStream == null) - { - return null; - } - - return MimeTypes.GetMimeType(ImagePath); + if (await GetSourceStream() == null) + { + return null; } + + return MimeTypes.GetMimeType(await GetImagePath()); } public override TimeSpan CacheDuration @@ -92,16 +107,16 @@ namespace MediaBrowser.Api.HttpHandlers } } - protected override DateTime? GetLastDateModified() + protected async override Task GetLastDateModified() { - EnsureSourceStream(); + await EnsureSourceStream(); - if (SourceStream == null) + if (await GetSourceStream() == null) { return null; } - return File.GetLastWriteTime(ImagePath); + return File.GetLastWriteTime(await GetImagePath()); } private int? Height @@ -194,36 +209,9 @@ namespace MediaBrowser.Api.HttpHandlers } } - protected override Task WriteResponseToOutputStream(Stream stream) + protected override async Task WriteResponseToOutputStream(Stream stream) { - return Task.Run(() => - { - ImageProcessor.ProcessImage(SourceStream, stream, Width, Height, MaxWidth, MaxHeight, Quality); - }); - } - - private string GetImagePath() - { - string path = QueryString["path"] ?? string.Empty; - - if (!string.IsNullOrEmpty(path)) - { - return path; - } - - string personName = QueryString["personname"]; - - if (!string.IsNullOrEmpty(personName)) - { - return Kernel.Instance.ItemController.GetPerson(personName).PrimaryImagePath; - } - - BaseItem item = ApiService.GetItemById(QueryString["id"]); - - string imageIndex = QueryString["index"]; - int index = string.IsNullOrEmpty(imageIndex) ? 0 : int.Parse(imageIndex); - - return GetImagePathFromTypes(item, ImageType, index); + ImageProcessor.ProcessImage(await GetSourceStream(), stream, Width, Height, MaxWidth, MaxHeight, Quality); } private string GetImagePathFromTypes(BaseItem item, ImageType imageType, int imageIndex) diff --git a/MediaBrowser.Api/HttpHandlers/ItemHandler.cs b/MediaBrowser.Api/HttpHandlers/ItemHandler.cs index dcbdf2a900..ac27633b7b 100644 --- a/MediaBrowser.Api/HttpHandlers/ItemHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/ItemHandler.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.DTO; @@ -9,7 +10,7 @@ namespace MediaBrowser.Api.HttpHandlers { public class ItemHandler : BaseJsonHandler { - protected sealed override DTOBaseItem GetObjectToSerialize() + protected async override Task GetObjectToSerialize() { Guid userId = Guid.Parse(QueryString["userid"]); User user = Kernel.Instance.Users.First(u => u.Id == userId); @@ -21,7 +22,7 @@ namespace MediaBrowser.Api.HttpHandlers return null; } - return ApiService.GetDTOBaseItem(item, user); + return await ApiService.GetDTOBaseItem(item, user); } protected virtual BaseItem ItemToSerialize diff --git a/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs b/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs index 84141a6bf5..6e4a420813 100644 --- a/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.DTO; @@ -10,14 +11,14 @@ namespace MediaBrowser.Api.HttpHandlers { public class ItemListHandler : BaseJsonHandler> { - protected override IEnumerable GetObjectToSerialize() + protected override async Task> GetObjectToSerialize() { User user = Kernel.Instance.Users.First(u => u.Id == UserId); - return ItemsToSerialize.Select(i => + return await Task.WhenAll(ItemsToSerialize.Select(i => { return ApiService.GetDTOBaseItem(i, user, includeChildren: false, includePeople: false); - }); + })); } protected IEnumerable ItemsToSerialize diff --git a/MediaBrowser.Api/HttpHandlers/PersonHandler.cs b/MediaBrowser.Api/HttpHandlers/PersonHandler.cs index 75cccfac60..f095a3a47c 100644 --- a/MediaBrowser.Api/HttpHandlers/PersonHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/PersonHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.DTO; @@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers /// public class PersonHandler : BaseJsonHandler> { - protected override IBNItem GetObjectToSerialize() + protected async override Task> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); @@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers string name = QueryString["name"]; - return GetPerson(parent, user, name); + return await GetPerson(parent, user, name); } /// /// Gets a Person /// - private IBNItem GetPerson(Folder parent, User user, string name) + private async Task> GetPerson(Folder parent, User user, string name) { int count = 0; @@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers // Get the original entity so that we can also supply the PrimaryImagePath return new IBNItem() { - Item = Kernel.Instance.ItemController.GetPerson(name), + Item = await Kernel.Instance.ItemController.GetPerson(name), BaseItemCount = count }; } diff --git a/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs b/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs index 0e19aecd5c..109440e982 100644 --- a/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.Plugins; @@ -8,11 +9,14 @@ namespace MediaBrowser.Api.HttpHandlers { public class PluginConfigurationHandler : BaseJsonHandler { - protected override BasePluginConfiguration GetObjectToSerialize() + protected override Task GetObjectToSerialize() { - string pluginName = QueryString["name"]; + return Task.Run(() => + { + string pluginName = QueryString["name"]; - return Kernel.Instance.Plugins.First(p => p.Name.Equals(pluginName, StringComparison.OrdinalIgnoreCase)).Configuration; + return Kernel.Instance.Plugins.First(p => p.Name.Equals(pluginName, StringComparison.OrdinalIgnoreCase)).Configuration; + }); } } } diff --git a/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs b/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs index c3c1b40493..f451832dd4 100644 --- a/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.DTO; @@ -11,26 +12,29 @@ namespace MediaBrowser.Api.HttpHandlers /// public class PluginsHandler : BaseJsonHandler> { - protected override IEnumerable GetObjectToSerialize() + protected override Task> GetObjectToSerialize() { - var plugins = Kernel.Instance.Plugins.Select(p => + return Task.Run(() => { - return new PluginInfo() + var plugins = Kernel.Instance.Plugins.Select(p => { - Path = p.Path, - Name = p.Name, - Enabled = p.Enabled, - DownloadToUI = p.DownloadToUI, - Version = p.Version - }; - }); + return new PluginInfo() + { + Path = p.Path, + Name = p.Name, + Enabled = p.Enabled, + DownloadToUI = p.DownloadToUI, + Version = p.Version + }; + }); - if (QueryString["uionly"] == "1") - { - plugins = plugins.Where(p => p.DownloadToUI); - } + if (QueryString["uionly"] == "1") + { + plugins = plugins.Where(p => p.DownloadToUI); + } - return plugins; + return plugins; + }); } } } diff --git a/MediaBrowser.Api/HttpHandlers/StudioHandler.cs b/MediaBrowser.Api/HttpHandlers/StudioHandler.cs index 40daadc70f..b44970ea50 100644 --- a/MediaBrowser.Api/HttpHandlers/StudioHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/StudioHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.DTO; @@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers /// public class StudioHandler : BaseJsonHandler> { - protected override IBNItem GetObjectToSerialize() + protected async override Task> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); @@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers string name = QueryString["name"]; - return GetStudio(parent, user, name); + return await GetStudio(parent, user, name); } /// /// Gets a Studio /// - private IBNItem GetStudio(Folder parent, User user, string name) + private async Task> GetStudio(Folder parent, User user, string name) { int count = 0; @@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers // Get the original entity so that we can also supply the PrimaryImagePath return new IBNItem() { - Item = Kernel.Instance.ItemController.GetStudio(name), + Item = await Kernel.Instance.ItemController.GetStudio(name), BaseItemCount = count }; } diff --git a/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs b/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs index bef381000a..d379b45fb4 100644 --- a/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.DTO; @@ -10,20 +11,20 @@ namespace MediaBrowser.Api.HttpHandlers { public class StudiosHandler : BaseJsonHandler>> { - protected override IEnumerable> GetObjectToSerialize() + protected override async Task>> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); User user = Kernel.Instance.Users.First(u => u.Id == userId); - return GetAllStudios(parent, user); + return await GetAllStudios(parent, user); } /// /// Gets all studios from all recursive children of a folder /// The CategoryInfo class is used to keep track of the number of times each studio appears /// - private IEnumerable> GetAllStudios(Folder parent, User user) + private async Task>> GetAllStudios(Folder parent, User user) { Dictionary data = new Dictionary(); @@ -52,25 +53,9 @@ namespace MediaBrowser.Api.HttpHandlers } } - // Now go through the dictionary and create a Category for each studio - List> list = new List>(); + IEnumerable entities = await Task.WhenAll(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetStudio(key); })); - foreach (string key in data.Keys) - { - // Get the original entity so that we can also supply the PrimaryImagePath - Studio entity = Kernel.Instance.ItemController.GetStudio(key); - - if (entity != null) - { - list.Add(new IBNItem() - { - Item = entity, - BaseItemCount = data[key] - }); - } - } - - return list; + return entities.Select(e => new IBNItem() { Item = e, BaseItemCount = data[e.Name] }); } } } diff --git a/MediaBrowser.Api/HttpHandlers/UsersHandler.cs b/MediaBrowser.Api/HttpHandlers/UsersHandler.cs index e1fe638ca8..1368735740 100644 --- a/MediaBrowser.Api/HttpHandlers/UsersHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/UsersHandler.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.Entities; @@ -7,9 +8,12 @@ namespace MediaBrowser.Api.HttpHandlers { class UsersHandler : BaseJsonHandler> { - protected override IEnumerable GetObjectToSerialize() + protected override Task> GetObjectToSerialize() { - return Kernel.Instance.Users; + return Task.Run(() => + { + return Kernel.Instance.Users; + }); } } } diff --git a/MediaBrowser.Api/HttpHandlers/YearHandler.cs b/MediaBrowser.Api/HttpHandlers/YearHandler.cs index 89cde99433..dfde600e78 100644 --- a/MediaBrowser.Api/HttpHandlers/YearHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/YearHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.DTO; @@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers /// public class YearHandler : BaseJsonHandler> { - protected override IBNItem GetObjectToSerialize() + protected override async Task> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); @@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers string year = QueryString["year"]; - return GetYear(parent, user, int.Parse(year)); + return await GetYear(parent, user, int.Parse(year)); } /// /// Gets a Year /// - private IBNItem GetYear(Folder parent, User user, int year) + private async Task> GetYear(Folder parent, User user, int year) { int count = 0; @@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers // Get the original entity so that we can also supply the PrimaryImagePath return new IBNItem() { - Item = Kernel.Instance.ItemController.GetYear(year), + Item = await Kernel.Instance.ItemController.GetYear(year), BaseItemCount = count }; } diff --git a/MediaBrowser.Api/HttpHandlers/YearsHandler.cs b/MediaBrowser.Api/HttpHandlers/YearsHandler.cs index 3d9ae59f2d..6ce087f857 100644 --- a/MediaBrowser.Api/HttpHandlers/YearsHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/YearsHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.DTO; @@ -10,20 +11,20 @@ namespace MediaBrowser.Api.HttpHandlers { public class YearsHandler : BaseJsonHandler>> { - protected override IEnumerable> GetObjectToSerialize() + protected override async Task>> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); User user = Kernel.Instance.Users.First(u => u.Id == userId); - return GetAllYears(parent, user); + return await GetAllYears(parent, user); } /// /// Gets all years from all recursive children of a folder /// The CategoryInfo class is used to keep track of the number of times each year appears /// - private IEnumerable> GetAllYears(Folder parent, User user) + private async Task>> GetAllYears(Folder parent, User user) { Dictionary data = new Dictionary(); @@ -49,25 +50,9 @@ namespace MediaBrowser.Api.HttpHandlers } } - // Now go through the dictionary and create a Category for each studio - List> list = new List>(); + IEnumerable entities = await Task.WhenAll(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetYear(key); })); - foreach (int key in data.Keys) - { - // Get the original entity so that we can also supply the PrimaryImagePath - Year entity = Kernel.Instance.ItemController.GetYear(key); - - if (entity != null) - { - list.Add(new IBNItem() - { - Item = entity, - BaseItemCount = data[key] - }); - } - } - - return list; + return entities.Select(e => new IBNItem() { Item = e, BaseItemCount = data[int.Parse(e.Name)] }); } } } diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 7b6f6844ce..5b2f97ced3 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -2,17 +2,16 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; -using System.Configuration; using System.IO; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Logging; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Progress; -using System.Threading.Tasks; namespace MediaBrowser.Common.Kernel { @@ -93,6 +92,8 @@ namespace MediaBrowser.Common.Kernel /// protected void ReloadComposableParts() { + DisposeComposableParts(); + // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that // This will prevent the .dll file from getting locked, and allow us to replace it when needed IEnumerable pluginAssemblies = Directory.GetFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.AllDirectories).Select(f => Assembly.Load(File.ReadAllBytes((f)))); @@ -203,10 +204,33 @@ namespace MediaBrowser.Common.Kernel /// public virtual void Dispose() { + DisposeComposableParts(); DisposeHttpServer(); DisposeLogger(); } + /// + /// Disposes all objects gathered through MEF composable parts + /// + protected virtual void DisposeComposableParts() + { + DisposePlugins(); + } + + /// + /// Disposes all plugins + /// + private void DisposePlugins() + { + if (Plugins != null) + { + foreach (BasePlugin plugin in Plugins) + { + plugin.Dispose(); + } + } + } + /// /// Disposes the current HttpServer /// diff --git a/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs index 2fcead05b0..a8c7090f7d 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs @@ -14,9 +14,9 @@ namespace MediaBrowser.Common.Net.Handlers protected string ResourcePath { get; set; } - public override string ContentType + public override Task GetContentType() { - get + return Task.Run(() => { string extension = Path.GetExtension(ResourcePath); @@ -46,7 +46,7 @@ namespace MediaBrowser.Common.Net.Handlers } return "text/plain; charset=utf-8"; - } + }); } protected override Task WriteResponseToOutputStream(Stream stream) diff --git a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs index f9ef065ecc..7a4efdaf2b 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs @@ -111,7 +111,7 @@ namespace MediaBrowser.Common.Net.Handlers /// /// Gets the MIME type to include in the response headers /// - public abstract string ContentType { get; } + public abstract Task GetContentType(); /// /// Gets the status code to include in the response headers @@ -129,31 +129,9 @@ namespace MediaBrowser.Common.Net.Handlers } } - private bool _LastDateModifiedDiscovered = false; - private DateTime? _LastDateModified = null; - /// - /// Gets the last date modified of the content being returned, if this can be determined. - /// This will be used to invalidate the cache, so it's not needed if CacheDuration is 0. - /// - public DateTime? LastDateModified + public virtual bool ShouldCompressResponse(string contentType) { - get - { - if (!_LastDateModifiedDiscovered) - { - _LastDateModified = GetLastDateModified(); - } - - return _LastDateModified; - } - } - - public virtual bool CompressResponse - { - get - { - return true; - } + return true; } private bool ClientSupportsCompression @@ -207,10 +185,12 @@ namespace MediaBrowser.Common.Net.Handlers // When serving a range request, we need to return status code 206 to indicate a partial response body StatusCode = SupportsByteRangeRequests && IsRangeRequest ? 206 : 200; - ctx.Response.ContentType = ContentType; + ctx.Response.ContentType = await GetContentType(); TimeSpan cacheDuration = CacheDuration; + DateTime? lastDateModified = await GetLastDateModified(); + if (ctx.Request.Headers.AllKeys.Contains("If-Modified-Since")) { DateTime ifModifiedSince; @@ -218,18 +198,20 @@ namespace MediaBrowser.Common.Net.Handlers if (DateTime.TryParse(ctx.Request.Headers["If-Modified-Since"].Replace(" GMT", string.Empty), out ifModifiedSince)) { // If the cache hasn't expired yet just return a 304 - if (IsCacheValid(ifModifiedSince, cacheDuration, LastDateModified)) + if (IsCacheValid(ifModifiedSince, cacheDuration, lastDateModified)) { StatusCode = 304; } } } - PrepareResponse(); + await PrepareResponse(); if (IsResponseValid) { - await ProcessUncachedRequest(ctx, cacheDuration); + bool compressResponse = ShouldCompressResponse(ctx.Response.ContentType) && ClientSupportsCompression; + + await ProcessUncachedRequest(ctx, compressResponse, cacheDuration, lastDateModified); } else { @@ -241,7 +223,7 @@ namespace MediaBrowser.Common.Net.Handlers { // It might be too late if some response data has already been transmitted, but try to set this ctx.Response.StatusCode = 500; - + Logger.LogException(ex); } finally @@ -250,7 +232,7 @@ namespace MediaBrowser.Common.Net.Handlers } } - private async Task ProcessUncachedRequest(HttpListenerContext ctx, TimeSpan cacheDuration) + private async Task ProcessUncachedRequest(HttpListenerContext ctx, bool compressResponse, TimeSpan cacheDuration, DateTime? lastDateModified) { long? totalContentLength = TotalContentLength; @@ -270,7 +252,7 @@ namespace MediaBrowser.Common.Net.Handlers } // Add the compression header - if (CompressResponse && ClientSupportsCompression) + if (compressResponse) { ctx.Response.AddHeader("Content-Encoding", CompressionMethod); } @@ -278,7 +260,7 @@ namespace MediaBrowser.Common.Net.Handlers // Add caching headers if (cacheDuration.Ticks > 0) { - CacheResponse(ctx.Response, cacheDuration, LastDateModified); + CacheResponse(ctx.Response, cacheDuration, lastDateModified); } // Set the status code @@ -289,7 +271,7 @@ namespace MediaBrowser.Common.Net.Handlers // Finally, write the response data Stream outputStream = ctx.Response.OutputStream; - if (CompressResponse && ClientSupportsCompression) + if (compressResponse) { if (CompressionMethod.Equals("deflate", StringComparison.OrdinalIgnoreCase)) { @@ -321,10 +303,11 @@ namespace MediaBrowser.Common.Net.Handlers } /// - /// Gives subclasses a chance to do and prep work, and also to validate data and set an error status code, if needed + /// Gives subclasses a chance to do any prep work, and also to validate data and set an error status code, if needed /// - protected virtual void PrepareResponse() + protected virtual Task PrepareResponse() { + return Task.Run(() => { }); } protected abstract Task WriteResponseToOutputStream(Stream stream); @@ -372,9 +355,11 @@ namespace MediaBrowser.Common.Net.Handlers return null; } - protected virtual DateTime? GetLastDateModified() + protected virtual Task GetLastDateModified() { - return null; + DateTime? value = null; + + return Task.Run(() => { return value; }); } private bool IsResponseValid diff --git a/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs index a35af92313..a3a47a4a33 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs @@ -6,19 +6,22 @@ namespace MediaBrowser.Common.Net.Handlers { public abstract class BaseJsonHandler : BaseHandler { - public override string ContentType + public override Task GetContentType() { - get { return MimeTypes.JsonMimeType; } + return Task.Run(() => + { + return MimeTypes.JsonMimeType; + }); } private bool _ObjectToSerializeEnsured = false; private T _ObjectToSerialize; - private void EnsureObjectToSerialize() + private async Task EnsureObjectToSerialize() { if (!_ObjectToSerializeEnsured) { - _ObjectToSerialize = GetObjectToSerialize(); + _ObjectToSerialize = await GetObjectToSerialize(); if (_ObjectToSerialize == null) { @@ -29,30 +32,18 @@ namespace MediaBrowser.Common.Net.Handlers } } - private T ObjectToSerialize - { - get - { - EnsureObjectToSerialize(); - return _ObjectToSerialize; - } - } + protected abstract Task GetObjectToSerialize(); - protected abstract T GetObjectToSerialize(); - - protected override void PrepareResponse() + protected override async Task PrepareResponse() { - base.PrepareResponse(); - - EnsureObjectToSerialize(); + await EnsureObjectToSerialize(); } - protected override Task WriteResponseToOutputStream(Stream stream) + protected async override Task WriteResponseToOutputStream(Stream stream) { - return Task.Run(() => - { - JsonSerializer.SerializeToStream(ObjectToSerialize, stream); - }); + await EnsureObjectToSerialize(); + + JsonSerializer.SerializeToStream(_ObjectToSerialize, stream); } } } diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs index 5656f92739..d8971dd97d 100644 --- a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs @@ -77,27 +77,22 @@ namespace MediaBrowser.Common.Net.Handlers } } - public override bool CompressResponse + public override bool ShouldCompressResponse(string contentType) { - get + // Can't compress these + if (IsRangeRequest) { - // Can't compress these - if (IsRangeRequest) - { - return false; - } - - string contentType = ContentType; - - // Don't compress media - if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } + return false; + } - // It will take some work to support compression within this handler + // Don't compress media + if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) + { return false; } + + // It will take some work to support compression within this handler + return false; } protected override long? GetTotalContentLength() @@ -105,31 +100,32 @@ namespace MediaBrowser.Common.Net.Handlers return SourceStream.Length; } - protected override DateTime? GetLastDateModified() + protected override Task GetLastDateModified() { - EnsureSourceStream(); - - if (SourceStream == null) + return Task.Run(() => { - return null; - } + EnsureSourceStream(); + + if (SourceStream == null) + { + return null; + } - return File.GetLastWriteTime(Path); + return File.GetLastWriteTime(Path); + }); } - public override string ContentType + public override Task GetContentType() { - get + return Task.Run(() => { return MimeTypes.GetMimeType(Path); - } + }); } - protected override void PrepareResponse() + protected override Task PrepareResponse() { - base.PrepareResponse(); - - EnsureSourceStream(); + return Task.Run(() => { EnsureSourceStream(); }); } protected async override Task WriteResponseToOutputStream(Stream stream) diff --git a/MediaBrowser.Controller/IO/DirectoryWatchers.cs b/MediaBrowser.Controller/IO/DirectoryWatchers.cs index 1ca9cf0c85..e4eadbbd0c 100644 --- a/MediaBrowser.Controller/IO/DirectoryWatchers.cs +++ b/MediaBrowser.Controller/IO/DirectoryWatchers.cs @@ -75,7 +75,7 @@ namespace MediaBrowser.Controller.IO } } - private void TimerStopped(object stateInfo) + private async void TimerStopped(object stateInfo) { updateTimer.Dispose(); updateTimer = null; @@ -83,7 +83,7 @@ namespace MediaBrowser.Controller.IO List paths = affectedPaths; affectedPaths = new List(); - //ProcessPathChanges(paths); + await ProcessPathChanges(paths); } private async Task ProcessPathChanges(IEnumerable paths) @@ -109,10 +109,7 @@ namespace MediaBrowser.Controller.IO } else { - /*Parallel.For(0, itemsToRefresh.Count, i => - { - Kernel.Instance.ReloadItem(itemsToRefresh[i]); - });*/ + await Task.WhenAll(itemsToRefresh.Select(i => Kernel.Instance.ReloadItem(i))); } } diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index b696abef54..57e30479b3 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -248,5 +248,47 @@ namespace MediaBrowser.Controller return list; } + + internal async Task ExecuteMetadataProviders(BaseEntity item, ItemResolveEventArgs args) + { + var supportedProviders = Kernel.Instance.MetadataProviders.Where(i => i.Supports(item)); + + // Start with non-internet providers. Run them sequentially + foreach (BaseMetadataProvider provider in supportedProviders.Where(i => !i.RequiresInternet)) + { + await provider.Fetch(item, args); + } + + var internetProviders = supportedProviders.Where(i => i.RequiresInternet); + + if (internetProviders.Any()) + { + // Now execute internet providers in parallel + await Task.WhenAll( + internetProviders.Select(i => i.Fetch(item, args)) + ); + } + } + + protected override void DisposeComposableParts() + { + base.DisposeComposableParts(); + + DisposeProviders(); + } + + /// + /// Disposes all providers + /// + private void DisposeProviders() + { + if (MetadataProviders != null) + { + foreach (var provider in MetadataProviders) + { + provider.Dispose(); + } + } + } } } diff --git a/MediaBrowser.Controller/Library/ItemController.cs b/MediaBrowser.Controller/Library/ItemController.cs index 4b0d9a9835..bc5cea79b9 100644 --- a/MediaBrowser.Controller/Library/ItemController.cs +++ b/MediaBrowser.Controller/Library/ItemController.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -217,49 +218,49 @@ namespace MediaBrowser.Controller.Library /// /// Gets a Person /// - public Person GetPerson(string name) + public async Task GetPerson(string name) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.PeoplePath, name); - return GetImagesByNameItem(path, name); + return await GetImagesByNameItem(path, name); } /// /// Gets a Studio /// - public Studio GetStudio(string name) + public async Task GetStudio(string name) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.StudioPath, name); - return GetImagesByNameItem(path, name); + return await GetImagesByNameItem(path, name); } /// /// Gets a Genre /// - public Genre GetGenre(string name) + public async Task GetGenre(string name) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.GenrePath, name); - return GetImagesByNameItem(path, name); + return await GetImagesByNameItem(path, name); } /// /// Gets a Year /// - public Year GetYear(int value) + public async Task GetYear(int value) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.YearPath, value.ToString()); - return GetImagesByNameItem(path, value.ToString()); + return await GetImagesByNameItem(path, value.ToString()); } - private Dictionary ImagesByNameItemCache = new Dictionary(); + private ConcurrentDictionary ImagesByNameItemCache = new ConcurrentDictionary(); /// /// Generically retrieves an IBN item /// - private T GetImagesByNameItem(string path, string name) + private async Task GetImagesByNameItem(string path, string name) where T : BaseEntity, new() { string key = path.ToLower(); @@ -267,7 +268,9 @@ namespace MediaBrowser.Controller.Library // Look for it in the cache, if it's not there, create it if (!ImagesByNameItemCache.ContainsKey(key)) { - ImagesByNameItemCache[key] = CreateImagesByNameItem(path, name); + T obj = await CreateImagesByNameItem(path, name); + ImagesByNameItemCache[key] = obj; + return obj; } return ImagesByNameItemCache[key] as T; @@ -276,7 +279,7 @@ namespace MediaBrowser.Controller.Library /// /// Creates an IBN item based on a given path /// - private T CreateImagesByNameItem(string path, string name) + private async Task CreateImagesByNameItem(string path, string name) where T : BaseEntity, new() { T item = new T(); @@ -284,25 +287,28 @@ namespace MediaBrowser.Controller.Library item.Name = name; item.Id = Kernel.GetMD5(path); - if (Directory.Exists(path)) + if (!Directory.Exists(path)) { - item.DateCreated = Directory.GetCreationTime(path); - item.DateModified = Directory.GetLastAccessTime(path); - if (File.Exists(Path.Combine(path, "folder.jpg"))) - { - item.PrimaryImagePath = Path.Combine(path, "folder.jpg"); - } - else if (File.Exists(Path.Combine(path, "folder.png"))) - { - item.PrimaryImagePath = Path.Combine(path, "folder.png"); - } + Directory.CreateDirectory(path); } - else + + item.DateCreated = Directory.GetCreationTime(path); + item.DateModified = Directory.GetLastAccessTime(path); + + if (File.Exists(Path.Combine(path, "folder.jpg"))) + { + item.PrimaryImagePath = Path.Combine(path, "folder.jpg"); + } + else if (File.Exists(Path.Combine(path, "folder.png"))) { - DateTime now = DateTime.Now; + item.PrimaryImagePath = Path.Combine(path, "folder.png"); + } + + var b = false; - item.DateCreated = now; - item.DateModified = now; + if (b) + { + await Kernel.Instance.ExecuteMetadataProviders(item, null); } return item; diff --git a/MediaBrowser.Controller/Providers/AudioInfoProvider.cs b/MediaBrowser.Controller/Providers/AudioInfoProvider.cs index 934f082d54..70adb688f1 100644 --- a/MediaBrowser.Controller/Providers/AudioInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/AudioInfoProvider.cs @@ -12,12 +12,12 @@ namespace MediaBrowser.Controller.Providers [Export(typeof(BaseMetadataProvider))] public class AudioInfoProvider : BaseMetadataProvider { - public override bool Supports(BaseItem item) + public override bool Supports(BaseEntity item) { return item is Audio; } - public async override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { Audio audio = item as Audio; @@ -62,6 +62,7 @@ namespace MediaBrowser.Controller.Providers { base.Init(); + // Do this now so that we don't have to do this on every operation, which would require us to create a lock in order to maintain thread-safety for (int i = 0; i <= 9; i++) { EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, i.ToString())); diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs index 93d9ef10e4..e40d30372d 100644 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs @@ -1,10 +1,11 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using MediaBrowser.Controller.Events; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Providers { - public abstract class BaseMetadataProvider + public abstract class BaseMetadataProvider : IDisposable { /// /// If the provider needs any startup routines, add them here @@ -13,11 +14,23 @@ namespace MediaBrowser.Controller.Providers { } - public virtual bool Supports(BaseItem item) + /// + /// Disposes anything created during Init + /// + public virtual void Dispose() + { + } + + public abstract bool Supports(BaseEntity item); + + public virtual bool RequiresInternet { - return true; + get + { + return false; + } } - public abstract Task Fetch(BaseItem item, ItemResolveEventArgs args); + public abstract Task Fetch(BaseEntity item, ItemResolveEventArgs args); } } diff --git a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs index 14067dd202..2ef2142375 100644 --- a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs +++ b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs @@ -9,12 +9,12 @@ namespace MediaBrowser.Controller.Providers [Export(typeof(BaseMetadataProvider))] public class FolderProviderFromXml : BaseMetadataProvider { - public override bool Supports(BaseItem item) + public override bool Supports(BaseEntity item) { return item is Folder; } - public async override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { var metadataFile = args.GetFileByName("folder.xml"); diff --git a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs index 2df07251af..5b086f795a 100644 --- a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs +++ b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs @@ -12,13 +12,18 @@ namespace MediaBrowser.Controller.Providers [Export(typeof(BaseMetadataProvider))] public class ImageFromMediaLocationProvider : BaseMetadataProvider { - public override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public override bool Supports(BaseEntity item) + { + return item is BaseItem; + } + + public override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { return Task.Run(() => { if (args.IsFolder) { - PopulateImages(item, args); + PopulateImages(item as BaseItem, args); } }); } diff --git a/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs b/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs index 027c2f75d2..9d909934d4 100644 --- a/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs +++ b/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs @@ -10,8 +10,15 @@ namespace MediaBrowser.Controller.Providers [Export(typeof(BaseMetadataProvider))] public class LocalTrailerProvider : BaseMetadataProvider { - public async override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public override bool Supports(BaseEntity item) { + return item is BaseItem; + } + + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) + { + BaseItem baseItem = item as BaseItem; + var trailerPath = args.GetFolderByName("trailers"); if (trailerPath.HasValue) @@ -32,7 +39,7 @@ namespace MediaBrowser.Controller.Providers } } - item.LocalTrailers = localTrailers; + baseItem.LocalTrailers = localTrailers; } } } diff --git a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs index 75e516487d..d8f6b61ce9 100644 --- a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs +++ b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs @@ -2,13 +2,12 @@ using System.IO; using System.Threading.Tasks; using MediaBrowser.Controller.Events; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Resolvers { public abstract class BaseItemResolver : IBaseItemResolver - where T : BaseItem, new () + where T : BaseItem, new() { protected virtual T Resolve(ItemResolveEventArgs args) { @@ -18,7 +17,7 @@ namespace MediaBrowser.Controller.Resolvers /// /// Sets initial values on the newly resolved item /// - protected virtual void SetItemValues(T item, ItemResolveEventArgs args) + protected virtual void SetInitialItemValues(T item, ItemResolveEventArgs args) { // If the subclass didn't specify this if (string.IsNullOrEmpty(item.Path)) @@ -38,35 +37,24 @@ namespace MediaBrowser.Controller.Resolvers public async Task ResolvePath(ItemResolveEventArgs args) { T item = Resolve(args); - + if (item != null) { // Set initial values on the newly resolved item - SetItemValues(item, args); + SetInitialItemValues(item, args); // Make sure the item has a name EnsureName(item); // Make sure DateCreated and DateModified have values EnsureDates(item); - - await FetchMetadataFromProviders(item, args); + + await Kernel.Instance.ExecuteMetadataProviders(item, args); } return item; } - private async Task FetchMetadataFromProviders(T item, ItemResolveEventArgs args) - { - foreach (BaseMetadataProvider provider in Kernel.Instance.MetadataProviders) - { - if (provider.Supports(item)) - { - await provider.Fetch(item, args); - } - } - } - private void EnsureName(T item) { // If the subclass didn't supply a name, add it here diff --git a/MediaBrowser.Controller/Resolvers/FolderResolver.cs b/MediaBrowser.Controller/Resolvers/FolderResolver.cs index ff326669f3..858b3bcd8d 100644 --- a/MediaBrowser.Controller/Resolvers/FolderResolver.cs +++ b/MediaBrowser.Controller/Resolvers/FolderResolver.cs @@ -21,9 +21,9 @@ namespace MediaBrowser.Controller.Resolvers public abstract class BaseFolderResolver : BaseItemResolver where TItemType : Folder, new() { - protected override void SetItemValues(TItemType item, ItemResolveEventArgs args) + protected override void SetInitialItemValues(TItemType item, ItemResolveEventArgs args) { - base.SetItemValues(item, args); + base.SetInitialItemValues(item, args); item.IsRoot = args.Parent == null; } diff --git a/MediaBrowser.Controller/Resolvers/VirtualFolderResolver.cs b/MediaBrowser.Controller/Resolvers/VirtualFolderResolver.cs index 51478fd02e..c81cb204a7 100644 --- a/MediaBrowser.Controller/Resolvers/VirtualFolderResolver.cs +++ b/MediaBrowser.Controller/Resolvers/VirtualFolderResolver.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Resolvers return null; } - protected override void SetItemValues(VirtualFolder item, ItemResolveEventArgs args) + protected override void SetInitialItemValues(VirtualFolder item, ItemResolveEventArgs args) { // Set the name initially by stripping off the [CollectionType=...] // The name can always be overridden later by folder.xml @@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Resolvers item.CollectionType = pathName.Substring(index + srch.Length).TrimEnd(']'); } - base.SetItemValues(item, args); + base.SetInitialItemValues(item, args); } } diff --git a/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs b/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs index 0e514b8b21..6c7a265fac 100644 --- a/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; using System.Xml; using MediaBrowser.Model.Entities; -using System.Threading.Tasks; namespace MediaBrowser.Controller.Xml { diff --git a/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs b/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs index 4e0bacb054..03c0814549 100644 --- a/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs +++ b/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs @@ -11,12 +11,12 @@ namespace MediaBrowser.Movies.Providers [Export(typeof(BaseMetadataProvider))] public class MovieProviderFromXml : BaseMetadataProvider { - public override bool Supports(BaseItem item) + public override bool Supports(BaseEntity item) { return item is Movie; } - public async override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { var metadataFile = args.GetFileByName("movie.xml"); diff --git a/MediaBrowser.Movies/Resolvers/MovieResolver.cs b/MediaBrowser.Movies/Resolvers/MovieResolver.cs index 36fbecf68b..498597c978 100644 --- a/MediaBrowser.Movies/Resolvers/MovieResolver.cs +++ b/MediaBrowser.Movies/Resolvers/MovieResolver.cs @@ -88,9 +88,9 @@ namespace MediaBrowser.Movies.Resolvers } } - protected override void SetItemValues(Movie item, ItemResolveEventArgs args) + protected override void SetInitialItemValues(Movie item, ItemResolveEventArgs args) { - base.SetItemValues(item, args); + base.SetInitialItemValues(item, args); PopulateBonusFeatures(item, args); } diff --git a/MediaBrowser.ServerApplication/MainWindow.xaml.cs b/MediaBrowser.ServerApplication/MainWindow.xaml.cs index abca9149f1..67e20b2a21 100644 --- a/MediaBrowser.ServerApplication/MainWindow.xaml.cs +++ b/MediaBrowser.ServerApplication/MainWindow.xaml.cs @@ -2,10 +2,9 @@ using System.Diagnostics; using System.Windows; using MediaBrowser.Common.Logging; +using MediaBrowser.Common.UI; using MediaBrowser.Controller; using MediaBrowser.Model.Progress; -using System.Threading.Tasks; -using MediaBrowser.Common.UI; namespace MediaBrowser.ServerApplication { diff --git a/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs b/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs index 61525dc790..8babcec630 100644 --- a/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs +++ b/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs @@ -13,22 +13,24 @@ namespace MediaBrowser.TV.Providers [Export(typeof(BaseMetadataProvider))] public class EpisodeImageFromMediaLocationProvider : BaseMetadataProvider { - public override bool Supports(BaseItem item) + public override bool Supports(BaseEntity item) { return item is Episode; } - public override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { return Task.Run(() => { + Episode episode = item as Episode; + string metadataFolder = Path.Combine(args.Parent.Path, "metadata"); - string episodeFileName = Path.GetFileName(item.Path); + string episodeFileName = Path.GetFileName(episode.Path); Season season = args.Parent as Season; - SetPrimaryImagePath(item as Episode, season, metadataFolder, episodeFileName); + SetPrimaryImagePath(episode, season, metadataFolder, episodeFileName); }); } diff --git a/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs b/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs index 4c6c584597..c92b1c4754 100644 --- a/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs +++ b/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs @@ -14,20 +14,22 @@ namespace MediaBrowser.TV.Providers [Export(typeof(BaseMetadataProvider))] public class EpisodeProviderFromXml : BaseMetadataProvider { - public override bool Supports(BaseItem item) + public override bool Supports(BaseEntity item) { return item is Episode; } - public async override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { string metadataFolder = Path.Combine(args.Parent.Path, "metadata"); - string episodeFileName = Path.GetFileName(item.Path); + Episode episode = item as Episode; + + string episodeFileName = Path.GetFileName(episode.Path); string metadataFile = Path.Combine(metadataFolder, Path.ChangeExtension(episodeFileName, ".xml")); - await FetchMetadata(item as Episode, args.Parent as Season, metadataFile); + await FetchMetadata(episode, args.Parent as Season, metadataFile); } private async Task FetchMetadata(Episode item, Season season, string metadataFile) diff --git a/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs b/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs index 7adfb0483b..02d5ce1782 100644 --- a/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs +++ b/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs @@ -11,12 +11,12 @@ namespace MediaBrowser.TV.Providers [Export(typeof(BaseMetadataProvider))] public class SeriesProviderFromXml : BaseMetadataProvider { - public override bool Supports(BaseItem item) + public override bool Supports(BaseEntity item) { return item is Series; } - public async override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { var metadataFile = args.GetFileByName("series.xml"); -- cgit v1.2.3 From fbf8cc833c441de8890998600be044296acfc783 Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Tue, 21 Aug 2012 22:50:59 -0400 Subject: a few more async optimizations --- MediaBrowser.Api/ApiService.cs | 14 +++--- MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs | 17 +++---- MediaBrowser.Api/HttpHandlers/GenreHandler.cs | 6 +-- MediaBrowser.Api/HttpHandlers/GenresHandler.cs | 6 +-- MediaBrowser.Api/HttpHandlers/ImageHandler.cs | 26 +++++----- MediaBrowser.Api/HttpHandlers/ItemHandler.cs | 4 +- MediaBrowser.Api/HttpHandlers/ItemListHandler.cs | 6 +-- MediaBrowser.Api/HttpHandlers/PersonHandler.cs | 6 +-- .../HttpHandlers/PluginConfigurationHandler.cs | 9 ++-- MediaBrowser.Api/HttpHandlers/PluginsHandler.cs | 31 ++++++------ MediaBrowser.Api/HttpHandlers/StudioHandler.cs | 6 +-- MediaBrowser.Api/HttpHandlers/StudiosHandler.cs | 6 +-- MediaBrowser.Api/HttpHandlers/UsersHandler.cs | 5 +- MediaBrowser.Api/HttpHandlers/YearHandler.cs | 6 +-- MediaBrowser.Api/HttpHandlers/YearsHandler.cs | 6 +-- MediaBrowser.Api/Plugin.cs | 4 +- MediaBrowser.ApiInteraction/ApiClient.cs | 32 ++++++------- .../Net/Handlers/BaseEmbeddedResourceHandler.cs | 35 +------------- MediaBrowser.Common/Net/Handlers/BaseHandler.cs | 14 +++--- .../Net/Handlers/BaseJsonHandler.cs | 11 ++--- .../Net/Handlers/StaticFileHandler.cs | 55 ++++++++++------------ MediaBrowser.Common/UI/BaseApplication.cs | 10 ++-- MediaBrowser.Controller/FFMpeg/FFProbe.cs | 22 ++++----- MediaBrowser.Controller/IO/DirectoryWatchers.cs | 6 +-- MediaBrowser.Controller/Kernel.cs | 37 +++++++-------- MediaBrowser.Controller/Library/ItemController.cs | 54 +++++++++------------ .../Providers/AudioInfoProvider.cs | 14 ++++-- .../Providers/BaseMetadataProvider.cs | 2 +- .../Providers/FolderProviderFromXml.cs | 6 ++- .../Providers/ImageFromMediaLocationProvider.cs | 29 ++++++------ .../Providers/LocalTrailerProvider.cs | 10 ++-- .../Providers/VideoInfoProvider.cs | 11 +++-- MediaBrowser.Controller/Xml/BaseItemXmlParser.cs | 2 - .../Providers/MovieProviderFromXml.cs | 6 ++- .../EpisodeImageFromMediaLocationProvider.cs | 5 +- .../Providers/EpisodeProviderFromXml.cs | 27 +++++------ MediaBrowser.TV/Providers/SeriesProviderFromXml.cs | 6 ++- 37 files changed, 245 insertions(+), 307 deletions(-) (limited to 'MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs') diff --git a/MediaBrowser.Api/ApiService.cs b/MediaBrowser.Api/ApiService.cs index b7a2c4adc3..03ea97fd0e 100644 --- a/MediaBrowser.Api/ApiService.cs +++ b/MediaBrowser.Api/ApiService.cs @@ -81,16 +81,16 @@ namespace MediaBrowser.Api dto.UserData = item.GetUserData(user); - await AttachStudios(dto, item); + await AttachStudios(dto, item).ConfigureAwait(false); if (includeChildren) { - await AttachChildren(dto, item, user); + await AttachChildren(dto, item, user).ConfigureAwait(false); } if (includePeople) { - await AttachPeople(dto, item); + await AttachPeople(dto, item).ConfigureAwait(false); } Folder folder = item as Folder; @@ -125,7 +125,7 @@ namespace MediaBrowser.Api // Attach Studios by transforming them into BaseItemStudio (DTO) if (item.Studios != null) { - IEnumerable entities = await Task.WhenAll(item.Studios.Select(c => Kernel.Instance.ItemController.GetStudio(c))); + IEnumerable entities = await Task.WhenAll(item.Studios.Select(c => Kernel.Instance.ItemController.GetStudio(c))).ConfigureAwait(false); dto.Studios = item.Studios.Select(s => { @@ -153,12 +153,12 @@ namespace MediaBrowser.Api { IEnumerable children = folder.GetParentalAllowedChildren(user); - dto.Children = await Task.WhenAll(children.Select(c => GetDTOBaseItem(c, user, false, false))); + dto.Children = await Task.WhenAll(children.Select(c => GetDTOBaseItem(c, user, false, false))).ConfigureAwait(false); } if (item.LocalTrailers != null && item.LocalTrailers.Any()) { - dto.LocalTrailers = await Task.WhenAll(item.LocalTrailers.Select(c => GetDTOBaseItem(c, user, false, false))); + dto.LocalTrailers = await Task.WhenAll(item.LocalTrailers.Select(c => GetDTOBaseItem(c, user, false, false))).ConfigureAwait(false); } } @@ -167,7 +167,7 @@ namespace MediaBrowser.Api // Attach People by transforming them into BaseItemPerson (DTO) if (item.People != null) { - IEnumerable entities = await Task.WhenAll(item.People.Select(c => Kernel.Instance.ItemController.GetPerson(c.Name))); + IEnumerable entities = await Task.WhenAll(item.People.Select(c => Kernel.Instance.ItemController.GetPerson(c.Name))).ConfigureAwait(false); dto.People = item.People.Select(p => { diff --git a/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs b/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs index d2dbd699d3..7d9200b111 100644 --- a/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs @@ -92,10 +92,7 @@ namespace MediaBrowser.Api.HttpHandlers public override Task GetContentType() { - return Task.Run(() => - { - return MimeTypes.GetMimeType("." + GetConversionOutputFormat()); - }); + return Task.FromResult(MimeTypes.GetMimeType("." + GetConversionOutputFormat())); } public override bool ShouldCompressResponse(string contentType) @@ -103,17 +100,17 @@ namespace MediaBrowser.Api.HttpHandlers return false; } - public override async Task ProcessRequest(HttpListenerContext ctx) + public override Task ProcessRequest(HttpListenerContext ctx) { HttpListenerContext = ctx; if (!RequiresConversion()) { - await new StaticFileHandler() { Path = LibraryItem.Path }.ProcessRequest(ctx); + return new StaticFileHandler() { Path = LibraryItem.Path }.ProcessRequest(ctx); } else { - await base.ProcessRequest(ctx); + return base.ProcessRequest(ctx); } } @@ -180,15 +177,15 @@ namespace MediaBrowser.Api.HttpHandlers // If we ever decide to disable the ffmpeg log then you must uncomment the below line. //process.BeginErrorReadLine(); - Task debugLogTask = Task.Run(async () => { await process.StandardError.BaseStream.CopyToAsync(logStream); }); + Task debugLogTask = process.StandardError.BaseStream.CopyToAsync(logStream); - await process.StandardOutput.BaseStream.CopyToAsync(stream); + await process.StandardOutput.BaseStream.CopyToAsync(stream).ConfigureAwait(false); process.WaitForExit(); Logger.LogInfo("FFMpeg exited with code " + process.ExitCode); - await debugLogTask; + await debugLogTask.ConfigureAwait(false); } catch (Exception ex) { diff --git a/MediaBrowser.Api/HttpHandlers/GenreHandler.cs b/MediaBrowser.Api/HttpHandlers/GenreHandler.cs index c4198b0288..e9e5c41f45 100644 --- a/MediaBrowser.Api/HttpHandlers/GenreHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/GenreHandler.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers /// public class GenreHandler : BaseJsonHandler> { - protected override async Task> GetObjectToSerialize() + protected override Task> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); @@ -22,7 +22,7 @@ namespace MediaBrowser.Api.HttpHandlers string name = QueryString["name"]; - return await GetGenre(parent, user, name); + return GetGenre(parent, user, name); } /// @@ -46,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers // Get the original entity so that we can also supply the PrimaryImagePath return new IBNItem() { - Item = await Kernel.Instance.ItemController.GetGenre(name), + Item = await Kernel.Instance.ItemController.GetGenre(name).ConfigureAwait(false), BaseItemCount = count }; } diff --git a/MediaBrowser.Api/HttpHandlers/GenresHandler.cs b/MediaBrowser.Api/HttpHandlers/GenresHandler.cs index cd68f1eaa9..8ac30043ef 100644 --- a/MediaBrowser.Api/HttpHandlers/GenresHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/GenresHandler.cs @@ -11,13 +11,13 @@ namespace MediaBrowser.Api.HttpHandlers { public class GenresHandler : BaseJsonHandler>> { - protected override async Task>> GetObjectToSerialize() + protected override Task>> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); User user = Kernel.Instance.Users.First(u => u.Id == userId); - return await GetAllGenres(parent, user); + return GetAllGenres(parent, user); } /// @@ -53,7 +53,7 @@ namespace MediaBrowser.Api.HttpHandlers } } - IEnumerable entities = await Task.WhenAll(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetGenre(key); })); + IEnumerable entities = await Task.WhenAll(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetGenre(key); })).ConfigureAwait(false); return entities.Select(e => new IBNItem() { Item = e, BaseItemCount = data[e.Name] }); } diff --git a/MediaBrowser.Api/HttpHandlers/ImageHandler.cs b/MediaBrowser.Api/HttpHandlers/ImageHandler.cs index 39a115cefb..48c67eeef2 100644 --- a/MediaBrowser.Api/HttpHandlers/ImageHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/ImageHandler.cs @@ -29,28 +29,28 @@ namespace MediaBrowser.Api.HttpHandlers if (!string.IsNullOrEmpty(personName)) { - return (await Kernel.Instance.ItemController.GetPerson(personName)).PrimaryImagePath; + return (await Kernel.Instance.ItemController.GetPerson(personName).ConfigureAwait(false)).PrimaryImagePath; } string genreName = QueryString["genre"]; if (!string.IsNullOrEmpty(genreName)) { - return (await Kernel.Instance.ItemController.GetGenre(genreName)).PrimaryImagePath; + return (await Kernel.Instance.ItemController.GetGenre(genreName).ConfigureAwait(false)).PrimaryImagePath; } string year = QueryString["year"]; if (!string.IsNullOrEmpty(year)) { - return (await Kernel.Instance.ItemController.GetYear(int.Parse(year))).PrimaryImagePath; + return (await Kernel.Instance.ItemController.GetYear(int.Parse(year)).ConfigureAwait(false)).PrimaryImagePath; } string studio = QueryString["studio"]; if (!string.IsNullOrEmpty(studio)) { - return (await Kernel.Instance.ItemController.GetStudio(studio)).PrimaryImagePath; + return (await Kernel.Instance.ItemController.GetStudio(studio).ConfigureAwait(false)).PrimaryImagePath; } BaseItem item = ApiService.GetItemById(QueryString["id"]); @@ -64,7 +64,7 @@ namespace MediaBrowser.Api.HttpHandlers private Stream _SourceStream = null; private async Task GetSourceStream() { - await EnsureSourceStream(); + await EnsureSourceStream().ConfigureAwait(false); return _SourceStream; } @@ -75,7 +75,7 @@ namespace MediaBrowser.Api.HttpHandlers { try { - _SourceStream = File.OpenRead(await GetImagePath()); + _SourceStream = File.OpenRead(await GetImagePath().ConfigureAwait(false)); } catch (FileNotFoundException ex) { @@ -101,14 +101,14 @@ namespace MediaBrowser.Api.HttpHandlers public async override Task GetContentType() { - await EnsureSourceStream(); + await EnsureSourceStream().ConfigureAwait(false); - if (await GetSourceStream() == null) + if (await GetSourceStream().ConfigureAwait(false) == null) { return null; } - return MimeTypes.GetMimeType(await GetImagePath()); + return MimeTypes.GetMimeType(await GetImagePath().ConfigureAwait(false)); } public override TimeSpan CacheDuration @@ -121,14 +121,14 @@ namespace MediaBrowser.Api.HttpHandlers protected async override Task GetLastDateModified() { - await EnsureSourceStream(); + await EnsureSourceStream().ConfigureAwait(false); - if (await GetSourceStream() == null) + if (await GetSourceStream().ConfigureAwait(false) == null) { return null; } - return File.GetLastWriteTime(await GetImagePath()); + return File.GetLastWriteTime(await GetImagePath().ConfigureAwait(false)); } private int? Height @@ -223,7 +223,7 @@ namespace MediaBrowser.Api.HttpHandlers protected override async Task WriteResponseToOutputStream(Stream stream) { - ImageProcessor.ProcessImage(await GetSourceStream(), stream, Width, Height, MaxWidth, MaxHeight, Quality); + ImageProcessor.ProcessImage(await GetSourceStream().ConfigureAwait(false), stream, Width, Height, MaxWidth, MaxHeight, Quality); } private string GetImagePathFromTypes(BaseItem item, ImageType imageType, int imageIndex) diff --git a/MediaBrowser.Api/HttpHandlers/ItemHandler.cs b/MediaBrowser.Api/HttpHandlers/ItemHandler.cs index ac27633b7b..4f2a9c68e5 100644 --- a/MediaBrowser.Api/HttpHandlers/ItemHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/ItemHandler.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Api.HttpHandlers { public class ItemHandler : BaseJsonHandler { - protected async override Task GetObjectToSerialize() + protected override Task GetObjectToSerialize() { Guid userId = Guid.Parse(QueryString["userid"]); User user = Kernel.Instance.Users.First(u => u.Id == userId); @@ -22,7 +22,7 @@ namespace MediaBrowser.Api.HttpHandlers return null; } - return await ApiService.GetDTOBaseItem(item, user); + return ApiService.GetDTOBaseItem(item, user); } protected virtual BaseItem ItemToSerialize diff --git a/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs b/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs index 6e4a420813..9d5e3eb580 100644 --- a/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs @@ -9,13 +9,13 @@ using MediaBrowser.Model.Entities; namespace MediaBrowser.Api.HttpHandlers { - public class ItemListHandler : BaseJsonHandler> + public class ItemListHandler : BaseJsonHandler { - protected override async Task> GetObjectToSerialize() + protected override Task GetObjectToSerialize() { User user = Kernel.Instance.Users.First(u => u.Id == UserId); - return await Task.WhenAll(ItemsToSerialize.Select(i => + return Task.WhenAll(ItemsToSerialize.Select(i => { return ApiService.GetDTOBaseItem(i, user, includeChildren: false, includePeople: false); })); diff --git a/MediaBrowser.Api/HttpHandlers/PersonHandler.cs b/MediaBrowser.Api/HttpHandlers/PersonHandler.cs index f095a3a47c..b144c0bdf4 100644 --- a/MediaBrowser.Api/HttpHandlers/PersonHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/PersonHandler.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers /// public class PersonHandler : BaseJsonHandler> { - protected async override Task> GetObjectToSerialize() + protected override Task> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); @@ -22,7 +22,7 @@ namespace MediaBrowser.Api.HttpHandlers string name = QueryString["name"]; - return await GetPerson(parent, user, name); + return GetPerson(parent, user, name); } /// @@ -46,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers // Get the original entity so that we can also supply the PrimaryImagePath return new IBNItem() { - Item = await Kernel.Instance.ItemController.GetPerson(name), + Item = await Kernel.Instance.ItemController.GetPerson(name).ConfigureAwait(false), BaseItemCount = count }; } diff --git a/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs b/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs index 109440e982..fbc16109d8 100644 --- a/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs @@ -11,12 +11,11 @@ namespace MediaBrowser.Api.HttpHandlers { protected override Task GetObjectToSerialize() { - return Task.Run(() => - { - string pluginName = QueryString["name"]; + string pluginName = QueryString["name"]; - return Kernel.Instance.Plugins.First(p => p.Name.Equals(pluginName, StringComparison.OrdinalIgnoreCase)).Configuration; - }); + BasePluginConfiguration config = Kernel.Instance.Plugins.First(p => p.Name.Equals(pluginName, StringComparison.OrdinalIgnoreCase)).Configuration; + + return Task.FromResult(config); } } } diff --git a/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs b/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs index f451832dd4..1cb4e95f76 100644 --- a/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs @@ -14,27 +14,24 @@ namespace MediaBrowser.Api.HttpHandlers { protected override Task> GetObjectToSerialize() { - return Task.Run(() => + var plugins = Kernel.Instance.Plugins.Select(p => { - var plugins = Kernel.Instance.Plugins.Select(p => + return new PluginInfo() { - return new PluginInfo() - { - Path = p.Path, - Name = p.Name, - Enabled = p.Enabled, - DownloadToUI = p.DownloadToUI, - Version = p.Version - }; - }); + Path = p.Path, + Name = p.Name, + Enabled = p.Enabled, + DownloadToUI = p.DownloadToUI, + Version = p.Version + }; + }); - if (QueryString["uionly"] == "1") - { - plugins = plugins.Where(p => p.DownloadToUI); - } + if (QueryString["uionly"] == "1") + { + plugins = plugins.Where(p => p.DownloadToUI); + } - return plugins; - }); + return Task.FromResult>(plugins); } } } diff --git a/MediaBrowser.Api/HttpHandlers/StudioHandler.cs b/MediaBrowser.Api/HttpHandlers/StudioHandler.cs index b44970ea50..727237882b 100644 --- a/MediaBrowser.Api/HttpHandlers/StudioHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/StudioHandler.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers /// public class StudioHandler : BaseJsonHandler> { - protected async override Task> GetObjectToSerialize() + protected override Task> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); @@ -22,7 +22,7 @@ namespace MediaBrowser.Api.HttpHandlers string name = QueryString["name"]; - return await GetStudio(parent, user, name); + return GetStudio(parent, user, name); } /// @@ -46,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers // Get the original entity so that we can also supply the PrimaryImagePath return new IBNItem() { - Item = await Kernel.Instance.ItemController.GetStudio(name), + Item = await Kernel.Instance.ItemController.GetStudio(name).ConfigureAwait(false), BaseItemCount = count }; } diff --git a/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs b/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs index d379b45fb4..7e85e5558c 100644 --- a/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs @@ -11,13 +11,13 @@ namespace MediaBrowser.Api.HttpHandlers { public class StudiosHandler : BaseJsonHandler>> { - protected override async Task>> GetObjectToSerialize() + protected override Task>> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); User user = Kernel.Instance.Users.First(u => u.Id == userId); - return await GetAllStudios(parent, user); + return GetAllStudios(parent, user); } /// @@ -53,7 +53,7 @@ namespace MediaBrowser.Api.HttpHandlers } } - IEnumerable entities = await Task.WhenAll(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetStudio(key); })); + IEnumerable entities = await Task.WhenAll(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetStudio(key); })).ConfigureAwait(false); return entities.Select(e => new IBNItem() { Item = e, BaseItemCount = data[e.Name] }); } diff --git a/MediaBrowser.Api/HttpHandlers/UsersHandler.cs b/MediaBrowser.Api/HttpHandlers/UsersHandler.cs index 1368735740..ad9ffec980 100644 --- a/MediaBrowser.Api/HttpHandlers/UsersHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/UsersHandler.cs @@ -10,10 +10,7 @@ namespace MediaBrowser.Api.HttpHandlers { protected override Task> GetObjectToSerialize() { - return Task.Run(() => - { - return Kernel.Instance.Users; - }); + return Task.FromResult>(Kernel.Instance.Users); } } } diff --git a/MediaBrowser.Api/HttpHandlers/YearHandler.cs b/MediaBrowser.Api/HttpHandlers/YearHandler.cs index dfde600e78..5e31c9689f 100644 --- a/MediaBrowser.Api/HttpHandlers/YearHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/YearHandler.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers /// public class YearHandler : BaseJsonHandler> { - protected override async Task> GetObjectToSerialize() + protected override Task> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); @@ -22,7 +22,7 @@ namespace MediaBrowser.Api.HttpHandlers string year = QueryString["year"]; - return await GetYear(parent, user, int.Parse(year)); + return GetYear(parent, user, int.Parse(year)); } /// @@ -46,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers // Get the original entity so that we can also supply the PrimaryImagePath return new IBNItem() { - Item = await Kernel.Instance.ItemController.GetYear(year), + Item = await Kernel.Instance.ItemController.GetYear(year).ConfigureAwait(false), BaseItemCount = count }; } diff --git a/MediaBrowser.Api/HttpHandlers/YearsHandler.cs b/MediaBrowser.Api/HttpHandlers/YearsHandler.cs index 6ce087f857..dcbbf6150e 100644 --- a/MediaBrowser.Api/HttpHandlers/YearsHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/YearsHandler.cs @@ -11,13 +11,13 @@ namespace MediaBrowser.Api.HttpHandlers { public class YearsHandler : BaseJsonHandler>> { - protected override async Task>> GetObjectToSerialize() + protected override Task>> GetObjectToSerialize() { Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder; Guid userId = Guid.Parse(QueryString["userid"]); User user = Kernel.Instance.Users.First(u => u.Id == userId); - return await GetAllYears(parent, user); + return GetAllYears(parent, user); } /// @@ -50,7 +50,7 @@ namespace MediaBrowser.Api.HttpHandlers } } - IEnumerable entities = await Task.WhenAll(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetYear(key); })); + IEnumerable entities = await Task.WhenAll(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetYear(key); })).ConfigureAwait(false); return entities.Select(e => new IBNItem() { Item = e, BaseItemCount = data[int.Parse(e.Name)] }); } diff --git a/MediaBrowser.Api/Plugin.cs b/MediaBrowser.Api/Plugin.cs index 7f764d6fb1..97d4a58652 100644 --- a/MediaBrowser.Api/Plugin.cs +++ b/MediaBrowser.Api/Plugin.cs @@ -22,13 +22,13 @@ namespace MediaBrowser.Api { var httpServer = Kernel.Instance.HttpServer; - httpServer.Where(ctx => ctx.Request.Url.LocalPath.IndexOf("/api/", StringComparison.OrdinalIgnoreCase) != -1).Subscribe(async (ctx) => + httpServer.Where(ctx => ctx.Request.Url.LocalPath.IndexOf("/api/", StringComparison.OrdinalIgnoreCase) != -1).Subscribe((ctx) => { BaseHandler handler = GetHandler(ctx); if (handler != null) { - await handler.ProcessRequest(ctx); + handler.ProcessRequest(ctx); } }); } diff --git a/MediaBrowser.ApiInteraction/ApiClient.cs b/MediaBrowser.ApiInteraction/ApiClient.cs index 58ccb627c0..f715e842e3 100644 --- a/MediaBrowser.ApiInteraction/ApiClient.cs +++ b/MediaBrowser.ApiInteraction/ApiClient.cs @@ -152,9 +152,9 @@ namespace MediaBrowser.ApiInteraction /// /// Gets an image stream based on a url /// - public async Task GetImageStreamAsync(string url) + public Task GetImageStreamAsync(string url) { - return await HttpClient.GetStreamAsync(url); + return HttpClient.GetStreamAsync(url); } /// @@ -169,7 +169,7 @@ namespace MediaBrowser.ApiInteraction url += "&id=" + id.ToString(); } - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream(stream); } @@ -182,7 +182,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/users"; - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>(stream); } @@ -195,7 +195,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/genres?userId=" + userId.ToString(); - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>>(stream); } @@ -208,7 +208,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/years?userId=" + userId.ToString(); - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>>(stream); } @@ -221,7 +221,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/itemlist?listtype=itemswithyear&userId=" + userId.ToString() + "&name=" + name; - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>(stream); } @@ -234,7 +234,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/itemlist?listtype=itemswithgenre&userId=" + userId.ToString() + "&name=" + name; - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>(stream); } @@ -247,7 +247,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name; - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>(stream); } @@ -262,7 +262,7 @@ namespace MediaBrowser.ApiInteraction url += "&persontype=" + personType; - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>(stream); } @@ -275,7 +275,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/studios?userId=" + userId.ToString(); - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>>(stream); } @@ -288,7 +288,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/itemlist?listtype=itemswithstudio&userId=" + userId.ToString() + "&name=" + name; - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>(stream); } @@ -301,7 +301,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/studio?userId=" + userId.ToString() + "&name=" + name; - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>(stream); } @@ -314,7 +314,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/genre?userId=" + userId.ToString() + "&name=" + name; - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>(stream); } @@ -327,7 +327,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/person?userId=" + userId.ToString() + "&name=" + name; - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>(stream); } @@ -340,7 +340,7 @@ namespace MediaBrowser.ApiInteraction { string url = ApiUrl + "/year?userId=" + userId.ToString() + "&year=" + year; - using (Stream stream = await HttpClient.GetStreamAsync(url)) + using (Stream stream = await HttpClient.GetStreamAsync(url).ConfigureAwait(false)) { return JsonSerializer.DeserializeFromStream>(stream); } diff --git a/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs index a8c7090f7d..9d9e2a0e03 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs @@ -1,5 +1,4 @@ -using System; -using System.IO; +using System.IO; using System.Threading.Tasks; namespace MediaBrowser.Common.Net.Handlers @@ -16,37 +15,7 @@ namespace MediaBrowser.Common.Net.Handlers public override Task GetContentType() { - return Task.Run(() => - { - string extension = Path.GetExtension(ResourcePath); - - if (extension.EndsWith("jpeg", StringComparison.OrdinalIgnoreCase) || extension.EndsWith("jpg", StringComparison.OrdinalIgnoreCase)) - { - return "image/jpeg"; - } - else if (extension.EndsWith("png", StringComparison.OrdinalIgnoreCase)) - { - return "image/png"; - } - else if (extension.EndsWith("ico", StringComparison.OrdinalIgnoreCase)) - { - return "image/ico"; - } - else if (extension.EndsWith("js", StringComparison.OrdinalIgnoreCase)) - { - return "application/x-javascript"; - } - else if (extension.EndsWith("css", StringComparison.OrdinalIgnoreCase)) - { - return "text/css"; - } - else if (extension.EndsWith("html", StringComparison.OrdinalIgnoreCase)) - { - return "text/html; charset=utf-8"; - } - - return "text/plain; charset=utf-8"; - }); + return Task.FromResult(MimeTypes.GetMimeType(ResourcePath)); } protected override Task WriteResponseToOutputStream(Stream stream) diff --git a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs index 7a4efdaf2b..19a1e7af7b 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs @@ -185,11 +185,11 @@ namespace MediaBrowser.Common.Net.Handlers // When serving a range request, we need to return status code 206 to indicate a partial response body StatusCode = SupportsByteRangeRequests && IsRangeRequest ? 206 : 200; - ctx.Response.ContentType = await GetContentType(); + ctx.Response.ContentType = await GetContentType().ConfigureAwait(false); TimeSpan cacheDuration = CacheDuration; - DateTime? lastDateModified = await GetLastDateModified(); + DateTime? lastDateModified = await GetLastDateModified().ConfigureAwait(false); if (ctx.Request.Headers.AllKeys.Contains("If-Modified-Since")) { @@ -205,13 +205,13 @@ namespace MediaBrowser.Common.Net.Handlers } } - await PrepareResponse(); + await PrepareResponse().ConfigureAwait(false); if (IsResponseValid) { bool compressResponse = ShouldCompressResponse(ctx.Response.ContentType) && ClientSupportsCompression; - await ProcessUncachedRequest(ctx, compressResponse, cacheDuration, lastDateModified); + await ProcessUncachedRequest(ctx, compressResponse, cacheDuration, lastDateModified).ConfigureAwait(false); } else { @@ -285,7 +285,7 @@ namespace MediaBrowser.Common.Net.Handlers outputStream = CompressedStream; } - await WriteResponseToOutputStream(outputStream); + await WriteResponseToOutputStream(outputStream).ConfigureAwait(false); } else { @@ -307,7 +307,7 @@ namespace MediaBrowser.Common.Net.Handlers /// protected virtual Task PrepareResponse() { - return Task.Run(() => { }); + return Task.FromResult(null); } protected abstract Task WriteResponseToOutputStream(Stream stream); @@ -359,7 +359,7 @@ namespace MediaBrowser.Common.Net.Handlers { DateTime? value = null; - return Task.Run(() => { return value; }); + return Task.FromResult(value); } private bool IsResponseValid diff --git a/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs index a3a47a4a33..6508535376 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs @@ -8,10 +8,7 @@ namespace MediaBrowser.Common.Net.Handlers { public override Task GetContentType() { - return Task.Run(() => - { - return MimeTypes.JsonMimeType; - }); + return Task.FromResult(MimeTypes.JsonMimeType); } private bool _ObjectToSerializeEnsured = false; @@ -21,7 +18,7 @@ namespace MediaBrowser.Common.Net.Handlers { if (!_ObjectToSerializeEnsured) { - _ObjectToSerialize = await GetObjectToSerialize(); + _ObjectToSerialize = await GetObjectToSerialize().ConfigureAwait(false); if (_ObjectToSerialize == null) { @@ -34,9 +31,9 @@ namespace MediaBrowser.Common.Net.Handlers protected abstract Task GetObjectToSerialize(); - protected override async Task PrepareResponse() + protected override Task PrepareResponse() { - await EnsureObjectToSerialize(); + return EnsureObjectToSerialize(); } protected async override Task WriteResponseToOutputStream(Stream stream) diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs index d8971dd97d..799abea9b4 100644 --- a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs @@ -102,33 +102,30 @@ namespace MediaBrowser.Common.Net.Handlers protected override Task GetLastDateModified() { - return Task.Run(() => - { - EnsureSourceStream(); + DateTime? value = null; - if (SourceStream == null) - { - return null; - } + EnsureSourceStream(); - return File.GetLastWriteTime(Path); - }); + if (SourceStream != null) + { + value = File.GetLastWriteTime(Path); + } + + return Task.FromResult(value); } public override Task GetContentType() { - return Task.Run(() => - { - return MimeTypes.GetMimeType(Path); - }); + return Task.FromResult(MimeTypes.GetMimeType(Path)); } protected override Task PrepareResponse() { - return Task.Run(() => { EnsureSourceStream(); }); + EnsureSourceStream(); + return Task.FromResult(null); } - protected async override Task WriteResponseToOutputStream(Stream stream) + protected override Task WriteResponseToOutputStream(Stream stream) { if (IsRangeRequest) { @@ -137,22 +134,22 @@ namespace MediaBrowser.Common.Net.Handlers // If the requested range is "0-" and we know the total length, we can optimize by avoiding having to buffer the content into memory if (requestedRange.Value == null && TotalContentLength != null) { - await ServeCompleteRangeRequest(requestedRange, stream); + return ServeCompleteRangeRequest(requestedRange, stream); } else if (TotalContentLength.HasValue) { // This will have to buffer a portion of the content into memory - await ServePartialRangeRequestWithKnownTotalContentLength(requestedRange, stream); + return ServePartialRangeRequestWithKnownTotalContentLength(requestedRange, stream); } else { // This will have to buffer the entire content into memory - await ServePartialRangeRequestWithUnknownTotalContentLength(requestedRange, stream); + return ServePartialRangeRequestWithUnknownTotalContentLength(requestedRange, stream); } } else { - await SourceStream.CopyToAsync(stream); + return SourceStream.CopyToAsync(stream); } } @@ -170,7 +167,7 @@ namespace MediaBrowser.Common.Net.Handlers /// Handles a range request of "bytes=0-" /// This will serve the complete content and add the content-range header /// - private async Task ServeCompleteRangeRequest(KeyValuePair requestedRange, Stream responseStream) + private Task ServeCompleteRangeRequest(KeyValuePair requestedRange, Stream responseStream) { long totalContentLength = TotalContentLength.Value; @@ -187,7 +184,7 @@ namespace MediaBrowser.Common.Net.Handlers SourceStream.Position = rangeStart; } - await SourceStream.CopyToAsync(responseStream); + return SourceStream.CopyToAsync(responseStream); } /// @@ -196,7 +193,7 @@ namespace MediaBrowser.Common.Net.Handlers private async Task ServePartialRangeRequestWithUnknownTotalContentLength(KeyValuePair requestedRange, Stream responseStream) { // Read the entire stream so that we can determine the length - byte[] bytes = await ReadBytes(SourceStream, 0, null); + byte[] bytes = await ReadBytes(SourceStream, 0, null).ConfigureAwait(false); long totalContentLength = bytes.LongLength; @@ -208,7 +205,7 @@ namespace MediaBrowser.Common.Net.Handlers HttpListenerContext.Response.ContentLength64 = rangeLength; HttpListenerContext.Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength); - await responseStream.WriteAsync(bytes, Convert.ToInt32(rangeStart), Convert.ToInt32(rangeLength)); + await responseStream.WriteAsync(bytes, Convert.ToInt32(rangeStart), Convert.ToInt32(rangeLength)).ConfigureAwait(false); } /// @@ -222,14 +219,14 @@ namespace MediaBrowser.Common.Net.Handlers long rangeLength = 1 + rangeEnd - rangeStart; // Only read the bytes we need - byte[] bytes = await ReadBytes(SourceStream, Convert.ToInt32(rangeStart), Convert.ToInt32(rangeLength)); + byte[] bytes = await ReadBytes(SourceStream, Convert.ToInt32(rangeStart), Convert.ToInt32(rangeLength)).ConfigureAwait(false); // Content-Length is the length of what we're serving, not the original content HttpListenerContext.Response.ContentLength64 = rangeLength; HttpListenerContext.Response.Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, totalContentLength); - await responseStream.WriteAsync(bytes, 0, Convert.ToInt32(rangeLength)); + await responseStream.WriteAsync(bytes, 0, Convert.ToInt32(rangeLength)).ConfigureAwait(false); } /// @@ -252,9 +249,9 @@ namespace MediaBrowser.Common.Net.Handlers using (MemoryStream ms = new MemoryStream()) { int read; - while ((read = await input.ReadAsync(buffer, 0, buffer.Length)) > 0) + while ((read = await input.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0) { - await ms.WriteAsync(buffer, 0, read); + await ms.WriteAsync(buffer, 0, read).ConfigureAwait(false); } return ms.ToArray(); } @@ -265,9 +262,9 @@ namespace MediaBrowser.Common.Net.Handlers using (MemoryStream ms = new MemoryStream()) { - int read = await input.ReadAsync(buffer, 0, buffer.Length); + int read = await input.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - await ms.WriteAsync(buffer, 0, read); + await ms.WriteAsync(buffer, 0, read).ConfigureAwait(false); return ms.ToArray(); } diff --git a/MediaBrowser.Common/UI/BaseApplication.cs b/MediaBrowser.Common/UI/BaseApplication.cs index 9ad2a749b6..27c64f4519 100644 --- a/MediaBrowser.Common/UI/BaseApplication.cs +++ b/MediaBrowser.Common/UI/BaseApplication.cs @@ -17,15 +17,15 @@ namespace MediaBrowser.Common.UI protected abstract IKernel InstantiateKernel(); protected abstract Window InstantiateMainWindow(); - protected async override void OnStartup(StartupEventArgs e) + protected override void OnStartup(StartupEventArgs e) { // Without this the app will shutdown after the splash screen closes this.ShutdownMode = ShutdownMode.OnExplicitShutdown; - await LoadKernel().ConfigureAwait(false); + LoadKernel(); } - private async Task LoadKernel() + private async void LoadKernel() { Kernel = InstantiateKernel(); @@ -40,9 +40,7 @@ namespace MediaBrowser.Common.UI await Kernel.Init(progress); - double seconds = (DateTime.Now - now).TotalSeconds; - - Logger.LogInfo("Kernel.Init completed in {0} seconds.", seconds); + Logger.LogInfo("Kernel.Init completed in {0} seconds.", (DateTime.Now - now).TotalSeconds); splash.Close(); this.ShutdownMode = System.Windows.ShutdownMode.OnLastWindowClose; diff --git a/MediaBrowser.Controller/FFMpeg/FFProbe.cs b/MediaBrowser.Controller/FFMpeg/FFProbe.cs index f5364821ce..1a0685a7a6 100644 --- a/MediaBrowser.Controller/FFMpeg/FFProbe.cs +++ b/MediaBrowser.Controller/FFMpeg/FFProbe.cs @@ -18,10 +18,7 @@ namespace MediaBrowser.Controller.FFMpeg // Use try catch to avoid having to use File.Exists try { - using (FileStream stream = File.OpenRead(outputCachePath)) - { - return JsonSerializer.DeserializeFromStream(stream); - } + return GetCachedResult(outputCachePath); } catch (FileNotFoundException) { @@ -29,7 +26,12 @@ namespace MediaBrowser.Controller.FFMpeg await Run(item.Path, outputCachePath).ConfigureAwait(false); - using (FileStream stream = File.OpenRead(outputCachePath)) + return GetCachedResult(item.Path); + } + + public static FFProbeResult GetCachedResult(string path) + { + using (FileStream stream = File.OpenRead(path)) { return JsonSerializer.DeserializeFromStream(stream); } @@ -40,10 +42,7 @@ namespace MediaBrowser.Controller.FFMpeg // Use try catch to avoid having to use File.Exists try { - using (FileStream stream = File.OpenRead(outputCachePath)) - { - return JsonSerializer.DeserializeFromStream(stream); - } + return GetCachedResult(outputCachePath); } catch (FileNotFoundException) { @@ -51,10 +50,7 @@ namespace MediaBrowser.Controller.FFMpeg await Run(item.Path, outputCachePath).ConfigureAwait(false); - using (FileStream stream = File.OpenRead(outputCachePath)) - { - return JsonSerializer.DeserializeFromStream(stream); - } + return GetCachedResult(item.Path); } private async static Task Run(string input, string output) diff --git a/MediaBrowser.Controller/IO/DirectoryWatchers.cs b/MediaBrowser.Controller/IO/DirectoryWatchers.cs index 0a96990bfe..10d11385ee 100644 --- a/MediaBrowser.Controller/IO/DirectoryWatchers.cs +++ b/MediaBrowser.Controller/IO/DirectoryWatchers.cs @@ -86,7 +86,7 @@ namespace MediaBrowser.Controller.IO await ProcessPathChanges(paths).ConfigureAwait(false); } - private async Task ProcessPathChanges(IEnumerable paths) + private Task ProcessPathChanges(IEnumerable paths) { List itemsToRefresh = new List(); @@ -105,11 +105,11 @@ namespace MediaBrowser.Controller.IO return folder != null && folder.IsRoot; })) { - await Kernel.Instance.ReloadRoot().ConfigureAwait(false); + return Kernel.Instance.ReloadRoot(); } else { - await Task.WhenAll(itemsToRefresh.Select(i => Kernel.Instance.ReloadItem(i))).ConfigureAwait(false); + return Task.WhenAll(itemsToRefresh.Select(i => Kernel.Instance.ReloadItem(i))); } } diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index a24571d87a..fa2baafbcf 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -68,21 +68,17 @@ namespace MediaBrowser.Controller public async override Task Init(IProgress progress) { - await Task.Run(async () => - { - await base.Init(progress).ConfigureAwait(false); + ExtractFFMpeg(); + + await base.Init(progress).ConfigureAwait(false); - progress.Report(new TaskProgress() { Description = "Loading Users", PercentComplete = 15 }); - ReloadUsers(); + progress.Report(new TaskProgress() { Description = "Loading Users", PercentComplete = 15 }); + ReloadUsers(); - progress.Report(new TaskProgress() { Description = "Extracting FFMpeg", PercentComplete = 20 }); - await ExtractFFMpeg().ConfigureAwait(false); + progress.Report(new TaskProgress() { Description = "Loading Media Library", PercentComplete = 25 }); + await ReloadRoot().ConfigureAwait(false); - progress.Report(new TaskProgress() { Description = "Loading Media Library", PercentComplete = 25 }); - await ReloadRoot().ConfigureAwait(false); - - progress.Report(new TaskProgress() { Description = "Loading Complete", PercentComplete = 100 }); - }).ConfigureAwait(false); + progress.Report(new TaskProgress() { Description = "Loading Complete", PercentComplete = 100 }); } protected override void OnComposablePartsLoaded() @@ -245,22 +241,21 @@ namespace MediaBrowser.Controller continue; } - await provider.Fetch(item, args).ConfigureAwait(false); + await provider.FetchAsync(item, args).ConfigureAwait(false); } } + private void ExtractFFMpeg() + { + ExtractFFMpeg(ApplicationPaths.FFMpegPath); + ExtractFFMpeg(ApplicationPaths.FFProbePath); + } + /// /// Run these during Init. /// Can't run do this on-demand because there will be multiple workers accessing them at once and we'd have to lock them /// - private async Task ExtractFFMpeg() - { - // FFMpeg.exe - await ExtractFFMpeg(ApplicationPaths.FFMpegPath).ConfigureAwait(false); - await ExtractFFMpeg(ApplicationPaths.FFProbePath).ConfigureAwait(false); - } - - private async Task ExtractFFMpeg(string exe) + private async void ExtractFFMpeg(string exe) { if (File.Exists(exe)) { diff --git a/MediaBrowser.Controller/Library/ItemController.cs b/MediaBrowser.Controller/Library/ItemController.cs index 9fd77fb0d9..f182f43f01 100644 --- a/MediaBrowser.Controller/Library/ItemController.cs +++ b/MediaBrowser.Controller/Library/ItemController.cs @@ -116,14 +116,17 @@ namespace MediaBrowser.Controller.Library if (item != null) { - await Kernel.Instance.ExecuteMetadataProviders(item, args); + await Kernel.Instance.ExecuteMetadataProviders(item, args).ConfigureAwait(false); - var folder = item as Folder; - - if (folder != null) + if (item.IsFolder) { // If it's a folder look for child entities - await AttachChildren(folder, fileSystemChildren).ConfigureAwait(false); + (item as Folder).Children = (await Task.WhenAll(GetChildren(item as Folder, fileSystemChildren)).ConfigureAwait(false)) + .Where(i => i != null).OrderBy(f => + { + return string.IsNullOrEmpty(f.SortName) ? f.Name : f.SortName; + + }); } } @@ -133,27 +136,18 @@ namespace MediaBrowser.Controller.Library /// /// Finds child BaseItems for a given Folder /// - private async Task AttachChildren(Folder folder, LazyFileInfo[] fileSystemChildren) + private Task[] GetChildren(Folder folder, LazyFileInfo[] fileSystemChildren) { - int count = fileSystemChildren.Length; - - Task[] tasks = new Task[count]; + Task[] tasks = new Task[fileSystemChildren.Length]; - for (int i = 0; i < count; i++) + for (int i = 0; i < fileSystemChildren.Length; i++) { var child = fileSystemChildren[i]; tasks[i] = GetItem(child.Path, folder, child.FileInfo); } - BaseItem[] baseItemChildren = await Task.WhenAll(tasks).ConfigureAwait(false); - - // Sort them - folder.Children = baseItemChildren.Where(i => i != null).OrderBy(f => - { - return string.IsNullOrEmpty(f.SortName) ? f.Name : f.SortName; - - }); + return tasks; } /// @@ -216,41 +210,41 @@ namespace MediaBrowser.Controller.Library /// /// Gets a Person /// - public async Task GetPerson(string name) + public Task GetPerson(string name) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.PeoplePath, name); - return await GetImagesByNameItem(path, name).ConfigureAwait(false); + return GetImagesByNameItem(path, name); } /// /// Gets a Studio /// - public async Task GetStudio(string name) + public Task GetStudio(string name) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.StudioPath, name); - return await GetImagesByNameItem(path, name).ConfigureAwait(false); + return GetImagesByNameItem(path, name); } /// /// Gets a Genre /// - public async Task GetGenre(string name) + public Task GetGenre(string name) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.GenrePath, name); - return await GetImagesByNameItem(path, name).ConfigureAwait(false); + return GetImagesByNameItem(path, name); } /// /// Gets a Year /// - public async Task GetYear(int value) + public Task GetYear(int value) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.YearPath, value.ToString()); - return await GetImagesByNameItem(path, value.ToString()).ConfigureAwait(false); + return GetImagesByNameItem(path, value.ToString()); } private ConcurrentDictionary ImagesByNameItemCache = new ConcurrentDictionary(); @@ -258,7 +252,7 @@ namespace MediaBrowser.Controller.Library /// /// Generically retrieves an IBN item /// - private async Task GetImagesByNameItem(string path, string name) + private Task GetImagesByNameItem(string path, string name) where T : BaseEntity, new() { string key = path.ToLower(); @@ -266,12 +260,10 @@ namespace MediaBrowser.Controller.Library // Look for it in the cache, if it's not there, create it if (!ImagesByNameItemCache.ContainsKey(key)) { - T obj = await CreateImagesByNameItem(path, name).ConfigureAwait(false); - ImagesByNameItemCache[key] = obj; - return obj; + ImagesByNameItemCache[key] = CreateImagesByNameItem(path, name); } - return ImagesByNameItemCache[key] as T; + return ImagesByNameItemCache[key] as Task; } /// diff --git a/MediaBrowser.Controller/Providers/AudioInfoProvider.cs b/MediaBrowser.Controller/Providers/AudioInfoProvider.cs index 85a030ddf5..64b397a697 100644 --- a/MediaBrowser.Controller/Providers/AudioInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/AudioInfoProvider.cs @@ -23,16 +23,22 @@ namespace MediaBrowser.Controller.Providers get { return MetadataProviderPriority.First; } } - public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) + public async override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) { Audio audio = item as Audio; - string outputDirectory = Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, item.Id.ToString().Substring(0, 1)); + Fetch(audio, await FFProbe.Run(audio, GetFFProbeOutputPath(item)).ConfigureAwait(false)); + } - string outputPath = Path.Combine(outputDirectory, item.Id + "-" + item.DateModified.Ticks + ".js"); + private string GetFFProbeOutputPath(BaseEntity item) + { + string outputDirectory = Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, item.Id.ToString().Substring(0, 1)); - FFProbeResult data = await FFProbe.Run(audio, outputPath).ConfigureAwait(false); + return Path.Combine(outputDirectory, item.Id + "-" + item.DateModified.Ticks + ".js"); + } + private void Fetch(Audio audio, FFProbeResult data) + { MediaStream stream = data.streams.First(s => s.codec_type.Equals("audio", StringComparison.OrdinalIgnoreCase)); string bitrate = null; diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs index 6222eec5f7..5c536913ec 100644 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs @@ -31,7 +31,7 @@ namespace MediaBrowser.Controller.Providers } } - public abstract Task Fetch(BaseEntity item, ItemResolveEventArgs args); + public abstract Task FetchAsync(BaseEntity item, ItemResolveEventArgs args); public abstract MetadataProviderPriority Priority { get; } } diff --git a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs index cba41f780a..2249fb6a50 100644 --- a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs +++ b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs @@ -19,14 +19,16 @@ namespace MediaBrowser.Controller.Providers get { return MetadataProviderPriority.First; } } - public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) + public override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) { var metadataFile = args.GetFileSystemEntryByName("folder.xml"); if (metadataFile.HasValue) { - await Task.Run(() => { new FolderXmlParser().Fetch(item as Folder, metadataFile.Value.Path); }).ConfigureAwait(false); + return Task.Run(() => { new FolderXmlParser().Fetch(item as Folder, metadataFile.Value.Path); }); } + + return Task.FromResult(null); } } } diff --git a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs index 2a5e0394c4..59b58474fc 100644 --- a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs +++ b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs @@ -21,24 +21,23 @@ namespace MediaBrowser.Controller.Providers get { return MetadataProviderPriority.First; } } - public override Task Fetch(BaseEntity item, ItemResolveEventArgs args) + public override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) { - return Task.Run(() => + if (args.IsDirectory) { - if (args.IsDirectory) + var baseItem = item as BaseItem; + + if (baseItem != null) + { + return Task.Run(() => { PopulateImages(baseItem, args); }); + } + else { - var baseItem = item as BaseItem; - - if (baseItem != null) - { - PopulateImages(baseItem, args); - } - else - { - PopulateImages(item, args); - } + return Task.Run(() => { PopulateImages(item, args); }); } - }); + } + + return Task.FromResult(null); } /// @@ -49,7 +48,7 @@ namespace MediaBrowser.Controller.Providers for (int i = 0; i < args.FileSystemChildren.Length; i++) { var file = args.FileSystemChildren[i]; - + string filePath = file.Path; string ext = Path.GetExtension(filePath); diff --git a/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs b/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs index c023edb9af..18ca261dca 100644 --- a/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs +++ b/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs @@ -20,10 +20,8 @@ namespace MediaBrowser.Controller.Providers get { return MetadataProviderPriority.First; } } - public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) + public async override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) { - BaseItem baseItem = item as BaseItem; - var trailerPath = args.GetFileSystemEntryByName("trailers", true); if (trailerPath.HasValue) @@ -36,9 +34,7 @@ namespace MediaBrowser.Controller.Providers { string file = allFiles[i]; - BaseItem child = await Kernel.Instance.ItemController.GetItem(file).ConfigureAwait(false); - - Video video = child as Video; + Video video = await Kernel.Instance.ItemController.GetItem(file).ConfigureAwait(false) as Video; if (video != null) { @@ -46,7 +42,7 @@ namespace MediaBrowser.Controller.Providers } } - baseItem.LocalTrailers = localTrailers; + (item as BaseItem).LocalTrailers = localTrailers; } } } diff --git a/MediaBrowser.Controller/Providers/VideoInfoProvider.cs b/MediaBrowser.Controller/Providers/VideoInfoProvider.cs index 5f88aa1cbb..96ca8ed358 100644 --- a/MediaBrowser.Controller/Providers/VideoInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/VideoInfoProvider.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Providers get { return MetadataProviderPriority.Second; } } - public override async Task Fetch(BaseEntity item, ItemResolveEventArgs args) + public override async Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) { Video video = item as Video; @@ -39,11 +39,14 @@ namespace MediaBrowser.Controller.Providers return; } - string outputDirectory = Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeVideoCacheDirectory, item.Id.ToString().Substring(0, 1)); + Fetch(video, await FFProbe.Run(video, GetFFProbeOutputPath(video)).ConfigureAwait(false)); + } - string outputPath = Path.Combine(outputDirectory, item.Id + "-" + item.DateModified.Ticks + ".js"); + private string GetFFProbeOutputPath(Video item) + { + string outputDirectory = Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeVideoCacheDirectory, item.Id.ToString().Substring(0, 1)); - FFProbeResult data = await FFProbe.Run(video, outputPath).ConfigureAwait(false); + return Path.Combine(outputDirectory, item.Id + "-" + item.DateModified.Ticks + ".js"); } private void Fetch(Video video, FFProbeResult data) diff --git a/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs b/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs index f5eecbcde9..d39ec60829 100644 --- a/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Threading.Tasks; using System.Xml; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs b/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs index 8d7a9af7de..b977a46e72 100644 --- a/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs +++ b/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs @@ -21,14 +21,16 @@ namespace MediaBrowser.Movies.Providers get { return MetadataProviderPriority.First; } } - public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) + public override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) { var metadataFile = args.GetFileSystemEntryByName("movie.xml"); if (metadataFile.HasValue) { - await Task.Run(() => { new BaseItemXmlParser().Fetch(item as Movie, metadataFile.Value.Path); }).ConfigureAwait(false); + return Task.Run(() => { new BaseItemXmlParser().Fetch(item as Movie, metadataFile.Value.Path); }); } + + return Task.FromResult(null); } } } diff --git a/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs b/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs index b98cee2efe..300adb7e1b 100644 --- a/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs +++ b/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs @@ -1,5 +1,4 @@ -using System; -using System.ComponentModel.Composition; +using System.ComponentModel.Composition; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -23,7 +22,7 @@ namespace MediaBrowser.TV.Providers get { return MetadataProviderPriority.First; } } - public override Task Fetch(BaseEntity item, ItemResolveEventArgs args) + public override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) { return Task.Run(() => { diff --git a/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs b/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs index 077096859d..bab746e4b7 100644 --- a/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs +++ b/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs @@ -22,24 +22,21 @@ namespace MediaBrowser.TV.Providers get { return MetadataProviderPriority.First; } } - public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) + public override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) { - await Task.Run(() => - { - string metadataFolder = Path.Combine(args.Parent.Path, "metadata"); - - Episode episode = item as Episode; - - string episodeFileName = Path.GetFileName(episode.Path); + return Fetch(item, args); + } - string metadataFile = Path.Combine(metadataFolder, Path.ChangeExtension(episodeFileName, ".xml")); + private Task Fetch(BaseEntity item, ItemResolveEventArgs args) + { + string metadataFolder = Path.Combine(args.Parent.Path, "metadata"); - FetchMetadata(episode, args.Parent as Season, metadataFile); + string metadataFile = Path.Combine(metadataFolder, Path.ChangeExtension(Path.GetFileName(args.Path), ".xml")); - }).ConfigureAwait(false); + return FetchMetadata(item as Episode, args.Parent as Season, metadataFile); } - private void FetchMetadata(Episode item, Season season, string metadataFile) + private Task FetchMetadata(Episode item, Season season, string metadataFile) { if (season == null) { @@ -47,18 +44,18 @@ namespace MediaBrowser.TV.Providers // Need to validate it the slow way if (!File.Exists(metadataFile)) { - return; + return Task.FromResult(null); } } else { if (!season.ContainsMetadataFile(metadataFile)) { - return; + return Task.FromResult(null); } } - new EpisodeXmlParser().Fetch(item, metadataFile); + return Task.Run(() => { new EpisodeXmlParser().Fetch(item, metadataFile); }); } } } diff --git a/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs b/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs index f28b0c1d02..d2f60461df 100644 --- a/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs +++ b/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs @@ -21,14 +21,16 @@ namespace MediaBrowser.TV.Providers get { return MetadataProviderPriority.First; } } - public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) + public override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) { var metadataFile = args.GetFileSystemEntryByName("series.xml"); if (metadataFile.HasValue) { - await Task.Run(() => { new SeriesXmlParser().Fetch(item as Series, metadataFile.Value.Path); }).ConfigureAwait(false); + return Task.Run(() => { new SeriesXmlParser().Fetch(item as Series, metadataFile.Value.Path); }); } + + return Task.FromResult(null); } } } -- cgit v1.2.3 From 4752d12aaa0aa3dcb6bb476910a7072556c70f85 Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Tue, 4 Sep 2012 15:23:15 -0400 Subject: Switched date operations to utc --- MediaBrowser.Api/HttpHandlers/ImageHandler.cs | 2 +- .../HttpHandlers/PluginConfigurationHandler.cs | 33 ++++++++++++++++++++-- .../HttpHandlers/ServerConfigurationHandler.cs | 17 ++++++++++- MediaBrowser.Common/Net/Handlers/BaseHandler.cs | 19 ++++++++----- .../Net/Handlers/StaticFileHandler.cs | 2 +- MediaBrowser.Common/Plugins/BasePlugin.cs | 2 +- MediaBrowser.Common/UI/BaseApplication.cs | 4 +-- MediaBrowser.Controller/IO/FileData.cs | 8 +++--- MediaBrowser.Controller/Library/ItemController.cs | 4 +-- .../Providers/AudioInfoProvider.cs | 2 +- .../Resolvers/BaseItemResolver.cs | 12 ++++---- MediaBrowser.Controller/Xml/BaseItemXmlParser.cs | 4 +-- MediaBrowser.Model/Entities/BaseItem.cs | 2 +- 13 files changed, 79 insertions(+), 32 deletions(-) (limited to 'MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs') diff --git a/MediaBrowser.Api/HttpHandlers/ImageHandler.cs b/MediaBrowser.Api/HttpHandlers/ImageHandler.cs index 470e39cd23..c45d20b7cc 100644 --- a/MediaBrowser.Api/HttpHandlers/ImageHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/ImageHandler.cs @@ -136,7 +136,7 @@ namespace MediaBrowser.Api.HttpHandlers return null; } - return File.GetLastWriteTime(await GetImagePath().ConfigureAwait(false)); + return File.GetLastWriteTimeUtc(await GetImagePath().ConfigureAwait(false)); } private int? Height diff --git a/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs b/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs index 38c039275c..bf06cbdb0c 100644 --- a/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; +using MediaBrowser.Common.Plugins; using MediaBrowser.Controller; using MediaBrowser.Model.Plugins; @@ -9,13 +10,39 @@ namespace MediaBrowser.Api.HttpHandlers { public class PluginConfigurationHandler : BaseSerializationHandler { + private BasePlugin _Plugin = null; + private BasePlugin Plugin + { + get + { + if (_Plugin == null) + { + string name = QueryString["assemblyfilename"]; + + _Plugin = Kernel.Instance.Plugins.First(p => p.AssemblyFileName.Equals(name, StringComparison.OrdinalIgnoreCase)); + } + + return _Plugin; + } + } + protected override Task GetObjectToSerialize() { - string name = QueryString["assemblyfilename"]; + return Task.FromResult(Plugin.Configuration); + } - BasePluginConfiguration config = Kernel.Instance.Plugins.First(p => p.AssemblyFileName.Equals(name, StringComparison.OrdinalIgnoreCase)).Configuration; + public override TimeSpan CacheDuration + { + get + { + return TimeSpan.FromDays(7); + } + } - return Task.FromResult(config); + protected override Task GetLastDateModified() + { + return Task.FromResult(Plugin.ConfigurationDateLastModified); } + } } diff --git a/MediaBrowser.Api/HttpHandlers/ServerConfigurationHandler.cs b/MediaBrowser.Api/HttpHandlers/ServerConfigurationHandler.cs index 175876b4ca..a26a6daf79 100644 --- a/MediaBrowser.Api/HttpHandlers/ServerConfigurationHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/ServerConfigurationHandler.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System; +using System.IO; +using System.Threading.Tasks; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.Configuration; @@ -11,5 +13,18 @@ namespace MediaBrowser.Api.HttpHandlers { return Task.FromResult(Kernel.Instance.Configuration); } + + public override TimeSpan CacheDuration + { + get + { + return TimeSpan.FromDays(7); + } + } + + protected override Task GetLastDateModified() + { + return Task.FromResult(File.GetLastWriteTimeUtc(Kernel.Instance.ApplicationPaths.SystemConfigurationFilePath)); + } } } diff --git a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs index 19a1e7af7b..2462833ffb 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs @@ -167,7 +167,8 @@ namespace MediaBrowser.Common.Net.Handlers { HttpListenerContext = ctx; - Logger.LogInfo("Http Server received request at: " + ctx.Request.Url.ToString()); + string url = ctx.Request.Url.ToString(); + Logger.LogInfo("Http Server received request at: " + url); Logger.LogInfo("Http Headers: " + string.Join(",", ctx.Request.Headers.AllKeys.Select(k => k + "=" + ctx.Request.Headers[k]))); ctx.Response.AddHeader("Access-Control-Allow-Origin", "*"); @@ -195,10 +196,10 @@ namespace MediaBrowser.Common.Net.Handlers { DateTime ifModifiedSince; - if (DateTime.TryParse(ctx.Request.Headers["If-Modified-Since"].Replace(" GMT", string.Empty), out ifModifiedSince)) + if (DateTime.TryParse(ctx.Request.Headers["If-Modified-Since"], out ifModifiedSince)) { // If the cache hasn't expired yet just return a 304 - if (IsCacheValid(ifModifiedSince, cacheDuration, lastDateModified)) + if (IsCacheValid(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified)) { StatusCode = 304; } @@ -207,6 +208,8 @@ namespace MediaBrowser.Common.Net.Handlers await PrepareResponse().ConfigureAwait(false); + Logger.LogInfo("Responding with status code {0} for url {1}", StatusCode, url); + if (IsResponseValid) { bool compressResponse = ShouldCompressResponse(ctx.Response.ContentType) && ClientSupportsCompression; @@ -295,10 +298,12 @@ namespace MediaBrowser.Common.Net.Handlers private void CacheResponse(HttpListenerResponse response, TimeSpan duration, DateTime? dateModified) { - DateTime lastModified = dateModified ?? DateTime.Now; + DateTime now = DateTime.UtcNow; + + DateTime lastModified = dateModified ?? now; response.Headers[HttpResponseHeader.CacheControl] = "public, max-age=" + Convert.ToInt32(duration.TotalSeconds); - response.Headers[HttpResponseHeader.Expires] = DateTime.Now.Add(duration).ToString("r"); + response.Headers[HttpResponseHeader.Expires] = now.Add(duration).ToString("r"); response.Headers[HttpResponseHeader.LastModified] = lastModified.ToString("r"); } @@ -334,7 +339,7 @@ namespace MediaBrowser.Common.Net.Handlers DateTime cacheExpirationDate = ifModifiedSince.Add(cacheDuration); - if (DateTime.Now < cacheExpirationDate) + if (DateTime.UtcNow < cacheExpirationDate) { return true; } @@ -347,7 +352,7 @@ namespace MediaBrowser.Common.Net.Handlers /// private DateTime NormalizeDateForComparison(DateTime date) { - return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second); + return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Kind); } protected virtual long? GetTotalContentLength() diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs index 799abea9b4..884e398bfd 100644 --- a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs @@ -108,7 +108,7 @@ namespace MediaBrowser.Common.Net.Handlers if (SourceStream != null) { - value = File.GetLastWriteTime(Path); + value = File.GetLastWriteTimeUtc(Path); } return Task.FromResult(value); diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs index c03964e6f7..2b7559c59d 100644 --- a/MediaBrowser.Common/Plugins/BasePlugin.cs +++ b/MediaBrowser.Common/Plugins/BasePlugin.cs @@ -83,7 +83,7 @@ namespace MediaBrowser.Common.Plugins { if (File.Exists(ConfigurationFilePath)) { - _ConfigurationDateLastModified = File.GetLastWriteTime(ConfigurationFilePath); + _ConfigurationDateLastModified = File.GetLastWriteTimeUtc(ConfigurationFilePath); } } diff --git a/MediaBrowser.Common/UI/BaseApplication.cs b/MediaBrowser.Common/UI/BaseApplication.cs index c7b2916b57..4cbc57c0d3 100644 --- a/MediaBrowser.Common/UI/BaseApplication.cs +++ b/MediaBrowser.Common/UI/BaseApplication.cs @@ -35,11 +35,11 @@ namespace MediaBrowser.Common.UI try { - DateTime now = DateTime.Now; + DateTime now = DateTime.UtcNow; await Kernel.Init(progress); - Logger.LogInfo("Kernel.Init completed in {0} seconds.", (DateTime.Now - now).TotalSeconds); + Logger.LogInfo("Kernel.Init completed in {0} seconds.", (DateTime.UtcNow - now).TotalSeconds); splash.Close(); this.ShutdownMode = System.Windows.ShutdownMode.OnLastWindowClose; diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs index b9bc7ea757..75069d4d58 100644 --- a/MediaBrowser.Controller/IO/FileData.cs +++ b/MediaBrowser.Controller/IO/FileData.cs @@ -188,7 +188,7 @@ namespace MediaBrowser.Controller.IO } } - public DateTime CreationTime + public DateTime CreationTimeUtc { get { @@ -196,7 +196,7 @@ namespace MediaBrowser.Controller.IO } } - public DateTime LastAccessTime + public DateTime LastAccessTimeUtc { get { @@ -204,7 +204,7 @@ namespace MediaBrowser.Controller.IO } } - public DateTime LastWriteTime + public DateTime LastWriteTimeUtc { get { @@ -216,7 +216,7 @@ namespace MediaBrowser.Controller.IO { long highBits = filetime.dwHighDateTime; highBits = highBits << 32; - return DateTime.FromFileTime(highBits + (long)filetime.dwLowDateTime); + return DateTime.FromFileTimeUtc(highBits + (long)filetime.dwLowDateTime); } public string Path { get; set; } diff --git a/MediaBrowser.Controller/Library/ItemController.cs b/MediaBrowser.Controller/Library/ItemController.cs index 26468c6565..a09f634012 100644 --- a/MediaBrowser.Controller/Library/ItemController.cs +++ b/MediaBrowser.Controller/Library/ItemController.cs @@ -268,8 +268,8 @@ namespace MediaBrowser.Controller.Library Directory.CreateDirectory(path); } - item.DateCreated = Directory.GetCreationTime(path); - item.DateModified = Directory.GetLastAccessTime(path); + item.DateCreated = Directory.GetCreationTimeUtc(path); + item.DateModified = Directory.GetLastWriteTimeUtc(path); ItemResolveEventArgs args = new ItemResolveEventArgs(); args.FileInfo = FileData.GetFileData(path); diff --git a/MediaBrowser.Controller/Providers/AudioInfoProvider.cs b/MediaBrowser.Controller/Providers/AudioInfoProvider.cs index 709589cdb4..355344662c 100644 --- a/MediaBrowser.Controller/Providers/AudioInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/AudioInfoProvider.cs @@ -276,7 +276,7 @@ namespace MediaBrowser.Controller.Providers if (DateTime.TryParse(val, out i)) { - return i; + return i.ToUniversalTime(); } } diff --git a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs index 643580b31c..1f5a6fe831 100644 --- a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs +++ b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs @@ -88,20 +88,20 @@ namespace MediaBrowser.Controller.Resolvers if (childData != null) { - item.DateCreated = childData.Value.CreationTime; - item.DateModified = childData.Value.LastWriteTime; + item.DateCreated = childData.Value.CreationTimeUtc; + item.DateModified = childData.Value.LastWriteTimeUtc; } else { WIN32_FIND_DATA fileData = FileData.GetFileData(item.Path); - item.DateCreated = fileData.CreationTime; - item.DateModified = fileData.LastWriteTime; + item.DateCreated = fileData.CreationTimeUtc; + item.DateModified = fileData.LastWriteTimeUtc; } } else { - item.DateCreated = args.FileInfo.CreationTime; - item.DateModified = args.FileInfo.LastWriteTime; + item.DateCreated = args.FileInfo.CreationTimeUtc; + item.DateModified = args.FileInfo.LastWriteTimeUtc; } } } diff --git a/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs b/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs index d5fdf640c8..612ba4c7cb 100644 --- a/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.Controller.Xml DateTime added; if (DateTime.TryParse(reader.ReadElementContentAsString() ?? string.Empty, out added)) { - item.DateCreated = added; + item.DateCreated = added.ToUniversalTime(); } break; @@ -232,7 +232,7 @@ namespace MediaBrowser.Controller.Xml if (DateTime.TryParse(firstAired, out airDate) && airDate.Year > 1850) { - item.PremiereDate = airDate; + item.PremiereDate = airDate.ToUniversalTime(); item.ProductionYear = airDate.Year; } } diff --git a/MediaBrowser.Model/Entities/BaseItem.cs b/MediaBrowser.Model/Entities/BaseItem.cs index 808ef5ad89..7751207425 100644 --- a/MediaBrowser.Model/Entities/BaseItem.cs +++ b/MediaBrowser.Model/Entities/BaseItem.cs @@ -131,7 +131,7 @@ namespace MediaBrowser.Model.Entities /// public bool IsRecentlyAdded(User user) { - return (DateTime.Now - DateCreated).TotalDays < user.RecentItemDays; + return (DateTime.UtcNow - DateCreated).TotalDays < user.RecentItemDays; } public void AddPerson(PersonInfo person) -- cgit v1.2.3 From 93b42641d23cf675b74d4bdaf6d6ece07fbb8900 Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Sat, 8 Sep 2012 10:52:13 -0400 Subject: Switched to MEF to register http handlers --- MediaBrowser.Api/ApiService.cs | 6 ++ MediaBrowser.Api/HttpHandlers/AudioHandler.cs | 13 ++- MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs | 12 +-- MediaBrowser.Api/HttpHandlers/GenreHandler.cs | 8 ++ MediaBrowser.Api/HttpHandlers/GenresHandler.cs | 8 ++ MediaBrowser.Api/HttpHandlers/ImageHandler.cs | 8 ++ MediaBrowser.Api/HttpHandlers/ItemHandler.cs | 8 ++ MediaBrowser.Api/HttpHandlers/ItemListHandler.cs | 8 ++ MediaBrowser.Api/HttpHandlers/PersonHandler.cs | 8 ++ .../HttpHandlers/PluginAssemblyHandler.cs | 13 ++- .../HttpHandlers/PluginConfigurationHandler.cs | 16 ++- MediaBrowser.Api/HttpHandlers/PluginsHandler.cs | 16 ++- .../HttpHandlers/ServerConfigurationHandler.cs | 16 ++- MediaBrowser.Api/HttpHandlers/StudioHandler.cs | 8 ++ MediaBrowser.Api/HttpHandlers/StudiosHandler.cs | 8 ++ .../HttpHandlers/UserAuthenticationHandler.cs | 8 ++ MediaBrowser.Api/HttpHandlers/UserHandler.cs | 8 ++ MediaBrowser.Api/HttpHandlers/UsersHandler.cs | 8 ++ MediaBrowser.Api/HttpHandlers/VideoHandler.cs | 15 ++- MediaBrowser.Api/HttpHandlers/WeatherHandler.cs | 14 ++- MediaBrowser.Api/HttpHandlers/YearHandler.cs | 8 ++ MediaBrowser.Api/HttpHandlers/YearsHandler.cs | 8 ++ MediaBrowser.Api/Plugin.cs | 120 +-------------------- MediaBrowser.Common/Kernel/BaseKernel.cs | 32 ++++++ MediaBrowser.Common/Net/Handlers/BaseHandler.cs | 8 +- .../Net/Handlers/StaticFileHandler.cs | 9 +- 26 files changed, 240 insertions(+), 154 deletions(-) (limited to 'MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs') diff --git a/MediaBrowser.Api/ApiService.cs b/MediaBrowser.Api/ApiService.cs index ab12a350f4..6b3c00ee25 100644 --- a/MediaBrowser.Api/ApiService.cs +++ b/MediaBrowser.Api/ApiService.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using System.Net; namespace MediaBrowser.Api { @@ -374,5 +375,10 @@ namespace MediaBrowser.Api LastLoginDate = user.LastLoginDate }; } + + public static bool IsApiUrlMatch(string url, HttpListenerRequest request) + { + return request.Url.LocalPath.EndsWith(url, StringComparison.OrdinalIgnoreCase); + } } } diff --git a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs index f0d86ab37e..a01368635c 100644 --- a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs @@ -1,15 +1,24 @@ -using System.Collections.Generic; +using MediaBrowser.Common.Net.Handlers; +using MediaBrowser.Model.Entities; +using System.Collections.Generic; +using System.ComponentModel.Composition; using System.IO; using System.Linq; -using MediaBrowser.Model.Entities; +using System.Net; namespace MediaBrowser.Api.HttpHandlers { /// /// Supported output formats are: mp3,flac,ogg,wav,asf,wma,aac /// + [Export(typeof(BaseHandler))] public class AudioHandler : BaseMediaHandler