From fe5a9232c84cea113336005b3c7cbd7fe77a2d80 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 24 Sep 2013 20:54:51 -0400 Subject: moved a few things for mono --- .../FFMpeg/FFMpegDownloader.cs | 302 +++++++++++++++++++++ .../FFMpeg/FFMpegInfo.cs | 24 ++ ...0904-git-f974289-win32-static.7z.REMOVED.git-id | 1 + 3 files changed, 327 insertions(+) create mode 100644 MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs create mode 100644 MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs create mode 100644 MediaBrowser.ServerApplication/FFMpeg/ffmpeg-20130904-git-f974289-win32-static.7z.REMOVED.git-id (limited to 'MediaBrowser.ServerApplication/FFMpeg') diff --git a/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs b/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs new file mode 100644 index 0000000000..c43a85c87f --- /dev/null +++ b/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs @@ -0,0 +1,302 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; +using MediaBrowser.Common.Net; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.ServerApplication.FFMpeg +{ + public class FFMpegDownloader + { + private readonly IHttpClient _httpClient; + private readonly IApplicationPaths _appPaths; + private readonly ILogger _logger; + private readonly IZipClient _zipClient; + + private const string Version = "ffmpeg20130904"; + + private readonly string[] _fontUrls = new[] + { + "https://www.dropbox.com/s/pj847twf7riq0j7/ARIALUNI.7z?dl=1" + }; + + private readonly string[] _ffMpegUrls = new[] + { + "https://raw.github.com/MediaBrowser/MediaBrowser/master/MediaBrowser.ServerApplication/Implementations/ffmpeg-20130904-git-f974289-win32-static.7z", + + "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20130904-git-f974289-win32-static.7z", + "https://www.dropbox.com/s/a81cb2ob23fwcfs/ffmpeg-20130904-git-f974289-win32-static.7z?dl=1" + }; + + public FFMpegDownloader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient) + { + _logger = logger; + _appPaths = appPaths; + _httpClient = httpClient; + _zipClient = zipClient; + } + + public async Task GetFFMpegInfo() + { + var versionedDirectoryPath = Path.Combine(GetMediaToolsPath(true), Version); + + var info = new FFMpegInfo + { + ProbePath = Path.Combine(versionedDirectoryPath, "ffprobe.exe"), + Path = Path.Combine(versionedDirectoryPath, "ffmpeg.exe"), + Version = Version + }; + + if (!Directory.Exists(versionedDirectoryPath)) + { + Directory.CreateDirectory(versionedDirectoryPath); + } + + var tasks = new List(); + + if (!File.Exists(info.ProbePath) || !File.Exists(info.Path)) + { + tasks.Add(DownloadFFMpeg(info)); + } + + tasks.Add(DownloadFonts(versionedDirectoryPath)); + + await Task.WhenAll(tasks).ConfigureAwait(false); + + return info; + } + + private async Task DownloadFFMpeg(FFMpegInfo info) + { + foreach (var url in _ffMpegUrls) + { + try + { + var tempFile = await DownloadFFMpeg(info, url).ConfigureAwait(false); + + ExtractFFMpeg(tempFile, Path.GetDirectoryName(info.Path)); + return; + } + catch (HttpException ex) + { + + } + } + + throw new ApplicationException("Unable to download required components. Please try again later."); + } + + private Task DownloadFFMpeg(FFMpegInfo info, string url) + { + return _httpClient.GetTempFile(new HttpRequestOptions + { + Url = url, + CancellationToken = CancellationToken.None, + Progress = new Progress(), + + // Make it look like a browser + // Try to hide that we're direct linking + UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.47 Safari/537.36" + }); + } + + private void ExtractFFMpeg(string tempFile, string targetFolder) + { + _logger.Debug("Extracting ffmpeg from {0}", tempFile); + + var tempFolder = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString()); + + if (!Directory.Exists(tempFolder)) + { + Directory.CreateDirectory(tempFolder); + } + + try + { + Extract7zArchive(tempFile, tempFolder); + + var files = Directory.EnumerateFiles(tempFolder, "*.exe", SearchOption.AllDirectories).ToList(); + + foreach (var file in files) + { + File.Copy(file, Path.Combine(targetFolder, Path.GetFileName(file))); + } + } + finally + { + DeleteFile(tempFile); + } + } + + private void Extract7zArchive(string archivePath, string targetPath) + { + _zipClient.ExtractAllFrom7z(archivePath, targetPath, true); + } + + private void DeleteFile(string path) + { + try + { + File.Delete(path); + } + catch (IOException ex) + { + _logger.ErrorException("Error deleting temp file {0}", ex, path); + } + } + + /// + /// Extracts the fonts. + /// + /// The target path. + private async Task DownloadFonts(string targetPath) + { + try + { + var fontsDirectory = Path.Combine(targetPath, "fonts"); + + if (!Directory.Exists(fontsDirectory)) + { + Directory.CreateDirectory(fontsDirectory); + } + + const string fontFilename = "ARIALUNI.TTF"; + + var fontFile = Path.Combine(fontsDirectory, fontFilename); + + if (!File.Exists(fontFile)) + { + await DownloadFontFile(fontsDirectory, fontFilename).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); + } + } + + /// + /// Downloads the font file. + /// + /// The fonts directory. + /// The font filename. + /// Task. + private async Task DownloadFontFile(string fontsDirectory, string fontFilename) + { + var existingFile = Directory + .EnumerateFiles(_appPaths.ProgramDataPath, fontFilename, SearchOption.AllDirectories) + .FirstOrDefault(); + + if (existingFile != null) + { + try + { + File.Copy(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) + { + try + { + tempFile = await _httpClient.GetTempFile(new HttpRequestOptions + { + Url = url, + Progress = new 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 + { + File.Delete(tempFile); + } + catch (IOException ex) + { + // Log this, but don't let it fail the operation + _logger.ErrorException("Error deleting temp file {0}", ex, tempFile); + } + } + + /// + /// Writes the font config file. + /// + /// The fonts directory. + /// Task. + private async Task WriteFontConfigFile(string fontsDirectory) + { + const string fontConfigFilename = "fonts.conf"; + var fontConfigFile = Path.Combine(fontsDirectory, fontConfigFilename); + + if (!File.Exists(fontConfigFile)) + { + var contents = string.Format("{0}ArialArial Unicode MS", fontsDirectory); + + var bytes = Encoding.UTF8.GetBytes(contents); + + using (var fileStream = new FileStream(fontConfigFile, FileMode.Create, FileAccess.Write, + FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, + FileOptions.Asynchronous)) + { + await fileStream.WriteAsync(bytes, 0, bytes.Length); + } + } + } + + /// + /// Gets the media tools path. + /// + /// if set to true [create]. + /// System.String. + private string GetMediaToolsPath(bool create) + { + var path = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg"); + + if (create && !Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + + return path; + } + } +} diff --git a/MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs b/MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs new file mode 100644 index 0000000000..147a9f7717 --- /dev/null +++ b/MediaBrowser.ServerApplication/FFMpeg/FFMpegInfo.cs @@ -0,0 +1,24 @@ +namespace MediaBrowser.ServerApplication.FFMpeg +{ + /// + /// Class FFMpegInfo + /// + public class FFMpegInfo + { + /// + /// Gets or sets the path. + /// + /// The path. + public string Path { get; set; } + /// + /// Gets or sets the probe path. + /// + /// The probe path. + public string ProbePath { get; set; } + /// + /// Gets or sets the version. + /// + /// The version. + public string Version { get; set; } + } +} \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/FFMpeg/ffmpeg-20130904-git-f974289-win32-static.7z.REMOVED.git-id b/MediaBrowser.ServerApplication/FFMpeg/ffmpeg-20130904-git-f974289-win32-static.7z.REMOVED.git-id new file mode 100644 index 0000000000..9f83b949b4 --- /dev/null +++ b/MediaBrowser.ServerApplication/FFMpeg/ffmpeg-20130904-git-f974289-win32-static.7z.REMOVED.git-id @@ -0,0 +1 @@ +8f1dfd62d31e48c31bef4b9ccc0e514f46650a79 \ No newline at end of file -- cgit v1.2.3