diff --git a/frontend/src/Components/Page/PageConnector.js b/frontend/src/Components/Page/PageConnector.js
index 889f559af..5f66ad81e 100644
--- a/frontend/src/Components/Page/PageConnector.js
+++ b/frontend/src/Components/Page/PageConnector.js
@@ -6,6 +6,7 @@ import { createSelector } from 'reselect';
import { saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions';
import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
import { fetchIndexers } from 'Store/Actions/indexerActions';
+import { fetchIndexerStatus } from 'Store/Actions/indexerStatusActions';
import { fetchIndexerCategories, fetchIndexerFlags, fetchLanguages, fetchUISettings } from 'Store/Actions/settingsActions';
import { fetchStatus } from 'Store/Actions/systemActions';
import { fetchTags } from 'Store/Actions/tagActions';
@@ -48,6 +49,7 @@ const selectIsPopulated = createSelector(
(state) => state.settings.ui.isPopulated,
(state) => state.settings.languages.isPopulated,
(state) => state.indexers.isPopulated,
+ (state) => state.indexerStatus.isPopulated,
(state) => state.settings.indexerCategories.isPopulated,
(state) => state.settings.indexerFlags.isPopulated,
(state) => state.system.status.isPopulated,
@@ -57,6 +59,7 @@ const selectIsPopulated = createSelector(
uiSettingsIsPopulated,
languagesIsPopulated,
indexersIsPopulated,
+ indexerStatusIsPopulated,
indexerCategoriesIsPopulated,
indexerFlagsIsPopulated,
systemStatusIsPopulated
@@ -67,6 +70,7 @@ const selectIsPopulated = createSelector(
uiSettingsIsPopulated &&
languagesIsPopulated &&
indexersIsPopulated &&
+ indexerStatusIsPopulated &&
indexerCategoriesIsPopulated &&
indexerFlagsIsPopulated &&
systemStatusIsPopulated
@@ -80,6 +84,7 @@ const selectErrors = createSelector(
(state) => state.settings.ui.error,
(state) => state.settings.languages.error,
(state) => state.indexers.error,
+ (state) => state.indexerStatus.error,
(state) => state.settings.indexerCategories.error,
(state) => state.settings.indexerFlags.error,
(state) => state.system.status.error,
@@ -89,6 +94,7 @@ const selectErrors = createSelector(
uiSettingsError,
languagesError,
indexersError,
+ indexerStatusError,
indexerCategoriesError,
indexerFlagsError,
systemStatusError
@@ -99,6 +105,7 @@ const selectErrors = createSelector(
uiSettingsError ||
languagesError ||
indexersError ||
+ indexerStatusError ||
indexerCategoriesError ||
indexerFlagsError ||
systemStatusError
@@ -111,6 +118,7 @@ const selectErrors = createSelector(
uiSettingsError,
languagesError,
indexersError,
+ indexerStatusError,
indexerCategoriesError,
indexerFlagsError,
systemStatusError
@@ -157,6 +165,9 @@ function createMapDispatchToProps(dispatch, props) {
dispatchFetchIndexers() {
dispatch(fetchIndexers());
},
+ dispatchFetchIndexerStatus() {
+ dispatch(fetchIndexerStatus());
+ },
dispatchFetchIndexerCategories() {
dispatch(fetchIndexerCategories());
},
@@ -197,6 +208,7 @@ class PageConnector extends Component {
this.props.dispatchFetchTags();
this.props.dispatchFetchLanguages();
this.props.dispatchFetchIndexers();
+ this.props.dispatchFetchIndexerStatus();
this.props.dispatchFetchIndexerCategories();
this.props.dispatchFetchIndexerFlags();
this.props.dispatchFetchUISettings();
@@ -221,6 +233,7 @@ class PageConnector extends Component {
dispatchFetchTags,
dispatchFetchLanguages,
dispatchFetchIndexers,
+ dispatchFetchIndexerStatus,
dispatchFetchIndexerCategories,
dispatchFetchIndexerFlags,
dispatchFetchUISettings,
@@ -260,6 +273,7 @@ PageConnector.propTypes = {
dispatchFetchTags: PropTypes.func.isRequired,
dispatchFetchLanguages: PropTypes.func.isRequired,
dispatchFetchIndexers: PropTypes.func.isRequired,
+ dispatchFetchIndexerStatus: PropTypes.func.isRequired,
dispatchFetchIndexerCategories: PropTypes.func.isRequired,
dispatchFetchIndexerFlags: PropTypes.func.isRequired,
dispatchFetchUISettings: PropTypes.func.isRequired,
diff --git a/frontend/src/Indexer/Index/MovieIndexItemConnector.js b/frontend/src/Indexer/Index/MovieIndexItemConnector.js
index 6a573d3a6..ef1f6c002 100644
--- a/frontend/src/Indexer/Index/MovieIndexItemConnector.js
+++ b/frontend/src/Indexer/Index/MovieIndexItemConnector.js
@@ -6,6 +6,8 @@ import * as commandNames from 'Commands/commandNames';
import { executeCommand } from 'Store/Actions/commandActions';
import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector';
import createIndexerSelector from 'Store/Selectors/createIndexerSelector';
+import createIndexerStatusSelector from 'Store/Selectors/createIndexerStatusSelector';
+import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
function selectShowSearchAction() {
return createSelector(
@@ -19,12 +21,16 @@ function selectShowSearchAction() {
function createMapStateToProps() {
return createSelector(
createIndexerSelector(),
+ createIndexerStatusSelector(),
selectShowSearchAction(),
createExecutingCommandsSelector(),
+ createUISettingsSelector(),
(
movie,
+ status,
showSearchAction,
- executingCommands
+ executingCommands,
+ uiSettings
) => {
// If a movie is deleted this selector may fire before the parent
@@ -32,6 +38,8 @@ function createMapStateToProps() {
// we want to return early here and again in the render function to avoid
// trying to show a movie that has no information available.
+ console.log(status);
+
if (!movie) {
return {};
}
@@ -52,9 +60,12 @@ function createMapStateToProps() {
return {
...movie,
+ status,
showSearchAction,
isRefreshingMovie,
- isSearchingMovie
+ isSearchingMovie,
+ longDateFormat: uiSettings.longDateFormat,
+ timeFormat: uiSettings.timeFormat
};
}
);
diff --git a/frontend/src/Indexer/Index/Table/IndexerStatusCell.js b/frontend/src/Indexer/Index/Table/IndexerStatusCell.js
index 4fd53220c..2c3191aa2 100644
--- a/frontend/src/Indexer/Index/Table/IndexerStatusCell.js
+++ b/frontend/src/Indexer/Index/Table/IndexerStatusCell.js
@@ -3,12 +3,16 @@ import React from 'react';
import Icon from 'Components/Icon';
import VirtualTableRowCell from 'Components/Table/Cells/TableRowCell';
import { icons, kinds } from 'Helpers/Props';
+import formatDateTime from 'Utilities/Date/formatDateTime';
import styles from './IndexerStatusCell.css';
function IndexerStatusCell(props) {
const {
className,
enabled,
+ status,
+ longDateFormat,
+ timeFormat,
component: Component,
...otherProps
} = props;
@@ -26,6 +30,15 @@ function IndexerStatusCell(props) {
title={enabled ? 'Indexer is Enabled' : 'Indexer is Disabled'}
/>
}
+ {
+ status &&
+
+ }
);
}
@@ -33,6 +46,9 @@ function IndexerStatusCell(props) {
IndexerStatusCell.propTypes = {
className: PropTypes.string.isRequired,
enabled: PropTypes.bool.isRequired,
+ status: PropTypes.object,
+ longDateFormat: PropTypes.string.isRequired,
+ timeFormat: PropTypes.string.isRequired,
component: PropTypes.elementType
};
diff --git a/frontend/src/Indexer/Index/Table/MovieIndexRow.js b/frontend/src/Indexer/Index/Table/MovieIndexRow.js
index c220b3944..9cf216bf2 100644
--- a/frontend/src/Indexer/Index/Table/MovieIndexRow.js
+++ b/frontend/src/Indexer/Index/Table/MovieIndexRow.js
@@ -68,9 +68,12 @@ class MovieIndexRow extends Component {
protocol,
privacy,
priority,
+ status,
added,
capabilities,
columns,
+ longDateFormat,
+ timeFormat,
isMovieEditorActive,
isSelected,
onSelectedChange
@@ -113,6 +116,8 @@ class MovieIndexRow extends Component {
className={styles[column.name]}
enabled={enableRss || enableAutomaticSearch || enableInteractiveSearch}
status={status}
+ longDateFormat={longDateFormat}
+ timeFormat={timeFormat}
component={VirtualTableRowCell}
/>
);
@@ -253,6 +258,7 @@ MovieIndexRow.propTypes = {
enableRss: PropTypes.bool.isRequired,
enableAutomaticSearch: PropTypes.bool.isRequired,
enableInteractiveSearch: PropTypes.bool.isRequired,
+ status: PropTypes.object,
capabilities: PropTypes.object.isRequired,
added: PropTypes.string.isRequired,
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
@@ -260,7 +266,9 @@ MovieIndexRow.propTypes = {
isSearchingMovie: PropTypes.bool.isRequired,
isMovieEditorActive: PropTypes.bool.isRequired,
isSelected: PropTypes.bool,
- onSelectedChange: PropTypes.func.isRequired
+ onSelectedChange: PropTypes.func.isRequired,
+ longDateFormat: PropTypes.string.isRequired,
+ timeFormat: PropTypes.string.isRequired
};
MovieIndexRow.defaultProps = {
diff --git a/frontend/src/Store/Actions/index.js b/frontend/src/Store/Actions/index.js
index ff8981a58..cdb94861e 100644
--- a/frontend/src/Store/Actions/index.js
+++ b/frontend/src/Store/Actions/index.js
@@ -6,6 +6,7 @@ import * as history from './historyActions';
import * as indexers from './indexerActions';
import * as indexerIndex from './indexerIndexActions';
import * as indexerStats from './indexerStatsActions';
+import * as indexerStatus from './indexerStatusActions';
import * as movies from './movieActions';
import * as oAuth from './oAuthActions';
import * as paths from './pathActions';
@@ -29,6 +30,7 @@ export default [
indexers,
indexerIndex,
indexerStats,
+ indexerStatus,
settings,
system,
tags
diff --git a/frontend/src/Store/Actions/indexerStatusActions.js b/frontend/src/Store/Actions/indexerStatusActions.js
new file mode 100644
index 000000000..07ba81ff6
--- /dev/null
+++ b/frontend/src/Store/Actions/indexerStatusActions.js
@@ -0,0 +1,46 @@
+import { createThunk, handleThunks } from 'Store/thunks';
+import createFetchHandler from './Creators/createFetchHandler';
+import createHandleActions from './Creators/createHandleActions';
+
+//
+// Variables
+
+export const section = 'indexerStatus';
+
+//
+// State
+
+export const defaultState = {
+ isFetching: false,
+ isPopulated: false,
+ error: null,
+ items: [],
+
+ details: {
+ isFetching: false,
+ isPopulated: false,
+ error: null,
+ items: []
+ }
+};
+
+//
+// Actions Types
+
+export const FETCH_INDEXER_STATUS = 'indexerStatus/fetchIndexerStatus';
+
+//
+// Action Creators
+
+export const fetchIndexerStatus = createThunk(FETCH_INDEXER_STATUS);
+
+//
+// Action Handlers
+
+export const actionHandlers = handleThunks({
+ [FETCH_INDEXER_STATUS]: createFetchHandler(section, '/indexerStatus')
+});
+
+//
+// Reducers
+export const reducers = createHandleActions({}, defaultState, section);
diff --git a/frontend/src/Store/Selectors/createIndexerStatusSelector.js b/frontend/src/Store/Selectors/createIndexerStatusSelector.js
new file mode 100644
index 000000000..e25d618fe
--- /dev/null
+++ b/frontend/src/Store/Selectors/createIndexerStatusSelector.js
@@ -0,0 +1,14 @@
+import _ from 'lodash';
+import { createSelector } from 'reselect';
+
+function createIndexerStatusSelector() {
+ return createSelector(
+ (state, { indexerId }) => indexerId,
+ (state) => state.indexerStatus.items,
+ (indexerId, indexerStatus) => {
+ return _.find(indexerStatus, { indexerId });
+ }
+ );
+}
+
+export default createIndexerStatusSelector;
diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs
index beae8724b..c990a2813 100644
--- a/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs
+++ b/src/Prowlarr.Api.V1/Indexers/IndexerResource.cs
@@ -20,6 +20,7 @@ namespace Prowlarr.Api.V1.Indexers
public IndexerCapabilityResource Capabilities { get; set; }
public int Priority { get; set; }
public DateTime Added { get; set; }
+ public IndexerStatusResource Status { get; set; }
}
public class IndexerResourceMapper : ProviderResourceMapper
diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerStatusModule.cs b/src/Prowlarr.Api.V1/Indexers/IndexerStatusModule.cs
new file mode 100644
index 000000000..017a107c1
--- /dev/null
+++ b/src/Prowlarr.Api.V1/Indexers/IndexerStatusModule.cs
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+using NzbDrone.Core.Indexers;
+using Prowlarr.Http;
+
+namespace Prowlarr.Api.V1.Indexers
+{
+ public class IndexerStatusModule : ProwlarrRestModule
+ {
+ private readonly IIndexerStatusService _indexerStatusService;
+
+ public IndexerStatusModule(IIndexerStatusService indexerStatusService)
+ {
+ _indexerStatusService = indexerStatusService;
+
+ GetResourceAll = GetAll;
+ }
+
+ private List GetAll()
+ {
+ return _indexerStatusService.GetBlockedProviders().ToResource();
+ }
+ }
+}
diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerStatusResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerStatusResource.cs
new file mode 100644
index 000000000..e624440a1
--- /dev/null
+++ b/src/Prowlarr.Api.V1/Indexers/IndexerStatusResource.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NzbDrone.Core.Indexers;
+using Prowlarr.Http.REST;
+
+namespace Prowlarr.Api.V1.Indexers
+{
+ public class IndexerStatusResource : RestResource
+ {
+ public int IndexerId { get; set; }
+ public DateTime? DisabledTill { get; set; }
+ }
+
+ public static class IndexerStatusResourceMapper
+ {
+ public static IndexerStatusResource ToResource(this IndexerStatus model)
+ {
+ if (model == null)
+ {
+ return null;
+ }
+
+ return new IndexerStatusResource
+ {
+ IndexerId = model.ProviderId,
+ DisabledTill = model.DisabledTill
+ };
+ }
+
+ public static List ToResource(this IEnumerable models)
+ {
+ return models.Select(ToResource).ToList();
+ }
+ }
+}