New: Rework List sync interval logic

* New: Rework List sync interval logic

(cherry picked from commit c522cd120d08757e7e43c2348be4d7f05a254fac)

* Minor alignment with Sonarr

* Remove ListUpdateInterval

---------

Co-authored-by: Qstick <qstick@gmail.com>
This commit is contained in:
Bogdan 2023-07-04 19:17:28 +03:00 committed by GitHub
parent 148ee5983d
commit bd1844030d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 174 additions and 101 deletions

View File

@ -3,3 +3,9 @@
margin-right: auto;
}
.message {
composes: alert from '~Components/Alert.css';
margin-bottom: 30px;
}

View File

@ -2,6 +2,7 @@
// Please do not change this file!
interface CssExports {
'deleteButton': string;
'message': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@ -14,6 +14,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props';
import formatShortTimeSpan from 'Utilities/Date/formatShortTimeSpan';
import translate from 'Utilities/String/translate';
import styles from './EditImportListModalContent.css';
@ -42,6 +43,7 @@ function EditImportListModalContent(props) {
name,
enabled,
enableAuto,
minRefreshInterval,
monitor,
minimumAvailability,
qualityProfileId,
@ -85,6 +87,14 @@ function EditImportListModalContent(props) {
{message.value.message}
</Alert>
}
<Alert
kind={kinds.INFO}
className={styles.message}
>
{translate('ListWillRefreshEveryInterp', [formatShortTimeSpan(minRefreshInterval.value)])}
</Alert>
<FormGroup>
<FormLabel>{translate('Name')}</FormLabel>

View File

@ -4,6 +4,7 @@ import Card from 'Components/Card';
import Label from 'Components/Label';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import { kinds } from 'Helpers/Props';
import formatShortTimeSpan from 'Utilities/Date/formatShortTimeSpan';
import translate from 'Utilities/String/translate';
import EditImportListModalConnector from './EditImportListModalConnector';
import styles from './ImportList.css';
@ -56,7 +57,8 @@ class ImportList extends Component {
id,
name,
enabled,
enableAuto
enableAuto,
minRefreshInterval
} = this.props;
return (
@ -96,6 +98,12 @@ class ImportList extends Component {
}
</div>
<div className={styles.enabled}>
<Label kind={kinds.INFO} title='List Refresh Interval'>
{`${translate('Refresh')}: ${formatShortTimeSpan(minRefreshInterval)}`}
</Label>
</div>
<EditImportListModalConnector
id={id}
isOpen={this.state.isEditImportListModalOpen}
@ -122,6 +130,7 @@ ImportList.propTypes = {
name: PropTypes.string.isRequired,
enabled: PropTypes.bool.isRequired,
enableAuto: PropTypes.bool.isRequired,
minRefreshInterval: PropTypes.string.isRequired,
onConfirmDeleteImportList: PropTypes.func.isRequired
};

View File

@ -46,23 +46,6 @@ function ImportListOptions(props) {
{
hasSettings && !isFetching && !error &&
<Form>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('ListUpdateInterval')}</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="importListSyncInterval"
min={6}
unit="hours"
helpText={translate('ImportListSyncIntervalHelpText')}
onChange={onInputChange}
{...settings.importListSyncInterval}
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}

View File

@ -0,0 +1,25 @@
import moment from 'moment';
function formatShortTimeSpan(timeSpan) {
if (!timeSpan) {
return '';
}
const duration = moment.duration(timeSpan);
const hours = Math.floor(duration.asHours());
const minutes = Math.floor(duration.asMinutes());
const seconds = Math.floor(duration.asSeconds());
if (hours > 0) {
return `${hours} hour(s)`;
}
if (minutes > 0) {
return `${minutes} minute(s)`;
}
return `${seconds} second(s)`;
}
export default formatShortTimeSpan;

View File

@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.ImportListTests
_blockedLists = new List<ImportListStatus>();
Mocker.GetMock<IImportListFactory>()
.Setup(v => v.Enabled())
.Setup(v => v.Enabled(It.IsAny<bool>()))
.Returns(_importLists);
Mocker.GetMock<IImportListStatusService>()
@ -183,7 +183,7 @@ namespace NzbDrone.Core.Test.ImportListTests
var listResult = Subject.Fetch();
listResult.AnyFailure.Should().BeFalse();
listResult.Movies.Count.Should().Be(10);
listResult.Movies.Count.Should().Be(5);
}
}
}

