Replaced some utility methods with library methods
This commit is contained in:
parent
9fb1c69a5c
commit
235d787a6e
11 changed files with 119 additions and 84 deletions
|
@ -1,5 +1,7 @@
|
|||
using Avalonia.Platform;
|
||||
using SkiaSharp;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace EllieHub.Common;
|
||||
|
||||
|
@ -9,29 +11,29 @@ namespace EllieHub.Common;
|
|||
internal static class Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads an image embedded with this application.
|
||||
/// Loads an image embeded with this application.
|
||||
/// </summary>
|
||||
/// <param name="uri">An uri that starts with "avares://"</param>
|
||||
/// <remarks>Valid uris must start with "avares://".</remarks>
|
||||
/// <returns>The embedded image or the default bot avatar placeholder.</returns>
|
||||
/// <exception cref="FileNotFoundException">Occurs when the embedded resource does not exist.</exception>
|
||||
public static SKBitmap LoadEmbeddedImage(string? uri = default)
|
||||
/// <returns>The embeded image or the default bot avatar placeholder.</returns>
|
||||
/// <exception cref="FileNotFoundException">Occurs when the embeded resource does not exist.</exception>
|
||||
public static SKBitmap LoadEmbededImage(string? uri = default)
|
||||
{
|
||||
return (string.IsNullOrWhiteSpace(uri) || !uri.StartsWith("avares://", StringComparison.Ordinal))
|
||||
? SKBitmap.Decode(AssetLoader.Open(new(AppConstants.BotAvatarUri)))
|
||||
: SKBitmap.Decode(AssetLoader.Open(new(uri)));
|
||||
? SKBitmap.Decode(AssetLoader.Open(new Uri(AppConstants.BotAvatarUri)))
|
||||
: SKBitmap.Decode(AssetLoader.Open(new Uri(uri)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the image at the specified location or the bot avatar placeholder if it was not found.
|
||||
/// </summary>
|
||||
/// <param name="imagePath">The absolute path to the image file or <see langword="null"/> to get the avatar placeholder.</param>
|
||||
/// <remarks>This fallsback to <see cref="LoadEmbeddedImage"/> if <paramref name="imagePath"/> doesn't point to a valid image file.</remarks>
|
||||
/// <param name="uri">The absolute path to the image file or <see langword="null"/> to get the avatar placeholder.</param>
|
||||
/// <remarks>This fallsback to <see cref="LoadEmbededImage(string?)"/> if <paramref name="uri"/> doesn't point to a valid image file.</remarks>
|
||||
/// <returns>The requested image or the default bot avatar placeholder.</returns>
|
||||
public static SKBitmap LoadLocalImage(string? imagePath)
|
||||
public static SKBitmap LoadLocalImage(string? uri = default)
|
||||
{
|
||||
return (File.Exists(imagePath))
|
||||
? SKBitmap.Decode(imagePath)
|
||||
: LoadEmbeddedImage(imagePath);
|
||||
return (File.Exists(uri))
|
||||
? SKBitmap.Decode(uri)
|
||||
: LoadEmbededImage(uri);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
using Toastie.Utilities;
|
||||
|
||||
namespace EllieHub.Features.AppConfig.Services.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
|
@ -22,7 +24,7 @@ public abstract class FfmpegResolver : IFfmpegResolver
|
|||
public virtual async ValueTask<bool?> CanUpdateAsync(CancellationToken cToken = default)
|
||||
{
|
||||
// Check where ffmpeg is referenced.
|
||||
using var whereProcess = Utilities.StartProcess(_programVerifier, FfmpegProcessName);
|
||||
using var whereProcess = ToastieUtilities.StartProcess(_programVerifier, FfmpegProcessName, true);
|
||||
var installationPath = await whereProcess.StandardOutput.ReadToEndAsync(cToken);
|
||||
|
||||
// If ffmpeg is present but not managed by us, just report it is installed.
|
||||
|
@ -32,7 +34,7 @@ public abstract class FfmpegResolver : IFfmpegResolver
|
|||
var currentVer = await GetCurrentVersionAsync(cToken);
|
||||
|
||||
// If ffmpeg or ffprobe are absent, a reinstall needs to be performed.
|
||||
if (currentVer is null || !await Utilities.ProgramExistsAsync("ffprobe", cToken))
|
||||
if (currentVer is null || !ToastieUtilities.ProgramExists("ffprobe"))
|
||||
return null;
|
||||
|
||||
var latestVer = await GetLatestVersionAsync(cToken);
|
||||
|
@ -44,20 +46,20 @@ public abstract class FfmpegResolver : IFfmpegResolver
|
|||
public virtual async ValueTask<string?> GetCurrentVersionAsync(CancellationToken cToken = default)
|
||||
{
|
||||
// If ffmpeg is not accessible from the shell...
|
||||
if (!await Utilities.ProgramExistsAsync(FfmpegProcessName, cToken))
|
||||
if (!ToastieUtilities.ProgramExists(FfmpegProcessName))
|
||||
{
|
||||
// And doesn't exist in the dependencies folder,
|
||||
// report that ffmpeg is not installed.
|
||||
if (!File.Exists(Path.Combine(AppStatics.AppDepsUri, FileName)))
|
||||
if (!File.Exists(Path.Join(AppStatics.AppDepsUri, FileName)))
|
||||
return null;
|
||||
|
||||
// Else, add the dependencies directory to the PATH envar,
|
||||
// then try again.
|
||||
Utilities.AddPathToPATHEnvar(AppStatics.AppDepsUri);
|
||||
ToastieUtilities.AddPathToPATHEnvar(AppStatics.AppDepsUri);
|
||||
return await GetCurrentVersionAsync(cToken);
|
||||
}
|
||||
|
||||
using var ffmpeg = Utilities.StartProcess(FfmpegProcessName, "-version");
|
||||
using var ffmpeg = ToastieUtilities.StartProcess(FfmpegProcessName, "-version", true);
|
||||
var match = AppStatics.FfmpegVersionRegex.Match(await ffmpeg.StandardOutput.ReadLineAsync(cToken) ?? string.Empty);
|
||||
|
||||
return match.Groups[1].Value;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Toastie.Utilities;
|
||||
using EllieHub.Features.AppConfig.Models;
|
||||
using EllieHub.Features.AppConfig.Services.Abstractions;
|
||||
using EllieHub.Features.AppWindow.Models;
|
||||
|
@ -33,7 +34,7 @@ public sealed class AppConfigManager : IAppConfigManager
|
|||
var newId = CreateNewId();
|
||||
var newPosition = _appConfig.BotEntries.Count is 0 ? 0 : _appConfig.BotEntries.Values.Max(x => x.Position) + 1;
|
||||
var newBotName = "NewBot_" + newPosition;
|
||||
var newEntry = new BotInstanceInfo(newBotName, Path.Combine(_appConfig.BotsDirectoryUri, newBotName), newPosition);
|
||||
var newEntry = new BotInstanceInfo(newBotName, Path.Join(_appConfig.BotsDirectoryUri, newBotName), newPosition);
|
||||
|
||||
if (!_appConfig.BotEntries.TryAdd(newId, newEntry))
|
||||
throw new InvalidOperationException($"Could not create a new bot entry with Id {newId}.");
|
||||
|
@ -49,7 +50,7 @@ public sealed class AppConfigManager : IAppConfigManager
|
|||
if (!_appConfig.BotEntries.TryRemove(id, out var removedEntry))
|
||||
return null;
|
||||
|
||||
Utilities.TryDeleteDirectory(removedEntry.InstanceDirectoryUri);
|
||||
ToastieUtilities.TryDeleteDirectory(removedEntry.InstanceDirectoryUri);
|
||||
|
||||
await SaveAsync(cToken);
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Toastie.Utilities;
|
||||
using EllieHub.Features.AppConfig.Services.Abstractions;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
@ -64,8 +65,8 @@ public sealed partial class FfmpegLinuxResolver : FfmpegResolver
|
|||
if (currentVersion == newVersion)
|
||||
return (currentVersion, null);
|
||||
|
||||
Utilities.TryDeleteFile(Path.Combine(installationUri, FileName));
|
||||
Utilities.TryDeleteFile(Path.Combine(installationUri, "ffprobe"));
|
||||
ToastieUtilities.TryDeleteFile(Path.Join(installationUri, FileName));
|
||||
ToastieUtilities.TryDeleteFile(Path.Join(installationUri, "ffprobe"));
|
||||
}
|
||||
|
||||
// Install
|
||||
|
@ -77,29 +78,29 @@ public sealed partial class FfmpegLinuxResolver : FfmpegResolver
|
|||
await using var downloadStream = await http.GetStreamAsync($"https://johnvansickle.com/ffmpeg/releases/{tarFileName}", cToken);
|
||||
|
||||
// Save tar file to the temporary directory.
|
||||
var tarFilePath = Path.Combine(_tempDirectory, tarFileName);
|
||||
var tarExtractDir = Path.Combine(_tempDirectory, $"ffmpeg-{newVersion}-{architecture}64-static");
|
||||
var tarFilePath = Path.Join(_tempDirectory, tarFileName);
|
||||
var tarExtractDir = Path.Join(_tempDirectory, $"ffmpeg-{newVersion}-{architecture}64-static");
|
||||
await using (var fileStream = new FileStream(tarFilePath, FileMode.Create))
|
||||
await downloadStream.CopyToAsync(fileStream, cToken);
|
||||
|
||||
// Extract the tar file.
|
||||
using var extractProcess = Utilities.StartProcess("tar", $"xf \"{tarFilePath}\" --directory=\"{_tempDirectory}\"");
|
||||
using var extractProcess = ToastieUtilities.StartProcess("tar", ["xf", tarFilePath, $"--directory=\"{_tempDirectory}\""]);
|
||||
await extractProcess.WaitForExitAsync(cToken);
|
||||
|
||||
// Move ffmpeg to the dependencies directory.
|
||||
File.Move(Path.Combine(tarExtractDir, FileName), Path.Combine(installationUri, FileName), true);
|
||||
File.Move(Path.Combine(tarExtractDir, "ffprobe"), Path.Combine(installationUri, "ffprobe"), true);
|
||||
ToastieUtilities.TryMoveFile(Path.Join(tarExtractDir, FileName), Path.Join(installationUri, FileName), true);
|
||||
ToastieUtilities.TryMoveFile(Path.Join(tarExtractDir, "ffprobe"), Path.Join(installationUri, "ffprobe"), true);
|
||||
|
||||
// Mark the files as executable.
|
||||
using var chmod = Utilities.StartProcess("chmod", $"+x \"{Path.Combine(installationUri, FileName)}\" \"{Path.Combine(installationUri, "ffprobe")}\"");
|
||||
using var chmod = ToastieUtilities.StartProcess("chmod", ["+x", Path.Join(installationUri, FileName), Path.Join(installationUri, "ffprobe")]);
|
||||
await chmod.WaitForExitAsync(cToken);
|
||||
|
||||
// Cleanup
|
||||
File.Delete(tarFilePath);
|
||||
Directory.Delete(tarExtractDir, true);
|
||||
ToastieUtilities.TryDeleteFile(tarFilePath);
|
||||
ToastieUtilities.TryDeleteDirectory(tarExtractDir, true);
|
||||
|
||||
// Update environment variable
|
||||
Utilities.AddPathToPathEnvar(installationUri);
|
||||
ToastieUtilities.AddPathToPATHEnvar(installationUri);
|
||||
|
||||
_isUpdating = false;
|
||||
return (currentVersion, newVersion);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Toastie.Utilities;
|
||||
using EllieHub.Features.AppConfig.Models.Api.Evermeet;
|
||||
using EllieHub.Features.AppConfig.Services.Abstractions;
|
||||
using System.IO.Compression;
|
||||
|
@ -15,7 +16,7 @@ public sealed class FfmpegMacResolver : FfmpegResolver
|
|||
private const string _apiFfmpegInfoEndpoint = "https://evermeet.cx/ffmpeg/info/ffmpeg/release";
|
||||
private const string _apiFfprobeInfoEndpoint = "https://evermeet.cx/ffmpeg/info/ffprobe/release";
|
||||
private readonly string _tempDirectory = Path.GetTempPath();
|
||||
private bool _isUpdating = false;
|
||||
private bool _isUpdating;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -57,8 +58,8 @@ public sealed class FfmpegMacResolver : FfmpegResolver
|
|||
return (currentVersion, null);
|
||||
}
|
||||
|
||||
Utilities.TryDeleteFile(Path.Combine(installationUri, FileName));
|
||||
Utilities.TryDeleteFile(Path.Combine(installationUri, "ffprobe"));
|
||||
ToastieUtilities.TryDeleteFile(Path.Join(installationUri, FileName));
|
||||
ToastieUtilities.TryDeleteFile(Path.Join(installationUri, "ffprobe"));
|
||||
}
|
||||
|
||||
// Install
|
||||
|
@ -74,7 +75,7 @@ public sealed class FfmpegMacResolver : FfmpegResolver
|
|||
);
|
||||
|
||||
// Update environment variable
|
||||
Utilities.AddPathToPathEnvar(installationUri);
|
||||
ToastieUtilities.AddPathToPATHEnvar(installationUri);
|
||||
|
||||
_isUpdating = false;
|
||||
return (currentVersion, newVersion);
|
||||
|
@ -91,26 +92,26 @@ public sealed class FfmpegMacResolver : FfmpegResolver
|
|||
var http = _httpClientFactory.CreateClient();
|
||||
var downloadUrl = downloadInfo.Download["zip"].Url;
|
||||
var zipFileName = downloadUrl[(downloadUrl.LastIndexOf('/') + 1)..];
|
||||
var zipFilePath = Path.Combine(_tempDirectory, zipFileName);
|
||||
var zipFilePath = Path.Join(_tempDirectory, zipFileName);
|
||||
|
||||
// Download the zip file and save it to the temporary directory.
|
||||
using var zipStream = await http.GetStreamAsync(downloadUrl, cToken);
|
||||
await using var zipStream = await http.GetStreamAsync(downloadUrl, cToken);
|
||||
|
||||
using (var fileStream = new FileStream(zipFilePath, FileMode.Create))
|
||||
await using (var fileStream = new FileStream(zipFilePath, FileMode.Create))
|
||||
await zipStream.CopyToAsync(fileStream, cToken);
|
||||
|
||||
// Extract the zip file.
|
||||
ZipFile.ExtractToDirectory(zipFileName, _tempDirectory);
|
||||
|
||||
// Move the dependency binary.
|
||||
var finalFileUri = Path.Combine(dependenciesUri, downloadInfo.Name);
|
||||
File.Move(Path.Combine(_tempDirectory, downloadInfo.Name), finalFileUri, true);
|
||||
var finalFileUri = Path.Join(dependenciesUri, downloadInfo.Name);
|
||||
ToastieUtilities.TryMoveFile(Path.Join(_tempDirectory, downloadInfo.Name), finalFileUri, true);
|
||||
|
||||
// Mark binary as executable.
|
||||
using var chmod = Utilities.StartProcess("chmod", $"+x \"{finalFileUri}\"");
|
||||
using var chmod = ToastieUtilities.StartProcess("chmod", $"+x \"{finalFileUri}\"");
|
||||
await chmod.WaitForExitAsync(cToken);
|
||||
|
||||
// Cleanup.
|
||||
File.Delete(zipFilePath);
|
||||
ToastieUtilities.TryDeleteFile(zipFilePath);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
using Toastie.Utilities;
|
||||
using EllieHub.Features.AppConfig.Services.Abstractions;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -13,7 +14,7 @@ namespace EllieHub.Features.AppConfig.Services;
|
|||
public sealed class FfmpegWindowsResolver : FfmpegResolver
|
||||
{
|
||||
private readonly string _tempDirectory = Path.GetTempPath();
|
||||
private bool _isUpdating = false;
|
||||
private bool _isUpdating;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -68,9 +69,9 @@ public sealed class FfmpegWindowsResolver : FfmpegResolver
|
|||
return (currentVersion, null);
|
||||
}
|
||||
|
||||
Utilities.TryDeleteFile(Path.Combine(installationUri, FileName));
|
||||
Utilities.TryDeleteFile(Path.Combine(installationUri, "ffprobe.exe"));
|
||||
//Utilities.TryDeleteFile(Path.Combine(dependenciesUri, "ffplay.exe"));
|
||||
ToastieUtilities.TryDeleteFile(Path.Join(installationUri, FileName));
|
||||
ToastieUtilities.TryDeleteFile(Path.Join(installationUri, "ffprobe.exe"));
|
||||
//ToastieUtilities.TryDeleteFile(Path.Join(dependenciesUri, "ffplay.exe"));
|
||||
}
|
||||
|
||||
// Install
|
||||
|
@ -78,12 +79,12 @@ public sealed class FfmpegWindowsResolver : FfmpegResolver
|
|||
|
||||
var zipFileName = $"ffmpeg-{newVersion}-full_build.zip";
|
||||
var http = _httpClientFactory.CreateClient();
|
||||
using var downloadStream = await http.GetStreamAsync($"https://github.com/GyanD/codexffmpeg/releases/download/{newVersion}/{zipFileName}", cToken);
|
||||
await using var downloadStream = await http.GetStreamAsync($"https://github.com/GyanD/codexffmpeg/releases/download/{newVersion}/{zipFileName}", cToken);
|
||||
|
||||
// Save zip file to the temporary directory.
|
||||
var zipFilePath = Path.Combine(_tempDirectory, zipFileName);
|
||||
var zipExtractDir = Path.Combine(_tempDirectory, zipFileName[..^4]);
|
||||
using (var fileStream = new FileStream(zipFilePath, FileMode.Create))
|
||||
var zipFilePath = Path.Join(_tempDirectory, zipFileName);
|
||||
var zipExtractDir = Path.Join(_tempDirectory, zipFileName[..^4]);
|
||||
await using (var fileStream = new FileStream(zipFilePath, FileMode.Create))
|
||||
await downloadStream.CopyToAsync(fileStream, cToken);
|
||||
|
||||
// Schedule installation to the thread-pool because ffmpeg is pretty
|
||||
|
@ -94,17 +95,17 @@ public sealed class FfmpegWindowsResolver : FfmpegResolver
|
|||
ZipFile.ExtractToDirectory(zipFilePath, _tempDirectory);
|
||||
|
||||
// Move ffmpeg to the dependencies directory.
|
||||
File.Move(Path.Combine(zipExtractDir, "bin", FileName), Path.Combine(installationUri, FileName), true);
|
||||
File.Move(Path.Combine(zipExtractDir, "bin", "ffprobe.exe"), Path.Combine(installationUri, "ffprobe.exe"), true);
|
||||
//File.Move(Path.Combine(zipExtractDir, "bin", "ffplay.exe"), Path.Combine(dependenciesUri, "ffplay.exe"));
|
||||
ToastieUtilities.TryMoveFile(Path.Join(zipExtractDir, "bin", FileName), Path.Join(installationUri, FileName), true);
|
||||
ToastieUtilities.TryMoveFile(Path.Join(zipExtractDir, "bin", "ffprobe.exe"), Path.Join(installationUri, "ffprobe.exe"), true);
|
||||
//ToastieUtilities.TryMoveFile(Path.Join(zipExtractDir, "bin", "ffplay.exe"), Path.Join(dependenciesUri, "ffplay.exe"));
|
||||
|
||||
// Cleanup
|
||||
File.Delete(zipFilePath);
|
||||
Directory.Delete(zipExtractDir, true);
|
||||
ToastieUtilities.TryDeleteFile(zipFilePath);
|
||||
ToastieUtilities.TryDeleteDirectory(zipExtractDir);
|
||||
}, cToken);
|
||||
|
||||
// Update environment variable
|
||||
Utilities.AddPathToPathEnvar(installationUri);
|
||||
ToastieUtilities.AddPathToPATHEnvar(installationUri);
|
||||
|
||||
_isUpdating = false;
|
||||
return (currentVersion, newVersion);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Toastie.Utilities;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using EllieHub.Features.AppConfig.Services.Abstractions;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -13,7 +14,7 @@ public sealed class YtdlpResolver : IYtdlpResolver
|
|||
private const string _cachedCurrentVersionKey = "currentVersion:yt-dlp";
|
||||
private const string _ytdlpProcessName = "yt-dlp";
|
||||
private static readonly string _downloadedFileName = GetDownloadFileName();
|
||||
private bool _isUpdating = false;
|
||||
private bool _isUpdating;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
|
@ -56,16 +57,16 @@ public sealed class YtdlpResolver : IYtdlpResolver
|
|||
public async ValueTask<string?> GetCurrentVersionAsync(CancellationToken cToken = default)
|
||||
{
|
||||
// If yt-dlp is not accessible from the shell...
|
||||
if (!await Utilities.ProgramExistsAsync(_ytdlpProcessName, cToken))
|
||||
if (!ToastieUtilities.ProgramExists(_ytdlpProcessName))
|
||||
{
|
||||
// And doesn't exist in the dependencies folder,
|
||||
// report that yt-dlp is not installed.
|
||||
if (!File.Exists(Path.Combine(AppStatics.AppDepsUri, FileName)))
|
||||
if (!File.Exists(Path.Join(AppStatics.AppDepsUri, FileName)))
|
||||
return null;
|
||||
|
||||
// Else, add the dependencies directory to the PATH envar,
|
||||
// then try again.
|
||||
Utilities.AddPathToPathEnvar(AppStatics.AppDepsUri);
|
||||
ToastieUtilities.AddPathToPATHEnvar(AppStatics.AppDepsUri);
|
||||
return await GetCurrentVersionAsync(cToken);
|
||||
}
|
||||
|
||||
|
@ -73,7 +74,7 @@ public sealed class YtdlpResolver : IYtdlpResolver
|
|||
if (_memoryCache.TryGetValue<string>(_cachedCurrentVersionKey, out var currentVersion) && currentVersion is not null)
|
||||
return currentVersion;
|
||||
|
||||
using var ytdlp = Utilities.StartProcess(_ytdlpProcessName, "--version");
|
||||
using var ytdlp = ToastieUtilities.StartProcess(_ytdlpProcessName, "--version", true);
|
||||
|
||||
var currentProcessVersion = (await ytdlp.StandardOutput.ReadToEndAsync(cToken)).Trim();
|
||||
_memoryCache.Set(_cachedCurrentVersionKey, currentProcessVersion, TimeSpan.FromMinutes(1.5));
|
||||
|
@ -116,7 +117,7 @@ public sealed class YtdlpResolver : IYtdlpResolver
|
|||
return (currentVersion, null);
|
||||
}
|
||||
|
||||
using var ytdlp = Utilities.StartProcess(_ytdlpProcessName, "-U");
|
||||
using var ytdlp = ToastieUtilities.StartProcess(_ytdlpProcessName, "-U");
|
||||
await ytdlp.WaitForExitAsync(cToken);
|
||||
|
||||
_isUpdating = false;
|
||||
|
@ -126,19 +127,19 @@ public sealed class YtdlpResolver : IYtdlpResolver
|
|||
// Install
|
||||
Directory.CreateDirectory(installationUri);
|
||||
|
||||
var finalFilePath = Path.Combine(installationUri, FileName);
|
||||
var finalFilePath = Path.Join(installationUri, FileName);
|
||||
var http = _httpClientFactory.CreateClient();
|
||||
using var downloadStream = await http.GetStreamAsync($"https://github.com/yt-dlp/yt-dlp/releases/download/{newVersion}/{_downloadedFileName}", cToken);
|
||||
using (var fileStream = new FileStream(finalFilePath, FileMode.Create))
|
||||
await using var downloadStream = await http.GetStreamAsync($"https://github.com/yt-dlp/yt-dlp/releases/download/{newVersion}/{_downloadedFileName}", cToken);
|
||||
await using (var fileStream = new FileStream(finalFilePath, FileMode.Create))
|
||||
await downloadStream.CopyToAsync(fileStream, cToken);
|
||||
|
||||
// Update environment variable
|
||||
Utilities.AddPathToPathEnvar(installationUri);
|
||||
ToastieUtilities.AddPathToPATHEnvar(installationUri);
|
||||
|
||||
// On Linux and MacOS, we need to mark the file as executable.
|
||||
if (Environment.OSVersion.Platform is PlatformID.Unix)
|
||||
{
|
||||
using var chmod = Utilities.StartProcess("chmod", $"+x \"{finalFilePath}\"");
|
||||
using var chmod = ToastieUtilities.StartProcess("chmod", ["+x", finalFilePath]);
|
||||
await chmod.WaitForExitAsync(cToken);
|
||||
}
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ public partial class AppView : ReactiveWindow<AppViewModel>
|
|||
base.Height = _appConfigManager.AppConfig.WindowSize.Height;
|
||||
base.Width = _appConfigManager.AppConfig.WindowSize.Width;
|
||||
|
||||
// Set the user prefered theme
|
||||
// Set the user preferred theme
|
||||
base.RequestedThemeVariant = _appConfigManager.AppConfig.Theme switch
|
||||
{
|
||||
ThemeType.Auto => ThemeVariant.Default,
|
||||
|
@ -256,9 +256,23 @@ public partial class AppView : ReactiveWindow<AppViewModel>
|
|||
|
||||
_ = new UpdateView().ShowDialog(this);
|
||||
|
||||
await _appResolver.InstallOrUpdateAsync(AppContext.BaseDirectory);
|
||||
_appResolver.LaunchNewVersion();
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine("Downloading new updater...");
|
||||
await _appResolver.InstallOrUpdateAsync(AppContext.BaseDirectory);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.WriteLine("Launching new updater...");
|
||||
_appResolver.LaunchNewVersion();
|
||||
}
|
||||
|
||||
Console.WriteLine("Finished update, closing down...");
|
||||
base.Close();
|
||||
}
|
||||
|
||||
|
@ -295,7 +309,7 @@ public partial class AppView : ReactiveWindow<AppViewModel>
|
|||
private static BotConfigViewModel GetBotConfigViewModel(Button button, IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
using var scope = scopeFactory.CreateScope();
|
||||
var botId = (button.Content ?? throw new InvalidOperationException("Bot button has no valid Id."));
|
||||
var botId = button.Content ?? throw new InvalidOperationException("Bot button has no valid Id.");
|
||||
var botResolver = scope.ServiceProvider.GetParameterizedService<EllieResolver>(botId);
|
||||
|
||||
return scope.ServiceProvider.GetParameterizedService<BotConfigViewModel>(botResolver);
|
||||
|
|
|
@ -183,7 +183,7 @@ public class BotConfigViewModel : ViewModelBase<BotConfigView>, IDisposable
|
|||
EnableButtons(!File.Exists(Path.Combine(botEntry.InstanceDirectoryUri, Resolver.FileName)), true);
|
||||
|
||||
// Dispose when the view is deactivated
|
||||
this.WhenActivated(disposables => Disposable.Create(() => Dispose()).DisposeWith(disposables));
|
||||
this.WhenActivated(disposables => Disposable.Create(Dispose).DisposeWith(disposables));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -425,7 +425,7 @@ public class BotConfigViewModel : ViewModelBase<BotConfigView>, IDisposable
|
|||
/// </summary>
|
||||
/// <param name="botResolver">The bot resolver.</param>
|
||||
/// <param name="updateBotBar">The update bar.</param>
|
||||
private async static Task LoadUpdateBarAsync(IBotResolver botResolver, DependencyButtonViewModel updateBotBar)
|
||||
private static async Task LoadUpdateBarAsync(IBotResolver botResolver, DependencyButtonViewModel updateBotBar)
|
||||
{
|
||||
updateBotBar.DependencyName = "Checking...";
|
||||
updateBotBar.Status = DependencyStatus.Checking;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Avalonia.Platform.Storage;
|
||||
using Toastie.Utilities;
|
||||
using EllieHub.Features.Abstractions;
|
||||
using EllieHub.Features.Common.Models;
|
||||
using EllieHub.Features.Common.Views.Controls;
|
||||
|
@ -14,7 +15,7 @@ public class UriInputBarViewModel : ViewModelBase<UriInputBar>
|
|||
{
|
||||
private static readonly FolderPickerOpenOptions _folderPickerOptions = new();
|
||||
private string _lastValidUri = AppStatics.AppDefaultConfigDirectoryUri;
|
||||
private bool _isDirectoryValid = false;
|
||||
private bool _isDirectoryValid;
|
||||
private string _currentUri = string.Empty;
|
||||
private readonly IStorageProvider _storageProvider;
|
||||
|
||||
|
@ -92,5 +93,5 @@ public class UriInputBarViewModel : ViewModelBase<UriInputBar>
|
|||
/// <param name="directoryUri">The absolute path to a directory.</param>
|
||||
/// <returns><see langword="true"/> if the directory is valid, <see langword="false"/> otherwise.</returns>
|
||||
private bool IsValidDirectory(string directoryUri)
|
||||
=> Directory.Exists(directoryUri) && Utilities.CanWriteTo(directoryUri);
|
||||
=> Directory.Exists(directoryUri) && ToastieUtilities.HasWritePermissionAt(directoryUri);
|
||||
}
|
|
@ -43,7 +43,7 @@ public sealed class AppResolver : IAppResolver
|
|||
_httpClientFactory = httpClientFactory;
|
||||
_memoryCache = memoryCache;
|
||||
FileName = OperatingSystem.IsWindows() ? "EllieHub.exe" : "EllieHub";
|
||||
BinaryUri = Path.Combine(AppContext.BaseDirectory, FileName);
|
||||
BinaryUri = Path.Join(AppContext.BaseDirectory, FileName);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -117,18 +117,18 @@ public sealed class AppResolver : IAppResolver
|
|||
return (currentVersion, null);
|
||||
|
||||
var http = _httpClientFactory.CreateClient(); // Do not initialize a ToastielabClient here, it returns 302 with no data
|
||||
var appTempLocation = Path.Combine(_tempDirectory, _downloadedFileName[.._downloadedFileName.LastIndexOf('.')]);
|
||||
var zipTempLocation = Path.Combine(_tempDirectory, _downloadedFileName);
|
||||
var appTempLocation = Path.Join(_tempDirectory, _downloadedFileName[.._downloadedFileName.LastIndexOf('.')]);
|
||||
var zipTempLocation = Path.Join(_tempDirectory, _downloadedFileName);
|
||||
|
||||
try
|
||||
{
|
||||
using var downloadStream = await http.GetStreamAsync(
|
||||
await using var downloadStream = await http.GetStreamAsync(
|
||||
await GetDownloadUrlAsync(latestVersion, cToken),
|
||||
cToken
|
||||
);
|
||||
|
||||
// Save the zip file
|
||||
using (var fileStream = new FileStream(zipTempLocation, FileMode.Create))
|
||||
await using (var fileStream = new FileStream(zipTempLocation, FileMode.Create))
|
||||
await downloadStream.CopyToAsync(fileStream, cToken);
|
||||
|
||||
// Extract the zip file
|
||||
|
@ -139,19 +139,30 @@ public sealed class AppResolver : IAppResolver
|
|||
|
||||
foreach (var newFileUri in newFilesUris)
|
||||
{
|
||||
var destinationUri = Path.Combine(AppContext.BaseDirectory, newFileUri[(newFileUri.LastIndexOf(Path.DirectorySeparatorChar) + 1)..]);
|
||||
var destinationUri = Path.Join(AppContext.BaseDirectory, newFileUri[(newFileUri.LastIndexOf(Path.DirectorySeparatorChar) + 1)..]);
|
||||
|
||||
// Rename the original file from "file" to "file_old".
|
||||
if (File.Exists(destinationUri))
|
||||
File.Move(destinationUri, destinationUri + OldFileSuffix, true);
|
||||
File.Move(destinationUri, destinationUri + OldFileSuffix, true); // This executes fine
|
||||
|
||||
ToastieUtilities.TryMoveFile(newFileUri, destinationUri, true);
|
||||
// Move the new file to the application's directory.
|
||||
// ...
|
||||
// This is a workaround for really weird bug with applications published as single-file, where
|
||||
// FileNotFoundException: Could not load file or assembly 'System.IO.Pipes, Version=9.0.0.0 [...]
|
||||
if (Environment.OSVersion.Platform is not PlatformID.Unix)
|
||||
File.Move(newFileUri, destinationUri, true);
|
||||
else
|
||||
{
|
||||
// Circumvent this issue on Unix systems: https://github.com/dotnet/runtime/issues/31149
|
||||
using var moveProcess = ToastieUtilities.StartProcess("mv", [newFileUri, destinationUri]);
|
||||
await moveProcess.WaitForExitAsync(cToken);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the new binary file as executable.
|
||||
if (Environment.OSVersion.Platform is PlatformID.Unix)
|
||||
{
|
||||
using var chmod = ToastieUtilities.StartProcess("chmod", $"+x \"{BinaryUri}\"");
|
||||
using var chmod = ToastieUtilities.StartProcess("chmod", ["+x", BinaryUri]);
|
||||
await chmod.WaitForExitAsync(cToken);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue