rework configurations

This commit is contained in:
Luke Pulverenti
2014-11-29 14:51:30 -05:00
parent aaac7e4208
commit 999ad78a0d
31 changed files with 280 additions and 206 deletions

View File

@@ -0,0 +1,220 @@
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
namespace MediaBrowser.Server.Implementations.Drawing
{
/// <summary>
/// Class ImageExtensions
/// </summary>
public static class ImageExtensions
{
/// <summary>
/// Saves the image.
/// </summary>
/// <param name="outputFormat">The output format.</param>
/// <param name="image">The image.</param>
/// <param name="toStream">To stream.</param>
/// <param name="quality">The quality.</param>
public static void Save(this Image image, System.Drawing.Imaging.ImageFormat outputFormat, Stream toStream, int quality)
{
// Use special save methods for jpeg and png that will result in a much higher quality image
// All other formats use the generic Image.Save
if (System.Drawing.Imaging.ImageFormat.Jpeg.Equals(outputFormat))
{
SaveAsJpeg(image, toStream, quality);
}
else if (System.Drawing.Imaging.ImageFormat.Png.Equals(outputFormat))
{
image.Save(toStream, System.Drawing.Imaging.ImageFormat.Png);
}
else
{
image.Save(toStream, outputFormat);
}
}
/// <summary>
/// Saves the JPEG.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="target">The target.</param>
/// <param name="quality">The quality.</param>
public static void SaveAsJpeg(this Image image, Stream target, int quality)
{
using (var encoderParameters = new EncoderParameters(1))
{
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
image.Save(target, GetImageCodecInfo("image/jpeg"), encoderParameters);
}
}
private static readonly ImageCodecInfo[] Encoders = ImageCodecInfo.GetImageEncoders();
/// <summary>
/// Gets the image codec info.
/// </summary>
/// <param name="mimeType">Type of the MIME.</param>
/// <returns>ImageCodecInfo.</returns>
private static ImageCodecInfo GetImageCodecInfo(string mimeType)
{
foreach (var encoder in Encoders)
{
if (string.Equals(encoder.MimeType, mimeType, StringComparison.OrdinalIgnoreCase))
{
return encoder;
}
}
return Encoders.Length == 0 ? null : Encoders[0];
}
/// <summary>
/// Crops an image by removing whitespace and transparency from the edges
/// </summary>
/// <param name="bmp">The BMP.</param>
/// <returns>Bitmap.</returns>
/// <exception cref="System.Exception"></exception>
public static Bitmap CropWhitespace(this Bitmap bmp)
{
var width = bmp.Width;
var height = bmp.Height;
var topmost = 0;
for (int row = 0; row < height; ++row)
{
if (IsAllWhiteRow(bmp, row, width))
topmost = row;
else break;
}
int bottommost = 0;
for (int row = height - 1; row >= 0; --row)
{
if (IsAllWhiteRow(bmp, row, width))
bottommost = row;
else break;
}
int leftmost = 0, rightmost = 0;
for (int col = 0; col < width; ++col)
{
if (IsAllWhiteColumn(bmp, col, height))
leftmost = col;
else
break;
}
for (int col = width - 1; col >= 0; --col)
{
if (IsAllWhiteColumn(bmp, col, height))
rightmost = col;
else
break;
}
if (rightmost == 0) rightmost = width; // As reached left
if (bottommost == 0) bottommost = height; // As reached top.
var croppedWidth = rightmost - leftmost;
var croppedHeight = bottommost - topmost;
if (croppedWidth == 0) // No border on left or right
{
leftmost = 0;
croppedWidth = width;
}
if (croppedHeight == 0) // No border on top or bottom
{
topmost = 0;
croppedHeight = height;
}
// Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
var thumbnail = new Bitmap(croppedWidth, croppedHeight, PixelFormat.Format32bppPArgb);
// Preserve the original resolution
TrySetResolution(thumbnail, bmp.HorizontalResolution, bmp.VerticalResolution);
using (var thumbnailGraph = Graphics.FromImage(thumbnail))
{
thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
thumbnailGraph.CompositingMode = CompositingMode.SourceCopy;
thumbnailGraph.DrawImage(bmp,
new RectangleF(0, 0, croppedWidth, croppedHeight),
new RectangleF(leftmost, topmost, croppedWidth, croppedHeight),
GraphicsUnit.Pixel);
}
return thumbnail;
}
/// <summary>
/// Tries the set resolution.
/// </summary>
/// <param name="bmp">The BMP.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
private static void TrySetResolution(Bitmap bmp, float x, float y)
{
if (x > 0 && y > 0)
{
bmp.SetResolution(x, y);
}
}
/// <summary>
/// Determines whether or not a row of pixels is all whitespace
/// </summary>
/// <param name="bmp">The BMP.</param>
/// <param name="row">The row.</param>
/// <param name="width">The width.</param>
/// <returns><c>true</c> if [is all white row] [the specified BMP]; otherwise, <c>false</c>.</returns>
private static bool IsAllWhiteRow(Bitmap bmp, int row, int width)
{
for (var i = 0; i < width; ++i)
{
if (!IsWhiteSpace(bmp.GetPixel(i, row)))
{
return false;
}
}
return true;
}
/// <summary>
/// Determines whether or not a column of pixels is all whitespace
/// </summary>
/// <param name="bmp">The BMP.</param>
/// <param name="col">The col.</param>
/// <param name="height">The height.</param>
/// <returns><c>true</c> if [is all white column] [the specified BMP]; otherwise, <c>false</c>.</returns>
private static bool IsAllWhiteColumn(Bitmap bmp, int col, int height)
{
for (var i = 0; i < height; ++i)
{
if (!IsWhiteSpace(bmp.GetPixel(col, i)))
{
return false;
}
}
return true;
}
/// <summary>
/// Determines if a color is whitespace
/// </summary>
/// <param name="color">The color.</param>
/// <returns><c>true</c> if [is white space] [the specified color]; otherwise, <c>false</c>.</returns>
private static bool IsWhiteSpace(Color color)
{
return (color.R == 255 && color.G == 255 && color.B == 255) || color.A == 0;
}
}
}

