Beispiel #1
0
        public void Progress_manager_with_multiple_operations_aggregates_their_progress_according_to_their_weight()
        {
            // Arrange
            var manager    = new ProgressManager();
            var operationA = manager.CreateOperation(2);
            var operationB = manager.CreateOperation(8);

            // Assert
            manager.Progress.Should().Be(0);
            manager.IsActive.Should().BeTrue();
            manager.Operations.Should().BeEquivalentTo(operationA, operationB);

            // Act
            operationA.Report(0.8);
            operationB.Report(0.4);

            // Assert
            manager.Progress.Should().BeApproximately(0.48, 10e-5);
            manager.IsActive.Should().BeTrue();
            manager.Operations.Should().BeEquivalentTo(operationA, operationB);

            // Act
            operationA.Dispose();
            operationB.Dispose();

            // Assert
            manager.Progress.Should().Be(0);
            manager.IsActive.Should().BeFalse();
            manager.Operations.Should().BeEmpty();
        }
Beispiel #2
0
        public void Progress_operation_correctly_implements_INotifyPropertyChanged()
        {
            // Arrange
            var manager = new ProgressManager();

            var operation = manager.CreateOperation();

            var eventValues = new List <double>();

            operation.PropertyChanged += (_, args) =>
            {
                if (args.PropertyName == nameof(manager.Progress))
                {
                    eventValues.Add(manager.Progress);
                }
            };

            // Act
            operation.Report(0.1);
            operation.Report(0.3);
            operation.Dispose();

            // Assert
            eventValues.Should().Equal(0.1, 0.3, 0);
        }
Beispiel #3
0
        public async void PopulateGuildsAndChannels()
        {
            using var operation = ProgressManager.CreateOperation();

            try
            {
                var tokenValue = TokenValue?.Trim('"', ' ');
                if (string.IsNullOrWhiteSpace(tokenValue))
                {
                    return;
                }

                var token = new AuthToken(
                    IsBotToken ? AuthTokenType.Bot : AuthTokenType.User,
                    tokenValue
                    );

                _settingsService.LastToken = token;

                var discord = new DiscordClient(token);

                var guildChannelMap = new Dictionary <Guild, IReadOnlyList <Channel> >();
                await foreach (var guild in discord.GetUserGuildsAsync())
                {
                    guildChannelMap[guild] = await discord.GetGuildChannelsAsync(guild.Id);
                }

                GuildChannelMap = guildChannelMap;
                SelectedGuild   = guildChannelMap.Keys.FirstOrDefault();
            }
            catch (DiscordChatExporterException ex) when(!ex.IsCritical)
            {
                Notifications.Enqueue(ex.Message.TrimEnd('.'));
            }
        }
Beispiel #4
0
        public void Start()
        {
            if (!CanStart)
            {
                return;
            }

            IsActive     = true;
            IsSuccessful = false;
            IsCanceled   = false;
            IsFailed     = false;

            Task.Run(async() =>
            {
                // Create cancellation token source
                _cancellationTokenSource = new CancellationTokenSource();

                // Create progress operation
                ProgressOperation = ProgressManager.CreateOperation();

                try
                {
                    // If download option is not set - get the best download option
                    if (DownloadOption == null)
                    {
                        DownloadOption = await _downloadService.GetBestDownloadOptionAsync(Video.Id, Format);
                    }

                    await _downloadService.DownloadVideoAsync(DownloadOption, FilePath, ProgressOperation, _cancellationTokenSource.Token);

                    if (_settingsService.ShouldInjectTags)
                    {
                        await _taggingService.InjectTagsAsync(Video, Format, FilePath, _cancellationTokenSource.Token);
                    }

                    if (SubtitleOption != null && SubtitleOption.ClosedCaptionTrackInfos.Any())
                    {
                        await _downloadService.DownloadSubtitleAsync(SubtitleOption, FilePath);
                    }

                    IsSuccessful = true;
                }
                catch (OperationCanceledException)
                {
                    IsCanceled = true;
                }
                catch (Exception ex)
                {
                    IsFailed   = true;
                    FailReason = ex.Message;
                }
                finally
                {
                    IsActive = false;

                    _cancellationTokenSource.Dispose();
                    ProgressOperation.Dispose();
                }
            });
        }
