Refactor download progress calculation to use centralized stats and simplify logic across services.
- Fixes an issue where progress goes back to 50% as soon as downloads are done - Prevents copy and update of torrent/nzb list by not updating download stats on every use, most callers don't require this data, notable perf/memory improvement.
This commit is contained in:
parent
a5f9cd353b
commit
40be170677
5 changed files with 58 additions and 68 deletions
|
|
@ -40,6 +40,7 @@ public class SabnzbdTest
|
|||
};
|
||||
|
||||
_torrentsMock.Setup(t => t.Get()).ReturnsAsync(torrentList);
|
||||
_torrentsMock.Setup(t => t.GetDownloadStats(It.IsAny<Guid>())).Returns((0, 1000, 500));
|
||||
|
||||
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings);
|
||||
|
||||
|
|
|
|||
|
|
@ -223,29 +223,28 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
|
|||
var speed = torrent.RdSpeed ?? 0;
|
||||
var bytesDone = (Int64)(bytesTotal * rdProgress);
|
||||
|
||||
Double downloadProgress = 0;
|
||||
|
||||
Double progress;
|
||||
if (torrent.Downloads is { Count: > 0 })
|
||||
{
|
||||
var dlBytesDone = torrent.Downloads.Sum(m => m.BytesDone);
|
||||
var dlBytesTotal = torrent.Downloads.Sum(m => m.BytesTotal);
|
||||
speed = (Int32)torrent.Downloads.Average(m => m.Speed);
|
||||
downloadProgress = bytesTotal > 0 ? Math.Clamp((Double)dlBytesDone / dlBytesTotal, 0.0, 1.0) : 0;
|
||||
var dlStats = torrent.Downloads.Select(m => torrents.GetDownloadStats(m.DownloadId)).ToList();
|
||||
var dlBytesDone = dlStats.Sum(m => m.BytesDone);
|
||||
var dlBytesTotal = dlStats.Sum(m => m.BytesTotal);
|
||||
speed = (Int32)(dlStats.Any() ? dlStats.Average(m => m.Speed) : 0);
|
||||
var downloadProgress = dlBytesTotal > 0 ? Math.Clamp((Double)dlBytesDone / dlBytesTotal, 0.0, 1.0) : 0;
|
||||
progress = (rdProgress + downloadProgress) / 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
progress = rdProgress;
|
||||
}
|
||||
|
||||
var progress = (rdProgress + downloadProgress) / 2.0;
|
||||
var remaining = TimeSpan.Zero;
|
||||
var bytesRemaining = bytesTotal - bytesDone;
|
||||
|
||||
if (speed > 0 && bytesRemaining > 0)
|
||||
if (progress > 0 && progress < 1.0)
|
||||
{
|
||||
remaining = TimeSpan.FromSeconds(bytesRemaining / (Double)speed);
|
||||
|
||||
// In case there is clock skew
|
||||
if (remaining < TimeSpan.Zero)
|
||||
{
|
||||
remaining = TimeSpan.Zero;
|
||||
}
|
||||
var startTime = torrent.Retry > torrent.Added ? torrent.Retry.Value : torrent.Added;
|
||||
var elapsed = DateTimeOffset.UtcNow - startTime;
|
||||
var totalEstimatedTime = TimeSpan.FromTicks((Int64)(elapsed.Ticks / progress));
|
||||
remaining = totalEstimatedTime - elapsed;
|
||||
}
|
||||
|
||||
var result = new TorrentInfo
|
||||
|
|
@ -361,9 +360,10 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
|
|||
|
||||
if (torrent.Downloads.Count > 0)
|
||||
{
|
||||
bytesDone = torrent.Downloads.Sum(m => m.BytesDone);
|
||||
bytesTotal = torrent.Downloads.Sum(m => m.BytesTotal);
|
||||
speed = (Int32)torrent.Downloads.Average(m => m.Speed);
|
||||
var dlStats = torrent.Downloads.Select(m => torrents.GetDownloadStats(m.DownloadId)).ToList();
|
||||
bytesDone = dlStats.Sum(m => m.BytesDone);
|
||||
bytesTotal = dlStats.Sum(m => m.BytesTotal);
|
||||
speed = (Int32)(dlStats.Any() ? dlStats.Average(m => m.Speed) : 0);
|
||||
}
|
||||
|
||||
var result = new TorrentProperties
|
||||
|
|
|
|||
|
|
@ -19,17 +19,21 @@ public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings app
|
|||
NoOfSlots = activeTorrents.Count,
|
||||
Slots = activeTorrents.Select((t, index) =>
|
||||
{
|
||||
Double downloadProgress = 0;
|
||||
var rdProgress = Math.Clamp(t.RdProgress ?? 0.0, 0.0, 100.0) / 100.0;
|
||||
Double progress;
|
||||
|
||||
if (t.Downloads is { Count: > 0 })
|
||||
var dlStats = t.Downloads.Select(m => torrents.GetDownloadStats(m.DownloadId)).ToList();
|
||||
if (dlStats.Count > 0)
|
||||
{
|
||||
var bytesDone = t.Downloads.Sum(m => m.BytesDone);
|
||||
var bytesTotal = t.Downloads.Sum(m => m.BytesTotal);
|
||||
downloadProgress = bytesTotal > 0 ? Math.Clamp((Double)bytesDone / bytesTotal, 0.0, 1.0) : 0;
|
||||
var bytesDone = dlStats.Sum(m => m.BytesDone);
|
||||
var bytesTotal = dlStats.Sum(m => m.BytesTotal);
|
||||
var downloadProgress = bytesTotal > 0 ? Math.Clamp((Double)bytesDone / bytesTotal, 0.0, 1.0) : 0;
|
||||
progress = (rdProgress + downloadProgress) / 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
progress = rdProgress;
|
||||
}
|
||||
|
||||
var progress = (rdProgress + downloadProgress) / 2.0;
|
||||
|
||||
var timeLeft = "0:00:00";
|
||||
var startTime = t.Retry > t.Added ? t.Retry.Value : t.Added;
|
||||
|
|
@ -50,8 +54,8 @@ public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings app
|
|||
Index = index,
|
||||
NzoId = t.Hash,
|
||||
Filename = t.RdName ?? t.Hash,
|
||||
Size = FileSizeHelper.FormatSize(t.Downloads.Sum(d => d.BytesTotal)),
|
||||
SizeLeft = FileSizeHelper.FormatSize(t.Downloads.Sum(d => d.BytesTotal - d.BytesDone)),
|
||||
Size = FileSizeHelper.FormatSize(dlStats.Sum(d => d.BytesTotal)),
|
||||
SizeLeft = FileSizeHelper.FormatSize(dlStats.Sum(d => d.BytesTotal - d.BytesDone)),
|
||||
Percentage = (progress * 100.0).ToString("0"),
|
||||
|
||||
Status = t.RdStatus switch
|
||||
|
|
|
|||
|
|
@ -23,6 +23,21 @@ public class TorrentRunner(ILogger<TorrentRunner> logger, Torrents torrents, Dow
|
|||
|
||||
public static Boolean IsPausedForLowDiskSpace { get; set; }
|
||||
|
||||
public static (Int64 Speed, Int64 BytesTotal, Int64 BytesDone) GetStats(Guid downloadId)
|
||||
{
|
||||
if (ActiveDownloadClients.TryGetValue(downloadId, out var downloadClient))
|
||||
{
|
||||
return (downloadClient.Speed, downloadClient.BytesTotal, downloadClient.BytesDone);
|
||||
}
|
||||
|
||||
if (ActiveUnpackClients.TryGetValue(downloadId, out var unpackClient))
|
||||
{
|
||||
return (0, 100, unpackClient.Progess);
|
||||
}
|
||||
|
||||
return (0, 0, 0);
|
||||
}
|
||||
|
||||
public async Task Initialize()
|
||||
{
|
||||
Log("Initializing TorrentRunner");
|
||||
|
|
@ -665,8 +680,8 @@ public class TorrentRunner(ILogger<TorrentRunner> logger, Torrents torrents, Dow
|
|||
|
||||
var completePerc = 0;
|
||||
|
||||
var totalDownloadBytes = torrent.Downloads.Sum(m => m.BytesTotal);
|
||||
var totalDoneBytes = torrent.Downloads.Sum(m => m.BytesDone);
|
||||
var totalDownloadBytes = torrent.Downloads.Sum(m => GetStats(m.DownloadId).BytesTotal);
|
||||
var totalDoneBytes = torrent.Downloads.Sum(m => GetStats(m.DownloadId).BytesDone);
|
||||
|
||||
if (totalDownloadBytes > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -58,29 +58,15 @@ public class Torrents(
|
|||
|
||||
private static readonly SemaphoreSlim TorrentResetLock = new(1, 1);
|
||||
|
||||
public virtual (Int64 Speed, Int64 BytesTotal, Int64 BytesDone) GetDownloadStats(Guid downloadId)
|
||||
{
|
||||
return TorrentRunner.GetStats(downloadId);
|
||||
}
|
||||
|
||||
public virtual async Task<IList<Torrent>> Get()
|
||||
{
|
||||
var torrents = await torrentData.Get();
|
||||
|
||||
foreach (var torrent in torrents)
|
||||
{
|
||||
foreach (var download in torrent.Downloads)
|
||||
{
|
||||
if (TorrentRunner.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient))
|
||||
{
|
||||
download.Speed = downloadClient.Speed;
|
||||
download.BytesTotal = downloadClient.BytesTotal;
|
||||
download.BytesDone = downloadClient.BytesDone;
|
||||
}
|
||||
|
||||
if (TorrentRunner.ActiveUnpackClients.TryGetValue(download.DownloadId, out var unpackClient))
|
||||
{
|
||||
download.BytesTotal = 100;
|
||||
download.BytesDone = unpackClient.Progess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return torrents;
|
||||
}
|
||||
|
||||
|
|
@ -663,8 +649,7 @@ public class Torrents(
|
|||
{
|
||||
Category = Settings.Get.Provider.Default.Category,
|
||||
DownloadClient = Settings.Get.DownloadClient.Client,
|
||||
DownloadAction =
|
||||
Settings.Get.Provider.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll,
|
||||
DownloadAction = Settings.Get.Provider.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll,
|
||||
HostDownloadAction = Settings.Get.Provider.Default.HostDownloadAction,
|
||||
FinishedActionDelay = Settings.Get.Provider.Default.FinishedActionDelay,
|
||||
FinishedAction = Settings.Get.Provider.Default.FinishedAction,
|
||||
|
|
@ -881,22 +866,6 @@ public class Torrents(
|
|||
|
||||
await UpdateTorrentClientData(torrent);
|
||||
|
||||
foreach (var download in torrent.Downloads)
|
||||
{
|
||||
if (TorrentRunner.ActiveDownloadClients.TryGetValue(download.DownloadId, out var downloadClient))
|
||||
{
|
||||
download.Speed = downloadClient.Speed;
|
||||
download.BytesTotal = downloadClient.BytesTotal;
|
||||
download.BytesDone = downloadClient.BytesDone;
|
||||
}
|
||||
|
||||
if (TorrentRunner.ActiveUnpackClients.TryGetValue(download.DownloadId, out var unpackClient))
|
||||
{
|
||||
download.BytesTotal = 100;
|
||||
download.BytesDone = unpackClient.Progess;
|
||||
}
|
||||
}
|
||||
|
||||
return torrent;
|
||||
}
|
||||
|
||||
|
|
@ -1084,6 +1053,7 @@ public class Torrents(
|
|||
|
||||
logger.LogDebug(message);
|
||||
}
|
||||
|
||||
private static String ComputeSha1Hash(String input)
|
||||
{
|
||||
using var sha1 = System.Security.Cryptography.SHA1.Create();
|
||||
|
|
|
|||
Loading…
Reference in a new issue