From ff4f3ec7a3ca4c0b7a1a638ede4042f1d2bc896c Mon Sep 17 00:00:00 2001 From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> Date: Mon, 19 Aug 2024 01:49:25 +0300 Subject: [PATCH] Check that FFmpeg exists on launch (#485) --- YoutubeDownloader.Core/Downloading/FFmpeg.cs | 32 +++++++++++++++++++ .../Downloading/VideoDownloader.cs | 1 + YoutubeDownloader/Services/SettingsService.cs | 2 +- YoutubeDownloader/ViewModels/MainViewModel.cs | 26 +++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 YoutubeDownloader.Core/Downloading/FFmpeg.cs diff --git a/YoutubeDownloader.Core/Downloading/FFmpeg.cs b/YoutubeDownloader.Core/Downloading/FFmpeg.cs new file mode 100644 index 000000000..6d4cf2316 --- /dev/null +++ b/YoutubeDownloader.Core/Downloading/FFmpeg.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace YoutubeDownloader.Core.Downloading; + +public static class FFmpeg +{ + public static string? TryGetCliFilePath() + { + static IEnumerable GetProbeDirectoryPaths() + { + yield return AppContext.BaseDirectory; + yield return Directory.GetCurrentDirectory(); + + foreach ( + var path in Environment.GetEnvironmentVariable("PATH")?.Split(Path.PathSeparator) + ?? Enumerable.Empty() + ) + { + yield return path; + } + } + + return GetProbeDirectoryPaths() + .Select(dirPath => + Path.Combine(dirPath, OperatingSystem.IsWindows() ? "ffmpeg.exe" : "ffmpeg") + ) + .FirstOrDefault(File.Exists); + } +} diff --git a/YoutubeDownloader.Core/Downloading/VideoDownloader.cs b/YoutubeDownloader.Core/Downloading/VideoDownloader.cs index 522b19429..610d44d26 100644 --- a/YoutubeDownloader.Core/Downloading/VideoDownloader.cs +++ b/YoutubeDownloader.Core/Downloading/VideoDownloader.cs @@ -67,6 +67,7 @@ await _youtube.Videos.DownloadAsync( downloadOption.StreamInfos, trackInfos, new ConversionRequestBuilder(filePath) + .SetFFmpegPath(FFmpeg.TryGetCliFilePath() ?? "ffmpeg") .SetContainer(downloadOption.Container) .SetPreset(ConversionPreset.Medium) .Build(), diff --git a/YoutubeDownloader/Services/SettingsService.cs b/YoutubeDownloader/Services/SettingsService.cs index eb8b3db2d..e328212cf 100644 --- a/YoutubeDownloader/Services/SettingsService.cs +++ b/YoutubeDownloader/Services/SettingsService.cs @@ -17,7 +17,7 @@ namespace YoutubeDownloader.Services; [INotifyPropertyChanged] public partial class SettingsService() : SettingsBase( - Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Settings.dat"), + Path.Combine(AppContext.BaseDirectory, "Settings.dat"), SerializerContext.Default ) { diff --git a/YoutubeDownloader/ViewModels/MainViewModel.cs b/YoutubeDownloader/ViewModels/MainViewModel.cs index 2e3ba7f28..caddf8ff3 100644 --- a/YoutubeDownloader/ViewModels/MainViewModel.cs +++ b/YoutubeDownloader/ViewModels/MainViewModel.cs @@ -3,6 +3,8 @@ using System.Threading.Tasks; using Avalonia; using CommunityToolkit.Mvvm.Input; +using YoutubeDownloader.Core; +using YoutubeDownloader.Core.Downloading; using YoutubeDownloader.Framework; using YoutubeDownloader.Services; using YoutubeDownloader.Utils; @@ -71,6 +73,29 @@ private async Task ShowDevelopmentBuildMessageAsync() ProcessEx.StartShellExecute(Program.ProjectReleasesUrl); } + private async Task ShowFFmpegMessageAsync() + { + if (!string.IsNullOrWhiteSpace(FFmpeg.TryGetCliFilePath())) + return; + + var dialog = viewModelManager.CreateMessageBoxViewModel( + "FFmpeg is missing", + $""" + FFmpeg is required for {Program.Name} to work. Please download it and make it available in the application directory or on the system PATH. + + Click DOWNLOAD to go to the FFmpeg download page. You can also install FFmpeg using a package manager instead. + """, + "DOWNLOAD", + "CLOSE" + ); + + if (await dialogManager.ShowDialogAsync(dialog) == true) + ProcessEx.StartShellExecute("https://ffmpeg.org/download.html"); + + if (Application.Current?.ApplicationLifetime?.TryShutdown(3) != true) + Environment.Exit(3); + } + private async Task CheckForUpdatesAsync() { try @@ -106,6 +131,7 @@ private async Task InitializeAsync() { await ShowUkraineSupportMessageAsync(); await ShowDevelopmentBuildMessageAsync(); + await ShowFFmpegMessageAsync(); await CheckForUpdatesAsync(); }