mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-05-10 07:46:33 -04:00
137 lines
5.3 KiB
C#
137 lines
5.3 KiB
C#
using Cleanuparr.Domain.Entities;
|
|
using Cleanuparr.Domain.Enums;
|
|
using Cleanuparr.Infrastructure.Extensions;
|
|
using Cleanuparr.Infrastructure.Features.Context;
|
|
using Cleanuparr.Persistence.Models.Configuration.QueueCleaner;
|
|
using Microsoft.Extensions.Logging;
|
|
using QBittorrent.Client;
|
|
|
|
namespace Cleanuparr.Infrastructure.Features.DownloadClient.QBittorrent;
|
|
|
|
public partial class QBitService
|
|
{
|
|
/// <inheritdoc/>
|
|
public override async Task<DownloadCheckResult> ShouldRemoveFromArrQueueAsync(string hash, IReadOnlyList<string> ignoredDownloads)
|
|
{
|
|
DownloadCheckResult result = new();
|
|
TorrentInfo? download = (await _client.GetTorrentListAsync(new TorrentListQuery { Hashes = [hash] }))
|
|
.FirstOrDefault();
|
|
|
|
if (download is null)
|
|
{
|
|
_logger.LogDebug("Failed to find torrent {hash} in the {name} download client", hash, _downloadClientConfig.Name);
|
|
return result;
|
|
}
|
|
|
|
IReadOnlyList<TorrentTracker> trackers = await GetTrackersAsync(hash);
|
|
|
|
TorrentProperties? torrentProperties = await _client.GetTorrentPropertiesAsync(hash);
|
|
|
|
if (torrentProperties is null)
|
|
{
|
|
_logger.LogError("Failed to find torrent properties for {name}", download.Name);
|
|
return result;
|
|
}
|
|
|
|
result.IsPrivate = torrentProperties.AdditionalData.TryGetValue("is_private", out var dictValue) &&
|
|
bool.TryParse(dictValue?.ToString(), out bool boolValue)
|
|
&& boolValue;
|
|
|
|
result.Found = true;
|
|
SetDownloadClientContext();
|
|
|
|
// Create ITorrentItem wrapper for consistent interface usage
|
|
QBitItemWrapper torrent = new(download, trackers, result.IsPrivate);
|
|
|
|
if (torrent.IsIgnored(ignoredDownloads))
|
|
{
|
|
_logger.LogInformation("skip | download is ignored | {name}", torrent.Name);
|
|
return result;
|
|
}
|
|
|
|
IReadOnlyList<TorrentContent>? files = await _client.GetTorrentContentsAsync(hash);
|
|
|
|
if (files?.Count is > 0 && files.All(x => x.Priority is TorrentContentPriority.Skip))
|
|
{
|
|
result.ShouldRemove = true;
|
|
|
|
// if all files were blocked by qBittorrent
|
|
if (download is { CompletionOn: not null, Downloaded: null or 0 })
|
|
{
|
|
_logger.LogDebug("all files are unwanted by qBit | removing download | {name}", torrent.Name);
|
|
result.DeleteReason = DeleteReason.AllFilesSkippedByQBit;
|
|
result.DeleteFromClient = true;
|
|
return result;
|
|
}
|
|
|
|
// remove if all files are unwanted
|
|
_logger.LogDebug("all files are unwanted | removing download | {name}", torrent.Name);
|
|
result.DeleteReason = DeleteReason.AllFilesSkipped;
|
|
result.DeleteFromClient = true;
|
|
return result;
|
|
}
|
|
|
|
(result.ShouldRemove, result.DeleteReason, result.DeleteFromClient, result.ChangeCategory) = await EvaluateDownloadRemoval(torrent);
|
|
|
|
return result;
|
|
}
|
|
|
|
private async Task<(bool ShouldRemove, DeleteReason Reason, bool DeleteFromClient, bool ChangeCategory)> EvaluateDownloadRemoval(ITorrentItemWrapper wrapper)
|
|
{
|
|
(bool ShouldRemove, DeleteReason Reason, bool DeleteFromClient, bool ChangeCategory) slowResult = await CheckIfSlow(wrapper);
|
|
|
|
if (slowResult.ShouldRemove)
|
|
{
|
|
return slowResult;
|
|
}
|
|
|
|
return await CheckIfStuck(wrapper);
|
|
}
|
|
|
|
private async Task<(bool ShouldRemove, DeleteReason Reason, bool DeleteFromClient, bool ChangeCategory)> CheckIfSlow(ITorrentItemWrapper wrapper)
|
|
{
|
|
if (!wrapper.IsDownloading())
|
|
{
|
|
_logger.LogTrace("skip slow check | download is not in downloading state | {name}", wrapper.Name);
|
|
return (false, DeleteReason.None, false, false);
|
|
}
|
|
|
|
if (wrapper.DownloadSpeed <= 0)
|
|
{
|
|
_logger.LogTrace("skip slow check | download speed is 0 | {name}", wrapper.Name);
|
|
return (false, DeleteReason.None, false, false);
|
|
}
|
|
|
|
return await _queueRuleEvaluator.EvaluateSlowRulesAsync(wrapper);
|
|
}
|
|
|
|
private async Task<(bool ShouldRemove, DeleteReason Reason, bool DeleteFromClient, bool ChangeCategory)> CheckIfStuck(ITorrentItemWrapper wrapper)
|
|
{
|
|
if (((QBitItemWrapper)wrapper).IsMetadataDownloading())
|
|
{
|
|
var queueCleanerConfig = ContextProvider.Get<QueueCleanerConfig>(nameof(QueueCleanerConfig));
|
|
|
|
if (queueCleanerConfig.DownloadingMetadataMaxStrikes > 0)
|
|
{
|
|
bool shouldRemove = await _striker.StrikeAndCheckLimit(
|
|
wrapper.Hash,
|
|
wrapper.Name,
|
|
queueCleanerConfig.DownloadingMetadataMaxStrikes,
|
|
StrikeType.DownloadingMetadata
|
|
);
|
|
|
|
return (shouldRemove, DeleteReason.DownloadingMetadata, shouldRemove, false);
|
|
}
|
|
|
|
return (false, DeleteReason.None, false, false);
|
|
}
|
|
|
|
if (!wrapper.IsStalled())
|
|
{
|
|
_logger.LogTrace("skip stalled check | download is not in stalled state | {name}", wrapper.Name);
|
|
return (false, DeleteReason.None, false, false);
|
|
}
|
|
|
|
return await _queueRuleEvaluator.EvaluateStallRulesAsync(wrapper);
|
|
}
|
|
} |