Compare commits

...

4 Commits

Author SHA1 Message Date
Flaminel
2cc3eb4ebb Fix ignored downloads not checking for certain fields (#362) 2025-11-09 18:24:26 +02:00
Flaminel
3a064a22bd Remove hardcoded app status timeout (#356) 2025-11-03 18:38:09 +02:00
Flaminel
ee764ff215 Fix Transmission stalled check (#354) 2025-11-02 17:48:30 +02:00
Flaminel
402677b69b Fix ignored downloads not being saved for Queue Cleaner (#353)
fixed ignored downloads not being saved for Queue Cleaner
2025-10-31 17:39:52 +02:00
7 changed files with 94 additions and 20 deletions

View File

@@ -13,4 +13,6 @@ public sealed record UpdateQueueCleanerConfigRequest
public FailedImportConfig FailedImport { get; init; } = new();
public ushort DownloadingMetadataMaxStrikes { get; init; }
public List<string> IgnoredDownloads { get; set; } = [];
}

View File

@@ -69,6 +69,7 @@ public sealed class QueueCleanerConfigController : ControllerBase
oldConfig.UseAdvancedScheduling = newConfigDto.UseAdvancedScheduling;
oldConfig.FailedImport = newConfigDto.FailedImport;
oldConfig.DownloadingMetadataMaxStrikes = newConfigDto.DownloadingMetadataMaxStrikes;
oldConfig.IgnoredDownloads = newConfigDto.IgnoredDownloads;
await _dataContext.SaveChangesAsync();

View File

@@ -1,5 +1,6 @@
using Cleanuparr.Domain.Entities;
using Cleanuparr.Domain.Entities.Deluge.Response;
using Cleanuparr.Infrastructure.Services;
namespace Cleanuparr.Infrastructure.Features.DownloadClient.Deluge;
@@ -70,11 +71,26 @@ public sealed class DelugeItem : ITorrentItem
{
return false;
}
foreach (string pattern in ignoredDownloads)
{
if (Hash?.Equals(pattern, StringComparison.InvariantCultureIgnoreCase) is true)
{
return true;
}
return ignoredDownloads.Any(pattern =>
Name.Contains(pattern, StringComparison.InvariantCultureIgnoreCase) ||
Hash.Equals(pattern, StringComparison.InvariantCultureIgnoreCase) ||
Trackers.Any(tracker => tracker.EndsWith(pattern, StringComparison.InvariantCultureIgnoreCase)));
if (Category?.Equals(pattern, StringComparison.InvariantCultureIgnoreCase) is true)
{
return true;
}
if (_downloadStatus.Trackers.Any(x => UriService.GetDomain(x.Url)?.EndsWith(pattern, StringComparison.InvariantCultureIgnoreCase) is true))
{
return true;
}
}
return false;
}
/// <summary>

View File

@@ -1,4 +1,5 @@
using Cleanuparr.Domain.Entities;
using Cleanuparr.Infrastructure.Features.DownloadClient.UTorrent.Extensions;
using QBittorrent.Client;
namespace Cleanuparr.Infrastructure.Features.DownloadClient.QBittorrent;
@@ -73,10 +74,30 @@ public sealed class QBitItem : ITorrentItem
return false;
}
return ignoredDownloads.Any(pattern =>
Name.Contains(pattern, StringComparison.InvariantCultureIgnoreCase) ||
Hash.Equals(pattern, StringComparison.InvariantCultureIgnoreCase) ||
Trackers.Any(tracker => tracker.EndsWith(pattern, StringComparison.InvariantCultureIgnoreCase)));
foreach (string pattern in ignoredDownloads)
{
if (Hash.Equals(pattern, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
if (Category?.Equals(pattern, StringComparison.InvariantCultureIgnoreCase) is true)
{
return true;
}
if (_torrentInfo.Tags.Contains(pattern, StringComparer.InvariantCultureIgnoreCase))
{
return true;
}
if (Trackers.Any(tracker => tracker.ShouldIgnore(ignoredDownloads)))
{
return true;
}
}
return false;
}
/// <summary>

View File

@@ -1,4 +1,6 @@
using Cleanuparr.Domain.Entities;
using Cleanuparr.Infrastructure.Extensions;
using Cleanuparr.Infrastructure.Services;
using Transmission.API.RPC.Entity;
namespace Cleanuparr.Infrastructure.Features.DownloadClient.Transmission;
@@ -55,13 +57,13 @@ public sealed class TransmissionItem : ITorrentItem
public long SeedingTimeSeconds => _torrentInfo.SecondsSeeding ?? 0;
// Categories and tags
public string? Category => _torrentInfo.Labels?.FirstOrDefault();
public string? Category => _torrentInfo.GetCategory();
public IReadOnlyList<string> Tags => _torrentInfo.Labels?.ToList().AsReadOnly() ?? (IReadOnlyList<string>)Array.Empty<string>();
// State checking methods
// Transmission status: 0=stopped, 1=check pending, 2=checking, 3=download pending, 4=downloading, 5=seed pending, 6=seeding
public bool IsDownloading() => _torrentInfo.Status == 4;
public bool IsStalled() => _torrentInfo.Status == 4 && (_torrentInfo.RateDownload ?? 0) == 0 && (_torrentInfo.Eta ?? 0) == 0;
public bool IsStalled() => _torrentInfo is { Status: 4, RateDownload: <= 0, Eta: <= 0 };
public bool IsSeeding() => _torrentInfo.Status == 6;
public bool IsCompleted() => CompletionPercentage >= 100.0;
public bool IsPaused() => _torrentInfo.Status == 0;
@@ -78,10 +80,28 @@ public sealed class TransmissionItem : ITorrentItem
return false;
}
return ignoredDownloads.Any(pattern =>
Name.Contains(pattern, StringComparison.InvariantCultureIgnoreCase) ||
Hash.Equals(pattern, StringComparison.InvariantCultureIgnoreCase) ||
Trackers.Any(tracker => tracker.EndsWith(pattern, StringComparison.InvariantCultureIgnoreCase)));
foreach (string pattern in ignoredDownloads)
{
if (Hash?.Equals(pattern, StringComparison.InvariantCultureIgnoreCase) is true)
{
return true;
}
if (Category?.Equals(pattern, StringComparison.InvariantCultureIgnoreCase) is true)
{
return true;
}
bool? hasIgnoredTracker = _torrentInfo.Trackers?
.Any(x => UriService.GetDomain(x.Announce)?.EndsWith(pattern, StringComparison.InvariantCultureIgnoreCase) ?? false);
if (hasIgnoredTracker is true)
{
return true;
}
}
return false;
}
/// <summary>

