beginning remote subtitle downloading

This commit is contained in:
Luke Pulverenti
2014-05-06 22:28:19 -04:00
parent e1dd361c7b
commit 0d025f7fb6
49 changed files with 1035 additions and 299 deletions

View File

@@ -31,11 +31,11 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Controller.Themes;
using MediaBrowser.Dlna;
using MediaBrowser.Dlna.Eventing;
using MediaBrowser.Dlna.Main;
using MediaBrowser.Dlna.PlayTo;
using MediaBrowser.Dlna.Server;
using MediaBrowser.MediaEncoding.BdInfo;
using MediaBrowser.MediaEncoding.Encoder;
@@ -44,6 +44,7 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Updates;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.Subtitles;
using MediaBrowser.Server.Implementations;
using MediaBrowser.Server.Implementations.Channels;
using MediaBrowser.Server.Implementations.Collections;
@@ -193,6 +194,7 @@ namespace MediaBrowser.ServerApplication
private IProviderRepository ProviderRepository { get; set; }
private INotificationManager NotificationManager { get; set; }
private ISubtitleManager SubtitleManager { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationHost"/> class.
@@ -531,6 +533,9 @@ namespace MediaBrowser.ServerApplication
NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager);
RegisterSingleInstance(NotificationManager);
SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor);
RegisterSingleInstance(SubtitleManager);
var displayPreferencesTask = Task.Run(async () => await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false));
var itemsTask = Task.Run(async () => await ConfigureItemRepositories().ConfigureAwait(false));
var userdataTask = Task.Run(async () => await ConfigureUserDataRepositories().ConfigureAwait(false));
@@ -566,7 +571,7 @@ namespace MediaBrowser.ServerApplication
{
var info = await new FFMpegDownloader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager).GetFFMpegInfo(progress).ConfigureAwait(false);
MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), ApplicationPaths, JsonSerializer, info.Path, info.ProbePath, info.Version, FileSystemManager);
MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), ApplicationPaths, JsonSerializer, info.EncoderPath, info.ProbePath, info.Version, FileSystemManager);
RegisterSingleInstance(MediaEncoder);
}
@@ -710,6 +715,8 @@ namespace MediaBrowser.ServerApplication
LiveTvManager.AddParts(GetExports<ILiveTvService>());
SubtitleManager.AddParts(GetExports<ISubtitleProvider>());
SessionManager.AddParts(GetExports<ISessionControllerFactory>());
ChannelManager.AddParts(GetExports<IChannel>(), GetExports<IChannelFactory>());

View File

