added separate strikes for downloading metadata

This commit is contained in:
Flaminel
2025-03-24 15:10:45 +02:00
parent 5fe0f5750a
commit 82cc1ba560
9 changed files with 62 additions and 31 deletions
+3 -2
View File
@@ -183,15 +183,16 @@ services:
- QUEUECLEANER__ENABLED=true - QUEUECLEANER__ENABLED=true
- QUEUECLEANER__IGNORED_DOWNLOADS_PATH=/ignored.txt - QUEUECLEANER__IGNORED_DOWNLOADS_PATH=/ignored.txt
- QUEUECLEANER__RUNSEQUENTIALLY=true - QUEUECLEANER__RUNSEQUENTIALLY=true
- QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES=5 - QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES=3
- QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE=false - QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE=false
- QUEUECLEANER__IMPORT_FAILED_DELETE_PRIVATE=false - QUEUECLEANER__IMPORT_FAILED_DELETE_PRIVATE=false
# - QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__0=title mismatch # - QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__0=title mismatch
# - QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__1=manual import required # - QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__1=manual import required
- QUEUECLEANER__STALLED_MAX_STRIKES=5 - QUEUECLEANER__STALLED_MAX_STRIKES=3
- QUEUECLEANER__STALLED_RESET_STRIKES_ON_PROGRESS=false - QUEUECLEANER__STALLED_RESET_STRIKES_ON_PROGRESS=false
- QUEUECLEANER__STALLED_IGNORE_PRIVATE=false - QUEUECLEANER__STALLED_IGNORE_PRIVATE=false
- QUEUECLEANER__STALLED_DELETE_PRIVATE=false - QUEUECLEANER__STALLED_DELETE_PRIVATE=false
- QUEUECLEANER__DOWNLOADING_METADATA_MAX_STRIKES=3
- CONTENTBLOCKER__ENABLED=true - CONTENTBLOCKER__ENABLED=true
- CONTENTBLOCKER__IGNORED_DOWNLOADS_PATH=/ignored.txt - CONTENTBLOCKER__IGNORED_DOWNLOADS_PATH=/ignored.txt
@@ -24,7 +24,7 @@ public sealed record QueueCleanerConfig : IJobConfig, IIgnoredDownloadsConfig
public bool ImportFailedDeletePrivate { get; init; } public bool ImportFailedDeletePrivate { get; init; }
[ConfigurationKeyName("IMPORT_FAILED_IGNORE_PATTERNS")] [ConfigurationKeyName("IMPORT_FAILED_IGNORE_PATTERNS")]
public List<string>? ImportFailedIgnorePatterns { get; init; } public IReadOnlyList<string>? ImportFailedIgnorePatterns { get; init; }
[ConfigurationKeyName("STALLED_MAX_STRIKES")] [ConfigurationKeyName("STALLED_MAX_STRIKES")]
public ushort StalledMaxStrikes { get; init; } public ushort StalledMaxStrikes { get; init; }
@@ -38,16 +38,24 @@ public sealed record QueueCleanerConfig : IJobConfig, IIgnoredDownloadsConfig
[ConfigurationKeyName("STALLED_DELETE_PRIVATE")] [ConfigurationKeyName("STALLED_DELETE_PRIVATE")]
public bool StalledDeletePrivate { get; init; } public bool StalledDeletePrivate { get; init; }
[ConfigurationKeyName("DOWNLOADING_METADATA_MAX_STRIKES")]
public ushort DownloadingMetadataMaxStrikes { get; init; }
public void Validate() public void Validate()
{ {
if (ImportFailedMaxStrikes is > 0 and < 3) if (ImportFailedMaxStrikes is > 0 and < 3)
{ {
throw new ValidationException("the minimum value for IMPORT_FAILED_MAX_STRIKES must be 3"); throw new ValidationException($"the minimum value for {SectionName.ToUpperInvariant()}__IMPORT_FAILED_MAX_STRIKES must be 3");
} }
if (StalledMaxStrikes is > 0 and < 3) if (StalledMaxStrikes is > 0 and < 3)
{ {
throw new ValidationException("the minimum value for STALLED_MAX_STRIKES must be 3"); throw new ValidationException($"the minimum value for {SectionName.ToUpperInvariant()}__STALLED_MAX_STRIKES must be 3");
}
if (DownloadingMetadataMaxStrikes is > 0 and < 3)
{
throw new ValidationException($"the minimum value for {SectionName.ToUpperInvariant()}__DOWNLOADING_METADATA_MAX_STRIKES must be 3");
} }
} }
} }
+1 -1
View File
@@ -1,4 +1,4 @@
namespace Domain.Enums; namespace Domain.Enums;
public enum DeleteReason public enum DeleteReason
{ {
+4 -3
View File
@@ -25,16 +25,17 @@
"Enabled": true, "Enabled": true,
"RunSequentially": true, "RunSequentially": true,
"IGNORED_DOWNLOADS_PATH": "../test/data/cleanuperr/ignored_downloads", "IGNORED_DOWNLOADS_PATH": "../test/data/cleanuperr/ignored_downloads",
"IMPORT_FAILED_MAX_STRIKES": 5, "IMPORT_FAILED_MAX_STRIKES": 3,
"IMPORT_FAILED_IGNORE_PRIVATE": true, "IMPORT_FAILED_IGNORE_PRIVATE": true,
"IMPORT_FAILED_DELETE_PRIVATE": false, "IMPORT_FAILED_DELETE_PRIVATE": false,
"IMPORT_FAILED_IGNORE_PATTERNS": [ "IMPORT_FAILED_IGNORE_PATTERNS": [
"file is a sample" "file is a sample"
], ],
"STALLED_MAX_STRIKES": 5, "STALLED_MAX_STRIKES": 3,
"STALLED_RESET_STRIKES_ON_PROGRESS": true, "STALLED_RESET_STRIKES_ON_PROGRESS": true,
"STALLED_IGNORE_PRIVATE": true, "STALLED_IGNORE_PRIVATE": true,
"STALLED_DELETE_PRIVATE": false "STALLED_DELETE_PRIVATE": false,
"DOWNLOADING_METADATA_MAX_STRIKES": 3
}, },
"DownloadCleaner": { "DownloadCleaner": {
"Enabled": false, "Enabled": false,
+2 -1
View File
@@ -31,7 +31,8 @@
"STALLED_MAX_STRIKES": 0, "STALLED_MAX_STRIKES": 0,
"STALLED_RESET_STRIKES_ON_PROGRESS": false, "STALLED_RESET_STRIKES_ON_PROGRESS": false,
"STALLED_IGNORE_PRIVATE": false, "STALLED_IGNORE_PRIVATE": false,
"STALLED_DELETE_PRIVATE": false "STALLED_DELETE_PRIVATE": false,
"DOWNLOADING_METADATA_MAX_STRIKES": 0
}, },
"DownloadCleaner": { "DownloadCleaner": {
"Enabled": false, "Enabled": false,
@@ -335,35 +335,41 @@ public class QBitService : DownloadService, IQBitService
private async Task<(bool, DeleteReason)> IsItemStuckAndShouldRemove(TorrentInfo torrent, bool isPrivate) private async Task<(bool, DeleteReason)> IsItemStuckAndShouldRemove(TorrentInfo torrent, bool isPrivate)
{ {
if (_queueCleanerConfig.StalledMaxStrikes is 0) if (_queueCleanerConfig.StalledMaxStrikes is 0 && _queueCleanerConfig.DownloadingMetadataMaxStrikes is 0)
{ {
return (false, default); return (false, DeleteReason.None);
}
if (_queueCleanerConfig.StalledIgnorePrivate && isPrivate)
{
// ignore private trackers
_logger.LogDebug("skip stalled check | download is private | {name}", torrent.Name);
return (false, default);
} }
if (torrent.State is not TorrentState.StalledDownload and not TorrentState.FetchingMetadata if (torrent.State is not TorrentState.StalledDownload and not TorrentState.FetchingMetadata
and not TorrentState.ForcedFetchingMetadata) and not TorrentState.ForcedFetchingMetadata)
{ {
// ignore other states // ignore other states
return (false, default); return (false, DeleteReason.None);
} }
if (_queueCleanerConfig.StalledMaxStrikes > 0 && torrent.State is TorrentState.StalledDownload)
{
if (_queueCleanerConfig.StalledIgnorePrivate && isPrivate)
{
// ignore private trackers
_logger.LogDebug("skip stalled check | download is private | {name}", torrent.Name);
}
else
{
ResetStrikesOnProgress(torrent.Hash, torrent.Downloaded ?? 0); ResetStrikesOnProgress(torrent.Hash, torrent.Downloaded ?? 0);
if (torrent.State is TorrentState.StalledDownload)
{
return (await StrikeAndCheckLimit(torrent.Hash, torrent.Name, StrikeType.Stalled), DeleteReason.Stalled); return (await StrikeAndCheckLimit(torrent.Hash, torrent.Name, StrikeType.Stalled), DeleteReason.Stalled);
} }
}
if (_queueCleanerConfig.DownloadingMetadataMaxStrikes > 0)
{
return (await StrikeAndCheckLimit(torrent.Hash, torrent.Name, StrikeType.DownloadingMetadata), DeleteReason.DownloadingMetadata); return (await StrikeAndCheckLimit(torrent.Hash, torrent.Name, StrikeType.DownloadingMetadata), DeleteReason.DownloadingMetadata);
} }
return (false, DeleteReason.None);
}
private async Task<IReadOnlyList<TorrentTracker>> GetTrackersAsync(string hash) private async Task<IReadOnlyList<TorrentTracker>> GetTrackersAsync(string hash)
{ {
return (await _client.GetTorrentTrackersAsync(hash)) return (await _client.GetTorrentTrackersAsync(hash))
@@ -119,9 +119,9 @@ public sealed class QueueCleaner : GenericHandler
bool removeFromClient = true; bool removeFromClient = true;
if (stalledCheckResult.IsPrivate) if (stalledCheckResult is { IsPrivate: true, DeleteReason: not DeleteReason.DownloadingMetadata })
{ {
if (stalledCheckResult.ShouldRemove && !_config.StalledDeletePrivate) if (stalledCheckResult is { ShouldRemove: true, DeleteReason: DeleteReason.Stalled } && !_config.StalledDeletePrivate)
{ {
removeFromClient = false; removeFromClient = false;
} }
+3 -2
View File
@@ -193,13 +193,14 @@ services:
- QUEUECLEANER__ENABLED=true - QUEUECLEANER__ENABLED=true
- QUEUECLEANER__IGNORED_DOWNLOADS_PATH=/ignored - QUEUECLEANER__IGNORED_DOWNLOADS_PATH=/ignored
- QUEUECLEANER__RUNSEQUENTIALLY=true - QUEUECLEANER__RUNSEQUENTIALLY=true
- QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES=5 - QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES=3
- QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE=true - QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE=true
- QUEUECLEANER__IMPORT_FAILED_DELETE_PRIVATE=false - QUEUECLEANER__IMPORT_FAILED_DELETE_PRIVATE=false
- QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__0=file is a sample - QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__0=file is a sample
- QUEUECLEANER__STALLED_MAX_STRIKES=5 - QUEUECLEANER__STALLED_MAX_STRIKES=3
- QUEUECLEANER__STALLED_IGNORE_PRIVATE=true - QUEUECLEANER__STALLED_IGNORE_PRIVATE=true
- QUEUECLEANER__STALLED_DELETE_PRIVATE=false - QUEUECLEANER__STALLED_DELETE_PRIVATE=false
- QUEUECLEANER__DOWNLOADING_METADATA_MAX_STRIKES=3
- CONTENTBLOCKER__ENABLED=true - CONTENTBLOCKER__ENABLED=true
- CONTENTBLOCKER__IGNORED_DOWNLOADS_PATH=/ignored - CONTENTBLOCKER__IGNORED_DOWNLOADS_PATH=/ignored
+15 -2
View File
@@ -152,7 +152,7 @@
#### **`QUEUECLEANER__STALLED_MAX_STRIKES`** #### **`QUEUECLEANER__STALLED_MAX_STRIKES`**
- Number of strikes before removing a stalled download. - Number of strikes before removing a stalled download.
- Set to `0` to never remove stalled downloads. - Set to `0` to never remove stalled downloads.
- A strike is given when an item is stalled (not downloading) or stuck while downloading metadata. - A strike is given when an item is stalled (not downloading).
- Type: Integer - Type: Integer
- Default: `0` - Default: `0`
- Required: No. - Required: No.
@@ -184,6 +184,19 @@
> [!WARNING] > [!WARNING]
> Setting `QUEUECLEANER__STALLED_DELETE_PRIVATE=true` means you don't care about seeding, ratio, H&R and potentially losing your private tracker account. > Setting `QUEUECLEANER__STALLED_DELETE_PRIVATE=true` means you don't care about seeding, ratio, H&R and potentially losing your private tracker account.
#### **`QUEUECLEANER__DOWNLOADING_METADATA_MAX_STRIKES`**
- Number of strikes before removing a download stuck while downloading metadata.
- Set to `0` to never remove downloads stuck at `downloading metadata`.
- A strike is given when an item is stuck while downloading metadata.
- Type: Integer
- Default: `0`
- Required: No.
> [!NOTE]
> If not set to `0`, the minimum value is `3`.
> [!IMPORTANT]
> `QUEUECLEANER__DOWNLOADING_METADATA_MAX_STRIKES` works only for qBitTorrent.
# #
### Content Blocker settings ### Content Blocker settings
@@ -317,7 +330,7 @@
> >
> For Deluge, the category name is the name of the label. > For Deluge, the category name is the name of the label.
> >
> For Transmission, the category name is the last directory from the save location. > For Transmission, the category name is the last directory from the save location (e.g. `myCategory` from `/downloads/path/myCategory`).
#### **`DOWNLOADCLEANER__CATEGORIES__0__MAX_RATIO`** #### **`DOWNLOADCLEANER__CATEGORIES__0__MAX_RATIO`**
- Maximum ratio to reach before removing a download. - Maximum ratio to reach before removing a download.