View File

@@ -1,5 +1,6 @@
using Cleanuparr.Domain.Entities;
using Cleanuparr.Domain.Entities.UTorrent.Response;
using Cleanuparr.Infrastructure.Features.DownloadClient.UTorrent.Extensions;
namespace Cleanuparr.Infrastructure.Features.DownloadClient.UTorrent;
@@ -82,11 +83,26 @@ public sealed class UTorrentItemWrapper : ITorrentItem
{
return false;
}
foreach (string value in ignoredDownloads)
{
if (Hash.Equals(value, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
if (Category?.Equals(value, StringComparison.InvariantCultureIgnoreCase) is true)
{
return true;
}
return ignoredDownloads.Any(pattern =>
Name.Contains(pattern, StringComparison.InvariantCultureIgnoreCase) ||
Hash.Equals(pattern, StringComparison.InvariantCultureIgnoreCase) ||
Trackers.Any(tracker => tracker.EndsWith(pattern, StringComparison.InvariantCultureIgnoreCase)));
if (_torrentProperties.TrackerList.Any(x => x.ShouldIgnore(ignoredDownloads)))
{
return true;
}
}
return false;
}
/// <summary>

View File

@@ -22,7 +22,6 @@ public sealed class AppStatusRefreshService : BackgroundService
private static readonly Uri StatusUri = new("https://cleanuparr-status.pages.dev/status.json");
private static readonly TimeSpan PollInterval = TimeSpan.FromMinutes(10);
private static readonly TimeSpan StartupDelay = TimeSpan.FromSeconds(5);
private static readonly TimeSpan RequestTimeout = TimeSpan.FromSeconds(3);
public AppStatusRefreshService(
ILogger<AppStatusRefreshService> logger,
@@ -70,7 +69,6 @@ public sealed class AppStatusRefreshService : BackgroundService
try
{
using var client = _httpClientFactory.CreateClient(Constants.HttpClientWithRetryName);
client.Timeout = RequestTimeout;
using var response = await client.GetAsync(StatusUri, cancellationToken);
response.EnsureSuccessStatusCode();