Beispiel #5
0
        public void Progress_manager_with_a_single_operation_returns_its_progress()
        {
            // Arrange
            var manager   = new ProgressManager();
            var operation = manager.CreateOperation();

            // Assert
            manager.Progress.Should().Be(0);
            manager.IsActive.Should().BeTrue();
            manager.Operations.Should().BeEquivalentTo(operation);

            // Act
            operation.Report(0.44);

            // Assert
            manager.Progress.Should().BeApproximately(0.44, 10e-5);
            manager.IsActive.Should().BeTrue();
            manager.Operations.Should().BeEquivalentTo(operation);

            // Act
            operation.Dispose();

            // Assert
            manager.Progress.Should().Be(0);
            manager.IsActive.Should().BeFalse();
            manager.Operations.Should().BeEmpty();
        }
Beispiel #6
0
        // This is async void on purpose because this is supposed to be always ran in background
        private async void EnqueueDownload(DownloadViewModel download)
        {
            // Cancel an existing download for this file path to prevent writing to the same file
            Downloads.FirstOrDefault(d => d.FilePath == download.FilePath)?.Cancel();

            // Add to list
            Downloads.Add(download);

            // Create progress operation
            download.ProgressOperation = ProgressManager.CreateOperation();

            // If download option is not set - get the best download option
            if (download.DownloadOption == null)
            {
                download.DownloadOption =
                    await _downloadService.GetBestDownloadOptionAsync(download.Video.Id, download.Format);
            }

            // Download
            try
            {
                await _downloadService.DownloadVideoAsync(download.Video.Id, download.FilePath,
                                                          download.DownloadOption, download.ProgressOperation, download.CancellationToken);
            }
            catch (OperationCanceledException)
            {
                // Ignore cancellations
            }

            // Mark download as completed
            download.MarkAsCompleted();
        }
Beispiel #7
0
        public void ProgressManager_SingleOperation_Test()
        {
            // Create manager
            var manager = new ProgressManager();

            // Create operation
            var operation = manager.CreateOperation();

            // Assert initial state after creating operation
            Assert.That(manager.Progress, Is.Zero);
            Assert.That(manager.IsActive, Is.True);
            Assert.That(manager.Operations.Count, Is.EqualTo(1));

            // Report new progress
            const double newProgress = 0.5;

            operation.Report(newProgress);

            // Assert intermediate state
            Assert.That(manager.Progress, Is.EqualTo(newProgress));
            Assert.That(manager.IsActive, Is.True);
            Assert.That(manager.Operations.Count, Is.EqualTo(1));

            // Report completion
            operation.Dispose();

            // Assert final state
            Assert.That(manager.Progress, Is.Zero);
            Assert.That(manager.IsActive, Is.False);
            Assert.That(manager.Operations.Count, Is.Zero);
        }
Beispiel #8
0
        public void Start()
        {
            if (!CanStart)
            {
                return;
            }

            IsActive     = true;
            IsSuccessful = false;
            IsCanceled   = false;
            IsFailed     = false;

            Task.Run(async() =>
            {
                // Create cancellation token source
                _cancellationTokenSource = new CancellationTokenSource();

                // Create progress operation
                ProgressOperation = ProgressManager.CreateOperation();

                try
                {
                    // daca nu sunt setate obtiuni de descarcare se foloseste setarea de baza
                    // descarca video
                    if (DownloadOption == null)
                    {
                        DownloadOption = await _downloadService.GetBestDownloadOptionAsync(Video.Id, Format);
                    }

                    await _downloadService.DownloadVideoAsync(DownloadOption, FilePath, ProgressOperation, _cancellationTokenSource.Token);

                    if (_settingsService.ShouldInjectTags)
                    {
                        await _taggingService.InjectTagsAsync(Video, Format, FilePath, _cancellationTokenSource.Token);
                    }

                    IsSuccessful = true;
                }
                catch (OperationCanceledException)
                {
                    IsCanceled = true;
                }
                catch (Exception ex)
                {
                    IsFailed   = true;
                    FailReason = ex.Message;
                }
                finally
                {
                    IsActive = false;

                    _cancellationTokenSource.Dispose();
                    ProgressOperation.Dispose();
                }
            });
        }
