commit
e1bdca9f1f
179
MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs
Normal file
179
MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CommonIO;
|
||||||
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Net;
|
||||||
|
|
||||||
|
namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
{
|
||||||
|
public class FontConfigLoader
|
||||||
|
{
|
||||||
|
private readonly IHttpClient _httpClient;
|
||||||
|
private readonly IApplicationPaths _appPaths;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly IZipClient _zipClient;
|
||||||
|
private readonly IFileSystem _fileSystem;
|
||||||
|
|
||||||
|
private readonly string[] _fontUrls =
|
||||||
|
{
|
||||||
|
"https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/ARIALUNI.7z"
|
||||||
|
};
|
||||||
|
|
||||||
|
public FontConfigLoader(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, IZipClient zipClient, IFileSystem fileSystem)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
_appPaths = appPaths;
|
||||||
|
_logger = logger;
|
||||||
|
_zipClient = zipClient;
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extracts the fonts.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetPath">The target path.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
public async Task DownloadFonts(string targetPath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fontsDirectory = Path.Combine(targetPath, "fonts");
|
||||||
|
|
||||||
|
_fileSystem.CreateDirectory(fontsDirectory);
|
||||||
|
|
||||||
|
const string fontFilename = "ARIALUNI.TTF";
|
||||||
|
|
||||||
|
var fontFile = Path.Combine(fontsDirectory, fontFilename);
|
||||||
|
|
||||||
|
if (_fileSystem.FileExists(fontFile))
|
||||||
|
{
|
||||||
|
await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Kick this off, but no need to wait on it
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await DownloadFontFile(fontsDirectory, fontFilename, new Progress<double>()).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (HttpException ex)
|
||||||
|
{
|
||||||
|
// Don't let the server crash because of this
|
||||||
|
_logger.ErrorException("Error downloading ffmpeg font files", ex);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Don't let the server crash because of this
|
||||||
|
_logger.ErrorException("Error writing ffmpeg font files", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Downloads the font file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fontsDirectory">The fonts directory.</param>
|
||||||
|
/// <param name="fontFilename">The font filename.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
private async Task DownloadFontFile(string fontsDirectory, string fontFilename, IProgress<double> progress)
|
||||||
|
{
|
||||||
|
var existingFile = Directory
|
||||||
|
.EnumerateFiles(_appPaths.ProgramDataPath, fontFilename, SearchOption.AllDirectories)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (existingFile != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_fileSystem.CopyFile(existingFile, Path.Combine(fontsDirectory, fontFilename), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
// Log this, but don't let it fail the operation
|
||||||
|
_logger.ErrorException("Error copying file", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string tempFile = null;
|
||||||
|
|
||||||
|
foreach (var url in _fontUrls)
|
||||||
|
{
|
||||||
|
progress.Report(0);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
|
||||||
|
{
|
||||||
|
Url = url,
|
||||||
|
Progress = progress
|
||||||
|
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// The core can function without the font file, so handle this
|
||||||
|
_logger.ErrorException("Failed to download ffmpeg font file from {0}", ex, url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(tempFile))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Extract7zArchive(tempFile, fontsDirectory);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_fileSystem.DeleteFile(tempFile);
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
// Log this, but don't let it fail the operation
|
||||||
|
_logger.ErrorException("Error deleting temp file {0}", ex, tempFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void Extract7zArchive(string archivePath, string targetPath)
|
||||||
|
{
|
||||||
|
_logger.Info("Extracting {0} to {1}", archivePath, targetPath);
|
||||||
|
|
||||||
|
_zipClient.ExtractAllFrom7z(archivePath, targetPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the font config file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fontsDirectory">The fonts directory.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
private async Task WriteFontConfigFile(string fontsDirectory)
|
||||||
|
{
|
||||||
|
const string fontConfigFilename = "fonts.conf";
|
||||||
|
var fontConfigFile = Path.Combine(fontsDirectory, fontConfigFilename);
|
||||||
|
|
||||||
|
if (!_fileSystem.FileExists(fontConfigFile))
|
||||||
|
{
|
||||||
|
var contents = string.Format("<?xml version=\"1.0\"?><fontconfig><dir>{0}</dir><alias><family>Arial</family><prefer>Arial Unicode MS</prefer></alias></fontconfig>", fontsDirectory);
|
||||||
|
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(contents);
|
||||||
|
|
||||||
|
using (var fileStream = _fileSystem.GetFileStream(fontConfigFile, FileMode.Create, FileAccess.Write,
|
||||||
|
FileShare.Read, true))
|
||||||
|
{
|
||||||
|
await fileStream.WriteAsync(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ using CommonIO;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
|
|
||||||
namespace MediaBrowser.MediaEncoding.Encoder
|
namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
|
@ -76,11 +77,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
protected readonly ISessionManager SessionManager;
|
protected readonly ISessionManager SessionManager;
|
||||||
protected readonly Func<ISubtitleEncoder> SubtitleEncoder;
|
protected readonly Func<ISubtitleEncoder> SubtitleEncoder;
|
||||||
protected readonly Func<IMediaSourceManager> MediaSourceManager;
|
protected readonly Func<IMediaSourceManager> MediaSourceManager;
|
||||||
|
private readonly IHttpClient _httpClient;
|
||||||
|
private readonly IZipClient _zipClient;
|
||||||
|
|
||||||
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
|
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
|
||||||
private readonly bool _hasExternalEncoder;
|
private readonly bool _hasExternalEncoder;
|
||||||
|
|
||||||
public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager)
|
public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager, IHttpClient httpClient, IZipClient zipClient)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_jsonSerializer = jsonSerializer;
|
_jsonSerializer = jsonSerializer;
|
||||||
|
@ -93,6 +96,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
SessionManager = sessionManager;
|
SessionManager = sessionManager;
|
||||||
SubtitleEncoder = subtitleEncoder;
|
SubtitleEncoder = subtitleEncoder;
|
||||||
MediaSourceManager = mediaSourceManager;
|
MediaSourceManager = mediaSourceManager;
|
||||||
|
_httpClient = httpClient;
|
||||||
|
_zipClient = zipClient;
|
||||||
FFProbePath = ffProbePath;
|
FFProbePath = ffProbePath;
|
||||||
FFMpegPath = ffMpegPath;
|
FFMpegPath = ffMpegPath;
|
||||||
|
|
||||||
|
@ -142,6 +147,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
SetAvailableDecoders(result.Item1);
|
SetAvailableDecoders(result.Item1);
|
||||||
SetAvailableEncoders(result.Item2);
|
SetAvailableEncoders(result.Item2);
|
||||||
|
|
||||||
|
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||||
|
{
|
||||||
|
var directory = Path.GetDirectoryName(FFMpegPath);
|
||||||
|
|
||||||
|
if (FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.ProgramDataPath, directory))
|
||||||
|
{
|
||||||
|
await new FontConfigLoader(_httpClient, ConfigurationManager.ApplicationPaths, _logger, _zipClient,
|
||||||
|
FileSystem).DownloadFonts(directory).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
<Compile Include="Encoder\EncodingJobFactory.cs" />
|
<Compile Include="Encoder\EncodingJobFactory.cs" />
|
||||||
<Compile Include="Encoder\EncodingUtils.cs" />
|
<Compile Include="Encoder\EncodingUtils.cs" />
|
||||||
<Compile Include="Encoder\EncoderValidator.cs" />
|
<Compile Include="Encoder\EncoderValidator.cs" />
|
||||||
|
<Compile Include="Encoder\FontConfigLoader.cs" />
|
||||||
<Compile Include="Encoder\JobLogger.cs" />
|
<Compile Include="Encoder\JobLogger.cs" />
|
||||||
<Compile Include="Encoder\MediaEncoder.cs" />
|
<Compile Include="Encoder\MediaEncoder.cs" />
|
||||||
<Compile Include="Encoder\VideoEncoder.cs" />
|
<Compile Include="Encoder\VideoEncoder.cs" />
|
||||||
|
|
|
@ -192,7 +192,7 @@ namespace MediaBrowser.Model.Configuration
|
||||||
|
|
||||||
public int MigrationVersion { get; set; }
|
public int MigrationVersion { get; set; }
|
||||||
public int SchemaVersion { get; set; }
|
public int SchemaVersion { get; set; }
|
||||||
public int SqliteCachePages { get; set; }
|
public int SqliteCacheSize { get; set; }
|
||||||
|
|
||||||
public bool DownloadImagesInAdvance { get; set; }
|
public bool DownloadImagesInAdvance { get; set; }
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ namespace MediaBrowser.Model.Configuration
|
||||||
{
|
{
|
||||||
LocalNetworkAddresses = new string[] { };
|
LocalNetworkAddresses = new string[] { };
|
||||||
Migrations = new string[] { };
|
Migrations = new string[] { };
|
||||||
SqliteCachePages = 10000;
|
SqliteCacheSize = 0;
|
||||||
|
|
||||||
EnableCustomPathSubFolders = true;
|
EnableCustomPathSubFolders = true;
|
||||||
EnableLocalizedGuids = true;
|
EnableLocalizedGuids = true;
|
||||||
|
|
|
@ -33,13 +33,13 @@ namespace MediaBrowser.Server.Implementations.IO
|
||||||
{
|
{
|
||||||
logger.Debug("New file refresher created for {0}", path);
|
logger.Debug("New file refresher created for {0}", path);
|
||||||
Path = path;
|
Path = path;
|
||||||
_affectedPaths.Add(path);
|
|
||||||
|
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
ConfigurationManager = configurationManager;
|
ConfigurationManager = configurationManager;
|
||||||
LibraryManager = libraryManager;
|
LibraryManager = libraryManager;
|
||||||
TaskManager = taskManager;
|
TaskManager = taskManager;
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
AddPath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddAffectedPath(string path)
|
private void AddAffectedPath(string path)
|
||||||
|
|
|
@ -123,7 +123,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
|
|
||||||
protected override async Task<IDbConnection> CreateConnection(bool isReadOnly = false)
|
protected override async Task<IDbConnection> CreateConnection(bool isReadOnly = false)
|
||||||
{
|
{
|
||||||
var connection = await DbConnector.Connect(DbFilePath, false, false, _config.Configuration.SqliteCachePages).ConfigureAwait(false);
|
var cacheSize = _config.Configuration.SqliteCacheSize;
|
||||||
|
if (cacheSize <= 0)
|
||||||
|
{
|
||||||
|
cacheSize = Math.Min(Environment.ProcessorCount * 50000, 200000);
|
||||||
|
}
|
||||||
|
|
||||||
|
var connection = await DbConnector.Connect(DbFilePath, false, false, 0 - cacheSize).ConfigureAwait(false);
|
||||||
|
|
||||||
connection.RunQueries(new[]
|
connection.RunQueries(new[]
|
||||||
{
|
{
|
||||||
|
@ -2968,10 +2974,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
whereClauses.Add("LocationType not in (" + val + ")");
|
whereClauses.Add("LocationType not in (" + val + ")");
|
||||||
}
|
}
|
||||||
if (query.IsVirtualItem.HasValue)
|
if (query.IsVirtualItem.HasValue)
|
||||||
|
{
|
||||||
|
if (_config.Configuration.SchemaVersion >= 90)
|
||||||
{
|
{
|
||||||
whereClauses.Add("IsVirtualItem=@IsVirtualItem");
|
whereClauses.Add("IsVirtualItem=@IsVirtualItem");
|
||||||
cmd.Parameters.Add(cmd, "@IsVirtualItem", DbType.Boolean).Value = query.IsVirtualItem.Value;
|
cmd.Parameters.Add(cmd, "@IsVirtualItem", DbType.Boolean).Value = query.IsVirtualItem.Value;
|
||||||
}
|
}
|
||||||
|
else if (!query.IsVirtualItem.Value)
|
||||||
|
{
|
||||||
|
whereClauses.Add("LocationType<>'Virtual'");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (query.MediaTypes.Length == 1)
|
if (query.MediaTypes.Length == 1)
|
||||||
{
|
{
|
||||||
whereClauses.Add("MediaType=@MediaTypes");
|
whereClauses.Add("MediaType=@MediaTypes");
|
||||||
|
|
|
@ -660,7 +660,9 @@ namespace MediaBrowser.Server.Startup.Common
|
||||||
ChannelManager,
|
ChannelManager,
|
||||||
SessionManager,
|
SessionManager,
|
||||||
() => SubtitleEncoder,
|
() => SubtitleEncoder,
|
||||||
() => MediaSourceManager);
|
() => MediaSourceManager,
|
||||||
|
HttpClient,
|
||||||
|
ZipClient);
|
||||||
|
|
||||||
MediaEncoder = mediaEncoder;
|
MediaEncoder = mediaEncoder;
|
||||||
RegisterSingleInstance(MediaEncoder);
|
RegisterSingleInstance(MediaEncoder);
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
using Mono.Unix.Native;
|
using Mono.Unix.Native;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CommonIO;
|
using CommonIO;
|
||||||
|
@ -26,11 +23,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
private readonly NativeEnvironment _environment;
|
private readonly NativeEnvironment _environment;
|
||||||
private readonly FFMpegInstallInfo _ffmpegInstallInfo;
|
private readonly FFMpegInstallInfo _ffmpegInstallInfo;
|
||||||
|
|
||||||
private readonly string[] _fontUrls =
|
|
||||||
{
|
|
||||||
"https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/ARIALUNI.7z"
|
|
||||||
};
|
|
||||||
|
|
||||||
public FFMpegLoader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient, IFileSystem fileSystem, NativeEnvironment environment, FFMpegInstallInfo ffmpegInstallInfo)
|
public FFMpegLoader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient, IFileSystem fileSystem, NativeEnvironment environment, FFMpegInstallInfo ffmpegInstallInfo)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -112,13 +104,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_environment.OperatingSystem == OperatingSystem.Windows)
|
|
||||||
{
|
|
||||||
await DownloadFonts(versionedDirectoryPath).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeleteOlderFolders(Path.GetDirectoryName(versionedDirectoryPath), excludeFromDeletions);
|
|
||||||
|
|
||||||
// Allow just one of these to be overridden, if desired.
|
// Allow just one of these to be overridden, if desired.
|
||||||
if (!string.IsNullOrWhiteSpace(customffMpegPath))
|
if (!string.IsNullOrWhiteSpace(customffMpegPath))
|
||||||
{
|
{
|
||||||
|
@ -132,30 +117,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteOlderFolders(string path, IEnumerable<string> excludeFolders)
|
|
||||||
{
|
|
||||||
var folders = Directory.GetDirectories(path)
|
|
||||||
.Where(i => !excludeFolders.Contains(i, StringComparer.OrdinalIgnoreCase))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
foreach (var folder in folders)
|
|
||||||
{
|
|
||||||
DeleteFolder(folder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DeleteFolder(string path)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_fileSystem.DeleteDirectory(path, true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error deleting {0}", ex, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private FFMpegInfo GetExistingVersion(FFMpegInfo info, string rootEncoderPath)
|
private FFMpegInfo GetExistingVersion(FFMpegInfo info, string rootEncoderPath)
|
||||||
{
|
{
|
||||||
var encoderFilename = Path.GetFileName(info.EncoderPath);
|
var encoderFilename = Path.GetFileName(info.EncoderPath);
|
||||||
|
@ -270,12 +231,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
_zipClient.ExtractAllFromTar(archivePath, targetPath, true);
|
_zipClient.ExtractAllFromTar(archivePath, targetPath, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void Extract7zArchive(string archivePath, string targetPath)
|
|
||||||
{
|
|
||||||
_logger.Info("Extracting {0} to {1}", archivePath, targetPath);
|
|
||||||
|
|
||||||
_zipClient.ExtractAllFrom7z(archivePath, targetPath, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DeleteFile(string path)
|
private void DeleteFile(string path)
|
||||||
{
|
{
|
||||||
|
@ -289,140 +244,5 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extracts the fonts.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetPath">The target path.</param>
|
|
||||||
/// <returns>Task.</returns>
|
|
||||||
private async Task DownloadFonts(string targetPath)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var fontsDirectory = Path.Combine(targetPath, "fonts");
|
|
||||||
|
|
||||||
_fileSystem.CreateDirectory(fontsDirectory);
|
|
||||||
|
|
||||||
const string fontFilename = "ARIALUNI.TTF";
|
|
||||||
|
|
||||||
var fontFile = Path.Combine(fontsDirectory, fontFilename);
|
|
||||||
|
|
||||||
if (_fileSystem.FileExists(fontFile))
|
|
||||||
{
|
|
||||||
await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Kick this off, but no need to wait on it
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await DownloadFontFile(fontsDirectory, fontFilename, new Progress<double>()).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HttpException ex)
|
|
||||||
{
|
|
||||||
// Don't let the server crash because of this
|
|
||||||
_logger.ErrorException("Error downloading ffmpeg font files", ex);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// Don't let the server crash because of this
|
|
||||||
_logger.ErrorException("Error writing ffmpeg font files", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Downloads the font file.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fontsDirectory">The fonts directory.</param>
|
|
||||||
/// <param name="fontFilename">The font filename.</param>
|
|
||||||
/// <returns>Task.</returns>
|
|
||||||
private async Task DownloadFontFile(string fontsDirectory, string fontFilename, IProgress<double> progress)
|
|
||||||
{
|
|
||||||
var existingFile = Directory
|
|
||||||
.EnumerateFiles(_appPaths.ProgramDataPath, fontFilename, SearchOption.AllDirectories)
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
if (existingFile != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_fileSystem.CopyFile(existingFile, Path.Combine(fontsDirectory, fontFilename), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
// Log this, but don't let it fail the operation
|
|
||||||
_logger.ErrorException("Error copying file", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string tempFile = null;
|
|
||||||
|
|
||||||
foreach (var url in _fontUrls)
|
|
||||||
{
|
|
||||||
progress.Report(0);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
|
|
||||||
{
|
|
||||||
Url = url,
|
|
||||||
Progress = progress
|
|
||||||
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// The core can function without the font file, so handle this
|
|
||||||
_logger.ErrorException("Failed to download ffmpeg font file from {0}", ex, url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(tempFile))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Extract7zArchive(tempFile, fontsDirectory);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_fileSystem.DeleteFile(tempFile);
|
|
||||||
}
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
// Log this, but don't let it fail the operation
|
|
||||||
_logger.ErrorException("Error deleting temp file {0}", ex, tempFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes the font config file.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fontsDirectory">The fonts directory.</param>
|
|
||||||
/// <returns>Task.</returns>
|
|
||||||
private async Task WriteFontConfigFile(string fontsDirectory)
|
|
||||||
{
|
|
||||||
const string fontConfigFilename = "fonts.conf";
|
|
||||||
var fontConfigFile = Path.Combine(fontsDirectory, fontConfigFilename);
|
|
||||||
|
|
||||||
if (!_fileSystem.FileExists(fontConfigFile))
|
|
||||||
{
|
|
||||||
var contents = string.Format("<?xml version=\"1.0\"?><fontconfig><dir>{0}</dir><alias><family>Arial</family><prefer>Arial Unicode MS</prefer></alias></fontconfig>", fontsDirectory);
|
|
||||||
|
|
||||||
var bytes = Encoding.UTF8.GetBytes(contents);
|
|
||||||
|
|
||||||
using (var fileStream = _fileSystem.GetFileStream(fontConfigFile, FileMode.Create, FileAccess.Write,
|
|
||||||
FileShare.Read, true))
|
|
||||||
{
|
|
||||||
await fileStream.WriteAsync(bytes, 0, bytes.Length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user