131 lines
5.2 KiB
C#
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());
|
|
}
|
|
}
|
|
}
|