mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2026-04-17 21:44:48 -04:00
Lots of workings to search processing, UI Categories
This commit is contained in:
@@ -4,48 +4,25 @@ import Label from 'Components/Label';
|
||||
|
||||
function CapabilitiesLabel(props) {
|
||||
const {
|
||||
movieSearchAvailable,
|
||||
tvSearchAvailable,
|
||||
musicSearchAvailable,
|
||||
bookSearchAvailable
|
||||
categories
|
||||
} = props.capabilities;
|
||||
|
||||
const filteredList = categories.filter((item) => item.id < 100000).map((item) => item.name).sort();
|
||||
|
||||
return (
|
||||
<span>
|
||||
{
|
||||
bookSearchAvailable ?
|
||||
<Label>
|
||||
{'Books'}
|
||||
</Label> :
|
||||
null
|
||||
filteredList.map((category) => {
|
||||
return (
|
||||
<Label key={category}>
|
||||
{category}
|
||||
</Label>
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
movieSearchAvailable ?
|
||||
<Label>
|
||||
{'Movies'}
|
||||
</Label> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
musicSearchAvailable ?
|
||||
<Label>
|
||||
{'Music'}
|
||||
</Label> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
tvSearchAvailable ?
|
||||
<Label>
|
||||
{'TV'}
|
||||
</Label> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
!tvSearchAvailable && !musicSearchAvailable && !movieSearchAvailable && !bookSearchAvailable ?
|
||||
filteredList.length === 0 ?
|
||||
<Label>
|
||||
{'None'}
|
||||
</Label> :
|
||||
@@ -61,10 +38,7 @@ CapabilitiesLabel.propTypes = {
|
||||
|
||||
CapabilitiesLabel.defaultProps = {
|
||||
capabilities: {
|
||||
movieSearchAvailable: false,
|
||||
tvSearchAvailable: false,
|
||||
musicSearchAvailable: false,
|
||||
bookSearchAvailable: false
|
||||
categories: []
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
.capabilities {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
flex: 0 0 180px;
|
||||
flex: 0 0 350px;
|
||||
}
|
||||
|
||||
.added {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
.capabilities {
|
||||
composes: cell;
|
||||
|
||||
flex: 0 0 180px;
|
||||
flex: 0 0 350px;
|
||||
}
|
||||
|
||||
.added {
|
||||
|
||||
23
frontend/src/Search/Table/CategoryLabel.js
Normal file
23
frontend/src/Search/Table/CategoryLabel.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Label from 'Components/Label';
|
||||
|
||||
function CategoryLabel({ categories }) {
|
||||
let catName = '';
|
||||
|
||||
if (categories && categories.length > 0) {
|
||||
catName = categories[0].name;
|
||||
}
|
||||
|
||||
return (
|
||||
<Label>
|
||||
{catName}
|
||||
</Label>
|
||||
);
|
||||
}
|
||||
|
||||
CategoryLabel.propTypes = {
|
||||
categories: PropTypes.arrayOf(PropTypes.object).isRequired
|
||||
};
|
||||
|
||||
export default CategoryLabel;
|
||||
@@ -10,6 +10,7 @@
|
||||
flex: 4 0 110px;
|
||||
}
|
||||
|
||||
.category,
|
||||
.indexer {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
flex: 4 0 110px;
|
||||
}
|
||||
|
||||
.category,
|
||||
.indexer {
|
||||
composes: cell;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import formatDateTime from 'Utilities/Date/formatDateTime';
|
||||
import formatAge from 'Utilities/Number/formatAge';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import CategoryLabel from './CategoryLabel';
|
||||
import Peers from './Peers';
|
||||
import ProtocolLabel from './ProtocolLabel';
|
||||
import styles from './SearchIndexRow.css';
|
||||
@@ -22,6 +23,7 @@ class SearchIndexRow extends Component {
|
||||
render() {
|
||||
const {
|
||||
protocol,
|
||||
categories,
|
||||
age,
|
||||
ageHours,
|
||||
ageMinutes,
|
||||
@@ -132,6 +134,19 @@ class SearchIndexRow extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (column.name === 'category') {
|
||||
return (
|
||||
<VirtualTableRowCell
|
||||
key={column.name}
|
||||
className={styles[column.name]}
|
||||
>
|
||||
<CategoryLabel
|
||||
categories={categories}
|
||||
/>
|
||||
</VirtualTableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (column.name === 'indexerFlags') {
|
||||
return (
|
||||
<VirtualTableRowCell
|
||||
@@ -192,6 +207,7 @@ class SearchIndexRow extends Component {
|
||||
|
||||
SearchIndexRow.propTypes = {
|
||||
guid: PropTypes.string.isRequired,
|
||||
categories: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
protocol: PropTypes.string.isRequired,
|
||||
age: PropTypes.number.isRequired,
|
||||
ageHours: PropTypes.number.isRequired,
|
||||
|
||||
@@ -66,6 +66,12 @@ export const defaultState = {
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'category',
|
||||
label: translate('Category'),
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'indexerFlags',
|
||||
label: React.createElement(Icon, { name: icons.FLAG }),
|
||||
|
||||
@@ -34,25 +34,6 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
|
||||
_movieSearchCriteria.ImdbId = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_all_categories_for_feed()
|
||||
{
|
||||
var results = Subject.GetRecentRequests();
|
||||
|
||||
results.GetAllTiers().Should().HaveCount(1);
|
||||
|
||||
var page = results.GetAllTiers().First().First();
|
||||
|
||||
var encoding = HttpHeader.GetEncodingFromContentType(page.HttpRequest.Headers.ContentType);
|
||||
|
||||
var body = encoding.GetString(page.HttpRequest.ContentData);
|
||||
var query = JsonConvert.DeserializeObject<TorrentQuery>(body);
|
||||
|
||||
query.Category.Should().HaveCount(2);
|
||||
query.Username.Should().Be(Subject.Settings.Username);
|
||||
query.Passkey.Should().Be(Subject.Settings.ApiKey);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_search_by_imdbid_if_supported()
|
||||
{
|
||||
|
||||
@@ -36,30 +36,6 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
|
||||
.Returns(_capabilities);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_all_categories_for_feed()
|
||||
{
|
||||
var results = Subject.GetRecentRequests();
|
||||
|
||||
results.GetAllTiers().Should().HaveCount(1);
|
||||
|
||||
var page = results.GetAllTiers().First().First();
|
||||
|
||||
page.Url.Query.Should().Contain("&cat=1,2&");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_have_duplicate_categories()
|
||||
{
|
||||
var results = Subject.GetRecentRequests();
|
||||
|
||||
results.GetAllTiers().Should().HaveCount(1);
|
||||
|
||||
var page = results.GetAllTiers().First().First();
|
||||
|
||||
page.Url.FullUri.Should().Contain("&cat=1,2,3&");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_subsequent_pages()
|
||||
{
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace NzbDrone.Core.Applications.Lidarr
|
||||
Fields = schema.Fields,
|
||||
};
|
||||
|
||||
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/api/v1/indexer/1/";
|
||||
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/api/v1/indexer/{indexer.Id}/";
|
||||
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/newznab";
|
||||
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace NzbDrone.Core.Applications.Radarr
|
||||
Fields = schema.Fields,
|
||||
};
|
||||
|
||||
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/api/v1/indexer/1/";
|
||||
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/api/v1/indexer/{indexer.Id}/";
|
||||
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/newznab";
|
||||
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace NzbDrone.Core.Applications.Readarr
|
||||
Fields = schema.Fields,
|
||||
};
|
||||
|
||||
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/api/v1/indexer/1/";
|
||||
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/api/v1/indexer/{indexer.Id}/";
|
||||
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/newznab";
|
||||
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace NzbDrone.Core.Applications.Sonarr
|
||||
Fields = schema.Fields,
|
||||
};
|
||||
|
||||
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/api/v1/indexer/1/";
|
||||
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/api/v1/indexer/{indexer.Id}/";
|
||||
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/newznab";
|
||||
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NzbDrone.Core.IndexerSearch.Definitions
|
||||
{
|
||||
public class BasicSearchCriteria : SearchCriteriaBase
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NzbDrone.Core.IndexerSearch.Definitions
|
||||
{
|
||||
public class BookSearchCriteria : SearchCriteriaBase
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,8 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
|
||||
public class MovieSearchCriteria : SearchCriteriaBase
|
||||
{
|
||||
public string ImdbId { get; set; }
|
||||
public int TmdbId { get; set; }
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[{0}]", ImdbId);
|
||||
}
|
||||
public int? TmdbId { get; set; }
|
||||
public int? Year { get; set; }
|
||||
public int? TraktId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NzbDrone.Core.IndexerSearch.Definitions
|
||||
{
|
||||
public class MusicSearchCriteria : SearchCriteriaBase
|
||||
{
|
||||
public string Album { get; set; }
|
||||
public string Artist { get; set; }
|
||||
public string Label { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -16,5 +16,8 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
|
||||
public List<int> IndexerIds { get; set; }
|
||||
public string SearchTerm { get; set; }
|
||||
public int[] Categories { get; set; }
|
||||
public string SearchType { get; set; }
|
||||
public int? Limit { get; set; }
|
||||
public int? Offset { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NzbDrone.Core.IndexerSearch.Definitions
|
||||
{
|
||||
public class TvSearchCriteria : SearchCriteriaBase
|
||||
{
|
||||
public int? Season { get; set; }
|
||||
public int? Ep { get; set; }
|
||||
|
||||
public string ImdbId { get; set; }
|
||||
public int? TvdbId { get; set; }
|
||||
public int? RId { get; set; }
|
||||
public int? TvMazeId { get; set; }
|
||||
public int? TraktId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -7,19 +7,21 @@ namespace NzbDrone.Core.IndexerSearch
|
||||
public string q { get; set; }
|
||||
public string cat { get; set; }
|
||||
public string imdbid { get; set; }
|
||||
public string tmdbid { get; set; }
|
||||
public int? tmdbid { get; set; }
|
||||
public string extended { get; set; }
|
||||
public string limit { get; set; }
|
||||
public string offset { get; set; }
|
||||
public string rid { get; set; }
|
||||
public string tvdbid { get; set; }
|
||||
public string season { get; set; }
|
||||
public string ep { get; set; }
|
||||
public int? limit { get; set; }
|
||||
public int? offset { get; set; }
|
||||
public int? rid { get; set; }
|
||||
public int? tvmazeid { get; set; }
|
||||
public int? traktid { get; set; }
|
||||
public int? tvdbid { get; set; }
|
||||
public int? season { get; set; }
|
||||
public int? ep { get; set; }
|
||||
public string album { get; set; }
|
||||
public string artist { get; set; }
|
||||
public string label { get; set; }
|
||||
public string track { get; set; }
|
||||
public string year { get; set; }
|
||||
public int? year { get; set; }
|
||||
public string genre { get; set; }
|
||||
public string author { get; set; }
|
||||
public string title { get; set; }
|
||||
|
||||
@@ -72,12 +72,14 @@ namespace NzbDrone.Core.IndexerSearch
|
||||
new XElement("guid", r.Guid), // GUID and (Link or Magnet) are mandatory
|
||||
new XElement("prowlarrindexer", new XAttribute("id", r.IndexerId), r.Indexer),
|
||||
r.PublishDate == DateTime.MinValue ? new XElement("pubDate", XmlDateFormat(DateTime.Now)) : new XElement("pubDate", XmlDateFormat(r.PublishDate)),
|
||||
r.Category == null ? null : from c in r.Category select new XElement("category", c),
|
||||
new XElement("size", r.Size),
|
||||
r.Category == null ? null : from c in r.Category select new XElement("category", c.Id),
|
||||
new XElement(
|
||||
"enclosure",
|
||||
new XAttribute("length", r.Size),
|
||||
new XAttribute("url", r.DownloadUrl ?? t.MagnetUrl ?? string.Empty),
|
||||
r.Size == null ? null : new XAttribute("length", r.Size),
|
||||
new XAttribute("type", "application/x-bittorrent")),
|
||||
r.Category == null ? null : from c in r.Category select GetTorznabElement("category", c.Id),
|
||||
GetTorznabElement("rageid", r.TvRageId),
|
||||
GetTorznabElement("thetvdb", r.TvdbId),
|
||||
GetTorznabElement("imdb", r.ImdbId.ToString("D7")),
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace NzbDrone.Core.IndexerSearch
|
||||
{
|
||||
public interface ISearchForNzb
|
||||
{
|
||||
List<ReleaseInfo> Search(string query, List<int> indexerIds, bool interactiveSearch);
|
||||
NewznabResults Search(NewznabRequest request, List<int> indexerIds, bool interactiveSearch);
|
||||
}
|
||||
|
||||
@@ -35,17 +34,70 @@ namespace NzbDrone.Core.IndexerSearch
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<ReleaseInfo> Search(string query, List<int> indexerIds, bool interactiveSearch)
|
||||
{
|
||||
var searchSpec = Get<MovieSearchCriteria>(new NewznabRequest { q = query }, indexerIds, interactiveSearch);
|
||||
|
||||
return Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
|
||||
}
|
||||
|
||||
public NewznabResults Search(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
|
||||
{
|
||||
var results = new NewznabResults();
|
||||
|
||||
switch (request.t)
|
||||
{
|
||||
case "movie":
|
||||
return MovieSearch(request, indexerIds, interactiveSearch);
|
||||
case "music":
|
||||
return MusicSearch(request, indexerIds, interactiveSearch);
|
||||
case "tvsearch":
|
||||
return TvSearch(request, indexerIds, interactiveSearch);
|
||||
case "book":
|
||||
return BookSearch(request, indexerIds, interactiveSearch);
|
||||
default:
|
||||
return BasicSearch(request, indexerIds, interactiveSearch);
|
||||
}
|
||||
}
|
||||
|
||||
private NewznabResults MovieSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
|
||||
{
|
||||
var searchSpec = Get<MovieSearchCriteria>(request, indexerIds, interactiveSearch);
|
||||
|
||||
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) };
|
||||
}
|
||||
|
||||
private NewznabResults MusicSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
|
||||
{
|
||||
var searchSpec = Get<MusicSearchCriteria>(request, indexerIds, interactiveSearch);
|
||||
|
||||
return new NewznabResults { Releases = Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
|
||||
}
|
||||
|
||||
private NewznabResults TvSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
|
||||
{
|
||||
var searchSpec = Get<TvSearchCriteria>(request, indexerIds, interactiveSearch);
|
||||
|
||||
searchSpec.Season = request.season;
|
||||
searchSpec.Ep = request.ep;
|
||||
searchSpec.TvdbId = request.tvdbid;
|
||||
searchSpec.ImdbId = request.imdbid;
|
||||
searchSpec.TraktId = request.traktid;
|
||||
searchSpec.RId = request.rid;
|
||||
searchSpec.TvMazeId = request.tvmazeid;
|
||||
|
||||
return new NewznabResults { Releases = Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
|
||||
}
|
||||
|
||||
private NewznabResults BookSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
|
||||
{
|
||||
var searchSpec = Get<TvSearchCriteria>(request, indexerIds, interactiveSearch);
|
||||
|
||||
return new NewznabResults { Releases = Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
|
||||
}
|
||||
|
||||
private NewznabResults BasicSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
|
||||
{
|
||||
var searchSpec = Get<BasicSearchCriteria>(request, indexerIds, interactiveSearch);
|
||||
|
||||
return new NewznabResults { Releases = Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
|
||||
}
|
||||
|
||||
@@ -67,6 +119,9 @@ namespace NzbDrone.Core.IndexerSearch
|
||||
}
|
||||
|
||||
spec.SearchTerm = query.q;
|
||||
spec.SearchType = query.t;
|
||||
spec.Limit = query.limit;
|
||||
spec.Offset = query.offset;
|
||||
|
||||
spec.IndexerIds = indexerIds;
|
||||
|
||||
|
||||
@@ -37,5 +37,25 @@ namespace NzbDrone.Core.Indexers.AwesomeHD
|
||||
yield return new IndexerRequest($"{Settings.BaseUrl.Trim().TrimEnd('/')}/searchapi.php?action=latestmovies&passkey={Settings.Passkey.Trim()}", HttpAccept.Rss);
|
||||
}
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using AngleSharp.Dom;
|
||||
@@ -9,7 +10,6 @@ using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Cardigann
|
||||
{
|
||||
@@ -22,7 +22,8 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
|
||||
protected string SiteLink { get; private set; }
|
||||
|
||||
/* protected readonly List<CategoryMapping> categoryMapping = new List<CategoryMapping>(); */
|
||||
protected readonly List<CategoryMapping> _categoryMapping = new List<CategoryMapping>();
|
||||
protected readonly List<string> _defaultCategories = new List<string>();
|
||||
|
||||
protected readonly string[] OptionalFields = new string[] { "imdb", "rageid", "tvdbid", "banner" };
|
||||
|
||||
@@ -54,6 +55,70 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
_logger = logger;
|
||||
|
||||
SiteLink = definition.Links.First();
|
||||
|
||||
if (_definition.Caps.Categories != null)
|
||||
{
|
||||
foreach (var category in _definition.Caps.Categories)
|
||||
{
|
||||
var cat = TorznabCatType.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));
|
||||
continue;
|
||||
}
|
||||
|
||||
AddCategoryMapping(category.Key, cat);
|
||||
}
|
||||
}
|
||||
|
||||
if (_definition.Caps.Categorymappings != null)
|
||||
{
|
||||
foreach (var categorymapping in _definition.Caps.Categorymappings)
|
||||
{
|
||||
IndexerCategory torznabCat = null;
|
||||
|
||||
if (categorymapping.cat != null)
|
||||
{
|
||||
torznabCat = TorznabCatType.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));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
AddCategoryMapping(categorymapping.id, torznabCat, categorymapping.desc);
|
||||
|
||||
if (categorymapping.Default)
|
||||
{
|
||||
_defaultCategories.Add(categorymapping.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddCategoryMapping(string trackerCategory, IndexerCategory torznabCategory, string trackerCategoryDesc = null)
|
||||
{
|
||||
_categoryMapping.Add(new CategoryMapping(trackerCategory, trackerCategoryDesc, torznabCategory.Id));
|
||||
|
||||
if (trackerCategoryDesc == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// create custom cats (1:1 categories) if trackerCategoryDesc is defined
|
||||
// - if trackerCategory is "integer" we use that number to generate custom category id
|
||||
// - if trackerCategory is "string" we compute a hash to generate fixed integer id for the custom category
|
||||
// the hash is not perfect but it should work in most cases. we can't use sequential numbers because
|
||||
// categories are updated frequently and the id must be fixed to work in 3rd party apps
|
||||
if (!int.TryParse(trackerCategory, out var trackerCategoryInt))
|
||||
{
|
||||
var hashed = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(trackerCategory));
|
||||
trackerCategoryInt = BitConverter.ToUInt16(hashed, 0); // id between 0 and 65535 < 100000
|
||||
}
|
||||
|
||||
var customCat = new IndexerCategory(trackerCategoryInt + 100000, trackerCategoryDesc);
|
||||
_categoryMapping.Add(new CategoryMapping(trackerCategory, trackerCategoryDesc, customCat.Id));
|
||||
}
|
||||
|
||||
protected IElement QuerySelector(IElement element, string selector)
|
||||
@@ -186,53 +251,36 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
return variables;
|
||||
}
|
||||
|
||||
protected ICollection<int> MapTrackerCatToNewznab(string input)
|
||||
protected ICollection<IndexerCategory> MapTrackerCatToNewznab(string input)
|
||||
{
|
||||
if (input == null)
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
return new List<int>();
|
||||
}
|
||||
|
||||
var cats = _definition.Caps.Categorymappings.Where(m => m.id != null && m.id.ToLowerInvariant() == input.ToLowerInvariant()).Select(c => TorznabCatType.GetCatByName(c.cat).Id).ToList();
|
||||
|
||||
// 1:1 category mapping
|
||||
try
|
||||
{
|
||||
var trackerCategoryInt = int.Parse(input);
|
||||
cats.Add(trackerCategoryInt + 100000);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
// input is not an integer, continue
|
||||
return new List<IndexerCategory>();
|
||||
}
|
||||
|
||||
var cats = _categoryMapping
|
||||
.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 })
|
||||
.ToList();
|
||||
return cats;
|
||||
}
|
||||
|
||||
public List<string> MapTorznabCapsToTrackers(int[] searchCategories, bool mapChildrenCatsToParent = false)
|
||||
{
|
||||
var queryCats = new List<string>();
|
||||
|
||||
if (searchCategories == null)
|
||||
{
|
||||
return queryCats;
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
foreach (var searchCat in searchCategories)
|
||||
{
|
||||
var match = TorznabCatType.AllCats.FirstOrDefault(c => c.Id == searchCat);
|
||||
var results = new List<string>();
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
queryCats.Add(match.Name);
|
||||
}
|
||||
}
|
||||
results.AddRange(_categoryMapping
|
||||
.Where(c => searchCategories.Contains(c.NewzNabCategory))
|
||||
.Select(mapping => mapping.TrackerCategory).Distinct().ToList());
|
||||
|
||||
var result = _definition.Caps.Categorymappings
|
||||
.Where(c => queryCats.Contains(c.cat))
|
||||
.Select(mapping => mapping.id).Distinct().ToList();
|
||||
|
||||
return result;
|
||||
return results;
|
||||
}
|
||||
|
||||
protected delegate string TemplateTextModifier(string str);
|
||||
|
||||
@@ -472,13 +472,14 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
|
||||
result.AddRange(releases.Select(x => new TorrentInfo
|
||||
{
|
||||
PublishDate = x.PublishDate,
|
||||
Guid = x.Guid.ToString(),
|
||||
Title = x.Title,
|
||||
Size = x.Size.Value,
|
||||
DownloadUrl = x.Link?.ToString(),
|
||||
DownloadUrl = x.Link.AbsoluteUri,
|
||||
CommentUrl = x.Comments?.ToString(),
|
||||
InfoUrl = x.Link?.ToString(),
|
||||
MagnetUrl = x.MagnetUri?.ToString(),
|
||||
MagnetUrl = x.MagnetUri?.AbsoluteUri,
|
||||
InfoHash = x.InfoHash,
|
||||
Seeders = (int?)x.Seeders,
|
||||
Peers = (int?)x.Peers,
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
public Uri Link { get; set; }
|
||||
public Uri Comments { get; set; }
|
||||
public DateTime PublishDate { get; set; }
|
||||
public ICollection<int> Category { get; set; }
|
||||
public ICollection<IndexerCategory> Category { get; set; }
|
||||
public long? Size { get; set; }
|
||||
public long? Files { get; set; }
|
||||
public long? Grabs { get; set; }
|
||||
|
||||
@@ -10,8 +10,6 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
{
|
||||
public class CardigannRequestGenerator : CardigannBase, IIndexerRequestGenerator
|
||||
{
|
||||
private List<string> _defaultCategories = new List<string>();
|
||||
|
||||
public CardigannRequestGenerator(CardigannDefinition definition,
|
||||
CardigannSettings settings,
|
||||
Logger logger)
|
||||
@@ -22,71 +20,134 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
|
||||
public virtual IndexerPageableRequestChain GetRecentRequests()
|
||||
{
|
||||
_logger.Trace("Getting recent");
|
||||
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
var variables = GetBaseTemplateVariables();
|
||||
|
||||
variables[".Query.Type"] = null;
|
||||
variables[".Query.Q"] = null;
|
||||
variables[".Query.Categories"] = null;
|
||||
variables[".Query.IMDBID"] = null;
|
||||
variables[".Query.IMDBIDShort"] = null;
|
||||
variables[".Query.TMDBID"] = null;
|
||||
|
||||
pageableRequests.Add(GetRequest(variables));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
_logger.Trace("Getting search");
|
||||
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
var variables = GetBaseTemplateVariables();
|
||||
var variables = GetQueryVariableDefaults(searchCriteria);
|
||||
|
||||
variables[".Query.Type"] = "movie";
|
||||
variables[".Query.Q"] = searchCriteria.SearchTerm;
|
||||
variables[".Query.Categories"] = searchCriteria.Categories;
|
||||
variables[".Query.Movie"] = null;
|
||||
variables[".Query.Year"] = searchCriteria.Year;
|
||||
variables[".Query.IMDBID"] = searchCriteria.ImdbId;
|
||||
variables[".Query.IMDBIDShort"] = null;
|
||||
variables[".Query.IMDBIDShort"] = searchCriteria.ImdbId.Replace("tt", "");
|
||||
variables[".Query.TMDBID"] = searchCriteria.TmdbId;
|
||||
variables[".Query.TraktID"] = searchCriteria.TraktId;
|
||||
|
||||
pageableRequests.Add(GetRequest(variables));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetRequest(Dictionary<string, object> variables)
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var search = _definition.Search;
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
var variables = GetQueryVariableDefaults(searchCriteria);
|
||||
|
||||
variables[".Query.Album"] = searchCriteria.Album;
|
||||
variables[".Query.Artist"] = searchCriteria.Artist;
|
||||
variables[".Query.Label"] = searchCriteria.Label;
|
||||
variables[".Query.Track"] = null;
|
||||
|
||||
pageableRequests.Add(GetRequest(variables));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
var variables = GetQueryVariableDefaults(searchCriteria);
|
||||
|
||||
variables[".Query.Series"] = null;
|
||||
variables[".Query.Ep"] = searchCriteria.Ep;
|
||||
variables[".Query.Season"] = searchCriteria.Season;
|
||||
variables[".Query.IMDBID"] = searchCriteria.ImdbId;
|
||||
variables[".Query.IMDBIDShort"] = searchCriteria.ImdbId.Replace("tt", "");
|
||||
variables[".Query.TVDBID"] = searchCriteria.TvdbId;
|
||||
variables[".Query.TVRageID"] = searchCriteria.RId;
|
||||
variables[".Query.TVMazeID"] = searchCriteria.TvMazeId;
|
||||
variables[".Query.TraktID"] = searchCriteria.TraktId;
|
||||
|
||||
pageableRequests.Add(GetRequest(variables));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
var variables = GetQueryVariableDefaults(searchCriteria);
|
||||
|
||||
variables[".Query.Author"] = null;
|
||||
variables[".Query.Title"] = null;
|
||||
|
||||
pageableRequests.Add(GetRequest(variables));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
var variables = GetQueryVariableDefaults(searchCriteria);
|
||||
|
||||
pageableRequests.Add(GetRequest(variables));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
private Dictionary<string, object> GetQueryVariableDefaults(SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var variables = GetBaseTemplateVariables();
|
||||
|
||||
variables[".Query.Type"] = searchCriteria.SearchType;
|
||||
variables[".Query.Q"] = searchCriteria.SearchTerm;
|
||||
variables[".Query.Categories"] = searchCriteria.Categories;
|
||||
variables[".Query.Limit"] = searchCriteria.Limit;
|
||||
variables[".Query.Offset"] = searchCriteria.Offset;
|
||||
variables[".Query.Extended"] = null;
|
||||
variables[".Query.APIKey"] = null;
|
||||
|
||||
//Movie
|
||||
variables[".Query.Movie"] = null;
|
||||
variables[".Query.Year"] = null;
|
||||
variables[".Query.IMDBID"] = null;
|
||||
variables[".Query.IMDBIDShort"] = null;
|
||||
variables[".Query.TMDBID"] = null;
|
||||
|
||||
//Tv
|
||||
variables[".Query.Series"] = null;
|
||||
variables[".Query.Ep"] = null;
|
||||
variables[".Query.Season"] = null;
|
||||
variables[".Query.Movie"] = null;
|
||||
variables[".Query.Year"] = null;
|
||||
variables[".Query.Limit"] = null;
|
||||
variables[".Query.Offset"] = null;
|
||||
variables[".Query.Extended"] = null;
|
||||
variables[".Query.APIKey"] = null;
|
||||
variables[".Query.TVDBID"] = null;
|
||||
variables[".Query.TVRageID"] = null;
|
||||
variables[".Query.TVMazeID"] = null;
|
||||
variables[".Query.TraktID"] = null;
|
||||
|
||||
//Music
|
||||
variables[".Query.Album"] = null;
|
||||
variables[".Query.Artist"] = null;
|
||||
variables[".Query.Label"] = null;
|
||||
variables[".Query.Track"] = null;
|
||||
variables[".Query.Episode"] = null;
|
||||
|
||||
//Book
|
||||
variables[".Query.Author"] = null;
|
||||
variables[".Query.Title"] = null;
|
||||
|
||||
return variables;
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetRequest(Dictionary<string, object> variables)
|
||||
{
|
||||
var search = _definition.Search;
|
||||
|
||||
var mappedCategories = MapTorznabCapsToTrackers((int[])variables[".Query.Categories"]);
|
||||
if (mappedCategories.Count == 0)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,26 @@ namespace NzbDrone.Core.Indexers.FileList
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetRequest(string searchType, string parameters)
|
||||
{
|
||||
var categoriesQuery = string.Join(",", Settings.Categories.Distinct());
|
||||
|
||||
@@ -12,13 +12,6 @@ namespace NzbDrone.Core.Indexers.HDBits
|
||||
{
|
||||
public HDBitsSettings Settings { get; set; }
|
||||
|
||||
public virtual IndexerPageableRequestChain GetRecentRequests()
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
pageableRequests.Add(GetRequest(new TorrentQuery()));
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public virtual IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
@@ -76,5 +69,25 @@ namespace NzbDrone.Core.Indexers.HDBits
|
||||
|
||||
yield return new IndexerRequest(request);
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,26 @@ namespace NzbDrone.Core.Indexers.IPTorrents
|
||||
yield return new IndexerRequest(Settings.BaseUrl, HttpAccept.Rss);
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
@@ -66,25 +66,6 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IndexerPageableRequestChain GetRecentRequests()
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
var capabilities = _capabilitiesProvider.GetCapabilities(Settings);
|
||||
|
||||
// Some indexers might forget to enable movie search, but normal search still works fine. Thus we force a normal search.
|
||||
if (capabilities.MovieSearchParams != null)
|
||||
{
|
||||
pageableRequests.Add(GetPagedRequests(MaxPages, new int[] { 2000 }, "movie", ""));
|
||||
}
|
||||
else if (capabilities.SearchParams != null)
|
||||
{
|
||||
pageableRequests.Add(GetPagedRequests(MaxPages, new int[] { 2000 }, "search", ""));
|
||||
}
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
@@ -94,6 +75,33 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(MaxPages,
|
||||
searchCriteria.Categories,
|
||||
"search",
|
||||
string.Format("&q={0}", NewsnabifyTitle(searchCriteria.SearchTerm))));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
private void AddMovieIdPageableRequests(IndexerPageableRequestChain chain, int maxPages, IEnumerable<int> categories, MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var includeTmdbSearch = SupportsTmdbSearch && searchCriteria.TmdbId > 0;
|
||||
@@ -153,15 +161,14 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, IEnumerable<int> categories, string searchType, string parameters)
|
||||
{
|
||||
if (categories.Empty())
|
||||
var baseUrl = string.Format("{0}{1}?t={2}&extended=1", Settings.BaseUrl.TrimEnd('/'), Settings.ApiPath.TrimEnd('/'), searchType);
|
||||
|
||||
if (categories != null && categories.Any())
|
||||
{
|
||||
yield break;
|
||||
var categoriesQuery = string.Join(",", categories.Distinct());
|
||||
baseUrl += string.Format("&cats={0}", categoriesQuery);
|
||||
}
|
||||
|
||||
var categoriesQuery = string.Join(",", categories.Distinct());
|
||||
|
||||
var baseUrl = string.Format("{0}{1}?t={2}&cat={3}&extended=1{4}", Settings.BaseUrl.TrimEnd('/'), Settings.ApiPath.TrimEnd('/'), searchType, categoriesQuery, Settings.AdditionalParameters);
|
||||
|
||||
if (Settings.ApiKey.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
baseUrl += "&apikey=" + Settings.ApiKey;
|
||||
|
||||
@@ -18,15 +18,6 @@ namespace NzbDrone.Core.Indexers.Nyaa
|
||||
PageSize = 100;
|
||||
}
|
||||
|
||||
public virtual IndexerPageableRequestChain GetRecentRequests()
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(MaxPages, null));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(int maxPages, string term)
|
||||
{
|
||||
var baseUrl = string.Format("{0}/?page=rss{1}", Settings.BaseUrl.TrimEnd('/'), Settings.AdditionalParameters);
|
||||
@@ -65,6 +56,26 @@ namespace NzbDrone.Core.Indexers.Nyaa
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
@@ -16,15 +16,6 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
||||
public IHttpClient HttpClient { get; set; }
|
||||
public Logger Logger { get; set; }
|
||||
|
||||
public virtual IndexerPageableRequestChain GetRecentRequests()
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetRequest(null));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
@@ -66,5 +57,25 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,26 @@ namespace NzbDrone.Core.Indexers.Rarbg
|
||||
yield return new IndexerRequest(requestBuilder.Build());
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
@@ -80,6 +80,26 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
@@ -39,6 +39,26 @@ namespace NzbDrone.Core.Indexers.TorrentRss
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
@@ -49,6 +49,46 @@ namespace NzbDrone.Core.Indexers
|
||||
return FetchReleases(g => g.GetSearchRequests(searchCriteria));
|
||||
}
|
||||
|
||||
public override IList<ReleaseInfo> Fetch(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
if (!SupportsSearch)
|
||||
{
|
||||
return new List<ReleaseInfo>();
|
||||
}
|
||||
|
||||
return FetchReleases(g => g.GetSearchRequests(searchCriteria));
|
||||
}
|
||||
|
||||
public override IList<ReleaseInfo> Fetch(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
if (!SupportsSearch)
|
||||
{
|
||||
return new List<ReleaseInfo>();
|
||||
}
|
||||
|
||||
return FetchReleases(g => g.GetSearchRequests(searchCriteria));
|
||||
}
|
||||
|
||||
public override IList<ReleaseInfo> Fetch(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
if (!SupportsSearch)
|
||||
{
|
||||
return new List<ReleaseInfo>();
|
||||
}
|
||||
|
||||
return FetchReleases(g => g.GetSearchRequests(searchCriteria));
|
||||
}
|
||||
|
||||
public override IList<ReleaseInfo> Fetch(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
if (!SupportsSearch)
|
||||
{
|
||||
return new List<ReleaseInfo>();
|
||||
}
|
||||
|
||||
return FetchReleases(g => g.GetSearchRequests(searchCriteria));
|
||||
}
|
||||
|
||||
protected IndexerPageableRequestChain GetRequestChain(SearchCriteriaBase searchCriteria = null)
|
||||
{
|
||||
var generator = GetRequestGenerator();
|
||||
@@ -254,7 +294,7 @@ namespace NzbDrone.Core.Indexers
|
||||
|
||||
protected virtual bool IsValidRelease(ReleaseInfo release)
|
||||
{
|
||||
if (release.DownloadUrl.IsNullOrWhiteSpace())
|
||||
if (release.DownloadUrl == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -15,5 +15,9 @@ namespace NzbDrone.Core.Indexers
|
||||
IndexerPrivacy Privacy { get; }
|
||||
|
||||
IList<ReleaseInfo> Fetch(MovieSearchCriteria searchCriteria);
|
||||
IList<ReleaseInfo> Fetch(MusicSearchCriteria searchCriteria);
|
||||
IList<ReleaseInfo> Fetch(TvSearchCriteria searchCriteria);
|
||||
IList<ReleaseInfo> Fetch(BookSearchCriteria searchCriteria);
|
||||
IList<ReleaseInfo> Fetch(BasicSearchCriteria searchCriteria);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ namespace NzbDrone.Core.Indexers
|
||||
public interface IIndexerRequestGenerator
|
||||
{
|
||||
IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria);
|
||||
IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria);
|
||||
IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria);
|
||||
IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria);
|
||||
IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria);
|
||||
Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
@@ -66,6 +66,10 @@ namespace NzbDrone.Core.Indexers
|
||||
protected TSettings Settings => (TSettings)Definition.Settings;
|
||||
|
||||
public abstract IList<ReleaseInfo> Fetch(MovieSearchCriteria searchCriteria);
|
||||
public abstract IList<ReleaseInfo> Fetch(MusicSearchCriteria searchCriteria);
|
||||
public abstract IList<ReleaseInfo> Fetch(TvSearchCriteria searchCriteria);
|
||||
public abstract IList<ReleaseInfo> Fetch(BookSearchCriteria searchCriteria);
|
||||
public abstract IList<ReleaseInfo> Fetch(BasicSearchCriteria searchCriteria);
|
||||
|
||||
protected virtual IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases)
|
||||
{
|
||||
|
||||
@@ -114,6 +114,7 @@ namespace NzbDrone.Core.Indexers
|
||||
throw new Exception("In search mode 'search' only 'q' parameter is supported and it's mandatory");
|
||||
}
|
||||
|
||||
SearchParams.Add(SearchParam.Q);
|
||||
break;
|
||||
case "tv-search":
|
||||
ParseTvSearchParams(entry.Value);
|
||||
@@ -277,6 +278,13 @@ namespace NzbDrone.Core.Indexers
|
||||
return string.Join(",", parameters);
|
||||
}
|
||||
|
||||
private string SupportedSearchParams()
|
||||
{
|
||||
var parameters = new List<string> { "q" }; // q is always enabled
|
||||
|
||||
return string.Join(",", parameters);
|
||||
}
|
||||
|
||||
private string SupportedMovieSearchParams()
|
||||
{
|
||||
var parameters = new List<string> { "q" }; // q is always enabled
|
||||
@@ -350,7 +358,7 @@ namespace NzbDrone.Core.Indexers
|
||||
new XElement("searching",
|
||||
new XElement("search",
|
||||
new XAttribute("available", SearchAvailable ? "yes" : "no"),
|
||||
new XAttribute("supportedParams", "q")),
|
||||
new XAttribute("supportedParams", SupportedSearchParams())),
|
||||
new XElement("tv-search",
|
||||
new XAttribute("available", TvSearchAvailable ? "yes" : "no"),
|
||||
new XAttribute("supportedParams", SupportedTvSearchParams())),
|
||||
|
||||
@@ -28,6 +28,26 @@ namespace NzbDrone.Core.Indexers
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return new IndexerPageableRequestChain();
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace NzbDrone.Core.Parser.Model
|
||||
{
|
||||
public string Guid { get; set; }
|
||||
public string Title { get; set; }
|
||||
public long Size { get; set; }
|
||||
public long? Size { get; set; }
|
||||
public string DownloadUrl { get; set; }
|
||||
public string InfoUrl { get; set; }
|
||||
public string CommentUrl { get; set; }
|
||||
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Parser.Model
|
||||
public string Container { get; set; }
|
||||
public string Codec { get; set; }
|
||||
public string Resolution { get; set; }
|
||||
public ICollection<int> Category { get; set; }
|
||||
public ICollection<IndexerCategory> Category { get; set; }
|
||||
|
||||
public IndexerFlags IndexerFlags { get; set; }
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Parser.Model
|
||||
|
||||
41
src/Prowlarr.Api.V1/Indexers/IndexerCapabilityResource.cs
Normal file
41
src/Prowlarr.Api.V1/Indexers/IndexerCapabilityResource.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using Prowlarr.Http.REST;
|
||||
|
||||
namespace Prowlarr.Api.V1.Indexers
|
||||
{
|
||||
public class IndexerCapabilityResource : RestResource
|
||||
{
|
||||
public int? LimitsMax { get; set; }
|
||||
public int? LimitsDefault { get; set; }
|
||||
|
||||
public List<IndexerCategory> Categories;
|
||||
}
|
||||
|
||||
public static class IndexerCapabilitiesResourceMapper
|
||||
{
|
||||
public static IndexerCapabilityResource ToResource(this IndexerCapabilities model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new IndexerCapabilityResource
|
||||
{
|
||||
LimitsMax = model.LimitsMax,
|
||||
LimitsDefault = model.LimitsDefault,
|
||||
Categories = model.Categories.GetTorznabCategoryTree()
|
||||
};
|
||||
}
|
||||
|
||||
public static List<IndexerCapabilityResource> ToResource(this IEnumerable<IndexerCapabilities> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,7 @@ namespace Prowlarr.Api.V1.Indexers
|
||||
return response;
|
||||
case "tvsearch":
|
||||
case "music":
|
||||
case "book":
|
||||
case "movie":
|
||||
Response movieResponse = _nzbSearchService.Search(request, new List<int> { indexer.Id }, false).ToXml();
|
||||
movieResponse.ContentType = "application/rss+xml";
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Prowlarr.Api.V1.Indexers
|
||||
public bool SupportsSearch { get; set; }
|
||||
public DownloadProtocol Protocol { get; set; }
|
||||
public IndexerPrivacy Privacy { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
public IndexerCapabilityResource Capabilities { get; set; }
|
||||
public int Priority { get; set; }
|
||||
public DateTime Added { get; set; }
|
||||
}
|
||||
@@ -59,7 +59,7 @@ namespace Prowlarr.Api.V1.Indexers
|
||||
resource.EnableInteractiveSearch = definition.EnableInteractiveSearch;
|
||||
resource.SupportsRss = definition.SupportsRss;
|
||||
resource.SupportsSearch = definition.SupportsSearch;
|
||||
resource.Capabilities = definition.Capabilities;
|
||||
resource.Capabilities = definition.Capabilities.ToResource();
|
||||
resource.Protocol = definition.Protocol;
|
||||
resource.Privacy = definition.Privacy;
|
||||
resource.Priority = definition.Priority;
|
||||
|
||||
@@ -6,6 +6,7 @@ using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.Core.IndexerSearch;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using Prowlarr.Http;
|
||||
|
||||
@@ -49,7 +50,7 @@ namespace Prowlarr.Api.V1.Search
|
||||
{
|
||||
try
|
||||
{
|
||||
var decisions = _nzbSearhService.Search(query, indexerIds, true);
|
||||
var decisions = _nzbSearhService.Search(new NewznabRequest { q = query, t = "search" }, indexerIds, true).Releases;
|
||||
|
||||
return MapDecisions(decisions);
|
||||
}
|
||||
|
||||
@@ -6,5 +6,6 @@ namespace Prowlarr.Api.V1.Search
|
||||
{
|
||||
public List<int> IndexerIds { get; set; }
|
||||
public string Query { get; set; }
|
||||
public int[] Categories { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Prowlarr.Api.V1.Search
|
||||
public string DownloadUrl { get; set; }
|
||||
public string InfoUrl { get; set; }
|
||||
public IEnumerable<string> IndexerFlags { get; set; }
|
||||
public ICollection<IndexerCategory> Categories { get; set; }
|
||||
|
||||
public string MagnetUrl { get; set; }
|
||||
public string InfoHash { get; set; }
|
||||
@@ -51,7 +52,7 @@ namespace Prowlarr.Api.V1.Search
|
||||
Age = releaseInfo.Age,
|
||||
AgeHours = releaseInfo.AgeHours,
|
||||
AgeMinutes = releaseInfo.AgeMinutes,
|
||||
Size = releaseInfo.Size,
|
||||
Size = releaseInfo.Size ?? 0,
|
||||
IndexerId = releaseInfo.IndexerId,
|
||||
Indexer = releaseInfo.Indexer,
|
||||
Title = releaseInfo.Title,
|
||||
@@ -60,6 +61,7 @@ namespace Prowlarr.Api.V1.Search
|
||||
CommentUrl = releaseInfo.CommentUrl,
|
||||
DownloadUrl = releaseInfo.DownloadUrl,
|
||||
InfoUrl = releaseInfo.InfoUrl,
|
||||
Categories = releaseInfo.Category,
|
||||
|
||||
//ReleaseWeight
|
||||
MagnetUrl = torrentInfo.MagnetUrl,
|
||||
|
||||
Reference in New Issue
Block a user