1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-18 21:35:27 -04:00

Add v5 Media Management endpoints

This commit is contained in:
Mark McDowall
2026-01-31 09:43:56 -08:00
parent 3e22ad59c3
commit 1d8da79172
5 changed files with 146 additions and 6 deletions
@@ -0,0 +1,69 @@
using FluentValidation;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Validation;
using NzbDrone.Core.Validation.Paths;
using Sonarr.Http;
namespace Sonarr.Api.V5.Settings;
[V5ApiController("settings/mediamanagement")]
public class MediaManagementSettingsController : SettingsController<MediaManagementSettingsResource>
{
public MediaManagementSettingsController(IConfigService configService,
PathExistsValidator pathExistsValidator,
FolderChmodValidator folderChmodValidator,
FolderWritableValidator folderWritableValidator,
SeriesPathValidator seriesPathValidator,
StartupFolderValidator startupFolderValidator,
SystemFolderValidator systemFolderValidator,
RootFolderAncestorValidator rootFolderAncestorValidator,
RootFolderValidator rootFolderValidator)
: base(configService)
{
SharedValidator.RuleFor(c => c.RecycleBinCleanupDays).GreaterThanOrEqualTo(0);
SharedValidator.RuleFor(c => c.ChmodFolder).SetValidator(folderChmodValidator).When(c => !string.IsNullOrEmpty(c.ChmodFolder) && (OsInfo.IsLinux || OsInfo.IsOsx));
SharedValidator.RuleFor(c => c.RecycleBin).IsValidPath()
.SetValidator(folderWritableValidator)
.SetValidator(rootFolderValidator)
.SetValidator(pathExistsValidator)
.SetValidator(rootFolderAncestorValidator)
.SetValidator(startupFolderValidator)
.SetValidator(systemFolderValidator)
.SetValidator(seriesPathValidator)
.When(c => !string.IsNullOrWhiteSpace(c.RecycleBin));
SharedValidator.RuleFor(c => c.ScriptImportPath).IsValidPath().When(c => c.UseScriptImport);
SharedValidator.RuleFor(c => c.MinimumFreeSpaceWhenImporting).GreaterThanOrEqualTo(100);
SharedValidator.RuleFor(c => c.UserRejectedExtensions).Custom((extensions, context) =>
{
var userRejectedExtensions = extensions?.Split([','], StringSplitOptions.RemoveEmptyEntries)
.Select(e => e.Trim(' ', '.')
.Insert(0, "."))
.ToList() ?? [];
var matchingArchiveExtensions = userRejectedExtensions.Where(ext => FileExtensions.ArchiveExtensions.Contains(ext)).ToList();
if (matchingArchiveExtensions.Count > 0)
{
context.AddFailure($"Rejected extensions may not include valid archive extensions: {string.Join(", ", matchingArchiveExtensions)}");
}
var matchingMediaFileExtensions = userRejectedExtensions.Where(ext => MediaFileExtensions.Extensions.Contains(ext)).ToList();
if (matchingMediaFileExtensions.Count > 0)
{
context.AddFailure($"Rejected extensions may not include valid media file extensions: {string.Join(", ", matchingMediaFileExtensions)}");
}
});
}
protected override MediaManagementSettingsResource ToResource(IConfigService model)
{
return MediaManagementConfigResourceMapper.ToResource(model);
}
}
@@ -0,0 +1,71 @@
using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Qualities;
using Sonarr.Http.REST;
namespace Sonarr.Api.V5.Settings;
public class MediaManagementSettingsResource : RestResource
{
public bool AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; }
public string? RecycleBin { get; set; }
public int RecycleBinCleanupDays { get; set; }
public ProperDownloadTypes DownloadPropersAndRepacks { get; set; }
public bool CreateEmptySeriesFolders { get; set; }
public bool DeleteEmptyFolders { get; set; }
public FileDateType FileDate { get; set; }
public RescanAfterRefreshType RescanAfterRefresh { get; set; }
public bool SetPermissionsLinux { get; set; }
public string? ChmodFolder { get; set; }
public string? ChownGroup { get; set; }
public EpisodeTitleRequiredType EpisodeTitleRequired { get; set; }
public bool SkipFreeSpaceCheckWhenImporting { get; set; }
public int MinimumFreeSpaceWhenImporting { get; set; }
public bool CopyUsingHardlinks { get; set; }
public bool UseScriptImport { get; set; }
public string? ScriptImportPath { get; set; }
public bool ImportExtraFiles { get; set; }
public string? ExtraFileExtensions { get; set; }
public bool EnableMediaInfo { get; set; }
public string? UserRejectedExtensions { get; set; }
public SeasonPackUpgradeType SeasonPackUpgrade { get; set; }
public double SeasonPackUpgradeThreshold { get; set; }
}
public static class MediaManagementConfigResourceMapper
{
public static MediaManagementSettingsResource ToResource(IConfigService model)
{
return new MediaManagementSettingsResource
{
AutoUnmonitorPreviouslyDownloadedEpisodes = model.AutoUnmonitorPreviouslyDownloadedEpisodes,
RecycleBin = model.RecycleBin,
RecycleBinCleanupDays = model.RecycleBinCleanupDays,
DownloadPropersAndRepacks = model.DownloadPropersAndRepacks,
CreateEmptySeriesFolders = model.CreateEmptySeriesFolders,
DeleteEmptyFolders = model.DeleteEmptyFolders,
FileDate = model.FileDate,
RescanAfterRefresh = model.RescanAfterRefresh,
SetPermissionsLinux = model.SetPermissionsLinux,
ChmodFolder = model.ChmodFolder,
ChownGroup = model.ChownGroup,
EpisodeTitleRequired = model.EpisodeTitleRequired,
SkipFreeSpaceCheckWhenImporting = model.SkipFreeSpaceCheckWhenImporting,
MinimumFreeSpaceWhenImporting = model.MinimumFreeSpaceWhenImporting,
CopyUsingHardlinks = model.CopyUsingHardlinks,
UseScriptImport = model.UseScriptImport,
ScriptImportPath = model.ScriptImportPath,
ImportExtraFiles = model.ImportExtraFiles,
ExtraFileExtensions = model.ExtraFileExtensions,
EnableMediaInfo = model.EnableMediaInfo,
UserRejectedExtensions = model.UserRejectedExtensions,
SeasonPackUpgrade = model.SeasonPackUpgrade,
SeasonPackUpgradeThreshold = model.SeasonPackUpgradeThreshold
};
}
}
@@ -4,14 +4,14 @@ using NzbDrone.Core.Configuration;
using Sonarr.Http.REST;
using Sonarr.Http.REST.Attributes;
namespace Sonarr.Api.V5.Config
namespace Sonarr.Api.V5.Settings
{
public abstract class ConfigController<TResource> : RestController<TResource>
public abstract class SettingsController<TResource> : RestController<TResource>
where TResource : RestResource, new()
{
protected readonly IConfigService _configService;
protected ConfigController(IConfigService configService)
protected SettingsController(IConfigService configService)
{
_configService = configService;
}
@@ -6,10 +6,10 @@ using NzbDrone.Core.Languages;
using Sonarr.Http;
using Sonarr.Http.REST.Attributes;
namespace Sonarr.Api.V5.Config;
namespace Sonarr.Api.V5.Settings;
[V5ApiController("settings/ui")]
public class UiSettingsController : ConfigController<UiSettingsResource>
public class UiSettingsController : SettingsController<UiSettingsResource>
{
private readonly IConfigFileProvider _configFileProvider;
@@ -1,7 +1,7 @@
using NzbDrone.Core.Configuration;
using Sonarr.Http.REST;
namespace Sonarr.Api.V5.Config;
namespace Sonarr.Api.V5.Settings;
public class UiSettingsResource : RestResource
{