Compare commits

...

24 Commits

Author SHA1 Message Date
Bogdan
f20319fff1 Bump version to 1.6.3 2023-06-25 19:15:06 +03:00
Bogdan
20bcc00662 Fix apprise server url migration 2023-06-25 08:38:39 +03:00
Bogdan
c4af3e746f Add more trace logs related info to bug_report.yml [skip ci]
Co-authored-by: Bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2023-06-24 08:38:50 +03:00
Bogdan
660a162b7e Fixed: (Cardigann) Throw exception only when all download selectors fail 2023-06-23 11:18:14 +03:00
Bogdan
20a3cad7fb Add indexer id in logs for invalid dates in Cardigann definitions 2023-06-23 10:41:25 +03:00
Bogdan
77fe3f78fe Fixed: (Cardigann) Skip to next download selector when max redirects reached
Fixes #578
2023-06-22 17:01:25 +03:00
Bogdan
d777cb8e29 Fixed: (API) Prevent NullRef when searching empty query with a non-default type 2023-06-22 10:36:53 +03:00
Bogdan
15e7cc7ea8 New: (UI) Show indexer categories in info modal 2023-06-20 13:23:06 +03:00
Shivam Dua
04cf061275 Fixed: (UI) Add New Indexer button on search page when no indexers are present
Add missing listeners and components to make add indexer button work on
search page when no indexers are present
2023-06-20 07:33:34 +03:00
Bogdan
d4cdeac69a Fixed: (Cardigann) Definitions with category mapping Other to use 8000 (Other) 2023-06-20 07:21:35 +03:00
Bogdan
e60fe05ee0 Revert "Fix typo botton to bottom"
This reverts commit e2e65627ee.
2023-06-20 05:20:26 +03:00
Bogdan
9a4c23797a Display error when search failed due to all indexers being disabled 2023-06-20 03:05:55 +03:00
Bogdan
acfdb5bae3 New: (UI) Show disabled indexers as disabled options in search page 2023-06-20 03:05:55 +03:00
Bogdan
e2e65627ee Fix typo botton to bottom 2023-06-19 14:31:37 +03:00
Bogdan
4b8906ea62 Cleanup redundant DownloadProtocol in indexers 2023-06-19 04:26:45 +03:00
Bogdan
f0c5d8ceea Minor refactoring in Cardigann definition 2023-06-19 04:08:01 +03:00
Bogdan
427802a50e Update status translations for Indexer index 2023-06-18 15:46:43 +03:00
Bogdan
0c9eae244a Add skip ci to API docs update commit 2023-06-18 15:45:04 +03:00
Bogdan
75ff2f41d3 Update description for freeleech only in BakaBT 2023-06-18 09:37:33 +03:00
Bakerboy448
d1ba208243 Fixed: (HttpIndexerBase) Better HTTP error handling 2023-06-18 08:15:23 +03:00
Bogdan
4e03ebadc4 New: (UI) Add filter by categories in add indexer modal
Fixes #872
Closes #1731
2023-06-18 08:14:39 +03:00
Bogdan
0155ff60fd Map Cardigann capabilities from meta definition 2023-06-18 08:14:35 +03:00
Bogdan
f0915638f3 New: (Apps) Sync Anime Standard Search with Sonarr
Fixes #998
Closes #1732
2023-06-18 07:05:08 +03:00
Bogdan
56eb58aed1 Bump version to 1.6.2 2023-06-18 07:01:38 +03:00
92 changed files with 425 additions and 169 deletions

View File

@@ -74,7 +74,7 @@ body:
- type: checkboxes
attributes:
label: Trace Logs have been provided as applicable. Reports may be closed if the required logs are not provided.
description: Trace logs are generally required for all bug reports
description: Trace logs are generally required for all bug reports and contain `trace`. Info logs are invalid for bug reports and do not contain `debug` nor `trace`
options:
- label: I have followed the steps in the wiki link above and provided the required trace logs that are relevant and show this issue.
- label: I have read and followed the steps in the wiki link above and provided the required trace logs - the logs contain `trace` - that are relevant and show this issue.
required: true

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '1.6.1'
majorVersion: '1.6.3'
minorVersion: $[counter('minorVersion', 1)]
prowlarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'
@@ -1003,7 +1003,7 @@ stages:
git add .
if git status | grep -q modified
then
git commit -am 'Automated API Docs update'
git commit -am 'Automated API Docs update [skip ci]'
git push -f --set-upstream origin api-docs
curl -X POST -H "Authorization: token ${GITHUBTOKEN}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/prowlarr/prowlarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}'
else

View File

