New: (Apps) Add force sync indexers for applications

This commit is contained in:
Bogdan
2023-07-23 01:33:08 +03:00
parent e51b85449d
commit 72e6d66269
23 changed files with 256 additions and 232 deletions

View File

@@ -7,7 +7,7 @@ import HistoryConnector from 'History/HistoryConnector';
import IndexerIndex from 'Indexer/Index/IndexerIndex'; import IndexerIndex from 'Indexer/Index/IndexerIndex';
import IndexerStats from 'Indexer/Stats/IndexerStats'; import IndexerStats from 'Indexer/Stats/IndexerStats';
import SearchIndexConnector from 'Search/SearchIndexConnector'; import SearchIndexConnector from 'Search/SearchIndexConnector';
import ApplicationSettingsConnector from 'Settings/Applications/ApplicationSettingsConnector'; import ApplicationSettings from 'Settings/Applications/ApplicationSettings';
import DevelopmentSettingsConnector from 'Settings/Development/DevelopmentSettingsConnector'; import DevelopmentSettingsConnector from 'Settings/Development/DevelopmentSettingsConnector';
import DownloadClientSettingsConnector from 'Settings/DownloadClients/DownloadClientSettingsConnector'; import DownloadClientSettingsConnector from 'Settings/DownloadClients/DownloadClientSettingsConnector';
import GeneralSettingsConnector from 'Settings/General/GeneralSettingsConnector'; import GeneralSettingsConnector from 'Settings/General/GeneralSettingsConnector';
@@ -98,7 +98,7 @@ function AppRoutes(props) {
<Route <Route
path="/settings/applications" path="/settings/applications"
component={ApplicationSettingsConnector} component={ApplicationSettings}
/> />
<Route <Route

View File

@@ -16,7 +16,9 @@ export interface AppProfileAppState
export interface ApplicationAppState export interface ApplicationAppState
extends AppSectionState<Application>, extends AppSectionState<Application>,
AppSectionDeleteState, AppSectionDeleteState,
AppSectionSaveState {} AppSectionSaveState {
isTestingAll: boolean;
}
export interface DownloadClientAppState export interface DownloadClientAppState
extends AppSectionState<DownloadClient>, extends AppSectionState<DownloadClient>,

View File

@@ -45,9 +45,7 @@ import IndexerIndexTable from './Table/IndexerIndexTable';
import IndexerIndexTableOptions from './Table/IndexerIndexTableOptions'; import IndexerIndexTableOptions from './Table/IndexerIndexTableOptions';
import styles from './IndexerIndex.css'; import styles from './IndexerIndex.css';
function getViewComponent() { const getViewComponent = () => IndexerIndexTable;
return IndexerIndexTable;
}
interface IndexerIndexProps { interface IndexerIndexProps {
initialScrollTop?: number; initialScrollTop?: number;
@@ -84,14 +82,6 @@ const IndexerIndex = withScrollPosition((props: IndexerIndexProps) => {
); );
const [isSelectMode, setIsSelectMode] = useState(false); const [isSelectMode, setIsSelectMode] = useState(false);
const onAppIndexerSyncPress = useCallback(() => {
dispatch(
executeCommand({
name: APP_INDEXER_SYNC,
})
);
}, [dispatch]);
const onAddIndexerPress = useCallback(() => { const onAddIndexerPress = useCallback(() => {
setIsAddIndexerModalOpen(true); setIsAddIndexerModalOpen(true);
}, [setIsAddIndexerModalOpen]); }, [setIsAddIndexerModalOpen]);
@@ -108,6 +98,15 @@ const IndexerIndex = withScrollPosition((props: IndexerIndexProps) => {
setIsEditIndexerModalOpen(false); setIsEditIndexerModalOpen(false);
}, [setIsEditIndexerModalOpen]); }, [setIsEditIndexerModalOpen]);
const onAppIndexerSyncPress = useCallback(() => {
dispatch(
executeCommand({
name: APP_INDEXER_SYNC,
forceSync: true,
})
);
}, [dispatch]);
const onTestAllPress = useCallback(() => { const onTestAllPress = useCallback(() => {
dispatch(testAllIndexers()); dispatch(testAllIndexers());
}, [dispatch]); }, [dispatch]);

View File

@@ -1,103 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component, Fragment } from 'react';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { icons } from 'Helpers/Props';
import AppProfilesConnector from 'Settings/Profiles/App/AppProfilesConnector';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
import ApplicationsConnector from './Applications/ApplicationsConnector';
import ManageApplicationsModal from './Applications/Manage/ManageApplicationsModal';
class ApplicationSettings extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isManageApplicationsOpen: false
};
}
//
// Listeners
onManageApplicationsPress = () => {
this.setState({ isManageApplicationsOpen: true });
};
onManageApplicationsModalClose = () => {
this.setState({ isManageApplicationsOpen: false });
};
//
// Render
render() {
const {
isTestingAll,
isSyncingIndexers,
onTestAllPress,
onAppIndexerSyncPress
} = this.props;
const { isManageApplicationsOpen } = this.state;
return (
<PageContent title={translate('Applications')}>
<SettingsToolbarConnector
showSave={false}
additionalButtons={
<Fragment>
<PageToolbarSeparator />
<PageToolbarButton
label={translate('SyncAppIndexers')}
iconName={icons.REFRESH}
isSpinning={isSyncingIndexers}
onPress={onAppIndexerSyncPress}
/>
<PageToolbarButton
label={translate('TestAllApps')}
iconName={icons.TEST}
isSpinning={isTestingAll}
onPress={onTestAllPress}
/>
<PageToolbarButton
label={translate('ManageApplications')}
iconName={icons.MANAGE}
onPress={this.onManageApplicationsPress}
/>
</Fragment>
}
/>
<PageContentBody>
<ApplicationsConnector />
<AppProfilesConnector />
<ManageApplicationsModal
isOpen={isManageApplicationsOpen}
onModalClose={this.onManageApplicationsModalClose}
/>
</PageContentBody>
</PageContent>
);
}
}
ApplicationSettings.propTypes = {
isTestingAll: PropTypes.bool.isRequired,
isSyncingIndexers: PropTypes.bool.isRequired,
onTestAllPress: PropTypes.func.isRequired,
onAppIndexerSyncPress: PropTypes.func.isRequired
};
export default ApplicationSettings;