Beispiel #9
0
        public void Start()
        {
            if (!CanStart)
            {
                return;
            }

            Task.Run(async() =>
            {
                // Create cancellation token source
                _cancellationTokenSource = new CancellationTokenSource();

                // Create progress operation
                ProgressOperation = ProgressManager.CreateOperation();

                try
                {
                    IsSuccessful = false;
                    IsCanceled   = false;
                    IsFailed     = false;
                    IsActive     = true;

                    // If download option is not set - get the best download option
                    if (DownloadOption == null)
                    {
                        DownloadOption = await _downloadService.GetBestDownloadOptionAsync(Video.Id, Format);
                    }

                    // Download
                    await _downloadService.DownloadVideoAsync(DownloadOption, FilePath, ProgressOperation, _cancellationTokenSource.Token);

                    IsSuccessful = true;
                }
                catch (OperationCanceledException)
                {
                    IsCanceled = true;
                }
                catch (Exception ex)
                {
                    IsFailed   = true;
                    FailReason = ex.Message;
                }
                finally
                {
                    IsActive = false;

                    _cancellationTokenSource.Dispose();
                    ProgressOperation.Dispose();
                }
            });
        }
Beispiel #10
0
        public void Progress_operation_cannot_report_progress_after_it_has_been_disposed()
        {
            // Arrange
            var manager = new ProgressManager();

            var operation = manager.CreateOperation();

            operation.Report(0.1);
            operation.Report(0.3);
            operation.Dispose();

            // Act & Assert
            Assert.Throws <InvalidOperationException>(() => operation.Report(1));
        }
Beispiel #11
0
        public void StartOperation(double weight)
        {
            // Start a task that simulates some work and reports progress
            Task.Run(async() =>
            {
                using var operation = ProgressManager.CreateOperation(weight);

                for (var i = 0; i < 100; i++)
                {
                    // Delay execution to simulate activity
                    await Task.Delay(TimeSpan.FromSeconds(0.1));

                    // Report new progress
                    operation.Report((i + 1) / 100.0);
                }
            });
        }
Beispiel #12
0
        public void ProgressManager_NotifyPropertyChanged_Test()
        {
            // Create manager
            var manager = new ProgressManager();

            // Subscribe to event
            var eventTriggerCount = 0;

            manager.PropertyChanged += (sender, args) => eventTriggerCount++;

            // Create operation
            var operation = manager.CreateOperation();

            // Invoke changes
            operation.Report(0.1);
            operation.Report(0.3);
            operation.Dispose();

            // Assert that the event was triggered accordingly
            Assert.That(eventTriggerCount, Is.GreaterThanOrEqualTo(3));
        }
