diff options
6 files changed, 201 insertions, 183 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs b/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs new file mode 100644 index 000000000..d7ef493c2 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs @@ -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); + } + } + } + } +} diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index a78e23669..383e93758 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -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); + } + } } } diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 794353451..1b5599577 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -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" /> diff --git a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs index 4bea6ad34..f48beacb5 100644 --- a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs +++ b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs @@ -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) diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 63bdddac9..bcd2ed8bd 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -660,7 +660,9 @@ namespace MediaBrowser.Server.Startup.Common ChannelManager, SessionManager, () => SubtitleEncoder, - () => MediaSourceManager); + () => MediaSourceManager, + HttpClient, + ZipClient); MediaEncoder = mediaEncoder; RegisterSingleInstance(MediaEncoder); diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs index 4c5759b56..68e2a4927 100644 --- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs +++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs @@ -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); - } - } - } } } |
