Files
PantherByte/PantherByte/ViewModels/MainWindowViewModel.cs
T
2025-09-12 21:08:49 -04:00

131 lines
5.2 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using CommunityToolkit.Mvvm.Input;
using System.Threading.Tasks;
using PantherByte.Services;
using ReactiveUI;
namespace PantherByte.ViewModels;
public partial class MainWindowViewModel : ViewModelBase {
private string _link = string.Empty;
private string _saveLocation = string.Empty;
private string _format = "mp3";
private bool _canDownload = true;
/// <summary>
/// The link to the video to download. For now, only use YouTube links.
/// </summary>
public string Link {
get => _link;
set => this.RaiseAndSetIfChanged(ref _link, value);
}
/// <summary>
/// The format to download the video in. Currently supported options are MP3, MP4, and WAV. This will become the
/// argument passed to the "-t" argument in <see cref="GenerateCmdStringAsync"/>.
/// </summary>
public string Format {
get => _format;
set => this.RaiseAndSetIfChanged(ref _format, value);
}
/// <summary>
/// The folder to save the files in. This will become the argument passed to the "-P" argument in
/// <see cref="GenerateCmdStringAsync"/>.
/// </summary>
public string SaveLocation {
get => _saveLocation;
set => this.RaiseAndSetIfChanged(ref _saveLocation, value);
}
/// <summary>
/// Indicates if the file can be downloaded. If not, the download button is disabled.
/// </summary>
public bool CanDownload {
get => _canDownload;
set => this.RaiseAndSetIfChanged(ref _canDownload, value);
}
/// <summary>
/// Constructor. Mainly used for subscribing properties to the changes from other properties.
/// </summary>
public MainWindowViewModel() {
// Subscribe the CanDownload bool to the results of the Link, SaveLocation, and Format property changes.
this.WhenAnyValue(
x => x.Link,
x => x.SaveLocation,
x => x.Format,
(link, saveLocation, format) => !string.IsNullOrWhiteSpace(link)
&& !string.IsNullOrWhiteSpace(format)
&& !string.IsNullOrWhiteSpace(saveLocation)
)
.Subscribe(value => CanDownload = value);
}
/// <summary>
/// Gets the save location for the generated file. We are only allowing users to download one file at a time for now.
/// </summary>
/// <exception cref="NullReferenceException">
/// Thrown when there are no available services that implement <see cref="IFileSaveService"/>, or when the
/// <see cref="Avalonia.Platform.Storage.IStorageFolder"/> returned from the <see cref="IFileSaveService.ChooseFolderAsync"/>
/// method is null.
/// </exception>
/// <exception cref="DirectoryNotFoundException">
/// Thrown when the selected directory path does not exist in the current filesystem.
/// </exception>
[RelayCommand]
private async Task GetSaveLocationAsync() {
try {
var fileService = App.Current?.Services?.GetService(typeof(IFileSaveService));
if (fileService is FileService service) {
var filePath = await service.ChooseFolderAsync();
if (filePath is not null) {
var tempPath = filePath.Path.AbsolutePath;
if (Directory.Exists(tempPath)) {
SaveLocation = tempPath;
Console.WriteLine("Successfully set the file path.");
} else {
throw new DirectoryNotFoundException($"Directory does not exist: {tempPath}");
}
} else {
throw new NullReferenceException("The resulting storage folder was null.");
}
} else {
throw new NullReferenceException("Missing a FileSaveService instance");
}
} catch (Exception ex) {
// Exceptions are caught locally for now, but will eventually require a modal error window.
Console.WriteLine(ex.ToString());
}
}
/// <summary>
/// Generates the arguments used for the main command string.
/// </summary>
[RelayCommand]
private async Task<List<string>> GenerateCmdArgsAsync() {
// The command string format to use: yt-dlp <link> -t <mp3|mp4|wav> -P <path> --no-playlist
// yt-dlp requires usage of ffmpeg as well.
// Code will be executed when the button is clicked.
return await Task.Run(() => new List<string>([Link, "-t", Format, "-P", SaveLocation, "--no-playlist"]));
}
/// <summary>
/// Handles the download process of the file. Generates the command and runs it.
/// </summary>
[RelayCommand]
private async Task DownloadFileAsync() {
// Build the command and run the yt-dlp program by using the generated string.
// Somehow we'll need to package the program in with the application during distribution.
var args = await GenerateCmdArgsAsync();
// Run the command.
try {
System.Diagnostics.Process.Start("yt-dlp", args);
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}
}