View File

@@ -129,13 +129,13 @@ namespace MediaBrowser.Server.Implementations.Drawing
}
}
public ImageOutputFormat[] GetSupportedImageOutputFormats()
public Model.Drawing.ImageFormat[] GetSupportedImageOutputFormats()
{
if (_webpAvailable)
{
return new[] { ImageOutputFormat.Webp, ImageOutputFormat.Gif, ImageOutputFormat.Jpg, ImageOutputFormat.Png };
return new[] { Model.Drawing.ImageFormat.Webp, Model.Drawing.ImageFormat.Gif, Model.Drawing.ImageFormat.Jpg, Model.Drawing.ImageFormat.Png };
}
return new[] { ImageOutputFormat.Gif, ImageOutputFormat.Jpg, ImageOutputFormat.Png };
return new[] { Model.Drawing.ImageFormat.Gif, Model.Drawing.ImageFormat.Jpg, Model.Drawing.ImageFormat.Png };
}
public async Task<string> ProcessImage(ImageProcessingOptions options)
@@ -227,7 +227,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
// Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
// Also, Webp only supports Format32bppArgb and Format32bppRgb
var pixelFormat = selectedOutputFormat == ImageOutputFormat.Webp
var pixelFormat = selectedOutputFormat == Model.Drawing.ImageFormat.Webp
? PixelFormat.Format32bppArgb
: PixelFormat.Format32bppPArgb;
@@ -263,7 +263,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
// Save to the cache location
using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
{
if (selectedOutputFormat == ImageOutputFormat.Webp)
if (selectedOutputFormat == Model.Drawing.ImageFormat.Webp)
{
SaveToWebP(thumbnail, cacheFileStream, quality);
}
@@ -381,17 +381,17 @@ namespace MediaBrowser.Server.Implementations.Drawing
/// <param name="image">The image.</param>
/// <param name="outputFormat">The output format.</param>
/// <returns>ImageFormat.</returns>
private System.Drawing.Imaging.ImageFormat GetOutputFormat(Image image, ImageOutputFormat outputFormat)
private System.Drawing.Imaging.ImageFormat GetOutputFormat(Image image, Model.Drawing.ImageFormat outputFormat)
{
switch (outputFormat)
{
case ImageOutputFormat.Bmp:
case Model.Drawing.ImageFormat.Bmp:
return System.Drawing.Imaging.ImageFormat.Bmp;
case ImageOutputFormat.Gif:
case Model.Drawing.ImageFormat.Gif:
return System.Drawing.Imaging.ImageFormat.Gif;
case ImageOutputFormat.Jpg:
case Model.Drawing.ImageFormat.Jpg:
return System.Drawing.Imaging.ImageFormat.Jpeg;
case ImageOutputFormat.Png:
case Model.Drawing.ImageFormat.Png:
return System.Drawing.Imaging.ImageFormat.Png;
default:
return image.RawFormat;
@@ -471,7 +471,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
/// <summary>
/// Gets the cache file path based on a set of parameters
/// </summary>
private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageOutputFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor)
private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, Model.Drawing.ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor)
{
var filename = originalPath;
@@ -772,15 +772,23 @@ namespace MediaBrowser.Server.Implementations.Drawing
{
await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false);
using (var originalImage = Image.FromStream(memoryStream, true, false))
memoryStream.Position = 0;
var imageStream = new ImageStream
{
//Pass the image through registered enhancers
using (var newImage = await ExecuteImageEnhancers(supportedEnhancers, originalImage, item, imageType, imageIndex).ConfigureAwait(false))
Stream = memoryStream,
Format = GetFormat(originalImagePath)
};
//Pass the image through registered enhancers
using (var newImageStream = await ExecuteImageEnhancers(supportedEnhancers, imageStream, item, imageType, imageIndex).ConfigureAwait(false))
{
var parentDirectory = Path.GetDirectoryName(enhancedImagePath);
Directory.CreateDirectory(parentDirectory);
using (var newImage = Image.FromStream(newImageStream.Stream, true, false))
{
var parentDirectory = Path.GetDirectoryName(enhancedImagePath);
Directory.CreateDirectory(parentDirectory);
//And then save it in the cache
using (var outputStream = _fileSystem.GetFileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
{
@@ -799,6 +807,30 @@ namespace MediaBrowser.Server.Implementations.Drawing
return enhancedImagePath;
}
private Model.Drawing.ImageFormat GetFormat(string path)
{
var extension = Path.GetExtension(path);
if (string.Equals(extension, ".png", StringComparison.OrdinalIgnoreCase))
{
return Model.Drawing.ImageFormat.Png;
}
if (string.Equals(extension, ".gif", StringComparison.OrdinalIgnoreCase))
{
return Model.Drawing.ImageFormat.Gif;
}
if (string.Equals(extension, ".webp", StringComparison.OrdinalIgnoreCase))
{
return Model.Drawing.ImageFormat.Webp;
}
if (string.Equals(extension, ".bmp", StringComparison.OrdinalIgnoreCase))
{
return Model.Drawing.ImageFormat.Bmp;
}
return Model.Drawing.ImageFormat.Jpg;
}
/// <summary>
/// Executes the image enhancers.
/// </summary>
@@ -808,7 +840,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
/// <param name="imageType">Type of the image.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <returns>Task{EnhancedImage}.</returns>
private async Task<Image> ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, Image originalImage, IHasImages item, ImageType imageType, int imageIndex)
private async Task<ImageStream> ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, ImageStream originalImage, IHasImages item, ImageType imageType, int imageIndex)
{
var result = originalImage;
@@ -832,21 +864,6 @@ namespace MediaBrowser.Server.Implementations.Drawing
return result;
}
/// <summary>
/// The _semaphoreLocks
/// </summary>
private readonly ConcurrentDictionary<string, object> _locks = new ConcurrentDictionary<string, object>();
/// <summary>
/// Gets the lock.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>System.Object.</returns>
private object GetObjectLock(string filename)
{
return _locks.GetOrAdd(filename, key => new object());
}
/// <summary>
/// The _semaphoreLocks
/// </summary>

View File

@@ -56,43 +56,40 @@ namespace MediaBrowser.Server.Implementations.Library
/// Ensures the name.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="args">The arguments.</param>
private static void EnsureName(BaseItem item, ItemResolveArgs args)
{
// If the subclass didn't supply a name, add it here
if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(item.Path))
{
//we use our resolve args name here to get the name of the containg folder, not actual video file
item.Name = GetMbName(args.FileInfo.Name, (args.FileInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory);
item.Name = GetDisplayName(args.FileInfo.Name, (args.FileInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory);
}
}
/// <summary>
/// Gets the display name.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="isDirectory">if set to <c>true</c> [is directory].</param>
/// <returns>System.String.</returns>
private static string GetDisplayName(string path, bool isDirectory)
{
//first just get the file or directory name
var fn = isDirectory ? Path.GetFileName(path) : Path.GetFileNameWithoutExtension(path);
return fn;
}
/// <summary>
/// The MB name regex
/// </summary>
private static readonly Regex MbNameRegex = new Regex(@"(\[.*?\])", RegexOptions.Compiled);
/// <summary>
/// Strip out attribute items and return just the name we will use for items
/// </summary>
/// <param name="path">Assumed to be a file or directory path</param>
/// <param name="isDirectory">if set to <c>true</c> [is directory].</param>
/// <returns>The cleaned name</returns>
private static string GetMbName(string path, bool isDirectory)
{
//first just get the file or directory name
var fn = isDirectory ? Path.GetFileName(path) : Path.GetFileNameWithoutExtension(path);
//now - strip out anything inside brackets
fn = StripBrackets(fn);
return fn;
}
private static string StripBrackets(string inputString)
internal static string StripBrackets(string inputString)
{
var output = MbNameRegex.Replace(inputString, string.Empty).Trim();
return Regex.Replace(output, @"\s+", " ");
}
}
}

View File

@@ -1,10 +1,9 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Naming.Audio;
using MediaBrowser.Naming.Common;
using MediaBrowser.Naming.Video;
using System;
using System.IO;
namespace MediaBrowser.Server.Implementations.Library.Resolvers
{
@@ -29,7 +28,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
/// <returns>`0.</returns>
protected override T Resolve(ItemResolveArgs args)
{
return ResolveVideo<T>(args);
return ResolveVideo<T>(args, true);
}
/// <summary>
@@ -37,8 +36,9 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
/// </summary>
/// <typeparam name="TVideoType">The type of the T video type.</typeparam>
/// <param name="args">The args.</param>
/// <param name="parseName">if set to <c>true</c> [parse name].</param>
/// <returns>``0.</returns>
protected TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args)
protected TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName)
where TVideoType : Video, new()
{
// If the path is a file check for a matching extensions
@@ -69,10 +69,18 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
IsInMixedFolder = true,
IsPlaceHolder = videoInfo.IsStub,
IsShortcut = isShortcut,
Name = videoInfo.Name,
ProductionYear = videoInfo.Year
};
if (parseName)
{
video.Name = videoInfo.Name;
}
else
{
video.Name = Path.GetFileNameWithoutExtension(path);
}
if (videoInfo.IsStub)
{
if (string.Equals(videoInfo.StubType, "dvd", StringComparison.OrdinalIgnoreCase))
@@ -89,6 +97,38 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
}
}
if (videoInfo.Is3D)
{
if (string.Equals(videoInfo.Format3D, "fsbs", StringComparison.OrdinalIgnoreCase))
{
video.Video3DFormat = Video3DFormat.FullSideBySide;
}
else if (string.Equals(videoInfo.Format3D, "ftab", StringComparison.OrdinalIgnoreCase))
{
video.Video3DFormat = Video3DFormat.FullTopAndBottom;
}
else if (string.Equals(videoInfo.Format3D, "hsbs", StringComparison.OrdinalIgnoreCase))
{
video.Video3DFormat = Video3DFormat.HalfSideBySide;
}
else if (string.Equals(videoInfo.Format3D, "htab", StringComparison.OrdinalIgnoreCase))
{
video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
}
else if (string.Equals(videoInfo.Format3D, "sbs", StringComparison.OrdinalIgnoreCase))
{
video.Video3DFormat = Video3DFormat.HalfSideBySide;
}
else if (string.Equals(videoInfo.Format3D, "sbs3d", StringComparison.OrdinalIgnoreCase))
{
video.Video3DFormat = Video3DFormat.HalfSideBySide;
}
else if (string.Equals(videoInfo.Format3D, "tab", StringComparison.OrdinalIgnoreCase))
{
video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
}
}
return video;
}
}

