using System.Diagnostics; using System.IO; using System.Threading; using System.Threading.Tasks; using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Metadata; using ErsatzTV.Core.Interfaces.Repositories; using LanguageExt; namespace ErsatzTV.Application.FFmpegProfiles.Commands { public class UpdateFFmpegSettingsHandler : MediatR.IRequestHandler> { private readonly IConfigElementRepository _configElementRepository; private readonly ILocalFileSystem _localFileSystem; public UpdateFFmpegSettingsHandler( IConfigElementRepository configElementRepository, ILocalFileSystem localFileSystem) { _configElementRepository = configElementRepository; _localFileSystem = localFileSystem; } public Task> Handle( UpdateFFmpegSettings request, CancellationToken cancellationToken) => Validate(request) .MapT(_ => ApplyUpdate(request)) .Bind(v => v.ToEitherAsync()); private async Task> Validate(UpdateFFmpegSettings request) => (await FFmpegMustExist(request), await FFprobeMustExist(request)) .Apply((_, _) => Unit.Default); private Task> FFmpegMustExist(UpdateFFmpegSettings request) => ValidateToolPath(request.Settings.FFmpegPath, "ffmpeg"); private Task> FFprobeMustExist(UpdateFFmpegSettings request) => ValidateToolPath(request.Settings.FFprobePath, "ffprobe"); private async Task> ValidateToolPath(string path, string name) { if (!_localFileSystem.FileExists(path)) { return BaseError.New($"{name} path does not exist"); } var startInfo = new ProcessStartInfo { FileName = path, Arguments = "-version", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false }; var test = new Process { StartInfo = startInfo }; test.Start(); string output = await test.StandardOutput.ReadToEndAsync(); await test.WaitForExitAsync(); return test.ExitCode == 0 && output.Contains($"{name} version") ? Unit.Default : BaseError.New($"Unable to verify {name} version"); } private async Task ApplyUpdate(UpdateFFmpegSettings request) { await _configElementRepository.Get(ConfigElementKey.FFmpegPath).Match( ce => { ce.Value = request.Settings.FFmpegPath; _configElementRepository.Update(ce); }, () => { var ce = new ConfigElement { Key = ConfigElementKey.FFmpegPath.Key, Value = request.Settings.FFmpegPath }; _configElementRepository.Add(ce); }); await _configElementRepository.Get(ConfigElementKey.FFprobePath).Match( ce => { ce.Value = request.Settings.FFprobePath; _configElementRepository.Update(ce); }, () => { var ce = new ConfigElement { Key = ConfigElementKey.FFprobePath.Key, Value = request.Settings.FFprobePath }; _configElementRepository.Add(ce); }); await _configElementRepository.Get(ConfigElementKey.FFmpegDefaultProfileId).Match( ce => { ce.Value = request.Settings.DefaultFFmpegProfileId.ToString(); _configElementRepository.Update(ce); }, () => { var ce = new ConfigElement { Key = ConfigElementKey.FFmpegDefaultProfileId.Key, Value = request.Settings.DefaultFFmpegProfileId.ToString() }; _configElementRepository.Add(ce); }); await _configElementRepository.Get(ConfigElementKey.FFmpegSaveReports).Match( ce => { ce.Value = request.Settings.SaveReports.ToString(); _configElementRepository.Update(ce); }, () => { var ce = new ConfigElement { Key = ConfigElementKey.FFmpegSaveReports.Key, Value = request.Settings.SaveReports.ToString() }; _configElementRepository.Add(ce); }); if (request.Settings.SaveReports && !Directory.Exists(FileSystemLayout.FFmpegReportsFolder)) { Directory.CreateDirectory(FileSystemLayout.FFmpegReportsFolder); } return Unit.Default; } } }