This repository has been archived on 2026-03-14. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Eco/VideoBrowser/Core/DownloadQueueHandler.cs
2023-07-24 12:00:34 +02:00

215 lines
6.7 KiB
C#

namespace VideoBrowser.Core
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
/// <summary>
/// Defines the <see cref="DownloadQueueHandler" />.
/// </summary>
public static class DownloadQueueHandler
{
#region Fields
private static bool _stop;
#endregion Fields
#region Properties
/// <summary>
/// Gets the DownloadingCount.
/// </summary>
private static int DownloadingCount => Queue.Count(o => IsDownloaderType(o) && o.CanPause());
/// <summary>
/// Gets or sets a value indicating whether LimitDownloads.
/// </summary>
public static bool LimitDownloads { get; set; }
/// <summary>
/// Gets or sets the MaxDownloads.
/// </summary>
public static int MaxDownloads { get; set; }
/// <summary>
/// Gets or sets the Queue.
/// </summary>
public static List<Operation> Queue { get; } = new List<Operation>();
#endregion Properties
#region Methods
/// <summary>
/// The Add.
/// </summary>
/// <param name="operation">The operation<see cref="Operation"/>.</param>
public static void Add(Operation operation)
{
operation.Completed += Operation_Completed;
operation.Resumed += Operation_Resumed;
operation.StatusChanged += Operation_StatusChanged;
Queue.Add(operation);
}
/// <summary>
/// The GetQueued.
/// </summary>
/// <returns>The <see cref="Operation[]"/>.</returns>
public static Operation[] GetQueued()
{
return Queue.Where(o => IsDownloaderType(o) && o.Status == OperationStatus.Queued).ToArray();
}
/// <summary>
/// The GetWorking.
/// </summary>
/// <returns>The <see cref="Operation[]"/>.</returns>
public static Operation[] GetWorking()
{
return Queue.Where(o => IsDownloaderType(o) && o.Status == OperationStatus.Working).ToArray();
}
/// <summary>
/// The Remove.
/// </summary>
/// <param name="operation">The operation<see cref="Operation"/>.</param>
public static void Remove(Operation operation)
{
operation.Completed -= Operation_Completed;
operation.Resumed -= Operation_Resumed;
operation.StatusChanged -= Operation_StatusChanged;
Queue.Remove(operation);
}
/// <summary>
/// The StartWatching.
/// </summary>
/// <param name="maxDownloads">The maxDownloads<see cref="int"/>.</param>
public static void StartWatching(int maxDownloads)
{
MaxDownloads = maxDownloads;
MainLoop();
}
/// <summary>
/// The Stop.
/// </summary>
public static void Stop()
{
_stop = true;
}
/// <summary>
/// The IsDownloaderType.
/// </summary>
/// <param name="operation">The operation<see cref="Operation"/>.</param>
/// <returns>The <see cref="bool"/>.</returns>
private static bool IsDownloaderType(Operation operation)
{
return operation is DownloadOperation;
}
/// <summary>
/// The MainLoop.
/// </summary>
private static async void MainLoop()
{
while (!_stop)
{
await Task.Delay(1000);
var queued = GetQueued();
// If downloads isn't limited, start all queued operations
if (!LimitDownloads)
{
if (queued.Length == 0)
{
continue;
}
foreach (var operation in queued)
{
if (operation.HasStarted)
{
operation.ResumeQuiet();
}
else
{
operation.Start();
}
}
}
else if (DownloadingCount < MaxDownloads)
{
// Number of operations to start
var count = Math.Min(MaxDownloads - DownloadingCount, queued.Length);
for (var i = 0; i < count; i++)
{
if (queued[i].HasStarted)
{
queued[i].ResumeQuiet();
}
else
{
queued[i].Start();
}
}
}
else if (DownloadingCount > MaxDownloads)
{
// Number of operations to pause
var count = DownloadingCount - MaxDownloads;
var working = GetWorking();
for (var i = DownloadingCount - 1; i > (MaxDownloads - 1); i--)
{
working[i].Queue();
}
}
}
}
/// <summary>
/// The Operation_Completed.
/// </summary>
/// <param name="sender">The sender<see cref="object"/>.</param>
/// <param name="e">The e<see cref="OperationEventArgs"/>.</param>
private static void Operation_Completed(object sender, OperationEventArgs e)
{
Remove((sender as Operation));
}
/// <summary>
/// The Operation_Resumed.
/// </summary>
/// <param name="sender">The sender<see cref="object"/>.</param>
/// <param name="e">The e<see cref="EventArgs"/>.</param>
private static void Operation_Resumed(object sender, EventArgs e)
{
// User resumed operation, prioritize this operation over other queued
var operation = sender as Operation;
// Move operation to top of queue, since pausing happens from the bottom.
// I.E. this operation will only paused if absolutely necessary.
Queue.Remove(operation);
Queue.Insert(0, operation);
}
/// <summary>
/// The Operation_StatusChanged.
/// </summary>
/// <param name="sender">The sender<see cref="object"/>.</param>
/// <param name="e">The e<see cref="StatusChangedEventArgs"/>.</param>
private static void Operation_StatusChanged(object sender, StatusChangedEventArgs e)
{
}
#endregion Methods
}
}