diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs index 78e90af26e..3bd425cb38 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs @@ -47,6 +47,7 @@ namespace MediaBrowser.Dlna.Profiles "http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000"; EnableSingleAlbumArtLimit = true; + EnableAlbumArtInDidl = true; TranscodingProfiles = new[] { diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs index b435c63642..de4f1d2b65 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs @@ -44,6 +44,7 @@ namespace MediaBrowser.Dlna.Profiles ManufacturerUrl = "http://www.microsoft.com/"; SonyAggregationFlags = "10"; EnableSingleAlbumArtLimit = true; + EnableAlbumArtInDidl = true; TranscodingProfiles = new[] { diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs index b0cbb0970d..5a5fb9e942 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs @@ -44,6 +44,7 @@ namespace MediaBrowser.Dlna.Profiles ManufacturerUrl = "http://www.microsoft.com/"; SonyAggregationFlags = "10"; EnableSingleAlbumArtLimit = true; + EnableAlbumArtInDidl = true; TranscodingProfiles = new[] { diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs index ca4e802a16..74a07f3892 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs @@ -44,6 +44,7 @@ namespace MediaBrowser.Dlna.Profiles ManufacturerUrl = "http://www.microsoft.com/"; SonyAggregationFlags = "10"; EnableSingleAlbumArtLimit = true; + EnableAlbumArtInDidl = true; TranscodingProfiles = new[] { diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml index 68bfe85cf9..7afc8183d2 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml @@ -15,7 +15,7 @@ Emby 3.0 http://www.microsoft.com/ - false + true true Audio,Photo,Video JPEG_TN diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml index 4f9ca7550c..7400600e22 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml @@ -15,7 +15,7 @@ Emby 3.0 http://www.microsoft.com/ - false + true true Audio,Photo,Video JPEG_TN diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml index 682b2f3585..b8e3d6d309 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml @@ -15,7 +15,7 @@ Emby 3.0 http://www.microsoft.com/ - false + true true Audio,Photo,Video JPEG_TN diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml index 5032bf69a8..5733d9d0b1 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml @@ -15,7 +15,7 @@ Emby 3.0 http://www.microsoft.com/ - false + true true Audio,Photo,Video JPEG_TN diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index a01f37f91d..4d5b669e2c 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -199,82 +199,83 @@ namespace MediaBrowser.MediaEncoding.Encoder await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - var processWrapper = new ProcessWrapper(process, this); - - try - { - StartProcess(processWrapper); - } - catch (Exception ex) + using (var processWrapper = new ProcessWrapper(process, this)) { - _ffProbeResourcePool.Release(); + try + { + StartProcess(processWrapper); + } + catch (Exception ex) + { + _ffProbeResourcePool.Release(); - _logger.ErrorException("Error starting ffprobe", ex); + _logger.ErrorException("Error starting ffprobe", ex); - throw; - } + throw; + } - try - { - process.BeginErrorReadLine(); + try + { + process.BeginErrorReadLine(); - var result = _jsonSerializer.DeserializeFromStream(process.StandardOutput.BaseStream); + var result = _jsonSerializer.DeserializeFromStream(process.StandardOutput.BaseStream); - if (result != null) - { - if (result.streams != null) + if (result != null) { - // Normalize aspect ratio if invalid - foreach (var stream in result.streams) + if (result.streams != null) { - if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) - { - stream.display_aspect_ratio = string.Empty; - } - if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) + // Normalize aspect ratio if invalid + foreach (var stream in result.streams) { - stream.sample_aspect_ratio = string.Empty; + if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) + { + stream.display_aspect_ratio = string.Empty; + } + if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) + { + stream.sample_aspect_ratio = string.Empty; + } } } - } - var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol); + var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol); - if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue) - { - foreach (var stream in mediaInfo.MediaStreams) + if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue) { - if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase)) + foreach (var stream in mediaInfo.MediaStreams) { - try - { - //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken) - // .ConfigureAwait(false); - } - catch (OperationCanceledException) - { - - } - catch (Exception ex) + if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase)) { - _logger.ErrorException("Error getting key frame interval", ex); + try + { + //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken) + // .ConfigureAwait(false); + } + catch (OperationCanceledException) + { + + } + catch (Exception ex) + { + _logger.ErrorException("Error getting key frame interval", ex); + } } } } - } - return mediaInfo; + return mediaInfo; + } } - } - catch - { - StopProcess(processWrapper, 100, true); + catch + { + StopProcess(processWrapper, 100, true); - throw; - } - finally - { - _ffProbeResourcePool.Release(); + throw; + } + finally + { + _ffProbeResourcePool.Release(); + } } throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath)); @@ -307,31 +308,32 @@ namespace MediaBrowser.MediaEncoding.Encoder _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - var processWrapper = new ProcessWrapper(process, this); - - StartProcess(processWrapper); + using (var processWrapper = new ProcessWrapper(process, this)) + { + StartProcess(processWrapper); - var lines = new List(); + var lines = new List(); - try - { - process.BeginErrorReadLine(); + try + { + process.BeginErrorReadLine(); - await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - if (cancellationToken.IsCancellationRequested) + await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) { - throw; + if (cancellationToken.IsCancellationRequested) + { + throw; + } + } + finally + { + StopProcess(processWrapper, 100, true); } - } - finally - { - StopProcess(processWrapper, 100, true); - } - return lines; + return lines; + } } private async Task StartReadingOutput(Stream source, List lines, int timeoutMs, CancellationToken cancellationToken) @@ -490,51 +492,53 @@ namespace MediaBrowser.MediaEncoding.Encoder await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - var processWrapper = new ProcessWrapper(process, this); - bool ranToCompletion; + using (var processWrapper = new ProcessWrapper(process, this)) + { + bool ranToCompletion; - var memoryStream = new MemoryStream(); + var memoryStream = new MemoryStream(); - try - { - StartProcess(processWrapper); + try + { + StartProcess(processWrapper); #pragma warning disable 4014 - // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback - process.StandardOutput.BaseStream.CopyToAsync(memoryStream); + // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback + process.StandardOutput.BaseStream.CopyToAsync(memoryStream); #pragma warning restore 4014 - // MUST read both stdout and stderr asynchronously or a deadlock may occurr - process.BeginErrorReadLine(); + // MUST read both stdout and stderr asynchronously or a deadlock may occurr + process.BeginErrorReadLine(); - ranToCompletion = process.WaitForExit(10000); + ranToCompletion = process.WaitForExit(10000); - if (!ranToCompletion) + if (!ranToCompletion) + { + StopProcess(processWrapper, 1000, false); + } + + } + finally { - StopProcess(processWrapper, 1000, false); + resourcePool.Release(); } - } - finally - { - resourcePool.Release(); - } + var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; - var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; + if (exitCode == -1 || memoryStream.Length == 0) + { + memoryStream.Dispose(); - if (exitCode == -1 || memoryStream.Length == 0) - { - memoryStream.Dispose(); + var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath); - var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath); + _logger.Error(msg); - _logger.Error(msg); + throw new ApplicationException(msg); + } - throw new ApplicationException(msg); + memoryStream.Position = 0; + return memoryStream; } - - memoryStream.Position = 0; - return memoryStream; } public string GetTimeParameter(long ticks) @@ -603,55 +607,56 @@ namespace MediaBrowser.MediaEncoding.Encoder bool ranToCompletion = false; - var processWrapper = new ProcessWrapper(process, this); - - try + using (var processWrapper = new ProcessWrapper(process, this)) { - StartProcess(processWrapper); + try + { + StartProcess(processWrapper); - // Need to give ffmpeg enough time to make all the thumbnails, which could be a while, - // but we still need to detect if the process hangs. - // Making the assumption that as long as new jpegs are showing up, everything is good. + // Need to give ffmpeg enough time to make all the thumbnails, which could be a while, + // but we still need to detect if the process hangs. + // Making the assumption that as long as new jpegs are showing up, everything is good. - bool isResponsive = true; - int lastCount = 0; + bool isResponsive = true; + int lastCount = 0; - while (isResponsive) - { - if (process.WaitForExit(30000)) + while (isResponsive) { - ranToCompletion = true; - break; - } + if (process.WaitForExit(30000)) + { + ranToCompletion = true; + break; + } + + cancellationToken.ThrowIfCancellationRequested(); - cancellationToken.ThrowIfCancellationRequested(); + var jpegCount = Directory.GetFiles(targetDirectory) + .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase)); - var jpegCount = Directory.GetFiles(targetDirectory) - .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase)); + isResponsive = (jpegCount > lastCount); + lastCount = jpegCount; + } - isResponsive = (jpegCount > lastCount); - lastCount = jpegCount; + if (!ranToCompletion) + { + StopProcess(processWrapper, 1000, false); + } } - - if (!ranToCompletion) + finally { - StopProcess(processWrapper, 1000, false); + resourcePool.Release(); } - } - finally - { - resourcePool.Release(); - } - var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; + var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; - if (exitCode == -1) - { - var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument); + if (exitCode == -1) + { + var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument); - _logger.Error(msg); + _logger.Error(msg); - throw new ApplicationException(msg); + throw new ApplicationException(msg); + } } } @@ -781,7 +786,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - private class ProcessWrapper + private class ProcessWrapper : IDisposable { public readonly Process Process; public bool HasExited; @@ -810,6 +815,25 @@ namespace MediaBrowser.MediaEncoding.Encoder process.Dispose(); } + + private bool _disposed; + private readonly object _syncLock = new object(); + public void Dispose() + { + lock (_syncLock) + { + if (!_disposed) + { + if (Process != null) + { + Process.Exited -= Process_Exited; + Process.Dispose(); + } + } + + _disposed = true; + } + } } } } diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index b3fe28561a..62463d196a 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -1,4 +1,5 @@ using MediaBrowser.Model.MediaInfo; +using System; using System.Collections.Generic; namespace MediaBrowser.Model.Dlna @@ -164,7 +165,7 @@ namespace MediaBrowser.Model.Dlna if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn)) { - orgPnValues.AddRange(mediaProfile.OrgPn.Split(',')); + orgPnValues.AddRange(mediaProfile.OrgPn.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)); } else { diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index c95cf67256..92fc1c2a80 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -38,12 +38,9 @@ namespace MediaBrowser.Providers.Manager { var hasChanges = false; - var localImageProviders = providers.OfType() - .ToList(); - - if (localImageProviders.Count > 0 || !(item is Photo)) + if (!(item is Photo)) { - var images = localImageProviders + var images = providers.OfType() .SelectMany(i => i.GetImages(item, directoryService)) .ToList(); @@ -425,19 +422,14 @@ namespace MediaBrowser.Providers.Manager var changed = false; var newImages = images.Where(i => i.Type == type).ToList(); - if (newImages.Count > 0) - { - var newImageFileInfos = images.Where(i => i.Type == type) + + var newImageFileInfos = newImages .Select(i => i.FileInfo) .ToList(); - if (newImageFileInfos.Count > 0) - { - if (item.AddImages(type, newImageFileInfos)) - { - changed = true; - } - } + if (item.AddImages(type, newImageFileInfos)) + { + changed = true; } return changed; diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index ff99c40786..0a922dd0a6 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1447,5 +1447,6 @@ "LabelServerHostHelp": "192.168.1.100 or https://myserver.com", "LabelServerPort": "Port:", "HeaderNewServer": "New Server", - "ButtonChangeServer": "Change Server" + "ButtonChangeServer": "Change Server", + "HeaderConnectToServer": "Connect to Server" } diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index 6c812acce0..292f74a56d 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -301,7 +301,7 @@ namespace MediaBrowser.WebDashboard.Api var builder = new StringBuilder(); - foreach (var file in new[] + var apiClientFiles = new[] { "thirdparty/apiclient/logger.js", "thirdparty/apiclient/md5.js", @@ -314,10 +314,20 @@ namespace MediaBrowser.WebDashboard.Api "thirdparty/apiclient/events.js", "thirdparty/apiclient/deferred.js", "thirdparty/apiclient/apiclient.js", - "thirdparty/apiclient/connectservice.js", - "thirdparty/apiclient/serverdiscovery.js", - "thirdparty/apiclient/connectionmanager.js" - }) + "thirdparty/apiclient/connectservice.js" + }.ToList(); + + if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase)) + { + apiClientFiles.Add("thirdparty/apiclient/cordova/serverdiscovery.js"); + } + else + { + apiClientFiles.Add("thirdparty/apiclient/serverdiscovery.js"); + } + apiClientFiles.Add("thirdparty/apiclient/connectionmanager.js"); + + foreach (var file in apiClientFiles) { using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) { diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index e39df9602c..6b3a0ae7ea 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -210,6 +210,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest