mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-06 22:07:13 -04:00
commit
b4b947c6e3
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.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
|
||||
namespace MediaBrowser.MediaEncoding.Encoder
|
||||
{
|
||||
@ -76,11 +77,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
protected readonly ISessionManager SessionManager;
|
||||
protected readonly Func<ISubtitleEncoder> SubtitleEncoder;
|
||||
protected readonly Func<IMediaSourceManager> MediaSourceManager;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IZipClient _zipClient;
|
||||
|
||||
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
|
||||
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;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
@ -93,6 +96,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
SessionManager = sessionManager;
|
||||
SubtitleEncoder = subtitleEncoder;
|
||||
MediaSourceManager = mediaSourceManager;
|
||||
_httpClient = httpClient;
|
||||
_zipClient = zipClient;
|
||||
FFProbePath = ffProbePath;
|
||||
FFMpegPath = ffMpegPath;
|
||||
|
||||
@ -142,6 +147,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
|
||||
SetAvailableDecoders(result.Item1);
|
||||
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\EncodingUtils.cs" />
|
||||
<Compile Include="Encoder\EncoderValidator.cs" />
|
||||
<Compile Include="Encoder\FontConfigLoader.cs" />
|
||||
<Compile Include="Encoder\JobLogger.cs" />
|
||||
<Compile Include="Encoder\MediaEncoder.cs" />
|
||||
<Compile Include="Encoder\VideoEncoder.cs" />
|
||||
|
@ -192,7 +192,7 @@ namespace MediaBrowser.Model.Configuration
|
||||
|
||||
public int MigrationVersion { get; set; }
|
||||
public int SchemaVersion { get; set; }
|
||||
public int SqliteCachePages { get; set; }
|
||||
public int SqliteCacheSizeKb { get; set; }
|
||||
|
||||
public bool DownloadImagesInAdvance { get; set; }
|
||||
|
||||
@ -212,7 +212,7 @@ namespace MediaBrowser.Model.Configuration
|
||||
{
|
||||
LocalNetworkAddresses = new string[] { };
|
||||
Migrations = new string[] { };
|
||||
SqliteCachePages = 10000;
|
||||
SqliteCacheSizeKb = 50000;
|
||||
|
||||
EnableCustomPathSubFolders = true;
|
||||
EnableLocalizedGuids = true;
|
||||
|
@ -33,13 +33,13 @@ namespace MediaBrowser.Server.Implementations.IO
|
||||
{
|
||||
logger.Debug("New file refresher created for {0}", path);
|
||||
Path = path;
|
||||
_affectedPaths.Add(path);
|
||||
|
||||
_fileSystem = fileSystem;
|
||||
ConfigurationManager = configurationManager;
|
||||
LibraryManager = libraryManager;
|
||||
TaskManager = taskManager;
|
||||
Logger = logger;
|
||||
AddPath(path);
|
||||
}
|
||||
|
||||
private void AddAffectedPath(string path)
|
||||
|
@ -123,7 +123,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
|
||||
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.SqliteCacheSizeKb;
|
||||
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[]
|
||||
{
|
||||
@ -2969,8 +2975,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||
}
|
||||
if (query.IsVirtualItem.HasValue)
|
||||
{
|
||||
whereClauses.Add("IsVirtualItem=@IsVirtualItem");
|
||||
cmd.Parameters.Add(cmd, "@IsVirtualItem", DbType.Boolean).Value = query.IsVirtualItem.Value;
|
||||
if (_config.Configuration.SchemaVersion >= 90)
|
||||
{
|
||||
whereClauses.Add("IsVirtualItem=@IsVirtualItem");
|
||||
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)
|
||||
{
|
||||
|
@ -660,7 +660,9 @@ namespace MediaBrowser.Server.Startup.Common
|
||||
ChannelManager,
|
||||
SessionManager,
|
||||
() => SubtitleEncoder,
|
||||
() => MediaSourceManager);
|
||||
() => MediaSourceManager,
|
||||
HttpClient,
|
||||
ZipClient);
|
||||
|
||||
MediaEncoder = mediaEncoder;
|
||||
RegisterSingleInstance(MediaEncoder);
|
||||
|
@ -2,14 +2,11 @@
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Net;
|
||||
using Mono.Unix.Native;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommonIO;
|
||||
@ -26,11 +23,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||
private readonly NativeEnvironment _environment;
|
||||
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)
|
||||
{
|
||||
_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.
|
||||
if (!string.IsNullOrWhiteSpace(customffMpegPath))
|
||||
{
|
||||
@ -132,30 +117,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||
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)
|
||||
{
|
||||
var encoderFilename = Path.GetFileName(info.EncoderPath);
|
||||
@ -270,12 +231,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
|
||||
_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)
|
||||
{
|
||||
@ -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