diff --git a/VDownload.Core/VDownload.Core.Strings/Strings/en-US/AuthenticationViewResources.resw b/VDownload.Core/VDownload.Core.Strings/Strings/en-US/AuthenticationViewResources.resw index f1c32dd..5943cab 100644 --- a/VDownload.Core/VDownload.Core.Strings/Strings/en-US/AuthenticationViewResources.resw +++ b/VDownload.Core/VDownload.Core.Strings/Strings/en-US/AuthenticationViewResources.resw @@ -117,10 +117,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + Sign in - + Sign out @@ -135,9 +135,18 @@ Token expired or is invalid. Please log in again + + Cannot validate token. Check your internet connection and try again later. + You are not authenticated. Please sign in + + You are not authenticated and there is no internet connection. Check your internet connection and try again later. + + + An unknown error occured during Twitch login + Twitch authentication error diff --git a/VDownload.Core/VDownload.Core.Strings/Strings/en-US/HomeDownloadsViewResources.resw b/VDownload.Core/VDownload.Core.Strings/Strings/en-US/HomeDownloadsViewResources.resw index f6b9601..07e88ad 100644 --- a/VDownload.Core/VDownload.Core.Strings/Strings/en-US/HomeDownloadsViewResources.resw +++ b/VDownload.Core/VDownload.Core.Strings/Strings/en-US/HomeDownloadsViewResources.resw @@ -117,6 +117,21 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + No internet connection. Try again later. + + + Error + + + Downloading timeout. Check your internet connection and try again later. + + + FFmpeg exited with error. + + + No FFmpeg executables found. Check path in settings and try again. + Cancelled diff --git a/VDownload.Core/VDownload.Core.Strings/Strings/en-US/HomeViewResources.resw b/VDownload.Core/VDownload.Core.Strings/Strings/en-US/HomeViewResources.resw index 5601658..6096f2a 100644 --- a/VDownload.Core/VDownload.Core.Strings/Strings/en-US/HomeViewResources.resw +++ b/VDownload.Core/VDownload.Core.Strings/Strings/en-US/HomeViewResources.resw @@ -117,6 +117,18 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Error + + + No internet connection + + + Cancel all + + + 80 + Download all diff --git a/VDownload.Core/VDownload.Core.Strings/Strings/en-US/SearchResources.resw b/VDownload.Core/VDownload.Core.Strings/Strings/en-US/SearchResources.resw index 093321f..bb15590 100644 --- a/VDownload.Core/VDownload.Core.Strings/Strings/en-US/SearchResources.resw +++ b/VDownload.Core/VDownload.Core.Strings/Strings/en-US/SearchResources.resw @@ -123,6 +123,9 @@ Invalid url. Url cannot be empty. + + Search timeout. Check your internet connection. + Invalid url. Url does not match any of supported source. diff --git a/VDownload.Core/VDownload.Core.Strings/Strings/en-US/SubscriptionsViewResources.resw b/VDownload.Core/VDownload.Core.Strings/Strings/en-US/SubscriptionsViewResources.resw index 1e97e5b..8f03e2f 100644 --- a/VDownload.Core/VDownload.Core.Strings/Strings/en-US/SubscriptionsViewResources.resw +++ b/VDownload.Core/VDownload.Core.Strings/Strings/en-US/SubscriptionsViewResources.resw @@ -126,6 +126,9 @@ Subscriptions + + No internet connection + Add diff --git a/VDownload.Core/VDownload.Core.Tasks/DownloadTask.cs b/VDownload.Core/VDownload.Core.Tasks/DownloadTask.cs index 05fa933..f19fd9b 100644 --- a/VDownload.Core/VDownload.Core.Tasks/DownloadTask.cs +++ b/VDownload.Core/VDownload.Core.Tasks/DownloadTask.cs @@ -13,6 +13,9 @@ using System.IO; using VDownload.Services.UI.Notifications; using VDownload.Services.UI.StringResources; using System.Collections.Generic; +using System.Net.Http; +using Instances.Exceptions; +using FFMpegCore.Exceptions; namespace VDownload.Core.Tasks { @@ -140,7 +143,11 @@ namespace VDownload.Core.Tasks await _settingsService.Load(); - string tempDirectory = $"{_settingsService.Data.Common.Temp.Directory}\\{_configurationService.Common.Path.Temp.TasksDirectory}\\{Id}"; + string tempDirectory = $"{_settingsService.Data.Common.Temp.Directory}\\{_configurationService.Common.Path.Temp.TasksDirectory}\\{Guid.NewGuid()}"; + if (Directory.Exists(tempDirectory)) + { + Directory.Delete(tempDirectory, true); + } Directory.CreateDirectory(tempDirectory); List content = new List() @@ -180,10 +187,11 @@ namespace VDownload.Core.Tasks .JoinProgressReporter(onProgressProcessing, downloadResult.NewDuration); await ffmpegBuilder.RunAsync(downloadResult.File, outputPath); + StorageFile outputFile = await StorageFile.GetFileFromPathAsync(outputPath); + UpdateStatusWithDispatcher(DownloadTaskStatus.Finalizing); - string destination = $"{DownloadOptions.Directory}\\{DownloadOptions.Filename}.{DownloadOptions.Extension}"; - File.Copy(outputPath, destination, true); + await Finalizing(outputFile); UpdateStatusWithDispatcher(DownloadTaskStatus.EndedSuccessfully); @@ -199,7 +207,26 @@ namespace VDownload.Core.Tasks } catch (Exception ex) { - UpdateErrorWithDispatcher(ex.Message); + string message; + + if (ex is TaskCanceledException || ex is HttpRequestException) + { + message = _stringResourcesService.HomeDownloadsViewResources.Get("ErrorDownloadingTimeout"); + } + else if (ex is InstanceFileNotFoundException) + { + message = _stringResourcesService.HomeDownloadsViewResources.Get("ErrorFFmpegPath"); + } + else if (ex is FFMpegException) + { + message = _stringResourcesService.HomeDownloadsViewResources.Get("ErrorFFmpeg"); + } + else + { + message = ex.Message; + } + + UpdateErrorWithDispatcher(message); UpdateStatusWithDispatcher(DownloadTaskStatus.EndedUnsuccessfully); if (_settingsService.Data.Common.Notifications.OnUnsuccessful) @@ -218,11 +245,19 @@ namespace VDownload.Core.Tasks } } - private void UpdateStatusWithDispatcher(DownloadTaskStatus status) => _dispatcherQueue.TryEnqueue(() => Status = status); + protected async Task Finalizing(StorageFile outputFile) + { + StorageFolder destination = await StorageFolder.GetFolderFromPathAsync(DownloadOptions.Directory); - private void UpdateProgressWithDispatcher(double progress) => _dispatcherQueue.TryEnqueue(() => Progress = progress); + string filename = $"{DownloadOptions.Filename}.{DownloadOptions.Extension}"; + await outputFile.CopyAsync(destination, filename, NameCollisionOption.ReplaceExisting); + } - private void UpdateErrorWithDispatcher(string message) => _dispatcherQueue.TryEnqueue(() => Error = message); + protected void UpdateStatusWithDispatcher(DownloadTaskStatus status) => _dispatcherQueue.TryEnqueue(() => Status = status); + + protected void UpdateProgressWithDispatcher(double progress) => _dispatcherQueue.TryEnqueue(() => Progress = progress); + + protected void UpdateErrorWithDispatcher(string message) => _dispatcherQueue.TryEnqueue(() => Error = message); #endregion } diff --git a/VDownload.Core/VDownload.Core.ViewModels/Authentication/AuthenticationViewModel.cs b/VDownload.Core/VDownload.Core.ViewModels/Authentication/AuthenticationViewModel.cs index 623cf20..4356c02 100644 --- a/VDownload.Core/VDownload.Core.ViewModels/Authentication/AuthenticationViewModel.cs +++ b/VDownload.Core/VDownload.Core.ViewModels/Authentication/AuthenticationViewModel.cs @@ -1,8 +1,10 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.WinUI.Helpers; using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -44,10 +46,13 @@ namespace VDownload.Core.ViewModels.Authentication #region PROPERTIES [ObservableProperty] - private AuthenticationButton _twitchButtonState = AuthenticationButton.Loading; + protected AuthenticationButton _twitchButtonState = AuthenticationButton.Loading; [ObservableProperty] - private string _twitchDescription; + protected bool _twitchButtonEnable = true; + + [ObservableProperty] + protected string _twitchDescription; #endregion @@ -107,7 +112,9 @@ namespace VDownload.Core.ViewModels.Authentication } else { - await _dialogsService.ShowOk(_stringResourcesService.AuthenticationViewResources.Get("TwitchAuthenticationDialogTitle"), "An unknown error occured"); // TODO : Change to string resource + string title = _stringResourcesService.AuthenticationViewResources.Get("TwitchAuthenticationDialogTitle"); + string message = _stringResourcesService.AuthenticationViewResources.Get("TwitchAuthenticationDialogMessage"); + await _dialogsService.ShowOk(title, message); } } await TwitchAuthenticationRefresh(); @@ -122,17 +129,38 @@ namespace VDownload.Core.ViewModels.Authentication private async Task TwitchAuthenticationRefresh() { TwitchButtonState = AuthenticationButton.Loading; + TwitchButtonEnable = true; byte[]? token = await _twitchAuthenticationService.GetToken(); if (token is null) { - TwitchDescription = _stringResourcesService.AuthenticationViewResources.Get("TwitchAuthenticationDescriptionNotAuthenticated"); + if (!NetworkHelper.Instance.ConnectionInformation.IsInternetAvailable) + { + TwitchButtonEnable = false; + TwitchDescription = _stringResourcesService.AuthenticationViewResources.Get("TwitchAuthenticationDescriptionNotAuthenticatedNoInternetConnection"); + } + else + { + TwitchDescription = _stringResourcesService.AuthenticationViewResources.Get("TwitchAuthenticationDescriptionNotAuthenticated"); + } TwitchButtonState = AuthenticationButton.SignIn; } else { - TwitchValidationResult validationResult = await _twitchAuthenticationService.ValidateToken(token); + TwitchValidationResult validationResult; + try + { + validationResult = await _twitchAuthenticationService.ValidateToken(token); + } + catch (Exception ex) when (ex is TaskCanceledException || ex is HttpRequestException) + { + TwitchDescription = _stringResourcesService.AuthenticationViewResources.Get("TwitchAuthenticationDescriptionCannotValidate"); + TwitchButtonState = AuthenticationButton.SignIn; + TwitchButtonEnable = false; + return; + } + if (validationResult.Success) { TwitchDescription = string.Format(_stringResourcesService.AuthenticationViewResources.Get("TwitchAuthenticationDescriptionAuthenticated"), validationResult.TokenData.Login, validationResult.TokenData.ExpirationDate); diff --git a/VDownload.Core/VDownload.Core.ViewModels/Home/HomeDownloadsViewModel.cs b/VDownload.Core/VDownload.Core.ViewModels/Home/HomeDownloadsViewModel.cs index cf82579..7d03e7f 100644 --- a/VDownload.Core/VDownload.Core.ViewModels/Home/HomeDownloadsViewModel.cs +++ b/VDownload.Core/VDownload.Core.ViewModels/Home/HomeDownloadsViewModel.cs @@ -68,6 +68,14 @@ namespace VDownload.Core.ViewModels.Home ]; if (idleStatuses.Contains(task.Status)) { + if (!NetworkHelper.Instance.ConnectionInformation.IsInternetAvailable) + { + string title = _stringResourcesService.HomeDownloadsViewResources.Get("DialogErrorTitle"); + string message = _stringResourcesService.HomeDownloadsViewResources.Get("DialogErrorMessageNoInternetConnection"); + await _dialogsService.ShowOk(title, message); + return; + } + bool continueEnqueue = true; if (NetworkHelper.Instance.ConnectionInformation.IsInternetOnMeteredConnection) { diff --git a/VDownload.Core/VDownload.Core.ViewModels/Home/HomeViewModel.cs b/VDownload.Core/VDownload.Core.ViewModels/Home/HomeViewModel.cs index 8dd6d3f..1841391 100644 --- a/VDownload.Core/VDownload.Core.ViewModels/Home/HomeViewModel.cs +++ b/VDownload.Core/VDownload.Core.ViewModels/Home/HomeViewModel.cs @@ -4,6 +4,7 @@ using CommunityToolkit.WinUI.Helpers; using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Text; using System.Threading.Tasks; using VDownload.Core.Tasks; @@ -23,13 +24,6 @@ namespace VDownload.Core.ViewModels.Home { #region ENUMS - public enum OptionBarMessageIconType - { - None, - ProgressRing, - Error - } - public enum OptionBarContentType { None, @@ -80,6 +74,11 @@ namespace VDownload.Core.ViewModels.Home [ObservableProperty] private Type _mainContent; + [ObservableProperty] + private string _optionBarError; + + [ObservableProperty] + private bool _optionBarIsErrorOpened; [ObservableProperty] private OptionBarContentType _optionBarContent; @@ -88,7 +87,7 @@ namespace VDownload.Core.ViewModels.Home private string _optionBarMessage; [ObservableProperty] - private OptionBarMessageIconType _optionBarMessageIcon; + private bool _optionBarLoading; [ObservableProperty] private bool _optionBarLoadSubscriptionButtonChecked; @@ -149,8 +148,10 @@ namespace VDownload.Core.ViewModels.Home MainContent = _downloadsView; OptionBarContent = OptionBarContentType.None; - OptionBarMessageIcon = OptionBarMessageIconType.None; + OptionBarLoading = false; OptionBarMessage = null; + OptionBarError = null; + OptionBarIsErrorOpened = true; OptionBarLoadSubscriptionButtonChecked = false; OptionBarVideoSearchButtonChecked = false; OptionBarPlaylistSearchButtonChecked = false; @@ -163,46 +164,57 @@ namespace VDownload.Core.ViewModels.Home [RelayCommand] public async Task LoadFromSubscription() { - MainContent = _downloadsView; - OptionBarMessageIcon = OptionBarMessageIconType.None; - OptionBarMessage = null; + SearchButtonClicked(); if (OptionBarLoadSubscriptionButtonChecked) { + if (!NetworkHelper.Instance.ConnectionInformation.IsInternetAvailable) + { + ShowError(ErrorNoInternetConnection()); + OptionBarLoadSubscriptionButtonChecked = false; + return; + } + OptionBarContent = OptionBarContentType.None; OptionBarVideoSearchButtonChecked = false; OptionBarPlaylistSearchButtonChecked = false; - OptionBarSearchNotPending = false; - OptionBarMessageIcon = OptionBarMessageIconType.ProgressRing; - OptionBarMessage = _stringResourcesService.HomeViewResources.Get("OptionBarMessageLoading"); + StartSearch(); SubscriptionsVideoList subList = new SubscriptionsVideoList { Name = _stringResourcesService.CommonResources.Get("SubscriptionVideoListName") }; List tasks = new List(); - foreach (Subscription sub in _subscriptionsDataService.Data.ToArray()) + try { - tasks.Add(Task.Run(async () => + foreach (Subscription sub in _subscriptionsDataService.Data.ToArray()) { - Playlist playlist; - try + tasks.Add(Task.Run(async () => { - playlist = await _searchService.SearchPlaylist(sub.Url.OriginalString, 0); - } - catch (MediaSearchException) - { - return; - } + Playlist playlist; + try + { + playlist = await _searchService.SearchPlaylist(sub.Url.OriginalString, 0); + } + catch (MediaSearchException) + { + return; + } - IEnumerable