@@ -4,6 +4,8 @@ using Mono.Unix.Native;
using System.Text.RegularExpressions;
using System.IO;
#endif
using System.IO;
using System.Text.RegularExpressions;
namespace MediaBrowser.ServerApplication.FFMpeg
{
@@ -32,7 +34,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
switch (arg)
{
case "Version":
return "20140304";
return "20140506";
case "FFMpegFilename":
return "ffmpeg.exe";
case "FFProbeFilename":
@@ -42,7 +44,6 @@ namespace MediaBrowser.ServerApplication.FFMpeg
}
break;
#if __MonoCS__
case PlatformID.Unix:
if (PlatformDetection.IsMac)
{
@@ -69,7 +70,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
switch (arg)
{
case "Version":
return "20140304";
return "20140506";
case "FFMpegFilename":
return "ffmpeg";
case "FFProbeFilename":
@@ -85,7 +86,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
switch (arg)
{
case "Version":
return "20140304";
return "20140505";
case "FFMpegFilename":
return "ffmpeg";
case "FFProbeFilename":
@@ -98,7 +99,6 @@ namespace MediaBrowser.ServerApplication.FFMpeg
}
// Unsupported Unix platform
return "";
#endif
}
return "";
}
@@ -106,18 +106,17 @@ namespace MediaBrowser.ServerApplication.FFMpeg
private static string[] GetDownloadUrls()
{
var pid = Environment.OSVersion.Platform;
switch (pid)
{
case PlatformID.Win32NT:
return new[]
{
"http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20140304-git-f34cceb-win32-static.7z",
"https://www.dropbox.com/s/6brdetuzbld93jk/ffmpeg-20140304-git-f34cceb-win32-static.7z?dl=1"
"http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20140506-git-2baf1c8-win32-static.7z",
"https://www.dropbox.com/s/lxlzxs0r83iatsv/ffmpeg-20140506-git-2baf1c8-win32-static.7z?dl=1"
};
#if __MonoCS__
case PlatformID.Unix:
case PlatformID.Unix:
if (PlatformDetection.IsMac && PlatformDetection.IsX86_64)
{
return new[]
@@ -132,8 +131,8 @@ namespace MediaBrowser.ServerApplication.FFMpeg
{
return new[]
{
"http://ffmpeg.gusari.org/static/32bit/ffmpeg.static.32bit.2014-03-04.tar.gz",
"https://www.dropbox.com/s/0l76mcauqqkta31/ffmpeg.static.32bit.2014-03-04.tar.gz?dl=1"
"http://ffmpeg.gusari.org/static/32bit/ffmpeg.static.32bit.latest.tar.gz",
"https://www.dropbox.com/s/k9s02pv5to6slfb/ffmpeg.static.32bit.2014-05-06.tar.gz?dl=1"
};
}
@@ -141,22 +140,20 @@ namespace MediaBrowser.ServerApplication.FFMpeg
{
return new[]
{
"http://ffmpeg.gusari.org/static/64bit/ffmpeg.static.64bit.2014-03-04.tar.gz",
"https://www.dropbox.com/s/9wlxz440mdejuqe/ffmpeg.static.64bit.2014-03-04.tar.gz?dl=1"
"http://ffmpeg.gusari.org/static/64bit/ffmpeg.static.64bit.latest.tar.gz",
"https://www.dropbox.com/s/onuregwghywnzjo/ffmpeg.static.64bit.2014-05-05.tar.gz?dl=1"
};
}
}
//No Unix version available
return new string[] {};
#endif
return new string[] { };
}
return new string[] {};
return new string[] { };
}
}
#if __MonoCS__
public static class PlatformDetection
{
public readonly static bool IsWindows;
@@ -166,34 +163,52 @@ namespace MediaBrowser.ServerApplication.FFMpeg
public readonly static bool IsX86_64;
public readonly static bool IsArm;
static PlatformDetection ()
static PlatformDetection()
{
IsWindows = Path.DirectorySeparatorChar == '\\';
//Don't call uname on windows
if (!IsWindows)
{
Utsname uname;
var callResult = Syscall.uname(out uname);
if (callResult == 0)
{
IsMac = uname.sysname == "Darwin";
IsLinux = !IsMac && uname.sysname == "Linux";
var uname = GetUnixName();
Regex archX86 = new Regex("(i|I)[3-6]86");
IsX86 = archX86.IsMatch(uname.machine);
IsX86_64 = !IsX86 && uname.machine == "x86_64";
IsArm = !IsX86 && !IsX86 && uname.machine.StartsWith("arm");
}
IsMac = uname.sysname == "Darwin";
IsLinux = uname.sysname == "Linux";
var archX86 = new Regex("(i|I)[3-6]86");
IsX86 = archX86.IsMatch(uname.machine);
IsX86_64 = !IsX86 && uname.machine == "x86_64";
IsArm = !IsX86 && !IsX86_64 && uname.machine.StartsWith("arm");
}
else
{
if (System.Environment.Is64BitOperatingSystem)
if (Environment.Is64BitOperatingSystem)
IsX86_64 = true;
else
IsX86 = true;
}
}
private static Uname GetUnixName()
{
var uname = new Uname();
#if __MonoCS__
Utsname uname;
var callResult = Syscall.uname(out uname);
if (callResult == 0)
{
uname.sysname= uname.sysname;
uname.machine= uname.machine;
}
#endif
return uname;
}
}
public class Uname
{
public string sysname = string.Empty;
public string machine = string.Empty;
}
#endif
}

View File

