예제 #1
0
        public DownloaderViewModel(DisplayMessageDelegate displayMessage, ShowUrlsDelegate showUrls)
        {
            _client                           = new HttpClient();
            DownloadItemsList                 = new ObservableCollection <DownloaderObjectModel>();
            CategoriesList                    = new ObservableCollection <Category>();
            QueueProcessor                    = new QueueProcessor(Settings.Default.MaxParallelDownloads, QueueProcessor_PropertyChanged);
            _requestThrottler                 = new RequestThrottler(AppConstants.RequestThrottlerInterval);
            CollectionView                    = CollectionViewSource.GetDefaultView(DownloadItemsList);
            CollectionView.CurrentChanged    += CollectionView_CurrentChanged;
            _clipboardService                 = new ClipboardObserver();
            _semaphoreMeasuringSpeed          = new SemaphoreSlim(1);
            _semaphoreUpdatingList            = new SemaphoreSlim(1);
            _semaphoreRefreshingView          = new SemaphoreSlim(1);
            _ctsUpdatingList                  = null;
            _ctsRefreshView                   = null;
            _displayMessage                   = displayMessage;
            _lockDownloadItemsList            = DownloadItemsList;
            _lockBytesDownloaded              = this.BytesDownloaded;
            _lockBytesTransferredOverLifetime = Settings.Default.BytesTransferredOverLifetime;
            _showUrls                         = showUrls;
            this.Count                        = 0;
            this.DownloadingCount             = 0;
            this.ErroredCount                 = 0;
            this.FinishedCount                = 0;
            this.PausedCount                  = 0;
            this.QueuedCount                  = 0;
            this.ReadyCount                   = 0;
            this.VerifyingCount               = 0;
            this.BytesDownloaded              = 0;
            this.Status                       = "Ready";
            this.ProgressReporter             = new Progress <long>(value =>
            {
                Monitor.Enter(_lockBytesDownloaded);
                try
                {
                    this.BytesDownloaded += value;
                }
                finally
                {
                    Monitor.Exit(_lockBytesDownloaded);
                }
            });

            AddCommand                    = new RelayCommand <object>(Add);
            StartCommand                  = new RelayCommand <object>(Start);
            RemoveFromListCommand         = new RelayCommand <object>(RemoveFromList);
            CancelCommand                 = new RelayCommand <object>(Cancel);
            PauseCommand                  = new RelayCommand <object>(Pause);
            OpenCommand                   = new RelayCommand <object>(Open);
            OpenContainingFolderCommand   = new RelayCommand <object>(OpenContainingFolder);
            StartQueueCommand             = new RelayCommand <object>(StartQueue);
            StopQueueCommand              = new RelayCommand <object>(StopQueue);
            CloseAppCommand               = new RelayCommand <object>(CloseApp);
            CategoryChangedCommand        = new RelayCommand <object>(CategoryChanged);
            OptionsCommand                = new RelayCommand <object>(ShowOptions);
            EnqueueCommand                = new RelayCommand <object>(Enqueue);
            DequeueCommand                = new RelayCommand <object>(Dequeue);
            DeleteFileCommand             = new RelayCommand <object>(DeleteFile);
            RecheckCommand                = new RelayCommand <object>(Recheck);
            RedownloadCommand             = new RelayCommand <object>(Redownload);
            CopyLinkToClipboardCommand    = new RelayCommand <object>(CopyLinkToClipboard);
            ClearFinishedDownloadsCommand = new RelayCommand <object>(ClearFinishedDownloads);
            CancelBackgroundTaskCommand   = new RelayCommand <object>(
                CancelBackgroundTask, CancelBackgroundTask_CanExecute);
            CheckForUpdatesCommand = new RelayCommand <object>(CheckForUpdates);
            ShowHelpTopicsCommand  = new RelayCommand <object>(ShowHelpTopics);

            foreach (Category cat in (Category[])Enum.GetValues(typeof(Category)))
            {
                CategoriesList.Add(cat);
            }

            // Load last selected category
            if (string.IsNullOrEmpty(Settings.Default.LastSelectedCatagory))
            {
                SwitchCategory(Category.All);
            }
            else
            {
                SwitchCategory((Category)Enum.Parse(typeof(Category), Settings.Default.LastSelectedCatagory));
            }

            // Check for updates
            if (Settings.Default.AutoCheckForUpdates)
            {
                Task.Run(async() => await TriggerUpdateCheckAsync(true));
            }

            // Populate history
            Task.Run(async() =>
            {
                await _semaphoreUpdatingList.WaitAsync();

                _ctsUpdatingList = new CancellationTokenSource();
                var ct           = _ctsUpdatingList.Token;

                RaisePropertyChanged(nameof(this.IsBackgroundWorking));

                try
                {
                    if (Directory.Exists(AppPaths.LocalAppData))
                    {
                        this.Status = "Restoring data...";
                        RaisePropertyChanged(nameof(this.Status));
                    }
                    else
                    {
                        return;
                    }

                    SerializableDownloaderObjectModelList source;
                    var xmlReader = new XmlSerializer(typeof(SerializableDownloaderObjectModelList));

                    using (var streamReader = new StreamReader(AppPaths.DownloadsHistoryFile))
                    {
                        source = (SerializableDownloaderObjectModelList)xmlReader.Deserialize(streamReader);
                    }

                    var sourceObjects = source.Objects.ToArray();
                    var finalObjects  = new DownloaderObjectModel[sourceObjects.Count()];
                    var total         = sourceObjects.Count();

                    for (int i = 0; i < sourceObjects.Count(); i++)
                    {
                        if (ct.IsCancellationRequested)
                        {
                            break;
                        }
                        if (sourceObjects[i] == null)
                        {
                            continue;
                        }

                        int progress  = (int)((double)(i + 1) / total * 100);
                        this.Progress = progress;
                        this.Status   = "Restoring " + (i + 1) + " of " + total + ": " + sourceObjects[i].Url;
                        RaisePropertyChanged(nameof(this.Progress));
                        RaisePropertyChanged(nameof(this.Status));

                        var item = new DownloaderObjectModel(
                            ref _client,
                            sourceObjects[i].Url,
                            sourceObjects[i].Destination,
                            sourceObjects[i].IsQueued,
                            sourceObjects[i].TotalBytesToDownload,
                            sourceObjects[i].StatusCode,
                            Download_Created,
                            Download_Verifying,
                            Download_Verified,
                            Download_Started,
                            Download_Stopped,
                            Download_Enqueued,
                            Download_Dequeued,
                            Download_Finished,
                            Download_PropertyChanged,
                            ProgressReporter,
                            ref _requestThrottler);
                        item.SetCreationTime(sourceObjects[i].DateCreated);

                        finalObjects[i] = item;
                    }

                    this.Status = "Listing...";
                    RaisePropertyChanged(nameof(this.Status));

                    AddObjects(finalObjects);
                }
                catch
                {
                    return;
                }
                finally
                {
                    _ctsUpdatingList = null;

                    this.Progress = 0;
                    this.Status   = "Ready";
                    RaisePropertyChanged(nameof(this.Progress));
                    RaisePropertyChanged(nameof(this.Status));
                    RaisePropertyChanged(nameof(this.IsBackgroundWorking));

                    _semaphoreUpdatingList.Release();

                    RefreshCollection();
                }
            });
        }