View File

@@ -0,0 +1,102 @@
import React, { Fragment, useCallback, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import AppState from 'App/State/AppState';
import { APP_INDEXER_SYNC } from 'Commands/commandNames';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { icons } from 'Helpers/Props';
import AppProfilesConnector from 'Settings/Profiles/App/AppProfilesConnector';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import { executeCommand } from 'Store/Actions/commandActions';
import { testAllApplications } from 'Store/Actions/Settings/applications';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import translate from 'Utilities/String/translate';
import ApplicationsConnector from './Applications/ApplicationsConnector';
import ManageApplicationsModal from './Applications/Manage/ManageApplicationsModal';
function ApplicationSettings() {
const isSyncingIndexers = useSelector(
createCommandExecutingSelector(APP_INDEXER_SYNC)
);
const isTestingAll = useSelector(
(state: AppState) => state.settings.applications.isTestingAll
);
const dispatch = useDispatch();
const [isManageApplicationsOpen, setIsManageApplicationsOpen] =
useState(false);
const onManageApplicationsPress = useCallback(() => {
setIsManageApplicationsOpen(true);
}, [setIsManageApplicationsOpen]);
const onManageApplicationsModalClose = useCallback(() => {
setIsManageApplicationsOpen(false);
}, [setIsManageApplicationsOpen]);
const onAppIndexerSyncPress = useCallback(() => {
dispatch(
executeCommand({
name: APP_INDEXER_SYNC,
forceSync: true,
})
);
}, [dispatch]);
const onTestAllPress = useCallback(() => {
dispatch(testAllApplications());
}, [dispatch]);
return (
<PageContent title={translate('Applications')}>
<SettingsToolbarConnector
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
showSave={false}
additionalButtons={
<Fragment>
<PageToolbarSeparator />
<PageToolbarButton
label={translate('SyncAppIndexers')}
iconName={icons.REFRESH}
isSpinning={isSyncingIndexers}
onPress={onAppIndexerSyncPress}
/>
<PageToolbarButton
label={translate('TestAllApps')}
iconName={icons.TEST}
isSpinning={isTestingAll}
onPress={onTestAllPress}
/>
<PageToolbarButton
label={translate('ManageApplications')}
iconName={icons.MANAGE}
onPress={onManageApplicationsPress}
/>
</Fragment>
}
/>
<PageContentBody>
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
{/* @ts-ignore */}
<ApplicationsConnector />
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
{/* @ts-ignore */}
<AppProfilesConnector />
<ManageApplicationsModal
isOpen={isManageApplicationsOpen}
onModalClose={onManageApplicationsModalClose}
/>
</PageContentBody>
</PageContent>
);
}
export default ApplicationSettings;

View File

@@ -1,35 +0,0 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import * as commandNames from 'Commands/commandNames';
import { executeCommand } from 'Store/Actions/commandActions';
import { testAllApplications } from 'Store/Actions/settingsActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import ApplicationSettings from './ApplicationSettings';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.applications.isTestingAll,
createCommandExecutingSelector(commandNames.APP_INDEXER_SYNC),
(isTestingAll, isSyncingIndexers) => {
return {
isTestingAll,
isSyncingIndexers
};
}
);
}
function mapDispatchToProps(dispatch, props) {
return {
onTestAllPress() {
dispatch(testAllApplications());
},
onAppIndexerSyncPress() {
dispatch(executeCommand({
name: commandNames.APP_INDEXER_SYNC
}));
}
};
}
export default connect(createMapStateToProps, mapDispatchToProps)(ApplicationSettings);

View File

@@ -54,7 +54,7 @@ namespace NzbDrone.Core.Applications
} }
public abstract void AddIndexer(IndexerDefinition indexer); public abstract void AddIndexer(IndexerDefinition indexer);
public abstract void UpdateIndexer(IndexerDefinition indexer); public abstract void UpdateIndexer(IndexerDefinition indexer, bool forceSync = false);
public abstract void RemoveIndexer(int indexerId); public abstract void RemoveIndexer(int indexerId);
public abstract List<AppIndexerMap> GetIndexerMappings(); public abstract List<AppIndexerMap> GetIndexerMappings();

View File

@@ -4,6 +4,13 @@ namespace NzbDrone.Core.Applications
{ {
public class ApplicationIndexerSyncCommand : Command public class ApplicationIndexerSyncCommand : Command
{ {
public bool ForceSync { get; set; }
public ApplicationIndexerSyncCommand()
{
ForceSync = false;
}
public override bool SendUpdatesToClient => true; public override bool SendUpdatesToClient => true;
public override string CompletionMessage => null; public override string CompletionMessage => null;

View File

@@ -104,7 +104,7 @@ namespace NzbDrone.Core.Applications
var indexers = _indexerFactory.AllProviders().Select(i => (IndexerDefinition)i.Definition).ToList(); var indexers = _indexerFactory.AllProviders().Select(i => (IndexerDefinition)i.Definition).ToList();
SyncIndexers(enabledApps, indexers, true); SyncIndexers(enabledApps, indexers, true, true);
} }
public void HandleAsync(ProviderBulkUpdatedEvent<IIndexer> message) public void HandleAsync(ProviderBulkUpdatedEvent<IIndexer> message)
@@ -122,10 +122,10 @@ namespace NzbDrone.Core.Applications
var indexers = _indexerFactory.AllProviders().Select(i => (IndexerDefinition)i.Definition).ToList(); var indexers = _indexerFactory.AllProviders().Select(i => (IndexerDefinition)i.Definition).ToList();
SyncIndexers(enabledApps, indexers, true); SyncIndexers(enabledApps, indexers, true, message.ForceSync);
} }
private void SyncIndexers(List<IApplication> applications, List<IndexerDefinition> indexers, bool removeRemote = false) private void SyncIndexers(List<IApplication> applications, List<IndexerDefinition> indexers, bool removeRemote = false, bool forceSync = false)
{ {
foreach (var app in applications) foreach (var app in applications)
{ {
@@ -165,7 +165,7 @@ namespace NzbDrone.Core.Applications
{ {
if (((ApplicationDefinition)app.Definition).SyncLevel == ApplicationSyncLevel.FullSync && ShouldHandleIndexer(app.Definition, indexer)) if (((ApplicationDefinition)app.Definition).SyncLevel == ApplicationSyncLevel.FullSync && ShouldHandleIndexer(app.Definition, indexer))
{ {
ExecuteAction(a => a.UpdateIndexer(definition), app); ExecuteAction(a => a.UpdateIndexer(definition, forceSync), app);
} }
} }
else else

View File

@@ -7,7 +7,7 @@ namespace NzbDrone.Core.Applications
public interface IApplication : IProvider public interface IApplication : IProvider
{ {
void AddIndexer(IndexerDefinition indexer); void AddIndexer(IndexerDefinition indexer);
void UpdateIndexer(IndexerDefinition indexer); void UpdateIndexer(IndexerDefinition indexer, bool forceSync = false);
void RemoveIndexer(int indexerId); void RemoveIndexer(int indexerId);
List<AppIndexerMap> GetIndexerMappings(); List<AppIndexerMap> GetIndexerMappings();
} }

View File

@@ -103,7 +103,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
} }
} }
public override void UpdateIndexer(IndexerDefinition indexer) public override void UpdateIndexer(IndexerDefinition indexer, bool forceSync = false)
{ {
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id); _logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
@@ -118,10 +118,12 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
if (remoteIndexer != null) if (remoteIndexer != null)
{ {
_logger.Debug("Remote indexer found, syncing with current settings"); _logger.Debug("Remote indexer {0} found", remoteIndexer.Name);
if (!lazyLibrarianIndexer.Equals(remoteIndexer)) if (!lazyLibrarianIndexer.Equals(remoteIndexer) || forceSync)
{ {
_logger.Debug("Syncing remote indexer with current settings");
_lazyLibrarianV1Proxy.UpdateIndexer(lazyLibrarianIndexer, Settings); _lazyLibrarianV1Proxy.UpdateIndexer(lazyLibrarianIndexer, Settings);
indexerMapping.RemoteIndexerName = $"{lazyLibrarianIndexer.Type},{lazyLibrarianIndexer.Altername}"; indexerMapping.RemoteIndexerName = $"{lazyLibrarianIndexer.Type},{lazyLibrarianIndexer.Altername}";
_appIndexerMapService.Update(indexerMapping); _appIndexerMapService.Update(indexerMapping);

View File

@@ -96,9 +96,15 @@ namespace NzbDrone.Core.Applications.Lidarr
foreach (var indexer in indexers) foreach (var indexer in indexers)
{ {
if ((string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value == _configFileProvider.ApiKey) var baseUrl = (string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl")?.Value ?? string.Empty;
if (!baseUrl.StartsWith(Settings.ProwlarrUrl.TrimEnd('/')) &&
(string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value != _configFileProvider.ApiKey)
{ {
var match = AppIndexerRegex.Match((string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value); continue;
}
var match = AppIndexerRegex.Match(baseUrl);
if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId))
{ {
@@ -106,7 +112,6 @@ namespace NzbDrone.Core.Applications.Lidarr
mappings.Add(new AppIndexerMap { IndexerId = indexerId, RemoteIndexerId = indexer.Id }); mappings.Add(new AppIndexerMap { IndexerId = indexerId, RemoteIndexerId = indexer.Id });
} }
} }
}
return mappings; return mappings;
} }
@@ -150,7 +155,7 @@ namespace NzbDrone.Core.Applications.Lidarr
} }
} }
public override void UpdateIndexer(IndexerDefinition indexer) public override void UpdateIndexer(IndexerDefinition indexer, bool forceSync = false)
{ {
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id); _logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
@@ -163,10 +168,12 @@ namespace NzbDrone.Core.Applications.Lidarr
if (remoteIndexer != null) if (remoteIndexer != null)
{ {
_logger.Debug("Remote indexer found, syncing with current settings"); _logger.Debug("Remote indexer {0} [{1}] found", remoteIndexer.Name, remoteIndexer.Id);
if (!lidarrIndexer.Equals(remoteIndexer)) if (!lidarrIndexer.Equals(remoteIndexer) || forceSync)
{ {
_logger.Debug("Syncing remote indexer with current settings");
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{ {
// Retain user fields not-affiliated with Prowlarr // Retain user fields not-affiliated with Prowlarr

View File

@@ -29,9 +29,12 @@ namespace NzbDrone.Core.Applications.Lidarr
} }
var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value;
var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value;
var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value);
var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value;
var otherApiKey = (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value;
var apiKeyCompare = apiKey == otherApiKey || otherApiKey == "********";
var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var apiPathCompare = apiPath.Equals(otherApiPath); var apiPathCompare = apiPath.Equals(otherApiPath);
@@ -59,7 +62,7 @@ namespace NzbDrone.Core.Applications.Lidarr
other.Implementation == Implementation && other.Implementation == Implementation &&
other.Priority == Priority && other.Priority == Priority &&
other.Id == Id && other.Id == Id &&
apiKey && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && discographySeedTimeCompare; apiKeyCompare && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && discographySeedTimeCompare;
} }
} }
} }

View File

@@ -103,7 +103,7 @@ namespace NzbDrone.Core.Applications.Mylar
} }
} }
public override void UpdateIndexer(IndexerDefinition indexer) public override void UpdateIndexer(IndexerDefinition indexer, bool forceSync = false)
{ {
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id); _logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
@@ -118,10 +118,12 @@ namespace NzbDrone.Core.Applications.Mylar
if (remoteIndexer != null) if (remoteIndexer != null)
{ {
_logger.Debug("Remote indexer found, syncing with current settings"); _logger.Debug("Remote indexer {0} found", remoteIndexer.Name);
if (!mylarIndexer.Equals(remoteIndexer)) if (!mylarIndexer.Equals(remoteIndexer) || forceSync)
{ {
_logger.Debug("Syncing remote indexer with current settings");
_mylarV3Proxy.UpdateIndexer(mylarIndexer, Settings); _mylarV3Proxy.UpdateIndexer(mylarIndexer, Settings);
indexerMapping.RemoteIndexerName = $"{mylarIndexer.Type},{mylarIndexer.Altername}"; indexerMapping.RemoteIndexerName = $"{mylarIndexer.Type},{mylarIndexer.Altername}";
_appIndexerMapService.Update(indexerMapping); _appIndexerMapService.Update(indexerMapping);

View File

@@ -96,9 +96,15 @@ namespace NzbDrone.Core.Applications.Radarr
foreach (var indexer in indexers) foreach (var indexer in indexers)
{ {
if ((string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value == _configFileProvider.ApiKey) var baseUrl = (string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl")?.Value ?? string.Empty;
if (!baseUrl.StartsWith(Settings.ProwlarrUrl.TrimEnd('/')) &&
(string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value != _configFileProvider.ApiKey)
{ {
var match = AppIndexerRegex.Match((string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value); continue;
}
var match = AppIndexerRegex.Match(baseUrl);
if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId))
{ {
@@ -106,7 +112,6 @@ namespace NzbDrone.Core.Applications.Radarr
mappings.Add(new AppIndexerMap { IndexerId = indexerId, RemoteIndexerId = indexer.Id }); mappings.Add(new AppIndexerMap { IndexerId = indexerId, RemoteIndexerId = indexer.Id });
} }
} }
}
return mappings; return mappings;
} }
@@ -150,7 +155,7 @@ namespace NzbDrone.Core.Applications.Radarr
} }
} }
public override void UpdateIndexer(IndexerDefinition indexer) public override void UpdateIndexer(IndexerDefinition indexer, bool forceSync = false)
{ {
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id); _logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
@@ -163,9 +168,9 @@ namespace NzbDrone.Core.Applications.Radarr
if (remoteIndexer != null) if (remoteIndexer != null)
{ {
_logger.Debug("Remote indexer found, syncing with current settings"); _logger.Debug("Remote indexer {0} [{1}] found", remoteIndexer.Name, remoteIndexer.Id);
if (!radarrIndexer.Equals(remoteIndexer)) if (!radarrIndexer.Equals(remoteIndexer) || forceSync)
{ {
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{ {

View File

@@ -29,9 +29,12 @@ namespace NzbDrone.Core.Applications.Radarr
} }
var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value;
var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value;
var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value);
var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value;
var otherApiKey = (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value;
var apiKeyCompare = apiKey == otherApiKey || otherApiKey == "********";
var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var apiPathCompare = apiPath.Equals(otherApiPath); var apiPathCompare = apiPath.Equals(otherApiPath);
@@ -55,7 +58,7 @@ namespace NzbDrone.Core.Applications.Radarr
other.Implementation == Implementation && other.Implementation == Implementation &&
other.Priority == Priority && other.Priority == Priority &&
other.Id == Id && other.Id == Id &&
apiKey && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; apiKeyCompare && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare;
} }
} }
} }

View File

@@ -90,15 +90,21 @@ namespace NzbDrone.Core.Applications.Readarr
public override List<AppIndexerMap> GetIndexerMappings() public override List<AppIndexerMap> GetIndexerMappings()
{ {
var indexers = _readarrV1Proxy.GetIndexers(Settings) var indexers = _readarrV1Proxy.GetIndexers(Settings)
.Where(i => i.Implementation == "Newznab" || i.Implementation == "Torznab"); .Where(i => i.Implementation is "Newznab" or "Torznab");
var mappings = new List<AppIndexerMap>(); var mappings = new List<AppIndexerMap>();
foreach (var indexer in indexers) foreach (var indexer in indexers)
{ {
if ((string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value == _configFileProvider.ApiKey) var baseUrl = (string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl")?.Value ?? string.Empty;
if (!baseUrl.StartsWith(Settings.ProwlarrUrl.TrimEnd('/')) &&
(string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value != _configFileProvider.ApiKey)
{ {
var match = AppIndexerRegex.Match((string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value); continue;
}
var match = AppIndexerRegex.Match(baseUrl);
if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId))
{ {
@@ -106,7 +112,6 @@ namespace NzbDrone.Core.Applications.Readarr
mappings.Add(new AppIndexerMap { IndexerId = indexerId, RemoteIndexerId = indexer.Id }); mappings.Add(new AppIndexerMap { IndexerId = indexerId, RemoteIndexerId = indexer.Id });
} }
} }
}
return mappings; return mappings;
} }
@@ -150,7 +155,7 @@ namespace NzbDrone.Core.Applications.Readarr
} }
} }
public override void UpdateIndexer(IndexerDefinition indexer) public override void UpdateIndexer(IndexerDefinition indexer, bool forceSync = false)
{ {
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id); _logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
@@ -163,10 +168,12 @@ namespace NzbDrone.Core.Applications.Readarr
if (remoteIndexer != null) if (remoteIndexer != null)
{ {
_logger.Debug("Remote indexer found, syncing with current settings"); _logger.Debug("Remote indexer {0} [{1}] found", remoteIndexer.Name, remoteIndexer.Id);
if (!readarrIndexer.Equals(remoteIndexer)) if (!readarrIndexer.Equals(remoteIndexer) || forceSync)
{ {
_logger.Debug("Syncing remote indexer with current settings");
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{ {
// Retain user fields not-affiliated with Prowlarr // Retain user fields not-affiliated with Prowlarr

View File

@@ -28,9 +28,12 @@ namespace NzbDrone.Core.Applications.Readarr
} }
var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value;
var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value;
var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value);
var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value;
var otherApiKey = (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value;
var apiKeyCompare = apiKey == otherApiKey || otherApiKey == "********";
var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var apiPathCompare = apiPath.Equals(otherApiPath); var apiPathCompare = apiPath.Equals(otherApiPath);
@@ -58,7 +61,7 @@ namespace NzbDrone.Core.Applications.Readarr
other.Implementation == Implementation && other.Implementation == Implementation &&
other.Priority == Priority && other.Priority == Priority &&
other.Id == Id && other.Id == Id &&
apiKey && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && discographySeedTimeCompare; apiKeyCompare && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && discographySeedTimeCompare;
} }
} }
} }

View File

@@ -100,9 +100,15 @@ namespace NzbDrone.Core.Applications.Sonarr
foreach (var indexer in indexers) foreach (var indexer in indexers)
{ {
if ((string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value == _configFileProvider.ApiKey) var baseUrl = (string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl")?.Value ?? string.Empty;
if (!baseUrl.StartsWith(Settings.ProwlarrUrl.TrimEnd('/')) &&
(string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value != _configFileProvider.ApiKey)
{ {
var match = AppIndexerRegex.Match((string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value); continue;
}
var match = AppIndexerRegex.Match(baseUrl);
if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId))
{ {
@@ -110,7 +116,6 @@ namespace NzbDrone.Core.Applications.Sonarr
mappings.Add(new AppIndexerMap { IndexerId = indexerId, RemoteIndexerId = indexer.Id }); mappings.Add(new AppIndexerMap { IndexerId = indexerId, RemoteIndexerId = indexer.Id });
} }
} }
}
return mappings; return mappings;
} }
@@ -155,7 +160,7 @@ namespace NzbDrone.Core.Applications.Sonarr
} }
} }
public override void UpdateIndexer(IndexerDefinition indexer) public override void UpdateIndexer(IndexerDefinition indexer, bool forceSync = false)
{ {
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id); _logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
@@ -168,10 +173,12 @@ namespace NzbDrone.Core.Applications.Sonarr
if (remoteIndexer != null) if (remoteIndexer != null)
{ {
_logger.Debug("Remote indexer found, syncing with current settings"); _logger.Debug("Remote indexer {0} [{1}] found", remoteIndexer.Name, remoteIndexer.Id);
if (!sonarrIndexer.Equals(remoteIndexer)) if (!sonarrIndexer.Equals(remoteIndexer) || forceSync)
{ {
_logger.Debug("Syncing remote indexer with current settings");
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()) if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any())
{ {
// Retain user fields not-affiliated with Prowlarr // Retain user fields not-affiliated with Prowlarr

View File

@@ -30,10 +30,13 @@ namespace NzbDrone.Core.Applications.Sonarr
} }
var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value;
var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value;
var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value);
var animeCats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "animeCategories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "animeCategories").Value); var animeCats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "animeCategories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "animeCategories").Value);
var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value;
var otherApiKey = (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value;
var apiKeyCompare = apiKey == otherApiKey || otherApiKey == "********";
var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var apiPathCompare = apiPath.Equals(otherApiPath); var apiPathCompare = apiPath.Equals(otherApiPath);
@@ -65,7 +68,7 @@ namespace NzbDrone.Core.Applications.Sonarr
other.Implementation == Implementation && other.Implementation == Implementation &&
other.Priority == Priority && other.Priority == Priority &&
other.Id == Id && other.Id == Id &&
apiKey && apiPathCompare && baseUrl && cats && animeCats && animeStandardFormatSearchCompare && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && seasonSeedTimeCompare; apiKeyCompare && apiPathCompare && baseUrl && cats && animeCats && animeStandardFormatSearchCompare && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && seasonSeedTimeCompare;
} }
} }
} }

