added separate strikes for downloading metadata
This commit is contained in:
@@ -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,4 +1,4 @@
|
|||||||
namespace Domain.Enums;
|
namespace Domain.Enums;
|
||||||
|
|
||||||
public enum DeleteReason
|
public enum DeleteReason
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user