add collages for playlists
This commit is contained in:
parent
9b92cc20f2
commit
a46c5b0a75
|
@ -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.Common.Events;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Dlna.Server;
|
using MediaBrowser.Dlna.Server;
|
||||||
|
@ -56,10 +58,24 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
public event EventHandler<SsdpMessageEventArgs> MessageReceived;
|
public event EventHandler<SsdpMessageEventArgs> MessageReceived;
|
||||||
|
|
||||||
private void OnMessageReceived(SsdpMessageEventArgs args)
|
private async void OnMessageReceived(SsdpMessageEventArgs args)
|
||||||
{
|
{
|
||||||
if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase))
|
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"]);
|
RespondToSearch(args.EndPoint, args.Headers["st"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +184,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
values["ST"] = d.Type;
|
values["ST"] = d.Type;
|
||||||
values["USN"] = d.USN;
|
values["USN"] = d.USN;
|
||||||
|
|
||||||
SendDatagram(header, values, endpoint, null);
|
SendDatagram(header, values, endpoint);
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Playlists;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Providers;
|
using MediaBrowser.Model.Providers;
|
||||||
|
@ -31,6 +32,22 @@ namespace MediaBrowser.Providers.FolderImages
|
||||||
|
|
||||||
public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
|
public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
var playlist = item as Playlist;
|
||||||
|
if (playlist != null)
|
||||||
|
{
|
||||||
|
var url = GetImageUrl(null);
|
||||||
|
|
||||||
|
return Task.FromResult<IEnumerable<RemoteImageInfo>>(new List<RemoteImageInfo>
|
||||||
|
{
|
||||||
|
new RemoteImageInfo
|
||||||
|
{
|
||||||
|
ProviderName = Name,
|
||||||
|
Url = url,
|
||||||
|
Type = ImageType.Primary
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var view = item as UserView;
|
var view = item as UserView;
|
||||||
|
|
||||||
if (view != null)
|
if (view != null)
|
||||||
|
@ -111,7 +128,7 @@ namespace MediaBrowser.Providers.FolderImages
|
||||||
|
|
||||||
public bool Supports(IHasImages item)
|
public bool Supports(IHasImages item)
|
||||||
{
|
{
|
||||||
return item is UserView || item is ICollectionFolder;
|
return item is UserView || item is ICollectionFolder || item is Playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||||
|
|
|
@ -226,6 +226,7 @@
|
||||||
<Compile Include="Persistence\SqliteShrinkMemoryTimer.cs" />
|
<Compile Include="Persistence\SqliteShrinkMemoryTimer.cs" />
|
||||||
<Compile Include="Persistence\TypeMapper.cs" />
|
<Compile Include="Persistence\TypeMapper.cs" />
|
||||||
<Compile Include="Playlists\ManualPlaylistsFolder.cs" />
|
<Compile Include="Playlists\ManualPlaylistsFolder.cs" />
|
||||||
|
<Compile Include="Playlists\PlaylistImageEnhancer.cs" />
|
||||||
<Compile Include="Playlists\PlaylistManager.cs" />
|
<Compile Include="Playlists\PlaylistManager.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="ScheduledTasks\PeopleValidationTask.cs" />
|
<Compile Include="ScheduledTasks\PeopleValidationTask.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<BaseItem> 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<BaseItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string Version = "3";
|
||||||
|
|
||||||
|
public string GetConfigurationCacheKey(List<BaseItem> 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<Image> 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<Image> GetCollage(List<BaseItem> items)
|
||||||
|
{
|
||||||
|
return GetCollage(items.Select(i => i.GetImagePath(ImageType.Primary)).ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Image> GetCollage(List<string> 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<Image> GetSingleImage(List<string> files)
|
||||||
|
{
|
||||||
|
return GetImage(files[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Image> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user