@@ -12,7 +12,7 @@ function createMapStateToProps() {
(state) => state.indexers,
(value, indexers) => {
const values = [];
const groupedIndexers = _(indexers.items).groupBy((x) => x.protocol).map((val, key) => ({ protocol: key, indexers: val })).value();
const groupedIndexers = _.map(_.groupBy(indexers.items, 'protocol'), (val, key) => ({ protocol: key, indexers: val }));
groupedIndexers.forEach((element) => {
values.push({
@@ -21,10 +21,11 @@ function createMapStateToProps() {
});
if (element.indexers && element.indexers.length > 0) {
element.indexers.forEach((subCat) => {
element.indexers.forEach((indexer) => {
values.push({
key: subCat.id,
value: subCat.name,
key: indexer.id,
value: indexer.name,
isDisabled: !indexer.enable,
parentKey: element.protocol === 'usenet' ? -1 : -2
});
});

View File

@@ -40,6 +40,7 @@
flex: 1;
flex-direction: column;
margin-right: 12px;
max-width: 50%;
}
.filterContainer:last-child {

View File

@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import EnhancedSelectInput from 'Components/Form/EnhancedSelectInput';
import NewznabCategorySelectInputConnector from 'Components/Form/NewznabCategorySelectInputConnector';
import TextInput from 'Components/Form/TextInput';
import Button from 'Components/Link/Button';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
@@ -89,7 +90,8 @@ class AddIndexerModalContent extends Component {
filter: '',
filterProtocols: [],
filterLanguages: [],
filterPrivacyLevels: []
filterPrivacyLevels: [],
filterCategories: []
};
}
@@ -121,7 +123,13 @@ class AddIndexerModalContent extends Component {
.map((language) => ({ key: language, value: language }));
const filteredIndexers = indexers.filter((indexer) => {
const { filter, filterProtocols, filterLanguages, filterPrivacyLevels } = this.state;
const {
filter,
filterProtocols,
filterLanguages,
filterPrivacyLevels,
filterCategories
} = this.state;
if (!indexer.name.toLowerCase().includes(filter.toLocaleLowerCase()) && !indexer.description.toLowerCase().includes(filter.toLocaleLowerCase())) {
return false;
@@ -139,6 +147,18 @@ class AddIndexerModalContent extends Component {
return false;
}
if (filterCategories.length) {
const { categories = [] } = indexer.capabilities || {};
const flat = ({ id, subCategories = [] }) => [id, ...subCategories.flatMap(flat)];
const flatCategories = categories
.filter((item) => item.id < 100000)
.flatMap(flat);
if (!filterCategories.every((item) => flatCategories.includes(item))) {
return false;
}
}
return true;
});
@@ -165,7 +185,7 @@ class AddIndexerModalContent extends Component {
<div className={styles.filterRow}>
<div className={styles.filterContainer}>
<label className={styles.filterLabel}>Protocol</label>
<label className={styles.filterLabel}>{translate('Protocol')}</label>
<EnhancedSelectInput
name="indexerProtocols"
value={this.state.filterProtocols}
@@ -175,7 +195,7 @@ class AddIndexerModalContent extends Component {
</div>
<div className={styles.filterContainer}>
<label className={styles.filterLabel}>Language</label>
<label className={styles.filterLabel}>{translate('Language')}</label>
<EnhancedSelectInput
name="indexerLanguages"
value={this.state.filterLanguages}
@@ -185,7 +205,7 @@ class AddIndexerModalContent extends Component {
</div>
<div className={styles.filterContainer}>
<label className={styles.filterLabel}>Privacy</label>
<label className={styles.filterLabel}>{translate('Privacy')}</label>
<EnhancedSelectInput
name="indexerPrivacyLevels"
value={this.state.filterPrivacyLevels}
@@ -193,6 +213,15 @@ class AddIndexerModalContent extends Component {
onChange={({ value }) => this.setState({ filterPrivacyLevels: value })}
/>
</div>
<div className={styles.filterContainer}>
<label className={styles.filterLabel}>{translate('Categories')}</label>
<NewznabCategorySelectInputConnector
name="indexerCategories"
value={this.state.filterCategories}
onChange={({ value }) => this.setState({ filterCategories: value })}
/>
</div>
</div>
<Alert
@@ -212,7 +241,7 @@ class AddIndexerModalContent extends Component {
isFetching ? <LoadingIndicator /> : null
}
{
error ? <div>{errorMessage}</div> : null
error ? <Alert kind={kinds.DANGER}>{errorMessage}</Alert> : null
}
{
isPopulated && !!indexers.length ?
@@ -237,6 +266,15 @@ class AddIndexerModalContent extends Component {
</Table> :
null
}
{
isPopulated && !!indexers.length && !filteredIndexers.length ?
<Alert
kind={kinds.WARNING}
>
{translate('NoIndexersFound')}
</Alert> :
null
}
</Scroller>
</ModalBody>

View File

@@ -43,7 +43,7 @@ function IndexerStatusCell(props: IndexerStatusCellProps) {
className={styles.statusIcon}
kind={enabled ? enableKind : kinds.DEFAULT}
name={enabled ? enableIcon : icons.BLOCKLIST}
title={enabled ? enableTitle : translate('EnabledIndexerIsDisabled')}
title={enabled ? enableTitle : translate('Disabled')}
/>
}
{status ? (

View File

@@ -13,6 +13,10 @@ import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TableRow from 'Components/Table/TableRow';
import TagListConnector from 'Components/TagListConnector';
import { kinds } from 'Helpers/Props';
import DeleteIndexerModal from 'Indexer/Delete/DeleteIndexerModal';
@@ -149,6 +153,7 @@ function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
</DescriptionList>
</div>
</FieldSet>
<FieldSet legend={translate('SearchCapabilities')}>
<div>
<DescriptionList>
@@ -237,6 +242,54 @@ function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
</DescriptionList>
</div>
</FieldSet>
{capabilities.categories !== null &&
capabilities.categories.length > 0 ? (
<FieldSet legend={translate('IndexerCategories')}>
<Table
columns={[
{
name: 'id',
label: translate('Id'),
isVisible: true,
},
{
name: 'name',
label: translate('Name'),
isVisible: true,
},
]}
>
{capabilities.categories
.sort((a, b) => a.id - b.id)
.map((category) => {
return (
<TableBody key={category.id}>
<TableRow key={category.id}>
<TableRowCell>{category.id}</TableRowCell>
<TableRowCell>{category.name}</TableRowCell>
</TableRow>
{category.subCategories !== null &&
category.subCategories.length > 0
? category.subCategories
.sort((a, b) => a.id - b.id)
.map((subCategory) => {
return (
<TableRow key={subCategory.id}>
<TableRowCell>{subCategory.id}</TableRowCell>
<TableRowCell>
{subCategory.name}
</TableRowCell>
</TableRow>
);
})
: null}
</TableBody>
);
})}
</Table>
</FieldSet>
) : null}
</ModalBody>
<ModalFooter>
<Button

View File

@@ -12,6 +12,8 @@ import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import { align, icons, kinds, sortDirections } from 'Helpers/Props';
import AddIndexerModal from 'Indexer/Add/AddIndexerModal';
import EditIndexerModalConnector from 'Indexer/Edit/EditIndexerModalConnector';
import NoIndexer from 'Indexer/NoIndexer';
import * as keyCodes from 'Utilities/Constants/keyCodes';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
@@ -54,7 +56,9 @@ class SearchIndex extends Component {
lastToggled: null,
allSelected: false,
allUnselected: false,
selectedState: {}
selectedState: {},
isAddIndexerModalOpen: false,
isEditIndexerModalOpen: false
};
}
@@ -181,6 +185,22 @@ class SearchIndex extends Component {
//
// Listeners
onAddIndexerPress = () => {
this.setState({ isAddIndexerModalOpen: true });
};
onAddIndexerModalClose = () => {
this.setState({ isAddIndexerModalOpen: false });
};
onAddIndexerSelectIndexer = () => {
this.setState({ isEditIndexerModalOpen: true });
};
onEditIndexerModalClose = () => {
this.setState({ isEditIndexerModalOpen: false });
};
onJumpBarItemPress = (jumpToCharacter) => {
this.setState({ jumpToCharacter });
};
@@ -252,7 +272,9 @@ class SearchIndex extends Component {
jumpToCharacter,
selectedState,
allSelected,
allUnselected
allUnselected,
isAddIndexerModalOpen,
isEditIndexerModalOpen
} = this.state;
const selectedIndexerIds = this.getSelectedIds();
@@ -348,6 +370,17 @@ class SearchIndex extends Component {
!error && !isFetching && hasIndexers && !items.length &&
<NoSearchResults totalItems={totalItems} />
}
<AddIndexerModal
isOpen={isAddIndexerModalOpen}
onModalClose={this.onAddIndexerModalClose}
onSelectIndexer={this.onAddIndexerSelectIndexer}
/>
<EditIndexerModalConnector
isOpen={isEditIndexerModalOpen}
onModalClose={this.onEditIndexerModalClose}
/>
</PageContentBody>
{

View File

@@ -36,7 +36,7 @@ export const defaultState = {
columns: [
{
name: 'status',
columnLabel: translate('ReleaseStatus'),
columnLabel: translate('IndexerStatus'),
isSortable: true,
isVisible: true,
isModifiable: false

View File

@@ -162,7 +162,7 @@ module.exports = {
inputHoverBackgroundColor: 'rgba(255, 255, 255, 0.20)',
inputSelectedBackgroundColor: 'rgba(255, 255, 255, 0.05)',
advancedFormLabelColor: '#ff902b',
disabledCheckInputColor: '#ddd',
disabledCheckInputColor: '#999',
disabledInputColor: '#808080',
//

View File

@@ -63,6 +63,8 @@ namespace NzbDrone.Common.Http
public bool HasHttpError => (int)StatusCode >= 400;
public bool HasHttpServerError => (int)StatusCode >= 500;
public bool HasHttpRedirect => StatusCode == HttpStatusCode.Moved ||
StatusCode == HttpStatusCode.Found ||
StatusCode == HttpStatusCode.SeeOther ||

View File

@@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class apprise_server_urlFixture : MigrationTest<apprise_server_url>
{
[Test]
public void should_rename_server_url_setting_for_apprise()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Notifications").Row(new
{
Name = "Apprise",
Implementation = "Apprise",
Settings = new
{
BaseUrl = "http://localhost:8000",
NotificationType = 0
}.ToJson(),
ConfigContract = "AppriseSettings",
OnHealthIssue = true,
IncludeHealthWarnings = true,
OnApplicationUpdate = true,
OnGrab = true,
IncludeManualGrabs = true
});
});
var items = db.Query<NotificationDefinition31>("SELECT * FROM \"Notifications\"");
items.Should().HaveCount(1);
items.First().Settings.Should().NotContainKey("baseUrl");
items.First().Settings.Should().ContainKey("serverUrl");
items.First().Settings.GetValueOrDefault("serverUrl").Should().Be("http://localhost:8000");
}
}
public class NotificationDefinition31
{
public int Id { get; set; }
public int Priority { get; set; }
public string Name { get; set; }
public string Implementation { get; set; }
public Dictionary<string, string> Settings { get; set; }
public string ConfigContract { get; set; }
public bool OnHealthIssue { get; set; }
public bool IncludeHealthWarnings { get; set; }
public bool OnApplicationUpdate { get; set; }
public bool OnGrab { get; set; }
public bool IncludeManualGrabs { get; set; }
public List<int> Tags { get; set; }
}
}

View File

@@ -183,12 +183,12 @@ namespace NzbDrone.Core.Applications.Sonarr
{
var cacheKey = $"{Settings.BaseUrl}";
var schemas = _schemaCache.Get(cacheKey, () => _sonarrV3Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7));
var syncFields = new List<string> { "baseUrl", "apiPath", "apiKey", "categories", "animeCategories", "minimumSeeders", "seedCriteria.seedRatio", "seedCriteria.seedTime", "seedCriteria.seasonPackSeedTime" };
var syncFields = new List<string> { "baseUrl", "apiPath", "apiKey", "categories", "animeCategories", "animeStandardFormatSearch", "minimumSeeders", "seedCriteria.seedRatio", "seedCriteria.seedTime", "seedCriteria.seasonPackSeedTime" };
if (id == 0)
{
// Ensuring backward compatibility with older versions on first sync
syncFields.AddRange(new List<string> { "animeStandardFormatSearch", "additionalParameters" });
syncFields.AddRange(new List<string> { "additionalParameters" });
}
var newznab = schemas.First(i => i.Implementation == "Newznab");
@@ -218,6 +218,11 @@ namespace NzbDrone.Core.Applications.Sonarr
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "animeCategories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()));
if (sonarrIndexer.Fields.Any(x => x.Name == "animeStandardFormatSearch"))
{
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "animeStandardFormatSearch").Value = Settings.SyncAnimeStandardFormatSearch;
}
if (indexer.Protocol == DownloadProtocol.Torrent)
{
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.AppMinimumSeeders ?? indexer.AppProfile.Value.MinimumSeeders;

View File

@@ -38,6 +38,10 @@ namespace NzbDrone.Core.Applications.Sonarr
var otherApiPath = other.Fields.FirstOrDefault(x => x.Name == "apiPath")?.Value == null ? null : other.Fields.FirstOrDefault(x => x.Name == "apiPath").Value;
var apiPathCompare = apiPath.Equals(otherApiPath);
var animeStandardFormatSearch = Fields.FirstOrDefault(x => x.Name == "animeStandardFormatSearch")?.Value == null ? null : (bool?)Convert.ToBoolean(Fields.FirstOrDefault(x => x.Name == "animeStandardFormatSearch").Value);
var otherAnimeStandardFormatSearch = other.Fields.FirstOrDefault(x => x.Name == "animeStandardFormatSearch")?.Value == null ? null : (bool?)Convert.ToBoolean(other.Fields.FirstOrDefault(x => x.Name == "animeStandardFormatSearch").Value);
var animeStandardFormatSearchCompare = animeStandardFormatSearch == otherAnimeStandardFormatSearch;
var minimumSeeders = Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value);
var otherMinimumSeeders = other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders")?.Value == null ? null : (int?)Convert.ToInt32(other.Fields.FirstOrDefault(x => x.Name == "minimumSeeders").Value);
var minimumSeedersCompare = minimumSeeders == otherMinimumSeeders;
@@ -61,7 +65,7 @@ namespace NzbDrone.Core.Applications.Sonarr
other.Implementation == Implementation &&
other.Priority == Priority &&
other.Id == Id &&
apiKey && apiPathCompare && baseUrl && cats && animeCats && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && seasonSeedTimeCompare;
apiKey && apiPathCompare && baseUrl && cats && animeCats && animeStandardFormatSearchCompare && minimumSeedersCompare && seedRatioCompare && seedTimeCompare && seasonSeedTimeCompare;
}
}
}

View File

@@ -43,6 +43,9 @@ namespace NzbDrone.Core.Applications.Sonarr
[FieldDefinition(4, Label = "Anime Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]
public IEnumerable<int> AnimeSyncCategories { get; set; }
[FieldDefinition(5, Label = "Sync Anime Standard Format Search", Type = FieldType.Checkbox, Advanced = true, HelpText = "Sync also searching for anime using the standard numbering")]
public bool SyncAnimeStandardFormatSearch { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Data;
using Dapper;
using FluentMigrator;
@@ -17,33 +18,43 @@ namespace NzbDrone.Core.Datastore.Migration
private void MigrateToServerUrl(IDbConnection conn, IDbTransaction tran)
{
using var selectCommand = conn.CreateCommand();
selectCommand.Transaction = tran;
selectCommand.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Notifications\" WHERE \"Implementation\" = 'Apprise'";
var updatedNotifications = new List<object>();
using var reader = selectCommand.ExecuteReader();
while (reader.Read())
using (var selectCommand = conn.CreateCommand())
{
var id = reader.GetInt32(0);
var settings = reader.GetString(1);
selectCommand.Transaction = tran;
selectCommand.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Notifications\" WHERE \"Implementation\" = 'Apprise'";
if (!string.IsNullOrWhiteSpace(settings))
using var reader = selectCommand.ExecuteReader();
while (reader.Read())
{
var jsonObject = Json.Deserialize<JObject>(settings);
var id = reader.GetInt32(0);
var settings = reader.GetString(1);
if (jsonObject.ContainsKey("baseUrl"))
if (!string.IsNullOrWhiteSpace(settings))
{
jsonObject.Add("serverUrl", jsonObject.Value<string>("baseUrl"));
jsonObject.Remove("baseUrl");
var jsonObject = Json.Deserialize<JObject>(settings);
if (jsonObject.ContainsKey("baseUrl"))
{
jsonObject.Add("serverUrl", jsonObject.Value<string>("baseUrl"));
jsonObject.Remove("baseUrl");
}
settings = jsonObject.ToJson();
}
settings = jsonObject.ToJson();
updatedNotifications.Add(new
{
Id = id,
Settings = settings
});
}
var parameters = new { Settings = settings, Id = id };
conn.Execute("UPDATE Notifications SET Settings = @Settings WHERE Id = @Id", parameters, transaction: tran);
}
var updateNotificationsSql = "UPDATE \"Notifications\" SET \"Settings\" = @Settings WHERE \"Id\" = @Id";
conn.Execute(updateNotificationsSql, updatedNotifications, transaction: tran);
}
}
}

View File

@@ -1,13 +1,14 @@
using System.Text.RegularExpressions;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Core.IndexerSearch
{
public class NewznabRequest
{
private static readonly Regex TvRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:rid\:)(?<rid>[^{]+)|(?:tvdbid\:)(?<tvdbid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:season\:)(?<season>[^{]+)|(?:episode\:)(?<episode>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex MovieRegex = new Regex(@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+)|(?:traktid\:)(?<traktid>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex MusicRegex = new Regex(@"\{((?:artist\:)(?<artist>[^{]+)|(?:album\:)(?<album>[^{]+)|(?:track\:)(?<track>[^{]+)|(?:label\:)(?<label>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex BookRegex = new Regex(@"\{((?:author\:)(?<author>[^{]+)|(?:publisher\:)(?<publisher>[^{]+)|(?:title\:)(?<title>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex TvRegex = new (@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:rid\:)(?<rid>[^{]+)|(?:tvdbid\:)(?<tvdbid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:season\:)(?<season>[^{]+)|(?:episode\:)(?<episode>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex MovieRegex = new (@"\{((?:imdbid\:)(?<imdbid>[^{]+)|(?:doubanid\:)(?<doubanid>[^{]+)|(?:tmdbid\:)(?<tmdbid>[^{]+)|(?:traktid\:)(?<traktid>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex MusicRegex = new (@"\{((?:artist\:)(?<artist>[^{]+)|(?:album\:)(?<album>[^{]+)|(?:track\:)(?<track>[^{]+)|(?:label\:)(?<label>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex BookRegex = new (@"\{((?:author\:)(?<author>[^{]+)|(?:publisher\:)(?<publisher>[^{]+)|(?:title\:)(?<title>[^{]+)|(?:year\:)(?<year>[^{]+)|(?:genre\:)(?<genre>[^{]+))\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public string t { get; set; }
public string q { get; set; }
@@ -40,6 +41,11 @@ namespace NzbDrone.Core.IndexerSearch
public void QueryToParams()
{
if (q.IsNullOrWhiteSpace())
{
return;
}
if (t == "tvsearch")
{
var matches = TvRegex.Matches(q);

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using NLog;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Events;
using NzbDrone.Core.IndexerSearch.Definitions;
@@ -157,15 +158,22 @@ namespace NzbDrone.Core.IndexerSearch
{
var indexers = _indexerFactory.Enabled();
if (criteriaBase.IndexerIds != null && criteriaBase.IndexerIds.Count > 0)
if (criteriaBase.IndexerIds is { Count: > 0 })
{
indexers = indexers.Where(i => criteriaBase.IndexerIds.Contains(i.Definition.Id) ||
(criteriaBase.IndexerIds.Contains(-1) && i.Protocol == DownloadProtocol.Usenet) ||
(criteriaBase.IndexerIds.Contains(-2) && i.Protocol == DownloadProtocol.Torrent))
.ToList();
if (indexers.Count == 0)
{
_logger.Debug("Search failed due to all selected indexers being unavailable: {0}", string.Join(", ", criteriaBase.IndexerIds));
throw new SearchFailedException("Search failed due to all selected indexers being unavailable");
}
}
if (criteriaBase.Categories != null && criteriaBase.Categories.Length > 0)
if (criteriaBase.Categories is { Length: > 0 })
{
//Only query supported indexers
indexers = indexers.Where(i => ((IndexerDefinition)i.Definition).Capabilities.Categories.SupportedCategories(criteriaBase.Categories).Any()).ToList();
@@ -173,6 +181,7 @@ namespace NzbDrone.Core.IndexerSearch
if (indexers.Count == 0)
{
_logger.Debug("All provided categories are unsupported by selected indexers: {0}", string.Join(", ", criteriaBase.Categories));
return Array.Empty<ReleaseInfo>();
}
}

View File

@@ -27,7 +27,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "Anidex is a Public torrent tracker and indexer, primarily for English fansub groups of anime";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -28,7 +28,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "Anidub is RUSSIAN anime voiceover group and eponymous anime tracker.";
public override string Language => "ru-RU";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -35,7 +35,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "AnimeBytes (AB) is the largest private torrent tracker that specialises in anime and anime-related content.";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override TimeSpan RateLimit => TimeSpan.FromSeconds(4);

View File

@@ -24,7 +24,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Name => "AnimeTorrents";
public override string[] IndexerUrls => new[] { "https://animetorrents.me/" };
public override string Description => "Definitive source for anime and manga";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsPagination => true;
public override TimeSpan RateLimit => TimeSpan.FromSeconds(4);

View File

@@ -24,7 +24,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "Animedia is RUSSIAN anime voiceover group and eponymous anime tracker.";
public override string Language => "ru-RU";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -28,7 +28,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "A movies tracker";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -59,7 +59,6 @@ public class AudioBookBay : TorrentIndexerBase<NoAuthTorrentBaseSettings>
};
public override string Description => "AudioBook Bay (ABB) is a public Torrent Tracker for AUDIOBOOKS";
public override string Language => "en-US";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override int PageSize => 15;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -12,7 +12,6 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
{
public abstract class AvistazBase : TorrentIndexerBase<AvistazSettings>
{
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override bool SupportsRss => true;
public override bool SupportsSearch => true;
public override bool SupportsPagination => true;

View File

@@ -28,7 +28,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "BB is a Private Torrent Tracker for 0DAY / GENERAL";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -28,7 +28,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string[] IndexerUrls => new[] { "https://bakabt.me/" };
public override string Description => "Anime Community";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
@@ -413,7 +412,7 @@ namespace NzbDrone.Core.Indexers.Definitions
FreeleechOnly = false;
}
[FieldDefinition(4, Label = "Freeleech Only", Type = FieldType.Checkbox, HelpText = "Search freeleech torrents only")]
[FieldDefinition(4, Label = "Freeleech Only", Type = FieldType.Checkbox, HelpText = "Show freeleech torrents only")]
public bool FreeleechOnly { get; set; }
[FieldDefinition(5, Label = "Add Romaji Title", Type = FieldType.Checkbox, HelpText = "Add releases for Romaji Title")]

View File

@@ -28,7 +28,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string[] IndexerUrls => new string[] { "https://beyond-hd.me/" };
public override string Description => "BeyondHD (BHD) is a Private Torrent Tracker for HD MOVIES / TV";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "The binary Usenet search engine";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override bool SupportsRss => false;
public override bool SupportsPagination => true;

View File

@@ -25,7 +25,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "BIT-HDTV - Home of High Definition";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1");
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -11,7 +11,6 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
public override string Name => "BroadcasTheNet";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override bool SupportsRss => true;
public override bool SupportsSearch => true;
public override bool SupportsPagination => true;

View File

@@ -24,8 +24,6 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
public override string Name => "Cardigann";
public override string[] IndexerUrls => new string[] { "" };
public override string Description => "";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
// Page size is different per indexer, setting to 1 ensures we don't break out of paging logic
@@ -166,7 +164,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
SupportsSearch = SupportsSearch,
SupportsRedirect = SupportsRedirect,
SupportsPagination = SupportsPagination,
Capabilities = new IndexerCapabilities(),
Capabilities = ParseCardigannCapabilities(definition),
ExtraFields = settings
};
}
@@ -238,5 +236,55 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
return null;
}
private IndexerCapabilities ParseCardigannCapabilities(CardigannMetaDefinition definition)
{
var capabilities = new IndexerCapabilities();
if (definition.Caps == null)
{
return capabilities;
}
capabilities.ParseCardigannSearchModes(definition.Caps.Modes);
capabilities.SupportsRawSearch = definition.Caps.Allowrawsearch;
if (definition.Caps.Categories != null && definition.Caps.Categories.Any())
{
foreach (var category in definition.Caps.Categories)
{
var cat = NewznabStandardCategory.GetCatByName(category.Value);
if (cat == null)
{
continue;
}
capabilities.Categories.AddCategoryMapping(category.Key, cat);
}
}
if (definition.Caps.Categorymappings != null && definition.Caps.Categorymappings.Any())
{
foreach (var categoryMapping in definition.Caps.Categorymappings)
{
IndexerCategory torznabCat = null;
if (categoryMapping.Cat != null)
{
torznabCat = NewznabStandardCategory.GetCatByName(categoryMapping.Cat);
if (torznabCat == null)
{
continue;
}
}
capabilities.Categories.AddCategoryMapping(categoryMapping.Id, torznabCat, categoryMapping.Desc);
}
}
return capabilities;
}
}
}

View File

@@ -26,8 +26,8 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
protected virtual string SiteLink { get; private set; }
protected readonly IndexerCapabilitiesCategories _categories = new IndexerCapabilitiesCategories();
protected readonly List<string> _defaultCategories = new List<string>();
protected readonly IndexerCapabilitiesCategories _categories = new ();
protected readonly List<string> _defaultCategories = new ();
protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "tmdbid", "rageid", "tvdbid", "tvmazeid", "traktid", "doubanid", "poster", "banner", "description", "genre" };
@@ -65,14 +65,16 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
SiteLink = definition.Links.First();
if (_definition.Caps.Categories != null)
if (_definition.Caps.Categories != null && _definition.Caps.Categories.Any())
{
foreach (var category in _definition.Caps.Categories)
{
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));
_logger.Error("CardigannIndexer ({0}): invalid Torznab category for id {1}: {2}", _definition.Id, category.Key, category.Value);
continue;
}
@@ -80,27 +82,29 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
}
}
if (_definition.Caps.Categorymappings != null)
if (_definition.Caps.Categorymappings != null && _definition.Caps.Categorymappings.Any())
{
foreach (var categorymapping in _definition.Caps.Categorymappings)
foreach (var categoryMapping in _definition.Caps.Categorymappings)
{
IndexerCategory torznabCat = null;
if (categorymapping.cat != null)
if (categoryMapping.Cat != null)
{
torznabCat = NewznabStandardCategory.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));
_logger.Error("CardigannIndexer ({0}): invalid Torznab category for id {1}: {2}", _definition.Id, categoryMapping.Id, categoryMapping.Cat);
continue;
}
}
_categories.AddCategoryMapping(categorymapping.id, torznabCat, categorymapping.desc);
_categories.AddCategoryMapping(categoryMapping.Id, torznabCat, categoryMapping.Desc);
if (categorymapping.Default)
if (categoryMapping.Default)
{
_defaultCategories.Add(categorymapping.id);
_defaultCategories.Add(categoryMapping.Id);
}
}
}
@@ -622,7 +626,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
}
catch (InvalidDateException ex)
{
_logger.Debug(ex.Message);
_logger.Debug("{0}: {1}", _definition.Id, ex.Message);
}
break;

View File

@@ -66,9 +66,9 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
public class CategorymappingBlock
{
public string id { get; set; }
public string cat { get; set; }
public string desc { get; set; }
public string Id { get; set; }
public string Cat { get; set; }
public string Desc { get; set; }
public bool Default { get; set; }
}

View File

@@ -19,7 +19,8 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
public List<string> Links { get; set; }
public List<string> Legacylinks { get; set; }
public List<SettingsField> Settings { get; set; }
public string Sha { get; set; }
public LoginBlock Login { get; set; }
public CapabilitiesBlock Caps { get; set; }
public string Sha { get; set; }
}
}

View File

@@ -890,11 +890,11 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
download.Infohash.Title.Selector);
}
}
else if (download.Selectors != null)
else if (download.Selectors != null && download.Selectors.Any())
{
foreach (var selector in download.Selectors)
{
var queryselector = ApplyGoTemplateText(selector.Selector, variables);
var querySelector = ApplyGoTemplateText(selector.Selector, variables);
try
{
@@ -904,16 +904,21 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
}
var href = MatchSelector(response, selector, variables, debugMatch: true);
if (href == null)
{
continue;
}
var torrentLink = ResolvePath(href, link);
if (torrentLink.Scheme != "magnet" && _definition.TestLinkTorrent)
{
// Test link
var testLinkRequest = new HttpRequestBuilder(torrentLink.ToString())
{
AllowAutoRedirect = true
}
.SetCookies(Cookies ?? new Dictionary<string, string>())
.SetHeaders(headers ?? new Dictionary<string, string>())
.SetEncoding(_encoding)
@@ -923,9 +928,10 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
response = await HttpClient.ExecuteProxiedAsync(testLinkRequest, Definition);
var content = response.Content;
if (content.Length >= 1 && content[0] != 'd')
{
_logger.Debug("CardigannIndexer ({0}): Download selector {1}'s torrent file is invalid, retrying with next available selector", _definition.Id, queryselector);
_logger.Debug("{0}: Download selector {1}'s torrent file is invalid, retrying with next available selector", _definition.Id, querySelector);
continue;
}
@@ -944,13 +950,13 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
return selectorDownloadRequest;
}
catch (Exception e)
catch (Exception ex)
{
_logger.Error("{0} CardigannIndexer ({1}): An exception occurred while trying selector {2}, retrying with next available selector", e, _definition.Id, queryselector);
throw new CardigannException(string.Format("An exception occurred while trying selector {0}", queryselector));
_logger.Error(ex, "{0}: An exception occurred while trying selector {1}, retrying with next available selector.", _definition.Id, querySelector);
}
}
throw new CardigannException($"Download selectors didn't match for {link}");
}
}

View File

@@ -15,7 +15,6 @@ public class FileList : TorrentIndexerBase<FileListSettings>
};
public override string[] LegacyUrls => new[] { "https://filelist.io" };
public override string Description => "FileList (FL) is a ROMANIAN Private Torrent Tracker for 0DAY / GENERAL";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsRss => true;
public override bool SupportsSearch => true;

View File

@@ -26,7 +26,6 @@ public class FunFile : TorrentIndexerBase<UserPassTorrentBaseSettings>
public override string Description => "FunFile is a general tracker";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1");
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -13,7 +13,6 @@ namespace NzbDrone.Core.Indexers.Definitions.Gazelle;
public abstract class GazelleBase<TSettings> : TorrentIndexerBase<TSettings>
where TSettings : GazelleSettings, new()
{
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override string[] IndexerUrls => new[] { "" };
protected virtual string LoginUrl => Settings.BaseUrl + "login.php";
public override bool SupportsRss => true;

View File

@@ -28,7 +28,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "GazelleGames (GGn) is a Private Torrent Tracker for GAMES";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -11,7 +11,6 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
public override string[] IndexerUrls => new[] { "https://hdbits.org/" };
public override string[] LegacyUrls => new[] { "https://hdbits.org" };
public override string Description => "Best HD Tracker";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override bool SupportsRedirect => true;

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "HD-Space (HDS) is a Private Torrent Tracker for HD MOVIES / TV";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -32,7 +32,6 @@ namespace NzbDrone.Core.Indexers.Definitions
"https://hd-torrents.me/",
};
public override string Description => "HD-Torrents is a private torrent website with HD torrents and strict rules on their content.";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -14,8 +14,6 @@ namespace NzbDrone.Core.Indexers.Headphones
public class Headphones : UsenetIndexerBase<HeadphonesSettings>
{
public override string Name => "Headphones VIP";
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override string[] IndexerUrls => new string[] { "https://indexer.codeshy.com" };
public override string Description => "A Private Usenet indexer for music";

View File

@@ -38,7 +38,6 @@ namespace NzbDrone.Core.Indexers.Definitions
"https://ipt.world/"
};
public override string Description => "IPTorrents (IPT) is a Private Torrent Tracker for 0DAY / GENERAL.";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsPagination => true;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -25,7 +25,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Name => "ImmortalSeed";
public override string[] IndexerUrls => new[] { "https://immortalseed.me/" };
public override string Description => "ImmortalSeed (iS) is a Private Torrent Tracker for MOVIES / TV / GENERAL";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override TimeSpan RateLimit => TimeSpan.FromSeconds(5);

View File

@@ -31,7 +31,6 @@ public class Libble : TorrentIndexerBase<LibbleSettings>
private string LoginUrl => Settings.BaseUrl + "login.php";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsPagination => true;
public override int PageSize => 50;

View File

@@ -26,7 +26,6 @@ public class MoreThanTV : TorrentIndexerBase<CookieTorrentBaseSettings>
public override string Name => "MoreThanTV";
public override string[] IndexerUrls => new[] { "https://www.morethantv.me/" };
public override string Description => "Private torrent tracker for TV / MOVIES";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override bool FollowRedirect => true;

View File

@@ -30,7 +30,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Name => "MyAnonamouse";
public override string[] IndexerUrls => new[] { "https://www.myanonamouse.net/" };
public override string Description => "MyAnonaMouse (MAM) is a large ebook and audiobook tracker.";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsPagination => true;
public override int PageSize => 100;

View File

@@ -27,7 +27,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "Nebulance (NBL) is a ratioless Private Torrent Tracker for TV";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsRedirect => true;
public override bool SupportsPagination => true;

View File

@@ -23,12 +23,8 @@ namespace NzbDrone.Core.Indexers.Newznab
public override bool FollowRedirect => true;
public override bool SupportsRedirect => true;
public override bool SupportsPagination => true;
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities { get => GetCapabilitiesFromSettings(); protected set => base.Capabilities = value; }
public override int PageSize => _capabilitiesProvider.GetCapabilities(Settings, Definition).LimitsDefault.Value;
public override IIndexerRequestGenerator GetRequestGenerator()

View File

@@ -29,7 +29,6 @@ public class NorBits : TorrentIndexerBase<NorBitsSettings>
public override string Description => "NorBits is a Norwegian Private site for MOVIES / TV / GENERAL";
public override string Language => "nb-NO";
public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1");
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -25,7 +25,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Name => "NZBIndex";
public override string[] IndexerUrls => new[] { "https://nzbindex.com/" };
public override string Description => "A Usenet Indexer";
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;
public override bool SupportsPagination => true;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Name => "Orpheus";
public override string[] IndexerUrls => new[] { "https://orpheus.network/" };
public override string Description => "Orpheus (APOLLO) is a Private Torrent Tracker for MUSIC";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override bool SupportsRedirect => true;

View File

@@ -10,7 +10,6 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
public override string Name => "PassThePopcorn";
public override string[] IndexerUrls => new[] { "https://passthepopcorn.me" };
public override string Description => "PassThePopcorn (PTP) is a Private site for MOVIES / TV";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsRss => true;
public override bool SupportsSearch => true;

View File

@@ -26,7 +26,6 @@ public class PirateTheNet : TorrentIndexerBase<UserPassTorrentBaseSettings>
public override string[] IndexerUrls => new[] { "https://piratethenet.org/" };
public override string[] LegacyUrls => new[] { "http://piratethenet.org/" };
public override string Description => "PirateTheNet (PTN) is a ratioless movie tracker.";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
private string LoginUrl => Settings.BaseUrl + "takelogin.php";

View File

@@ -28,7 +28,6 @@ public class PixelHD : TorrentIndexerBase<PixelHDSettings>
public override string Description => "PixelHD (PxHD) is a ratioless Private Torrent Tracker for HD .MP4 MOVIES / TV";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -28,7 +28,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "PornoLab is a Semi-Private Russian site for Adult content";
public override string Language => "ru-RU";
public override Encoding Encoding => Encoding.GetEncoding("windows-1251");
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -29,7 +29,6 @@ public class PreToMe : TorrentIndexerBase<PreToMeSettings>
public override string Description => "PreToMe is a ratioless 0Day/General tracker.";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1");
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -27,7 +27,6 @@ namespace NzbDrone.Core.Indexers.Definitions.Rarbg
public override string[] IndexerUrls => new[] { "https://torrentapi.org/" };
public override string[] LegacyUrls => new[] { "https://torrentapi.org" };
public override string Description => "RARBG is a Public torrent site for MOVIES / TV / GENERAL";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override TimeSpan RateLimit => TimeSpan.FromSeconds(7);

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Name => "Redacted";
public override string[] IndexerUrls => new[] { "https://redacted.ch/" };
public override string Description => "REDActed (Aka.PassTheHeadPhones) is one of the most well-known music trackers.";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override bool SupportsRedirect => true;

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string[] IndexerUrls => new[] { "https://revolutiontt.me/" };
public override string Description => "The Revolution has begun";
private string LoginUrl => Settings.BaseUrl + "takelogin.php";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -33,7 +33,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "RuTracker is a Semi-Private Russian torrent site with a thriving file-sharing community";
public override string Language => "ru-RU";
public override Encoding Encoding => Encoding.GetEncoding("windows-1251");
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -28,7 +28,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "SceneHD is Private site for HD TV / MOVIES";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "Always on time";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -20,7 +20,6 @@ public class SecretCinema : GazelleBase<GazelleSettings>
public override string Name => "Secret Cinema";
public override string[] IndexerUrls => new[] { "https://secret-cinema.pw/" };
public override string Description => "A tracker for rare movies.";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -30,7 +30,6 @@ public class Shazbat : TorrentIndexerBase<ShazbatSettings>
public override string Description => "Shazbat is a PRIVATE Torrent Tracker with highly curated TV content";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override TimeSpan RateLimit => TimeSpan.FromSeconds(5.1);

View File

@@ -24,7 +24,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "Shizaproject is russian anime voiceover group and eponymous anime tracker.";
public override string Language => "ru-RU";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -29,7 +29,6 @@ namespace NzbDrone.Core.Indexers.Definitions
{
private string LoginUrl => Settings.BaseUrl + "api/login";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override bool SupportsPagination => true;
public override int PageSize => 100;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -33,7 +33,6 @@ public class SpeedCD : TorrentIndexerBase<SpeedCDSettings>
public override string Description => "Your home now!";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsPagination => true;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -28,7 +28,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Language => "en-US";
public override string Description => "SubsPlease - A better HorribleSubs/Erai replacement";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -30,7 +30,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "TV-Vault is a very unique tracker dedicated for old TV shows, TV movies and documentaries.";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override TimeSpan RateLimit => TimeSpan.FromSeconds(5);

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "Toloka.to is a Semi-Private Ukrainian torrent site with a thriving file-sharing community";
public override string Language => "uk-UA";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -27,7 +27,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "A decade of TorrentBytes";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1");
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -32,7 +32,6 @@ namespace NzbDrone.Core.Indexers.Definitions
"https://td.workisboring.net/"
};
public override string Description => "TorrentDay (TD) is a Private site for TV / MOVIES / GENERAL";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -11,7 +11,6 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
public override string[] IndexerUrls => new[] { "http://127.0.0.1" };
public override string Description => "A JSON based torrent provider previously developed for CouchPotato";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override TimeSpan RateLimit => TimeSpan.FromSeconds(2);

View File

@@ -13,7 +13,6 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentRss
public override string Name => "Torrent RSS Feed";
public override string[] IndexerUrls => new[] { "" };
public override string Description => "Generic RSS Feed containing torrents";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override bool SupportsRss => true;
public override bool SupportsSearch => false;

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "A German general tracker";
public override string Language => "de-DE";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -22,7 +22,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Language => "en-US";
public override string Description => "Torrents.csv is a self-hostable open source torrent search engine and database";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override bool SupportsRss => false;

View File

@@ -24,7 +24,6 @@ namespace NzbDrone.Core.Indexers.Torznab
public override bool SupportsRedirect => true;
public override bool SupportsPagination => true;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override int PageSize => _capabilitiesProvider.GetCapabilities(Settings, Definition).LimitsDefault.Value;

View File

@@ -6,7 +6,6 @@ namespace NzbDrone.Core.Indexers.Definitions.UNIT3D
{
public abstract class Unit3dBase : TorrentIndexerBase<Unit3dSettings>
{
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override string[] IndexerUrls => new string[] { "" };
public override bool SupportsRss => true;
public override bool SupportsSearch => true;

View File

@@ -25,7 +25,6 @@ public class Uniotaku : TorrentIndexerBase<UniotakuSettings>
public override string[] IndexerUrls => new[] { "https://tracker.uniotaku.com/" };
public override string Description => "UniOtaku is a BRAZILIAN Semi-Private Torrent Tracker for ANIME";
public override string Language => "pt-BR";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -24,7 +24,6 @@ public class XSpeeds : TorrentIndexerBase<UserPassTorrentBaseSettings>
public override string Name => "XSpeeds";
public override string[] IndexerUrls => new[] { "https://www.xspeeds.eu/" };
public override string Description => "XSpeeds (XS) is a Private Torrent Tracker for MOVIES / TV / GENERAL";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
private string LandingUrl => Settings.BaseUrl + "login.php";

View File

@@ -15,7 +15,6 @@ namespace NzbDrone.Core.Indexers.Definitions.Xthor
public override string Language => "fr-FR";
public override string Description => "Xthor is a general Private torrent site";
public override Encoding Encoding => Encoding.GetEncoding("windows-1252");
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.5);

View File

@@ -34,7 +34,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Description => "ZonaQ is a SPANISH Private Torrent Tracker for MOVIES / TV";
public override string Language => "es-ES";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();

View File

@@ -264,6 +264,7 @@ namespace NzbDrone.Core.Indexers
var releases = new List<ReleaseInfo>();
var result = new IndexerPageableQueryResult();
var url = string.Empty;
var minimumBackoff = TimeSpan.FromHours(1);
try
{
@@ -317,8 +318,7 @@ namespace NzbDrone.Core.Indexers
}
catch (WebException webException)
{
if (webException.Status == WebExceptionStatus.NameResolutionFailure ||
webException.Status == WebExceptionStatus.ConnectFailure)
if (webException.Status is WebExceptionStatus.NameResolutionFailure or WebExceptionStatus.ConnectFailure)
{
_indexerStatusService.RecordConnectionFailure(Definition.Id);
}
@@ -341,7 +341,7 @@ namespace NzbDrone.Core.Indexers
{
result.Queries.Add(new IndexerQueryResult { Response = ex.Response });
var retryTime = ex.RetryAfter != TimeSpan.Zero ? ex.RetryAfter : TimeSpan.FromHours(1);
var retryTime = ex.RetryAfter != TimeSpan.Zero ? ex.RetryAfter : minimumBackoff;
_indexerStatusService.RecordFailure(Definition.Id, retryTime);
_logger.Warn("Request Limit reached for {0}. Disabled for {1}", this, retryTime);
@@ -350,13 +350,21 @@ namespace NzbDrone.Core.Indexers
{
result.Queries.Add(new IndexerQueryResult { Response = ex.Response });
_indexerStatusService.RecordFailure(Definition.Id);
_logger.Warn("{0} {1}", this, ex.Message);
if (ex.Response.HasHttpServerError)
{
_logger.Warn("Unable to connect to {0} at [{1}]. Indexer's server is unavailable. Try again later. {2}", this, url, ex.Message);
}
else
{
_logger.Warn("{0} {1}", this, ex.Message);
}
}
catch (RequestLimitReachedException ex)
{
result.Queries.Add(new IndexerQueryResult { Response = ex.Response.HttpResponse });
_indexerStatusService.RecordFailure(Definition.Id, TimeSpan.FromHours(1));
_logger.Warn("API Request Limit reached for {0}", this);
_indexerStatusService.RecordFailure(Definition.Id, minimumBackoff);
_logger.Warn("Request Limit reached for {0}. Disabled for {1}", this, minimumBackoff);
}
catch (IndexerAuthException ex)
{
@@ -494,7 +502,7 @@ namespace NzbDrone.Core.Indexers
var response = await _httpClient.ExecuteProxiedAsync(request.HttpRequest, Definition);
// Check reponse to see if auth is needed, if needed try again
// Check response to see if auth is needed, if needed try again
if (CheckIfLoginNeeded(response))
{
_logger.Trace("Attempting to re-auth based on indexer search response");
@@ -507,6 +515,11 @@ namespace NzbDrone.Core.Indexers
response = await _httpClient.ExecuteProxiedAsync(request.HttpRequest, Definition);
}
if (CloudFlareDetectionService.IsCloudflareProtected(response))
{
throw new CloudFlareProtectionException(response);
}
// Throw common http errors here before we try to parse
if (response.HasHttpError && (request.HttpRequest.SuppressHttpErrorStatusCodes == null || !request.HttpRequest.SuppressHttpErrorStatusCodes.Contains(response.StatusCode)))
{
@@ -519,11 +532,11 @@ namespace NzbDrone.Core.Indexers
{
throw new TooManyRequestsException(request.HttpRequest, response);
}
}
if (CloudFlareDetectionService.IsCloudflareProtected(response))
{
throw new CloudFlareProtectionException(response);
if (response.HasHttpServerError)
{
throw new HttpException(request.HttpRequest, response);
}
}
UpdateCookies(request.HttpRequest.Cookies, DateTime.Now.AddDays(30));
@@ -594,9 +607,9 @@ namespace NzbDrone.Core.Indexers
}
catch (IndexerAuthException ex)
{
_logger.Warn("Indexer returned result for RSS URL, Credentials appears to be invalid: " + ex.Message);
_logger.Warn("Indexer returned result for RSS URL, Credentials appears to be invalid. Response: " + ex.Message);
return new ValidationFailure("", ex.Message);
return new ValidationFailure("", "Indexer returned result for RSS URL, Credentials appears to be invalid. Response: " + ex.Message);
}
catch (RequestLimitReachedException ex)
{
@@ -629,6 +642,11 @@ namespace NzbDrone.Core.Indexers
_logger.Warn(ex, "Unable to connect to indexer");
if (ex.Response.HasHttpServerError)
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer, indexer's server is unavailable. Try again later. " + ex.Message);
}
return new ValidationFailure(string.Empty, "Unable to connect to indexer, check the log above the ValidationFailure for more details. " + ex.Message);
}
catch (HttpRequestException ex)
@@ -643,6 +661,21 @@ namespace NzbDrone.Core.Indexers
return new ValidationFailure(string.Empty, "Unable to connect to indexer, possibly due to a timeout. Try again or check your network settings. " + ex.Message);
}
catch (WebException webException)
{
_logger.Warn("Unable to connect to indexer.");
if (webException.Status is WebExceptionStatus.NameResolutionFailure or WebExceptionStatus.ConnectFailure)
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer connection failure. Check your connection to the indexer's server and DNS." + webException.Message);
}
if (webException.Message.Contains("502") || webException.Message.Contains("503") ||
webException.Message.Contains("504") || webException.Message.Contains("timed out"))
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer, indexer's server is unavailable. Try again later. " + webException.Message);
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to connect to indexer");

View File

@@ -58,7 +58,7 @@ namespace NzbDrone.Core.Indexers
catch
{
// Skip indexer if we fail in Cardigann mapping
_logger.Debug("Indexer {0} has no definition", definition.Name);
_logger.Debug("Indexer '{0}' has no definition", definition.Name);
}
}
@@ -127,7 +127,7 @@ namespace NzbDrone.Core.Indexers
private void MapCardigannCategories(IndexerDefinition def, CardigannDefinition defFile)
{
if (defFile.Caps.Categories != null)
if (defFile.Caps.Categories != null && defFile.Caps.Categories.Any())
{
foreach (var category in defFile.Caps.Categories)
{
@@ -142,27 +142,23 @@ namespace NzbDrone.Core.Indexers
}
}
if (defFile.Caps.Categorymappings != null)
if (defFile.Caps.Categorymappings != null && defFile.Caps.Categorymappings.Any())
{
foreach (var categorymapping in defFile.Caps.Categorymappings)
foreach (var categoryMapping in defFile.Caps.Categorymappings)
{
IndexerCategory torznabCat = null;
if (categorymapping.cat != null)
if (categoryMapping.Cat != null)
{
torznabCat = NewznabStandardCategory.GetCatByName(categorymapping.cat);
torznabCat = NewznabStandardCategory.GetCatByName(categoryMapping.Cat);
if (torznabCat == null)
{
continue;
}
}
def.Capabilities.Categories.AddCategoryMapping(categorymapping.id, torznabCat, categorymapping.desc);
//if (categorymapping.Default)
//{
// DefaultCategories.Add(categorymapping.id);
//}
def.Capabilities.Categories.AddCategoryMapping(categoryMapping.Id, torznabCat, categoryMapping.Desc);
}
}
}

View File

@@ -103,9 +103,6 @@ namespace NzbDrone.Core.Indexers
public static readonly IndexerCategory[] AllCats =
{
ZedOther,
ZedOtherHashed,
ZedOtherMisc,
Console,
ConsoleNDS,
ConsolePSP,
@@ -176,7 +173,10 @@ namespace NzbDrone.Core.Indexers
BooksForeign,
Other,
OtherMisc,
OtherHashed
OtherHashed,
ZedOther,
ZedOtherHashed,
ZedOtherMisc
};
static NewznabStandardCategory()

View File

@@ -9,6 +9,8 @@ namespace NzbDrone.Core.Indexers
public abstract class TorrentIndexerBase<TSettings> : HttpIndexerBase<TSettings>
where TSettings : IIndexerSettings, new()
{
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
protected TorrentIndexerBase(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{

View File

@@ -10,6 +10,8 @@ namespace NzbDrone.Core.Indexers
{
private readonly IValidateNzbs _nzbValidationService;
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
protected UsenetIndexerBase(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{

View File

@@ -201,6 +201,7 @@
"Indexer": "Indexer",
"IndexerAlreadySetup": "At least one instance of indexer is already setup",
"IndexerAuth": "Indexer Auth",
"IndexerCategories": "Indexer Categories",
"IndexerDetails": "Indexer Details",
"IndexerDisabled": "Indexer Disabled",
"IndexerFailureRate": "Indexer Failure Rate",
@@ -222,6 +223,7 @@
"IndexerRss": "Indexer Rss",
"IndexerSettingsSummary": "Configure various global Indexer settings including Proxies.",
"IndexerSite": "Indexer Site",
"IndexerStatus": "Indexer Status",
"IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures",
"IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}",
"IndexerTagsHelpText": "Use tags to specify Indexer Proxies or which apps the indexer is synced to. Applications without 1 or more matching Indexer Tags will not be synced to.",
@@ -277,6 +279,7 @@
"NoChange": "No Change",
"NoChanges": "No Changes",
"NoHistoryFound": "No history found",
"NoIndexersFound": "No indexers found",
"NoLeaveIt": "No, Leave It",
"NoLinks": "No Links",
"NoLogFiles": "No log files",