diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs index 4c7c0d60c8..d724628122 100644 --- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs +++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Common.Configuration; +using System.Globalization; +using System.Threading.Tasks; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Events; using MediaBrowser.Controller.Configuration; using MediaBrowser.Dlna.Server; @@ -56,10 +58,24 @@ namespace MediaBrowser.Dlna.Ssdp public event EventHandler MessageReceived; - private void OnMessageReceived(SsdpMessageEventArgs args) + private async void OnMessageReceived(SsdpMessageEventArgs args) { if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase)) { + var mx = args.Headers["mx"]; + int delaySeconds; + if (!string.IsNullOrWhiteSpace(mx) && + int.TryParse(mx, NumberStyles.Any, CultureInfo.InvariantCulture, out delaySeconds) + && delaySeconds > 0) + { + if (_config.GetDlnaConfiguration().EnableDebugLogging) + { + _logger.Debug("Delaying search response by {0} seconds", delaySeconds); + } + + await Task.Delay(delaySeconds * 1000).ConfigureAwait(false); + } + RespondToSearch(args.EndPoint, args.Headers["st"]); } @@ -168,7 +184,7 @@ namespace MediaBrowser.Dlna.Ssdp values["ST"] = d.Type; values["USN"] = d.USN; - SendDatagram(header, values, endpoint, null); + SendDatagram(header, values, endpoint); if (_config.GetDlnaConfiguration().EnableDebugLogging) { diff --git a/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs b/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs index f72b27be64..36815d18c4 100644 --- a/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs +++ b/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; @@ -31,6 +32,22 @@ namespace MediaBrowser.Providers.FolderImages public Task> GetImages(IHasImages item, CancellationToken cancellationToken) { + var playlist = item as Playlist; + if (playlist != null) + { + var url = GetImageUrl(null); + + return Task.FromResult>(new List + { + new RemoteImageInfo + { + ProviderName = Name, + Url = url, + Type = ImageType.Primary + } + }); + } + var view = item as UserView; if (view != null) @@ -111,7 +128,7 @@ namespace MediaBrowser.Providers.FolderImages public bool Supports(IHasImages item) { - return item is UserView || item is ICollectionFolder; + return item is UserView || item is ICollectionFolder || item is Playlist; } public Task GetImageResponse(string url, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 58c8ef995b..af9c7563be 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -226,6 +226,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistImageEnhancer.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistImageEnhancer.cs new file mode 100644 index 0000000000..768d372647 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistImageEnhancer.cs @@ -0,0 +1,218 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Playlists; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Drawing; +using MediaBrowser.Model.Entities; +using MoreLinq; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Playlists +{ + public class PlaylistImageEnhancer : IImageEnhancer + { + private readonly IFileSystem _fileSystem; + + public PlaylistImageEnhancer(IFileSystem fileSystem) + { + _fileSystem = fileSystem; + } + + public bool Supports(IHasImages item, ImageType imageType) + { + return imageType == ImageType.Primary && item is Playlist; + } + + public MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.First; } + } + + private List GetItemsWithImages(IHasImages item) + { + var playlist = (Playlist)item; + + var items = playlist.GetManageableItems() + .Select(i => + { + var subItem = i.Item2; + + var episode = subItem as Episode; + + if (episode != null) + { + var series = episode.Series; + if (series != null && series.HasImage(ImageType.Primary)) + { + return series; + } + } + + if (subItem.HasImage(ImageType.Primary)) + { + return subItem; + } + + var parent = subItem.Parent; + + if (parent != null && parent.HasImage(ImageType.Primary)) + { + if (parent is MusicAlbum) + { + return parent; + } + } + + return null; + }) + .Where(i => i != null) + .DistinctBy(i => i.Id) + .OrderBy(i => Guid.NewGuid()) + .Take(4) + .OrderBy(i => i.Name) + .ToList(); + + if (items.Count == 0) + { + return new List(); + } + + return items; + } + + private const string Version = "3"; + + public string GetConfigurationCacheKey(List items) + { + return Version + "_" + string.Join(",", items.Select(i => i.Id.ToString("N")).ToArray()); + } + + public string GetConfigurationCacheKey(IHasImages item, ImageType imageType) + { + var items = GetItemsWithImages(item); + + return GetConfigurationCacheKey(items); + } + + private const int ImageSize = 800; + + public ImageSize GetEnhancedImageSize(IHasImages item, ImageType imageType, int imageIndex, ImageSize originalImageSize) + { + var items = GetItemsWithImages(item); + + if (items.Count == 0) + { + return originalImageSize; + } + + return new ImageSize + { + Height = ImageSize, + Width = ImageSize + }; + } + + public async Task EnhanceImageAsync(IHasImages item, Image originalImage, ImageType imageType, int imageIndex) + { + var items = GetItemsWithImages(item); + + if (items.Count == 0) + { + return originalImage; + } + + var img = await GetCollage(items).ConfigureAwait(false); + + using (originalImage) + { + return img; + } + } + + private Task GetCollage(List items) + { + return GetCollage(items.Select(i => i.GetImagePath(ImageType.Primary)).ToList()); + } + + private async Task GetCollage(List files) + { + if (files.Count < 4) + { + return await GetSingleImage(files).ConfigureAwait(false); + } + + const int rows = 2; + const int cols = 2; + + const int singleSize = ImageSize / 2; + var index = 0; + + var img = new Bitmap(ImageSize, ImageSize, PixelFormat.Format32bppPArgb); + + using (var graphics = Graphics.FromImage(img)) + { + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingMode = CompositingMode.SourceCopy; + + for (var row = 0; row < rows; row++) + { + for (var col = 0; col < cols; col++) + { + var x = col * singleSize; + var y = row * singleSize; + + using (var fileStream = _fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true)) + { + using (var memoryStream = new MemoryStream()) + { + await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false); + + memoryStream.Position = 0; + + using (var imgtemp = Image.FromStream(memoryStream, true, false)) + { + graphics.DrawImage(imgtemp, x, y, singleSize, singleSize); + } + } + } + + index++; + } + } + } + + return img; + } + + private Task GetSingleImage(List files) + { + return GetImage(files[0]); + } + + private async Task GetImage(string file) + { + using (var fileStream = _fileSystem.GetFileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, true)) + { + var memoryStream = new MemoryStream(); + + await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false); + + memoryStream.Position = 0; + + return Image.FromStream(memoryStream, true, false); + } + } + } +}