View File

@ -72,7 +72,7 @@ namespace NzbDrone.Core.Test.ImportList
};
Mocker.GetMock<IImportListFactory>()
.Setup(v => v.Enabled())
.Setup(v => v.Enabled(It.IsAny<bool>()))
.Returns(_importLists);
Mocker.GetMock<IImportExclusionsService>()
@ -347,7 +347,7 @@ namespace NzbDrone.Core.Test.ImportList
}
[Test]
public void should_not_add_duplicate_movies_from_seperate_lists()
public void should_not_add_duplicate_movies_from_separate_lists()
{
_list2Movies.ForEach(m => m.ListId = 2);
_importListFetch.Movies.ForEach(m => m.ListId = 1);
@ -384,7 +384,7 @@ namespace NzbDrone.Core.Test.ImportList
Subject.Execute(_commandAll);
Mocker.GetMock<IAddMovieService>()
.Verify(v => v.AddMovies(It.Is<List<Movie>>(s => s.Count == 7 && !s.Any(m => m.TmdbId == _existingMovies[0].TmdbId)), true), Times.Once());
.Verify(v => v.AddMovies(It.Is<List<Movie>>(s => s.Count == 7 && s.All(m => m.TmdbId != _existingMovies[0].TmdbId)), true), Times.Once());
}
[Test]
@ -406,7 +406,7 @@ namespace NzbDrone.Core.Test.ImportList
Subject.Execute(_commandAll);
Mocker.GetMock<IAddMovieService>()
.Verify(v => v.AddMovies(It.Is<List<Movie>>(s => s.Count == 7 && !s.Any(m => m.TmdbId == _existingMovies[0].TmdbId)), true), Times.Once());
.Verify(v => v.AddMovies(It.Is<List<Movie>>(s => s.Count == 7 && s.All(m => m.TmdbId != _existingMovies[0].TmdbId)), true), Times.Once());
}
}
}

View File

@ -116,13 +116,6 @@ namespace NzbDrone.Core.Configuration
set { SetValue("AvailabilityDelay", value); }
}
public int ImportListSyncInterval
{
get { return GetValueInt("ImportListSyncInterval", 24); }
set { SetValue("ImportListSyncInterval", value); }
}
public string ListSyncLevel
{
get { return GetValue("ListSyncLevel", "disabled"); }

View File

@ -60,7 +60,6 @@ namespace NzbDrone.Core.Configuration
bool AllowHardcodedSubs { get; set; }
string WhitelistedHardcodedSubs { get; set; }
int ImportListSyncInterval { get; set; }
string ListSyncLevel { get; set; }
string ImportExclusions { get; set; }

View File

@ -0,0 +1,18 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(224)]
public class list_sync_time : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Delete.Column("LastSyncListInfo").FromTable("ImportListStatus");
Alter.Table("ImportListStatus").AddColumn("LastInfoSync").AsDateTimeOffset().Nullable();
Delete.FromTable("Config").Row(new { Key = "importlistsyncinterval" });
}
}
}

View File

@ -80,6 +80,7 @@ namespace NzbDrone.Core.Datastore
Mapper.Entity<ImportListDefinition>("ImportLists").RegisterModel()
.Ignore(x => x.ImplementationName)
.Ignore(i => i.ListType)
.Ignore(i => i.MinRefreshInterval)
.Ignore(i => i.Enable);
Mapper.Entity<NotificationDefinition>("Notifications").RegisterModel()

