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 6e53ecf2e..8fb41f28b 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;
@@ -40,7 +41,7 @@ function TagDetailsModalContent(props) {
}
{
- !!author.length &&
+ author.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
}
@@ -191,6 +213,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 3444039f4..64a829d47 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(
createMatchingAuthorSelector(),
@@ -76,13 +84,15 @@ function createMapStateToProps() {
createMatchingImportListsSelector(),
createMatchingNotificationsSelector(),
createMatchingReleaseProfilesSelector(),
- (author, delayProfiles, importLists, notifications, releaseProfiles) => {
+ createMatchingIndexersSelector(),
+ (author, delayProfiles, importLists, notifications, releaseProfiles, indexers) => {
return {
author,
delayProfiles,
importLists,
notifications,
- releaseProfiles
+ releaseProfiles,
+ indexers
};
}
);
diff --git a/frontend/src/Settings/Tags/Tag.js b/frontend/src/Settings/Tags/Tag.js
index b1f44a26a..b68db9519 100644
--- a/frontend/src/Settings/Tags/Tag.js
+++ b/frontend/src/Settings/Tags/Tag.js
@@ -57,6 +57,7 @@ class Tag extends Component {
importListIds,
notificationIds,
restrictionIds,
+ indexerIds,
authorIds
} = this.props;
@@ -70,6 +71,7 @@ class Tag extends Component {
importListIds.length ||
notificationIds.length ||
restrictionIds.length ||
+ indexerIds.length ||
authorIds.length
);
@@ -120,6 +122,14 @@ class Tag extends Component {
{restrictionIds.length} restriction{restrictionIds.length > 1 && 's'}
}
+
+ {
+ indexerIds.length ?
+
+ {indexerIds.length} indexer{indexerIds.length > 1 && 's'}
+
:
+ null
+ }
}
@@ -138,6 +148,7 @@ class Tag extends Component {
importListIds={importListIds}
notificationIds={notificationIds}
restrictionIds={restrictionIds}
+ indexerIds={indexerIds}
isOpen={isDetailsModalOpen}
onModalClose={this.onDetailsModalClose}
onDeleteTagPress={this.onDeleteTagPress}
@@ -164,6 +175,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,
authorIds: PropTypes.arrayOf(PropTypes.number).isRequired,
onConfirmDeleteTag: PropTypes.func.isRequired
};
@@ -173,6 +185,7 @@ Tag.defaultProps = {
importListIds: [],
notificationIds: [],
restrictionIds: [],
+ indexerIds: [],
authorIds: []
};
diff --git a/frontend/src/Settings/Tags/TagsConnector.js b/frontend/src/Settings/Tags/TagsConnector.js
index bbfa5d27e..241ee260a 100644
--- a/frontend/src/Settings/Tags/TagsConnector.js
+++ b/frontend/src/Settings/Tags/TagsConnector.js
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
-import { fetchDelayProfiles, fetchImportLists, fetchNotifications, fetchReleaseProfiles } from 'Store/Actions/settingsActions';
+import { fetchDelayProfiles, fetchImportLists, fetchIndexers, fetchNotifications, fetchReleaseProfiles } from 'Store/Actions/settingsActions';
import { fetchTagDetails } from 'Store/Actions/tagActions';
import Tags from './Tags';
@@ -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/MonitoredAlbumSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/MonitoredBookSpecificationFixture.cs
similarity index 100%
rename from src/NzbDrone.Core.Test/DecisionEngineTests/MonitoredAlbumSpecificationFixture.cs
rename to src/NzbDrone.Core.Test/DecisionEngineTests/MonitoredBookSpecificationFixture.cs
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..9c7c3987b
--- /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.Books;
+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;
+
+namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
+{
+ [TestFixture]
+ public class IndexerTagSpecificationFixture : CoreTest
+ {
+ private IndexerTagSpecification _specification;
+
+ private RemoteBook _parseResultMulti;
+ private IndexerDefinition _fakeIndexerDefinition;
+ private Author _fakeAuthor;
+ private Book _firstBook;
+ private Book _secondBook;
+ 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();
+
+ _fakeAuthor = Builder.CreateNew()
+ .With(c => c.Monitored = true)
+ .With(c => c.Tags = new HashSet())
+ .Build();
+
+ _fakeRelease = new ReleaseInfo
+ {
+ IndexerId = 1
+ };
+
+ _firstBook = new Book { Monitored = true };
+ _secondBook = new Book { Monitored = true };
+
+ var doubleBookList = new List { _firstBook, _secondBook };
+
+ _parseResultMulti = new RemoteBook
+ {
+ Author = _fakeAuthor,
+ Books = doubleBookList,
+ Release = _fakeRelease
+ };
+ }
+
+ [Test]
+ public void indexer_and_author_without_tags_should_return_true()
+ {
+ _fakeIndexerDefinition.Tags = new HashSet();
+ _fakeAuthor.Tags = new HashSet();
+
+ _specification.IsSatisfiedBy(_parseResultMulti, new BookSearchCriteria { MonitoredBooksOnly = true }).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void indexer_with_tags_author_without_tags_should_return_false()
+ {
+ _fakeIndexerDefinition.Tags = new HashSet { 123 };
+ _fakeAuthor.Tags = new HashSet();
+
+ _specification.IsSatisfiedBy(_parseResultMulti, new BookSearchCriteria { MonitoredBooksOnly = true }).Accepted.Should().BeFalse();
+ }
+
+ [Test]
+ public void indexer_without_tags_author_with_tags_should_return_true()
+ {
+ _fakeIndexerDefinition.Tags = new HashSet();
+ _fakeAuthor.Tags = new HashSet { 123 };
+
+ _specification.IsSatisfiedBy(_parseResultMulti, new BookSearchCriteria { MonitoredBooksOnly = true }).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void indexer_with_tags_author_with_matching_tags_should_return_true()
+ {
+ _fakeIndexerDefinition.Tags = new HashSet { 123, 456 };
+ _fakeAuthor.Tags = new HashSet { 123, 789 };
+
+ _specification.IsSatisfiedBy(_parseResultMulti, new BookSearchCriteria { MonitoredBooksOnly = true }).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void indexer_with_tags_author_with_different_tags_should_return_false()
+ {
+ _fakeIndexerDefinition.Tags = new HashSet { 456 };
+ _fakeAuthor.Tags = new HashSet { 123, 789 };
+
+ _specification.IsSatisfiedBy(_parseResultMulti, new BookSearchCriteria { MonitoredBooksOnly = true }).Accepted.Should().BeFalse();
+ }
+ }
+}
diff --git a/src/NzbDrone.Core.Test/IndexerSearchTests/ArtistSearchServiceFixture.cs b/src/NzbDrone.Core.Test/IndexerSearchTests/AuthorSearchServiceFixture.cs
similarity index 100%
rename from src/NzbDrone.Core.Test/IndexerSearchTests/ArtistSearchServiceFixture.cs
rename to src/NzbDrone.Core.Test/IndexerSearchTests/AuthorSearchServiceFixture.cs
diff --git a/src/NzbDrone.Core.Test/IndexerSearchTests/ReleaseSearchServiceFixture.cs b/src/NzbDrone.Core.Test/IndexerSearchTests/ReleaseSearchServiceFixture.cs
new file mode 100644
index 000000000..5fc1569f3
--- /dev/null
+++ b/src/NzbDrone.Core.Test/IndexerSearchTests/ReleaseSearchServiceFixture.cs
@@ -0,0 +1,166 @@
+using System.Collections.Generic;
+using System.Linq;
+using FizzWare.NBuilder;
+using FluentAssertions;
+using Moq;
+using NUnit.Framework;
+using NzbDrone.Core.Books;
+using NzbDrone.Core.DecisionEngine;
+using NzbDrone.Core.Indexers;
+using NzbDrone.Core.IndexerSearch;
+using NzbDrone.Core.IndexerSearch.Definitions;
+using NzbDrone.Core.Test.Framework;
+
+namespace NzbDrone.Core.Test.IndexerSearchTests
+{
+ public class ReleaseSearchServiceFixture : CoreTest
+ {
+ private Mock _mockIndexer;
+ private Author _author;
+ private Book _firstBook;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _mockIndexer = Mocker.GetMock();
+ _mockIndexer.SetupGet(s => s.Definition).Returns(new IndexerDefinition { Id = 1 });
+ _mockIndexer.SetupGet(s => s.SupportsSearch).Returns(true);
+
+ Mocker.GetMock()
+ .Setup(s => s.AutomaticSearchEnabled(true))
+ .Returns(new List { _mockIndexer.Object });
+
+ Mocker.GetMock()
+ .Setup(s => s.GetSearchDecision(It.IsAny>(), It.IsAny()))
+ .Returns(new List());
+
+ _author = Builder.CreateNew()
+ .With(v => v.Monitored = true)
+ .Build();
+
+ _firstBook = Builder.CreateNew()
+ .With(e => e.Author = _author)
+ .Build();
+
+ var edition = Builder.CreateNew()
+ .With(e => e.Book = _firstBook)
+ .With(e => e.Monitored = true)
+ .Build();
+
+ _firstBook.Editions = new List { edition };
+
+ Mocker.GetMock()
+ .Setup(v => v.GetAuthor(_author.Id))
+ .Returns(_author);
+ }
+
+ private List WatchForSearchCriteria()
+ {
+ var result = new List();
+
+ _mockIndexer.Setup(v => v.Fetch(It.IsAny()))
+ .Callback(s => result.Add(s))
+ .Returns(new List());
+
+ return result;
+ }
+
+ [Test]
+ public void Tags_IndexerTags_AuthorNoTags_IndexerNotIncluded()
+ {
+ _mockIndexer.SetupGet(s => s.Definition).Returns(new IndexerDefinition
+ {
+ Id = 1,
+ Tags = new HashSet { 3 }
+ });
+
+ var allCriteria = WatchForSearchCriteria();
+
+ Subject.BookSearch(_firstBook, false, true, false);
+
+ var criteria = allCriteria.OfType().ToList();
+
+ criteria.Count.Should().Be(0);
+ }
+
+ [Test]
+ public void Tags_IndexerNoTags_AuthorTags_IndexerIncluded()
+ {
+ _mockIndexer.SetupGet(s => s.Definition).Returns(new IndexerDefinition
+ {
+ Id = 1
+ });
+
+ _author = Builder.CreateNew()
+ .With(v => v.Monitored = true)
+ .With(v => v.Tags = new HashSet { 3 })
+ .Build();
+
+ Mocker.GetMock()
+ .Setup(v => v.GetAuthor(_author.Id))
+ .Returns(_author);
+
+ var allCriteria = WatchForSearchCriteria();
+
+ Subject.BookSearch(_firstBook, false, true, false);
+
+ var criteria = allCriteria.OfType().ToList();
+
+ criteria.Count.Should().Be(1);
+ }
+
+ [Test]
+ public void Tags_IndexerAndAuthorTagsMatch_IndexerIncluded()
+ {
+ _mockIndexer.SetupGet(s => s.Definition).Returns(new IndexerDefinition
+ {
+ Id = 1,
+ Tags = new HashSet { 1, 2, 3 }
+ });
+
+ _author = Builder.CreateNew()
+ .With(v => v.Monitored = true)
+ .With(v => v.Tags = new HashSet { 3, 4, 5 })
+ .Build();
+
+ Mocker.GetMock()
+ .Setup(v => v.GetAuthor(_author.Id))
+ .Returns(_author);
+
+ var allCriteria = WatchForSearchCriteria();
+
+ Subject.BookSearch(_firstBook, false, true, false);
+
+ var criteria = allCriteria.OfType().ToList();
+
+ criteria.Count.Should().Be(1);
+ }
+
+ [Test]
+ public void Tags_IndexerAndAuthorTagsMismatch_IndexerNotIncluded()
+ {
+ _mockIndexer.SetupGet(s => s.Definition).Returns(new IndexerDefinition
+ {
+ Id = 1,
+ Tags = new HashSet { 1, 2, 3 }
+ });
+
+ _author = Builder.CreateNew()
+ .With(v => v.Monitored = true)
+ .With(v => v.Tags = new HashSet { 4, 5, 6 })
+ .Build();
+
+ Mocker.GetMock()
+ .Setup(v => v.GetAuthor(_author.Id))
+ .Returns(_author);
+
+ var allCriteria = WatchForSearchCriteria();
+
+ Subject.BookSearch(_firstBook, false, true, false);
+
+ var criteria = allCriteria.OfType().ToList();
+
+ criteria.Count.Should().Be(0);
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Datastore/Migration/028_add_indexer_tags.cs b/src/NzbDrone.Core/Datastore/Migration/028_add_indexer_tags.cs
new file mode 100644
index 000000000..42902049b
--- /dev/null
+++ b/src/NzbDrone.Core/Datastore/Migration/028_add_indexer_tags.cs
@@ -0,0 +1,14 @@
+using FluentMigrator;
+using NzbDrone.Core.Datastore.Migration.Framework;
+
+namespace NzbDrone.Core.Datastore.Migration
+{
+ [Migration(028)]
+ 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 94e077654..e43791951 100644
--- a/src/NzbDrone.Core/Datastore/TableMapping.cs
+++ b/src/NzbDrone.Core/Datastore/TableMapping.cs
@@ -71,8 +71,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("ImportLists").RegisterModel()
.Ignore(x => x.ImplementationName)
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..00103ba79
--- /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(RemoteBook subject, SearchCriteriaBase searchCriteria)
+ {
+ // If indexer has tags, check that at least one of them is present on the author
+ var indexerTags = _indexerRepository.Get(subject.Release.IndexerId).Tags;
+
+ if (indexerTags.Any() && indexerTags.Intersect(subject.Author.Tags).Empty())
+ {
+ _logger.Debug("Indexer {0} has tags. None of these are present on author {1}. Rejecting", subject.Release.Indexer, subject.Author);
+
+ return Decision.Reject("Author tags do not match any of the indexer tags");
+ }
+
+ return Decision.Accept();
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs
index 7968e2e3a..d45a6d139 100644
--- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs
+++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs
@@ -20,10 +20,10 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
{
using (var mapper = _database.OpenConnection())
{
- var usedTags = new[] { "Authors", "Notifications", "DelayProfiles", "ReleaseProfiles", "ImportLists" }
- .SelectMany(v => GetUsedTags(v, mapper))
- .Distinct()
- .ToArray();
+ var usedTags = new[] { "Authors", "Notifications", "DelayProfiles", "ReleaseProfiles", "ImportLists", "Indexers" }
+ .SelectMany(v => GetUsedTags(v, mapper))
+ .Distinct()
+ .ToArray();
if (usedTags.Any())
{
diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs
index f851ed0ff..63962502b 100644
--- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs
+++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs
@@ -112,6 +112,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.Author.Tags).Any()).ToList();
+
var reports = new List();
_logger.ProgressInfo("Searching indexers for {0}. {1} active indexers", criteriaBase, indexers.Count);
diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json
index edd3cb775..bbebb6ad9 100644
--- a/src/NzbDrone.Core/Localization/Core/en.json
+++ b/src/NzbDrone.Core/Localization/Core/en.json
@@ -375,6 +375,7 @@
"IndexerSettings": "Indexer Settings",
"IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures",
"IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}",
+ "IndexerTagsHelpText": "Only use this indexer for authors with at least one matching tag. Leave blank to use with all authors.",
"Indexers": "Indexers",
"IndexersSettingsSummary": "Indexers and release restrictions",
"InstanceName": "Instance Name",
diff --git a/src/NzbDrone.Core/Tags/TagDetails.cs b/src/NzbDrone.Core/Tags/TagDetails.cs
index dd4ac1e5c..45eded56b 100644
--- a/src/NzbDrone.Core/Tags/TagDetails.cs
+++ b/src/NzbDrone.Core/Tags/TagDetails.cs
@@ -12,13 +12,14 @@ 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 List RootFolderIds { get; set; }
public bool InUse
{
get
{
- return AuthorIds.Any() || NotificationIds.Any() || RestrictionIds.Any() || DelayProfileIds.Any() || ImportListIds.Any() || RootFolderIds.Any();
+ return AuthorIds.Any() || NotificationIds.Any() || RestrictionIds.Any() || DelayProfileIds.Any() || ImportListIds.Any() || IndexerIds.Any() || RootFolderIds.Any();
}
}
}
diff --git a/src/NzbDrone.Core/Tags/TagService.cs b/src/NzbDrone.Core/Tags/TagService.cs
index dbf0985c1..dbee84331 100644
--- a/src/NzbDrone.Core/Tags/TagService.cs
+++ b/src/NzbDrone.Core/Tags/TagService.cs
@@ -3,6 +3,7 @@ using System.Linq;
using NzbDrone.Core.Books;
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;
@@ -32,6 +33,7 @@ namespace NzbDrone.Core.Tags
private readonly INotificationFactory _notificationFactory;
private readonly IReleaseProfileService _releaseProfileService;
private readonly IAuthorService _authorService;
+ private readonly IIndexerFactory _indexerService;
private readonly IRootFolderService _rootFolderService;
public TagService(ITagRepository repo,
@@ -41,6 +43,7 @@ namespace NzbDrone.Core.Tags
INotificationFactory notificationFactory,
IReleaseProfileService releaseProfileService,
IAuthorService authorService,
+ IIndexerFactory indexerService,
IRootFolderService rootFolderService)
{
_repo = repo;
@@ -50,6 +53,7 @@ namespace NzbDrone.Core.Tags
_notificationFactory = notificationFactory;
_releaseProfileService = releaseProfileService;
_authorService = authorService;
+ _indexerService = indexerService;
_rootFolderService = rootFolderService;
}
@@ -78,6 +82,7 @@ namespace NzbDrone.Core.Tags
var notifications = _notificationFactory.AllForTag(tagId);
var restrictions = _releaseProfileService.AllForTag(tagId);
var author = _authorService.AllForTag(tagId);
+ var indexers = _indexerService.AllForTag(tagId);
var rootFolders = _rootFolderService.AllForTag(tagId);
return new TagDetails
@@ -89,6 +94,7 @@ namespace NzbDrone.Core.Tags
NotificationIds = notifications.Select(c => c.Id).ToList(),
RestrictionIds = restrictions.Select(c => c.Id).ToList(),
AuthorIds = author.Select(c => c.Id).ToList(),
+ IndexerIds = indexers.Select(c => c.Id).ToList(),
RootFolderIds = rootFolders.Select(c => c.Id).ToList()
};
}
@@ -101,6 +107,7 @@ namespace NzbDrone.Core.Tags
var notifications = _notificationFactory.All();
var restrictions = _releaseProfileService.All();
var authors = _authorService.GetAllAuthors();
+ var indexers = _indexerService.All();
var rootFolders = _rootFolderService.All();
var details = new List();
@@ -116,6 +123,7 @@ namespace NzbDrone.Core.Tags
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(),
AuthorIds = authors.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(),
RootFolderIds = rootFolders.Where(c => c.DefaultTags.Contains(tag.Id)).Select(c => c.Id).ToList()
});
}
diff --git a/src/Readarr.Api.V1/Tags/TagDetailsResource.cs b/src/Readarr.Api.V1/Tags/TagDetailsResource.cs
index 7d4447e91..1d0ec7067 100644
--- a/src/Readarr.Api.V1/Tags/TagDetailsResource.cs
+++ b/src/Readarr.Api.V1/Tags/TagDetailsResource.cs
@@ -12,6 +12,7 @@ namespace Readarr.Api.V1.Tags
public List ImportListIds { get; set; }
public List NotificationIds { get; set; }
public List RestrictionIds { get; set; }
+ public List IndexerIds { get; set; }
public List AuthorIds { get; set; }
}
@@ -32,6 +33,7 @@ namespace Readarr.Api.V1.Tags
ImportListIds = model.ImportListIds,
NotificationIds = model.NotificationIds,
RestrictionIds = model.RestrictionIds,
+ IndexerIds = model.IndexerIds,
AuthorIds = model.AuthorIds
};
}