Beispiel #13
0
        public async void PopulateRecommendations()
        {
            // Create progress operation
            var operation = ProgressManager.CreateOperation();

            try
            {
                // Validate settings
                if (_settingsService.UserId.IsNullOrWhiteSpace() || _settingsService.ApiKey.IsNullOrWhiteSpace())
                {
                    Notifications.Enqueue("Not configured – set username and API key in settings",
                                          "OPEN", ShowSettings);
                    return;
                }

                // Get recommendations
                Recommendations = await _recommendationService.GetRecommendationsAsync(operation);

                // Persist recommendations in cache
                _cacheService.Store("LastRecommendations", Recommendations);

                // Notify completion
                Notifications.Enqueue("Recommendations updated");
            }
            catch (RecommendationsUnavailableException)
            {
                Notifications.Enqueue("Recommendations unavailable – no top plays set in selected game mode");
            }
            catch (HttpErrorStatusCodeException ex) when(ex.StatusCode == HttpStatusCode.Unauthorized)
            {
                Notifications.Enqueue("Unauthorized – make sure API key is valid");
            }
            finally
            {
                // Dispose progress operation
                operation.Dispose();
            }
        }
        public async void PopulateGuildsAndChannels()
        {
            // Create progress operation
            var operation = ProgressManager.CreateOperation();

            try
            {
                // Sanitize token
                TokenValue = TokenValue.Trim('"');

                // Create token
                var token = new AuthToken(
                    IsBotToken ? AuthTokenType.Bot : AuthTokenType.User,
                    TokenValue);

                // Save token
                _settingsService.LastToken = token;

                // Prepare available guild list
                var availableGuilds = new List <GuildViewModel>();

                // Get direct messages
                {
                    // Get fake guild
                    var guild = Guild.DirectMessages;

                    // Get channels
                    var channels = await _dataService.GetDirectMessageChannelsAsync(token);

                    // Create channel view models
                    var channelViewModels = new List <ChannelViewModel>();
                    foreach (var channel in channels)
                    {
                        // Get fake category
                        var category = channel.Type == ChannelType.DirectTextChat ? "Private" : "Group";

                        // Create channel view model
                        var channelViewModel = _viewModelFactory.CreateChannelViewModel(channel, category);

                        // Add to list
                        channelViewModels.Add(channelViewModel);
                    }

                    // Create guild view model
                    var guildViewModel = _viewModelFactory.CreateGuildViewModel(guild,
                                                                                channelViewModels.OrderBy(c => c.Category)
                                                                                .ThenBy(c => c.Model.Name)
                                                                                .ToArray());

                    // Add to list
                    availableGuilds.Add(guildViewModel);
                }

                // Get guilds
                var guilds = await _dataService.GetUserGuildsAsync(token);

                foreach (var guild in guilds)
                {
                    // Get channels
                    var channels = await _dataService.GetGuildChannelsAsync(token, guild.Id);

                    // Get category channels
                    var categoryChannels = channels.Where(c => c.Type == ChannelType.Category).ToArray();

                    // Get text channels
                    var textChannels = channels.Where(c => c.Type == ChannelType.GuildTextChat).ToArray();

                    // Create channel view models
                    var channelViewModels = new List <ChannelViewModel>();
                    foreach (var channel in textChannels)
                    {
                        // Get category
                        var category = categoryChannels.FirstOrDefault(c => c.Id == channel.ParentId)?.Name;

                        // Create channel view model
                        var channelViewModel = _viewModelFactory.CreateChannelViewModel(channel, category);

                        // Add to list
                        channelViewModels.Add(channelViewModel);
                    }

                    // Create guild view model
                    var guildViewModel = _viewModelFactory.CreateGuildViewModel(guild,
                                                                                channelViewModels.OrderBy(c => c.Category)
                                                                                .ThenBy(c => c.Model.Name)
                                                                                .ToArray());

                    // Add to list
                    availableGuilds.Add(guildViewModel);
                }

                // Update available guild list
                AvailableGuilds = availableGuilds;

                // Pre-select first guild
                SelectedGuild = AvailableGuilds.FirstOrDefault();
            }
            catch (HttpErrorStatusCodeException ex) when(ex.StatusCode == HttpStatusCode.Unauthorized)
            {
                Notifications.Enqueue("Unauthorized – make sure the token is valid");
            }
            catch (HttpErrorStatusCodeException ex) when(ex.StatusCode == HttpStatusCode.Forbidden)
            {
                Notifications.Enqueue("Forbidden – account may be locked by 2FA");
            }
            finally
            {
                // Dispose progress operation
                operation.Dispose();
            }
        }