View File

@ -1,3 +1,4 @@
using System;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
@ -10,6 +11,7 @@ namespace NzbDrone.Core.ImportLists.CouchPotato
public override string Name => "CouchPotato";
public override ImportListType ListType => ImportListType.Program;
public override TimeSpan MinRefreshInterval => TimeSpan.FromMinutes(30);
public override bool Enabled => true;
public override bool EnableAuto => false;

View File

@ -66,6 +66,15 @@ namespace NzbDrone.Core.ImportLists
_logger.ProgressInfo("Syncing Movies for List: {0}", importList.Name);
var importListLocal = importList;
var importListStatus = _importListStatusService.GetLastSyncListInfo(importListLocal.Definition.Id);
if (importListStatus.HasValue && DateTime.UtcNow < importListStatus + importListLocal.MinRefreshInterval)
{
_logger.Trace("Skipping refresh of Import List {0} due to minimum refresh inverval", importListLocal.Definition.Name);
continue;
}
var blockedLists = _importListStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v);
if (blockedLists.TryGetValue(importList.Definition.Id, out var blockedListStatus))
@ -88,7 +97,7 @@ namespace NzbDrone.Core.ImportLists
if (!importListReports.AnyFailure)
{
var alreadyMapped = result.Movies.Where(x => importListReports.Movies.Any(r => r.TmdbId == x.TmdbId));
var listMovies = MapMovieReports(importListReports.Movies.Where(x => !result.Movies.Any(r => r.TmdbId == x.TmdbId)).ToList()).Where(x => x.TmdbId > 0).ToList();
var listMovies = MapMovieReports(importListReports.Movies.Where(x => result.Movies.All(r => r.TmdbId != x.TmdbId)).ToList()).Where(x => x.TmdbId > 0).ToList();
listMovies.AddRange(alreadyMapped);
listMovies = listMovies.DistinctBy(x => x.TmdbId).ToList();
@ -99,6 +108,8 @@ namespace NzbDrone.Core.ImportLists
}
result.AnyFailure |= importListReports.AnyFailure;
_importListStatusService.UpdateListSyncStatus(importList.Definition.Id);
}
}
catch (Exception e)
@ -112,6 +123,8 @@ namespace NzbDrone.Core.ImportLists
Task.WaitAll(taskList.ToArray());
result.Movies = result.Movies.DistinctBy(r => new { r.TmdbId, r.ImdbId, r.Title }).ToList();
_logger.Debug("Found {0} reports for all lists", result.Movies.Count);
return result;
@ -151,6 +164,8 @@ namespace NzbDrone.Core.ImportLists
}
result.AnyFailure |= importListReports.AnyFailure;
_importListStatusService.UpdateListSyncStatus(importList.Definition.Id);
}
}
catch (Exception e)
@ -158,6 +173,8 @@ namespace NzbDrone.Core.ImportLists
_logger.Error(e, "Error during Import List Sync for list {0}", importList.Name);
}
result.Movies = result.Movies.DistinctBy(r => new { r.TmdbId, r.ImdbId, r.Title }).ToList();
_logger.Debug("Found {0} reports for list {1}", result.Movies.Count, importList.Name);
return result;
@ -166,9 +183,9 @@ namespace NzbDrone.Core.ImportLists
private List<ImportListMovie> MapMovieReports(List<ImportListMovie> reports)
{
var mappedMovies = reports.Select(m => _movieSearch.MapMovieToTmdbMovie(new MovieMetadata { Title = m.Title, TmdbId = m.TmdbId, ImdbId = m.ImdbId, Year = m.Year }))
.Where(x => x != null)
.DistinctBy(x => x.TmdbId)
.ToList();
.Where(x => x != null)
.DistinctBy(x => x.TmdbId)
.ToList();
_movieMetadataService.UpsertMany(mappedMovies);

View File

@ -1,3 +1,4 @@
using System;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.ImportLists
@ -8,6 +9,7 @@ namespace NzbDrone.Core.ImportLists
bool EnableAuto { get; }
ImportListType ListType { get; }
TimeSpan MinRefreshInterval { get; }
ImportListFetchResult Fetch();
}
}