View File

@@ -90,15 +90,21 @@ namespace NzbDrone.Core.Applications.Whisparr
public override List<AppIndexerMap> GetIndexerMappings() public override List<AppIndexerMap> GetIndexerMappings()
{ {
var indexers = _whisparrV3Proxy.GetIndexers(Settings) var indexers = _whisparrV3Proxy.GetIndexers(Settings)
.Where(i => i.Implementation == "Newznab" || i.Implementation == "Torznab"); .Where(i => i.Implementation is "Newznab" or "Torznab");
var mappings = new List<AppIndexerMap>(); var mappings = new List<AppIndexerMap>();
foreach (var indexer in indexers) foreach (var indexer in indexers)
{ {
if ((string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value == _configFileProvider.ApiKey) var baseUrl = (string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl")?.Value ?? string.Empty;
if (!baseUrl.StartsWith(Settings.ProwlarrUrl.TrimEnd('/')) &&
(string)indexer.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value != _configFileProvider.ApiKey)
{ {
var match = AppIndexerRegex.Match((string)indexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value); continue;
}
var match = AppIndexerRegex.Match(baseUrl);
if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId)) if (match.Groups["indexer"].Success && int.TryParse(match.Groups["indexer"].Value, out var indexerId))
{ {
@@ -106,7 +112,6 @@ namespace NzbDrone.Core.Applications.Whisparr
mappings.Add(new AppIndexerMap { IndexerId = indexerId, RemoteIndexerId = indexer.Id }); mappings.Add(new AppIndexerMap { IndexerId = indexerId, RemoteIndexerId = indexer.Id });
} }
} }
}
return mappings; return mappings;
} }
@@ -150,7 +155,7 @@ namespace NzbDrone.Core.Applications.Whisparr
} }
} }
public override void UpdateIndexer(IndexerDefinition indexer) public override void UpdateIndexer(IndexerDefinition indexer, bool forceSync = false)
{ {
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id); _logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
@@ -163,10 +168,12 @@ namespace NzbDrone.Core.Applications.Whisparr
if (remoteIndexer != null) if (remoteIndexer != null)
{ {
_logger.Debug("Remote indexer found, syncing with current settings"); _logger.Debug("Remote indexer {0} [{1}] found", remoteIndexer.Name, remoteIndexer.Id);
if (!whisparrIndexer.Equals(remoteIndexer)) if (!whisparrIndexer.Equals(remoteIndexer) || forceSync)
{ {
_logger.Debug("Syncing remote indexer with current settings");
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any()) if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{ {
// Retain user fields not-affiliated with Prowlarr // Retain user fields not-affiliated with Prowlarr

View File

@@ -28,9 +28,12 @@ namespace NzbDrone.Core.Applications.Whisparr
} }
var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value; var baseUrl = (string)Fields.FirstOrDefault(x => x.Name == "baseUrl").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value;
var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey").Value == (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey").Value;
var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value); var cats = JToken.DeepEquals((JArray)Fields.FirstOrDefault(x => x.Name == "categories").Value, (JArray)other.Fields.FirstOrDefault(x => x.Name == "categories").Value);
var apiKey = (string)Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value;
var otherApiKey = (string)other.Fields.FirstOrDefault(x => x.Name == "apiKey")?.Value;
var apiKeyCompare = apiKey == otherApiKey || otherApiKey == "********";
var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var apiPath = Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value; var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var apiPathCompare = apiPath.Equals(otherApiPath); var apiPathCompare = apiPath.Equals(otherApiPath);
@@ -54,7 +57,7 @@ namespace NzbDrone.Core.Applications.Whisparr
other.Implementation == Implementation && other.Implementation == Implementation &&
other.Priority == Priority && other.Priority == Priority &&
other.Id == Id && other.Id == Id &&
apiKey && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare; apiKeyCompare && apiPathCompare && baseUrl && cats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare;
} }
} }
} }

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.Datastore.Events;
@@ -7,7 +8,6 @@ using NzbDrone.Core.ThingiProvider.Events;
using NzbDrone.SignalR; using NzbDrone.SignalR;
using Prowlarr.Http; using Prowlarr.Http;
using Prowlarr.Http.REST; using Prowlarr.Http.REST;
using NotImplementedException = System.NotImplementedException;
namespace Prowlarr.Api.V1.Indexers namespace Prowlarr.Api.V1.Indexers
{ {