diff --git a/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs b/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs index 6cc4626ea..dcc974413 100644 --- a/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs +++ b/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs @@ -10,11 +10,17 @@ namespace Emby.Common.Implementations.EnvironmentInfo public class EnvironmentInfo : IEnvironmentInfo { public MediaBrowser.Model.System.Architecture? CustomArchitecture { get; set; } + public MediaBrowser.Model.System.OperatingSystem? CustomOperatingSystem { get; set; } public MediaBrowser.Model.System.OperatingSystem OperatingSystem { get { + if (CustomOperatingSystem.HasValue) + { + return CustomOperatingSystem.Value; + } + #if NET46 switch (Environment.OSVersion.Platform) { diff --git a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index cbc7c7c2d..de528a94f 100644 --- a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -282,9 +282,12 @@ namespace Emby.Common.Implementations.ScheduledTasks throw new ArgumentNullException("value"); } - SaveTriggers(value); + // This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly + var triggerList = value.Where(i => i != null).ToArray(); - InternalTriggers = value.Select(i => new Tuple(i, GetTrigger(i))).ToArray(); + SaveTriggers(triggerList); + + InternalTriggers = triggerList.Select(i => new Tuple(i, GetTrigger(i))).ToArray(); } } @@ -535,7 +538,8 @@ namespace Emby.Common.Implementations.ScheduledTasks /// IEnumerable{BaseTaskTrigger}. private Tuple[] LoadTriggers() { - var settings = LoadTriggerSettings(); + // This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly + var settings = LoadTriggerSettings().Where(i => i != null).ToArray(); return settings.Select(i => new Tuple(i, GetTrigger(i))).ToArray(); } @@ -544,8 +548,12 @@ namespace Emby.Common.Implementations.ScheduledTasks { try { - return JsonSerializer.DeserializeFromFile>(GetConfigurationFilePath()) - .ToArray(); + var list = JsonSerializer.DeserializeFromFile>(GetConfigurationFilePath()); + + if (list != null) + { + return list.ToArray(); + } } catch (FileNotFoundException) { @@ -555,8 +563,8 @@ namespace Emby.Common.Implementations.ScheduledTasks catch (DirectoryNotFoundException) { // File doesn't exist. No biggie. Return defaults. - return ScheduledTask.GetDefaultTriggers().ToArray(); } + return ScheduledTask.GetDefaultTriggers().ToArray(); } /// diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index a0a7416e7..3590ade40 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -1583,7 +1583,8 @@ namespace Emby.Server.Core public void LaunchUrl(string url) { - if (EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows) + if (EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows && + EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.OSX) { throw new NotImplementedException(); } @@ -1591,7 +1592,7 @@ namespace Emby.Server.Core var process = ProcessFactory.Create(new ProcessOptions { FileName = url, - EnableRaisingEvents = true, + //EnableRaisingEvents = true, UseShellExecute = true, ErrorDialog = false }); diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 995dc7b7b..e78446bc8 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -203,20 +203,12 @@ namespace Emby.Server.Implementations.HttpServer // Do not use the memoryStreamFactory here, they don't place nice with compression using (var ms = new MemoryStream()) { - using (var compressionStream = GetCompressionStream(ms, compressionType)) - { - ContentTypes.Instance.SerializeToStream(request, dto, compressionStream); - compressionStream.Dispose(); + ContentTypes.Instance.SerializeToStream(request, dto, ms); + ms.Position = 0; - var compressedBytes = ms.ToArray(); + var responseHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); - var httpResult = new StreamWriter(compressedBytes, request.ResponseContentType, _logger); - - //httpResult.Headers["Content-Length"] = compressedBytes.Length.ToString(UsCulture); - httpResult.Headers["Content-Encoding"] = compressionType; - - return httpResult; - } + return GetCompressedResult(ms, compressionType, responseHeaders, false, request.ResponseContentType).Result; } } @@ -591,45 +583,53 @@ namespace Emby.Server.Implementations.HttpServer }; } - string content; - using (var stream = await factoryFn().ConfigureAwait(false)) { - using (var reader = new StreamReader(stream)) - { - content = await reader.ReadToEndAsync().ConfigureAwait(false); - } + return await GetCompressedResult(stream, requestedCompressionType, responseHeaders, isHeadRequest, contentType).ConfigureAwait(false); } - - var contents = Compress(content, requestedCompressionType); - - responseHeaders["Content-Length"] = contents.Length.ToString(UsCulture); - responseHeaders["Content-Encoding"] = requestedCompressionType; - - if (isHeadRequest) - { - return GetHttpResult(new byte[] { }, contentType, true); - } - - return GetHttpResult(contents, contentType, true, responseHeaders); } - private byte[] Compress(string text, string compressionType) + private async Task GetCompressedResult(Stream stream, + string requestedCompressionType, + IDictionary responseHeaders, + bool isHeadRequest, + string contentType) + { + using (var reader = new MemoryStream()) + { + await stream.CopyToAsync(reader).ConfigureAwait(false); + + reader.Position = 0; + var content = reader.ToArray(); + + if (content.Length >= 1024) + { + content = Compress(content, requestedCompressionType); + responseHeaders["Content-Encoding"] = requestedCompressionType; + } + + responseHeaders["Content-Length"] = content.Length.ToString(UsCulture); + + if (isHeadRequest) + { + return GetHttpResult(new byte[] { }, contentType, true); + } + + return GetHttpResult(content, contentType, true, responseHeaders); + } + } + + private byte[] Compress(byte[] bytes, string compressionType) { if (compressionType == "deflate") - return Deflate(text); + return Deflate(bytes); if (compressionType == "gzip") - return GZip(text); + return GZip(bytes); throw new NotSupportedException(compressionType); } - private byte[] Deflate(string text) - { - return Deflate(Encoding.UTF8.GetBytes(text)); - } - private byte[] Deflate(byte[] bytes) { // In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream @@ -644,11 +644,6 @@ namespace Emby.Server.Implementations.HttpServer } } - private byte[] GZip(string text) - { - return GZip(Encoding.UTF8.GetBytes(text)); - } - private byte[] GZip(byte[] buffer) { using (var ms = new MemoryStream()) diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 55a63b4e5..b791311f9 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -74,21 +74,21 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - return ResolveVideos(parent, files, directoryService, false); + return ResolveVideos(parent, files, directoryService, false, collectionType); } if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) || string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase)) { - return ResolveVideos