@@ -42,63 +42,86 @@ namespace MediaBrowser.ServerApplication.FFMpeg
public async Task<FFMpegInfo> GetFFMpegInfo(IProgress<double> progress)
{
var versionedDirectoryPath = Path.Combine(GetMediaToolsPath(true), FFMpegDownloadInfo.Version);
var rootEncoderPath = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg");
var versionedDirectoryPath = Path.Combine(rootEncoderPath, FFMpegDownloadInfo.Version);
var info = new FFMpegInfo
{
ProbePath = Path.Combine(versionedDirectoryPath, FFMpegDownloadInfo.FFProbeFilename),
Path = Path.Combine(versionedDirectoryPath, FFMpegDownloadInfo.FFMpegFilename),
EncoderPath = Path.Combine(versionedDirectoryPath, FFMpegDownloadInfo.FFMpegFilename),
Version = FFMpegDownloadInfo.Version
};
Directory.CreateDirectory(versionedDirectoryPath);
var tasks = new List<Task>();
double ffmpegPercent = 0;
double fontPercent = 0;
var syncLock = new object();
if (!File.Exists(info.ProbePath) || !File.Exists(info.Path))
if (!File.Exists(info.ProbePath) || !File.Exists(info.EncoderPath))
{
var ffmpegProgress = new ActionableProgress<double>();
ffmpegProgress.RegisterAction(p =>
// ffmpeg not present. See if there's an older version we can start with
var existingVersion = GetExistingVersion(info, rootEncoderPath);
// No older version. Need to download and block until complete
if (existingVersion == null)
{
ffmpegPercent = p;
lock (syncLock)
{
progress.Report((ffmpegPercent / 2) + (fontPercent / 2));
}
});
tasks.Add(DownloadFFMpeg(info, ffmpegProgress));
}
else
{
ffmpegPercent = 100;
progress.Report(50);
}
var fontProgress = new ActionableProgress<double>();
fontProgress.RegisterAction(p =>
{
fontPercent = p;
lock (syncLock)
{
progress.Report((ffmpegPercent / 2) + (fontPercent / 2));
await DownloadFFMpeg(versionedDirectoryPath, progress).ConfigureAwait(false);
}
});
else
{
// Older version found.
// Start with that. Download new version in the background.
var newPath = versionedDirectoryPath;
Task.Run(() => DownloadFFMpegInBackground(newPath));
tasks.Add(DownloadFonts(versionedDirectoryPath, fontProgress));
info = existingVersion;
versionedDirectoryPath = Path.GetDirectoryName(info.EncoderPath);
}
}
await Task.WhenAll(tasks).ConfigureAwait(false);
await DownloadFonts(versionedDirectoryPath).ConfigureAwait(false);
return info;
}
private async Task DownloadFFMpeg(FFMpegInfo info, IProgress<double> progress)
private FFMpegInfo GetExistingVersion(FFMpegInfo info, string rootEncoderPath)
{
var encoderFilename = Path.GetFileName(info.EncoderPath);
var probeFilename = Path.GetFileName(info.ProbePath);
foreach (var directory in Directory.EnumerateDirectories(rootEncoderPath, "*", SearchOption.TopDirectoryOnly)
.ToList())
{
var allFiles = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories).ToList();
var encoder = allFiles.FirstOrDefault(i => string.Equals(Path.GetFileName(i), encoderFilename, StringComparison.OrdinalIgnoreCase));
var probe = allFiles.FirstOrDefault(i => string.Equals(Path.GetFileName(i), probeFilename, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(encoder) &&
!string.IsNullOrWhiteSpace(probe))
{
return new FFMpegInfo
{
EncoderPath = encoder,
ProbePath = probe,
Version = Path.GetFileNameWithoutExtension(Path.GetDirectoryName(probe))
};
}
}
return null;
}
private async void DownloadFFMpegInBackground(string directory)
{
try
{
await DownloadFFMpeg(directory, new Progress<double>()).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.ErrorException("Error downloading ffmpeg", ex);
}
}
private async Task DownloadFFMpeg(string directory, IProgress<double> progress)
{
foreach (var url in FFMpegDownloadInfo.FfMpegUrls)
{
@@ -114,7 +137,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
}).ConfigureAwait(false);
ExtractFFMpeg(tempFile, Path.GetDirectoryName(info.Path));
ExtractFFMpeg(tempFile, directory);
return;
}
catch (HttpException ex)
@@ -132,7 +155,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
private void ExtractFFMpeg(string tempFile, string targetFolder)
{
_logger.Debug("Extracting ffmpeg from {0}", tempFile);
_logger.Info("Extracting ffmpeg from {0}", tempFile);
var tempFolder = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString());
@@ -171,6 +194,8 @@ namespace MediaBrowser.ServerApplication.FFMpeg
private void ExtractArchive(string archivePath, string targetPath)
{
_logger.Info("Extracting {0} to {1}", archivePath, targetPath);
if (string.Equals(FFMpegDownloadInfo.ArchiveType, "7z", StringComparison.OrdinalIgnoreCase))
{
_zipClient.ExtractAllFrom7z(archivePath, targetPath, true);
@@ -182,6 +207,8 @@ namespace MediaBrowser.ServerApplication.FFMpeg
}
private void Extract7zArchive(string archivePath, string targetPath)
{
_logger.Info("Extracting {0} to {1}", archivePath, targetPath);
_zipClient.ExtractAllFrom7z(archivePath, targetPath, true);
}
@@ -201,7 +228,8 @@ namespace MediaBrowser.ServerApplication.FFMpeg
/// Extracts the fonts.
/// </summary>
/// <param name="targetPath">The target path.</param>
private async Task DownloadFonts(string targetPath, IProgress<double> progress)
/// <returns>Task.</returns>
private async Task DownloadFonts(string targetPath)
{
try
{
@@ -213,12 +241,19 @@ namespace MediaBrowser.ServerApplication.FFMpeg
var fontFile = Path.Combine(fontsDirectory, fontFilename);
if (!File.Exists(fontFile))
if (File.Exists(fontFile))
{
await DownloadFontFile(fontsDirectory, fontFilename, progress).ConfigureAwait(false);
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);
});
}
await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
}
catch (HttpException ex)
{
@@ -230,8 +265,6 @@ namespace MediaBrowser.ServerApplication.FFMpeg
// Don't let the server crash because of this
_logger.ErrorException("Error writing ffmpeg font files", ex);
}
progress.Report(100);
}
/// <summary>
@@ -325,19 +358,5 @@ namespace MediaBrowser.ServerApplication.FFMpeg
}
}
}
/// <summary>
/// Gets the media tools path.
/// </summary>
/// <param name="create">if set to <c>true</c> [create].</param>
/// <returns>System.String.</returns>
private string GetMediaToolsPath(bool create)
{
var path = Path.Combine(_appPaths.ProgramDataPath, "ffmpeg");
Directory.CreateDirectory(path);
return path;
}
}
}

View File

@@ -9,7 +9,7 @@
/// Gets or sets the path.
/// </summary>
/// <value>The path.</value>
public string Path { get; set; }
public string EncoderPath { get; set; }
/// <summary>
/// Gets or sets the probe path.
/// </summary>