예제 #2
0
        private async Task AddItemsAsync(string destination, bool enqueue, bool start = false, params string[] urls)
        {
            await _semaphoreUpdatingList.WaitAsync();

            _ctsUpdatingList = new CancellationTokenSource();
            var ct = _ctsUpdatingList.Token;

            RaisePropertyChanged(nameof(this.IsBackgroundWorking));

            int           total = urls.Count();
            int           maxParallelDownloads = Settings.Default.MaxParallelDownloads;
            var           items                = new DownloaderObjectModel[urls.Count()];
            var           tasks                = new List <Task>();
            var           forceEnqueue         = false;
            var           existingUrls         = (from di in DownloadItemsList select di.Url).ToArray();
            var           existingDestinations = (from di in DownloadItemsList select di.Destination).ToArray();
            List <string> skipping             = new List <string>();
            var           wasCanceled          = false;

            if (start && !enqueue && urls.Count() > Settings.Default.MaxParallelDownloads)
            {
                forceEnqueue = true;
            }

            for (int i = 0; i < total; i++)
            {
                int progress = (int)((double)(i + 1) / total * 100);
                this.Progress = progress;
                this.Status   = "Creating download " + (i + 1) + " of " + total + ": " + urls[i];
                RaisePropertyChanged(nameof(this.Status));
                RaisePropertyChanged(nameof(this.Progress));

                if (existingUrls.Contains(urls[i]))
                {
                    skipping.Add(urls[i]);
                    continue;
                }
                var fileName = CommonFunctions.GetFreshFilename(destination + Path.GetFileName(urls[i]));
                if (existingDestinations.Contains(fileName))
                {
                    skipping.Add(urls[i]);
                    continue;
                }

                DownloaderObjectModel item;
                if (forceEnqueue || enqueue)
                {
                    item = new DownloaderObjectModel(
                        ref _client,
                        urls[i],
                        fileName,
                        enqueue: true,
                        Download_Created,
                        Download_Verifying,
                        Download_Verified,
                        Download_Started,
                        Download_Stopped,
                        Download_Enqueued,
                        Download_Dequeued,
                        Download_Finished,
                        Download_PropertyChanged,
                        ProgressReporter,
                        ref _requestThrottler);
                }
                else
                {
                    item = new DownloaderObjectModel(
                        ref _client,
                        urls[i],
                        fileName,
                        enqueue: false,
                        Download_Created,
                        Download_Verifying,
                        Download_Verified,
                        Download_Started,
                        Download_Stopped,
                        Download_Enqueued,
                        Download_Dequeued,
                        Download_Finished,
                        Download_PropertyChanged,
                        ProgressReporter,
                        ref _requestThrottler);
                    if (start)
                    {
                        tasks.Add(item.StartAsync());
                    }
                }
                items[i] = item;

                if (ct.IsCancellationRequested)
                {
                    wasCanceled = true;
                    break;
                }
            }

            if (!wasCanceled)
            {
                this.Status = "Listing...";
                RaisePropertyChanged(nameof(this.Status));

                AddObjects(items);
            }

            _ctsUpdatingList = null;

            this.Progress = 0;
            this.Status   = "Ready";
            RaisePropertyChanged(nameof(this.Status));
            RaisePropertyChanged(nameof(this.Progress));
            RaisePropertyChanged(nameof(this.IsBackgroundWorking));

            _semaphoreUpdatingList.Release();

            RefreshCollection();

            if (!wasCanceled)
            {
                if (skipping.Count > 0)
                {
                    _showUrls(
                        skipping, "Duplicate Entries",
                        "The following URLs were not added because they are already in the list:");
                }

                if ((enqueue && start) || forceEnqueue)
                {
                    await QueueProcessor.StartAsync();
                }
                else
                {
                    await Task.WhenAll(tasks);
                }
            }
        }