Beispiel #15
0
        public void Start()
        {
            if (!CanStart)
            {
                return;
            }

            IsActive     = true;
            IsSuccessful = false;
            IsCanceled   = false;
            IsFailed     = false;

            Task.Run(async() =>
            {
                _cancellationTokenSource = new CancellationTokenSource();
                ProgressOperation        = ProgressManager?.CreateOperation();

                try
                {
                    // If download option is not set - get the best download option
                    VideoOption ??= await _downloadService.TryGetBestVideoDownloadOptionAsync(
                        Video.Id,
                        Format,
                        QualityPreference
                        );

                    // It's possible that video has no streams
                    if (VideoOption == null)
                    {
                        throw new InvalidOperationException($"Video '{Video.Id}' contains no streams.");
                    }

                    await _downloadService.DownloadAsync(
                        VideoOption,
                        SubtitleOption,
                        FilePath,
                        ProgressOperation,
                        _cancellationTokenSource.Token
                        );

                    if (_settingsService.ShouldInjectTags)
                    {
                        await _taggingService.InjectTagsAsync(
                            Video,
                            Format,
                            FilePath,
                            _cancellationTokenSource.Token
                            );
                    }

                    IsSuccessful = true;
                }
                catch (OperationCanceledException)
                {
                    IsCanceled = true;
                }
                catch (Exception ex)
                {
                    IsFailed = true;

                    // Short error message for expected errors, full for unexpected
                    FailReason = ex is YoutubeExplodeException
                        ? ex.Message
                        : ex.ToString();
                }
                finally
                {
                    IsActive = false;
                    _cancellationTokenSource?.Dispose();
                    _cancellationTokenSource = null;
                    ProgressOperation?.Dispose();
                }
            });
        }
        public async void ProcessQuery()
        {
            var operation = ProgressManager.CreateOperation();

            try
            {
                // Split query into separate lines and parse them
                var parsedQueries = _queryService.ParseMultilineQuery(Query);

                // Execute separate queries
                var executedQueries = await _queryService.ExecuteQueriesAsync(parsedQueries, operation);

                // Extract videos and other details
                var videos      = executedQueries.SelectMany(q => q.Videos).Distinct(v => v.Id).ToArray();
                var dialogTitle = executedQueries.Count == 1 ? executedQueries.Single().Title : "Multiple queries";

                // If no videos were found - tell the user
                if (videos.Length <= 0)
                {
                    // Create dialog
                    var dialog = _viewModelFactory.CreateMessageBoxViewModel("Nothing found",
                                                                             "Couldn't find any videos based on the query or URL you provided");

                    // Show dialog
                    await _dialogManager.ShowDialogAsync(dialog);
                }

                // If only one video was found - show download setup for single video
                else if (videos.Length == 1)
                {
                    // Get single video
                    var video = videos.Single();

                    // Get download options
                    var downloadOptions = await _downloadService.GetDownloadOptionsAsync(video.Id);

                    // Create dialog
                    var dialog = _viewModelFactory.CreateDownloadSingleSetupViewModel(dialogTitle, video, downloadOptions);

                    // Show dialog and get download
                    var download = await _dialogManager.ShowDialogAsync(dialog);

                    // If canceled - return
                    if (download == null)
                    {
                        return;
                    }

                    // Enqueue download
                    EnqueueAndStartDownload(download);
                }

                // If multiple videos were found - show download setup for multiple videos
                else
                {
                    // Create dialog
                    var dialog = _viewModelFactory.CreateDownloadMultipleSetupViewModel(dialogTitle, videos);

                    // Preselect all videos if none of the videos come from a search query
                    if (executedQueries.All(q => q.Query.Type != QueryType.Search))
                    {
                        dialog.SelectedVideos = dialog.AvailableVideos;
                    }

                    // Show dialog and get downloads
                    var downloads = await _dialogManager.ShowDialogAsync(dialog);

                    // If canceled - return
                    if (downloads == null)
                    {
                        return;
                    }

                    // Enqueue downloads
                    foreach (var download in downloads)
                    {
                        EnqueueAndStartDownload(download);
                    }
                }
            }
            catch (Exception ex)
            {
                // Create dialog
                var dialog = _viewModelFactory.CreateMessageBoxViewModel("Error", ex.Message);

                // Show dialog
                await _dialogManager.ShowDialogAsync(dialog);
            }
            finally
            {
                // Dispose progress operation
                operation.Dispose();
            }
        }
