Compare commits

..

6 Commits

Author SHA1 Message Date
Flaminel
f8f438d3e7 added torrent pausing back 2025-10-04 21:48:53 +03:00
Flaminel
3916843cee removed concurrency for queue removal; removed torrent pausing 2025-09-21 23:37:11 +03:00
Flaminel
4175a8b69b added download pausing for Deluge before queue removal 2025-09-21 23:07:20 +03:00
Flaminel
4593a13e74 Revert "added a 5s delay between queue item removals"
This reverts commit f5335feca7.
2025-09-21 21:30:16 +03:00
Flaminel
f5335feca7 added a 5s delay between queue item removals 2025-09-17 12:27:31 +03:00
Flaminel
911849c6dd Fix blacklist synchronizer docs (#307) 2025-09-16 23:30:38 +03:00
9 changed files with 108 additions and 57 deletions

View File

@@ -55,8 +55,8 @@ public static class MainDI
{
e.ConfigureConsumer<DownloadRemoverConsumer<SearchItem>>(context);
e.ConfigureConsumer<DownloadRemoverConsumer<SeriesSearchItem>>(context);
e.ConcurrentMessageLimit = 2;
e.PrefetchCount = 2;
e.ConcurrentMessageLimit = 1;
e.PrefetchCount = 1;
});
cfg.ReceiveEndpoint("download-hunter-queue", e =>

View File

@@ -5,6 +5,7 @@ using Cleanuparr.Infrastructure.Features.Arr;
using Cleanuparr.Infrastructure.Features.Arr.Interfaces;
using Cleanuparr.Infrastructure.Features.Context;
using Cleanuparr.Infrastructure.Features.DownloadClient;
using Cleanuparr.Infrastructure.Features.DownloadClient.Deluge;
using Cleanuparr.Infrastructure.Features.Jobs;
using Cleanuparr.Infrastructure.Features.MalwareBlocker;
using Cleanuparr.Infrastructure.Helpers;
@@ -147,35 +148,37 @@ public sealed class MalwareBlocker : GenericHandler
ContextProvider.Set(nameof(QueueRecord), record);
BlockFilesResult result = new();
IDownloadService? downloadService = null;
if (record.Protocol is "torrent")
{
var torrentClients = downloadServices
var torrentServices = downloadServices
.Where(x => x.ClientConfig.Type is DownloadClientType.Torrent)
.ToList();
_logger.LogDebug("searching unwanted files for {title}", record.Title);
if (torrentClients.Count > 0)
if (torrentServices.Count > 0)
{
// Check each download client for the download item
foreach (var downloadService in torrentClients)
foreach (var torrentService in torrentServices)
{
try
{
// stalled download check
result = await downloadService
result = await torrentService
.BlockUnwantedFilesAsync(record.DownloadId, ignoredDownloads);
if (result.Found)
{
downloadService = torrentService;
break;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error checking download {dName} with download client {cName}",
record.Title, downloadService.ClientConfig.Name);
record.Title, torrentService.ClientConfig.Name);
}
}
@@ -204,6 +207,11 @@ public sealed class MalwareBlocker : GenericHandler
removeFromClient = false;
}
if (downloadService is DelugeService delugeService)
{
await delugeService.PauseAsync(record.DownloadId);
}
await PublishQueueItemRemoveRequest(
downloadRemovalKey,
instanceType,

View File

@@ -5,6 +5,7 @@ using Cleanuparr.Infrastructure.Features.Arr;
using Cleanuparr.Infrastructure.Features.Arr.Interfaces;
using Cleanuparr.Infrastructure.Features.Context;
using Cleanuparr.Infrastructure.Features.DownloadClient;
using Cleanuparr.Infrastructure.Features.DownloadClient.Deluge;
using Cleanuparr.Infrastructure.Features.Jobs;
using Cleanuparr.Infrastructure.Helpers;
using Cleanuparr.Persistence;
@@ -107,33 +108,35 @@ public sealed class QueueCleaner : GenericHandler
ContextProvider.Set(nameof(QueueRecord), record);
DownloadCheckResult downloadCheckResult = new();
IDownloadService? downloadService = null;
if (record.Protocol.Contains("torrent", StringComparison.InvariantCultureIgnoreCase))
{
var torrentClients = downloadServices
var torrentServices = downloadServices
.Where(x => x.ClientConfig.Type is DownloadClientType.Torrent)
.ToList();
if (torrentClients.Count > 0)
if (torrentServices.Count > 0)
{
// Check each download client for the download item
foreach (var downloadService in torrentClients)
foreach (var torrentService in torrentServices)
{
try
{
// stalled download check
downloadCheckResult = await downloadService
downloadCheckResult = await torrentService
.ShouldRemoveFromArrQueueAsync(record.DownloadId, ignoredDownloads);
if (downloadCheckResult.Found)
{
downloadService = torrentService;
break;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error checking download {dName} with download client {cName}",
record.Title, downloadService.ClientConfig.Name);
record.Title, torrentService.ClientConfig.Name);
}
}
@@ -183,6 +186,11 @@ public sealed class QueueCleaner : GenericHandler
}
}
if (downloadService is DelugeService delugeService)
{
await delugeService.PauseAsync(record.DownloadId);
}
await PublishQueueItemRemoveRequest(
downloadRemovalKey,
instanceType,

View File

@@ -236,4 +236,9 @@ public sealed class DelugeClient
{
await SendRequest<DelugeResponse<object>>("label.set_torrent", hash, newLabel);
}
public async Task PauseAsync(string hash)
{
await SendRequest<DelugeResponse<object>>("core.pause_torrent", hash);
}
}

View File

@@ -55,6 +55,15 @@ public partial class DelugeService : DownloadService, IDelugeService
throw;
}
}
public async Task PauseAsync(string hash)
{
hash = hash.ToLowerInvariant();
_logger.LogDebug("Pausing torrent {hash} in Deluge client {name}", hash, _downloadClientConfig.Name);
await _client.PauseAsync(hash);
}
public override async Task<HealthCheckResult> HealthCheckAsync()
{

View File

@@ -60,6 +60,8 @@ public sealed class QueueItemRemover : IQueueItemRemover
SearchItem = request.SearchItem,
Record = request.Record
});
await Task.Delay(30 * 1000);
}
catch (HttpRequestException exception)
{

View File

@@ -21,7 +21,7 @@
<div class="flex align-items-center justify-content-between p-3 border-bottom-1 surface-border">
<div class="header-title-container">
<h2 class="card-title m-0">Blacklist Sync Configuration</h2>
<span class="card-subtitle">Configure automatic blacklist synchronization</span>
<span class="card-subtitle">Configure automatic blacklist synchronization for qBittorrent clients</span>
</div>
</div>
</ng-template>
@@ -38,7 +38,7 @@
</label>
<div class="field-input">
<p-checkbox formControlName="enabled" [binary]="true" inputId="blacklistSyncEnabled"></p-checkbox>
<small class="form-helper-text">When enabled, blacklist patterns will be synchronized to download clients hourly</small>
<small class="form-helper-text">When enabled, blacklist patterns will be synchronized to enabled qBittorrent clients hourly</small>
</div>
</div>

View File

@@ -0,0 +1,62 @@
---
sidebar_position: 5
---
import { Note, Warning } from '@site/src/components/Admonition';
import {
ConfigSection,
EnhancedNote,
EnhancedWarning,
styles
} from '@site/src/components/documentation';
# Blacklist Synchronizer
The Blacklist Synchronizer automatically synchronizes blacklist entries to all enabled qBittorrent clients every hour. This helps maintain consistent content filtering across your download clients.
<div className={styles.documentationPage}>
<div className={styles.section}>
<h2 className={styles.sectionTitle}>
<span className={styles.sectionIcon}>⛔</span>
Blacklist Sync
</h2>
<ConfigSection
id="enable-blacklist-sync"
title="Enable Blacklist Sync"
icon="✅"
>
When enabled, Cleanuparr will automatically synchronize blacklist entries to all enabled qBittorrent clients every hour. The sync happens when the blacklist path or content changes.
<EnhancedNote>
This feature updates the qBittorrent "Excluded file names" setting, but does not enable it.
</EnhancedNote>
</ConfigSection>
<ConfigSection
id="blacklist-path"
title="Blacklist Path"
icon="🗂️"
>
Path to the blacklist content. This can be a local file path or an HTTP/HTTPS URL. The application computes a content hash and only pushes updates when the content changes.
**Examples:**
```
/data/blacklists/qbit-exclusions.txt
https://example.com/blacklist.txt
```
<EnhancedWarning>
If Blacklist Sync is enabled, this field is required. For remote URLs, ensure the server is reachable from Cleanuparr and the certificate is valid (or adjust HTTP certificate validation settings).
</EnhancedWarning>
</ConfigSection>
</div>
</div>

View File

@@ -157,49 +157,6 @@ mytracker.com
</div>
<div className={styles.section}>
<h2 className={styles.sectionTitle}>
<span className={styles.sectionIcon}>⛔</span>
Blacklist Sync
</h2>
<ConfigSection
id="enable-blacklist-sync"
title="Enable Blacklist Sync"
icon="✅"
>
When enabled, Cleanuparr will automatically synchronize blacklist entries to all enabled qBittorrent clients every hour. The sync happens when the blacklist path or content changes.
<EnhancedNote>
This feature updates the qBittorrent "Excluded file names" setting, but does not enable it.
</EnhancedNote>
</ConfigSection>
<ConfigSection
id="blacklist-path"
title="Blacklist Path"
icon="🗂️"
>
Path to the blacklist content. This can be a local file path or an HTTP/HTTPS URL. The application computes a content hash and only pushes updates when the content changes.
**Examples:**
```
/data/blacklists/qbit-exclusions.txt
https://example.com/blacklist.txt
```
<EnhancedWarning>
If Blacklist Sync is enabled, this field is required. For remote URLs, ensure the server is reachable from Cleanuparr and the certificate is valid (or adjust HTTP certificate validation settings).
</EnhancedWarning>
</ConfigSection>
</div>
</div>
<div className={styles.section}>