aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgnattu <gnattu@users.noreply.github.com>2024-08-29 02:43:37 +0800
committerGitHub <noreply@github.com>2024-08-28 12:43:37 -0600
commit6c8ca30f7fc02170901a969c71dc35ec8992ad02 (patch)
tree20e674033780ce8254fd41e467c9c1fe3d03bdbc
parent8c3f3c503b4b0606e2987ed58e5228d72669afeb (diff)
Prevent server from starting if the ffmpeg path is invalid (#12463)
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs7
-rw-r--r--Emby.Server.Implementations/ConfigurationOptions.cs3
-rw-r--r--MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs13
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs10
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs81
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs2
6 files changed, 43 insertions, 73 deletions
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index ceda0bd64..5292003f0 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -402,7 +402,12 @@ namespace Emby.Server.Implementations
ConfigurationManager.ConfigurationUpdated += 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("Core startup complete");
diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs
index f0c267627..e86010513 100644
--- a/Emby.Server.Implementations/ConfigurationOptions.cs
+++ b/Emby.Server.Implementations/ConfigurationOptions.cs
@@ -19,7 +19,8 @@ namespace Emby.Server.Implementations
{ FfmpegAnalyzeDurationKey, "200M" },
{ PlaylistsAllowDuplicatesKey, bool.FalseString },
{ BindToUnixSocketKey, bool.FalseString },
- { SqliteCacheSizeKey, "20000" }
+ { SqliteCacheSizeKey, "20000" },
+ { FfmpegSkipValidationKey, bool.FalseString }
};
}
}
diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs
index 6c58064ce..0aaf4fcd9 100644
--- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs
+++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs
@@ -30,6 +30,11 @@ namespace MediaBrowser.Controller.Extensions
public const string FfmpegProbeSizeKey = "FFmpeg:probesize";
/// <summary>
+ /// The key for the skipping FFmpeg validation.
+ /// </summary>
+ public const string FfmpegSkipValidationKey = "FFmpeg:novalidation";
+
+ /// <summary>
/// The key for the FFmpeg analyze duration option.
/// </summary>
public const string FfmpegAnalyzeDurationKey = "FFmpeg:analyzeduration";
@@ -90,6 +95,14 @@ namespace MediaBrowser.Controller.Extensions
=> 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>
/// Gets a value indicating whether playlists should allow duplicate entries from the <see cref="IConfiguration"/>.
/// </summary>
/// <param name="configuration">The configuration to read the setting from.</param>
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 038c6c7f6..e36106e52 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -223,14 +223,8 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Sets the path to find FFmpeg.
/// </summary>
- void 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);
+ /// <returns>bool indicates whether a valid ffmpeg is found.</returns>
+ bool SetFFmpegPath();
/// <summary>
/// Gets the primary playlist of .vob files.
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index e8461e77f..d9fe0594f 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -147,28 +147,41 @@ namespace MediaBrowser.MediaEncoding.Encoder
private static partial Regex FfprobePathRegex();
/// <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.
- /// Precedence is: Config > CLI > $PATH.
+ /// Precedence is: CLI/Env var > Config > $PATH.
/// </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
var ffmpegPath = _startupOptionFFmpegPath;
+ string ffmpegPathSetMethodText = "command line or environment variable";
if (string.IsNullOrEmpty(ffmpegPath))
{
// 2) Custom path stored in config/encoding xml file under tag <EncoderAppPath> should be used as a fallback
ffmpegPath = _configurationManager.GetEncodingOptions().EncoderAppPath;
+ ffmpegPathSetMethodText = "encoding.xml config file";
if (string.IsNullOrEmpty(ffmpegPath))
{
// 3) Check "ffmpeg"
ffmpegPath = "ffmpeg";
+ ffmpegPathSetMethodText = "system $PATH";
}
}
if (!ValidatePath(ffmpegPath))
{
_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
@@ -229,65 +242,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
_logger.LogInformation("FFmpeg: {FfmpegPath}", _ffmpegPath ?? string.Empty);
- }
-
- /// <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();
+ return !string.IsNullOrWhiteSpace(ffmpegPath);
}
/// <summary>
@@ -306,7 +261,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
bool rc = new EncoderValidator(_logger, path).ValidateVersion();
if (!rc)
{
- _logger.LogWarning("FFmpeg: Failed version check: {Path}", path);
+ _logger.LogError("FFmpeg: Failed version check: {Path}", path);
return false;
}
diff --git a/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs b/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs
index a078eff77..78b32d278 100644
--- a/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs
+++ b/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs
@@ -47,6 +47,8 @@ namespace Jellyfin.Server.Integration.Tests
/// <inheritdoc/>
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
+ // Skip ffmpeg check for testing
+ Environment.SetEnvironmentVariable("JELLYFIN_FFMPEG__NOVALIDATION", "true");
// Specify the startup command line options
var commandLineOpts = new StartupOptions();