indexers
+ createTagsSelector(),
+ (indexers, tagList) => {
+ return {
+ ...indexers,
+ tagList
+ };
+ }
);
}
diff --git a/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js b/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js
index 1809aa264..7a08123bb 100644
--- a/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js
+++ b/frontend/src/Settings/Tags/Details/TagDetailsModalContent.js
@@ -21,6 +21,7 @@ function TagDetailsModalContent(props) {
importLists,
notifications,
releaseProfiles,
+ indexers,
onModalClose,
onDeleteTagPress
} = props;
@@ -38,7 +39,7 @@ function TagDetailsModalContent(props) {
}
{
- !!series.length &&
+ series.length ?
+ :
+ null
}
{
- !!delayProfiles.length &&
+ delayProfiles.length ?
+ :
+ null
}
{
- !!notifications.length &&
+ notifications.length ?
+ :
+ null
}
{
- !!importLists.length &&
+ importLists.length ?
+ :
+ null
}
{
- !!releaseProfiles.length &&
+ releaseProfiles.length ?
+ :
+ null
+ }
+
+ {
+ indexers.length ?
+ :
+ null
}
@@ -189,6 +211,7 @@ TagDetailsModalContent.propTypes = {
importLists: PropTypes.arrayOf(PropTypes.object).isRequired,
notifications: PropTypes.arrayOf(PropTypes.object).isRequired,
releaseProfiles: PropTypes.arrayOf(PropTypes.object).isRequired,
+ indexers: PropTypes.arrayOf(PropTypes.object).isRequired,
onModalClose: PropTypes.func.isRequired,
onDeleteTagPress: PropTypes.func.isRequired
};
diff --git a/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js b/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js
index 470dbb059..71948e1e2 100644
--- a/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js
+++ b/frontend/src/Settings/Tags/Details/TagDetailsModalContentConnector.js
@@ -69,6 +69,14 @@ function createMatchingReleaseProfilesSelector() {
);
}
+function createMatchingIndexersSelector() {
+ return createSelector(
+ (state, { indexerIds }) => indexerIds,
+ (state) => state.settings.indexers.items,
+ findMatchingItems
+ );
+}
+
function createMapStateToProps() {
return createSelector(
createMatchingSeriesSelector(),
@@ -76,13 +84,15 @@ function createMapStateToProps() {
createMatchingImportListsSelector(),
createMatchingNotificationsSelector(),
createMatchingReleaseProfilesSelector(),
- (series, delayProfiles, importLists, notifications, releaseProfiles) => {
+ createMatchingIndexersSelector(),
+ (series, delayProfiles, importLists, notifications, releaseProfiles, indexers) => {
return {
series,
delayProfiles,
importLists,
notifications,
- releaseProfiles
+ releaseProfiles,
+ indexers
};
}
);
diff --git a/frontend/src/Settings/Tags/Tag.js b/frontend/src/Settings/Tags/Tag.js
index 00a13ec82..b610c1cbb 100644
--- a/frontend/src/Settings/Tags/Tag.js
+++ b/frontend/src/Settings/Tags/Tag.js
@@ -56,6 +56,7 @@ class Tag extends Component {
importListIds,
notificationIds,
restrictionIds,
+ indexerIds,
seriesIds
} = this.props;
@@ -69,6 +70,7 @@ class Tag extends Component {
importListIds.length ||
notificationIds.length ||
restrictionIds.length ||
+ indexerIds.length ||
seriesIds.length
);
@@ -124,6 +126,14 @@ class Tag extends Component {
:
null
}
+
+ {
+ indexerIds.length ?
+
+ {indexerIds.length} indexer{indexerIds.length > 1 && 's'}
+
:
+ null
+ }
}
@@ -142,6 +152,7 @@ class Tag extends Component {
importListIds={importListIds}
notificationIds={notificationIds}
restrictionIds={restrictionIds}
+ indexerIds={indexerIds}
isOpen={isDetailsModalOpen}
onModalClose={this.onDetailsModalClose}
onDeleteTagPress={this.onDeleteTagPress}
@@ -168,6 +179,7 @@ Tag.propTypes = {
importListIds: PropTypes.arrayOf(PropTypes.number).isRequired,
notificationIds: PropTypes.arrayOf(PropTypes.number).isRequired,
restrictionIds: PropTypes.arrayOf(PropTypes.number).isRequired,
+ indexerIds: PropTypes.arrayOf(PropTypes.number).isRequired,
seriesIds: PropTypes.arrayOf(PropTypes.number).isRequired,
onConfirmDeleteTag: PropTypes.func.isRequired
};
@@ -177,6 +189,7 @@ Tag.defaultProps = {
importListIds: [],
notificationIds: [],
restrictionIds: [],
+ indexerIds: [],
seriesIds: []
};
diff --git a/frontend/src/Settings/Tags/TagsConnector.js b/frontend/src/Settings/Tags/TagsConnector.js
index 70b727387..4b3cce22b 100644
--- a/frontend/src/Settings/Tags/TagsConnector.js
+++ b/frontend/src/Settings/Tags/TagsConnector.js
@@ -3,7 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchTagDetails } from 'Store/Actions/tagActions';
-import { fetchDelayProfiles, fetchNotifications, fetchReleaseProfiles, fetchImportLists } from 'Store/Actions/settingsActions';
+import { fetchDelayProfiles, fetchNotifications, fetchReleaseProfiles, fetchImportLists, fetchIndexers } from 'Store/Actions/settingsActions';
import Tags from './Tags';
function createMapStateToProps() {
@@ -29,7 +29,8 @@ const mapDispatchToProps = {
dispatchFetchDelayProfiles: fetchDelayProfiles,
dispatchFetchImportLists: fetchImportLists,
dispatchFetchNotifications: fetchNotifications,
- dispatchFetchReleaseProfiles: fetchReleaseProfiles
+ dispatchFetchReleaseProfiles: fetchReleaseProfiles,
+ dispatchFetchIndexers: fetchIndexers
};
class MetadatasConnector extends Component {
@@ -43,7 +44,8 @@ class MetadatasConnector extends Component {
dispatchFetchDelayProfiles,
dispatchFetchImportLists,
dispatchFetchNotifications,
- dispatchFetchReleaseProfiles
+ dispatchFetchReleaseProfiles,
+ dispatchFetchIndexers
} = this.props;
dispatchFetchTagDetails();
@@ -51,6 +53,7 @@ class MetadatasConnector extends Component {
dispatchFetchImportLists();
dispatchFetchNotifications();
dispatchFetchReleaseProfiles();
+ dispatchFetchIndexers();
}
//
@@ -70,7 +73,8 @@ MetadatasConnector.propTypes = {
dispatchFetchDelayProfiles: PropTypes.func.isRequired,
dispatchFetchImportLists: PropTypes.func.isRequired,
dispatchFetchNotifications: PropTypes.func.isRequired,
- dispatchFetchReleaseProfiles: PropTypes.func.isRequired
+ dispatchFetchReleaseProfiles: PropTypes.func.isRequired,
+ dispatchFetchIndexers: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(MetadatasConnector);
diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/MonitoredEpisodeSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/MonitoredEpisodeSpecificationFixture.cs
index b83e5a1ed..d81e67f27 100644
--- a/src/NzbDrone.Core.Test/DecisionEngineTests/MonitoredEpisodeSpecificationFixture.cs
+++ b/src/NzbDrone.Core.Test/DecisionEngineTests/MonitoredEpisodeSpecificationFixture.cs
@@ -5,8 +5,8 @@ using NUnit.Framework;
using NzbDrone.Core.DecisionEngine.Specifications.RssSync;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
-using NzbDrone.Core.Tv;
using NzbDrone.Core.Test.Framework;
+using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.DecisionEngineTests
{
diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/IndexerTagSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/IndexerTagSpecificationFixture.cs
new file mode 100644
index 000000000..bc15bf276
--- /dev/null
+++ b/src/NzbDrone.Core.Test/DecisionEngineTests/RssSync/IndexerTagSpecificationFixture.cs
@@ -0,0 +1,110 @@
+using System.Collections.Generic;
+using FizzWare.NBuilder;
+using FluentAssertions;
+using Moq;
+using NUnit.Framework;
+using NzbDrone.Core.DecisionEngine.Specifications.RssSync;
+using NzbDrone.Core.Indexers;
+using NzbDrone.Core.IndexerSearch.Definitions;
+using NzbDrone.Core.Parser.Model;
+using NzbDrone.Core.Test.Framework;
+using NzbDrone.Core.Tv;
+
+namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
+{
+ [TestFixture]
+ public class IndexerTagSpecificationFixture : CoreTest
+ {
+ private IndexerTagSpecification _specification;
+
+ private RemoteEpisode _parseResultMulti;
+ private IndexerDefinition _fakeIndexerDefinition;
+ private Series _fakeSeries;
+ private Episode _firstEpisode;
+ private Episode _secondEpisode;
+ private ReleaseInfo _fakeRelease;
+
+ [SetUp]
+ public void Setup()
+ {
+ _fakeIndexerDefinition = new IndexerDefinition
+ {
+ Tags = new HashSet()
+ };
+
+ Mocker
+ .GetMock()
+ .Setup(m => m.Get(It.IsAny()))
+ .Returns(_fakeIndexerDefinition);
+
+ _specification = Mocker.Resolve();
+
+ _fakeSeries = Builder.CreateNew()
+ .With(c => c.Monitored = true)
+ .With(c => c.Tags = new HashSet())
+ .Build();
+
+ _fakeRelease = new ReleaseInfo
+ {
+ IndexerId = 1
+ };
+
+ _firstEpisode = new Episode { Monitored = true };
+ _secondEpisode = new Episode { Monitored = true };
+
+ var doubleEpisodeList = new List { _firstEpisode, _secondEpisode };
+
+ _parseResultMulti = new RemoteEpisode
+ {
+ Series = _fakeSeries,
+ Episodes = doubleEpisodeList,
+ Release = _fakeRelease
+ };
+ }
+
+ [Test]
+ public void indexer_and_series_without_tags_should_return_true()
+ {
+ _fakeIndexerDefinition.Tags = new HashSet();
+ _fakeSeries.Tags = new HashSet();
+
+ _specification.IsSatisfiedBy(_parseResultMulti, new SingleEpisodeSearchCriteria { MonitoredEpisodesOnly = true }).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void indexer_with_tags_series_without_tags_should_return_false()
+ {
+ _fakeIndexerDefinition.Tags = new HashSet { 123 };
+ _fakeSeries.Tags = new HashSet();
+
+ _specification.IsSatisfiedBy(_parseResultMulti, new SingleEpisodeSearchCriteria { MonitoredEpisodesOnly = true }).Accepted.Should().BeFalse();
+ }
+
+ [Test]
+ public void indexer_without_tags_series_with_tags_should_return_true()
+ {
+ _fakeIndexerDefinition.Tags = new HashSet();
+ _fakeSeries.Tags = new HashSet { 123 };
+
+ _specification.IsSatisfiedBy(_parseResultMulti, new SingleEpisodeSearchCriteria { MonitoredEpisodesOnly = true }).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void indexer_with_tags_series_with_matching_tags_should_return_true()
+ {
+ _fakeIndexerDefinition.Tags = new HashSet { 123, 456 };
+ _fakeSeries.Tags = new HashSet { 123, 789 };
+
+ _specification.IsSatisfiedBy(_parseResultMulti, new SingleEpisodeSearchCriteria { MonitoredEpisodesOnly = true }).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void indexer_with_tags_series_with_different_tags_should_return_false()
+ {
+ _fakeIndexerDefinition.Tags = new HashSet { 456 };
+ _fakeSeries.Tags = new HashSet { 123, 789 };
+
+ _specification.IsSatisfiedBy(_parseResultMulti, new SingleEpisodeSearchCriteria { MonitoredEpisodesOnly = true }).Accepted.Should().BeFalse();
+ }
+ }
+}
diff --git a/src/NzbDrone.Core.Test/IndexerSearchTests/NzbSearchServiceFixture.cs b/src/NzbDrone.Core.Test/IndexerSearchTests/NzbSearchServiceFixture.cs
index da95f78d8..44482d1c1 100644
--- a/src/NzbDrone.Core.Test/IndexerSearchTests/NzbSearchServiceFixture.cs
+++ b/src/NzbDrone.Core.Test/IndexerSearchTests/NzbSearchServiceFixture.cs
@@ -135,6 +135,114 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
return result;
}
+ [Test]
+ public void Tags_IndexerTags_SeriesNoTags_IndexerNotIncluded()
+ {
+ _mockIndexer.SetupGet(s => s.Definition).Returns(new IndexerDefinition {
+ Id = 1,
+ Tags = new HashSet { 3 }
+ });
+
+ WithEpisodes();
+
+ var allCriteria = WatchForSearchCriteria();
+
+ Subject.EpisodeSearch(_xemEpisodes.First(), true, false);
+
+ var criteria = allCriteria.OfType().ToList();
+
+ criteria.Count.Should().Be(0);
+ }
+
+ [Test]
+ public void Tags_IndexerNoTags_SeriesTags_IndexerIncluded()
+ {
+ _mockIndexer.SetupGet(s => s.Definition).Returns(new IndexerDefinition
+ {
+ Id = 1
+ });
+
+ _xemSeries = Builder.CreateNew()
+ .With(v => v.UseSceneNumbering = true)
+ .With(v => v.Monitored = true)
+ .With(v => v.Tags = new HashSet { 3 })
+ .Build();
+
+ Mocker.GetMock()
+ .Setup(v => v.GetSeries(_xemSeries.Id))
+ .Returns(_xemSeries);
+
+ WithEpisodes();
+
+ var allCriteria = WatchForSearchCriteria();
+
+ Subject.EpisodeSearch(_xemEpisodes.First(), true, false);
+
+ var criteria = allCriteria.OfType().ToList();
+
+ criteria.Count.Should().Be(1);
+ }
+
+ [Test]
+ public void Tags_IndexerAndSeriesTagsMatch_IndexerIncluded()
+ {
+ _mockIndexer.SetupGet(s => s.Definition).Returns(new IndexerDefinition
+ {
+ Id = 1,
+ Tags = new HashSet { 1, 2, 3 }
+ });
+
+ _xemSeries = Builder.CreateNew()
+ .With(v => v.UseSceneNumbering = true)
+ .With(v => v.Monitored = true)
+ .With(v => v.Tags = new HashSet { 3, 4, 5 })
+ .Build();
+
+ Mocker.GetMock()
+ .Setup(v => v.GetSeries(_xemSeries.Id))
+ .Returns(_xemSeries);
+
+ WithEpisodes();
+
+ var allCriteria = WatchForSearchCriteria();
+
+ Subject.EpisodeSearch(_xemEpisodes.First(), true, false);
+
+ var criteria = allCriteria.OfType().ToList();
+
+ criteria.Count.Should().Be(1);
+ }
+
+ [Test]
+ public void Tags_IndexerAndSeriesTagsMismatch_IndexerNotIncluded()
+ {
+ _mockIndexer.SetupGet(s => s.Definition).Returns(new IndexerDefinition
+ {
+ Id = 1,
+ Tags = new HashSet { 1, 2, 3 }
+ });
+
+ _xemSeries = Builder.CreateNew()
+ .With(v => v.UseSceneNumbering = true)
+ .With(v => v.Monitored = true)
+ .With(v => v.Tags = new HashSet { 4, 5, 6 })
+ .Build();
+
+ Mocker.GetMock()
+ .Setup(v => v.GetSeries(_xemSeries.Id))
+ .Returns(_xemSeries);
+
+ WithEpisodes();
+
+ var allCriteria = WatchForSearchCriteria();
+
+ Subject.EpisodeSearch(_xemEpisodes.First(), true, false);
+
+ var criteria = allCriteria.OfType().ToList();
+
+ criteria.Count.Should().Be(0);
+ }
+
[Test]
public void scene_episodesearch()
{
diff --git a/src/NzbDrone.Core/Datastore/Migration/159_add_indexer_tags.cs b/src/NzbDrone.Core/Datastore/Migration/159_add_indexer_tags.cs
new file mode 100644
index 000000000..28f9eaf62
--- /dev/null
+++ b/src/NzbDrone.Core/Datastore/Migration/159_add_indexer_tags.cs
@@ -0,0 +1,14 @@
+using FluentMigrator;
+using NzbDrone.Core.Datastore.Migration.Framework;
+
+namespace NzbDrone.Core.Datastore.Migration
+{
+ [Migration(159)]
+ public class add_indexer_tags : NzbDroneMigrationBase
+ {
+ protected override void MainDbUpgrade()
+ {
+ Alter.Table("Indexers").AddColumn("Tags").AsString().Nullable();
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs
index 5f56f890f..8a1f49ac1 100644
--- a/src/NzbDrone.Core/Datastore/TableMapping.cs
+++ b/src/NzbDrone.Core/Datastore/TableMapping.cs
@@ -66,8 +66,7 @@ namespace NzbDrone.Core.Datastore
.Ignore(i => i.Enable)
.Ignore(i => i.Protocol)
.Ignore(i => i.SupportsRss)
- .Ignore(i => i.SupportsSearch)
- .Ignore(d => d.Tags);
+ .Ignore(i => i.SupportsSearch);
Mapper.Entity().RegisterDefinition("Notifications")
.Ignore(i => i.SupportsOnGrab)
diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/IndexerTagSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/IndexerTagSpecification.cs
new file mode 100644
index 000000000..5ab1c1423
--- /dev/null
+++ b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/IndexerTagSpecification.cs
@@ -0,0 +1,39 @@
+using System.Linq;
+using NLog;
+using NzbDrone.Common.Extensions;
+using NzbDrone.Core.Indexers;
+using NzbDrone.Core.IndexerSearch.Definitions;
+using NzbDrone.Core.Parser.Model;
+
+namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
+{
+ public class IndexerTagSpecification : IDecisionEngineSpecification
+ {
+ private readonly Logger _logger;
+ private readonly IIndexerRepository _indexerRepository;
+
+ public IndexerTagSpecification(Logger logger, IIndexerRepository indexerRepository)
+ {
+ _logger = logger;
+ _indexerRepository = indexerRepository;
+ }
+
+ public SpecificationPriority Priority => SpecificationPriority.Default;
+ public RejectionType Type => RejectionType.Permanent;
+
+ public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
+ {
+ // If indexer has tags, check that at least one of them is present on the series
+ var indexerTags = _indexerRepository.Get(subject.Release.IndexerId).Tags;
+
+ if (indexerTags.Any() && indexerTags.Intersect(subject.Series.Tags).Empty())
+ {
+ _logger.Debug("Indexer {0} has tags. None of these are present on series {1}. Rejecting", subject.Release.Indexer, subject.Series);
+
+ return Decision.Reject("Series tags do not match any of the indexer tags");
+ }
+
+ return Decision.Accept();
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs
index d0f7f6c15..42438ecab 100644
--- a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs
+++ b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs
@@ -503,6 +503,9 @@ namespace NzbDrone.Core.IndexerSearch
_indexerFactory.InteractiveSearchEnabled() :
_indexerFactory.AutomaticSearchEnabled();
+ // Filter indexers to untagged indexers and indexers with intersecting tags
+ indexers = indexers.Where(i => i.Definition.Tags.Empty() || i.Definition.Tags.Intersect(criteriaBase.Series.Tags).Any()).ToList();
+
var reports = new List();
_logger.ProgressInfo("Searching {0} indexers for {1}", indexers.Count, criteriaBase);
diff --git a/src/NzbDrone.Core/Tags/TagDetails.cs b/src/NzbDrone.Core/Tags/TagDetails.cs
index ddd5717b6..4369f3c72 100644
--- a/src/NzbDrone.Core/Tags/TagDetails.cs
+++ b/src/NzbDrone.Core/Tags/TagDetails.cs
@@ -12,12 +12,13 @@ namespace NzbDrone.Core.Tags
public List RestrictionIds { get; set; }
public List DelayProfileIds { get; set; }
public List ImportListIds { get; set; }
+ public List IndexerIds { get; set; }
public bool InUse
{
get
{
- return (SeriesIds.Any() || NotificationIds.Any() || RestrictionIds.Any() || DelayProfileIds.Any() || ImportListIds.Any());
+ return (SeriesIds.Any() || NotificationIds.Any() || RestrictionIds.Any() || DelayProfileIds.Any() || ImportListIds.Any() || IndexerIds.Any());
}
}
}
diff --git a/src/NzbDrone.Core/Tags/TagService.cs b/src/NzbDrone.Core/Tags/TagService.cs
index b804c7954..ac1ededfd 100644
--- a/src/NzbDrone.Core/Tags/TagService.cs
+++ b/src/NzbDrone.Core/Tags/TagService.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.ImportLists;
+using NzbDrone.Core.Indexers;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Notifications;
using NzbDrone.Core.Profiles.Delay;
@@ -33,6 +34,7 @@ namespace NzbDrone.Core.Tags
private readonly INotificationFactory _notificationFactory;
private readonly IReleaseProfileService _releaseProfileService;
private readonly ISeriesService _seriesService;
+ private readonly IIndexerFactory _indexerService;
public TagService(ITagRepository repo,
IEventAggregator eventAggregator,
@@ -40,7 +42,8 @@ namespace NzbDrone.Core.Tags
IImportListFactory importListFactory,
INotificationFactory notificationFactory,
IReleaseProfileService releaseProfileService,
- ISeriesService seriesService)
+ ISeriesService seriesService,
+ IIndexerFactory indexerService)
{
_repo = repo;
_eventAggregator = eventAggregator;
@@ -49,6 +52,7 @@ namespace NzbDrone.Core.Tags
_notificationFactory = notificationFactory;
_releaseProfileService = releaseProfileService;
_seriesService = seriesService;
+ _indexerService = indexerService;
}
public Tag GetTag(int tagId)
@@ -81,16 +85,18 @@ namespace NzbDrone.Core.Tags
var notifications = _notificationFactory.AllForTag(tagId);
var restrictions = _releaseProfileService.AllForTag(tagId);
var series = _seriesService.AllForTag(tagId);
+ var indexers = _indexerService.AllForTag(tagId);
return new TagDetails
- {
- Id = tagId,
- Label = tag.Label,
- DelayProfileIds = delayProfiles.Select(c => c.Id).ToList(),
- ImportListIds = importLists.Select(c => c.Id).ToList(),
- NotificationIds = notifications.Select(c => c.Id).ToList(),
- RestrictionIds = restrictions.Select(c => c.Id).ToList(),
- SeriesIds = series.Select(c => c.Id).ToList()
+ {
+ Id = tagId,
+ Label = tag.Label,
+ DelayProfileIds = delayProfiles.Select(c => c.Id).ToList(),
+ ImportListIds = importLists.Select(c => c.Id).ToList(),
+ NotificationIds = notifications.Select(c => c.Id).ToList(),
+ RestrictionIds = restrictions.Select(c => c.Id).ToList(),
+ SeriesIds = series.Select(c => c.Id).ToList(),
+ IndexerIds = indexers.Select(c => c.Id).ToList()
};
}
@@ -102,21 +108,23 @@ namespace NzbDrone.Core.Tags
var notifications = _notificationFactory.All();
var restrictions = _releaseProfileService.All();
var series = _seriesService.GetAllSeries();
+ var indexers = _indexerService.All();
var details = new List();
foreach (var tag in tags)
{
details.Add(new TagDetails
- {
- Id = tag.Id,
- Label = tag.Label,
- DelayProfileIds = delayProfiles.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(),
- ImportListIds = importLists.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(),
- NotificationIds = notifications.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(),
- RestrictionIds = restrictions.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(),
- SeriesIds = series.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList()
- }
+ {
+ Id = tag.Id,
+ Label = tag.Label,
+ DelayProfileIds = delayProfiles.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(),
+ ImportListIds = importLists.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(),
+ NotificationIds = notifications.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(),
+ RestrictionIds = restrictions.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(),
+ SeriesIds = series.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList(),
+ IndexerIds = indexers.Where(c => c.Tags.Contains(tag.Id)).Select(c => c.Id).ToList()
+ }
);
}
diff --git a/src/Sonarr.Api.V3/Tags/TagDetailsResource.cs b/src/Sonarr.Api.V3/Tags/TagDetailsResource.cs
index 7a55aa410..2cc7059af 100644
--- a/src/Sonarr.Api.V3/Tags/TagDetailsResource.cs
+++ b/src/Sonarr.Api.V3/Tags/TagDetailsResource.cs
@@ -12,6 +12,7 @@ namespace Sonarr.Api.V3.Tags
public List ImportListIds { get; set; }
public List NotificationIds { get; set; }
public List RestrictionIds { get; set; }
+ public List IndexerIds { get; set; }
public List SeriesIds { get; set; }
}
@@ -29,6 +30,7 @@ namespace Sonarr.Api.V3.Tags
ImportListIds = model.ImportListIds,
NotificationIds = model.NotificationIds,
RestrictionIds = model.RestrictionIds,
+ IndexerIds = model.IndexerIds,
SeriesIds = model.SeriesIds
};
}