View File

@@ -40,7 +40,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
if (filename.IndexOf("[boxset]", StringComparison.OrdinalIgnoreCase) != -1 || args.ContainsFileSystemEntryByName("collection.xml"))
{
return new BoxSet { Path = args.Path };
return new BoxSet
{
Path = args.Path,
Name = ResolverHelper.StripBrackets(Path.GetFileName(args.Path))
};
}
}

View File

@@ -8,13 +8,12 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Naming.Common;
using MediaBrowser.Naming.Video;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MediaBrowser.Naming.Audio;
using MediaBrowser.Naming.Common;
using MediaBrowser.Naming.Video;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
{
@@ -116,14 +115,14 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
// Find movies that are mixed in the same folder
if (string.Equals(collectionType, CollectionType.Trailers, StringComparison.OrdinalIgnoreCase))
{
return ResolveVideo<Trailer>(args);
return ResolveVideo<Trailer>(args, true);
}
Video item = null;
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
{
item = ResolveVideo<MusicVideo>(args);
item = ResolveVideo<MusicVideo>(args, true);
}
// To find a movie file, the collection type must be movies or boxsets
@@ -131,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) ||
string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
{
item = ResolveVideo<Movie>(args);
item = ResolveVideo<Movie>(args, true);
}
if (item != null)
@@ -180,8 +179,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
/// <param name="fileSystemEntries">The file system entries.</param>
/// <param name="directoryService">The directory service.</param>
/// <param name="supportMultiFileItems">if set to <c>true</c> [support multi file items].</param>
/// <param name="supportsMultipleSources">if set to <c>true</c> [supports multiple sources].</param>
/// <param name="collectionType">Type of the collection.</param>
/// <returns>Movie.</returns>
private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, bool supportMultiFileItems, bool supportsMultipleSources, string collectionType)
private T FindMovie<T>(string path, Folder parent, IEnumerable<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, bool supportMultiFileItems, bool supportsMultipleSources, string collectionType)
where T : Video, new()
{
var movies = new List<T>();
@@ -231,7 +232,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
CollectionType = collectionType
};
var item = ResolveVideo<T>(childArgs);
var item = ResolveVideo<T>(childArgs, true);
if (item != null)
{

View File

@@ -28,7 +28,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
if (filename.IndexOf("[playlist]", StringComparison.OrdinalIgnoreCase) != -1)
{
return new Playlist { Path = args.Path };
return new Playlist
{
Path = args.Path,
Name = ResolverHelper.StripBrackets(Path.GetFileName(args.Path))
};
}
}

View File

@@ -81,7 +81,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
if (IsSeriesFolder(args.Path, isTvShowsFolder, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager))
{
return new Series();
return new Series
{
Path = args.Path,
Name = ResolverHelper.StripBrackets(Path.GetFileName(args.Path))
};
}
}

View File

@@ -121,6 +121,7 @@
<Compile Include="Devices\DeviceManager.cs" />
<Compile Include="Devices\DeviceRepository.cs" />
<Compile Include="Devices\CameraUploadsFolder.cs" />
<Compile Include="Drawing\ImageExtensions.cs" />
<Compile Include="Drawing\ImageHeader.cs" />
<Compile Include="Drawing\PercentPlayedDrawer.cs" />
<Compile Include="Drawing\PlayedIndicatorDrawer.cs" />