View File

@ -32,6 +32,7 @@ namespace NzbDrone.Core.ImportLists
public abstract string Name { get; }
public abstract ImportListType ListType { get; }
public abstract TimeSpan MinRefreshInterval { get; }
public abstract bool Enabled { get; }
public abstract bool EnableAuto { get; }

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using NzbDrone.Core.Movies;
using NzbDrone.Core.ThingiProvider;
@ -21,5 +22,6 @@ namespace NzbDrone.Core.ImportLists
public override bool Enable => Enabled;
public ImportListType ListType { get; set; }
public TimeSpan MinRefreshInterval { get; set; }
}
}

View File

@ -9,23 +9,24 @@ namespace NzbDrone.Core.ImportLists
{
public interface IImportListFactory : IProviderFactory<IImportList, ImportListDefinition>
{
List<IImportList> Enabled();
List<IImportList> Enabled(bool filterBlockedImportLists = true);
List<IImportList> Discoverable();
}
public class ImportListFactory : ProviderFactory<IImportList, ImportListDefinition>, IImportListFactory
{
private readonly IImportListRepository _providerRepository;
private readonly IImportListStatusService _importListStatusService;
private readonly Logger _logger;
public ImportListFactory(IImportListRepository providerRepository,
public ImportListFactory(IImportListStatusService importListStatusService,
IImportListRepository providerRepository,
IEnumerable<IImportList> providers,
IServiceProvider container,
IEventAggregator eventAggregator,
Logger logger)
: base(providerRepository, providers, container, eventAggregator, logger)
{
_providerRepository = providerRepository;
_importListStatusService = importListStatusService;
_logger = logger;
}
@ -39,18 +40,42 @@ namespace NzbDrone.Core.ImportLists
base.SetProviderCharacteristics(provider, definition);
definition.ListType = provider.ListType;
definition.MinRefreshInterval = provider.MinRefreshInterval;
}
public List<IImportList> Enabled()
public List<IImportList> Enabled(bool filterBlockedImportLists = true)
{
var enabledImporters = GetAvailableProviders().Where(n => ((ImportListDefinition)n.Definition).Enabled);
return enabledImporters.ToList();
var enabledImportLists = GetAvailableProviders().Where(n => ((ImportListDefinition)n.Definition).Enabled);
if (filterBlockedImportLists)
{
return FilterBlockedImportLists(enabledImportLists).ToList();
}
return enabledImportLists.ToList();
}
public List<IImportList> Discoverable()
{
var enabledImporters = GetAvailableProviders().Where(n => (n.GetType() == typeof(RadarrList.RadarrListImport) || n.GetType() == typeof(TMDb.Popular.TMDbPopularImport)));
return enabledImporters.ToList();
var enabledImportLists = GetAvailableProviders().Where(n => n.GetType() == typeof(RadarrList.RadarrListImport) || n.GetType() == typeof(TMDb.Popular.TMDbPopularImport));
return enabledImportLists.ToList();
}
private IEnumerable<IImportList> FilterBlockedImportLists(IEnumerable<IImportList> importLists)
{
var blockedImportLists = _importListStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v);
foreach (var importList in importLists)
{
if (blockedImportLists.TryGetValue(importList.Definition.Id, out var blockedImportListStatus))
{
_logger.Debug("Temporarily ignoring import list {0} till {1} due to recent failures.", importList.Definition.Name, blockedImportListStatus.DisabledTill.Value.ToLocalTime());
continue;
}
yield return importList;
}
}
}
}

View File

