Files
VDownload/VDownload/Views/Home/Controls/HomeTaskPanel.xaml.cs

338 lines
16 KiB
C#

using Microsoft.Toolkit.Uwp.Connectivity;
using Microsoft.Toolkit.Uwp.Notifications;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using VDownload.Core.Enums;
using VDownload.Core.Services;
using VDownload.Core.Structs;
using Windows.ApplicationModel.ExtendedExecution;
using Windows.ApplicationModel.Resources;
using Windows.Storage;
using Windows.Storage.AccessCache;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
namespace VDownload.Views.Home.Controls
{
public sealed partial class HomeTaskPanel : UserControl
{
#region CONSTANTS
private static readonly ResourceDictionary IconsRes = new ResourceDictionary { Source = new Uri("ms-appx:///Resources/Icons.xaml") };
private static readonly ResourceDictionary ImagesRes = new ResourceDictionary { Source = new Uri("ms-appx:///Resources/Images.xaml") };
#endregion
#region CONSTRUCTORS
public HomeTaskPanel(TaskData taskData)
{
this.InitializeComponent();
// Set task data
Data = taskData;
// Set video status
Status = Core.Enums.TaskStatus.Idle;
// Create video cancellation token
CancellationTokenSource = new CancellationTokenSource();
// Set thumbnail image
ThumbnailImage = Data.VideoService.Metadata.Thumbnail != null ? new BitmapImage { UriSource = Data.VideoService.Metadata.Thumbnail } : (BitmapImage)ImagesRes["UnknownThumbnailImage"];
// Set source icon
SourceImage = new BitmapIcon { UriSource = new Uri($"ms-appx:///Assets/Sources/{Data.VideoService.GetType().Namespace.Split(".").Last()}.png"), ShowAsMonochrome = false };
// Set duration
TimeSpan newDuration = Data.TaskOptions.TrimEnd.Subtract(Data.TaskOptions.TrimStart);
Duration = TimeSpanCustomFormat.ToOptTHBaseMMSS(newDuration);
if (Data.VideoService.Metadata.Duration > newDuration) Duration += $" ({TimeSpanCustomFormat.ToOptTHBaseMMSS(Data.TaskOptions.TrimStart, Data.TaskOptions.TrimEnd)} - {TimeSpanCustomFormat.ToOptTHBaseMMSS(Data.TaskOptions.TrimEnd, Data.TaskOptions.TrimStart)})";
// Set media type
MediaTypeQuality += ResourceLoader.GetForCurrentView().GetString($"MediaType{Data.TaskOptions.MediaType}Text");
if (Data.TaskOptions.MediaType != MediaType.OnlyAudio) MediaTypeQuality += $" ({Data.TaskOptions.Stream.Height}p{(Data.TaskOptions.Stream.FrameRate > 0 ? Data.TaskOptions.Stream.FrameRate.ToString() : "N/A")})";
// Set file
File += $@"{(Data.TaskOptions.Location != null ? Data.TaskOptions.Location.Path : $@"{UserDataPaths.GetDefault().Downloads}\VDownload")}\{Data.TaskOptions.Filename}.{Data.TaskOptions.Extension.ToString().ToLower()}";
// Set state controls
HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateIdleIcon"];
HomeTaskPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextIdle");
HomeTaskPanelStateProgressBar.Visibility = Visibility.Collapsed;
}
#endregion
#region PROPERTIES
// TASK STATUS
public Core.Enums.TaskStatus Status { get; set; }
// TASK CANCELLATION TOKEN
public CancellationTokenSource CancellationTokenSource { get; set; }
// TASK DATA
private TaskData Data { get; set; }
// TASK PANEL DATA
private ImageSource ThumbnailImage { get; set; }
private IconElement SourceImage { get; set; }
private string Title { get; set; }
private string Author { get; set; }
private string Duration { get; set; }
private string MediaTypeQuality { get; set; }
private string File { get; set; }
#endregion
#region METHODS
public async Task Start(bool delayWhenOnMeteredConnection)
{
// Change icon
HomeTaskPanelStartStopButton.Icon = new SymbolIcon(Symbol.Stop);
// Create cancellation token
CancellationTokenSource = new CancellationTokenSource();
// Scheduling
if (Data.TaskOptions.Schedule > 0)
{
DateTime ScheduledDateTime = DateTime.Now.AddMinutes(Data.TaskOptions.Schedule);
// Set task status
Status = Core.Enums.TaskStatus.Scheduled;
// Set state controls
HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateScheduledIcon"];
HomeTaskPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextScheduled")} ({ScheduledDateTime.ToString(CultureInfo.InstalledUICulture.DateTimeFormat.ShortDatePattern)} {ScheduledDateTime.ToString(CultureInfo.InstalledUICulture.DateTimeFormat.ShortTimePattern)})";
HomeTaskPanelStateProgressBar.Visibility = Visibility.Collapsed;
while (DateTime.Now < ScheduledDateTime && !CancellationTokenSource.IsCancellationRequested) await Task.Delay(100);
}
// Set task status
Status = Core.Enums.TaskStatus.Waiting;
// Set state controls
HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateWaitingIcon"];
HomeTaskPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextWaiting");
HomeTaskPanelStateProgressBar.Visibility = Visibility.Visible;
// Wait in queue
await HomeMain.WaitInQueue(delayWhenOnMeteredConnection, CancellationTokenSource.Token);
if (!CancellationTokenSource.IsCancellationRequested)
{
// Set task status
Status = Core.Enums.TaskStatus.InProgress;
// Get task unique ID
string uniqueID = TaskId.Get();
// Get temporary folder
StorageFolder tempFolder;
if ((bool)Config.GetValue("custom_temp_location") && StorageApplicationPermissions.FutureAccessList.ContainsItem("custom_temp_location"))
tempFolder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync("custom_temp_location");
else
tempFolder = ApplicationData.Current.TemporaryFolder;
tempFolder = await tempFolder.CreateFolderAsync(uniqueID);
bool endedWithError = false;
try
{
// Throw exception if cancellation requested
CancellationTokenSource.Token.ThrowIfCancellationRequested();
// Start stopwatch
Stopwatch taskStopwatch = Stopwatch.StartNew();
// Set progress event handlers
Data.VideoService.DownloadingProgressChanged += (s, a) =>
{
HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateDownloadingIcon"];
HomeTaskPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextDownloading")} ({Math.Round(a.Progress)}%)";
HomeTaskPanelStateProgressBar.Value = a.Progress;
};
Data.VideoService.ProcessingProgressChanged += (s, a) =>
{
HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateProcessingIcon"];
HomeTaskPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextProcessing")} ({Math.Round(a.Progress)}%)";
HomeTaskPanelStateProgressBar.Value = a.Progress;
};
// Request extended session
ExtendedExecutionSession session = new ExtendedExecutionSession { Reason = ExtendedExecutionReason.Unspecified };
await session.RequestExtensionAsync();
// Start task
CancellationTokenSource.Token.ThrowIfCancellationRequested();
StorageFile tempOutputFile = await Data.VideoService.DownloadAndTranscodeAsync(tempFolder, Data.TaskOptions.Stream, Data.TaskOptions.Extension, Data.TaskOptions.MediaType, Data.TaskOptions.TrimStart, Data.TaskOptions.TrimEnd, CancellationTokenSource.Token);
// Dispose session
session.Dispose();
// Cancel if requested
CancellationTokenSource.Token.ThrowIfCancellationRequested();
// Set state controls
HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateFinalizingIcon"];
HomeTaskPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextFinalizing");
HomeTaskPanelStateProgressBar.IsIndeterminate = true;
// Move to output location
string filename = $"{Data.TaskOptions.Filename}.{Data.TaskOptions.Extension.ToString().ToLower()}";
CreationCollisionOption collisionOption = (bool)Config.GetValue("replace_output_file_if_exists") ? CreationCollisionOption.ReplaceExisting : CreationCollisionOption.GenerateUniqueName;
StorageFile outputFile = await (Data.TaskOptions.Location != null ? Data.TaskOptions.Location.CreateFileAsync(filename, collisionOption): DownloadsFolder.CreateFileAsync(filename, collisionOption));
await tempOutputFile.MoveAndReplaceAsync(outputFile);
// Stop stopwatch
taskStopwatch.Stop();
// Set state controls
HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateDoneIcon"];
HomeTaskPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextDone")} ({(Math.Floor(taskStopwatch.Elapsed.TotalHours) > 0 ? $"{ Math.Floor(taskStopwatch.Elapsed.TotalHours):0}:" : "")}{taskStopwatch.Elapsed.Minutes:00}:{taskStopwatch.Elapsed.Seconds:00})";
HomeTaskPanelStateProgressBar.Visibility = Visibility.Collapsed;
// Show notification
if ((bool)Config.GetValue("show_notification_when_task_ended_successfully"))
new ToastContentBuilder()
.AddText(ResourceLoader.GetForCurrentView().GetString("NotificationTaskEndedSuccessfullyHeader"))
.AddText($"\"{Title}\" - {ResourceLoader.GetForCurrentView().GetString("NotificationTaskEndedSuccessfullyDescription")}")
.Show();
}
catch (OperationCanceledException)
{
// Set state controls
HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateCancelledIcon"];
HomeTaskPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextCancelled");
HomeTaskPanelStateProgressBar.Visibility = Visibility.Collapsed;
}
catch (WebException ex)
{
string errorInfo;
if (ex.Response is null) errorInfo = ResourceLoader.GetForCurrentView().GetString("TaskErrorInternetConnection");
else throw ex;
// Set state controls
HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateErrorIcon"];
HomeTaskPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextError")} ({errorInfo})";
HomeTaskPanelStateProgressBar.Visibility = Visibility.Collapsed;
// Show notification
if ((bool)Config.GetValue("show_notification_when_task_ended_unsuccessfully"))
new ToastContentBuilder()
.AddText(ResourceLoader.GetForCurrentView().GetString("NotificationTaskEndedUnsuccessfullyHeader"))
.AddText($"\"{Title}\" - {ResourceLoader.GetForCurrentView().GetString("NotificationTaskEndedUnsuccessfullyDescription")} ({errorInfo})")
.Show();
}
finally
{
// Set video status
Status = Core.Enums.TaskStatus.Idle;
// Change icon
HomeTaskPanelStartStopButton.Icon = new SymbolIcon(Symbol.Download);
if (!endedWithError || (bool)Config.GetValue("delete_task_temp_when_ended_with_error"))
{
// Delete temporary files
await tempFolder.DeleteAsync();
// Dispose unique id
TaskId.Dispose(uniqueID);
}
if (!endedWithError && !CancellationTokenSource.IsCancellationRequested && (bool)Config.GetValue("remove_task_when_successfully_ended"))
{
// Remove task when successfully ended
TaskRemovingRequested?.Invoke(this, EventArgs.Empty);
}
}
}
else
{
// Set state controls
HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateCancelledIcon"];
HomeTaskPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextCancelled");
HomeTaskPanelStateProgressBar.Visibility = Visibility.Collapsed;
// Change icon
HomeTaskPanelStartStopButton.Icon = new SymbolIcon(Symbol.Download);
}
}
#endregion
#region EVENT HANDLERS VOIDS
// SOURCE BUTTON CLICKED
private async void HomeTaskPanelSourceButton_Click(object sender, RoutedEventArgs e)
{
// Launch the website
await Windows.System.Launcher.LaunchUriAsync(Data.VideoService.Url);
}
// START STOP BUTTON CLICKED
private async void HomeTaskPanelStartStopButton_Click(object sender, RoutedEventArgs e)
{
if (Status == Core.Enums.TaskStatus.InProgress || Status == Core.Enums.TaskStatus.Waiting || Status == Core.Enums.TaskStatus.Scheduled) CancellationTokenSource.Cancel();
else
{
bool delay = (bool)Config.GetValue("delay_task_when_queued_task_starts_on_metered_network");
if (NetworkHelper.Instance.ConnectionInformation.IsInternetOnMeteredConnection)
{
ContentDialogResult dialogResult = await new ContentDialog
{
Title = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelTaskStartMeteredConnectionDialogTitle"),
Content = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelTaskStartMeteredConnectionDialogDescription"),
PrimaryButtonText = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelTaskStartMeteredConnectionDialogStartAndDelayText"),
SecondaryButtonText = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelTaskStartMeteredConnectionDialogStartWithoutDelayText"),
CloseButtonText = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelTaskStartMeteredConnectionDialogCancel"),
}.ShowAsync();
switch (dialogResult)
{
case ContentDialogResult.Primary: delay = true; break;
case ContentDialogResult.Secondary: delay = false; break;
case ContentDialogResult.None: return;
}
}
await Start(delay);
}
}
// REMOVE BUTTON CLICKED
private void HomeTaskPanelRemoveButton_Click(object sender, RoutedEventArgs e)
{
if (Status == Core.Enums.TaskStatus.InProgress || Status == Core.Enums.TaskStatus.Waiting || Status == Core.Enums.TaskStatus.Scheduled) CancellationTokenSource.Cancel();
TaskRemovingRequested?.Invoke(this, EventArgs.Empty);
}
#endregion
#region EVENT HANDLERS
public event EventHandler TaskRemovingRequested;
#endregion
}
}