Beispiel #17
0
        public async void ProcessQuery()
        {
            // Small operation weight to not offset any existing download operations
            var operation = ProgressManager.CreateOperation(0.01);

            IsBusy = true;

            try
            {
                var parsedQueries   = _queryService.ParseMultilineQuery(Query !);
                var executedQueries = await _queryService.ExecuteQueriesAsync(parsedQueries, operation);

                var videos = executedQueries.SelectMany(q => q.Videos).Distinct(v => v.Id).ToArray();

                var dialogTitle = executedQueries.Count == 1
                    ? executedQueries.Single().Title
                    : "Multiple queries";

                // No videos found
                if (videos.Length <= 0)
                {
                    var dialog = _viewModelFactory.CreateMessageBoxViewModel(
                        "Nothing found",
                        "Couldn't find any videos based on the query or URL you provided"
                        );

                    await _dialogManager.ShowDialogAsync(dialog);
                }

                // Single video
                else if (videos.Length == 1)
                {
                    var video = videos.Single();

                    var downloadOptions = await _downloadService.GetVideoDownloadOptionsAsync(video.Id);

                    var subtitleOptions = await _downloadService.GetSubtitleDownloadOptionsAsync(video.Id);

                    var dialog = _viewModelFactory.CreateDownloadSingleSetupViewModel(
                        dialogTitle,
                        video,
                        downloadOptions,
                        subtitleOptions
                        );

                    var download = await _dialogManager.ShowDialogAsync(dialog);

                    if (download == null) // generics + NRTs issue
                    {
                        return;
                    }

                    EnqueueDownload(download);
                }

                // Multiple videos
                else
                {
                    var dialog = _viewModelFactory.CreateDownloadMultipleSetupViewModel(
                        dialogTitle,
                        videos
                        );

                    // Preselect all videos if none of the videos come from a search query
                    if (executedQueries.All(q => q.Query.Kind != QueryKind.Search))
                    {
                        dialog.SelectedVideos = dialog.AvailableVideos;
                    }

                    var downloads = await _dialogManager.ShowDialogAsync(dialog);

                    if (downloads == null) // generics + NRTs issue
                    {
                        return;
                    }

                    foreach (var download in downloads)
                    {
                        EnqueueDownload(download);
                    }
                }
            }
            catch (Exception ex)
            {
                var dialog = _viewModelFactory.CreateMessageBoxViewModel(
                    "Error",
                    // Short error message for expected errors, full for unexpected
                    ex is YoutubeExplodeException
                        ? ex.Message
                        : ex.ToString()
                    );

                await _dialogManager.ShowDialogAsync(dialog);
            }
            finally
            {
                operation.Dispose();
                IsBusy = false;
            }
        }
        public async void ProcessQuery()
        {
            var operation = ProgressManager.CreateOperation(0.01);


            IsBusy = true;

            try
            {
                var parsedQueries = _queryService.ParseMultilineQuery(Query !);


                var executedQueries = await _queryService.ExecuteQueriesAsync(parsedQueries, operation);


                var videos      = executedQueries.SelectMany(q => q.Videos).Distinct(v => v.Id).ToArray();
                var dialogTitle = executedQueries.Count == 1 ? executedQueries.Single().Title : "Multiple queries";


                if (videos.Length <= 0)
                {
                    // Create dialog
                    var dialog = _viewModelFactory.CreateMessageBoxViewModel("Nothing found",
                                                                             "Couldn't find any videos based on the query or URL you provided");


                    await _dialogManager.ShowDialogAsync(dialog);
                }


                else if (videos.Length == 1)
                {
                    var video = videos.Single();


                    var downloadOptions = await _downloadService.GetDownloadOptionsAsync(video.Id);


                    var dialog = _viewModelFactory.CreateDownloadSingleSetupViewModel(dialogTitle, video, downloadOptions);


                    var download = await _dialogManager.ShowDialogAsync(dialog);


                    if (download == null)
                    {
                        return;
                    }


                    EnqueueAndStartDownload(download);
                }


                else
                {
                    var dialog = _viewModelFactory.CreateDownloadMultipleSetupViewModel(dialogTitle, videos);


                    if (executedQueries.All(q => q.Query.Type != QueryType.Search))
                    {
                        dialog.SelectedVideos = dialog.AvailableVideos;
                    }


                    var downloads = await _dialogManager.ShowDialogAsync(dialog);


                    if (downloads == null)
                    {
                        return;
                    }


                    foreach (var download in downloads)
                    {
                        EnqueueAndStartDownload(download);
                    }
                }
            }
            catch (Exception ex)
            {
                var dialog = _viewModelFactory.CreateMessageBoxViewModel("Error", ex.Message);


                await _dialogManager.ShowDialogAsync(dialog);
            }
            finally
            {
                operation.Dispose();


                IsBusy = false;
            }
        }