Prevent server from starting if the ffmpeg path is invalid (#12463)
This commit is contained in:
parent
8c3f3c503b
commit
6c8ca30f7f
|
@ -402,7 +402,12 @@ namespace Emby.Server.Implementations
|
||||||
ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
|
ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
|
||||||
ConfigurationManager.NamedConfigurationUpdated += OnConfigurationUpdated;
|
ConfigurationManager.NamedConfigurationUpdated += OnConfigurationUpdated;
|
||||||
|
|
||||||
Resolve<IMediaEncoder>().SetFFmpegPath();
|
var ffmpegValid = Resolve<IMediaEncoder>().SetFFmpegPath();
|
||||||
|
|
||||||
|
if (!ffmpegValid)
|
||||||
|
{
|
||||||
|
throw new FfmpegException("Failed to find valid ffmpeg");
|
||||||
|
}
|
||||||
|
|
||||||
Logger.LogInformation("ServerId: {ServerId}", SystemId);
|
Logger.LogInformation("ServerId: {ServerId}", SystemId);
|
||||||
Logger.LogInformation("Core startup complete");
|
Logger.LogInformation("Core startup complete");
|
||||||
|
|
|
@ -19,7 +19,8 @@ namespace Emby.Server.Implementations
|
||||||
{ FfmpegAnalyzeDurationKey, "200M" },
|
{ FfmpegAnalyzeDurationKey, "200M" },
|
||||||
{ PlaylistsAllowDuplicatesKey, bool.FalseString },
|
{ PlaylistsAllowDuplicatesKey, bool.FalseString },
|
||||||
{ BindToUnixSocketKey, bool.FalseString },
|
{ BindToUnixSocketKey, bool.FalseString },
|
||||||
{ SqliteCacheSizeKey, "20000" }
|
{ SqliteCacheSizeKey, "20000" },
|
||||||
|
{ FfmpegSkipValidationKey, bool.FalseString }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,11 @@ namespace MediaBrowser.Controller.Extensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string FfmpegProbeSizeKey = "FFmpeg:probesize";
|
public const string FfmpegProbeSizeKey = "FFmpeg:probesize";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The key for the skipping FFmpeg validation.
|
||||||
|
/// </summary>
|
||||||
|
public const string FfmpegSkipValidationKey = "FFmpeg:novalidation";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The key for the FFmpeg analyze duration option.
|
/// The key for the FFmpeg analyze duration option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -89,6 +94,14 @@ namespace MediaBrowser.Controller.Extensions
|
||||||
public static string? GetFFmpegAnalyzeDuration(this IConfiguration configuration)
|
public static string? GetFFmpegAnalyzeDuration(this IConfiguration configuration)
|
||||||
=> configuration[FfmpegAnalyzeDurationKey];
|
=> configuration[FfmpegAnalyzeDurationKey];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the server should validate FFmpeg during startup.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration">The configuration to read the setting from.</param>
|
||||||
|
/// <returns><c>true</c> if the server should validate FFmpeg during startup, otherwise <c>false</c>.</returns>
|
||||||
|
public static bool GetFFmpegSkipValidation(this IConfiguration configuration)
|
||||||
|
=> configuration.GetValue<bool>(FfmpegSkipValidationKey);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether playlists should allow duplicate entries from the <see cref="IConfiguration"/>.
|
/// Gets a value indicating whether playlists should allow duplicate entries from the <see cref="IConfiguration"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -223,14 +223,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the path to find FFmpeg.
|
/// Sets the path to find FFmpeg.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void SetFFmpegPath();
|
/// <returns>bool indicates whether a valid ffmpeg is found.</returns>
|
||||||
|
bool SetFFmpegPath();
|
||||||
/// <summary>
|
|
||||||
/// Updates the encoder path.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path.</param>
|
|
||||||
/// <param name="pathType">The type of path.</param>
|
|
||||||
void UpdateEncoderPath(string path, string pathType);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the primary playlist of .vob files.
|
/// Gets the primary playlist of .vob files.
|
||||||
|
|
|
@ -147,28 +147,41 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
private static partial Regex FfprobePathRegex();
|
private static partial Regex FfprobePathRegex();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Run at startup or if the user removes a Custom path from transcode page.
|
/// Run at startup to validate ffmpeg.
|
||||||
/// Sets global variables FFmpegPath.
|
/// Sets global variables FFmpegPath.
|
||||||
/// Precedence is: Config > CLI > $PATH.
|
/// Precedence is: CLI/Env var > Config > $PATH.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetFFmpegPath()
|
/// <returns>bool indicates whether a valid ffmpeg is found.</returns>
|
||||||
|
public bool SetFFmpegPath()
|
||||||
{
|
{
|
||||||
|
var skipValidation = _config.GetFFmpegSkipValidation();
|
||||||
|
if (skipValidation)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("FFmpeg: Skipping FFmpeg Validation due to FFmpeg:novalidation set to true");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// 1) Check if the --ffmpeg CLI switch has been given
|
// 1) Check if the --ffmpeg CLI switch has been given
|
||||||
var ffmpegPath = _startupOptionFFmpegPath;
|
var ffmpegPath = _startupOptionFFmpegPath;
|
||||||
|
string ffmpegPathSetMethodText = "command line or environment variable";
|
||||||
if (string.IsNullOrEmpty(ffmpegPath))
|
if (string.IsNullOrEmpty(ffmpegPath))
|
||||||
{
|
{
|
||||||
// 2) Custom path stored in config/encoding xml file under tag <EncoderAppPath> should be used as a fallback
|
// 2) Custom path stored in config/encoding xml file under tag <EncoderAppPath> should be used as a fallback
|
||||||
ffmpegPath = _configurationManager.GetEncodingOptions().EncoderAppPath;
|
ffmpegPath = _configurationManager.GetEncodingOptions().EncoderAppPath;
|
||||||
|
ffmpegPathSetMethodText = "encoding.xml config file";
|
||||||
if (string.IsNullOrEmpty(ffmpegPath))
|
if (string.IsNullOrEmpty(ffmpegPath))
|
||||||
{
|
{
|
||||||
// 3) Check "ffmpeg"
|
// 3) Check "ffmpeg"
|
||||||
ffmpegPath = "ffmpeg";
|
ffmpegPath = "ffmpeg";
|
||||||
|
ffmpegPathSetMethodText = "system $PATH";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidatePath(ffmpegPath))
|
if (!ValidatePath(ffmpegPath))
|
||||||
{
|
{
|
||||||
_ffmpegPath = null;
|
_ffmpegPath = null;
|
||||||
|
_logger.LogError("FFmpeg: Path set by {FfmpegPathSetMethodText} is invalid", ffmpegPathSetMethodText);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the FFmpeg path to the config/encoding.xml file as <EncoderAppPathDisplay> so it appears in UI
|
// Write the FFmpeg path to the config/encoding.xml file as <EncoderAppPathDisplay> so it appears in UI
|
||||||
|
@ -229,65 +242,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("FFmpeg: {FfmpegPath}", _ffmpegPath ?? string.Empty);
|
_logger.LogInformation("FFmpeg: {FfmpegPath}", _ffmpegPath ?? string.Empty);
|
||||||
}
|
return !string.IsNullOrWhiteSpace(ffmpegPath);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggered from the Settings > Transcoding UI page when users submits Custom FFmpeg path to use.
|
|
||||||
/// Only write the new path to xml if it exists. Do not perform validation checks on ffmpeg here.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path.</param>
|
|
||||||
/// <param name="pathType">The path type.</param>
|
|
||||||
public void UpdateEncoderPath(string path, string pathType)
|
|
||||||
{
|
|
||||||
var config = _configurationManager.GetEncodingOptions();
|
|
||||||
|
|
||||||
// Filesystem may not be case insensitive, but EncoderAppPathDisplay should always point to a valid file?
|
|
||||||
if (string.IsNullOrEmpty(config.EncoderAppPath)
|
|
||||||
&& string.Equals(config.EncoderAppPathDisplay, path, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
_logger.LogDebug("Existing ffmpeg path is empty and the new path is the same as {EncoderAppPathDisplay}. Skipping", nameof(config.EncoderAppPathDisplay));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string newPath;
|
|
||||||
|
|
||||||
_logger.LogInformation("Attempting to update encoder path to {Path}. pathType: {PathType}", path ?? string.Empty, pathType ?? string.Empty);
|
|
||||||
|
|
||||||
if (!string.Equals(pathType, "custom", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Unexpected pathType value");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(path))
|
|
||||||
{
|
|
||||||
// User had cleared the custom path in UI
|
|
||||||
newPath = string.Empty;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Directory.Exists(path))
|
|
||||||
{
|
|
||||||
// Given path is directory, so resolve down to filename
|
|
||||||
newPath = GetEncoderPathFromDirectory(path, "ffmpeg");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!new EncoderValidator(_logger, newPath).ValidateVersion())
|
|
||||||
{
|
|
||||||
throw new ResourceNotFoundException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the new ffmpeg path to the xml as <EncoderAppPath>
|
|
||||||
// This ensures its not lost on next startup
|
|
||||||
config.EncoderAppPath = newPath;
|
|
||||||
_configurationManager.SaveConfiguration("encoding", config);
|
|
||||||
|
|
||||||
// Trigger SetFFmpegPath so we validate the new path and setup probe path
|
|
||||||
SetFFmpegPath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -306,7 +261,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
bool rc = new EncoderValidator(_logger, path).ValidateVersion();
|
bool rc = new EncoderValidator(_logger, path).ValidateVersion();
|
||||||
if (!rc)
|
if (!rc)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("FFmpeg: Failed version check: {Path}", path);
|
_logger.LogError("FFmpeg: Failed version check: {Path}", path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,8 @@ namespace Jellyfin.Server.Integration.Tests
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
|
// Skip ffmpeg check for testing
|
||||||
|
Environment.SetEnvironmentVariable("JELLYFIN_FFMPEG__NOVALIDATION", "true");
|
||||||
// Specify the startup command line options
|
// Specify the startup command line options
|
||||||
var commandLineOpts = new StartupOptions();
|
var commandLineOpts = new StartupOptions();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user