From cd74725561cf8ddc66b935e9d62cd1d81294aa90 Mon Sep 17 00:00:00 2001 From: Mateusz Skoczek Date: Sat, 9 Mar 2024 21:53:30 +0100 Subject: [PATCH 1/4] infobar errors --- .../Strings/en-US/HomeViewResources.resw | 3 + .../Home/HomeViewModel.cs | 53 ++-- .../VDownload.Core.Views/Home/HomeView.xaml | 248 +++++++++--------- .../Subscriptions/SubscriptionsView.xaml | 2 +- 4 files changed, 158 insertions(+), 148 deletions(-) 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..8462c2e 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,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Error + Download all diff --git a/VDownload.Core/VDownload.Core.ViewModels/Home/HomeViewModel.cs b/VDownload.Core/VDownload.Core.ViewModels/Home/HomeViewModel.cs index 8dd6d3f..a6bb706 100644 --- a/VDownload.Core/VDownload.Core.ViewModels/Home/HomeViewModel.cs +++ b/VDownload.Core/VDownload.Core.ViewModels/Home/HomeViewModel.cs @@ -23,13 +23,6 @@ namespace VDownload.Core.ViewModels.Home { #region ENUMS - public enum OptionBarMessageIconType - { - None, - ProgressRing, - Error - } - public enum OptionBarContentType { None, @@ -80,6 +73,11 @@ namespace VDownload.Core.ViewModels.Home [ObservableProperty] private Type _mainContent; + [ObservableProperty] + private string _optionBarError; + + [ObservableProperty] + private bool _optionBarIsErrorOpened; [ObservableProperty] private OptionBarContentType _optionBarContent; @@ -88,7 +86,7 @@ namespace VDownload.Core.ViewModels.Home private string _optionBarMessage; [ObservableProperty] - private OptionBarMessageIconType _optionBarMessageIcon; + private bool _optionBarLoading; [ObservableProperty] private bool _optionBarLoadSubscriptionButtonChecked; @@ -149,8 +147,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; @@ -164,7 +164,7 @@ namespace VDownload.Core.ViewModels.Home public async Task LoadFromSubscription() { MainContent = _downloadsView; - OptionBarMessageIcon = OptionBarMessageIconType.None; + OptionBarLoading = false; OptionBarMessage = null; if (OptionBarLoadSubscriptionButtonChecked) @@ -174,7 +174,7 @@ namespace VDownload.Core.ViewModels.Home OptionBarPlaylistSearchButtonChecked = false; OptionBarSearchNotPending = false; - OptionBarMessageIcon = OptionBarMessageIconType.ProgressRing; + OptionBarLoading = true; OptionBarMessage = _stringResourcesService.HomeViewResources.Get("OptionBarMessageLoading"); SubscriptionsVideoList subList = new SubscriptionsVideoList { Name = _stringResourcesService.CommonResources.Get("SubscriptionVideoListName") }; @@ -217,7 +217,7 @@ namespace VDownload.Core.ViewModels.Home } OptionBarSearchNotPending = true; - OptionBarMessageIcon = OptionBarMessageIconType.None; + OptionBarLoading = false; } } @@ -225,7 +225,7 @@ namespace VDownload.Core.ViewModels.Home public void VideoSearchShow() { OptionBarSearchNotPending = true; - OptionBarMessageIcon = OptionBarMessageIconType.None; + OptionBarLoading = false; OptionBarMessage = null; MainContent = _downloadsView; @@ -245,7 +245,7 @@ namespace VDownload.Core.ViewModels.Home public void PlaylistSearchShow() { OptionBarSearchNotPending = true; - OptionBarMessageIcon = OptionBarMessageIconType.None; + OptionBarLoading = false; OptionBarMessage = null; MainContent = _downloadsView; @@ -265,7 +265,7 @@ namespace VDownload.Core.ViewModels.Home public async Task VideoSearchStart() { OptionBarSearchNotPending = false; - OptionBarMessageIcon = OptionBarMessageIconType.ProgressRing; + OptionBarLoading = true; OptionBarMessage = _stringResourcesService.HomeViewResources.Get("OptionBarMessageLoading"); Video video; @@ -275,9 +275,10 @@ namespace VDownload.Core.ViewModels.Home } catch (MediaSearchException ex) { - OptionBarMessageIcon = OptionBarMessageIconType.Error; - OptionBarMessage = _stringResourcesService.SearchResources.Get(ex.StringCode); + OptionBarError = _stringResourcesService.SearchResources.Get(ex.StringCode); OptionBarSearchNotPending = true; + OptionBarLoading = false; + OptionBarMessage = null; return; } @@ -286,7 +287,7 @@ namespace VDownload.Core.ViewModels.Home MainContent = _videoView; OptionBarSearchNotPending = true; - OptionBarMessageIcon = OptionBarMessageIconType.None; + OptionBarLoading = false; OptionBarMessage = null; } @@ -294,7 +295,7 @@ namespace VDownload.Core.ViewModels.Home public async Task PlaylistSearchStart() { OptionBarSearchNotPending = false; - OptionBarMessageIcon = OptionBarMessageIconType.ProgressRing; + OptionBarLoading = true; OptionBarMessage = _stringResourcesService.HomeViewResources.Get("OptionBarMessageLoading"); Playlist playlist; @@ -304,9 +305,10 @@ namespace VDownload.Core.ViewModels.Home } catch (MediaSearchException ex) { - OptionBarMessageIcon = OptionBarMessageIconType.Error; - OptionBarMessage = _stringResourcesService.SearchResources.Get(ex.StringCode); + OptionBarError = _stringResourcesService.SearchResources.Get(ex.StringCode); OptionBarSearchNotPending = true; + OptionBarLoading = false; + OptionBarMessage = null; return; } @@ -315,7 +317,7 @@ namespace VDownload.Core.ViewModels.Home MainContent = _videoCollectionView; OptionBarSearchNotPending = true; - OptionBarMessageIcon = OptionBarMessageIconType.None; + OptionBarLoading = false; OptionBarMessage = null; } @@ -339,6 +341,13 @@ namespace VDownload.Core.ViewModels.Home } } + [RelayCommand] + public void CloseError() + { + OptionBarError = null; + OptionBarIsErrorOpened = true; + } + #endregion diff --git a/VDownload.Core/VDownload.Core.Views/Home/HomeView.xaml b/VDownload.Core/VDownload.Core.Views/Home/HomeView.xaml index 25a1322..f9e900b 100644 --- a/VDownload.Core/VDownload.Core.Views/Home/HomeView.xaml +++ b/VDownload.Core/VDownload.Core.Views/Home/HomeView.xaml @@ -25,130 +25,128 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/VDownload.Core/VDownload.Core.Views/Home/HomeView.xaml b/VDownload.Core/VDownload.Core.Views/Home/HomeView.xaml index ff6a882..263bcdc 100644 --- a/VDownload.Core/VDownload.Core.Views/Home/HomeView.xaml +++ b/VDownload.Core/VDownload.Core.Views/Home/HomeView.xaml @@ -134,6 +134,9 @@ IsChecked="{Binding OptionBarPlaylistSearchButtonChecked, Mode=TwoWay}" Command="{Binding PlaylistSearchShowCommand}"/> + diff --git a/VDownload.Core/VDownload.Core.Views/Subscriptions/SubscriptionsView.xaml b/VDownload.Core/VDownload.Core.Views/Subscriptions/SubscriptionsView.xaml index d84690d..feb9aca 100644 --- a/VDownload.Core/VDownload.Core.Views/Subscriptions/SubscriptionsView.xaml +++ b/VDownload.Core/VDownload.Core.Views/Subscriptions/SubscriptionsView.xaml @@ -107,7 +107,7 @@ diff --git a/VDownload.Services/VDownload.Services.UI/VDownload.Services.UI.WebView/WebViewWindow.xaml b/VDownload.Services/VDownload.Services.UI/VDownload.Services.UI.WebView/WebViewWindow.xaml index 5b40d42..7ae602f 100644 --- a/VDownload.Services/VDownload.Services.UI/VDownload.Services.UI.WebView/WebViewWindow.xaml +++ b/VDownload.Services/VDownload.Services.UI/VDownload.Services.UI.WebView/WebViewWindow.xaml @@ -7,6 +7,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" - Closed="Window_Closed"> + Closed="Window_Closed" + Activated="Window_Activated"> diff --git a/VDownload.Services/VDownload.Services.UI/VDownload.Services.UI.WebView/WebViewWindow.xaml.cs b/VDownload.Services/VDownload.Services.UI/VDownload.Services.UI.WebView/WebViewWindow.xaml.cs index 838a358..a08a635 100644 --- a/VDownload.Services/VDownload.Services.UI/VDownload.Services.UI.WebView/WebViewWindow.xaml.cs +++ b/VDownload.Services/VDownload.Services.UI/VDownload.Services.UI.WebView/WebViewWindow.xaml.cs @@ -1,3 +1,5 @@ +using Microsoft.UI; +using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls.Primitives; @@ -84,6 +86,14 @@ namespace VDownload.Services.UI.WebView _isOpened = false; } + private void Window_Activated(object sender, WindowActivatedEventArgs args) + { + IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(this); + WindowId windowId = Win32Interop.GetWindowIdFromWindow(windowHandle); + AppWindow appWindow = AppWindow.GetFromWindowId(windowId); + appWindow.SetIcon(@"Assets\Logo\Logo.ico"); + } + #endregion } } From f0894c0ccdb3053c04653347648b6a3f149ea862 Mon Sep 17 00:00:00 2001 From: Mateusz Skoczek Date: Sun, 10 Mar 2024 01:52:23 +0100 Subject: [PATCH 4/4] fixes, errors handling --- .../en-US/HomeDownloadsViewResources.resw | 15 ++++++ .../VDownload.Core.Tasks/DownloadTask.cs | 49 ++++++++++++++++--- .../Home/HomeDownloadsViewModel.cs | 8 +++ .../FFmpegBuilder.cs | 15 +++--- .../TwitchVodStream.cs | 23 ++++----- 5 files changed, 83 insertions(+), 27 deletions(-) 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.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/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.Services/VDownload.Services.Utility/VDownload.Services.Utility.FFmpeg/FFmpegBuilder.cs b/VDownload.Services/VDownload.Services.Utility/VDownload.Services.Utility.FFmpeg/FFmpegBuilder.cs index fc635da..33ea457 100644 --- a/VDownload.Services/VDownload.Services.Utility/VDownload.Services.Utility.FFmpeg/FFmpegBuilder.cs +++ b/VDownload.Services/VDownload.Services.Utility/VDownload.Services.Utility.FFmpeg/FFmpegBuilder.cs @@ -40,6 +40,9 @@ namespace VDownload.Services.Utility.FFmpeg protected string _inputFile; protected string _outputFile; + protected string _audioCodec; + protected string _videoCodec; + protected FFOptions _options; #endregion @@ -103,6 +106,10 @@ namespace VDownload.Services.Utility.FFmpeg _inputFile = inputFile; _outputFile = outputFile; + IMediaAnalysis analysis = await FFProbe.AnalyseAsync(_inputFile, _options); + _audioCodec = analysis.AudioStreams.First().CodecName; + _videoCodec = analysis.VideoStreams.First().CodecName; + FFMpegArgumentProcessor ffmpegArguments = FFMpegArguments.FromFileInput(inputFile, true, async (options) => await BuildInputArgumentOptions(options)) .OutputToFile(outputFile, true, async (options) => await BuildOutputArgumentOptions(options)); @@ -154,17 +161,13 @@ namespace VDownload.Services.Utility.FFmpeg private async Task BuildOutputArgumentOptions(FFMpegArgumentOptions options) { - IMediaAnalysis analysis = await FFProbe.AnalyseAsync(_inputFile, _options); - string audioCodec = analysis.AudioStreams.First().CodecName; - string videoCodec = analysis.VideoStreams.First().CodecName; - string extension = Path.GetExtension(_outputFile).Replace(".", string.Empty); Data.Configuration.Models.Muxer muxer = _configurationService.Common.Processing.Muxers.First(x => x.Extension == extension); if (_mediaType != MediaType.OnlyAudio) { IEnumerable availableCodecs = muxer.VideoCodecs; - string selectedCodec = availableCodecs.Contains(videoCodec) ? "copy" : availableCodecs.First(); + string selectedCodec = availableCodecs.Contains(_videoCodec) ? "copy" : availableCodecs.First(); options.WithCustomArgument($"-vcodec {selectedCodec}"); } else @@ -175,7 +178,7 @@ namespace VDownload.Services.Utility.FFmpeg if (_mediaType != MediaType.OnlyVideo) { IEnumerable availableCodecs = muxer.AudioCodecs; - string selectedCodec = availableCodecs.Contains(audioCodec) ? "copy" : availableCodecs.First(); + string selectedCodec = availableCodecs.Contains(_audioCodec) ? "copy" : availableCodecs.First(); options.WithCustomArgument($"-acodec {selectedCodec}"); } else diff --git a/VDownload.Sources/VDownload.Sources.Twitch/VDownload.Sources.Twitch.Models/TwitchVodStream.cs b/VDownload.Sources/VDownload.Sources.Twitch/VDownload.Sources.Twitch.Models/TwitchVodStream.cs index 5c00f2f..2e052c2 100644 --- a/VDownload.Sources/VDownload.Sources.Twitch/VDownload.Sources.Twitch.Models/TwitchVodStream.cs +++ b/VDownload.Sources/VDownload.Sources.Twitch/VDownload.Sources.Twitch.Models/TwitchVodStream.cs @@ -145,15 +145,17 @@ namespace VDownload.Sources.Twitch.Models { token.ThrowIfCancellationRequested(); - using (FileStream inputStream = File.OpenRead(path)) + using (FileStream inputStream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { inputStream.CopyTo(outputStream); } - - if (deleteSource) - { - File.Delete(path); - } + } + } + foreach (string item in sourceFiles) + { + if (deleteSource) + { + File.Delete(item); } } } @@ -184,10 +186,7 @@ namespace VDownload.Sources.Twitch.Models int retriesCount = 0; while (true) { - if (token.IsCancellationRequested) - { - return; - } + token.ThrowIfCancellationRequested(); try { byte[] data = await _httpClient.GetByteArrayAsync(chunk.Url, token); @@ -195,10 +194,6 @@ namespace VDownload.Sources.Twitch.Models onTaskEndSuccessfully.Invoke(); return; } - catch (OperationCanceledException) - { - return; - } catch (Exception ex) when (ex is HttpRequestException || ex is TaskCanceledException) { if (_settingsService.Data.Twitch.Vod.ChunkDownloadingError.Retry && retriesCount < _settingsService.Data.Twitch.Vod.ChunkDownloadingError.RetriesCount)