2
0
Эх сурвалжийг харах

Prevent server from starting if the ffmpeg path is invalid (#12463)

gnattu 9 сар өмнө
parent
commit
6c8ca30f7f

+ 6 - 1
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");

+ 2 - 1
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 }
         };
     }
 }

+ 13 - 0
MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs

@@ -29,6 +29,11 @@ namespace MediaBrowser.Controller.Extensions
         /// </summary>
         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>
@@ -89,6 +94,14 @@ namespace MediaBrowser.Controller.Extensions
         public static string? GetFFmpegAnalyzeDuration(this IConfiguration configuration)
             => 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>

+ 2 - 8
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.

+ 18 - 63
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;
             }
 

+ 2 - 0
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();