Compare commits

...

4 Commits

Author SHA1 Message Date
Flaminel
569eeae181 Fix hardlinks on ARM64 (#130) 2025-05-07 21:44:49 +03:00
Flaminel
5a0ef56074 Remove empty clean categories list validation (#131) 2025-05-07 14:12:36 +03:00
Flaminel
09bd4321fb fixed readme icons 2025-05-06 19:59:00 +03:00
Flaminel
4939e37210 updated discord invite 2025-05-06 15:57:12 +03:00
9 changed files with 50 additions and 21 deletions

View File

@@ -4,9 +4,11 @@ on:
jobs:
build:
uses: flmorg/universal-workflows/.github/workflows/dotnet.build.app.yml@main
uses: flmorg/universal-workflows-testing/.github/workflows/dotnet.build.app.yml@main
with:
dockerRepository: flaminel/cleanuperr
githubContext: ${{ toJSON(github) }}
outputName: cleanuperr
selfContained: false
baseImage: 9.0-bookworm-slim
secrets: inherit

View File

@@ -2,7 +2,7 @@ _Love this project? Give it a ⭐️ and let others know!_
# <img width="24px" src="./Logo/256.png" alt="cleanuperr"></img> Cleanuperr
[![Discord](https://img.shields.io/discord/1306721212587573389?color=7289DA&label=Discord&style=for-the-badge&logo=discord)](https://discord.gg/sWggpnmGNY)
[![Discord](https://img.shields.io/discord/1306721212587573389?color=7289DA&label=Discord&style=for-the-badge&logo=discord)](https://discord.gg/SCtMCgtsc4)
Cleanuperr is a tool for automating the cleanup of unwanted or blocked files in Sonarr, Radarr, and supported download clients like qBittorrent. It removes incomplete or blocked downloads, updates queues, and enforces blacklists or whitelists to manage file selection. After removing blocked content, Cleanuperr can also trigger a search to replace the deleted shows/movies.
@@ -38,13 +38,13 @@ Cleanuperr supports both qBittorrent's built-in exclusion features and its own b
Docs can be found [here](https://flmorg.github.io/cleanuperr/).
# <img width="24px" src="./Logo/256.png" alt="Cleanuperr"> Cleanuperr <svg width="14px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M376.6 84.5c11.3-13.6 9.5-33.8-4.1-45.1s-33.8-9.5-45.1 4.1L192 206 56.6 43.5C45.3 29.9 25.1 28.1 11.5 39.4S-3.9 70.9 7.4 84.5L150.3 256 7.4 427.5c-11.3 13.6-9.5 33.8 4.1 45.1s33.8 9.5 45.1-4.1L192 306 327.4 468.5c11.3 13.6 31.5 15.4 45.1 4.1s15.4-31.5 4.1-45.1L233.7 256 376.6 84.5z"/></svg> Huntarr <img width="24px" src="https://github.com/plexguide/Huntarr.io/blob/main/frontend/static/logo/256.png?raw=true" alt Huntarr></img>
# <img style="vertical-align: middle;" width="24px" src="./Logo/256.png" alt="Cleanuperr"> <span style="vertical-align: middle;">Cleanuperr</span> <img src="https://raw.githubusercontent.com/FortAwesome/Font-Awesome/6.x/svgs/solid/x.svg" height="24px" width="30px" style="vertical-align: middle;"> <span style="vertical-align: middle;">Huntarr</span> <img style="vertical-align: middle;" width="24px" src="https://github.com/plexguide/Huntarr.io/blob/main/frontend/static/logo/512.png?raw=true" alt Huntarr></img>
Think of **Cleanuperr** as the janitor of your server; it keeps your download queue spotless, removes clutter, and blocks malicious files. Now imagine combining that with **Huntarr**, the compulsive librarian who finds missing and upgradable media to complete your collection
While **Huntarr** fills in the blanks and improves what you already have, **Cleanuperr** makes sure that only clean downloads get through. If you're aiming for a reliable and self-sufficient setup, **Cleanuperr** and **Huntarr** will take your automated media stack to another level.
<span style="font-size:24px"> ➡️ [**Huntarr**](https://github.com/plexguide/Huntarr.io) ![Huntarr](https://img.shields.io/github/stars/plexguide/Huntarr.io?style=social)</span>
<span style="font-size:24px"> ➡️ [**Huntarr**](https://github.com/plexguide/Huntarr.io) <span style="vertical-align: middle">![Huntarr](https://img.shields.io/github/stars/plexguide/Huntarr.io?style=social)</span></span>
# Credits
Special thanks for inspiration go to:

View File

@@ -33,11 +33,6 @@ public sealed record DownloadCleanerConfig : IJobConfig, IIgnoredDownloadsConfig
return;
}
if (Categories?.Count is null or 0)
{
throw new ValidationException("no categories configured");
}
if (Categories?.GroupBy(x => x.Name).Any(x => x.Count() > 1) is true)
{
throw new ValidationException("duplicated clean categories found");

View File

@@ -18,7 +18,7 @@
<PackageReference Include="MassTransit" Version="8.3.6" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.2" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.2" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="Mono.Unix" Version="7.1.0-final.1.21458.1" />
<PackageReference Include="Quartz" Version="3.13.1" />
<PackageReference Include="Scrutor" Version="6.0.1" />
</ItemGroup>

View File

@@ -58,9 +58,12 @@ public sealed class DownloadCleaner : GenericHandler
return;
}
if (_config.Categories?.Count is null or 0)
bool isUnlinkedEnabled = !string.IsNullOrEmpty(_config.UnlinkedTargetCategory) && _config.UnlinkedCategories?.Count > 0;
bool isCleaningEnabled = _config.Categories?.Count > 0;
if (!isUnlinkedEnabled && !isCleaningEnabled)
{
_logger.LogWarning("no categories configured");
_logger.LogWarning("{name} is not configured properly", nameof(DownloadCleaner));
return;
}
@@ -68,9 +71,18 @@ public sealed class DownloadCleaner : GenericHandler
await _downloadService.LoginAsync();
List<object>? downloads = await _downloadService.GetSeedingDownloads();
List<object>? downloadsToChangeCategory = null;
if (downloads?.Count is null or 0)
{
_logger.LogDebug("no seeding downloads found");
return;
}
if (!string.IsNullOrEmpty(_config.UnlinkedTargetCategory) && _config.UnlinkedCategories?.Count > 0)
_logger.LogTrace("found {count} seeding downloads", downloads.Count);
List<object>? downloadsToChangeCategory = null;
if (isUnlinkedEnabled)
{
if (!_hardLinkCategoryCreated)
{
@@ -89,17 +101,27 @@ public sealed class DownloadCleaner : GenericHandler
await ProcessArrConfigAsync(_sonarrConfig, InstanceType.Sonarr, true);
await ProcessArrConfigAsync(_radarrConfig, InstanceType.Radarr, true);
await ProcessArrConfigAsync(_lidarrConfig, InstanceType.Lidarr, true);
if (isUnlinkedEnabled)
{
_logger.LogTrace("found {count} potential downloads to change category", downloadsToChangeCategory?.Count);
await _downloadService.ChangeCategoryForNoHardLinksAsync(downloadsToChangeCategory, _excludedHashes, ignoredDownloads);
_logger.LogTrace("finished changing category");
}
_logger.LogTrace("looking for downloads to change category");
await _downloadService.ChangeCategoryForNoHardLinksAsync(downloadsToChangeCategory, _excludedHashes, ignoredDownloads);
if (_config.Categories?.Count is null or 0)
{
return;
}
List<object>? downloadsToClean = _downloadService.FilterDownloadsToBeCleanedAsync(downloads, _config.Categories);
// release unused objects
downloads = null;
_logger.LogTrace("looking for downloads to clean");
_logger.LogTrace("found {count} potential downloads to clean", downloadsToClean?.Count);
await _downloadService.CleanDownloadsAsync(downloadsToClean, _config.Categories, _excludedHashes, ignoredDownloads);
_logger.LogTrace("finished cleaning downloads");
}
protected override async Task ProcessInstanceAsync(ArrInstance instance, InstanceType instanceType)

View File

@@ -13,7 +13,7 @@ Cleanuperr was created primarily to address malicious files, such as `*.lnk` or
<Warning>
Because this tool is actively developed and still a work in progress, using the `latest` Docker tag may result in breaking changes.
Join the Discord server if you want to reach out to me quickly (or just stay updated on new releases) so we can squash those pesky bugs together: https://discord.gg/sWggpnmGNY
Join the Discord server if you want to reach out to me quickly (or just stay updated on new releases) so we can squash those pesky bugs together: https://discord.gg/SCtMCgtsc4
</Warning>

View File

@@ -12,8 +12,12 @@ services:
image: ghcr.io/flmorg/cleanuperr:latest
restart: unless-stopped
volumes:
# if you want persistent logs
- ./cleanuperr/logs:/var/logs
# if you want to ignore certain downloads from being processed
- ./cleanuperr/ignored.txt:/ignored.txt
# if you're using cross-seed and the hardlinks functionality
- ./downloads:/downloads
environment:
# general settings
- TZ=America/New_York

View File

@@ -61,7 +61,7 @@ const config: Config = {
position: 'right',
},
{
href: 'https://discord.gg/sWggpnmGNY',
href: 'https://discord.gg/SCtMCgtsc4',
label: 'Discord',
position: 'right',
}

View File

@@ -30,11 +30,17 @@ const settings: EnvVarProps[] = [
title: "Multiple patterns can be specified using incrementing numbers starting from 0.",
content: `DOWNLOADCLEANER__UNLINKED_CATEGORIES__0=tv-sonarr
DOWNLOADCLEANER__UNLINKED_CATEGORIES__1=radarr`
}
},
],
type: "text",
defaultValue: "Empty",
required: false,
notes: [
"The category name must match the category that was set in the *arr.",
"For qBittorrent, the category name is the name of the download category.",
"For Deluge, the category name is the name of the label.",
"For Transmission, the category name is the last directory from the save location.",
],
}
];