mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
Newznab Work
This commit is contained in:
@@ -3,17 +3,21 @@ import React from 'react';
|
||||
import Label from 'Components/Label';
|
||||
|
||||
function CategoryLabel({ categories }) {
|
||||
let catName = '';
|
||||
|
||||
if (categories && categories.length > 0) {
|
||||
catName = categories[0].name;
|
||||
}
|
||||
const sortedCategories = categories.sort((c) => c.id);
|
||||
|
||||
return (
|
||||
<Label>
|
||||
{catName}
|
||||
<span>
|
||||
{
|
||||
sortedCategories.map((category) => {
|
||||
return (
|
||||
<Label key={category.name}>
|
||||
{category.name}
|
||||
</Label>
|
||||
);
|
||||
})
|
||||
}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
CategoryLabel.propTypes = {
|
||||
|
@@ -10,7 +10,12 @@
|
||||
flex: 4 0 110px;
|
||||
}
|
||||
|
||||
.category,
|
||||
.category {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
flex: 0 0 110px;
|
||||
}
|
||||
|
||||
.indexer {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
|
@@ -17,7 +17,12 @@
|
||||
flex: 4 0 110px;
|
||||
}
|
||||
|
||||
.category,
|
||||
.category {
|
||||
composes: cell;
|
||||
|
||||
flex: 0 0 110px;
|
||||
}
|
||||
|
||||
.indexer {
|
||||
composes: cell;
|
||||
|
||||
|
@@ -1,6 +1,9 @@
|
||||
import React from 'react';
|
||||
import React, { 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 SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import ApplicationsConnector from './Applications/ApplicationsConnector';
|
||||
@@ -10,6 +13,21 @@ function ApplicationSettings() {
|
||||
<PageContent title={translate('Applications')}>
|
||||
<SettingsToolbarConnector
|
||||
showSave={false}
|
||||
additionalButtons={
|
||||
<Fragment>
|
||||
<PageToolbarSeparator />
|
||||
|
||||
<PageToolbarButton
|
||||
label={translate('SyncAppIndexers')}
|
||||
iconName={icons.REFRESH}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label={translate('TestAllApps')}
|
||||
iconName={icons.TEST}
|
||||
/>
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageContentBody>
|
||||
|
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Applications
|
||||
{
|
||||
public class ApplicationIndexerSyncCommand : Command
|
||||
{
|
||||
public override bool SendUpdatesToClient => true;
|
||||
|
||||
public override string CompletionMessage => null;
|
||||
}
|
||||
}
|
@@ -1,11 +1,16 @@
|
||||
using NLog;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.ThingiProvider.Events;
|
||||
|
||||
namespace NzbDrone.Core.Applications
|
||||
{
|
||||
public class ApplicationService : IHandle<ProviderAddedEvent<IIndexer>>, IHandle<ProviderDeletedEvent<IIndexer>>, IHandle<ProviderAddedEvent<IApplication>>, IHandle<ProviderUpdatedEvent<IIndexer>>
|
||||
public class ApplicationService : IHandleAsync<ProviderAddedEvent<IIndexer>>,
|
||||
IHandleAsync<ProviderDeletedEvent<IIndexer>>,
|
||||
IHandleAsync<ProviderAddedEvent<IApplication>>,
|
||||
IHandleAsync<ProviderUpdatedEvent<IIndexer>>,
|
||||
IExecute<ApplicationIndexerSyncCommand>
|
||||
{
|
||||
private readonly IApplicationFactory _applicationsFactory;
|
||||
private readonly Logger _logger;
|
||||
@@ -17,7 +22,7 @@ namespace NzbDrone.Core.Applications
|
||||
}
|
||||
|
||||
// Sync Indexers on App Add if Sync Enabled
|
||||
public void Handle(ProviderAddedEvent<IApplication> message)
|
||||
public void HandleAsync(ProviderAddedEvent<IApplication> message)
|
||||
{
|
||||
var appDefinition = (ApplicationDefinition)message.Definition;
|
||||
|
||||
@@ -29,7 +34,7 @@ namespace NzbDrone.Core.Applications
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ProviderAddedEvent<IIndexer> message)
|
||||
public void HandleAsync(ProviderAddedEvent<IIndexer> message)
|
||||
{
|
||||
var enabledApps = _applicationsFactory.GetAvailableProviders();
|
||||
|
||||
@@ -40,7 +45,7 @@ namespace NzbDrone.Core.Applications
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ProviderDeletedEvent<IIndexer> message)
|
||||
public void HandleAsync(ProviderDeletedEvent<IIndexer> message)
|
||||
{
|
||||
var enabledApps = _applicationsFactory.GetAvailableProviders();
|
||||
|
||||
@@ -51,7 +56,7 @@ namespace NzbDrone.Core.Applications
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ProviderUpdatedEvent<IIndexer> message)
|
||||
public void HandleAsync(ProviderUpdatedEvent<IIndexer> message)
|
||||
{
|
||||
var enabledApps = _applicationsFactory.GetAvailableProviders();
|
||||
|
||||
@@ -61,5 +66,15 @@ namespace NzbDrone.Core.Applications
|
||||
app.UpdateIndexer((IndexerDefinition)message.Definition);
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute(ApplicationIndexerSyncCommand message)
|
||||
{
|
||||
var enabledApps = _applicationsFactory.GetAvailableProviders();
|
||||
|
||||
foreach (var app in enabledApps)
|
||||
{
|
||||
app.SyncIndexers();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
|
||||
{
|
||||
public string ImdbId { get; set; }
|
||||
public int? TmdbId { get; set; }
|
||||
public int? Year { get; set; }
|
||||
public int? TraktId { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -60,7 +60,6 @@ namespace NzbDrone.Core.IndexerSearch
|
||||
searchSpec.ImdbId = request.imdbid;
|
||||
searchSpec.TmdbId = request.tmdbid;
|
||||
searchSpec.TraktId = request.traktid;
|
||||
searchSpec.Year = request.year;
|
||||
|
||||
return new NewznabResults { Releases = Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
|
||||
}
|
||||
|
@@ -60,7 +60,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
{
|
||||
foreach (var category in _definition.Caps.Categories)
|
||||
{
|
||||
var cat = TorznabCatType.GetCatByName(category.Value);
|
||||
var cat = NewznabStandardCategory.GetCatByName(category.Value);
|
||||
if (cat == null)
|
||||
{
|
||||
_logger.Error(string.Format("CardigannIndexer ({0}): invalid Torznab category for id {1}: {2}", _definition.Id, category.Key, category.Value));
|
||||
@@ -79,7 +79,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
|
||||
if (categorymapping.cat != null)
|
||||
{
|
||||
torznabCat = TorznabCatType.GetCatByName(categorymapping.cat);
|
||||
torznabCat = NewznabStandardCategory.GetCatByName(categorymapping.cat);
|
||||
if (torznabCat == null)
|
||||
{
|
||||
_logger.Error(string.Format("CardigannIndexer ({0}): invalid Torznab category for id {1}: {2}", _definition.Id, categorymapping.id, categorymapping.cat));
|
||||
@@ -262,7 +262,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
.Where(m =>
|
||||
!string.IsNullOrWhiteSpace(m.TrackerCategory) &&
|
||||
string.Equals(m.TrackerCategory, input, StringComparison.InvariantCultureIgnoreCase))
|
||||
.Select(c => TorznabCatType.AllCats.FirstOrDefault(n => n.Id == c.NewzNabCategory) ?? new IndexerCategory { Id = c.NewzNabCategory })
|
||||
.Select(c => NewznabStandardCategory.AllCats.FirstOrDefault(n => n.Id == c.NewzNabCategory) ?? new IndexerCategory { Id = c.NewzNabCategory })
|
||||
.ToList();
|
||||
return cats;
|
||||
}
|
||||
|
@@ -29,9 +29,9 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
var variables = GetQueryVariableDefaults(searchCriteria);
|
||||
|
||||
variables[".Query.Movie"] = null;
|
||||
variables[".Query.Year"] = searchCriteria.Year;
|
||||
variables[".Query.Year"] = null;
|
||||
variables[".Query.IMDBID"] = searchCriteria.ImdbId;
|
||||
variables[".Query.IMDBIDShort"] = searchCriteria.ImdbId.Replace("tt", "");
|
||||
variables[".Query.IMDBIDShort"] = searchCriteria.ImdbId?.TrimStart('t') ?? null;
|
||||
variables[".Query.TMDBID"] = searchCriteria.TmdbId;
|
||||
variables[".Query.TraktID"] = searchCriteria.TraktId;
|
||||
|
||||
|
@@ -20,7 +20,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
|
||||
public override IndexerCapabilities Capabilities { get => new IndexerCapabilities(); protected set => base.Capabilities = value; }
|
||||
public override IndexerCapabilities Capabilities { get => GetCapabilitiesFromSettings(); protected set => base.Capabilities = value; }
|
||||
|
||||
public override int PageSize => _capabilitiesProvider.GetCapabilities(Settings).LimitsDefault.Value;
|
||||
|
||||
@@ -38,6 +38,29 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
return new NewznabRssParser(Settings);
|
||||
}
|
||||
|
||||
public IndexerCapabilities GetCapabilitiesFromSettings()
|
||||
{
|
||||
var caps = new IndexerCapabilities();
|
||||
|
||||
if (Definition == null || Settings == null || Settings.Categories == null)
|
||||
{
|
||||
return caps;
|
||||
}
|
||||
|
||||
foreach (var category in Settings.Categories)
|
||||
{
|
||||
caps.Categories.AddCategoryMapping(category.Name, category);
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
public override IndexerCapabilities GetCapabilities()
|
||||
{
|
||||
// Newznab uses different Caps per site, so we need to cache them to db on first indexer add to prevent issues with loading UI and pulling caps every time.
|
||||
return _capabilitiesProvider.GetCapabilities(Settings);
|
||||
}
|
||||
|
||||
public override IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||
{
|
||||
get
|
||||
|
@@ -206,12 +206,15 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
|
||||
foreach (var xmlSubcat in xmlCategory.Elements("subcat"))
|
||||
{
|
||||
cat.SubCategories.Add(new IndexerCategory
|
||||
var subCat = new IndexerCategory
|
||||
{
|
||||
Id = int.Parse(xmlSubcat.Attribute("id").Value),
|
||||
Name = xmlSubcat.Attribute("name").Value,
|
||||
Description = xmlSubcat.Attribute("description") != null ? xmlSubcat.Attribute("description").Value : string.Empty
|
||||
});
|
||||
};
|
||||
|
||||
cat.SubCategories.Add(subCat);
|
||||
capabilities.Categories.AddCategoryMapping(subCat.Name, subCat);
|
||||
}
|
||||
|
||||
capabilities.Categories.AddCategoryMapping(cat.Name, cat);
|
||||
|
@@ -22,55 +22,35 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
PageSize = 100;
|
||||
}
|
||||
|
||||
private bool SupportsSearch
|
||||
{
|
||||
get
|
||||
{
|
||||
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
|
||||
|
||||
return capabilities.SearchParams != null &&
|
||||
capabilities.SearchParams.Contains(SearchParam.Q);
|
||||
}
|
||||
}
|
||||
|
||||
private bool SupportsImdbSearch
|
||||
{
|
||||
get
|
||||
{
|
||||
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
|
||||
|
||||
return capabilities.MovieSearchParams != null &&
|
||||
capabilities.MovieSearchParams.Contains(MovieSearchParam.ImdbId);
|
||||
}
|
||||
}
|
||||
|
||||
private bool SupportsTmdbSearch
|
||||
{
|
||||
get
|
||||
{
|
||||
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
|
||||
|
||||
return capabilities.MovieSearchParams != null &&
|
||||
capabilities.MovieSearchParams.Contains(MovieSearchParam.TmdbId);
|
||||
}
|
||||
}
|
||||
|
||||
private bool SupportsAggregatedIdSearch
|
||||
{
|
||||
get
|
||||
{
|
||||
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
|
||||
|
||||
// TODO: Fix this, return capabilities.SupportsAggregateIdSearch;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
|
||||
|
||||
AddMovieIdPageableRequests(pageableRequests, MaxPages, searchCriteria.Categories, searchCriteria);
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
var parameters = string.Empty;
|
||||
|
||||
if (searchCriteria.TmdbId.HasValue && capabilities.MovieSearchTmdbAvailable)
|
||||
{
|
||||
parameters += string.Format("&tmdbid={0}", searchCriteria.TmdbId.Value);
|
||||
}
|
||||
|
||||
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace() && capabilities.MovieSearchImdbAvailable)
|
||||
{
|
||||
parameters += string.Format("&imdbid={0}", searchCriteria.ImdbId);
|
||||
}
|
||||
|
||||
if (searchCriteria.TraktId.HasValue && capabilities.MovieSearchTraktAvailable)
|
||||
{
|
||||
parameters += string.Format("&traktid={0}", searchCriteria.ImdbId);
|
||||
}
|
||||
|
||||
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
parameters += string.Format("&q={0}", searchCriteria.SearchTerm);
|
||||
}
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(searchCriteria,
|
||||
parameters));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
@@ -82,7 +62,50 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
|
||||
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
var parameters = string.Empty;
|
||||
|
||||
if (searchCriteria.TvdbId.HasValue && capabilities.TvSearchTvdbAvailable)
|
||||
{
|
||||
parameters += string.Format("&tvdbid={0}", searchCriteria.TvdbId.Value);
|
||||
}
|
||||
|
||||
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace() && capabilities.TvSearchImdbAvailable)
|
||||
{
|
||||
parameters += string.Format("&imdbid={0}", searchCriteria.ImdbId);
|
||||
}
|
||||
|
||||
if (searchCriteria.TvMazeId.HasValue && capabilities.TvSearchTvMazeAvailable)
|
||||
{
|
||||
parameters += string.Format("&tvmazeid={0}", searchCriteria.TvMazeId);
|
||||
}
|
||||
|
||||
if (searchCriteria.RId.HasValue && capabilities.TvSearchTvRageAvailable)
|
||||
{
|
||||
parameters += string.Format("&rid={0}", searchCriteria.RId);
|
||||
}
|
||||
|
||||
if (searchCriteria.Season.HasValue && capabilities.TvSearchSeasonAvailable)
|
||||
{
|
||||
parameters += string.Format("&season={0}", searchCriteria.Season);
|
||||
}
|
||||
|
||||
if (searchCriteria.Ep.HasValue && capabilities.TvSearchEpAvailable)
|
||||
{
|
||||
parameters += string.Format("&ep={0}", searchCriteria.Ep);
|
||||
}
|
||||
|
||||
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
parameters += string.Format("&q={0}", searchCriteria.SearchTerm);
|
||||
}
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(searchCriteria,
|
||||
parameters));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
@@ -94,74 +117,18 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(MaxPages,
|
||||
searchCriteria.Categories,
|
||||
"search",
|
||||
string.Format("&q={0}", NewsnabifyTitle(searchCriteria.SearchTerm))));
|
||||
var searchQuery = searchCriteria.SearchTerm;
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(searchCriteria,
|
||||
searchQuery.IsNotNullOrWhiteSpace() ? string.Format("&q={0}", NewsnabifyTitle(searchCriteria.SearchTerm)) : string.Empty));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
private void AddMovieIdPageableRequests(IndexerPageableRequestChain chain, int maxPages, IEnumerable<int> categories, MovieSearchCriteria searchCriteria)
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(SearchCriteriaBase searchCriteria, string parameters)
|
||||
{
|
||||
var includeTmdbSearch = SupportsTmdbSearch && searchCriteria.TmdbId > 0;
|
||||
var includeImdbSearch = SupportsImdbSearch && searchCriteria.ImdbId.IsNotNullOrWhiteSpace();
|
||||
|
||||
if (SupportsAggregatedIdSearch && (includeTmdbSearch || includeImdbSearch))
|
||||
{
|
||||
var ids = "";
|
||||
|
||||
if (includeTmdbSearch)
|
||||
{
|
||||
ids += "&tmdbid=" + searchCriteria.TmdbId;
|
||||
}
|
||||
|
||||
if (includeImdbSearch)
|
||||
{
|
||||
ids += "&imdbid=" + searchCriteria.ImdbId.Substring(2);
|
||||
}
|
||||
|
||||
chain.Add(GetPagedRequests(maxPages, categories, "movie", ids));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (includeTmdbSearch)
|
||||
{
|
||||
chain.Add(GetPagedRequests(maxPages,
|
||||
categories,
|
||||
"movie",
|
||||
string.Format("&tmdbid={0}", searchCriteria.TmdbId)));
|
||||
}
|
||||
else if (includeImdbSearch)
|
||||
{
|
||||
chain.Add(GetPagedRequests(maxPages,
|
||||
categories,
|
||||
"movie",
|
||||
string.Format("&imdbid={0}", searchCriteria.ImdbId.Substring(2))));
|
||||
}
|
||||
}
|
||||
|
||||
if (SupportsSearch)
|
||||
{
|
||||
chain.AddTier();
|
||||
|
||||
var searchQuery = searchCriteria.SearchTerm;
|
||||
|
||||
if (!Settings.RemoveYear)
|
||||
{
|
||||
searchQuery = string.Format("{0}", searchQuery);
|
||||
}
|
||||
|
||||
chain.Add(GetPagedRequests(MaxPages,
|
||||
categories,
|
||||
"movie",
|
||||
string.Format("&q={0}", NewsnabifyTitle(searchQuery))));
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, IEnumerable<int> categories, string searchType, string parameters)
|
||||
{
|
||||
var baseUrl = string.Format("{0}{1}?t={2}&extended=1", Settings.BaseUrl.TrimEnd('/'), Settings.ApiPath.TrimEnd('/'), searchType);
|
||||
var baseUrl = string.Format("{0}{1}?t={2}&extended=1", Settings.BaseUrl.TrimEnd('/'), Settings.ApiPath.TrimEnd('/'), searchCriteria.SearchType);
|
||||
var categories = searchCriteria.Categories;
|
||||
|
||||
if (categories != null && categories.Any())
|
||||
{
|
||||
@@ -174,16 +141,23 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
baseUrl += "&apikey=" + Settings.ApiKey;
|
||||
}
|
||||
|
||||
if (searchCriteria.Limit.HasValue)
|
||||
{
|
||||
parameters += string.Format("&limit={0}", searchCriteria.Limit);
|
||||
}
|
||||
|
||||
if (searchCriteria.Offset.HasValue)
|
||||
{
|
||||
parameters += string.Format("&offset={0}", searchCriteria.Offset);
|
||||
}
|
||||
|
||||
if (PageSize == 0)
|
||||
{
|
||||
yield return new IndexerRequest(string.Format("{0}{1}", baseUrl, parameters), HttpAccept.Rss);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var page = 0; page < maxPages; page++)
|
||||
{
|
||||
yield return new IndexerRequest(string.Format("{0}&offset={1}&limit={2}{3}", baseUrl, page * PageSize, PageSize, parameters), HttpAccept.Rss);
|
||||
}
|
||||
yield return new IndexerRequest(string.Format("{0}&offset={1}&limit={2}{3}", baseUrl, searchCriteria.Offset, searchCriteria.Limit, parameters), HttpAccept.Rss);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -96,6 +96,27 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
return ParseUrl(item.TryGetValue("comments"));
|
||||
}
|
||||
|
||||
protected override ICollection<IndexerCategory> GetCategory(XElement item)
|
||||
{
|
||||
var cats = TryGetMultipleNewznabAttributes(item, "category");
|
||||
var results = new List<IndexerCategory>();
|
||||
|
||||
foreach (var cat in cats)
|
||||
{
|
||||
if (int.TryParse(cat, out var intCategory))
|
||||
{
|
||||
var indexerCat = _settings.Categories.FirstOrDefault(c => c.Id == intCategory);
|
||||
|
||||
if (indexerCat != null)
|
||||
{
|
||||
results.Add(indexerCat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
protected override long GetSize(XElement item)
|
||||
{
|
||||
long size;
|
||||
@@ -174,5 +195,22 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
protected List<string> TryGetMultipleNewznabAttributes(XElement item, string key)
|
||||
{
|
||||
var attrElements = item.Elements(ns + "attr").Where(e => e.Attribute("name").Value.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||||
var results = new List<string>();
|
||||
|
||||
foreach (var element in attrElements)
|
||||
{
|
||||
var attrValue = element.Attribute("value");
|
||||
if (attrValue != null)
|
||||
{
|
||||
results.Add(attrValue.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -76,6 +76,8 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
Type = FieldType.Checkbox)]
|
||||
public bool RemoveYear { get; set; }
|
||||
|
||||
public List<IndexerCategory> Categories { get; set; }
|
||||
|
||||
// Field 8 is used by TorznabSettings MinimumSeeders
|
||||
// If you need to add another field here, update TorznabSettings as well and this comment
|
||||
public virtual NzbDroneValidationResult Validate()
|
||||
|
@@ -11,6 +11,7 @@ using NzbDrone.Core.Http.CloudFlare;
|
||||
using NzbDrone.Core.Indexers.Exceptions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
@@ -292,6 +293,11 @@ namespace NzbDrone.Core.Indexers
|
||||
return CleanupReleases(releases);
|
||||
}
|
||||
|
||||
public override IndexerCapabilities GetCapabilities()
|
||||
{
|
||||
return Capabilities ?? ((IndexerDefinition)Definition).Capabilities;
|
||||
}
|
||||
|
||||
protected virtual bool IsValidRelease(ReleaseInfo release)
|
||||
{
|
||||
if (release.DownloadUrl == null)
|
||||
|
@@ -19,5 +19,7 @@ namespace NzbDrone.Core.Indexers
|
||||
IList<ReleaseInfo> Fetch(TvSearchCriteria searchCriteria);
|
||||
IList<ReleaseInfo> Fetch(BookSearchCriteria searchCriteria);
|
||||
IList<ReleaseInfo> Fetch(BasicSearchCriteria searchCriteria);
|
||||
|
||||
IndexerCapabilities GetCapabilities();
|
||||
}
|
||||
}
|
||||
|
@@ -71,6 +71,8 @@ namespace NzbDrone.Core.Indexers
|
||||
public abstract IList<ReleaseInfo> Fetch(BookSearchCriteria searchCriteria);
|
||||
public abstract IList<ReleaseInfo> Fetch(BasicSearchCriteria searchCriteria);
|
||||
|
||||
public abstract IndexerCapabilities GetCapabilities();
|
||||
|
||||
protected virtual IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases)
|
||||
{
|
||||
var result = releases.DistinctBy(v => v.Guid).ToList();
|
||||
|
@@ -22,7 +22,8 @@ namespace NzbDrone.Core.Indexers
|
||||
ImdbId,
|
||||
TmdbId,
|
||||
ImdbTitle,
|
||||
ImdbYear
|
||||
ImdbYear,
|
||||
TraktId,
|
||||
}
|
||||
|
||||
public enum MusicSearchParam
|
||||
@@ -67,6 +68,7 @@ namespace NzbDrone.Core.Indexers
|
||||
public bool MovieSearchAvailable => MovieSearchParams.Count > 0;
|
||||
public bool MovieSearchImdbAvailable => MovieSearchParams.Contains(MovieSearchParam.ImdbId);
|
||||
public bool MovieSearchTmdbAvailable => MovieSearchParams.Contains(MovieSearchParam.TmdbId);
|
||||
public bool MovieSearchTraktAvailable => MovieSearchParams.Contains(MovieSearchParam.TraktId);
|
||||
|
||||
public List<MusicSearchParam> MusicSearchParams;
|
||||
public bool MusicSearchAvailable => MusicSearchParams.Count > 0;
|
||||
|
@@ -168,7 +168,7 @@ namespace NzbDrone.Core.Indexers
|
||||
private void AddTorznabCategoryTree(IndexerCategory torznabCategory)
|
||||
{
|
||||
// build the category tree
|
||||
if (TorznabCatType.ParentCats.Contains(torznabCategory))
|
||||
if (NewznabStandardCategory.ParentCats.Contains(torznabCategory))
|
||||
{
|
||||
// parent cat
|
||||
if (!_torznabCategoryTree.Contains(torznabCategory))
|
||||
@@ -179,7 +179,7 @@ namespace NzbDrone.Core.Indexers
|
||||
else
|
||||
{
|
||||
// child or custom cat
|
||||
var parentCat = TorznabCatType.ParentCats.FirstOrDefault(c => c.Contains(torznabCategory));
|
||||
var parentCat = NewznabStandardCategory.ParentCats.FirstOrDefault(c => c.Contains(torznabCategory));
|
||||
if (parentCat != null)
|
||||
{
|
||||
// child cat
|
||||
@@ -203,9 +203,39 @@ namespace NzbDrone.Core.Indexers
|
||||
else
|
||||
{
|
||||
// custom cat
|
||||
if (torznabCategory.Id > 1000 && torznabCategory.Id < 10000)
|
||||
{
|
||||
var potentialParent = NewznabStandardCategory.ParentCats.FirstOrDefault(c => (c.Id / 1000) == (torznabCategory.Id / 1000));
|
||||
if (potentialParent != null)
|
||||
{
|
||||
var nodeCat = _torznabCategoryTree.FirstOrDefault(c => c.Equals(potentialParent));
|
||||
if (nodeCat != null)
|
||||
{
|
||||
// parent cat already exists
|
||||
if (!nodeCat.Contains(torznabCategory))
|
||||
{
|
||||
nodeCat.SubCategories.Add(torznabCategory);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// create parent cat and add child
|
||||
nodeCat = potentialParent.CopyWithoutSubCategories();
|
||||
nodeCat.SubCategories.Add(torznabCategory);
|
||||
_torznabCategoryTree.Add(nodeCat);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_torznabCategoryTree.Add(torznabCategory);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_torznabCategoryTree.Add(torznabCategory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ using FluentValidation.Results;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Composition;
|
||||
using NzbDrone.Core.Indexers.Cardigann;
|
||||
using NzbDrone.Core.Indexers.Newznab;
|
||||
using NzbDrone.Core.IndexerVersions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
@@ -22,10 +23,12 @@ namespace NzbDrone.Core.Indexers
|
||||
public class IndexerFactory : ProviderFactory<IIndexer, IndexerDefinition>, IIndexerFactory
|
||||
{
|
||||
private readonly IIndexerDefinitionUpdateService _definitionService;
|
||||
private readonly INewznabCapabilitiesProvider _newznabCapabilitiesProvider;
|
||||
private readonly IIndexerStatusService _indexerStatusService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public IndexerFactory(IIndexerDefinitionUpdateService definitionService,
|
||||
INewznabCapabilitiesProvider newznabCapabilitiesProvider,
|
||||
IIndexerStatusService indexerStatusService,
|
||||
IIndexerRepository providerRepository,
|
||||
IEnumerable<IIndexer> providers,
|
||||
@@ -36,6 +39,7 @@ namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
_definitionService = definitionService;
|
||||
_indexerStatusService = indexerStatusService;
|
||||
_newznabCapabilitiesProvider = newznabCapabilitiesProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -89,7 +93,7 @@ namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
foreach (var category in defFile.Caps.Categories)
|
||||
{
|
||||
var cat = TorznabCatType.GetCatByName(category.Value);
|
||||
var cat = NewznabStandardCategory.GetCatByName(category.Value);
|
||||
|
||||
if (cat == null)
|
||||
{
|
||||
@@ -108,7 +112,7 @@ namespace NzbDrone.Core.Indexers
|
||||
|
||||
if (categorymapping.cat != null)
|
||||
{
|
||||
torznabCat = TorznabCatType.GetCatByName(categorymapping.cat);
|
||||
torznabCat = NewznabStandardCategory.GetCatByName(categorymapping.cat);
|
||||
if (torznabCat == null)
|
||||
{
|
||||
continue;
|
||||
@@ -242,6 +246,14 @@ namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
definition.Added = DateTime.UtcNow;
|
||||
|
||||
var provider = _providers.First(v => v.GetType().Name == definition.Implementation);
|
||||
|
||||
if (definition.Implementation == typeof(Newznab.Newznab).Name)
|
||||
{
|
||||
var settings = (NewznabSettings)definition.Settings;
|
||||
settings.Categories = _newznabCapabilitiesProvider.GetCapabilities(settings).Categories.GetTorznabCategoryList();
|
||||
}
|
||||
|
||||
return base.Create(definition);
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ using System.Linq;
|
||||
|
||||
namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
public static class TorznabCatType
|
||||
public static class NewznabStandardCategory
|
||||
{
|
||||
public static readonly IndexerCategory Console = new IndexerCategory(1000, "Console");
|
||||
public static readonly IndexerCategory ConsoleNDS = new IndexerCategory(1010, "Console/NDS");
|
||||
@@ -171,7 +171,7 @@ namespace NzbDrone.Core.Indexers
|
||||
OtherHashed
|
||||
};
|
||||
|
||||
static TorznabCatType()
|
||||
static NewznabStandardCategory()
|
||||
{
|
||||
Console.SubCategories.AddRange(
|
||||
new List<IndexerCategory>
|
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
@@ -160,6 +160,7 @@ namespace NzbDrone.Core.Indexers
|
||||
releaseInfo.DownloadUrl = GetDownloadUrl(item);
|
||||
releaseInfo.InfoUrl = GetInfoUrl(item);
|
||||
releaseInfo.CommentUrl = GetCommentUrl(item);
|
||||
releaseInfo.Category = GetCategory(item);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -188,6 +189,11 @@ namespace NzbDrone.Core.Indexers
|
||||
return item.TryGetValue("title", "Unknown");
|
||||
}
|
||||
|
||||
protected virtual ICollection<IndexerCategory> GetCategory(XElement item)
|
||||
{
|
||||
return new List<IndexerCategory> { NewznabStandardCategory.Other };
|
||||
}
|
||||
|
||||
protected virtual DateTime GetPublishDate(XElement item)
|
||||
{
|
||||
var dateString = item.TryGetValue("pubDate");
|
||||
|
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Applications;
|
||||
using NzbDrone.Core.Backup;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.HealthCheck;
|
||||
@@ -61,6 +62,7 @@ namespace NzbDrone.Core.Jobs
|
||||
new ScheduledTask { Interval = 6 * 60, TypeName = typeof(CheckHealthCommand).FullName },
|
||||
new ScheduledTask { Interval = 24 * 60, TypeName = typeof(HousekeepingCommand).FullName },
|
||||
new ScheduledTask { Interval = 6 * 60, TypeName = typeof(IndexerDefinitionUpdateCommand).FullName },
|
||||
new ScheduledTask { Interval = 6 * 60, TypeName = typeof(ApplicationIndexerSyncCommand).FullName },
|
||||
|
||||
new ScheduledTask
|
||||
{
|
||||
|
@@ -14,8 +14,8 @@
|
||||
"AddMovies": "Add Movies",
|
||||
"AddMoviesMonitored": "Add Movies Monitored",
|
||||
"AddNew": "Add New",
|
||||
"AddNewMessage": "It's easy to add a new movie, just start typing the name of the movie you want to add",
|
||||
"AddNewIndexer": "Add New Indexer",
|
||||
"AddNewMessage": "It's easy to add a new movie, just start typing the name of the movie you want to add",
|
||||
"AddNewTmdbIdMessage": "You can also search using TMDb Id of a movie. eg. tmdb:71663",
|
||||
"AddRemotePathMapping": "Add Remote Path Mapping",
|
||||
"AddRestriction": "Add Restriction",
|
||||
@@ -332,6 +332,8 @@
|
||||
"IncludeUnmonitored": "Include Unmonitored",
|
||||
"Indexer": "Indexer",
|
||||
"IndexerFlags": "Indexer Flags",
|
||||
"IndexerLongTermStatusCheckAllClientMessage": "All indexers are unavailable due to failures for more than 6 hours",
|
||||
"IndexerLongTermStatusCheckSingleClientMessage": "Indexers unavailable due to failures for more than 6 hours: {0}",
|
||||
"IndexerPriority": "Indexer Priority",
|
||||
"IndexerPriorityHelpText": "Indexer Priority from 1 (Highest) to 50 (Lowest). Default: 25.",
|
||||
"IndexerRssHealthCheckNoAvailableIndexers": "All rss-capable indexers are temporarily unavailable due to recent indexer errors",
|
||||
@@ -341,11 +343,10 @@
|
||||
"IndexerSearchCheckNoAvailableIndexersMessage": "All search-capable indexers are temporarily unavailable due to recent indexer errors",
|
||||
"IndexerSearchCheckNoInteractiveMessage": "No indexers available with Interactive Search enabled, Prowlarr will not provide any interactive search results",
|
||||
"IndexerSettings": "Indexer Settings",
|
||||
"IndexersSelectedInterp": "{0} Indexer(s) Selected",
|
||||
"IndexersSettingsSummary": "Indexers and release restrictions",
|
||||
"IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures",
|
||||
"IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}",
|
||||
"IndexerLongTermStatusCheckAllClientMessage": "All indexers are unavailable due to failures for more than 6 hours",
|
||||
"IndexerLongTermStatusCheckSingleClientMessage": "Indexers unavailable due to failures for more than 6 hours: {0}",
|
||||
"Info": "Info",
|
||||
"InteractiveImport": "Interactive Import",
|
||||
"InteractiveSearch": "Interactive Search",
|
||||
@@ -452,7 +453,6 @@
|
||||
"MovieIsUnmonitored": "Movie is unmonitored",
|
||||
"MovieNaming": "Movie Naming",
|
||||
"Movies": "Movies",
|
||||
"IndexersSelectedInterp": "{0} Indexer(s) Selected",
|
||||
"MovieTitle": "Movie Title",
|
||||
"MovieTitleHelpText": "The title of the movie to exclude (can be anything meaningful)",
|
||||
"MovieYear": "Movie Year",
|
||||
@@ -530,6 +530,12 @@
|
||||
"Proper": "Proper",
|
||||
"Protocol": "Protocol",
|
||||
"ProtocolHelpText": "Choose which protocol(s) to use and which one is preferred when choosing between otherwise equal releases",
|
||||
"Prowlarr": "Prowlarr",
|
||||
"ProwlarrSupportsAnyDownloadClient": "Prowlarr supports any download client that uses the Newznab standard, as well as other download clients listed below.",
|
||||
"ProwlarrSupportsAnyIndexer": "Prowlarr supports any indexer that uses the Newznab standard, as well as other indexers listed below.",
|
||||
"ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Prowlarr supports any RSS movie lists as well as the one stated below.",
|
||||
"ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Prowlarr supports custom conditions against the release properties below.",
|
||||
"ProwlarrTags": "Prowlarr Tags",
|
||||
"Proxy": "Proxy",
|
||||
"ProxyBypassFilterHelpText": "Use ',' as a separator, and '*.' as a wildcard for subdomains",
|
||||
"ProxyCheckBadRequestMessage": "Failed to test proxy. StatusCode: {0}",
|
||||
@@ -551,12 +557,6 @@
|
||||
"Queue": "Queue",
|
||||
"Queued": "Queued",
|
||||
"QuickImport": "Quick Import",
|
||||
"Prowlarr": "Prowlarr",
|
||||
"ProwlarrSupportsAnyDownloadClient": "Prowlarr supports any download client that uses the Newznab standard, as well as other download clients listed below.",
|
||||
"ProwlarrSupportsAnyIndexer": "Prowlarr supports any indexer that uses the Newznab standard, as well as other indexers listed below.",
|
||||
"ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Prowlarr supports any RSS movie lists as well as the one stated below.",
|
||||
"ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Prowlarr supports custom conditions against the release properties below.",
|
||||
"ProwlarrTags": "Prowlarr Tags",
|
||||
"Ratings": "Ratings",
|
||||
"ReadTheWikiForMoreInformation": "Read the Wiki for more information",
|
||||
"Real": "Real",
|
||||
@@ -727,6 +727,7 @@
|
||||
"Style": "Style",
|
||||
"SubfolderWillBeCreatedAutomaticallyInterp": "'{0}' subfolder will be created automatically",
|
||||
"SuggestTranslationChange": "Suggest translation change",
|
||||
"SyncAppIndexers": "Sync App Indexers",
|
||||
"System": "System",
|
||||
"SystemTimeCheckMessage": "System time is off by more than 1 day. Scheduled tasks may not run correctly until the time is corrected",
|
||||
"Table": "Table",
|
||||
@@ -740,6 +741,7 @@
|
||||
"Tasks": "Tasks",
|
||||
"Test": "Test",
|
||||
"TestAll": "Test All",
|
||||
"TestAllApps": "Test All Apps",
|
||||
"TestAllClients": "Test All Clients",
|
||||
"TestAllIndexers": "Test All Indexers",
|
||||
"TestAllLists": "Test All Lists",
|
||||
|
@@ -59,7 +59,7 @@ namespace Prowlarr.Api.V1.Indexers
|
||||
switch (requestType)
|
||||
{
|
||||
case "caps":
|
||||
Response response = indexer.Capabilities.ToXml();
|
||||
Response response = indexerInstance.GetCapabilities().ToXml();
|
||||
response.ContentType = "application/rss+xml";
|
||||
return response;
|
||||
case "tvsearch":
|
||||
|
Reference in New Issue
Block a user