@ -1,10 +1,10 @@
using NzbDrone.Core.Movies;
using System;
using NzbDrone.Core.ThingiProvider.Status;
namespace NzbDrone.Core.ImportLists
{
public class ImportListStatus : ProviderStatusBase
{
public Movie LastSyncListInfo { get; set; }
public DateTime? LastInfoSync { get; set; }
}
}

View File

@ -1,16 +1,16 @@
using System;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Movies;
using NzbDrone.Core.ThingiProvider.Status;
namespace NzbDrone.Core.ImportLists
{
public interface IImportListStatusService : IProviderStatusServiceBase<ImportListStatus>
{
Movie GetLastSyncListInfo(int importListId);
DateTime? GetLastSyncListInfo(int importListId);
void UpdateListSyncStatus(int importListId, Movie listItemInfo);
void UpdateListSyncStatus(int importListId);
}
public class ImportListStatusService : ProviderStatusServiceBase<IImportList, ImportListStatus>, IImportListStatusService
@ -20,18 +20,18 @@ namespace NzbDrone.Core.ImportLists
{
}
public Movie GetLastSyncListInfo(int importListId)
public DateTime? GetLastSyncListInfo(int importListId)
{
return GetProviderStatus(importListId).LastSyncListInfo;
return GetProviderStatus(importListId).LastInfoSync;
}
public void UpdateListSyncStatus(int importListId, Movie listItemInfo)
public void UpdateListSyncStatus(int importListId)
{
lock (_syncRoot)
{
var status = GetProviderStatus(importListId);
status.LastSyncListInfo = listItemInfo;
status.LastInfoSync = DateTime.UtcNow;
_providerStatusRepository.Upsert(status);
}

View File

@ -15,6 +15,7 @@ namespace NzbDrone.Core.ImportLists.Plex
{
public readonly IPlexTvService _plexTvService;
public override ImportListType ListType => ImportListType.Plex;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(6);
public PlexImport(IPlexTvService plexTvService,
IHttpClient httpClient,

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
@ -12,6 +13,7 @@ namespace NzbDrone.Core.ImportLists.RSSImport
public override string Name => "RSS List";
public override ImportListType ListType => ImportListType.Advanced;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(12);
public override bool Enabled => true;
public override bool EnableAuto => false;

View File

@ -19,6 +19,7 @@ namespace NzbDrone.Core.ImportLists.Radarr
public override bool EnableAuto => false;
public override ImportListType ListType => ImportListType.Program;
public override TimeSpan MinRefreshInterval => TimeSpan.FromMinutes(15);
public RadarrImport(IRadarrV3Proxy radarrV3Proxy,
IImportListStatusService importListStatusService,

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
@ -12,6 +13,7 @@ namespace NzbDrone.Core.ImportLists.RadarrList
public override string Name => "Custom Lists";
public override ImportListType ListType => ImportListType.Advanced;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(12);
public override bool Enabled => true;
public override bool EnableAuto => false;

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Cloud;
@ -15,6 +16,7 @@ namespace NzbDrone.Core.ImportLists.RadarrList2.IMDbList
public override string Name => "IMDb Lists";
public override ImportListType ListType => ImportListType.Other;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(12);
public override bool Enabled => true;
public override bool EnableAuto => false;

View File

@ -1,3 +1,4 @@
using System;
using NLog;
using NzbDrone.Common.Cloud;
using NzbDrone.Common.Http;
@ -13,6 +14,8 @@ namespace NzbDrone.Core.ImportLists.RadarrList2.StevenLu
public override string Name => "StevenLu List";
public override ImportListType ListType => ImportListType.Other;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(12);
public override bool Enabled => true;
public override bool EnableAuto => false;

View File

@ -1,3 +1,4 @@
using System;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
@ -9,6 +10,7 @@ namespace NzbDrone.Core.ImportLists.Rss.Plex
{
public override string Name => "Plex Watchlist RSS";
public override ImportListType ListType => ImportListType.Plex;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(6);
public PlexRssImport(IHttpClient httpClient,
IImportListStatusService importListStatusService,

View File

@ -1,3 +1,4 @@
using System;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
@ -10,6 +11,7 @@ namespace NzbDrone.Core.ImportLists.StevenLu
public override string Name => "StevenLu Custom";
public override ImportListType ListType => ImportListType.Advanced;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(24);
public override bool Enabled => true;
public override bool EnableAuto => false;

View File

@ -1,3 +1,4 @@
using System;
using NLog;
using NzbDrone.Common.Cloud;
using NzbDrone.Common.Http;
@ -11,6 +12,7 @@ namespace NzbDrone.Core.ImportLists.TMDb
where TSettings : TMDbSettingsBase<TSettings>, new()
{
public override ImportListType ListType => ImportListType.TMDB;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(12);
public readonly ISearchForNewMovie _skyhookProxy;
public readonly IHttpRequestBuilderFactory _requestBuilder;

View File

@ -15,6 +15,7 @@ namespace NzbDrone.Core.ImportLists.Trakt
public ITraktProxy _traktProxy;
private readonly IImportListRepository _importListRepository;
public override ImportListType ListType => ImportListType.Trakt;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(12);
protected TraktImportBase(IImportListRepository importListRepository,
ITraktProxy traktProxy,

View File

@ -121,7 +121,7 @@ namespace NzbDrone.Core.Jobs
new ScheduledTask
{
Interval = GetImportListSyncInterval(),
Interval = 5,
TypeName = typeof(ImportListSyncCommand).FullName
},
@ -210,14 +210,6 @@ namespace NzbDrone.Core.Jobs
return interval;
}
private int GetImportListSyncInterval()
{
// Enforce 6 hour min on list sync
var interval = Math.Max(_configService.ImportListSyncInterval, 6);
return interval * 60;
}
public void Handle(CommandExecutedEvent message)
{
var scheduledTask = _scheduledTaskRepository.All().SingleOrDefault(c => c.TypeName == message.Command.Body.GetType().FullName);
@ -239,19 +231,15 @@ namespace NzbDrone.Core.Jobs
var rss = _scheduledTaskRepository.GetDefinition(typeof(RssSyncCommand));
rss.Interval = GetRssSyncInterval();
var importList = _scheduledTaskRepository.GetDefinition(typeof(ImportListSyncCommand));
importList.Interval = GetImportListSyncInterval();
var backup = _scheduledTaskRepository.GetDefinition(typeof(BackupCommand));
backup.Interval = GetBackupInterval();
var refreshMonitoredDownloads = _scheduledTaskRepository.GetDefinition(typeof(RefreshMonitoredDownloadsCommand));
refreshMonitoredDownloads.Interval = GetRefreshMonitoredInterval();
_scheduledTaskRepository.UpdateMany(new List<ScheduledTask> { rss, importList, refreshMonitoredDownloads, backup });
_scheduledTaskRepository.UpdateMany(new List<ScheduledTask> { rss, refreshMonitoredDownloads, backup });
_cache.Find(rss.TypeName).Interval = rss.Interval;
_cache.Find(importList.TypeName).Interval = importList.Interval;
_cache.Find(backup.TypeName).Interval = backup.Interval;
_cache.Find(refreshMonitoredDownloads.TypeName).Interval = refreshMonitoredDownloads.Interval;
}

View File

@ -416,7 +416,6 @@
"ImportListMultipleMissingRoots": "Multiple root folders are missing for import lists: {0}",
"ImportListStatusCheckAllClientMessage": "All lists are unavailable due to failures",
"ImportListStatusCheckSingleClientMessage": "Lists unavailable due to failures: {0}",
"ImportListSyncIntervalHelpText": "How often Radarr syncs with your lists. Minimum value of 6 hours",
"ImportMechanismHealthCheckMessage": "Enable Completed Download Handling",
"ImportMovies": "Import Movies",
"ImportNotForDownloads": "Do not use for importing downloads from your download client, this is only for existing organized libraries, not unsorted files.",
@ -484,11 +483,12 @@
"Links": "Links",
"List": "List",
"ListExclusions": "List Exclusions",
"ListRefreshInterval": "List Refresh Interval",
"ListSettings": "List Settings",
"ListSyncLevelHelpText": "Movies in library will be handled based on your selection if they fall off or do not appear on your list(s)",
"ListSyncLevelHelpTextWarning": "Movie files will be permanently deleted, this can result in wiping your library if your lists are empty",
"ListTagsHelpText": "Tags list items will be added with",
"ListUpdateInterval": "List Update Interval",
"ListWillRefreshEveryInterp": "List will refresh every {0}",
"Lists": "Lists",
"ListsSettingsSummary": "Import Lists, list exclusions",
"Loading": "Loading",

View File

@ -1,6 +1,5 @@
using NzbDrone.Core.Configuration;
using Radarr.Http;
using Radarr.Http.Validation;
namespace Radarr.Api.V3.Config
{
@ -11,8 +10,6 @@ namespace Radarr.Api.V3.Config
public ImportListConfigController(IConfigService configService)
: base(configService)
{
SharedValidator.RuleFor(c => c.ImportListSyncInterval)
.IsValidImportListSyncInterval();
}
protected override ImportListConfigResource ToResource(IConfigService model)

View File

@ -5,7 +5,6 @@ namespace Radarr.Api.V3.Config
{
public class ImportListConfigResource : RestResource
{
public int ImportListSyncInterval { get; set; }
public string ListSyncLevel { get; set; }
public string ImportExclusions { get; set; }
}
@ -16,7 +15,6 @@ namespace Radarr.Api.V3.Config
{
return new ImportListConfigResource
{
ImportListSyncInterval = model.ImportListSyncInterval,
ListSyncLevel = model.ListSyncLevel,
ImportExclusions = model.ImportExclusions
};

View File

@ -1,3 +1,4 @@
using System;
using NzbDrone.Core.ImportLists;
using NzbDrone.Core.Movies;
@ -14,6 +15,7 @@ namespace Radarr.Api.V3.ImportLists
public MovieStatusType MinimumAvailability { get; set; }
public ImportListType ListType { get; set; }
public int ListOrder { get; set; }
public TimeSpan MinRefreshInterval { get; set; }
}
public class ImportListResourceMapper : ProviderResourceMapper<ImportListResource, ImportListDefinition>
@ -36,6 +38,7 @@ namespace Radarr.Api.V3.ImportLists
resource.MinimumAvailability = definition.MinimumAvailability;
resource.ListType = definition.ListType;
resource.ListOrder = (int)definition.ListType;
resource.MinRefreshInterval = definition.MinRefreshInterval;
return resource;
}
@ -57,6 +60,7 @@ namespace Radarr.Api.V3.ImportLists
definition.ProfileId = resource.QualityProfileId;
definition.MinimumAvailability = resource.MinimumAvailability;
definition.ListType = resource.ListType;
definition.MinRefreshInterval = resource.MinRefreshInterval;
return definition;
}

View File

@ -1,21 +0,0 @@
using FluentValidation.Validators;
namespace Radarr.Http.Validation
{
public class ImportListSyncIntervalValidator : PropertyValidator
{
protected override string GetDefaultMessageTemplate() => "Must be greater than 6 hours";
protected override bool IsValid(PropertyValidatorContext context)
{
if (context.PropertyValue == null)
{
return true;
}
var value = (int)context.PropertyValue;
return value >= 6;
}
}
}

View File

@ -36,10 +36,5 @@ namespace Radarr.Http.Validation
{
return ruleBuilder.SetValidator(new RssSyncIntervalValidator());
}
public static IRuleBuilderOptions<T, int> IsValidImportListSyncInterval<T>(this IRuleBuilder<T, int> ruleBuilder)
{
return ruleBuilder.SetValidator(new ImportListSyncIntervalValidator());
}
}
}