mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2025-12-23 22:18:39 -05:00
Add option for multiple ignored root directories (#390)
This commit is contained in:
@@ -44,8 +44,8 @@ public static class ServicesDI
|
||||
.AddScoped<IDownloadHunter, DownloadHunter>()
|
||||
.AddScoped<IFilenameEvaluator, FilenameEvaluator>()
|
||||
.AddScoped<IHardLinkFileService, HardLinkFileService>()
|
||||
.AddScoped<UnixHardLinkFileService>()
|
||||
.AddScoped<WindowsHardLinkFileService>()
|
||||
.AddScoped<IUnixHardLinkFileService, UnixHardLinkFileService>()
|
||||
.AddScoped<IWindowsHardLinkFileService, WindowsHardLinkFileService>()
|
||||
.AddScoped<IArrQueueIterator, ArrQueueIterator>()
|
||||
.AddScoped<IDownloadServiceFactory, DownloadServiceFactory>()
|
||||
.AddScoped<IStriker, Striker>()
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed record UpdateDownloadCleanerConfigRequest
|
||||
|
||||
public bool UnlinkedUseTag { get; init; }
|
||||
|
||||
public string UnlinkedIgnoredRootDir { get; init; } = string.Empty;
|
||||
public List<string> UnlinkedIgnoredRootDirs { get; init; } = [];
|
||||
|
||||
public List<string> UnlinkedCategories { get; init; } = [];
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ public sealed class DownloadCleanerConfigController : ControllerBase
|
||||
oldConfig.UnlinkedEnabled = newConfigDto.UnlinkedEnabled;
|
||||
oldConfig.UnlinkedTargetCategory = newConfigDto.UnlinkedTargetCategory;
|
||||
oldConfig.UnlinkedUseTag = newConfigDto.UnlinkedUseTag;
|
||||
oldConfig.UnlinkedIgnoredRootDir = newConfigDto.UnlinkedIgnoredRootDir;
|
||||
oldConfig.UnlinkedIgnoredRootDirs = newConfigDto.UnlinkedIgnoredRootDirs;
|
||||
oldConfig.UnlinkedCategories = newConfigDto.UnlinkedCategories;
|
||||
oldConfig.IgnoredDownloads = newConfigDto.IgnoredDownloads;
|
||||
oldConfig.Categories.Clear();
|
||||
|
||||
@@ -716,7 +716,7 @@ public class DelugeServiceDCTests : IClassFixture<DelugeServiceFixture>
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
UnlinkedTargetCategory = "unlinked",
|
||||
UnlinkedIgnoredRootDir = "/ignore"
|
||||
UnlinkedIgnoredRootDirs = ["/ignore"]
|
||||
};
|
||||
ContextProvider.Set(nameof(DownloadCleanerConfig), config);
|
||||
|
||||
@@ -744,7 +744,7 @@ public class DelugeServiceDCTests : IClassFixture<DelugeServiceFixture>
|
||||
|
||||
// Assert
|
||||
_fixture.HardLinkFileService.Verify(
|
||||
x => x.PopulateFileCounts("/ignore"),
|
||||
x => x.PopulateFileCounts(It.Is<IEnumerable<string>>(dirs => dirs.Contains("/ignore"))),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
|
||||
@@ -900,7 +900,7 @@ public class QBitServiceDCTests : IClassFixture<QBitServiceFixture>
|
||||
Id = Guid.NewGuid(),
|
||||
UnlinkedUseTag = false,
|
||||
UnlinkedTargetCategory = "unlinked",
|
||||
UnlinkedIgnoredRootDir = "/ignore"
|
||||
UnlinkedIgnoredRootDirs = ["/ignore"]
|
||||
};
|
||||
ContextProvider.Set(nameof(DownloadCleanerConfig), config);
|
||||
|
||||
@@ -925,7 +925,7 @@ public class QBitServiceDCTests : IClassFixture<QBitServiceFixture>
|
||||
|
||||
// Assert
|
||||
_fixture.HardLinkFileService.Verify(
|
||||
x => x.PopulateFileCounts("/ignore"),
|
||||
x => x.PopulateFileCounts(It.Is<IEnumerable<string>>(dirs => dirs.Contains("/ignore"))),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
|
||||
@@ -787,7 +787,7 @@ public class TransmissionServiceDCTests : IClassFixture<TransmissionServiceFixtu
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
UnlinkedTargetCategory = "unlinked",
|
||||
UnlinkedIgnoredRootDir = "/ignore"
|
||||
UnlinkedIgnoredRootDirs = ["/ignore"]
|
||||
};
|
||||
ContextProvider.Set(nameof(DownloadCleanerConfig), config);
|
||||
|
||||
@@ -813,7 +813,7 @@ public class TransmissionServiceDCTests : IClassFixture<TransmissionServiceFixtu
|
||||
|
||||
// Assert
|
||||
_fixture.HardLinkFileService.Verify(
|
||||
x => x.PopulateFileCounts("/ignore"),
|
||||
x => x.PopulateFileCounts(It.Is<IEnumerable<string>>(dirs => dirs.Contains("/ignore"))),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
|
||||
@@ -639,7 +639,7 @@ public class UTorrentServiceDCTests : IClassFixture<UTorrentServiceFixture>
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
UnlinkedTargetCategory = "unlinked",
|
||||
UnlinkedIgnoredRootDir = "/ignore"
|
||||
UnlinkedIgnoredRootDirs = ["/ignore"]
|
||||
};
|
||||
ContextProvider.Set(nameof(DownloadCleanerConfig), config);
|
||||
|
||||
@@ -666,7 +666,7 @@ public class UTorrentServiceDCTests : IClassFixture<UTorrentServiceFixture>
|
||||
|
||||
// Assert
|
||||
_fixture.HardLinkFileService.Verify(
|
||||
x => x.PopulateFileCounts("/ignore"),
|
||||
x => x.PopulateFileCounts(It.Is<IEnumerable<string>>(dirs => dirs.Contains("/ignore"))),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,9 +65,9 @@ public partial class DelugeService
|
||||
|
||||
var downloadCleanerConfig = ContextProvider.Get<DownloadCleanerConfig>(nameof(DownloadCleanerConfig));
|
||||
|
||||
if (!string.IsNullOrEmpty(downloadCleanerConfig.UnlinkedIgnoredRootDir))
|
||||
if (downloadCleanerConfig.UnlinkedIgnoredRootDirs.Count > 0)
|
||||
{
|
||||
_hardLinkFileService.PopulateFileCounts(downloadCleanerConfig.UnlinkedIgnoredRootDir);
|
||||
_hardLinkFileService.PopulateFileCounts(downloadCleanerConfig.UnlinkedIgnoredRootDirs);
|
||||
}
|
||||
|
||||
foreach (DelugeItemWrapper torrent in downloads.Cast<DelugeItemWrapper>())
|
||||
@@ -105,7 +105,7 @@ public partial class DelugeService
|
||||
}
|
||||
|
||||
long hardlinkCount = _hardLinkFileService
|
||||
.GetHardLinkCount(filePath, !string.IsNullOrEmpty(downloadCleanerConfig.UnlinkedIgnoredRootDir));
|
||||
.GetHardLinkCount(filePath, downloadCleanerConfig.UnlinkedIgnoredRootDirs.Count > 0);
|
||||
|
||||
if (hardlinkCount < 0)
|
||||
{
|
||||
|
||||
@@ -89,9 +89,9 @@ public partial class QBitService
|
||||
|
||||
var downloadCleanerConfig = ContextProvider.Get<DownloadCleanerConfig>(nameof(DownloadCleanerConfig));
|
||||
|
||||
if (!string.IsNullOrEmpty(downloadCleanerConfig.UnlinkedIgnoredRootDir))
|
||||
if (downloadCleanerConfig.UnlinkedIgnoredRootDirs.Count > 0)
|
||||
{
|
||||
_hardLinkFileService.PopulateFileCounts(downloadCleanerConfig.UnlinkedIgnoredRootDir);
|
||||
_hardLinkFileService.PopulateFileCounts(downloadCleanerConfig.UnlinkedIgnoredRootDirs);
|
||||
}
|
||||
|
||||
foreach (QBitItemWrapper torrent in downloads.Cast<QBitItemWrapper>())
|
||||
@@ -131,7 +131,7 @@ public partial class QBitService
|
||||
continue;
|
||||
}
|
||||
|
||||
long hardlinkCount = _hardLinkFileService.GetHardLinkCount(filePath, !string.IsNullOrEmpty(downloadCleanerConfig.UnlinkedIgnoredRootDir));
|
||||
long hardlinkCount = _hardLinkFileService.GetHardLinkCount(filePath, downloadCleanerConfig.UnlinkedIgnoredRootDirs.Count > 0);
|
||||
|
||||
if (hardlinkCount < 0)
|
||||
{
|
||||
|
||||
@@ -59,9 +59,9 @@ public partial class TransmissionService
|
||||
|
||||
var downloadCleanerConfig = ContextProvider.Get<DownloadCleanerConfig>(nameof(DownloadCleanerConfig));
|
||||
|
||||
if (!string.IsNullOrEmpty(downloadCleanerConfig.UnlinkedIgnoredRootDir))
|
||||
if (downloadCleanerConfig.UnlinkedIgnoredRootDirs.Count > 0)
|
||||
{
|
||||
_hardLinkFileService.PopulateFileCounts(downloadCleanerConfig.UnlinkedIgnoredRootDir);
|
||||
_hardLinkFileService.PopulateFileCounts(downloadCleanerConfig.UnlinkedIgnoredRootDirs);
|
||||
}
|
||||
|
||||
foreach (TransmissionItemWrapper torrent in downloads.Cast<TransmissionItemWrapper>())
|
||||
@@ -95,7 +95,7 @@ public partial class TransmissionService
|
||||
|
||||
string filePath = string.Join(Path.DirectorySeparatorChar, Path.Combine(torrent.Info.DownloadDir, file.Name).Split(['\\', '/']));
|
||||
|
||||
long hardlinkCount = _hardLinkFileService.GetHardLinkCount(filePath, !string.IsNullOrEmpty(downloadCleanerConfig.UnlinkedIgnoredRootDir));
|
||||
long hardlinkCount = _hardLinkFileService.GetHardLinkCount(filePath, downloadCleanerConfig.UnlinkedIgnoredRootDirs.Count > 0);
|
||||
|
||||
if (hardlinkCount < 0)
|
||||
{
|
||||
|
||||
@@ -55,9 +55,9 @@ public partial class UTorrentService
|
||||
|
||||
var downloadCleanerConfig = ContextProvider.Get<DownloadCleanerConfig>(nameof(DownloadCleanerConfig));
|
||||
|
||||
if (!string.IsNullOrEmpty(downloadCleanerConfig.UnlinkedIgnoredRootDir))
|
||||
if (downloadCleanerConfig.UnlinkedIgnoredRootDirs.Count > 0)
|
||||
{
|
||||
_hardLinkFileService.PopulateFileCounts(downloadCleanerConfig.UnlinkedIgnoredRootDir);
|
||||
_hardLinkFileService.PopulateFileCounts(downloadCleanerConfig.UnlinkedIgnoredRootDirs);
|
||||
}
|
||||
|
||||
foreach (UTorrentItemWrapper torrent in downloads.Cast<UTorrentItemWrapper>())
|
||||
@@ -86,7 +86,7 @@ public partial class UTorrentService
|
||||
}
|
||||
|
||||
long hardlinkCount = _hardLinkFileService
|
||||
.GetHardLinkCount(filePath, !string.IsNullOrEmpty(downloadCleanerConfig.UnlinkedIgnoredRootDir));
|
||||
.GetHardLinkCount(filePath, downloadCleanerConfig.UnlinkedIgnoredRootDirs.Count > 0);
|
||||
|
||||
if (hardlinkCount < 0)
|
||||
{
|
||||
|
||||
@@ -6,13 +6,13 @@ namespace Cleanuparr.Infrastructure.Features.Files;
|
||||
public class HardLinkFileService : IHardLinkFileService
|
||||
{
|
||||
private readonly ILogger<HardLinkFileService> _logger;
|
||||
private readonly UnixHardLinkFileService _unixHardLinkFileService;
|
||||
private readonly WindowsHardLinkFileService _windowsHardLinkFileService;
|
||||
private readonly IUnixHardLinkFileService _unixHardLinkFileService;
|
||||
private readonly IWindowsHardLinkFileService _windowsHardLinkFileService;
|
||||
|
||||
public HardLinkFileService(
|
||||
ILogger<HardLinkFileService> logger,
|
||||
UnixHardLinkFileService unixHardLinkFileService,
|
||||
WindowsHardLinkFileService windowsHardLinkFileService
|
||||
IUnixHardLinkFileService unixHardLinkFileService,
|
||||
IWindowsHardLinkFileService windowsHardLinkFileService
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
@@ -23,16 +23,24 @@ public class HardLinkFileService : IHardLinkFileService
|
||||
public void PopulateFileCounts(string directoryPath)
|
||||
{
|
||||
_logger.LogTrace("populating file counts from {dir}", directoryPath);
|
||||
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
_windowsHardLinkFileService.PopulateFileCounts(directoryPath);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_unixHardLinkFileService.PopulateFileCounts(directoryPath);
|
||||
}
|
||||
|
||||
public void PopulateFileCounts(IEnumerable<string> directoryPaths)
|
||||
{
|
||||
foreach (var directoryPath in directoryPaths.Where(d => !string.IsNullOrEmpty(d)))
|
||||
{
|
||||
PopulateFileCounts(directoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
public long GetHardLinkCount(string filePath, bool ignoreRootDir)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
|
||||
@@ -8,6 +8,12 @@ public interface IHardLinkFileService
|
||||
/// </summary>
|
||||
/// <param name="directoryPath">The root directory where to search for hardlinks.</param>
|
||||
void PopulateFileCounts(string directoryPath);
|
||||
|
||||
/// <summary>
|
||||
/// Populates the inode counts for Unix and the file index counts for Windows from multiple directories.
|
||||
/// </summary>
|
||||
/// <param name="directoryPaths">The root directories where to search for hardlinks.</param>
|
||||
void PopulateFileCounts(IEnumerable<string> directoryPaths);
|
||||
|
||||
/// <summary>
|
||||
/// Get the hardlink count of a file.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Cleanuparr.Infrastructure.Features.Files;
|
||||
|
||||
public interface ISpecificFileService
|
||||
{
|
||||
/// <summary>
|
||||
/// Populates the inode counts for Unix and the file index counts for Windows.
|
||||
/// Needs to be called before <see cref="GetHardLinkCount"/> to populate the inode counts.
|
||||
/// </summary>
|
||||
/// <param name="directoryPath">The root directory where to search for hardlinks.</param>
|
||||
void PopulateFileCounts(string directoryPath);
|
||||
|
||||
/// <summary>
|
||||
/// Get the hardlink count of a file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">File path.</param>
|
||||
/// <param name="ignoreRootDir">Whether to ignore hardlinks found in the same root dir.</param>
|
||||
/// <returns>-1 on error, 0 if there are no hardlinks and 1 otherwise.</returns>
|
||||
long GetHardLinkCount(string filePath, bool ignoreRootDir);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Cleanuparr.Infrastructure.Features.Files;
|
||||
|
||||
public interface IUnixHardLinkFileService : ISpecificFileService
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Cleanuparr.Infrastructure.Features.Files;
|
||||
|
||||
public interface IWindowsHardLinkFileService : ISpecificFileService
|
||||
{
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Mono.Unix.Native;
|
||||
|
||||
namespace Cleanuparr.Infrastructure.Features.Files;
|
||||
|
||||
public class UnixHardLinkFileService : IHardLinkFileService, IDisposable
|
||||
public class UnixHardLinkFileService : IUnixHardLinkFileService, IDisposable
|
||||
{
|
||||
private readonly ILogger<UnixHardLinkFileService> _logger;
|
||||
private readonly ConcurrentDictionary<ulong, int> _inodeCounts = new();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Cleanuparr.Infrastructure.Features.Files;
|
||||
|
||||
public class WindowsHardLinkFileService : IHardLinkFileService, IDisposable
|
||||
public class WindowsHardLinkFileService : IWindowsHardLinkFileService, IDisposable
|
||||
{
|
||||
private readonly ILogger<WindowsHardLinkFileService> _logger;
|
||||
private readonly ConcurrentDictionary<ulong, int> _fileIndexCounts = new();
|
||||
|
||||
@@ -224,7 +224,7 @@ public sealed class DownloadCleanerConfigTests
|
||||
UnlinkedEnabled = true,
|
||||
UnlinkedTargetCategory = "cleanuparr-unlinked",
|
||||
UnlinkedCategories = ["movies"],
|
||||
UnlinkedIgnoredRootDir = "/non/existent/directory"
|
||||
UnlinkedIgnoredRootDirs = ["/non/existent/directory"]
|
||||
};
|
||||
|
||||
var exception = Should.Throw<ValidationException>(() => config.Validate());
|
||||
@@ -241,7 +241,7 @@ public sealed class DownloadCleanerConfigTests
|
||||
UnlinkedEnabled = true,
|
||||
UnlinkedTargetCategory = "cleanuparr-unlinked",
|
||||
UnlinkedCategories = ["movies"],
|
||||
UnlinkedIgnoredRootDir = ""
|
||||
UnlinkedIgnoredRootDirs = []
|
||||
};
|
||||
|
||||
Should.NotThrow(() => config.Validate());
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Cleanuparr.Persistence.Migrations.Data
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ChangeUnlinkedIgnoredRootDirType : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "unlinked_ignored_root_dir",
|
||||
table: "download_cleaner_configs",
|
||||
newName: "unlinked_ignored_root_dirs");
|
||||
|
||||
migrationBuilder.Sql("""
|
||||
UPDATE download_cleaner_configs
|
||||
SET unlinked_ignored_root_dirs = CASE
|
||||
WHEN unlinked_ignored_root_dirs IS NULL OR unlinked_ignored_root_dirs = '' THEN '[]'
|
||||
ELSE '["' || unlinked_ignored_root_dirs || '"]'
|
||||
END
|
||||
""");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql("""
|
||||
UPDATE download_cleaner_configs
|
||||
SET unlinked_ignored_root_dirs = CASE
|
||||
WHEN unlinked_ignored_root_dirs = '[]' OR unlinked_ignored_root_dirs IS NULL THEN ''
|
||||
ELSE SUBSTR(unlinked_ignored_root_dirs, 3, LENGTH(unlinked_ignored_root_dirs) - 4)
|
||||
END
|
||||
""");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "unlinked_ignored_root_dirs",
|
||||
table: "download_cleaner_configs",
|
||||
newName: "unlinked_ignored_root_dir");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,10 +139,10 @@ namespace Cleanuparr.Persistence.Migrations.Data
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("unlinked_enabled");
|
||||
|
||||
b.Property<string>("UnlinkedIgnoredRootDir")
|
||||
b.PrimitiveCollection<string>("UnlinkedIgnoredRootDirs")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("unlinked_ignored_root_dir");
|
||||
.HasColumnName("unlinked_ignored_root_dirs");
|
||||
|
||||
b.Property<string>("UnlinkedTargetCategory")
|
||||
.IsRequired()
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed record DownloadCleanerConfig : IJobConfig
|
||||
|
||||
public bool UnlinkedUseTag { get; set; }
|
||||
|
||||
public string UnlinkedIgnoredRootDir { get; set; } = string.Empty;
|
||||
public List<string> UnlinkedIgnoredRootDirs { get; set; } = [];
|
||||
|
||||
public List<string> UnlinkedCategories { get; set; } = [];
|
||||
|
||||
@@ -87,9 +87,12 @@ public sealed record DownloadCleanerConfig : IJobConfig
|
||||
throw new ValidationException("Empty unlinked category filter found");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(UnlinkedIgnoredRootDir) && !Directory.Exists(UnlinkedIgnoredRootDir))
|
||||
foreach (var dir in UnlinkedIgnoredRootDirs.Where(d => !string.IsNullOrEmpty(d)))
|
||||
{
|
||||
throw new ValidationException($"{UnlinkedIgnoredRootDir} root directory does not exist");
|
||||
if (!Directory.Exists(dir))
|
||||
{
|
||||
throw new ValidationException($"{dir} root directory does not exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -333,17 +333,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ignored Root Directory -->
|
||||
<!-- Ignored Root Directories -->
|
||||
<div class="field-row">
|
||||
<label class="field-label">
|
||||
<i class="pi pi-question-circle field-info-icon"
|
||||
(click)="openFieldDocs('unlinkedIgnoredRootDir')"
|
||||
<i class="pi pi-question-circle field-info-icon"
|
||||
(click)="openFieldDocs('unlinkedIgnoredRootDirs')"
|
||||
title="Click for documentation"></i>
|
||||
Ignored Root Directory
|
||||
Ignored Root Directories
|
||||
</label>
|
||||
<div class="field-input">
|
||||
<input type="text" pInputText formControlName="unlinkedIgnoredRootDir" placeholder="/path/to/directory" />
|
||||
<small class="form-helper-text">Root directory to ignore when checking for unlinked downloads (used for cross-seed)</small>
|
||||
<app-mobile-autocomplete
|
||||
formControlName="unlinkedIgnoredRootDirs"
|
||||
placeholder="Add directory path"
|
||||
></app-mobile-autocomplete>
|
||||
<small class="form-helper-text">Root directories to ignore when checking for unlinked downloads (used for cross-seed)</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ export class DownloadCleanerSettingsComponent implements OnDestroy, CanComponent
|
||||
unlinkedEnabled: [{ value: false, disabled: true }],
|
||||
unlinkedTargetCategory: [{ value: 'cleanuparr-unlinked', disabled: true }, [Validators.required]],
|
||||
unlinkedUseTag: [{ value: false, disabled: true }],
|
||||
unlinkedIgnoredRootDir: [{ value: '', disabled: true }],
|
||||
unlinkedIgnoredRootDirs: [{ value: [], disabled: true }],
|
||||
unlinkedCategories: [{ value: [], disabled: true }]
|
||||
}, { validators: [this.validateUnlinkedCategories, this.validateAtLeastOneFeature] });
|
||||
|
||||
@@ -341,7 +341,7 @@ export class DownloadCleanerSettingsComponent implements OnDestroy, CanComponent
|
||||
unlinkedEnabled: config.unlinkedEnabled,
|
||||
unlinkedTargetCategory: config.unlinkedTargetCategory,
|
||||
unlinkedUseTag: config.unlinkedUseTag,
|
||||
unlinkedIgnoredRootDir: config.unlinkedIgnoredRootDir,
|
||||
unlinkedIgnoredRootDirs: config.unlinkedIgnoredRootDirs || [],
|
||||
unlinkedCategories: config.unlinkedCategories || []
|
||||
});
|
||||
|
||||
@@ -624,7 +624,7 @@ export class DownloadCleanerSettingsComponent implements OnDestroy, CanComponent
|
||||
unlinkedEnabled: formValues.unlinkedEnabled,
|
||||
unlinkedTargetCategory: formValues.unlinkedTargetCategory,
|
||||
unlinkedUseTag: formValues.unlinkedUseTag,
|
||||
unlinkedIgnoredRootDir: formValues.unlinkedIgnoredRootDir,
|
||||
unlinkedIgnoredRootDirs: formValues.unlinkedIgnoredRootDirs || [],
|
||||
unlinkedCategories: formValues.unlinkedCategories || []
|
||||
};
|
||||
|
||||
@@ -682,7 +682,7 @@ export class DownloadCleanerSettingsComponent implements OnDestroy, CanComponent
|
||||
unlinkedEnabled: false,
|
||||
unlinkedTargetCategory: 'cleanuparr-unlinked',
|
||||
unlinkedUseTag: false,
|
||||
unlinkedIgnoredRootDir: '',
|
||||
unlinkedIgnoredRootDirs: [],
|
||||
unlinkedCategories: []
|
||||
});
|
||||
|
||||
@@ -793,7 +793,7 @@ export class DownloadCleanerSettingsComponent implements OnDestroy, CanComponent
|
||||
private updateUnlinkedControlsState(enabled: boolean): void {
|
||||
const targetCategoryControl = this.downloadCleanerForm.get('unlinkedTargetCategory');
|
||||
const useTagControl = this.downloadCleanerForm.get('unlinkedUseTag');
|
||||
const ignoredRootDirControl = this.downloadCleanerForm.get('unlinkedIgnoredRootDir');
|
||||
const ignoredRootDirsControl = this.downloadCleanerForm.get('unlinkedIgnoredRootDirs');
|
||||
const categoriesControl = this.downloadCleanerForm.get('unlinkedCategories');
|
||||
|
||||
// Disable emitting events during bulk changes
|
||||
@@ -803,13 +803,13 @@ export class DownloadCleanerSettingsComponent implements OnDestroy, CanComponent
|
||||
// Enable all unlinked controls
|
||||
targetCategoryControl?.enable(options);
|
||||
useTagControl?.enable(options);
|
||||
ignoredRootDirControl?.enable(options);
|
||||
ignoredRootDirsControl?.enable(options);
|
||||
categoriesControl?.enable(options);
|
||||
} else {
|
||||
// Disable all unlinked controls
|
||||
targetCategoryControl?.disable(options);
|
||||
useTagControl?.disable(options);
|
||||
ignoredRootDirControl?.disable(options);
|
||||
ignoredRootDirsControl?.disable(options);
|
||||
categoriesControl?.disable(options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface DownloadCleanerConfig {
|
||||
unlinkedEnabled: boolean;
|
||||
unlinkedTargetCategory: string;
|
||||
unlinkedUseTag: boolean;
|
||||
unlinkedIgnoredRootDir: string;
|
||||
unlinkedIgnoredRootDirs: string[];
|
||||
unlinkedCategories: string[];
|
||||
}
|
||||
|
||||
@@ -56,6 +56,6 @@ export const defaultDownloadCleanerConfig: DownloadCleanerConfig = {
|
||||
unlinkedEnabled: false,
|
||||
unlinkedTargetCategory: 'cleanuparr-unlinked',
|
||||
unlinkedUseTag: false,
|
||||
unlinkedIgnoredRootDir: '',
|
||||
unlinkedIgnoredRootDirs: [],
|
||||
unlinkedCategories: []
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user