mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
add error handling to work around skia crashes
This commit is contained in:
parent
ccda4bd629
commit
5fa007d04e
@ -10,22 +10,27 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Extensions;
|
||||||
|
using System.Globalization;
|
||||||
|
using MediaBrowser.Model.Globalization;
|
||||||
|
|
||||||
namespace Emby.Drawing.Skia
|
namespace Emby.Drawing.Skia
|
||||||
{
|
{
|
||||||
public class SkiaEncoder : IImageEncoder
|
public class SkiaEncoder : IImageEncoder
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IApplicationPaths _appPaths;
|
private static IApplicationPaths _appPaths;
|
||||||
private readonly Func<IHttpClient> _httpClientFactory;
|
private readonly Func<IHttpClient> _httpClientFactory;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
|
private static ILocalizationManager _localizationManager;
|
||||||
|
|
||||||
public SkiaEncoder(ILogger logger, IApplicationPaths appPaths, Func<IHttpClient> httpClientFactory, IFileSystem fileSystem)
|
public SkiaEncoder(ILogger logger, IApplicationPaths appPaths, Func<IHttpClient> httpClientFactory, IFileSystem fileSystem, ILocalizationManager localizationManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_appPaths = appPaths;
|
_appPaths = appPaths;
|
||||||
_httpClientFactory = httpClientFactory;
|
_httpClientFactory = httpClientFactory;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
|
_localizationManager = localizationManager;
|
||||||
|
|
||||||
LogVersion();
|
LogVersion();
|
||||||
}
|
}
|
||||||
@ -190,14 +195,53 @@ namespace Emby.Drawing.Skia
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string[] TransparentImageTypes = new string[] { ".png", ".gif", ".webp" };
|
private static bool HasDiacritics(string text)
|
||||||
internal static SKBitmap Decode(string path, bool forceCleanBitmap, out SKCodecOrigin origin)
|
|
||||||
{
|
{
|
||||||
|
return !String.Equals(text, text.RemoveDiacritics(), StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool RequiresSpecialCharacterHack(string path)
|
||||||
|
{
|
||||||
|
if (_localizationManager.HasUnicodeCategory(path, UnicodeCategory.OtherLetter))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasDiacritics(path))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizePath(string path, IFileSystem fileSystem)
|
||||||
|
{
|
||||||
|
if (!RequiresSpecialCharacterHack(path))
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tempPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + Path.GetExtension(path) ?? string.Empty);
|
||||||
|
|
||||||
|
fileSystem.CopyFile(path, tempPath, true);
|
||||||
|
|
||||||
|
return tempPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] TransparentImageTypes = new string[] { ".png", ".gif", ".webp" };
|
||||||
|
internal static SKBitmap Decode(string path, bool forceCleanBitmap, IFileSystem fileSystem, out SKCodecOrigin origin)
|
||||||
|
{
|
||||||
|
if (!fileSystem.FileExists(path))
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException("File not found", path);
|
||||||
|
}
|
||||||
|
|
||||||
var requiresTransparencyHack = TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty);
|
var requiresTransparencyHack = TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty);
|
||||||
|
|
||||||
if (requiresTransparencyHack || forceCleanBitmap)
|
if (requiresTransparencyHack || forceCleanBitmap)
|
||||||
{
|
{
|
||||||
using (var stream = new SKFileStream(path))
|
using (var stream = new SKFileStream(NormalizePath(path, fileSystem)))
|
||||||
{
|
{
|
||||||
using (var codec = SKCodec.Create(stream))
|
using (var codec = SKCodec.Create(stream))
|
||||||
{
|
{
|
||||||
@ -227,11 +271,11 @@ namespace Emby.Drawing.Skia
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultBitmap = SKBitmap.Decode(path);
|
var resultBitmap = SKBitmap.Decode(NormalizePath(path, fileSystem));
|
||||||
|
|
||||||
if (resultBitmap == null)
|
if (resultBitmap == null)
|
||||||
{
|
{
|
||||||
return Decode(path, true, out origin);
|
return Decode(path, true, fileSystem, out origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have to resize these they often end up distorted
|
// If we have to resize these they often end up distorted
|
||||||
@ -239,7 +283,7 @@ namespace Emby.Drawing.Skia
|
|||||||
{
|
{
|
||||||
using (resultBitmap)
|
using (resultBitmap)
|
||||||
{
|
{
|
||||||
return Decode(path, true, out origin);
|
return Decode(path, true, fileSystem, out origin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,13 +295,13 @@ namespace Emby.Drawing.Skia
|
|||||||
{
|
{
|
||||||
if (cropWhitespace)
|
if (cropWhitespace)
|
||||||
{
|
{
|
||||||
using (var bitmap = Decode(path, forceAnalyzeBitmap, out origin))
|
using (var bitmap = Decode(path, forceAnalyzeBitmap, _fileSystem, out origin))
|
||||||
{
|
{
|
||||||
return CropWhiteSpace(bitmap);
|
return CropWhiteSpace(bitmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Decode(path, forceAnalyzeBitmap, out origin);
|
return Decode(path, forceAnalyzeBitmap, _fileSystem, out origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient)
|
private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient)
|
||||||
|
@ -83,7 +83,7 @@ namespace Emby.Drawing.Skia
|
|||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
SKCodecOrigin origin;
|
SKCodecOrigin origin;
|
||||||
using (var currentBitmap = SkiaEncoder.Decode(paths[imageIndex], false, out origin))
|
using (var currentBitmap = SkiaEncoder.Decode(paths[imageIndex], false, _fileSystem, out origin))
|
||||||
{
|
{
|
||||||
// resize to the same aspect as the original
|
// resize to the same aspect as the original
|
||||||
int iWidth = (int)Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
|
int iWidth = (int)Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
|
||||||
@ -165,7 +165,7 @@ namespace Emby.Drawing.Skia
|
|||||||
for (var y = 0; y < 2; y++)
|
for (var y = 0; y < 2; y++)
|
||||||
{
|
{
|
||||||
SKCodecOrigin origin;
|
SKCodecOrigin origin;
|
||||||
using (var currentBitmap = SkiaEncoder.Decode(paths[imageIndex], false, out origin))
|
using (var currentBitmap = SkiaEncoder.Decode(paths[imageIndex], false, _fileSystem, out origin))
|
||||||
{
|
{
|
||||||
using (var resizedBitmap = new SKBitmap(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
|
using (var resizedBitmap = new SKBitmap(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@ using MediaBrowser.Model.IO;
|
|||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using Emby.Drawing.Skia;
|
using Emby.Drawing.Skia;
|
||||||
using MediaBrowser.Model.System;
|
using MediaBrowser.Model.System;
|
||||||
|
using MediaBrowser.Model.Globalization;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Startup.Common
|
namespace MediaBrowser.Server.Startup.Common
|
||||||
{
|
{
|
||||||
@ -20,13 +21,14 @@ namespace MediaBrowser.Server.Startup.Common
|
|||||||
StartupOptions startupOptions,
|
StartupOptions startupOptions,
|
||||||
Func<IHttpClient> httpClient,
|
Func<IHttpClient> httpClient,
|
||||||
IApplicationPaths appPaths,
|
IApplicationPaths appPaths,
|
||||||
IEnvironmentInfo environment)
|
IEnvironmentInfo environment,
|
||||||
|
ILocalizationManager localizationManager)
|
||||||
{
|
{
|
||||||
if (!startupOptions.ContainsOption("-enablegdi"))
|
if (!startupOptions.ContainsOption("-enablegdi"))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return new SkiaEncoder(logManager.GetLogger("Skia"), appPaths, httpClient, fileSystem);
|
return new SkiaEncoder(logManager.GetLogger("Skia"), appPaths, httpClient, fileSystem, localizationManager);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -127,7 +127,7 @@ namespace MediaBrowser.Server.Mono
|
|||||||
|
|
||||||
Task.WaitAll(task);
|
Task.WaitAll(task);
|
||||||
|
|
||||||
appHost.ImageProcessor.ImageEncoder = ImageEncoderHelper.GetImageEncoder(_logger, logManager, fileSystem, options, () => appHost.HttpClient, appPaths, environmentInfo);
|
appHost.ImageProcessor.ImageEncoder = ImageEncoderHelper.GetImageEncoder(_logger, logManager, fileSystem, options, () => appHost.HttpClient, appPaths, environmentInfo, appHost.LocalizationManager);
|
||||||
|
|
||||||
Console.WriteLine("Running startup tasks");
|
Console.WriteLine("Running startup tasks");
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ using MediaBrowser.Common.Net;
|
|||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Globalization;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Startup.Common
|
namespace MediaBrowser.Server.Startup.Common
|
||||||
{
|
{
|
||||||
@ -17,11 +18,12 @@ namespace MediaBrowser.Server.Startup.Common
|
|||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
StartupOptions startupOptions,
|
StartupOptions startupOptions,
|
||||||
Func<IHttpClient> httpClient,
|
Func<IHttpClient> httpClient,
|
||||||
IApplicationPaths appPaths)
|
IApplicationPaths appPaths,
|
||||||
|
ILocalizationManager localizationManager)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return new SkiaEncoder(logManager.GetLogger("Skia"), appPaths, httpClient, fileSystem);
|
return new SkiaEncoder(logManager.GetLogger("Skia"), appPaths, httpClient, fileSystem, localizationManager);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -304,6 +304,19 @@ namespace MediaBrowser.ServerApplication
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string UpdatePackageFileName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Environment.Is64BitOperatingSystem)
|
||||||
|
{
|
||||||
|
return "embyserver-win-x64-{version}.zip";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "embyserver-win-x86-{version}.zip";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs the application.
|
/// Runs the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -324,7 +337,7 @@ namespace MediaBrowser.ServerApplication
|
|||||||
options,
|
options,
|
||||||
fileSystem,
|
fileSystem,
|
||||||
new PowerManagement(),
|
new PowerManagement(),
|
||||||
"emby.windows.zip",
|
UpdatePackageFileName,
|
||||||
environmentInfo,
|
environmentInfo,
|
||||||
new NullImageEncoder(),
|
new NullImageEncoder(),
|
||||||
new SystemEvents(logManager.GetLogger("SystemEvents")),
|
new SystemEvents(logManager.GetLogger("SystemEvents")),
|
||||||
@ -355,7 +368,7 @@ namespace MediaBrowser.ServerApplication
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set image encoder here
|
// set image encoder here
|
||||||
appHost.ImageProcessor.ImageEncoder = ImageEncoderHelper.GetImageEncoder(_logger, logManager, fileSystem, options, () => appHost.HttpClient, appPaths);
|
appHost.ImageProcessor.ImageEncoder = ImageEncoderHelper.GetImageEncoder(_logger, logManager, fileSystem, options, () => appHost.HttpClient, appPaths, appHost.LocalizationManager);
|
||||||
|
|
||||||
task = task.ContinueWith(new Action<Task>(a => appHost.RunStartupTasks()), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent);
|
task = task.ContinueWith(new Action<Task>(a => appHost.RunStartupTasks()), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user