Compare commits

..

60 Commits

Author SHA1 Message Date
Qstick 3e700b63c2 New: Retry Postgres connection 3 times (with 5 second sleep) on Startup 2022-10-10 22:30:00 -05:00
Qstick df0b8fc660 And another..... 2022-10-09 19:04:30 -05:00
Qstick f96dbbfc21 Ensure FS doesn't fail when no proxy 2022-10-09 19:03:53 -05:00
Qstick 4a75f92cb5 Fixed: (FlareSolverr) Send non-auth global proxy when set
Fixes #1142
2022-10-09 18:33:41 -05:00
Qstick dd05a9dbd4 Obsolete Anthelion C# Indexer 2022-10-09 10:34:40 -05:00
Qstick e78b8d5346 New: Add long term Application status Healthcheck 2022-10-09 10:15:50 -05:00
Qstick 74a1d95ab7 Update NZBIndex Categories 2022-10-08 22:52:17 -05:00
Qstick f929a7e62f New: (Indexer) NZBIndex 2022-10-08 22:14:46 -05:00
Qstick e9e4248af4 New: (Indexer) RetroFlix 2022-10-08 19:18:12 -05:00
Yukine 9e3b43ef12 Fixed: (GreatPosterWall) correctly override Gazelle base method 2022-10-08 18:38:46 -05:00
Qstick 738a690aac Fixed: (Rarbg) Incorrect TVDB param logic
Fixes #1129

Co-Authored-By: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2022-10-08 18:20:41 -05:00
Qstick 3b7c59e9bb Fixed: (Rarbg) More reliable token handling and retry
Fixes #1148
2022-10-08 18:11:22 -05:00
Qstick b8ca28d955 Fixed: Explicitly forbid redirects on Gazelle search requests
Fixes #1144
2022-10-08 15:31:51 -05:00
Yukine 8797bb7d1c Remove unused Gazelle legacy code 2022-10-04 06:46:20 -05:00
Yukine be430732f5 Fixed: (GreatPosterWall) move imdb id search to searchstr query param 2022-10-04 06:46:20 -05:00
h96kikh6 e7b1380b85 Fixed: (Indexer) HDSpace - Added new categories
Added new categories: 45 - HDTV 2160 -> Prowlarr: Movies/UHD (2045), 46 - Movies 2160 -> Prowlarr: TV/UHD (5045), 47 - Doc 2160 -> Prowlarr: TV/Documentary (5080), 48 - Animation 2160 -> Prowlarr: TV/Anime (5070), 49 - XXX 2160 -> Prowlarr: XXX/UHD (6045)
2022-10-02 11:08:51 -05:00
Qstick c29735741c Optimize Indexer updates (v2) 2022-09-29 22:47:00 -05:00
Qstick f56a13a375 Bump Mailkit to 3.4.1 2022-09-29 22:14:25 -05:00
Qstick 148d8ee249 Bump Sentry to 3.21.0 2022-09-29 22:14:25 -05:00
Qstick 3547028b96 Bump YamlDotNet to 12.0.1 2022-09-29 22:14:25 -05:00
Qstick e4ffa1873e Fixed: Definition not updating if local file is missing 2022-09-29 22:13:21 -05:00
Qstick 2e85a21576 Fixed: (GazelleGames) Serialization error on empty response
Fixes #1137
2022-09-29 20:14:18 -05:00
Qstick 0a111e7572 Fixed: (Cardigann) Search path redirect
Fixes #1102
2022-09-26 21:13:57 -05:00
Qstick 25217c0ee8 Fixed: TypeError on Keyup in Firefox for IndexerIndex 2022-09-25 20:44:26 -05:00
Qstick 791592927c Purge old PTP Radarr check 2022-09-25 12:13:49 -05:00
Qstick 4137193a60 Fixed: (Avistaz) FL Only should be checkbox 2022-09-25 10:08:12 -05:00
Qstick 99816bfd36 Fix test error due to DryIOC update 2022-09-24 20:24:17 -05:00
Qstick 59e5b5bd52 Set PooledConnectionLifetime to 10 minutes
Setting PooledConnectinLifetime to a defined number will ensure we don't run into DNS refresh issues
2022-09-18 21:45:10 -05:00
Qstick 7fa0a2b33c Bump Swashbuckle to 6.4.0 2022-09-18 21:43:06 -05:00
Qstick 0593ca6b9e Bump DryIoc to 5.2.2 2022-09-18 21:40:32 -05:00
Qstick 06a26b5c87 Fixed: (RarBG) Don't disable indexer on temp rate limit
Fixes #1027
2022-09-18 15:56:31 -05:00
Weblate dcae6dc151 Translated using Weblate (Slovak)
Currently translated at 12.5% (58 of 462 strings)

Translated using Weblate (Portuguese)

Currently translated at 78.3% (362 of 462 strings)

Translated using Weblate (Portuguese)

Currently translated at 78.3% (362 of 462 strings)

Translated using Weblate (Chinese (Traditional) (zh_TW))

Currently translated at 2.8% (13 of 462 strings)

Translated using Weblate (Finnish)

Currently translated at 100.0% (462 of 462 strings)

Added translation using Weblate (Latvian)

Co-authored-by: Dainel Amendoeira <daniel@amendoeira.eu>
Co-authored-by: Gylesie <github-anon.dasheens@aleeas.com>
Co-authored-by: HiNesslio <chi.lio@shms-mail.ch>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/
Translation: Servarr/Prowlarr
2022-09-18 15:54:43 -05:00
Qstick 04e3ed0ffe Fixed: (Gazelle) Download fails if out of FL tokens
Fixes #1088
2022-09-18 15:39:09 -05:00
Qstick 1ed5ed9179 Bump version to 0.4.7 2022-09-18 14:55:58 -05:00
Qstick d292d086ee Prevent query failures on Cardigann Indexers 2022-09-12 22:49:28 -05:00
Qstick f68915c5dd New: Don't query indexers if they don't support query categories 2022-09-12 22:28:07 -05:00
Qstick 01e970e1a7 New: (Avistaz) Genre Search Support
Fixes #1097
2022-09-12 21:27:32 -05:00
Qstick 68df439498 New: (Avistaz) Freeleech Only Setting
#1108
2022-09-12 21:16:05 -05:00
Qstick 33de7ca7ab Fixed: (MoreThanTv) Parsing issue when download url is null
Fixes #1047
2022-09-10 12:50:32 -05:00
Qstick ae2d9b795b Don't reset request Url when calculating RedirectUrl 2022-09-10 12:24:41 -05:00
Qstick eadea745f8 Warn on redirect to alt domain when checking if login required 2022-09-10 12:24:41 -05:00
Qstick f958c4aefa Bump version to 0.4.6 2022-09-08 20:57:06 -05:00
Weblate 4cf9fb0e79 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (462 of 462 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.7% (461 of 462 strings)

Translated using Weblate (French)

Currently translated at 95.6% (442 of 462 strings)

Translated using Weblate (French)

Currently translated at 95.2% (440 of 462 strings)

Translated using Weblate (German)

Currently translated at 99.1% (458 of 462 strings)

Translated using Weblate (French)

Currently translated at 95.2% (440 of 462 strings)

Translated using Weblate (French)

Currently translated at 94.8% (438 of 462 strings)

Translated using Weblate (Spanish)

Currently translated at 77.7% (359 of 462 strings)

Co-authored-by: Fradri <adrien.riotte@live.fr>
Co-authored-by: Gian Klug <gian.klug@ict-scouts.ch>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Mijail Todorovich <mijailtodorovich+git@gmail.com>
Co-authored-by: Thomas Schwery <thomas@schwery.me>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: berrre <zdch6W75@gmail.com>
Co-authored-by: cikyw <cikyw@vomoto.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translation: Servarr/Prowlarr
2022-09-08 20:29:59 -05:00
psylenced bfa68347e6 Fix: Trace logging postgres cleanse for large json files. 2022-09-08 20:28:05 -05:00
Qstick f97b35403d Fixed: Indexer proxies not applying to requests
Fixes #1107
2022-09-05 19:55:46 -05:00
Weblate bf2e057247 Translated using Weblate (Russian)
Currently translated at 76.1% (352 of 462 strings)

Translated using Weblate (Romanian)

Currently translated at 71.8% (332 of 462 strings)

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: emanuelsipos <emanuelsipos1@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/
Translation: Servarr/Prowlarr
2022-08-18 23:12:04 -05:00
Qstick 5a278f4e9d Fixed: Set default null value for Genre, Publisher, Douban parameters 2022-08-18 22:30:04 -05:00
Yukine 232a6efd0d New: (Indexer) GreatPosterWall (#1085)
* New: (Indexer) GreatPosterWall

* fix(GreatPosterWall): time is Chinese and not UTC

* feat(GreatPosterWall): add canUseToken check to GetDownloadUrl

* feat(GreatPosterWall): add fileName property as title
2022-08-18 20:04:29 -05:00
Chris 7e01c93b2c Fixed: Regex in log cleanser taking 10+ minutes on messages longer than 100k.
(cherry picked from commit d01bae92bfd68b04c54ab19bafe8af16c68ce711)
2022-08-18 20:03:31 -05:00
Qstick d58f6551e6 Fixed: Set Units for Seed Time settings 2022-08-18 19:56:13 -05:00
Qstick 6446528022 Bump version to 0.4.5 2022-08-15 22:40:22 -05:00
Weblate 7f63757e06 Translated using Weblate (Chinese (Simplified) (zh_CN))
Currently translated at 100.0% (462 of 462 strings)

Co-authored-by: Jessie <1355239678@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2022-08-14 23:40:16 -05:00
Qstick b5d789df3a Fixed: Correctly persist FlareSolverr Cookies to ensure it doesn't run on every request 2022-08-13 17:30:25 -05:00
Qstick 4473551182 Fixed: Correctly use FlareSolverr User Agent 2022-08-13 17:27:58 -05:00
Qstick fd88f44865 Remove duplicate package NLog.Extensions in Prowlarr.Common 2022-08-13 16:41:09 -05:00
bakerboy448 69b8be5b67 Fixed: (Cardigann) fix imatch for rows
based on jackett 9768fd288ba299f8a2d1aada1a539d156e7e97b9
2022-08-11 21:32:53 -05:00
ta264 fbde3fe2cd Support for digest auth with HttpRequests
Changes from de243991dd78c0fa4cfd2b629839874bbd8f2650 missed b7b5a6e7e1
2022-08-05 16:09:27 +01:00
bakerboy448 f9e2c5b673 Fixed: (Cardigann) Genre is optional
Fixed: (Cardigann) Expand Genre Validate characters
2022-08-02 23:38:41 -05:00
bakerboy448 5c5dfbb66b Fixed: (Cardigann) Genre Parsing
New: (Cardigann) Add Validate Field Filter

v7
2022-08-02 23:38:41 -05:00
Servarr 2db24d454e Automated API Docs update 2022-07-30 16:22:01 -05:00
136 changed files with 7541 additions and 1194 deletions
+3 -3
View File
@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests' testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '0.4.4' majorVersion: '0.4.7'
minorVersion: $[counter('minorVersion', 1)] minorVersion: $[counter('minorVersion', 1)]
prowlarrVersion: '$(majorVersion).$(minorVersion)' prowlarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)' buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'
@@ -541,7 +541,7 @@ stages:
Prowlarr__Postgres__Password: 'prowlarr' Prowlarr__Postgres__Password: 'prowlarr'
pool: pool:
vmImage: 'ubuntu-18.04' vmImage: ${{ variables.linuxImage }}
timeoutInMinutes: 10 timeoutInMinutes: 10
@@ -675,7 +675,7 @@ stages:
Prowlarr__Postgres__Password: 'prowlarr' Prowlarr__Postgres__Password: 'prowlarr'
pool: pool:
vmImage: 'ubuntu-18.04' vmImage: ${{ variables.linuxImage }}
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
+1 -1
View File
@@ -221,7 +221,7 @@ class IndexerIndex extends Component {
onKeyUp = (event) => { onKeyUp = (event) => {
const jumpBarItems = this.state.jumpBarItems.order; const jumpBarItems = this.state.jumpBarItems.order;
if (event.path.length === 4) { if (event.composedPath && event.composedPath().length === 4) {
if (event.keyCode === keyCodes.HOME && event.ctrlKey) { if (event.keyCode === keyCodes.HOME && event.ctrlKey) {
this.setState({ jumpToCharacter: jumpBarItems[0] }); this.setState({ jumpToCharacter: jumpBarItems[0] });
} }
@@ -98,15 +98,30 @@ namespace NzbDrone.Common.Test.InstrumentationTests
// Internal // Internal
[TestCase(@"[Info] MigrationController: *** Migrating Database=prowlarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;Enlist=False ***")] [TestCase(@"[Info] MigrationController: *** Migrating Database=prowlarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;Enlist=False ***")]
[TestCase("/readarr/signalr/messages/negotiate?access_token=1234530f422f4aacb6b301233210aaaa&negotiateVersion=1")] [TestCase("/readarr/signalr/messages/negotiate?access_token=1234530f422f4aacb6b301233210aaaa&negotiateVersion=1")]
[TestCase(@"[Info] MigrationController: *** Migrating Database=prowlarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;token=mySecret;Enlist=False&username=mySecret;mypassword=mySecret;mypass=shouldkeep1;test_token=mySecret;password=123%@%_@!#^#@;use_password=mySecret;get_token=shouldkeep2;usetoken=shouldkeep3;passwrd=mySecret;")]
public void should_clean_message(string message) public void should_clean_message(string message)
{ {
var cleansedMessage = CleanseLogMessage.Cleanse(message); var cleansedMessage = CleanseLogMessage.Cleanse(message);
cleansedMessage.Should().NotContain("mySecret"); cleansedMessage.Should().NotContain("mySecret");
cleansedMessage.Should().NotContain("123%@%_@!#^#@");
cleansedMessage.Should().NotContain("01233210"); cleansedMessage.Should().NotContain("01233210");
} }
[TestCase(@"[Info] MigrationController: *** Migrating Database=radarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;token=mySecret;Enlist=False&username=mySecret;mypassword=mySecret;mypass=shouldkeep1;test_token=mySecret;password=123%@%_@!#^#@;use_password=mySecret;get_token=shouldkeep2;usetoken=shouldkeep3;passwrd=mySecret;")]
public void should_keep_message(string message)
{
var cleansedMessage = CleanseLogMessage.Cleanse(message);
cleansedMessage.Should().NotContain("mySecret");
cleansedMessage.Should().NotContain("123%@%_@!#^#@");
cleansedMessage.Should().NotContain("01233210");
cleansedMessage.Should().Contain("shouldkeep1");
cleansedMessage.Should().Contain("shouldkeep2");
cleansedMessage.Should().Contain("shouldkeep3");
}
[TestCase(@"Some message (from 32.2.3.5 user agent)")] [TestCase(@"Some message (from 32.2.3.5 user agent)")]
[TestCase(@"Auth-Invalidated ip 32.2.3.5")] [TestCase(@"Auth-Invalidated ip 32.2.3.5")]
[TestCase(@"Auth-Success ip 32.2.3.5")] [TestCase(@"Auth-Success ip 32.2.3.5")]
@@ -99,7 +99,7 @@ namespace NzbDrone.Common.Http.Dispatchers
AddRequestHeaders(requestMessage, request.Headers); AddRequestHeaders(requestMessage, request.Headers);
} }
var httpClient = GetClient(request.Url); var httpClient = GetClient(request.Url, request.ProxySettings);
var sw = new Stopwatch(); var sw = new Stopwatch();
@@ -154,9 +154,9 @@ namespace NzbDrone.Common.Http.Dispatchers
} }
} }
protected virtual System.Net.Http.HttpClient GetClient(HttpUri uri) protected virtual System.Net.Http.HttpClient GetClient(HttpUri uri, HttpProxySettings requestProxy)
{ {
var proxySettings = _proxySettingsProvider.GetProxySettings(uri); var proxySettings = requestProxy ?? _proxySettingsProvider.GetProxySettings(uri);
var key = proxySettings?.Key ?? NO_PROXY_KEY; var key = proxySettings?.Key ?? NO_PROXY_KEY;
@@ -174,6 +174,7 @@ namespace NzbDrone.Common.Http.Dispatchers
PreAuthenticate = true, PreAuthenticate = true,
MaxConnectionsPerServer = 12, MaxConnectionsPerServer = 12,
ConnectCallback = onConnect, ConnectCallback = onConnect,
PooledConnectionLifetime = TimeSpan.FromMinutes(10),
SslOptions = new SslClientAuthenticationOptions SslOptions = new SslClientAuthenticationOptions
{ {
RemoteCertificateValidationCallback = _certificateValidationService.ShouldByPassValidationError RemoteCertificateValidationCallback = _certificateValidationService.ShouldByPassValidationError
@@ -234,6 +235,7 @@ namespace NzbDrone.Common.Http.Dispatchers
webRequest.Headers.TransferEncoding.ParseAdd(header.Value); webRequest.Headers.TransferEncoding.ParseAdd(header.Value);
break; break;
case "User-Agent": case "User-Agent":
webRequest.Headers.UserAgent.Clear();
webRequest.Headers.UserAgent.ParseAdd(header.Value); webRequest.Headers.UserAgent.ParseAdd(header.Value);
break; break;
case "Proxy-Connection": case "Proxy-Connection":
+2 -1
View File
@@ -6,6 +6,7 @@ using System.Net.Http;
using System.Text; using System.Text;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http.Proxy;
namespace NzbDrone.Common.Http namespace NzbDrone.Common.Http
{ {
@@ -37,7 +38,7 @@ namespace NzbDrone.Common.Http
public HttpMethod Method { get; set; } public HttpMethod Method { get; set; }
public HttpHeader Headers { get; set; } public HttpHeader Headers { get; set; }
public Encoding Encoding { get; set; } public Encoding Encoding { get; set; }
public IWebProxy Proxy { get; set; } public HttpProxySettings ProxySettings { get; set; }
public byte[] ContentData { get; set; } public byte[] ContentData { get; set; }
public string ContentSummary { get; set; } public string ContentSummary { get; set; }
public ICredentials Credentials { get; set; } public ICredentials Credentials { get; set; }
+2 -2
View File
@@ -89,13 +89,13 @@ namespace NzbDrone.Common.Http
if (match.Success) if (match.Success)
{ {
return (Request.Url += new HttpUri(match.Groups[2].Value)).FullUri; return (Request.Url + new HttpUri(match.Groups[2].Value)).FullUri;
} }
return string.Empty; return string.Empty;
} }
return (Request.Url += new HttpUri(newUrl)).FullUri; return (Request.Url + new HttpUri(newUrl)).FullUri;
} }
} }
@@ -18,6 +18,7 @@ namespace NzbDrone.Common.Instrumentation
new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled), new Regex(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled),
new Regex(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"\b(\w*)?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=authkey = "")(?<secret>[^&=]+?)(?="")", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=authkey = "")(?<secret>[^&=]+?)(?="")", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=beyond-hd\.[a-z]+/api/torrents/)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase), new Regex(@"(?<=beyond-hd\.[a-z]+/api/torrents/)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
+2 -3
View File
@@ -4,14 +4,13 @@
<DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants> <DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DryIoc.dll" Version="4.8.8" /> <PackageReference Include="DryIoc.dll" Version="5.2.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NLog" Version="5.0.1" /> <PackageReference Include="NLog" Version="5.0.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Sentry" Version="3.19.0" /> <PackageReference Include="Sentry" Version="3.21.0" />
<PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" />
<PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="SharpZipLib" Version="1.3.3" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" />
@@ -0,0 +1,4 @@
{
"status": "success",
"response": []
}
@@ -17,7 +17,7 @@ using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.IndexerTests.AvistazTests namespace NzbDrone.Core.Test.IndexerTests.AvistazTests
{ {
[TestFixture] [TestFixture]
public class AvistazFixture : CoreTest<Avistaz> public class AvistazFixture : CoreTest<AvistaZ>
{ {
[SetUp] [SetUp]
public void Setup() public void Setup()
@@ -17,7 +17,7 @@ using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.IndexerTests.AvistazTests namespace NzbDrone.Core.Test.IndexerTests.AvistazTests
{ {
[TestFixture] [TestFixture]
public class PrivateHDFixture : CoreTest<Avistaz> public class PrivateHDFixture : CoreTest<PrivateHD>
{ {
[SetUp] [SetUp]
public void Setup() public void Setup()
@@ -12,6 +12,7 @@ using NzbDrone.Core.Indexers.Definitions;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.IndexerTests.GazelleGamesTests namespace NzbDrone.Core.Test.IndexerTests.GazelleGamesTests
{ {
@@ -64,5 +65,19 @@ namespace NzbDrone.Core.Test.IndexerTests.GazelleGamesTests
torrentInfo.DownloadVolumeFactor.Should().Be(1); torrentInfo.DownloadVolumeFactor.Should().Be(1);
torrentInfo.UploadVolumeFactor.Should().Be(1); torrentInfo.UploadVolumeFactor.Should().Be(1);
} }
[Test]
public async Task should_not_error_if_empty_response()
{
var recentFeed = ReadAllText(@"Files/Indexers/GazelleGames/recentfeed-empty.json");
Mocker.GetMock<IIndexerHttpClient>()
.Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition))
.Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, new CookieCollection(), recentFeed)));
var releases = (await Subject.Fetch(new BasicSearchCriteria { Categories = new int[] { 2000 } })).Releases;
releases.Should().HaveCount(0);
}
} }
} }
@@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RarbgTests
}; };
Mocker.GetMock<IRarbgTokenProvider>() Mocker.GetMock<IRarbgTokenProvider>()
.Setup(v => v.GetToken(It.IsAny<RarbgSettings>(), It.IsAny<string>())) .Setup(v => v.GetToken(It.IsAny<RarbgSettings>()))
.Returns("validtoken"); .Returns("validtoken");
} }
@@ -3,7 +3,6 @@ using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Test.IndexerTests namespace NzbDrone.Core.Test.IndexerTests
@@ -21,8 +20,8 @@ namespace NzbDrone.Core.Test.IndexerTests
public int _supportedPageSize; public int _supportedPageSize;
public override int PageSize => _supportedPageSize; public override int PageSize => _supportedPageSize;
public TestIndexer(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) public TestIndexer(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, nzbValidationService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, nzbValidationService, logger)
{ {
} }
@@ -6,7 +6,7 @@
<PackageReference Include="Dapper" Version="2.0.123" /> <PackageReference Include="Dapper" Version="2.0.123" />
<PackageReference Include="NBuilder" Version="6.1.0" /> <PackageReference Include="NBuilder" Version="6.1.0" />
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
<PackageReference Include="YamlDotNet" Version="11.2.1" /> <PackageReference Include="YamlDotNet" Version="12.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" />
+32
View File
@@ -1,6 +1,7 @@
using System; using System;
using System.Data.Common; using System.Data.Common;
using System.Data.SQLite; using System.Data.SQLite;
using System.Net.Sockets;
using NLog; using NLog;
using Npgsql; using Npgsql;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
@@ -125,6 +126,37 @@ namespace NzbDrone.Core.Datastore
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/prowlarr/faq#i-am-getting-an-error-database-disk-image-is-malformed", e, fileName); throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/prowlarr/faq#i-am-getting-an-error-database-disk-image-is-malformed", e, fileName);
} }
catch (NpgsqlException e)
{
if (e.InnerException is SocketException)
{
var retryCount = 3;
while (true)
{
Logger.Error(e, "Failure to connect to Postgres DB, {0} retries remaining", retryCount);
try
{
_migrationController.Migrate(connectionString, migrationContext);
}
catch (Exception ex)
{
if (--retryCount > 0)
{
System.Threading.Thread.Sleep(5000);
continue;
}
throw new ProwlarrStartupException(ex, "Error creating main database");
}
}
}
else
{
throw new ProwlarrStartupException(e, "Error creating main database");
}
}
catch (Exception e) catch (Exception e)
{ {
throw new ProwlarrStartupException(e, "Error creating main database"); throw new ProwlarrStartupException(e, "Error creating main database");
@@ -1,87 +0,0 @@
using System.Collections.Generic;
using System.Data;
using System.Text.Json;
using Dapper;
using FluentMigrator;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(22)]
public class indexer_definition : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Indexers")
.AddColumn("DefinitionFile").AsString().Nullable();
Execute.WithConnection(MigrateCardigannDefinitions);
}
private void MigrateCardigannDefinitions(IDbConnection conn, IDbTransaction tran)
{
var indexers = new List<Indexer017>();
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandText = "SELECT \"Id\", \"Settings\", \"Implementation\", \"ConfigContract\" FROM \"Indexers\"";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var id = reader.GetInt32(0);
var settings = reader.GetString(1);
var implementation = reader.GetString(2);
var configContract = reader.GetString(3);
var defFile = implementation.ToLowerInvariant();
if (implementation == "Cardigann")
{
if (!string.IsNullOrWhiteSpace(settings))
{
var jsonObject = STJson.Deserialize<JsonElement>(settings);
if (jsonObject.TryGetProperty("definitionFile", out JsonElement jsonDef))
{
defFile = jsonDef.GetString();
}
}
}
else if (configContract == "AvistazSettings")
{
implementation = "Avistaz";
}
else if (configContract == "Unit3dSettings")
{
implementation = "Unit3d";
}
else if (configContract == "Newznab")
{
defFile = "";
}
indexers.Add(new Indexer017
{
DefinitionFile = defFile,
Implementation = implementation,
Id = id
});
}
}
}
var updateSql = "UPDATE \"Indexers\" SET \"DefinitionFile\" = @DefinitionFile, \"Implementation\" = @Implementation WHERE \"Id\" = @Id";
conn.Execute(updateSql, indexers, transaction: tran);
}
public class Indexer017
{
public int Id { get; set; }
public string DefinitionFile { get; set; }
public string Implementation { get; set; }
}
}
}
@@ -73,7 +73,7 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
baseUrl = HttpUri.CombinePath(baseUrl, "api"); baseUrl = HttpUri.CombinePath(baseUrl, "api");
var requestBuilder = new JsonRpcRequestBuilder(baseUrl, method, parameters); var requestBuilder = new JsonRpcRequestBuilder(baseUrl, method, parameters);
requestBuilder.LogResponseContent = true; requestBuilder.LogResponseContent = true;
requestBuilder.NetworkCredential = new NetworkCredential(settings.Username, settings.Password); requestBuilder.NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password);
requestBuilder.Headers.Add("Accept-Encoding", "gzip,deflate"); requestBuilder.Headers.Add("Accept-Encoding", "gzip,deflate");
var httpRequest = requestBuilder.Build(); var httpRequest = requestBuilder.Build();
@@ -242,7 +242,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var requestBuilder = new JsonRpcRequestBuilder(baseUrl, method, parameters); var requestBuilder = new JsonRpcRequestBuilder(baseUrl, method, parameters);
requestBuilder.LogResponseContent = true; requestBuilder.LogResponseContent = true;
requestBuilder.NetworkCredential = new NetworkCredential(settings.Username, settings.Password); requestBuilder.NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password);
var httpRequest = requestBuilder.Build(); var httpRequest = requestBuilder.Build();
@@ -276,7 +276,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase) var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase)
{ {
LogResponseContent = true, LogResponseContent = true,
NetworkCredential = new NetworkCredential(settings.Username, settings.Password) NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password)
}; };
return requestBuilder; return requestBuilder;
} }
@@ -317,7 +317,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase) var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase)
{ {
LogResponseContent = true, LogResponseContent = true,
NetworkCredential = new NetworkCredential(settings.Username, settings.Password) NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password)
}; };
return requestBuilder; return requestBuilder;
} }
@@ -200,7 +200,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
.Accept(HttpAccept.Json); .Accept(HttpAccept.Json);
requestBuilder.LogResponseContent = true; requestBuilder.LogResponseContent = true;
requestBuilder.NetworkCredential = new NetworkCredential(settings.Username, settings.Password); requestBuilder.NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password);
requestBuilder.AllowAutoRedirect = false; requestBuilder.AllowAutoRedirect = false;
return requestBuilder; return requestBuilder;
@@ -196,7 +196,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
.Accept(HttpAccept.Json); .Accept(HttpAccept.Json);
requestBuilder.LogResponseContent = true; requestBuilder.LogResponseContent = true;
requestBuilder.NetworkCredential = new NetworkCredential(settings.Username, settings.Password); requestBuilder.NetworkCredential = new BasicNetworkCredential(settings.Username, settings.Password);
return requestBuilder; return requestBuilder;
} }
@@ -0,0 +1,59 @@
using System;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Applications;
using NzbDrone.Core.Localization;
using NzbDrone.Core.ThingiProvider.Events;
namespace NzbDrone.Core.HealthCheck.Checks
{
[CheckOn(typeof(ProviderUpdatedEvent<IApplication>))]
[CheckOn(typeof(ProviderDeletedEvent<IApplication>))]
[CheckOn(typeof(ProviderStatusChangedEvent<IApplication>))]
public class ApplicationLongTermStatusCheck : HealthCheckBase
{
private readonly IApplicationFactory _providerFactory;
private readonly IApplicationStatusService _providerStatusService;
public ApplicationLongTermStatusCheck(IApplicationFactory providerFactory,
IApplicationStatusService providerStatusService,
ILocalizationService localizationService)
: base(localizationService)
{
_providerFactory = providerFactory;
_providerStatusService = providerStatusService;
}
public override HealthCheck Check()
{
var enabledProviders = _providerFactory.GetAvailableProviders();
var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(),
i => i.Definition.Id,
s => s.ProviderId,
(i, s) => new { Provider = i, Status = s })
.Where(p => p.Status.InitialFailure.HasValue &&
p.Status.InitialFailure.Value.Before(
DateTime.UtcNow.AddHours(-6)))
.ToList();
if (backOffProviders.Empty())
{
return new HealthCheck(GetType());
}
if (backOffProviders.Count == enabledProviders.Count)
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("ApplicationLongTermStatusCheckAllClientMessage"),
"#applications-are-unavailable-due-to-failures");
}
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("ApplicationLongTermStatusCheckSingleClientMessage"),
string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))),
"#applications-are-unavailable-due-to-failures");
}
}
}
@@ -26,7 +26,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
var currentDefs = _indexerDefinitionUpdateService.All(); var currentDefs = _indexerDefinitionUpdateService.All();
var noDefIndexers = _indexerFactory.AllProviders(false) var noDefIndexers = _indexerFactory.AllProviders(false)
.Where(i => i.Definition.Implementation == "Cardigann" && !currentDefs.Any(d => d.File == ((IndexerDefinition)i.Definition).DefinitionFile)).ToList(); .Where(i => i.Definition.Implementation == "Cardigann" && !currentDefs.Any(d => d.File == ((CardigannSettings)i.Definition.Settings).DefinitionFile)).ToList();
if (noDefIndexers.Count == 0) if (noDefIndexers.Count == 0)
{ {
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
var blocklist = _indexerDefinitionUpdateService.GetBlocklist(); var blocklist = _indexerDefinitionUpdateService.GetBlocklist();
var oldIndexers = _indexerFactory.AllProviders(false) var oldIndexers = _indexerFactory.AllProviders(false)
.Where(i => i.IsObsolete() || (i.Definition.Implementation == "Cardigann" && blocklist.Contains(((IndexerDefinition)i.Definition).DefinitionFile))).ToList(); .Where(i => i.IsObsolete() || (i.Definition.Implementation == "Cardigann" && blocklist.Contains(((CardigannSettings)i.Definition.Settings).DefinitionFile))).ToList();
if (oldIndexers.Count == 0) if (oldIndexers.Count == 0)
{ {
@@ -1,34 +0,0 @@
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.PassThePopcorn;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.HealthCheck.Checks
{
public class PTPOldSettingsCheck : HealthCheckBase
{
private readonly IIndexerFactory _indexerFactory;
public PTPOldSettingsCheck(IIndexerFactory indexerFactory, ILocalizationService localizationService)
: base(localizationService)
{
_indexerFactory = indexerFactory;
}
public override HealthCheck Check()
{
var ptpIndexers = _indexerFactory.All().Where(i => i.Settings.GetType() == typeof(PassThePopcornSettings));
var ptpIndexerOldSettings = ptpIndexers
.Where(i => (i.Settings as PassThePopcornSettings).APIUser.IsNullOrWhiteSpace()).Select(i => i.Name);
if (ptpIndexerOldSettings.Any())
{
return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("PtpOldSettingsCheckMessage"), string.Join(", ", ptpIndexerOldSettings)));
}
return new HealthCheck(GetType());
}
}
}
@@ -10,6 +10,7 @@ using NzbDrone.Common.Cache;
using NzbDrone.Common.Cloud; using NzbDrone.Common.Cloud;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Http.Proxy;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
using NzbDrone.Core.Http.CloudFlare; using NzbDrone.Core.Http.CloudFlare;
using NzbDrone.Core.Localization; using NzbDrone.Core.Localization;
@@ -20,10 +21,12 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
public class FlareSolverr : HttpIndexerProxyBase<FlareSolverrSettings> public class FlareSolverr : HttpIndexerProxyBase<FlareSolverrSettings>
{ {
private readonly ICached<string> _cache; private readonly ICached<string> _cache;
private readonly IHttpProxySettingsProvider _proxySettingsProvider;
public FlareSolverr(IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService, ICacheManager cacheManager) public FlareSolverr(IHttpProxySettingsProvider proxySettingsProvider, IProwlarrCloudRequestBuilder cloudRequestBuilder, IHttpClient httpClient, Logger logger, ILocalizationService localizationService, ICacheManager cacheManager)
: base(cloudRequestBuilder, httpClient, logger, localizationService) : base(cloudRequestBuilder, httpClient, logger, localizationService)
{ {
_proxySettingsProvider = proxySettingsProvider;
_cache = cacheManager.GetCache<string>(typeof(string), "UserAgent"); _cache = cacheManager.GetCache<string>(typeof(string), "UserAgent");
} }
@@ -100,6 +103,10 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
var userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"; var userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36";
var maxTimeout = Settings.RequestTimeout * 1000; var maxTimeout = Settings.RequestTimeout * 1000;
// Use Proxy if no credentials are set (creds not supported as of FS 2.2.9)
var proxySettings = _proxySettingsProvider.GetProxySettings();
var proxyUrl = proxySettings != null && proxySettings.Username.IsNullOrWhiteSpace() && proxySettings.Password.IsNullOrWhiteSpace() ? GetProxyUri(proxySettings) : null;
if (request.Method == HttpMethod.Get) if (request.Method == HttpMethod.Get)
{ {
req = new FlareSolverrRequestGet req = new FlareSolverrRequestGet
@@ -107,14 +114,18 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
Cmd = "request.get", Cmd = "request.get",
Url = url, Url = url,
MaxTimeout = maxTimeout, MaxTimeout = maxTimeout,
UserAgent = userAgent UserAgent = userAgent,
Proxy = new FlareSolverrProxy
{
Url = proxyUrl?.AbsoluteUri
}
}; };
} }
else if (request.Method == HttpMethod.Post) else if (request.Method == HttpMethod.Post)
{ {
var contentTypeType = request.Headers.ContentType; var contentTypeType = request.Headers.ContentType.ToLower() ?? "<null>";
if (contentTypeType == "application/x-www-form-urlencoded") if (contentTypeType.Contains("application/x-www-form-urlencoded"))
{ {
var contentTypeValue = request.Headers.ContentType.ToString(); var contentTypeValue = request.Headers.ContentType.ToString();
var postData = request.GetContent(); var postData = request.GetContent();
@@ -130,10 +141,15 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
ContentLength = null ContentLength = null
}, },
MaxTimeout = maxTimeout, MaxTimeout = maxTimeout,
UserAgent = userAgent UserAgent = userAgent,
Proxy = new FlareSolverrProxy
{
Url = proxyUrl?.AbsoluteUri
}
}; };
} }
else if (contentTypeType.Contains("multipart/form-data")) else if (contentTypeType.Contains("multipart/form-data")
|| contentTypeType.Contains("text/html"))
{ {
//TODO Implement - check if we just need to pass the content-type with the relevant headers //TODO Implement - check if we just need to pass the content-type with the relevant headers
throw new FlareSolverrException("Unimplemented POST Content-Type: " + request.Headers.ContentType); throw new FlareSolverrException("Unimplemented POST Content-Type: " + request.Headers.ContentType);
@@ -153,9 +169,10 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
newRequest.Headers.ContentType = "application/json"; newRequest.Headers.ContentType = "application/json";
newRequest.Method = HttpMethod.Post; newRequest.Method = HttpMethod.Post;
newRequest.LogResponseContent = true;
newRequest.SetContent(req.ToJson()); newRequest.SetContent(req.ToJson());
_logger.Debug("Applying FlareSolverr Proxy {0} to request {1}", Name, request.Url); _logger.Debug("Cloudflare Detected, Applying FlareSolverr Proxy {0} to request {1}", Name, request.Url);
return newRequest; return newRequest;
} }
@@ -189,38 +206,59 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
return new ValidationResult(failures); return new ValidationResult(failures);
} }
public class FlareSolverrRequest private Uri GetProxyUri(HttpProxySettings proxySettings)
{
switch (proxySettings.Type)
{
case ProxyType.Http:
return new Uri("http://" + proxySettings.Host + ":" + proxySettings.Port);
case ProxyType.Socks4:
return new Uri("socks4://" + proxySettings.Host + ":" + proxySettings.Port);
case ProxyType.Socks5:
return new Uri("socks5://" + proxySettings.Host + ":" + proxySettings.Port);
default:
return null;
}
}
private class FlareSolverrRequest
{ {
public string Cmd { get; set; } public string Cmd { get; set; }
public string Url { get; set; } public string Url { get; set; }
public string UserAgent { get; set; } public string UserAgent { get; set; }
public Cookie[] Cookies { get; set; } public Cookie[] Cookies { get; set; }
public FlareSolverrProxy Proxy { get; set; }
} }
public class FlareSolverrRequestGet : FlareSolverrRequest private class FlareSolverrRequestGet : FlareSolverrRequest
{ {
public string Headers { get; set; } public string Headers { get; set; }
public int MaxTimeout { get; set; } public int MaxTimeout { get; set; }
} }
public class FlareSolverrRequestPost : FlareSolverrRequest private class FlareSolverrRequestPost : FlareSolverrRequest
{ {
public string PostData { get; set; } public string PostData { get; set; }
public int MaxTimeout { get; set; } public int MaxTimeout { get; set; }
} }
public class FlareSolverrRequestPostUrlEncoded : FlareSolverrRequestPost private class FlareSolverrRequestPostUrlEncoded : FlareSolverrRequestPost
{ {
public HeadersPost Headers { get; set; } public HeadersPost Headers { get; set; }
} }
public class HeadersPost private class FlareSolverrProxy
{
public string Url { get; set; }
}
private class HeadersPost
{ {
public string ContentType { get; set; } public string ContentType { get; set; }
public string ContentLength { get; set; } public string ContentLength { get; set; }
} }
public class FlareSolverrResponse private class FlareSolverrResponse
{ {
public string Status { get; set; } public string Status { get; set; }
public string Message { get; set; } public string Message { get; set; }
@@ -230,7 +268,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
public Solution Solution { get; set; } public Solution Solution { get; set; }
} }
public class Solution private class Solution
{ {
public string Url { get; set; } public string Url { get; set; }
public string Status { get; set; } public string Status { get; set; }
@@ -240,7 +278,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
public string UserAgent { get; set; } public string UserAgent { get; set; }
} }
public class Cookie private class Cookie
{ {
public string Name { get; set; } public string Name { get; set; }
public string Value { get; set; } public string Value { get; set; }
@@ -257,7 +295,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
public System.Net.Cookie ToCookieObj() => new System.Net.Cookie(Name, Value); public System.Net.Cookie ToCookieObj() => new System.Net.Cookie(Name, Value);
} }
public class Headers private class Headers
{ {
public string Status { get; set; } public string Status { get; set; }
public string Date { get; set; } public string Date { get; set; }
@@ -3,7 +3,9 @@ using NLog;
using NzbDrone.Common.Cloud; using NzbDrone.Common.Cloud;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Http.Proxy;
using NzbDrone.Core.Localization; using NzbDrone.Core.Localization;
using NzbDrone.Core.Notifications.Prowl;
namespace NzbDrone.Core.IndexerProxies.Http namespace NzbDrone.Core.IndexerProxies.Http
{ {
@@ -18,14 +20,13 @@ namespace NzbDrone.Core.IndexerProxies.Http
public override HttpRequest PreRequest(HttpRequest request) public override HttpRequest PreRequest(HttpRequest request)
{ {
if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) request.ProxySettings = new HttpProxySettings(ProxyType.Http,
{ Settings.Host,
request.Proxy = new WebProxy(Settings.Host + ":" + Settings.Port, false, null, new NetworkCredential(Settings.Username, Settings.Password)); Settings.Port,
} null,
else false,
{ Settings.Username,
request.Proxy = new WebProxy(Settings.Host + ":" + Settings.Port, false, null); Settings.Password);
}
_logger.Debug("Applying HTTP(S) Proxy {0} to request {1}", Name, request.Url); _logger.Debug("Applying HTTP(S) Proxy {0} to request {1}", Name, request.Url);
@@ -4,6 +4,7 @@ using NLog;
using NzbDrone.Common.Cloud; using NzbDrone.Common.Cloud;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Http.Proxy;
using NzbDrone.Core.Localization; using NzbDrone.Core.Localization;
namespace NzbDrone.Core.IndexerProxies.Socks4 namespace NzbDrone.Core.IndexerProxies.Socks4
@@ -25,14 +26,13 @@ namespace NzbDrone.Core.IndexerProxies.Socks4
return null; return null;
} }
if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) request.ProxySettings = new HttpProxySettings(ProxyType.Socks4,
{ Settings.Host,
request.Proxy = new WebProxy(uri, false, null, new NetworkCredential(Settings.Username, Settings.Password)); Settings.Port,
} null,
else false,
{ Settings.Username,
request.Proxy = new WebProxy(uri); Settings.Password);
}
_logger.Debug("Applying Socks4 Proxy {0} to request {1}", Name, request.Url); _logger.Debug("Applying Socks4 Proxy {0} to request {1}", Name, request.Url);
@@ -4,6 +4,7 @@ using NLog;
using NzbDrone.Common.Cloud; using NzbDrone.Common.Cloud;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Http.Proxy;
using NzbDrone.Core.Localization; using NzbDrone.Core.Localization;
namespace NzbDrone.Core.IndexerProxies.Socks5 namespace NzbDrone.Core.IndexerProxies.Socks5
@@ -26,14 +27,13 @@ namespace NzbDrone.Core.IndexerProxies.Socks5
return null; return null;
} }
if (Settings.Username.IsNotNullOrWhiteSpace() && Settings.Password.IsNotNullOrWhiteSpace()) request.ProxySettings = new HttpProxySettings(ProxyType.Socks5,
{ Settings.Host,
request.Proxy = new WebProxy(uri, false, null, new NetworkCredential(Settings.Username, Settings.Password)); Settings.Port,
} null,
else false,
{ Settings.Username,
request.Proxy = new WebProxy(uri); Settings.Password);
}
_logger.Debug("Applying Socks5 Proxy {0} to request {1}", Name, request.Url); _logger.Debug("Applying Socks5 Proxy {0} to request {1}", Name, request.Url);
@@ -160,6 +160,18 @@ namespace NzbDrone.Core.IndexerSearch
.ToList(); .ToList();
} }
if (criteriaBase.Categories != null && criteriaBase.Categories.Length > 0)
{
//Only query supported indexers
indexers = indexers.Where(i => ((IndexerDefinition)i.Definition).Capabilities.Categories.SupportedCategories(criteriaBase.Categories).Any()).ToList();
if (indexers.Count == 0)
{
_logger.Debug("All provided categories are unsupported by selected indexers: {0}", string.Join(", ", criteriaBase.Categories));
return new List<ReleaseInfo>();
}
}
_logger.ProgressInfo("Searching indexer(s): [{0}] for {1}", string.Join(", ", indexers.Select(i => i.Definition.Name).ToList()), criteriaBase.ToString()); _logger.ProgressInfo("Searching indexer(s): [{0}] for {1}", string.Join(", ", indexers.Select(i => i.Definition.Name).ToList()), criteriaBase.ToString());
var tasks = indexers.Select(x => DispatchIndexer(searchAction, x, criteriaBase)); var tasks = indexers.Select(x => DispatchIndexer(searchAction, x, criteriaBase));
@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
@@ -18,18 +19,17 @@ namespace NzbDrone.Core.IndexerVersions
{ {
public interface IIndexerDefinitionUpdateService public interface IIndexerDefinitionUpdateService
{ {
List<IndexerMetaDefinition> All(); List<CardigannMetaDefinition> All();
List<IndexerMetaDefinition> AllForImplementation(string implementation);
CardigannDefinition GetCachedDefinition(string fileKey); CardigannDefinition GetCachedDefinition(string fileKey);
List<string> GetBlocklist(); List<string> GetBlocklist();
} }
public class IndexerDefinitionUpdateService : IIndexerDefinitionUpdateService, IExecute<IndexerDefinitionUpdateCommand>, IHandle<ApplicationStartedEvent> public class IndexerDefinitionUpdateService : IIndexerDefinitionUpdateService, IExecute<IndexerDefinitionUpdateCommand>, IHandle<ApplicationStartedEvent>
{ {
/* Update Service will fall back if version # does not exist for an indexer per Ta */ /* Update Service will fall back if version # does not exist for an indexer per Ta */
private const string DEFINITION_BRANCH = "newznab-xml-to-yml-scriptupdates"; private const string DEFINITION_BRANCH = "master";
private const int DEFINITION_VERSION = 8; private const int DEFINITION_VERSION = 7;
//Used when moving yml to C# //Used when moving yml to C#
private readonly List<string> _defintionBlocklist = new List<string>() private readonly List<string> _defintionBlocklist = new List<string>()
@@ -78,9 +78,9 @@ namespace NzbDrone.Core.IndexerVersions
_logger = logger; _logger = logger;
} }
public List<IndexerMetaDefinition> All() public List<CardigannMetaDefinition> All()
{ {
var indexerList = new List<IndexerMetaDefinition>(); var indexerList = new List<CardigannMetaDefinition>();
try try
{ {
@@ -88,7 +88,7 @@ namespace NzbDrone.Core.IndexerVersions
try try
{ {
var request = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}"); var request = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}");
var response = _httpClient.Get<List<IndexerMetaDefinition>>(request); var response = _httpClient.Get<List<CardigannMetaDefinition>>(request);
indexerList = response.Resource.Where(i => !_defintionBlocklist.Contains(i.File)).ToList(); indexerList = response.Resource.Where(i => !_defintionBlocklist.Contains(i.File)).ToList();
} }
catch catch
@@ -111,11 +111,6 @@ namespace NzbDrone.Core.IndexerVersions
return indexerList; return indexerList;
} }
public List<IndexerMetaDefinition> AllForImplementation(string implementation)
{
return All().Where(d => d.Implementation == implementation).ToList();
}
public CardigannDefinition GetCachedDefinition(string fileKey) public CardigannDefinition GetCachedDefinition(string fileKey)
{ {
if (string.IsNullOrEmpty(fileKey)) if (string.IsNullOrEmpty(fileKey))
@@ -133,7 +128,7 @@ namespace NzbDrone.Core.IndexerVersions
return _defintionBlocklist; return _defintionBlocklist;
} }
private List<IndexerMetaDefinition> ReadDefinitionsFromDisk(List<IndexerMetaDefinition> defs, string path, SearchOption options = SearchOption.TopDirectoryOnly) private List<CardigannMetaDefinition> ReadDefinitionsFromDisk(List<CardigannMetaDefinition> defs, string path, SearchOption options = SearchOption.TopDirectoryOnly)
{ {
var indexerList = defs; var indexerList = defs;
@@ -150,7 +145,7 @@ namespace NzbDrone.Core.IndexerVersions
try try
{ {
var definitionString = File.ReadAllText(file.FullName); var definitionString = File.ReadAllText(file.FullName);
var definition = _deserializer.Deserialize<IndexerMetaDefinition>(definitionString); var definition = _deserializer.Deserialize<CardigannMetaDefinition>(definitionString);
definition.File = Path.GetFileNameWithoutExtension(file.Name); definition.File = Path.GetFileNameWithoutExtension(file.Name);
@@ -248,11 +243,6 @@ namespace NzbDrone.Core.IndexerVersions
definition.Login.Method = "form"; definition.Login.Method = "form";
} }
if (definition.Search == null)
{
definition.Search = new SearchBlock();
}
if (definition.Search.Paths == null) if (definition.Search.Paths == null)
{ {
definition.Search.Paths = new List<SearchPathBlock>(); definition.Search.Paths = new List<SearchPathBlock>();
@@ -293,44 +283,29 @@ namespace NzbDrone.Core.IndexerVersions
{ {
var startupFolder = _appFolderInfo.AppDataFolder; var startupFolder = _appFolderInfo.AppDataFolder;
var request = new HttpRequest($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}");
var response = _httpClient.Get<List<IndexerMetaDefinition>>(request);
var currentDefs = _versionService.All().ToDictionary(x => x.DefinitionId, x => x.Sha);
try try
{ {
EnsureDefinitionsFolder(); EnsureDefinitionsFolder();
foreach (var def in response.Resource) var definitionsFolder = Path.Combine(startupFolder, "Definitions");
var saveFile = Path.Combine(definitionsFolder, $"indexers.zip");
_httpClient.DownloadFile($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}/package.zip", saveFile);
using (ZipArchive archive = ZipFile.OpenRead(saveFile))
{ {
try archive.ExtractToDirectory(definitionsFolder, true);
{
var saveFile = Path.Combine(startupFolder, "Definitions", $"{def.File}.yml");
if (currentDefs.TryGetValue(def.Id, out var defSha) && defSha == def.Sha)
{
_logger.Trace("Indexer already up to date: {0}", def.File);
continue;
}
_httpClient.DownloadFile($"https://indexers.prowlarr.com/{DEFINITION_BRANCH}/{DEFINITION_VERSION}/{def.File}", saveFile);
_versionService.Upsert(new IndexerDefinitionVersion { Sha = def.Sha, DefinitionId = def.Id, File = def.File, LastUpdated = DateTime.UtcNow });
_cache.Remove(def.File);
_logger.Debug("Updated definition: {0}", def.File);
}
catch (Exception ex)
{
_logger.Error("Definition download failed: {0}, {1}", def.File, ex.Message);
}
} }
_diskProvider.DeleteFile(saveFile);
_cache.Clear();
_logger.Debug("Updated indexer definitions");
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Definition download failed, error creating definitions folder in {0}", startupFolder); _logger.Error(ex, "Definition update failed");
} }
} }
} }
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions namespace NzbDrone.Core.Indexers.Definitions
@@ -10,9 +9,12 @@ namespace NzbDrone.Core.Indexers.Definitions
public class AlphaRatio : Gazelle.Gazelle public class AlphaRatio : Gazelle.Gazelle
{ {
public override string Name => "AlphaRatio"; public override string Name => "AlphaRatio";
public override string[] IndexerUrls => new string[] { "https://alpharatio.cc/" };
public override string Description => "AlphaRatio(AR) is a Private Torrent Tracker for 0DAY / GENERAL";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public AlphaRatio(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public AlphaRatio(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -26,6 +28,54 @@ namespace NzbDrone.Core.Indexers.Definitions
Capabilities = Capabilities Capabilities = Capabilities
}; };
} }
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TVSD, "TvSD");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVHD, "TvHD");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVUHD, "TvUHD");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.TVSD, "TvDVDRip");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVSD, "TvPackSD");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.TVHD, "TvPackHD");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TVUHD, "TvPackUHD");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.MoviesSD, "MovieSD");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.MoviesHD, "MovieHD");
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.MoviesUHD, "MovieUHD");
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.MoviesSD, "MoviePackSD");
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.MoviesHD, "MoviePackHD");
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.MoviesUHD, "MoviePackUHD");
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.XXX, "MovieXXX");
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.MoviesBluRay, "Bluray");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.TVAnime, "AnimeSD");
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.TVAnime, "AnimeHD");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.PCGames, "GamesPC");
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.ConsoleXBox, "GamesxBox");
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.ConsolePS4, "GamesPS");
caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.ConsoleWii, "GamesNin");
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.PC0day, "AppsWindows");
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.PCMac, "AppsMAC");
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.PC0day, "AppsLinux");
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.PCMobileOther, "AppsMobile");
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.XXX, "0dayXXX");
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.Books, "eBook");
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.AudioAudiobook, "AudioBook");
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.AudioOther, "Music");
caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.Other, "Misc");
return caps;
}
} }
public class AlphaRatioRequestGenerator : Gazelle.GazelleRequestGenerator public class AlphaRatioRequestGenerator : Gazelle.GazelleRequestGenerator
@@ -17,7 +17,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -28,15 +27,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class Anidub : TorrentIndexerBase<UserPassTorrentBaseSettings> public class Anidub : TorrentIndexerBase<UserPassTorrentBaseSettings>
{ {
public override string Name => "Anidub"; public override string Name => "Anidub";
public override string[] IndexerUrls => new string[] { "https://tr.anidub.com/" };
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;
public override IndexerCapabilities Capabilities => SetCapabilities();
public Anidub(IIndexerHttpClient httpClient, public Anidub(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
IEventAggregator eventAggregator, : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
IIndexerStatusService indexerStatusService,
IIndexerDefinitionUpdateService definitionService,
IConfigService configService,
Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger)
{ {
} }
@@ -99,6 +99,47 @@ namespace NzbDrone.Core.Indexers.Definitions
return true; return true;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVAnime, "Аниме TV");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Movies, "Аниме Фильмы");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.TVAnime, "Аниме OVA");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVAnime, "Аниме OVA |- Аниме ONA");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.TV, "Дорамы / Японские Сериалы и Фильмы");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TV, "Дорамы / Корейские Сериалы и Фильмы");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TV, "Дорамы / Китайские Сериалы и Фильмы");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TV, "Дорамы");
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TVAnime, "Аниме TV / Аниме Ongoing");
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.TVAnime, "Аниме TV / Многосерийный сёнэн");
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.Other, "Аниме Ongoing Анонсы");
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.XXX, "18+");
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.TVAnime, "Аниме TV / Законченные сериалы");
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.BooksComics, "Манга");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.Audio, "OST");
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.Audio, "Подкасты");
return caps;
}
} }
public class AnidubRequestGenerator : IIndexerRequestGenerator public class AnidubRequestGenerator : IIndexerRequestGenerator
@@ -17,7 +17,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -28,10 +27,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class AnimeBytes : TorrentIndexerBase<AnimeBytesSettings> public class AnimeBytes : TorrentIndexerBase<AnimeBytesSettings>
{ {
public override string Name => "AnimeBytes"; public override string Name => "AnimeBytes";
public override string[] IndexerUrls => new string[] { "https://animebytes.tv/" };
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public AnimeBytes(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public AnimeBytes(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -49,6 +54,48 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping("anime[tv_series]", NewznabStandardCategory.TVAnime, "TV Series");
caps.Categories.AddCategoryMapping("anime[tv_special]", NewznabStandardCategory.TVAnime, "TV Special");
caps.Categories.AddCategoryMapping("anime[ova]", NewznabStandardCategory.TVAnime, "OVA");
caps.Categories.AddCategoryMapping("anime[ona]", NewznabStandardCategory.TVAnime, "ONA");
caps.Categories.AddCategoryMapping("anime[dvd_special]", NewznabStandardCategory.TVAnime, "DVD Special");
caps.Categories.AddCategoryMapping("anime[bd_special]", NewznabStandardCategory.TVAnime, "BD Special");
caps.Categories.AddCategoryMapping("anime[movie]", NewznabStandardCategory.Movies, "Movie");
caps.Categories.AddCategoryMapping("audio", NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping("gamec[game]", NewznabStandardCategory.PCGames, "Game");
caps.Categories.AddCategoryMapping("gamec[visual_novel]", NewznabStandardCategory.PCGames, "Game Visual Novel");
caps.Categories.AddCategoryMapping("printedtype[manga]", NewznabStandardCategory.BooksComics, "Manga");
caps.Categories.AddCategoryMapping("printedtype[oneshot]", NewznabStandardCategory.BooksComics, "Oneshot");
caps.Categories.AddCategoryMapping("printedtype[anthology]", NewznabStandardCategory.BooksComics, "Anthology");
caps.Categories.AddCategoryMapping("printedtype[manhwa]", NewznabStandardCategory.BooksComics, "Manhwa");
caps.Categories.AddCategoryMapping("printedtype[light_novel]", NewznabStandardCategory.BooksComics, "Light Novel");
caps.Categories.AddCategoryMapping("printedtype[artbook]", NewznabStandardCategory.BooksComics, "Artbook");
return caps;
}
} }
public class AnimeBytesRequestGenerator : IIndexerRequestGenerator public class AnimeBytesRequestGenerator : IIndexerRequestGenerator
@@ -15,7 +15,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -26,11 +25,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class AnimeTorrents : TorrentIndexerBase<UserPassTorrentBaseSettings> public class AnimeTorrents : TorrentIndexerBase<UserPassTorrentBaseSettings>
{ {
public override string Name => "AnimeTorrents"; public override string Name => "AnimeTorrents";
public override string[] IndexerUrls => new string[] { "https://animetorrents.me/" };
public override string Description => "Definitive source for anime and manga";
private string LoginUrl => Settings.BaseUrl + "login.php"; private string LoginUrl => Settings.BaseUrl + "login.php";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public AnimeTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public AnimeTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -90,6 +94,43 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Anime Movie");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesHD, "Anime Movie HD");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVAnime, "Anime Series");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TVAnime, "Anime Series HD");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.XXXDVD, "Hentai (censored)");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.XXXDVD, "Hentai (censored) HD");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.XXXDVD, "Hentai (un-censored)");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.XXXDVD, "Hentai (un-censored) HD");
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.BooksForeign, "Light Novel");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.BooksComics, "Manga");
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.BooksComics, "Manga 18+");
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.TVAnime, "OVA");
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.TVAnime, "OVA HD");
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.BooksComics, "Doujin Anime");
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.XXXDVD, "Doujin Anime 18+");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.AudioForeign, "Doujin Music");
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.BooksComics, "Doujinshi");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.BooksComics, "Doujinshi 18+");
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.Audio, "OST");
return caps;
}
} }
public class AnimeTorrentsRequestGenerator : IIndexerRequestGenerator public class AnimeTorrentsRequestGenerator : IIndexerRequestGenerator
@@ -13,7 +13,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -24,10 +23,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class Animedia : TorrentIndexerBase<NoAuthTorrentBaseSettings> public class Animedia : TorrentIndexerBase<NoAuthTorrentBaseSettings>
{ {
public override string Name => "Animedia"; public override string Name => "Animedia";
public override string[] IndexerUrls => new string[] { "https://tt.animedia.tv/" };
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();
public Animedia(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public Animedia(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -40,6 +45,26 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
return new AnimediaParser(Settings, Capabilities.Categories) { HttpClient = _httpClient, Logger = _logger }; return new AnimediaParser(Settings, Capabilities.Categories) { HttpClient = _httpClient, Logger = _logger };
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TVAnime, "TV Anime");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVAnime, "OVA/ONA/Special");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TV, "Dorama");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.Movies, "Movies");
return caps;
}
} }
public class AnimediaRequestGenerator : IIndexerRequestGenerator public class AnimediaRequestGenerator : IIndexerRequestGenerator
@@ -13,21 +13,27 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions namespace NzbDrone.Core.Indexers.Definitions
{ {
[Obsolete("Moved to YML for Cardigann")]
public class Anthelion : TorrentIndexerBase<UserPassTorrentBaseSettings> public class Anthelion : TorrentIndexerBase<UserPassTorrentBaseSettings>
{ {
public override string Name => "Anthelion"; public override string Name => "Anthelion";
public override string[] IndexerUrls => new string[] { "https://anthelion.me/" };
private string LoginUrl => Settings.BaseUrl + "login.php"; private string LoginUrl => Settings.BaseUrl + "login.php";
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public Anthelion(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public Anthelion(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -96,6 +102,28 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
}
};
caps.Categories.AddCategoryMapping("1", NewznabStandardCategory.Movies, "Film/Feature");
caps.Categories.AddCategoryMapping("2", NewznabStandardCategory.Movies, "Film/Short");
caps.Categories.AddCategoryMapping("3", NewznabStandardCategory.TV, "TV/Miniseries");
caps.Categories.AddCategoryMapping("4", NewznabStandardCategory.Other, "Other");
return caps;
}
} }
public class AnthelionRequestGenerator : IIndexerRequestGenerator public class AnthelionRequestGenerator : IIndexerRequestGenerator
@@ -0,0 +1,60 @@
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Definitions.Avistaz;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions
{
public class AvistaZ : AvistazBase
{
public override string Name => "AvistaZ";
public override string[] IndexerUrls => new string[] { "https://avistaz.to/" };
public override string Description => "Aka AsiaTorrents";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public AvistaZ(IIndexerRepository indexerRepository, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(indexerRepository, httpClient, eventAggregator, indexerStatusService, configService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new AvistazRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
Logger = _logger,
Capabilities = Capabilities
};
}
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId, TvSearchParam.Genre
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.Genre
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesUHD);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesHD);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVUHD);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVHD);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD);
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio);
return caps;
}
}
}
@@ -6,31 +6,28 @@ using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions.Avistaz namespace NzbDrone.Core.Indexers.Definitions.Avistaz
{ {
public class Avistaz : TorrentIndexerBase<AvistazSettings> public abstract class AvistazBase : TorrentIndexerBase<AvistazSettings>
{ {
public override string Name => "Avistaz";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override string[] IndexerUrls => new string[] { "" };
protected virtual string LoginUrl => Settings.BaseUrl + "api/v1/jackett/auth"; protected virtual string LoginUrl => Settings.BaseUrl + "api/v1/jackett/auth";
public override string Description => "";
public override bool SupportsRss => true; public override bool SupportsRss => true;
public override bool SupportsSearch => true; public override bool SupportsSearch => true;
public override int PageSize => 50; public override int PageSize => 50;
public override IndexerCapabilities Capabilities => SetCapabilities();
private IIndexerRepository _indexerRepository; private IIndexerRepository _indexerRepository;
public Avistaz(IIndexerRepository indexerRepository, public AvistazBase(IIndexerRepository indexerRepository,
IIndexerHttpClient httpClient, IIndexerHttpClient httpClient,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
IIndexerStatusService indexerStatusService, IIndexerStatusService indexerStatusService,
IIndexerDefinitionUpdateService definitionService,
IConfigService configService, IConfigService configService,
Logger logger) Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
_indexerRepository = indexerRepository; _indexerRepository = indexerRepository;
} }
@@ -25,7 +25,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; } public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
// hook to adjust the search category // hook to adjust the search category
protected virtual List<KeyValuePair<string, string>> GetBasicSearchParameters(int[] categories) protected virtual List<KeyValuePair<string, string>> GetBasicSearchParameters(int[] categories, string genre)
{ {
var categoryMapping = Capabilities.Categories.MapTorznabCapsToTrackers(categories).Distinct().ToList(); var categoryMapping = Capabilities.Categories.MapTorznabCapsToTrackers(categories).Distinct().ToList();
var qc = new List<KeyValuePair<string, string>> // NameValueCollection don't support cat[]=19&cat[]=6 var qc = new List<KeyValuePair<string, string>> // NameValueCollection don't support cat[]=19&cat[]=6
@@ -34,6 +34,16 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
{ "type", categoryMapping.Any() ? categoryMapping.First() : "0" } { "type", categoryMapping.Any() ? categoryMapping.First() : "0" }
}; };
if (Settings.FreeleechOnly)
{
qc.Add("discount[]", "1");
}
if (genre.IsNotNullOrWhiteSpace())
{
qc.Add("tags", genre);
}
// resolution filter to improve the search // resolution filter to improve the search
if (!categories.Contains(NewznabStandardCategory.Movies.Id) && !categories.Contains(NewznabStandardCategory.TV.Id) && if (!categories.Contains(NewznabStandardCategory.Movies.Id) && !categories.Contains(NewznabStandardCategory.TV.Id) &&
!categories.Contains(NewznabStandardCategory.Audio.Id)) !categories.Contains(NewznabStandardCategory.Audio.Id))
@@ -71,7 +81,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{ {
var parameters = GetBasicSearchParameters(searchCriteria.Categories); var parameters = GetBasicSearchParameters(searchCriteria.Categories, searchCriteria.Genre);
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace()) if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
{ {
@@ -93,7 +103,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{ {
var parameters = GetBasicSearchParameters(searchCriteria.Categories); var parameters = GetBasicSearchParameters(searchCriteria.Categories, null);
parameters.Add("search", GetSearchTerm(searchCriteria.SanitizedSearchTerm).Trim()); parameters.Add("search", GetSearchTerm(searchCriteria.SanitizedSearchTerm).Trim());
@@ -104,7 +114,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{ {
var parameters = GetBasicSearchParameters(searchCriteria.Categories); var parameters = GetBasicSearchParameters(searchCriteria.Categories, searchCriteria.Genre);
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace()) if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
{ {
@@ -136,7 +146,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{ {
var parameters = GetBasicSearchParameters(searchCriteria.Categories); var parameters = GetBasicSearchParameters(searchCriteria.Categories, null);
parameters.Add("search", GetSearchTerm(searchCriteria.SanitizedSearchTerm).Trim()); parameters.Add("search", GetSearchTerm(searchCriteria.SanitizedSearchTerm).Trim());
@@ -22,6 +22,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public AvistazSettings() public AvistazSettings()
{ {
Token = ""; Token = "";
FreeleechOnly = false;
} }
public string Token { get; set; } public string Token { get; set; }
@@ -35,6 +36,9 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
[FieldDefinition(4, Label = "PID", HelpText = "PID from My Account or My Profile page")] [FieldDefinition(4, Label = "PID", HelpText = "PID from My Account or My Profile page")]
public string Pid { get; set; } public string Pid { get; set; }
[FieldDefinition(5, Label = "Freeleech Only", Type = FieldType.Checkbox, HelpText = "Search freeleech only")]
public bool FreeleechOnly { get; set; }
public override NzbDroneValidationResult Validate() public override NzbDroneValidationResult Validate()
{ {
return new NzbDroneValidationResult(Validator.Validate(this)); return new NzbDroneValidationResult(Validator.Validate(this));
+51 -3
View File
@@ -15,7 +15,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -28,10 +27,15 @@ namespace NzbDrone.Core.Indexers.Definitions
public override string Name => "BB"; public override string Name => "BB";
public override string[] IndexerUrls => new string[] { StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw==") }; public override string[] IndexerUrls => new string[] { StringUtil.FromBase64("aHR0cHM6Ly9iYWNvbmJpdHMub3JnLw==") };
private string LoginUrl => Settings.BaseUrl + "login.php"; private string LoginUrl => Settings.BaseUrl + "login.php";
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public BB(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public BB(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -108,6 +112,50 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Audio);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.AudioMP3);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.AudioLossless);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PC);
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.BooksEBook);
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.AudioAudiobook);
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Other);
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.BooksMags);
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.BooksComics);
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TVAnime);
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.Movies);
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TVHD);
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TVSD);
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TV);
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.PCGames);
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.Console);
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.Other);
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.Other);
return caps;
}
} }
public class BBRequestGenerator : IIndexerRequestGenerator public class BBRequestGenerator : IIndexerRequestGenerator
@@ -16,7 +16,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -28,11 +27,15 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
public override string Name => "BakaBT"; public override string Name => "BakaBT";
public override string[] IndexerUrls => new string[] { "https://bakabt.me/" };
public override string Description => "Anime Community";
private string LoginUrl => Settings.BaseUrl + "login.php"; private string LoginUrl => Settings.BaseUrl + "login.php";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public BakaBT(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public BakaBT(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -121,6 +124,41 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TVAnime, "Anime Series");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVAnime, "OVA");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.AudioOther, "Soundtrack");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.BooksComics, "Manga");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Movies, "Anime Movie");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.TVOther, "Live Action");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.BooksOther, "Artbook");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.AudioVideo, "Music Video");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.BooksEBook, "Light Novel");
return caps;
}
} }
public class BakaBTRequestGenerator : IIndexerRequestGenerator public class BakaBTRequestGenerator : IIndexerRequestGenerator
@@ -15,7 +15,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -26,10 +25,15 @@ namespace NzbDrone.Core.Indexers.Definitions
public class BeyondHD : TorrentIndexerBase<BeyondHDSettings> public class BeyondHD : TorrentIndexerBase<BeyondHDSettings>
{ {
public override string Name => "BeyondHD"; public override string Name => "BeyondHD";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public BeyondHD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public override string[] IndexerUrls => new string[] { "https://beyond-hd.me/" };
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) 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();
public BeyondHD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -42,6 +46,26 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
return new BeyondHDParser(Settings, Capabilities.Categories); return new BeyondHDParser(Settings, Capabilities.Categories);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV");
return caps;
}
} }
public class BeyondHDRequestGenerator : IIndexerRequestGenerator public class BeyondHDRequestGenerator : IIndexerRequestGenerator
@@ -12,7 +12,6 @@ using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -23,11 +22,17 @@ namespace NzbDrone.Core.Indexers.Definitions
public class BinSearch : UsenetIndexerBase<BinSearchSettings> public class BinSearch : UsenetIndexerBase<BinSearchSettings>
{ {
public override string Name => "BinSearch"; public override string Name => "BinSearch";
public override string[] IndexerUrls => new string[] { "https://binsearch.info/" };
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 DownloadProtocol Protocol => DownloadProtocol.Usenet;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override bool SupportsRss => false; public override bool SupportsRss => false;
public override IndexerCapabilities Capabilities => SetCapabilities();
public BinSearch(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) public BinSearch(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, nzbValidationService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, nzbValidationService, logger)
{ {
} }
@@ -40,6 +45,31 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
return new BinSearchParser(Capabilities.Categories, Settings); return new BinSearchParser(Capabilities.Categories, Settings);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
return caps;
}
} }
public class BinSearchRequestGenerator : IIndexerRequestGenerator public class BinSearchRequestGenerator : IIndexerRequestGenerator
@@ -14,7 +14,6 @@ using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -26,10 +25,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class BitHDTV : TorrentIndexerBase<CookieTorrentBaseSettings> public class BitHDTV : TorrentIndexerBase<CookieTorrentBaseSettings>
{ {
public override string Name => "BitHDTV"; public override string Name => "BitHDTV";
public override string[] IndexerUrls => new string[] { "https://www.bit-hdtv.com/" };
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public BitHDTV(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public BitHDTV(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -52,6 +57,35 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TVAnime, "Anime");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesBluRay, "Movies/Blu-ray");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.TVDocumentary, "Documentaries");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.AudioLossless, "HQ Audio");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Movies, "Movies");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.AudioVideo, "Music Videos");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.Other, "Other");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVSport, "Sports");
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TV, "TV");
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.TV, "TV/Seasonpack");
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.XXX, "XXX");
return caps;
}
} }
public class BitHDTVRequestGenerator : IIndexerRequestGenerator public class BitHDTVRequestGenerator : IIndexerRequestGenerator
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.BroadcastheNet namespace NzbDrone.Core.Indexers.BroadcastheNet
@@ -11,15 +10,22 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
public class BroadcastheNet : TorrentIndexerBase<BroadcastheNetSettings> public class BroadcastheNet : TorrentIndexerBase<BroadcastheNetSettings>
{ {
public override string Name => "BroadcasTheNet"; public override string Name => "BroadcasTheNet";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override bool SupportsRss => true; public override bool SupportsRss => true;
public override bool SupportsSearch => true; public override bool SupportsSearch => true;
public override int PageSize => 100; public override int PageSize => 100;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override TimeSpan RateLimit => TimeSpan.FromSeconds(5); public override TimeSpan RateLimit => TimeSpan.FromSeconds(5);
public BroadcastheNet(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public override string[] IndexerUrls => new string[] { "https://api.broadcasthe.net/" };
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) public override string[] LegacyUrls => new string[] { "http://api.broadcasthe.net/" };
public override string Description => "BroadcasTheNet (BTN) is an invite-only torrent tracker focused on TV shows";
public BroadcastheNet(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -44,5 +50,27 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
{ {
return new BroadcastheNetParser(Capabilities.Categories); return new BroadcastheNetParser(Capabilities.Categories);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
LimitsDefault = 100,
LimitsMax = 1000,
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.TvdbId, TvSearchParam.RId
}
};
caps.Categories.AddCategoryMapping("SD", NewznabStandardCategory.TVSD, "SD");
caps.Categories.AddCategoryMapping("720p", NewznabStandardCategory.TVHD, "720p");
caps.Categories.AddCategoryMapping("1080p", NewznabStandardCategory.TVHD, "1080p");
caps.Categories.AddCategoryMapping("1080i", NewznabStandardCategory.TVHD, "1080i");
caps.Categories.AddCategoryMapping("2160p", NewznabStandardCategory.TVHD, "2160p");
caps.Categories.AddCategoryMapping("Portable Device", NewznabStandardCategory.TVSD, "Portable Device");
return caps;
}
} }
} }
@@ -1,7 +1,6 @@
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions namespace NzbDrone.Core.Indexers.Definitions
@@ -9,10 +8,31 @@ namespace NzbDrone.Core.Indexers.Definitions
public class BrokenStones : Gazelle.Gazelle public class BrokenStones : Gazelle.Gazelle
{ {
public override string Name => "BrokenStones"; public override string Name => "BrokenStones";
public override string[] IndexerUrls => new string[] { "https://brokenstones.club/" };
public override string Description => "Broken Stones is a Private site for MacOS and iOS APPS / GAMES";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public BrokenStones(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public BrokenStones(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.PCMac, "MacOS Apps");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PCMac, "MacOS Games");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.PCMobileiOS, "iOS Apps");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.PCMobileiOS, "iOS Games");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Other, "Graphics");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.Audio, "Audio");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Other, "Tutorials");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.Other, "Other");
return caps;
}
} }
} }
@@ -1,7 +1,6 @@
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions namespace NzbDrone.Core.Indexers.Definitions
@@ -9,10 +8,30 @@ namespace NzbDrone.Core.Indexers.Definitions
public class CGPeers : Gazelle.Gazelle public class CGPeers : Gazelle.Gazelle
{ {
public override string Name => "CGPeers"; public override string Name => "CGPeers";
public override string[] IndexerUrls => new string[] { "https://cgpeers.to/" };
public override string Description => "CGPeers is a Private Torrent Tracker for GRAPHICS SOFTWARE / TUTORIALS / ETC";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public CGPeers(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public CGPeers(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.PCISO, "Full Applications");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PC0day, "Plugins");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Other, "Tutorials");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.Other, "Models");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Other, "Materials");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.OtherMisc, "Misc");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Other, "GameDev");
return caps;
}
} }
} }
@@ -19,10 +19,15 @@ namespace NzbDrone.Core.Indexers.Cardigann
{ {
public class Cardigann : TorrentIndexerBase<CardigannSettings> public class Cardigann : TorrentIndexerBase<CardigannSettings>
{ {
private readonly IIndexerDefinitionUpdateService _definitionService;
private readonly ICached<CardigannRequestGenerator> _generatorCache; private readonly ICached<CardigannRequestGenerator> _generatorCache;
public override string Name => "Cardigann"; public override string Name => "Cardigann";
public override string[] IndexerUrls => new string[] { "" };
public override string Description => "";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; 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 // Page size is different per indexer, setting to 1 ensures we don't break out of paging logic
// thinking its a partial page and insteaad all search_path requests are run for each indexer // thinking its a partial page and insteaad all search_path requests are run for each indexer
@@ -30,9 +35,9 @@ namespace NzbDrone.Core.Indexers.Cardigann
public override IIndexerRequestGenerator GetRequestGenerator() public override IIndexerRequestGenerator GetRequestGenerator()
{ {
var generator = _generatorCache.Get(((IndexerDefinition)Definition).DefinitionFile, () => var generator = _generatorCache.Get(Settings.DefinitionFile, () =>
new CardigannRequestGenerator(_configService, new CardigannRequestGenerator(_configService,
_definitionService.GetCachedDefinition(((IndexerDefinition)Definition).DefinitionFile), _definitionService.GetCachedDefinition(Settings.DefinitionFile),
_logger) _logger)
{ {
HttpClient = _httpClient, HttpClient = _httpClient,
@@ -52,7 +57,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
public override IParseIndexerResponse GetParser() public override IParseIndexerResponse GetParser()
{ {
return new CardigannParser(_configService, return new CardigannParser(_configService,
_definitionService.GetCachedDefinition(((IndexerDefinition)Definition).DefinitionFile), _definitionService.GetCachedDefinition(Settings.DefinitionFile),
_logger) _logger)
{ {
Settings = Settings Settings = Settings
@@ -69,6 +74,17 @@ namespace NzbDrone.Core.Indexers.Cardigann
return base.GetCookies(); return base.GetCookies();
} }
public override IEnumerable<ProviderDefinition> DefaultDefinitions
{
get
{
foreach (var def in _definitionService.All())
{
yield return GetDefinition(def);
}
}
}
public Cardigann(IIndexerDefinitionUpdateService definitionService, public Cardigann(IIndexerDefinitionUpdateService definitionService,
IIndexerHttpClient httpClient, IIndexerHttpClient httpClient,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
@@ -76,12 +92,13 @@ namespace NzbDrone.Core.Indexers.Cardigann
IConfigService configService, IConfigService configService,
ICacheManager cacheManager, ICacheManager cacheManager,
Logger logger) Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
_definitionService = definitionService;
_generatorCache = cacheManager.GetRollingCache<CardigannRequestGenerator>(GetType(), "CardigannGeneratorCache", TimeSpan.FromMinutes(5)); _generatorCache = cacheManager.GetRollingCache<CardigannRequestGenerator>(GetType(), "CardigannGeneratorCache", TimeSpan.FromMinutes(5));
} }
private IndexerDefinition GetDefinition(IndexerMetaDefinition definition) private IndexerDefinition GetDefinition(CardigannMetaDefinition definition)
{ {
var defaultSettings = new List<SettingsField> var defaultSettings = new List<SettingsField>
{ {
@@ -110,8 +127,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
Implementation = GetType().Name, Implementation = GetType().Name,
IndexerUrls = definition.Links.ToArray(), IndexerUrls = definition.Links.ToArray(),
LegacyUrls = definition.Legacylinks.ToArray(), LegacyUrls = definition.Legacylinks.ToArray(),
DefinitionFile = definition.File, Settings = new CardigannSettings { DefinitionFile = definition.File },
Settings = new CardigannSettings(),
Protocol = DownloadProtocol.Torrent, Protocol = DownloadProtocol.Torrent,
Privacy = definition.Type switch Privacy = definition.Type switch
{ {
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
protected readonly IndexerCapabilitiesCategories _categories = new IndexerCapabilitiesCategories(); protected readonly IndexerCapabilitiesCategories _categories = new IndexerCapabilitiesCategories();
protected readonly List<string> _defaultCategories = new List<string>(); protected readonly List<string> _defaultCategories = new List<string>();
protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "tmdbid", "rageid", "tvdbid", "tvmazeid", "traktid", "doubanid", "poster", "banner", "description" }; protected readonly string[] OptionalFields = new string[] { "imdb", "imdbid", "tmdbid", "rageid", "tvdbid", "tvmazeid", "traktid", "doubanid", "poster", "banner", "description", "genre" };
protected static readonly string[] _SupportedLogicFunctions = protected static readonly string[] _SupportedLogicFunctions =
{ {
@@ -37,7 +37,6 @@ namespace NzbDrone.Core.Indexers.Cardigann
public string Id { get; set; } public string Id { get; set; }
public List<SettingsField> Settings { get; set; } public List<SettingsField> Settings { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Implementation { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string Type { get; set; } public string Type { get; set; }
public string Language { get; set; } public string Language { get; set; }
@@ -1,18 +1,16 @@
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Core.Indexers.Cardigann;
namespace NzbDrone.Core.IndexerVersions namespace NzbDrone.Core.Indexers.Cardigann
{ {
public class IndexerMetaDefinition public class CardigannMetaDefinition
{ {
public IndexerMetaDefinition() public CardigannMetaDefinition()
{ {
Legacylinks = new List<string>(); Legacylinks = new List<string>();
} }
public string Id { get; set; } public string Id { get; set; }
public string File { get; set; } public string File { get; set; }
public string Implementation { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string Type { get; set; } public string Type { get; set; }
@@ -20,8 +18,8 @@ namespace NzbDrone.Core.IndexerVersions
public string Encoding { get; set; } public string Encoding { get; set; }
public List<string> Links { get; set; } public List<string> Links { get; set; }
public List<string> Legacylinks { get; set; } public List<string> Legacylinks { get; set; }
public string Sha { get; set; }
public List<SettingsField> Settings { get; set; } public List<SettingsField> Settings { get; set; }
public string Sha { get; set; }
public LoginBlock Login { get; set; } public LoginBlock Login { get; set; }
} }
} }
@@ -145,14 +145,14 @@ namespace NzbDrone.Core.Indexers.Cardigann
throw new CardigannException(string.Format("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value ?? "<null>", ex.Message)); throw new CardigannException(string.Format("Error while parsing field={0}, selector={1}, value={2}: {3}", field.Key, field.Value.Selector, value ?? "<null>", ex.Message));
} }
}
var filters = search.Rows.Filters; var filters = search.Rows.Filters;
var skipRelease = ParseRowFilters(filters, release, variables, row); var skipRelease = ParseRowFilters(filters, release, variables, row);
if (skipRelease) if (skipRelease)
{ {
continue; continue;
}
} }
releases.Add(release); releases.Add(release);
@@ -594,8 +594,9 @@ namespace NzbDrone.Core.Indexers.Cardigann
value = release.PosterUrl; value = release.PosterUrl;
break; break;
case "genre": case "genre":
release.Genres = release.Genres.Union(value.Split(',')).ToList(); char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']', '"', '|', ':' };
value = string.Join(",", release.Genres); release.Genres = release.Genres.Union(value.Split(delimiters, System.StringSplitOptions.RemoveEmptyEntries)).ToList();
value = string.Join(", ", release.Genres);
break; break;
case "year": case "year":
release.Year = ParseUtil.CoerceInt(value); release.Year = ParseUtil.CoerceInt(value);
@@ -653,6 +654,14 @@ namespace NzbDrone.Core.Indexers.Cardigann
// for debugging // for debugging
_logger.Debug(string.Format("CardigannIndexer ({0}): row strdump: {1}", _definition.Id, row.ToString())); _logger.Debug(string.Format("CardigannIndexer ({0}): row strdump: {1}", _definition.Id, row.ToString()));
break; break;
case "validate":
char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']', '"', '|', ':' };
var args = (string)filter.Args;
var argsList = args.ToLower().Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
var validList = argsList.ToList();
var validIntersect = validList.Intersect(row.ToString().ToLower().Split(delimiters, StringSplitOptions.RemoveEmptyEntries)).ToList();
row = string.Join(", ", validIntersect);
break;
default: default:
_logger.Error(string.Format("CardigannIndexer ({0}): Unsupported rows filter: {1}", _definition.Id, filter.Name)); _logger.Error(string.Format("CardigannIndexer ({0}): Unsupported rows filter: {1}", _definition.Id, filter.Name));
break; break;
@@ -152,6 +152,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
variables[".Query.Offset"] = searchCriteria.Offset?.ToString() ?? null; variables[".Query.Offset"] = searchCriteria.Offset?.ToString() ?? null;
variables[".Query.Extended"] = null; variables[".Query.Extended"] = null;
variables[".Query.APIKey"] = null; variables[".Query.APIKey"] = null;
variables[".Query.Genre"] = null;
//Movie //Movie
variables[".Query.Movie"] = null; variables[".Query.Movie"] = null;
@@ -168,6 +169,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
variables[".Query.TVRageID"] = null; variables[".Query.TVRageID"] = null;
variables[".Query.TVMazeID"] = null; variables[".Query.TVMazeID"] = null;
variables[".Query.TraktID"] = null; variables[".Query.TraktID"] = null;
variables[".Query.DoubanID"] = null;
variables[".Query.Episode"] = null; variables[".Query.Episode"] = null;
//Music //Music
@@ -179,6 +181,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
//Book //Book
variables[".Query.Author"] = null; variables[".Query.Author"] = null;
variables[".Query.Title"] = null; variables[".Query.Title"] = null;
variables[".Query.Publisher"] = null;
return variables; return variables;
} }
@@ -942,6 +945,11 @@ namespace NzbDrone.Core.Indexers.Cardigann
public bool CheckIfLoginIsNeeded(HttpResponse response) public bool CheckIfLoginIsNeeded(HttpResponse response)
{ {
if (_definition.Login == null || _definition.Login.Test == null)
{
return false;
}
if (response.HasHttpRedirect) if (response.HasHttpRedirect)
{ {
var domainHint = GetRedirectDomainHint(response); var domainHint = GetRedirectDomainHint(response);
@@ -949,17 +957,12 @@ namespace NzbDrone.Core.Indexers.Cardigann
{ {
var errormessage = "Got redirected to another domain. Try changing the indexer URL to " + domainHint + "."; var errormessage = "Got redirected to another domain. Try changing the indexer URL to " + domainHint + ".";
throw new CardigannException(errormessage); _logger.Warn(errormessage);
} }
return true; return true;
} }
if (_definition.Login == null || _definition.Login.Test == null)
{
return false;
}
if (response.HasHttpError) if (response.HasHttpError)
{ {
return true; return true;
@@ -1121,6 +1124,8 @@ namespace NzbDrone.Core.Indexers.Cardigann
var request = new CardigannRequest(requestbuilder.SetEncoding(_encoding).Build(), variables, searchPath); var request = new CardigannRequest(requestbuilder.SetEncoding(_encoding).Build(), variables, searchPath);
request.HttpRequest.AllowAutoRedirect = searchPath.Followredirect;
yield return request; yield return request;
} }
} }
@@ -22,6 +22,9 @@ namespace NzbDrone.Core.Indexers.Cardigann
ExtraFieldData = new Dictionary<string, object>(); ExtraFieldData = new Dictionary<string, object>();
} }
[FieldDefinition(0, Hidden = HiddenType.Hidden)]
public string DefinitionFile { get; set; }
public Dictionary<string, object> ExtraFieldData { get; set; } public Dictionary<string, object> ExtraFieldData { get; set; }
public override NzbDroneValidationResult Validate() public override NzbDroneValidationResult Validate()
@@ -0,0 +1,60 @@
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Definitions.Avistaz;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions
{
public class CinemaZ : AvistazBase
{
public override string Name => "CinemaZ";
public override string[] IndexerUrls => new string[] { "https://cinemaz.to/" };
public override string Description => "CinemaZ (EuTorrents) is a Private Torrent Tracker for FOREIGN NON-ASIAN MOVIES.";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public CinemaZ(IIndexerRepository indexerRepository, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(indexerRepository, httpClient, eventAggregator, indexerStatusService, configService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new AvistazRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
Logger = _logger,
Capabilities = Capabilities
};
}
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.Genre
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.Genre
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesUHD);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesHD);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVUHD);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVHD);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD);
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio);
return caps;
}
}
}
@@ -0,0 +1,71 @@
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Definitions.Avistaz;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions
{
public class ExoticaZ : AvistazBase
{
public override string Name => "ExoticaZ";
public override string[] IndexerUrls => new string[] { "https://exoticaz.to/" };
public override string Description => "ExoticaZ (YourExotic) is a Private Torrent Tracker for 3X";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public ExoticaZ(IIndexerRepository indexerRepository, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(indexerRepository, httpClient, eventAggregator, indexerStatusService, configService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new AvistazRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
Logger = _logger,
Capabilities = Capabilities,
};
}
public override IParseIndexerResponse GetParser()
{
return new ExoticaZParser(Capabilities.Categories);
}
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities();
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.XXXx264, "Video Clip");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.XXXPack, "Video Pack");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.XXXPack, "Siterip Pack");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.XXXPack, "Pornstar Pack");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.XXXDVD, "DVD");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.XXXx264, "BluRay");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.XXXImageSet, "Photo Pack");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.XXXImageSet, "Books & Magazines");
return caps;
}
}
public class ExoticaZParser : AvistazParser
{
private readonly IndexerCapabilitiesCategories _categories;
public ExoticaZParser(IndexerCapabilitiesCategories categories)
{
_categories = categories;
}
protected override List<IndexerCategory> ParseCategories(AvistazRelease row)
{
var cat = row.Category;
return cat.SelectMany(c => _categories.MapTrackerCatToNewznab(c.Key)).ToList();
}
}
}
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.FileList namespace NzbDrone.Core.Indexers.FileList
@@ -10,13 +9,17 @@ namespace NzbDrone.Core.Indexers.FileList
public class FileList : TorrentIndexerBase<FileListSettings> public class FileList : TorrentIndexerBase<FileListSettings>
{ {
public override string Name => "FileList.io"; public override string Name => "FileList.io";
public override string[] IndexerUrls => new string[] { "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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsRss => true; public override bool SupportsRss => true;
public override bool SupportsSearch => true; public override bool SupportsSearch => true;
public override bool SupportsRedirect => true; public override bool SupportsRedirect => true;
public override IndexerCapabilities Capabilities => SetCapabilities();
public FileList(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public FileList(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -29,5 +32,61 @@ namespace NzbDrone.Core.Indexers.FileList
{ {
return new FileListParser(Settings, Capabilities.Categories); return new FileListParser(Settings, Capabilities.Categories);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
},
Flags = new List<IndexerFlag>
{
IndexerFlag.FreeLeech
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Filme SD");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesDVD, "Filme DVD");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.MoviesForeign, "Filme DVD-RO");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.MoviesHD, "Filme HD");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.AudioLossless, "FLAC");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesUHD, "Filme 4K");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.XXX, "XXX");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.PC, "Programe");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.PCGames, "Jocuri PC");
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.Console, "Jocuri Console");
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.Audio, "Audio");
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.AudioVideo, "Videoclip");
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.TVSport, "Sport");
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.TV, "Desene");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.Books, "Docs");
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.PC, "Linux");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.Other, "Diverse");
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.MoviesForeign, "Filme HD-RO");
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.MoviesBluRay, "Filme Blu-Ray");
caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.TVHD, "Seriale HD");
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.PCMobileOther, "Mobile");
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.TVSD, "Seriale SD");
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVAnime, "Anime");
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.Movies3D, "Filme 3D");
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.MoviesBluRay, "Filme 4K Blu-Ray");
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.TVUHD, "Seriale 4K");
return caps;
}
} }
} }
@@ -4,7 +4,6 @@ using System.Threading.Tasks;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Gazelle namespace NzbDrone.Core.Indexers.Gazelle
@@ -17,14 +16,14 @@ namespace NzbDrone.Core.Indexers.Gazelle
public override bool SupportsRss => true; public override bool SupportsRss => true;
public override bool SupportsSearch => true; public override bool SupportsSearch => true;
public override int PageSize => 50; public override int PageSize => 50;
public override IndexerCapabilities Capabilities => SetCapabilities();
public Gazelle(IIndexerHttpClient httpClient, public Gazelle(IIndexerHttpClient httpClient,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
IIndexerStatusService indexerStatusService, IIndexerStatusService indexerStatusService,
IIndexerDefinitionUpdateService definitionService,
IConfigService configService, IConfigService configService,
Logger logger) Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -44,6 +43,13 @@ namespace NzbDrone.Core.Indexers.Gazelle
return new GazelleParser(Settings, Capabilities); return new GazelleParser(Settings, Capabilities);
} }
protected virtual IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities();
return caps;
}
protected override async Task DoLogin() protected override async Task DoLogin()
{ {
var requestBuilder = new HttpRequestBuilder(LoginUrl) var requestBuilder = new HttpRequestBuilder(LoginUrl)
@@ -74,6 +80,30 @@ namespace NzbDrone.Core.Indexers.Gazelle
_logger.Debug("Gazelle authentication succeeded."); _logger.Debug("Gazelle authentication succeeded.");
} }
public override async Task<byte[]> Download(Uri link)
{
var response = await base.Download(link);
if (response.Length >= 1
&& response[0] != 'd' // simple test for torrent vs HTML content
&& link.Query.Contains("usetoken=1"))
{
var html = Encoding.GetString(response);
if (html.Contains("You do not have any freeleech tokens left.")
|| html.Contains("You do not have enough freeleech tokens")
|| html.Contains("This torrent is too large.")
|| html.Contains("You cannot use tokens here"))
{
// download again with usetoken=0
var requestLinkNew = link.ToString().Replace("usetoken=1", "usetoken=0");
response = await base.Download(new Uri(requestLinkNew));
}
}
return response;
}
protected override bool CheckIfLoginNeeded(HttpResponse response) protected override bool CheckIfLoginNeeded(HttpResponse response)
{ {
if (response.HasHttpRedirect || (response.Content != null && response.Content.Contains("\"bad credentials\""))) if (response.HasHttpRedirect || (response.Content != null && response.Content.Contains("\"bad credentials\"")))
@@ -30,22 +30,19 @@ namespace NzbDrone.Core.Indexers.Gazelle
return pageableRequests; return pageableRequests;
} }
private IEnumerable<IndexerRequest> GetRequest(string searchParameters) protected IEnumerable<IndexerRequest> GetRequest(string searchParameters)
{ {
var filter = "";
if (searchParameters == null)
{
}
var request = var request =
new IndexerRequest( new IndexerRequest(
$"{APIUrl}?{searchParameters}{filter}", $"{APIUrl}?{searchParameters}",
HttpAccept.Json); HttpAccept.Json);
request.HttpRequest.AllowAutoRedirect = false;
yield return request; yield return request;
} }
private string GetBasicSearchParameters(string searchTerm, int[] categories) protected string GetBasicSearchParameters(string searchTerm, int[] categories)
{ {
var searchString = GetSearchTerm(searchTerm); var searchString = GetSearchTerm(searchTerm);
@@ -67,7 +64,7 @@ namespace NzbDrone.Core.Indexers.Gazelle
return parameters; return parameters;
} }
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) public virtual IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{ {
var parameters = GetBasicSearchParameters(searchCriteria.SearchTerm, searchCriteria.Categories); var parameters = GetBasicSearchParameters(searchCriteria.SearchTerm, searchCriteria.Categories);
@@ -15,7 +15,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -25,10 +24,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class GazelleGames : TorrentIndexerBase<GazelleGamesSettings> public class GazelleGames : TorrentIndexerBase<GazelleGamesSettings>
{ {
public override string Name => "GazelleGames"; public override string Name => "GazelleGames";
public override string[] IndexerUrls => new string[] { "https://gazellegames.net/" };
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public GazelleGames(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public GazelleGames(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -42,6 +47,145 @@ namespace NzbDrone.Core.Indexers.Definitions
return new GazelleGamesParser(Settings, Capabilities.Categories); return new GazelleGamesParser(Settings, Capabilities.Categories);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
};
// Apple
caps.Categories.AddCategoryMapping("Mac", NewznabStandardCategory.ConsoleOther, "Mac");
caps.Categories.AddCategoryMapping("iOS", NewznabStandardCategory.PCMobileiOS, "iOS");
caps.Categories.AddCategoryMapping("Apple Bandai Pippin", NewznabStandardCategory.ConsoleOther, "Apple Bandai Pippin");
// Google
caps.Categories.AddCategoryMapping("Android", NewznabStandardCategory.PCMobileAndroid, "Android");
// Microsoft
caps.Categories.AddCategoryMapping("DOS", NewznabStandardCategory.PCGames, "DOS");
caps.Categories.AddCategoryMapping("Windows", NewznabStandardCategory.PCGames, "Windows");
caps.Categories.AddCategoryMapping("Xbox", NewznabStandardCategory.ConsoleXBox, "Xbox");
caps.Categories.AddCategoryMapping("Xbox 360", NewznabStandardCategory.ConsoleXBox360, "Xbox 360");
// Nintendo
caps.Categories.AddCategoryMapping("Game Boy", NewznabStandardCategory.ConsoleOther, "Game Boy");
caps.Categories.AddCategoryMapping("Game Boy Advance", NewznabStandardCategory.ConsoleOther, "Game Boy Advance");
caps.Categories.AddCategoryMapping("Game Boy Color", NewznabStandardCategory.ConsoleOther, "Game Boy Color");
caps.Categories.AddCategoryMapping("NES", NewznabStandardCategory.ConsoleOther, "NES");
caps.Categories.AddCategoryMapping("Nintendo 64", NewznabStandardCategory.ConsoleOther, "Nintendo 64");
caps.Categories.AddCategoryMapping("Nintendo 3DS", NewznabStandardCategory.ConsoleOther, "Nintendo 3DS");
caps.Categories.AddCategoryMapping("New Nintendo 3DS", NewznabStandardCategory.ConsoleOther, "New Nintendo 3DS");
caps.Categories.AddCategoryMapping("Nintendo DS", NewznabStandardCategory.ConsoleNDS, "Nintendo DS");
caps.Categories.AddCategoryMapping("Nintendo GameCube", NewznabStandardCategory.ConsoleOther, "Nintendo GameCube");
caps.Categories.AddCategoryMapping("Pokemon Mini", NewznabStandardCategory.ConsoleOther, "Pokemon Mini");
caps.Categories.AddCategoryMapping("SNES", NewznabStandardCategory.ConsoleOther, "SNES");
caps.Categories.AddCategoryMapping("Virtual Boy", NewznabStandardCategory.ConsoleOther, "Virtual Boy");
caps.Categories.AddCategoryMapping("Wii", NewznabStandardCategory.ConsoleWii, "Wii");
caps.Categories.AddCategoryMapping("Wii U", NewznabStandardCategory.ConsoleWiiU, "Wii U");
// Sony
caps.Categories.AddCategoryMapping("PlayStation 1", NewznabStandardCategory.ConsoleOther, "PlayStation 1");
caps.Categories.AddCategoryMapping("PlayStation 2", NewznabStandardCategory.ConsoleOther, "PlayStation 2");
caps.Categories.AddCategoryMapping("PlayStation 3", NewznabStandardCategory.ConsolePS3, "PlayStation 3");
caps.Categories.AddCategoryMapping("PlayStation 4", NewznabStandardCategory.ConsolePS4, "PlayStation 4");
caps.Categories.AddCategoryMapping("PlayStation Portable", NewznabStandardCategory.ConsolePSP, "PlayStation Portable");
caps.Categories.AddCategoryMapping("PlayStation Vita", NewznabStandardCategory.ConsolePSVita, "PlayStation Vita");
// Sega
caps.Categories.AddCategoryMapping("Dreamcast", NewznabStandardCategory.ConsoleOther, "Dreamcast");
caps.Categories.AddCategoryMapping("Game Gear", NewznabStandardCategory.ConsoleOther, "Game Gear");
caps.Categories.AddCategoryMapping("Master System", NewznabStandardCategory.ConsoleOther, "Master System");
caps.Categories.AddCategoryMapping("Mega Drive", NewznabStandardCategory.ConsoleOther, "Mega Drive");
caps.Categories.AddCategoryMapping("Pico", NewznabStandardCategory.ConsoleOther, "Pico");
caps.Categories.AddCategoryMapping("Saturn", NewznabStandardCategory.ConsoleOther, "Saturn");
caps.Categories.AddCategoryMapping("SG-1000", NewznabStandardCategory.ConsoleOther, "SG-1000");
// Atari
caps.Categories.AddCategoryMapping("Atari 2600", NewznabStandardCategory.ConsoleOther, "Atari 2600");
caps.Categories.AddCategoryMapping("Atari 5200", NewznabStandardCategory.ConsoleOther, "Atari 5200");
caps.Categories.AddCategoryMapping("Atari 7800", NewznabStandardCategory.ConsoleOther, "Atari 7800");
caps.Categories.AddCategoryMapping("Atari Jaguar", NewznabStandardCategory.ConsoleOther, "Atari Jaguar");
caps.Categories.AddCategoryMapping("Atari Lynx", NewznabStandardCategory.ConsoleOther, "Atari Lynx");
caps.Categories.AddCategoryMapping("Atari ST", NewznabStandardCategory.ConsoleOther, "Atari ST");
// Amstrad
caps.Categories.AddCategoryMapping("Amstrad CPC", NewznabStandardCategory.ConsoleOther, "Amstrad CPC");
// Sinclair
caps.Categories.AddCategoryMapping("ZX Spectrum", NewznabStandardCategory.ConsoleOther, "ZX Spectrum");
// Spectravideo
caps.Categories.AddCategoryMapping("MSX", NewznabStandardCategory.ConsoleOther, "MSX");
caps.Categories.AddCategoryMapping("MSX 2", NewznabStandardCategory.ConsoleOther, "MSX 2");
// Tiger
caps.Categories.AddCategoryMapping("Game.com", NewznabStandardCategory.ConsoleOther, "Game.com");
caps.Categories.AddCategoryMapping("Gizmondo", NewznabStandardCategory.ConsoleOther, "Gizmondo");
// VTech
caps.Categories.AddCategoryMapping("V.Smile", NewznabStandardCategory.ConsoleOther, "V.Smile");
caps.Categories.AddCategoryMapping("CreatiVision", NewznabStandardCategory.ConsoleOther, "CreatiVision");
// Tabletop Games
caps.Categories.AddCategoryMapping("Board Game", NewznabStandardCategory.ConsoleOther, "Board Game");
caps.Categories.AddCategoryMapping("Card Game", NewznabStandardCategory.ConsoleOther, "Card Game");
caps.Categories.AddCategoryMapping("Miniature Wargames", NewznabStandardCategory.ConsoleOther, "Miniature Wargames");
caps.Categories.AddCategoryMapping("Pen and Paper RPG", NewznabStandardCategory.ConsoleOther, "Pen and Paper RPG");
// Other
caps.Categories.AddCategoryMapping("3DO", NewznabStandardCategory.ConsoleOther, "3DO");
caps.Categories.AddCategoryMapping("Bandai WonderSwan", NewznabStandardCategory.ConsoleOther, "Bandai WonderSwan");
caps.Categories.AddCategoryMapping("Bandai WonderSwan Color", NewznabStandardCategory.ConsoleOther, "Bandai WonderSwan Color");
caps.Categories.AddCategoryMapping("Casio Loopy", NewznabStandardCategory.ConsoleOther, "Casio Loopy");
caps.Categories.AddCategoryMapping("Casio PV-1000", NewznabStandardCategory.ConsoleOther, "Casio PV-1000");
caps.Categories.AddCategoryMapping("Colecovision", NewznabStandardCategory.ConsoleOther, "Colecovision");
caps.Categories.AddCategoryMapping("Commodore 64", NewznabStandardCategory.ConsoleOther, "Commodore 64");
caps.Categories.AddCategoryMapping("Commodore 128", NewznabStandardCategory.ConsoleOther, "Commodore 128");
caps.Categories.AddCategoryMapping("Commodore Amiga", NewznabStandardCategory.ConsoleOther, "Commodore Amiga");
caps.Categories.AddCategoryMapping("Commodore Plus-4", NewznabStandardCategory.ConsoleOther, "Commodore Plus-4");
caps.Categories.AddCategoryMapping("Commodore VIC-20", NewznabStandardCategory.ConsoleOther, "Commodore VIC-20");
caps.Categories.AddCategoryMapping("Emerson Arcadia 2001", NewznabStandardCategory.ConsoleOther, "Emerson Arcadia 2001");
caps.Categories.AddCategoryMapping("Entex Adventure Vision", NewznabStandardCategory.ConsoleOther, "Entex Adventure Vision");
caps.Categories.AddCategoryMapping("Epoch Super Casette Vision", NewznabStandardCategory.ConsoleOther, "Epoch Super Casette Vision");
caps.Categories.AddCategoryMapping("Fairchild Channel F", NewznabStandardCategory.ConsoleOther, "Fairchild Channel F");
caps.Categories.AddCategoryMapping("Funtech Super Acan", NewznabStandardCategory.ConsoleOther, "Funtech Super Acan");
caps.Categories.AddCategoryMapping("GamePark GP32", NewznabStandardCategory.ConsoleOther, "GamePark GP32");
caps.Categories.AddCategoryMapping("General Computer Vectrex", NewznabStandardCategory.ConsoleOther, "General Computer Vectrex");
caps.Categories.AddCategoryMapping("Interactive DVD", NewznabStandardCategory.ConsoleOther, "Interactive DVD");
caps.Categories.AddCategoryMapping("Linux", NewznabStandardCategory.ConsoleOther, "Linux");
caps.Categories.AddCategoryMapping("Hartung Game Master", NewznabStandardCategory.ConsoleOther, "Hartung Game Master");
caps.Categories.AddCategoryMapping("Magnavox-Phillips Odyssey", NewznabStandardCategory.ConsoleOther, "Magnavox-Phillips Odyssey");
caps.Categories.AddCategoryMapping("Mattel Intellivision", NewznabStandardCategory.ConsoleOther, "Mattel Intellivision");
caps.Categories.AddCategoryMapping("Memotech MTX", NewznabStandardCategory.ConsoleOther, "Memotech MTX");
caps.Categories.AddCategoryMapping("Miles Gordon Sam Coupe", NewznabStandardCategory.ConsoleOther, "Miles Gordon Sam Coupe");
caps.Categories.AddCategoryMapping("NEC PC-98", NewznabStandardCategory.ConsoleOther, "NEC PC-98");
caps.Categories.AddCategoryMapping("NEC PC-FX", NewznabStandardCategory.ConsoleOther, "NEC PC-FX");
caps.Categories.AddCategoryMapping("NEC SuperGrafx", NewznabStandardCategory.ConsoleOther, "NEC SuperGrafx");
caps.Categories.AddCategoryMapping("NEC TurboGrafx-16", NewznabStandardCategory.ConsoleOther, "NEC TurboGrafx-16");
caps.Categories.AddCategoryMapping("Nokia N-Gage", NewznabStandardCategory.ConsoleOther, "Nokia N-Gage");
caps.Categories.AddCategoryMapping("Ouya", NewznabStandardCategory.ConsoleOther, "Ouya");
caps.Categories.AddCategoryMapping("Philips Videopac+", NewznabStandardCategory.ConsoleOther, "Philips Videopac+");
caps.Categories.AddCategoryMapping("Phone/PDA", NewznabStandardCategory.ConsoleOther, "Phone/PDA");
caps.Categories.AddCategoryMapping("RCA Studio II", NewznabStandardCategory.ConsoleOther, "RCA Studio II");
caps.Categories.AddCategoryMapping("Sharp X1", NewznabStandardCategory.ConsoleOther, "Sharp X1");
caps.Categories.AddCategoryMapping("Sharp X68000", NewznabStandardCategory.ConsoleOther, "Sharp X68000");
caps.Categories.AddCategoryMapping("SNK Neo Geo", NewznabStandardCategory.ConsoleOther, "SNK Neo Geo");
caps.Categories.AddCategoryMapping("SNK Neo Geo Pocket", NewznabStandardCategory.ConsoleOther, "SNK Neo Geo Pocket");
caps.Categories.AddCategoryMapping("Taito Type X", NewznabStandardCategory.ConsoleOther, "Taito Type X");
caps.Categories.AddCategoryMapping("Tandy Color Computer", NewznabStandardCategory.ConsoleOther, "Tandy Color Computer");
caps.Categories.AddCategoryMapping("Tangerine Oric", NewznabStandardCategory.ConsoleOther, "Tangerine Oric");
caps.Categories.AddCategoryMapping("Thomson MO5", NewznabStandardCategory.ConsoleOther, "Thomson MO5");
caps.Categories.AddCategoryMapping("Watara Supervision", NewznabStandardCategory.ConsoleOther, "Watara Supervision");
caps.Categories.AddCategoryMapping("Retro - Other", NewznabStandardCategory.ConsoleOther, "Retro - Other");
// special categories (real categories/not platforms)
caps.Categories.AddCategoryMapping("OST", NewznabStandardCategory.AudioOther, "OST");
caps.Categories.AddCategoryMapping("Applications", NewznabStandardCategory.PC0day, "Applications");
caps.Categories.AddCategoryMapping("E-Books", NewznabStandardCategory.BooksEBook, "E-Books");
return caps;
}
protected override async Task Test(List<ValidationFailure> failures) protected override async Task Test(List<ValidationFailure> failures)
{ {
((GazelleGamesRequestGenerator)GetRequestGenerator()).FetchPasskey(); ((GazelleGamesRequestGenerator)GetRequestGenerator()).FetchPasskey();
@@ -197,7 +341,18 @@ namespace NzbDrone.Core.Indexers.Definitions
return torrentInfos; return torrentInfos;
} }
foreach (var result in jsonResponse.Resource.Response) Dictionary<string, GazelleGamesGroup> response;
try
{
response = ((JObject)jsonResponse.Resource.Response).ToObject<Dictionary<string, GazelleGamesGroup>>();
}
catch
{
return torrentInfos;
}
foreach (var result in response)
{ {
Dictionary<string, GazelleGamesTorrent> torrents; Dictionary<string, GazelleGamesTorrent> torrents;
@@ -311,7 +466,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public class GazelleGamesResponse public class GazelleGamesResponse
{ {
public string Status { get; set; } public string Status { get; set; }
public Dictionary<string, GazelleGamesGroup> Response { get; set; } public object Response { get; set; }
} }
public class GazelleGamesGroup public class GazelleGamesGroup
@@ -0,0 +1,369 @@
using System;
using System.Collections.Generic;
using System.Net;
using Newtonsoft.Json;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Gazelle;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions;
public class GreatPosterWall : Gazelle.Gazelle
{
public override string Name => "GreatPosterWall";
public override string[] IndexerUrls => new string[] { "https://greatposterwall.com/" };
public override string Description => "GreatPosterWall (GPW) is a CHINESE Private site for MOVIES";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public GreatPosterWall(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new GreatPosterWallRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
Logger = _logger,
Capabilities = Capabilities
};
}
public override IParseIndexerResponse GetParser()
{
return new GreatPosterWallParser(Settings, Capabilities);
}
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies 电影");
return caps;
}
}
public class GreatPosterWallRequestGenerator : GazelleRequestGenerator
{
protected override bool ImdbInTags => false;
public override IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var parameters = GetBasicSearchParameters(searchCriteria.SearchTerm, searchCriteria.Categories);
if (searchCriteria.ImdbId != null)
{
parameters += string.Format("&searchstr={0}", searchCriteria.FullImdbId);
}
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetRequest(parameters));
return pageableRequests;
}
}
public class GreatPosterWallParser : GazelleParser
{
public GreatPosterWallParser(GazelleSettings settings, IndexerCapabilities capabilities)
: base(settings, capabilities)
{
}
public override IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
var torrentInfos = new List<ReleaseInfo>();
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
// Remove cookie cache
CookiesUpdater(null, null);
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
}
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
{
// Remove cookie cache
CookiesUpdater(null, null);
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
}
var jsonResponse = new HttpResponse<GreatPosterWallResponse>(indexerResponse.HttpResponse);
if (jsonResponse.Resource.Status != "success" ||
jsonResponse.Resource.Status.IsNullOrWhiteSpace() ||
jsonResponse.Resource.Response == null)
{
return torrentInfos;
}
foreach (var result in jsonResponse.Resource.Response.Results)
{
foreach (var torrent in result.Torrents)
{
var infoUrl = GetInfoUrl(result.GroupId.ToString(), torrent.TorrentId);
var time = DateTime.SpecifyKind(torrent.Time, DateTimeKind.Unspecified);
var release = new GazelleInfo
{
MinimumRatio = 1,
MinimumSeedTime = 172800,
Title = torrent.FileName,
InfoUrl = infoUrl,
Guid = infoUrl,
PosterUrl = GetPosterUrl(result.Cover),
DownloadUrl = GetDownloadUrl(torrent.TorrentId, torrent.CanUseToken),
PublishDate = new DateTimeOffset(time, TimeSpan.FromHours(8)).LocalDateTime, // Time is Chinese Time, add 8 hours difference from UTC and then convert back to local time
Categories = new List<IndexerCategory> { NewznabStandardCategory.Movies },
Size = torrent.Size,
Seeders = torrent.Seeders,
Peers = torrent.Seeders + torrent.Leechers,
Grabs = torrent.Snatches,
Files = torrent.FileCount,
Scene = torrent.Scene,
DownloadVolumeFactor = torrent.IsFreeleech || torrent.IsNeutralLeech || torrent.IsPersonalFreeleech ? 0 : 1,
UploadVolumeFactor = torrent.IsNeutralLeech ? 0 : 1
};
var imdbId = ParseUtil.GetImdbID(result.ImdbId);
if (imdbId != null)
{
release.ImdbId = (int)imdbId;
}
switch (torrent.FreeType)
{
case "11":
release.DownloadVolumeFactor = 0.75;
break;
case "12":
release.DownloadVolumeFactor = 0.5;
break;
case "13":
release.DownloadVolumeFactor = 0.25;
break;
case "1":
release.DownloadVolumeFactor = 0;
break;
case "2":
release.DownloadVolumeFactor = 0;
release.UploadVolumeFactor = 0;
break;
}
torrentInfos.Add(release);
}
}
return torrentInfos;
}
protected string GetDownloadUrl(int torrentId, bool canUseToken)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/torrents.php")
.AddQueryParam("action", "download")
.AddQueryParam("usetoken", _settings.UseFreeleechToken && canUseToken ? "1" : "0")
.AddQueryParam("id", torrentId);
return url.FullUri;
}
}
public class GreatPosterWallResponse
{
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("response")]
public Response Response { get; set; }
}
public class Response
{
[JsonProperty("currentPage")]
public int CurrentPage { get; set; }
[JsonProperty("pages")]
public int Pages { get; set; }
[JsonProperty("results")]
public List<Result> Results { get; set; }
}
public class Result
{
[JsonProperty("groupId")]
public int GroupId { get; set; }
[JsonProperty("groupName")]
public string GroupName { get; set; }
[JsonProperty("groupSubName")]
public string GroupSubName { get; set; }
[JsonProperty("cover")]
public string Cover { get; set; }
[JsonProperty("tags")]
public List<string> Tags { get; set; }
[JsonProperty("bookmarked")]
public bool Bookmarked { get; set; }
[JsonProperty("groupYear")]
public int GroupYear { get; set; }
[JsonProperty("releaseType")]
public string ReleaseType { get; set; }
[JsonProperty("groupTime")]
public string GroupTime { get; set; }
[JsonProperty("maxSize")]
public object MaxSize { get; set; }
[JsonProperty("totalSnatched")]
public int TotalSnatched { get; set; }
[JsonProperty("totalSeeders")]
public int TotalSeeders { get; set; }
[JsonProperty("totalLeechers")]
public int TotalLeechers { get; set; }
[JsonProperty("imdbId")]
public string ImdbId { get; set; }
[JsonProperty("imdbRating")]
public string ImdbRating { get; set; }
[JsonProperty("imdbVote")]
public string ImdbVote { get; set; }
[JsonProperty("doubanId")]
public string DoubanId { get; set; }
[JsonProperty("doubanRating")]
public string DoubanRating { get; set; }
[JsonProperty("doubanVote")]
public string DoubanVote { get; set; }
[JsonProperty("rtRating")]
public string RtRating { get; set; }
[JsonProperty("region")]
public string Region { get; set; }
[JsonProperty("torrents")]
public List<GreatPosterWallTorrent> Torrents { get; set; }
}
public class GreatPosterWallTorrent
{
[JsonProperty("torrentId")]
public int TorrentId { get; set; }
[JsonProperty("editionId")]
public int EditionId { get; set; }
[JsonProperty("remasterYear")]
public int RemasterYear { get; set; }
[JsonProperty("remasterTitle")]
public string RemasterTitle { get; set; }
[JsonProperty("remasterCustomTitle")]
public string RemasterCustomTitle { get; set; }
[JsonProperty("scene")]
public bool Scene { get; set; }
[JsonProperty("jinzhuan")]
public bool Jinzhuan { get; set; }
[JsonProperty("fileCount")]
public int FileCount { get; set; }
[JsonProperty("time")]
public DateTime Time { get; set; }
[JsonProperty("size")]
public long Size { get; set; }
[JsonProperty("snatches")]
public int Snatches { get; set; }
[JsonProperty("seeders")]
public int Seeders { get; set; }
[JsonProperty("leechers")]
public int Leechers { get; set; }
[JsonProperty("isFreeleech")]
public bool IsFreeleech { get; set; }
[JsonProperty("isNeutralLeech")]
public bool IsNeutralLeech { get; set; }
[JsonProperty("freeType")]
public string FreeType { get; set; }
[JsonProperty("isPersonalFreeleech")]
public bool IsPersonalFreeleech { get; set; }
[JsonProperty("canUseToken")]
public bool CanUseToken { get; set; }
[JsonProperty("hasSnatched")]
public bool HasSnatched { get; set; }
[JsonProperty("resolution")]
public string Resolution { get; set; }
[JsonProperty("source")]
public string Source { get; set; }
[JsonProperty("codec")]
public string Codec { get; set; }
[JsonProperty("container")]
public string Container { get; set; }
[JsonProperty("processing")]
public string Processing { get; set; }
[JsonProperty("chineseDubbed")]
public string ChineseDubbed { get; set; }
[JsonProperty("specialSub")]
public string SpecialSub { get; set; }
[JsonProperty("subtitles")]
public string Subtitles { get; set; }
[JsonProperty("fileName")]
public string FileName { get; set; }
[JsonProperty("releaseGroup")]
public string ReleaseGroup { get; set; }
}
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.HDBits namespace NzbDrone.Core.Indexers.HDBits
@@ -10,13 +9,17 @@ namespace NzbDrone.Core.Indexers.HDBits
public class HDBits : TorrentIndexerBase<HDBitsSettings> public class HDBits : TorrentIndexerBase<HDBitsSettings>
{ {
public override string Name => "HDBits"; public override string Name => "HDBits";
public override string[] IndexerUrls => new string[] { "https://hdbits.org" };
public override string Description => "Best HD Tracker";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override bool SupportsRedirect => true; public override bool SupportsRedirect => true;
public override int PageSize => 30; public override int PageSize => 30;
public HDBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public HDBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -29,5 +32,31 @@ namespace NzbDrone.Core.Indexers.HDBits
{ {
return new HDBitsParser(Settings, Capabilities.Categories); return new HDBitsParser(Settings, Capabilities.Categories);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.TvdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
}
};
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.Audio, "Audio Track");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVDocumentary, "Documentary");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.Other, "Misc/Demo");
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movie");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVSport, "Sport");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.XXX, "XXX");
return caps;
}
} }
} }
@@ -15,7 +15,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -26,11 +25,17 @@ namespace NzbDrone.Core.Indexers.Definitions
public class HDSpace : TorrentIndexerBase<UserPassTorrentBaseSettings> public class HDSpace : TorrentIndexerBase<UserPassTorrentBaseSettings>
{ {
public override string Name => "HD-Space"; public override string Name => "HD-Space";
public override string[] IndexerUrls => new string[] { "https://hd-space.org/" };
private string LoginUrl => Settings.BaseUrl + "index.php?page=login"; private string LoginUrl => Settings.BaseUrl + "index.php?page=login";
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public HDSpace(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public HDSpace(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -97,6 +102,52 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.MoviesBluRay, "Movie / Blu-ray");
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.MoviesHD, "Movie / 1080p");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.MoviesHD, "Movie / 720p");
caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.MoviesUHD, "Movie / 2160p");
caps.Categories.AddCategoryMapping(40, NewznabStandardCategory.MoviesHD, "Movie / Remux");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.MoviesHD, "Movie / HD-DVD");
caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.MoviesUHD, "Movie / 4K UHD");
caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.TVHD, "TV Show / 720p HDTV");
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.TVHD, "TV Show / 1080p HDTV");
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.TVUHD, "TV Show / 2160p HDTV");
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVDocumentary, "Documentary / 720p");
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.TVDocumentary, "Documentary / 1080p");
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.TVDocumentary, "Documentary / 2160p");
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.TVAnime, "Animation / 720p");
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.TVAnime, "Animation / 1080p");
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.TVAnime, "Animation / 2160p");
caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.AudioLossless, "Music / HQ Audio");
caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.AudioVideo, "Music / Videos");
caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.XXX, "XXX / 720p");
caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.XXX, "XXX / 1080p");
caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.XXX, "XXX / 2160p");
caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.MoviesOther, "Trailers");
caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.PC, "Software");
caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.Other, "Others");
return caps;
}
} }
public class HDSpaceRequestGenerator : IIndexerRequestGenerator public class HDSpaceRequestGenerator : IIndexerRequestGenerator
@@ -14,7 +14,6 @@ using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -25,11 +24,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class HDTorrents : TorrentIndexerBase<UserPassTorrentBaseSettings> public class HDTorrents : TorrentIndexerBase<UserPassTorrentBaseSettings>
{ {
public override string Name => "HD-Torrents"; public override string Name => "HD-Torrents";
public override string[] IndexerUrls => new string[] { "https://hdts.ru/", "https://hd-torrents.org/" };
public override string Description => "HD-Torrents is a private torrent website with HD torrents and strict rules on their content.";
private string LoginUrl => Settings.BaseUrl + "login.php"; private string LoginUrl => Settings.BaseUrl + "login.php";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public HDTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public HDTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -79,6 +83,60 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
}
};
caps.Categories.AddCategoryMapping("70", NewznabStandardCategory.MoviesUHD, "Movie/UHD/Blu-Ray");
caps.Categories.AddCategoryMapping("1", NewznabStandardCategory.MoviesHD, "Movie/Blu-Ray");
caps.Categories.AddCategoryMapping("71", NewznabStandardCategory.MoviesUHD, "Movie/UHD/Remux");
caps.Categories.AddCategoryMapping("2", NewznabStandardCategory.MoviesHD, "Movie/Remux");
caps.Categories.AddCategoryMapping("5", NewznabStandardCategory.MoviesHD, "Movie/1080p/i");
caps.Categories.AddCategoryMapping("3", NewznabStandardCategory.MoviesHD, "Movie/720p");
caps.Categories.AddCategoryMapping("64", NewznabStandardCategory.MoviesUHD, "Movie/2160p");
caps.Categories.AddCategoryMapping("63", NewznabStandardCategory.Audio, "Movie/Audio Track");
// TV Show
caps.Categories.AddCategoryMapping("72", NewznabStandardCategory.TVUHD, "TV Show/UHD/Blu-ray");
caps.Categories.AddCategoryMapping("59", NewznabStandardCategory.TVHD, "TV Show/Blu-ray");
caps.Categories.AddCategoryMapping("73", NewznabStandardCategory.TVUHD, "TV Show/UHD/Remux");
caps.Categories.AddCategoryMapping("60", NewznabStandardCategory.TVHD, "TV Show/Remux");
caps.Categories.AddCategoryMapping("30", NewznabStandardCategory.TVHD, "TV Show/1080p/i");
caps.Categories.AddCategoryMapping("38", NewznabStandardCategory.TVHD, "TV Show/720p");
caps.Categories.AddCategoryMapping("65", NewznabStandardCategory.TVUHD, "TV Show/2160p");
// Music
caps.Categories.AddCategoryMapping("44", NewznabStandardCategory.Audio, "Music/Album");
caps.Categories.AddCategoryMapping("61", NewznabStandardCategory.AudioVideo, "Music/Blu-Ray");
caps.Categories.AddCategoryMapping("62", NewznabStandardCategory.AudioVideo, "Music/Remux");
caps.Categories.AddCategoryMapping("57", NewznabStandardCategory.AudioVideo, "Music/1080p/i");
caps.Categories.AddCategoryMapping("45", NewznabStandardCategory.AudioVideo, "Music/720p");
caps.Categories.AddCategoryMapping("66", NewznabStandardCategory.AudioVideo, "Music/2160p");
// XXX
caps.Categories.AddCategoryMapping("58", NewznabStandardCategory.XXX, "XXX/Blu-ray");
caps.Categories.AddCategoryMapping("74", NewznabStandardCategory.XXX, "XXX/UHD/Blu-ray");
caps.Categories.AddCategoryMapping("48", NewznabStandardCategory.XXX, "XXX/1080p/i");
caps.Categories.AddCategoryMapping("47", NewznabStandardCategory.XXX, "XXX/720p");
caps.Categories.AddCategoryMapping("67", NewznabStandardCategory.XXX, "XXX/2160p");
return caps;
}
} }
public class HDTorrentsRequestGenerator : IIndexerRequestGenerator public class HDTorrentsRequestGenerator : IIndexerRequestGenerator
@@ -7,7 +7,6 @@ using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Headphones namespace NzbDrone.Core.Indexers.Headphones
@@ -17,6 +16,10 @@ namespace NzbDrone.Core.Indexers.Headphones
public override string Name => "Headphones VIP"; public override string Name => "Headphones VIP";
public override DownloadProtocol Protocol => DownloadProtocol.Usenet; 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";
public override IndexerCapabilities Capabilities => SetCapabilities();
public override IIndexerRequestGenerator GetRequestGenerator() public override IIndexerRequestGenerator GetRequestGenerator()
{ {
@@ -33,8 +36,8 @@ namespace NzbDrone.Core.Indexers.Headphones
return new HeadphonesRssParser(Capabilities.Categories); return new HeadphonesRssParser(Capabilities.Categories);
} }
public Headphones(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) public Headphones(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, nzbValidationService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, nzbValidationService, logger)
{ {
} }
@@ -71,5 +74,22 @@ namespace NzbDrone.Core.Indexers.Headphones
return downloadBytes; return downloadBytes;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
};
caps.Categories.AddCategoryMapping(3000, NewznabStandardCategory.Audio);
caps.Categories.AddCategoryMapping(3010, NewznabStandardCategory.AudioMP3);
caps.Categories.AddCategoryMapping(3040, NewznabStandardCategory.AudioLossless);
return caps;
}
} }
} }
@@ -10,7 +10,6 @@ using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -21,10 +20,27 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
public override string Name => "IPTorrents"; public override string Name => "IPTorrents";
public override string[] IndexerUrls => new string[]
{
"https://iptorrents.com/",
"https://iptorrents.me/",
"https://nemo.iptorrents.com/",
"https://ipt.getcrazy.me/",
"https://ipt.findnemo.net/",
"https://ipt.beelyrics.net/",
"https://ipt.venom.global/",
"https://ipt.workisboring.net/",
"https://ipt.lol/",
"https://ipt.cool/",
"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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public IPTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public IPTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -42,6 +58,102 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
return CookieUtil.CookieHeaderToDictionary(Settings.Cookie); return CookieUtil.CookieHeaderToDictionary(Settings.Cookie);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(72, NewznabStandardCategory.Movies, "Movies");
caps.Categories.AddCategoryMapping(87, NewznabStandardCategory.Movies3D, "Movie/3D");
caps.Categories.AddCategoryMapping(77, NewznabStandardCategory.MoviesSD, "Movie/480p");
caps.Categories.AddCategoryMapping(101, NewznabStandardCategory.MoviesUHD, "Movie/4K");
caps.Categories.AddCategoryMapping(89, NewznabStandardCategory.MoviesHD, "Movie/BD-R");
caps.Categories.AddCategoryMapping(90, NewznabStandardCategory.MoviesSD, "Movie/BD-Rip");
caps.Categories.AddCategoryMapping(96, NewznabStandardCategory.MoviesSD, "Movie/Cam");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesDVD, "Movie/DVD-R");
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.MoviesBluRay, "Movie/HD/Bluray");
caps.Categories.AddCategoryMapping(54, NewznabStandardCategory.Movies, "Movie/Kids");
caps.Categories.AddCategoryMapping(62, NewznabStandardCategory.MoviesSD, "Movie/MP4");
caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.MoviesForeign, "Movie/Non-English");
caps.Categories.AddCategoryMapping(68, NewznabStandardCategory.Movies, "Movie/Packs");
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.MoviesWEBDL, "Movie/Web-DL");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.MoviesSD, "Movie/Xvid");
caps.Categories.AddCategoryMapping(100, NewznabStandardCategory.Movies, "Movie/x265");
caps.Categories.AddCategoryMapping(73, NewznabStandardCategory.TV, "TV");
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.TVDocumentary, "TV/Documentaries");
caps.Categories.AddCategoryMapping(55, NewznabStandardCategory.TVSport, "Sports");
caps.Categories.AddCategoryMapping(78, NewznabStandardCategory.TVSD, "TV/480p");
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.TVHD, "TV/BD");
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVSD, "TV/DVD-R");
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.TVSD, "TV/DVD-Rip");
caps.Categories.AddCategoryMapping(66, NewznabStandardCategory.TVSD, "TV/Mobile");
caps.Categories.AddCategoryMapping(82, NewznabStandardCategory.TVForeign, "TV/Non-English");
caps.Categories.AddCategoryMapping(65, NewznabStandardCategory.TV, "TV/Packs");
caps.Categories.AddCategoryMapping(83, NewznabStandardCategory.TVForeign, "TV/Packs/Non-English");
caps.Categories.AddCategoryMapping(79, NewznabStandardCategory.TVSD, "TV/SD/x264");
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.TVWEBDL, "TV/Web-DL");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVHD, "TV/x264");
caps.Categories.AddCategoryMapping(99, NewznabStandardCategory.TVHD, "TV/x265");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.TVSD, "TV/Xvid");
caps.Categories.AddCategoryMapping(74, NewznabStandardCategory.Console, "Games");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.ConsoleOther, "Games/Mixed");
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.ConsoleNDS, "Games/Nintendo DS");
caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.PCISO, "Games/PC-ISO");
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.PCGames, "Games/PC-Rip");
caps.Categories.AddCategoryMapping(71, NewznabStandardCategory.ConsolePS3, "Games/PS3");
caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.ConsoleWii, "Games/Wii");
caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.ConsoleXBox360, "Games/Xbox-360");
caps.Categories.AddCategoryMapping(75, NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.AudioMP3, "Music/Audio");
caps.Categories.AddCategoryMapping(80, NewznabStandardCategory.AudioLossless, "Music/Flac");
caps.Categories.AddCategoryMapping(93, NewznabStandardCategory.Audio, "Music/Packs");
caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.AudioVideo, "Music/Video");
caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.AudioVideo, "Podcast");
caps.Categories.AddCategoryMapping(76, NewznabStandardCategory.Other, "Other/Miscellaneous");
caps.Categories.AddCategoryMapping(60, NewznabStandardCategory.TVAnime, "Anime");
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.PC0day, "Appz");
caps.Categories.AddCategoryMapping(86, NewznabStandardCategory.PC0day, "Appz/Non-English");
caps.Categories.AddCategoryMapping(64, NewznabStandardCategory.AudioAudiobook, "AudioBook");
caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.Books, "Books");
caps.Categories.AddCategoryMapping(102, NewznabStandardCategory.Books, "Books/Non-English");
caps.Categories.AddCategoryMapping(94, NewznabStandardCategory.BooksComics, "Books/Comics");
caps.Categories.AddCategoryMapping(95, NewznabStandardCategory.BooksOther, "Books/Educational");
caps.Categories.AddCategoryMapping(98, NewznabStandardCategory.Other, "Other/Fonts");
caps.Categories.AddCategoryMapping(69, NewznabStandardCategory.PCMac, "Appz/Mac");
caps.Categories.AddCategoryMapping(92, NewznabStandardCategory.BooksMags, "Books/Magazines & Newspapers");
caps.Categories.AddCategoryMapping(58, NewznabStandardCategory.PCMobileOther, "Appz/Mobile");
caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.Other, "Other/Pics/Wallpapers");
caps.Categories.AddCategoryMapping(88, NewznabStandardCategory.XXX, "XXX");
caps.Categories.AddCategoryMapping(85, NewznabStandardCategory.XXXOther, "XXX/Magazines");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.XXX, "XXX/Movie");
caps.Categories.AddCategoryMapping(81, NewznabStandardCategory.XXX, "XXX/Movie/0Day");
caps.Categories.AddCategoryMapping(91, NewznabStandardCategory.XXXPack, "XXX/Packs");
caps.Categories.AddCategoryMapping(84, NewznabStandardCategory.XXXImageSet, "XXX/Pics/Wallpapers");
return caps;
}
} }
public class IPTorrentsRequestGenerator : IIndexerRequestGenerator public class IPTorrentsRequestGenerator : IIndexerRequestGenerator
@@ -15,7 +15,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -27,11 +26,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class ImmortalSeed : TorrentIndexerBase<UserPassTorrentBaseSettings> public class ImmortalSeed : TorrentIndexerBase<UserPassTorrentBaseSettings>
{ {
public override string Name => "ImmortalSeed"; public override string Name => "ImmortalSeed";
public override string[] IndexerUrls => new string[] { "https://immortalseed.me/" };
public override string Description => "ImmortalSeed (iS) is a Private Torrent Tracker for MOVIES / TV / GENERAL";
private string LoginUrl => Settings.BaseUrl + "takelogin.php"; private string LoginUrl => Settings.BaseUrl + "takelogin.php";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public ImmortalSeed(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public ImmortalSeed(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -86,6 +90,74 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Other, "Nuked");
caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.TVAnime, "Anime");
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.PC, "Apps");
caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.AudioAudiobook, "Audiobooks");
caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.TV, "Childrens/Cartoons");
caps.Categories.AddCategoryMapping(54, NewznabStandardCategory.TVDocumentary, "Documentary - HD");
caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.BooksComics, "Comics");
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.PCGames, "Games");
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.ConsoleXBox, "Games Xbox");
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.PCGames, "Games-PC Rips");
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.ConsolePS4, "Games-PSx");
caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.PCMobileOther, "Mobile");
caps.Categories.AddCategoryMapping(59, NewznabStandardCategory.MoviesUHD, "Movies-4k");
caps.Categories.AddCategoryMapping(60, NewznabStandardCategory.MoviesForeign, "Non-English 4k Movies");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.MoviesHD, "Movies HD");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.MoviesForeign, "Movies HD Non-English");
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.MoviesSD, "TS/CAM/PPV");
caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.MoviesForeign, "Movies Low Def Non-English");
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.MoviesSD, "Movies-SD");
caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.MoviesForeign, "Movies SD Non-English");
caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.AudioOther, "Music");
caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.AudioLossless, "FLAC");
caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.AudioMP3, "MP3");
caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.AudioOther, "Music Other");
caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.AudioVideo, "Music Video");
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.Other, "Other");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TVSport, "Sports Tv");
caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.TVSport, "Sports Fitness-Instructional");
caps.Categories.AddCategoryMapping(58, NewznabStandardCategory.TVSport, "Olympics");
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.TVSD, "TV - 480p");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TVHD, "TV - High Definition");
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.TVSD, "TV - Standard Definition - x264");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVSD, "TV - Standard Definition - XviD");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.TVHD, "TV Season Packs - HD");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.TVSD, "TV Season Packs - SD");
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.BooksEBook, "Ebooks");
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.PCGames, "Games-PC ISO");
caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.BooksMags, "Magazines");
caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.PCMobileiOS, "IOS");
caps.Categories.AddCategoryMapping(51, NewznabStandardCategory.PCMobileAndroid, "Android");
caps.Categories.AddCategoryMapping(52, NewznabStandardCategory.PC0day, "Windows");
caps.Categories.AddCategoryMapping(53, NewznabStandardCategory.TVDocumentary, "Documentary - SD");
return caps;
}
} }
public class ImmortalSeedRequestGenerator : IIndexerRequestGenerator public class ImmortalSeedRequestGenerator : IIndexerRequestGenerator
@@ -16,7 +16,6 @@ using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -27,11 +26,15 @@ namespace NzbDrone.Core.Indexers.Definitions;
public class MoreThanTV : TorrentIndexerBase<CookieTorrentBaseSettings> public class MoreThanTV : TorrentIndexerBase<CookieTorrentBaseSettings>
{ {
public override string Name => "MoreThanTV"; 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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override bool FollowRedirect => true; public override bool FollowRedirect => true;
public MoreThanTV(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public MoreThanTV(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -44,6 +47,26 @@ public class MoreThanTV : TorrentIndexerBase<CookieTorrentBaseSettings>
Settings = Settings Settings = Settings
}; };
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV");
return caps;
}
protected override IDictionary<string, string> GetCookies() protected override IDictionary<string, string> GetCookies()
{ {
return CookieUtil.CookieHeaderToDictionary(Settings.Cookie); return CookieUtil.CookieHeaderToDictionary(Settings.Cookie);
@@ -167,6 +190,12 @@ public class MoreThanTVParser : IParseIndexerResponse
{ {
// Parse required data // Parse required data
var downloadAnchor = torrent.QuerySelector("span a[href^=\"/torrents.php?action=download\"]"); var downloadAnchor = torrent.QuerySelector("span a[href^=\"/torrents.php?action=download\"]");
if (downloadAnchor == null)
{
continue;
}
var title = downloadAnchor.ParentElement.ParentElement.ParentElement.QuerySelector("a[class=\"overlay_torrent\"]").TextContent.Trim(); var title = downloadAnchor.ParentElement.ParentElement.ParentElement.QuerySelector("a[class=\"overlay_torrent\"]").TextContent.Trim();
title = CleanUpTitle(title); title = CleanUpTitle(title);
@@ -16,7 +16,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -29,10 +28,15 @@ namespace NzbDrone.Core.Indexers.Definitions
private static readonly Regex TorrentIdRegex = new Regex(@"tor/download.php\?tid=(?<id>\d+)$"); private static readonly Regex TorrentIdRegex = new Regex(@"tor/download.php\?tid=(?<id>\d+)$");
public override string Name => "MyAnonamouse"; public override string Name => "MyAnonamouse";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public MyAnonamouse(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public override string[] IndexerUrls => new string[] { "https://www.myanonamouse.net/" };
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) 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 IndexerCapabilities Capabilities => SetCapabilities();
public MyAnonamouse(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -91,6 +95,114 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
return CookieUtil.CookieHeaderToDictionary("mam_id=" + Settings.MamId); return CookieUtil.CookieHeaderToDictionary("mam_id=" + Settings.MamId);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping("13", NewznabStandardCategory.AudioAudiobook, "AudioBooks");
caps.Categories.AddCategoryMapping("14", NewznabStandardCategory.BooksEBook, "E-Books");
caps.Categories.AddCategoryMapping("15", NewznabStandardCategory.AudioAudiobook, "Musicology");
caps.Categories.AddCategoryMapping("16", NewznabStandardCategory.AudioAudiobook, "Radio");
caps.Categories.AddCategoryMapping("39", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Action/Adventure");
caps.Categories.AddCategoryMapping("49", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Art");
caps.Categories.AddCategoryMapping("50", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Biographical");
caps.Categories.AddCategoryMapping("83", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Business");
caps.Categories.AddCategoryMapping("51", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Computer/Internet");
caps.Categories.AddCategoryMapping("97", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Crafts");
caps.Categories.AddCategoryMapping("40", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Crime/Thriller");
caps.Categories.AddCategoryMapping("41", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Fantasy");
caps.Categories.AddCategoryMapping("106", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Food");
caps.Categories.AddCategoryMapping("42", NewznabStandardCategory.AudioAudiobook, "Audiobooks - General Fiction");
caps.Categories.AddCategoryMapping("52", NewznabStandardCategory.AudioAudiobook, "Audiobooks - General Non-Fic");
caps.Categories.AddCategoryMapping("98", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Historical Fiction");
caps.Categories.AddCategoryMapping("54", NewznabStandardCategory.AudioAudiobook, "Audiobooks - History");
caps.Categories.AddCategoryMapping("55", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Home/Garden");
caps.Categories.AddCategoryMapping("43", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Horror");
caps.Categories.AddCategoryMapping("99", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Humor");
caps.Categories.AddCategoryMapping("84", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Instructional");
caps.Categories.AddCategoryMapping("44", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Juvenile");
caps.Categories.AddCategoryMapping("56", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Language");
caps.Categories.AddCategoryMapping("45", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Literary Classics");
caps.Categories.AddCategoryMapping("57", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Math/Science/Tech");
caps.Categories.AddCategoryMapping("85", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Medical");
caps.Categories.AddCategoryMapping("87", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Mystery");
caps.Categories.AddCategoryMapping("119", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Nature");
caps.Categories.AddCategoryMapping("88", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Philosophy");
caps.Categories.AddCategoryMapping("58", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Pol/Soc/Relig");
caps.Categories.AddCategoryMapping("59", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Recreation");
caps.Categories.AddCategoryMapping("46", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Romance");
caps.Categories.AddCategoryMapping("47", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Science Fiction");
caps.Categories.AddCategoryMapping("53", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Self-Help");
caps.Categories.AddCategoryMapping("89", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Travel/Adventure");
caps.Categories.AddCategoryMapping("100", NewznabStandardCategory.AudioAudiobook, "Audiobooks - True Crime");
caps.Categories.AddCategoryMapping("108", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Urban Fantasy");
caps.Categories.AddCategoryMapping("48", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Western");
caps.Categories.AddCategoryMapping("111", NewznabStandardCategory.AudioAudiobook, "Audiobooks - Young Adult");
caps.Categories.AddCategoryMapping("60", NewznabStandardCategory.BooksEBook, "Ebooks - Action/Adventure");
caps.Categories.AddCategoryMapping("71", NewznabStandardCategory.BooksEBook, "Ebooks - Art");
caps.Categories.AddCategoryMapping("72", NewznabStandardCategory.BooksEBook, "Ebooks - Biographical");
caps.Categories.AddCategoryMapping("90", NewznabStandardCategory.BooksEBook, "Ebooks - Business");
caps.Categories.AddCategoryMapping("61", NewznabStandardCategory.BooksComics, "Ebooks - Comics/Graphic novels");
caps.Categories.AddCategoryMapping("73", NewznabStandardCategory.BooksEBook, "Ebooks - Computer/Internet");
caps.Categories.AddCategoryMapping("101", NewznabStandardCategory.BooksEBook, "Ebooks - Crafts");
caps.Categories.AddCategoryMapping("62", NewznabStandardCategory.BooksEBook, "Ebooks - Crime/Thriller");
caps.Categories.AddCategoryMapping("63", NewznabStandardCategory.BooksEBook, "Ebooks - Fantasy");
caps.Categories.AddCategoryMapping("107", NewznabStandardCategory.BooksEBook, "Ebooks - Food");
caps.Categories.AddCategoryMapping("64", NewznabStandardCategory.BooksEBook, "Ebooks - General Fiction");
caps.Categories.AddCategoryMapping("74", NewznabStandardCategory.BooksEBook, "Ebooks - General Non-Fiction");
caps.Categories.AddCategoryMapping("102", NewznabStandardCategory.BooksEBook, "Ebooks - Historical Fiction");
caps.Categories.AddCategoryMapping("76", NewznabStandardCategory.BooksEBook, "Ebooks - History");
caps.Categories.AddCategoryMapping("77", NewznabStandardCategory.BooksEBook, "Ebooks - Home/Garden");
caps.Categories.AddCategoryMapping("65", NewznabStandardCategory.BooksEBook, "Ebooks - Horror");
caps.Categories.AddCategoryMapping("103", NewznabStandardCategory.BooksEBook, "Ebooks - Humor");
caps.Categories.AddCategoryMapping("115", NewznabStandardCategory.BooksEBook, "Ebooks - Illusion/Magic");
caps.Categories.AddCategoryMapping("91", NewznabStandardCategory.BooksEBook, "Ebooks - Instructional");
caps.Categories.AddCategoryMapping("66", NewznabStandardCategory.BooksEBook, "Ebooks - Juvenile");
caps.Categories.AddCategoryMapping("78", NewznabStandardCategory.BooksEBook, "Ebooks - Language");
caps.Categories.AddCategoryMapping("67", NewznabStandardCategory.BooksEBook, "Ebooks - Literary Classics");
caps.Categories.AddCategoryMapping("79", NewznabStandardCategory.BooksMags, "Ebooks - Magazines/Newspapers");
caps.Categories.AddCategoryMapping("80", NewznabStandardCategory.BooksTechnical, "Ebooks - Math/Science/Tech");
caps.Categories.AddCategoryMapping("92", NewznabStandardCategory.BooksEBook, "Ebooks - Medical");
caps.Categories.AddCategoryMapping("118", NewznabStandardCategory.BooksEBook, "Ebooks - Mixed Collections");
caps.Categories.AddCategoryMapping("94", NewznabStandardCategory.BooksEBook, "Ebooks - Mystery");
caps.Categories.AddCategoryMapping("120", NewznabStandardCategory.BooksEBook, "Ebooks - Nature");
caps.Categories.AddCategoryMapping("95", NewznabStandardCategory.BooksEBook, "Ebooks - Philosophy");
caps.Categories.AddCategoryMapping("81", NewznabStandardCategory.BooksEBook, "Ebooks - Pol/Soc/Relig");
caps.Categories.AddCategoryMapping("82", NewznabStandardCategory.BooksEBook, "Ebooks - Recreation");
caps.Categories.AddCategoryMapping("68", NewznabStandardCategory.BooksEBook, "Ebooks - Romance");
caps.Categories.AddCategoryMapping("69", NewznabStandardCategory.BooksEBook, "Ebooks - Science Fiction");
caps.Categories.AddCategoryMapping("75", NewznabStandardCategory.BooksEBook, "Ebooks - Self-Help");
caps.Categories.AddCategoryMapping("96", NewznabStandardCategory.BooksEBook, "Ebooks - Travel/Adventure");
caps.Categories.AddCategoryMapping("104", NewznabStandardCategory.BooksEBook, "Ebooks - True Crime");
caps.Categories.AddCategoryMapping("109", NewznabStandardCategory.BooksEBook, "Ebooks - Urban Fantasy");
caps.Categories.AddCategoryMapping("70", NewznabStandardCategory.BooksEBook, "Ebooks - Western");
caps.Categories.AddCategoryMapping("112", NewznabStandardCategory.BooksEBook, "Ebooks - Young Adult");
caps.Categories.AddCategoryMapping("19", NewznabStandardCategory.AudioAudiobook, "Guitar/Bass Tabs");
caps.Categories.AddCategoryMapping("20", NewznabStandardCategory.AudioAudiobook, "Individual Sheet");
caps.Categories.AddCategoryMapping("24", NewznabStandardCategory.AudioAudiobook, "Individual Sheet MP3");
caps.Categories.AddCategoryMapping("126", NewznabStandardCategory.AudioAudiobook, "Instructional Book with Video");
caps.Categories.AddCategoryMapping("22", NewznabStandardCategory.AudioAudiobook, "Instructional Media - Music");
caps.Categories.AddCategoryMapping("113", NewznabStandardCategory.AudioAudiobook, "Lick Library - LTP/Jam With");
caps.Categories.AddCategoryMapping("114", NewznabStandardCategory.AudioAudiobook, "Lick Library - Techniques/QL");
caps.Categories.AddCategoryMapping("17", NewznabStandardCategory.AudioAudiobook, "Music - Complete Editions");
caps.Categories.AddCategoryMapping("26", NewznabStandardCategory.AudioAudiobook, "Music Book");
caps.Categories.AddCategoryMapping("27", NewznabStandardCategory.AudioAudiobook, "Music Book MP3");
caps.Categories.AddCategoryMapping("30", NewznabStandardCategory.AudioAudiobook, "Sheet Collection");
caps.Categories.AddCategoryMapping("31", NewznabStandardCategory.AudioAudiobook, "Sheet Collection MP3");
caps.Categories.AddCategoryMapping("127", NewznabStandardCategory.AudioAudiobook, "Radio - Comedy");
caps.Categories.AddCategoryMapping("130", NewznabStandardCategory.AudioAudiobook, "Radio - Drama");
caps.Categories.AddCategoryMapping("128", NewznabStandardCategory.AudioAudiobook, "Radio - Factual/Documentary");
caps.Categories.AddCategoryMapping("132", NewznabStandardCategory.AudioAudiobook, "Radio - Reading");
return caps;
}
} }
public class MyAnonamouseRequestGenerator : IIndexerRequestGenerator public class MyAnonamouseRequestGenerator : IIndexerRequestGenerator
@@ -14,7 +14,6 @@ using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -25,11 +24,17 @@ namespace NzbDrone.Core.Indexers.Definitions
public class Nebulance : TorrentIndexerBase<NebulanceSettings> public class Nebulance : TorrentIndexerBase<NebulanceSettings>
{ {
public override string Name => "Nebulance"; public override string Name => "Nebulance";
public override string[] IndexerUrls => new string[] { "https://nebulance.io/" };
private string LoginUrl => Settings.BaseUrl + "login.php"; private string LoginUrl => Settings.BaseUrl + "login.php";
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public Nebulance(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public Nebulance(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -82,6 +87,23 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TV);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD);
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVHD);
return caps;
}
} }
public class NebulanceRequestGenerator : IIndexerRequestGenerator public class NebulanceRequestGenerator : IIndexerRequestGenerator
@@ -8,7 +8,6 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@@ -90,12 +89,35 @@ namespace NzbDrone.Core.Indexers.Newznab
{ {
get get
{ {
yield return GetDefinition("abNZB", GetSettings("https://abnzb.com"));
yield return GetDefinition("altHUB", GetSettings("https://api.althub.co.za"));
yield return GetDefinition("AnimeTosho (Usenet)", GetSettings("https://feed.animetosho.org"));
yield return GetDefinition("DOGnzb", GetSettings("https://api.dognzb.cr"));
yield return GetDefinition("DrunkenSlug", GetSettings("https://drunkenslug.com"));
yield return GetDefinition("GingaDADDY", GetSettings("https://www.gingadaddy.com"));
yield return GetDefinition("Miatrix", GetSettings("https://www.miatrix.com"));
yield return GetDefinition("Newz-Complex", GetSettings("https://newz-complex.org/www"));
yield return GetDefinition("Newz69", GetSettings("https://newz69.keagaming.com"));
yield return GetDefinition("NinjaCentral", GetSettings("https://ninjacentral.co.za"));
yield return GetDefinition("Nzb.su", GetSettings("https://api.nzb.su"));
yield return GetDefinition("NZBCat", GetSettings("https://nzb.cat"));
yield return GetDefinition("NZBFinder", GetSettings("https://nzbfinder.ws"));
yield return GetDefinition("NZBgeek", GetSettings("https://api.nzbgeek.info"));
yield return GetDefinition("NzbNoob", GetSettings("https://www.nzbnoob.com"));
yield return GetDefinition("NZBNDX", GetSettings("https://www.nzbndx.com"));
yield return GetDefinition("NzbPlanet", GetSettings("https://api.nzbplanet.net"));
yield return GetDefinition("NZBStars", GetSettings("https://nzbstars.com"));
yield return GetDefinition("OZnzb", GetSettings("https://api.oznzb.com"));
yield return GetDefinition("SimplyNZBs", GetSettings("https://simplynzbs.com"));
yield return GetDefinition("SpotNZB", GetSettings("https://spotnzb.xyz"));
yield return GetDefinition("Tabula Rasa", GetSettings("https://www.tabula-rasa.pw", apiPath: @"/api/v1/api"));
yield return GetDefinition("Usenet Crawler", GetSettings("https://www.usenet-crawler.com"));
yield return GetDefinition("Generic Newznab", GetSettings("")); yield return GetDefinition("Generic Newznab", GetSettings(""));
} }
} }
public Newznab(INewznabCapabilitiesProvider capabilitiesProvider, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger) public Newznab(INewznabCapabilitiesProvider capabilitiesProvider, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, nzbValidationService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, nzbValidationService, logger)
{ {
_capabilitiesProvider = capabilitiesProvider; _capabilitiesProvider = capabilitiesProvider;
} }
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
using DryIoc;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
@@ -268,7 +269,10 @@ namespace NzbDrone.Core.Indexers.Newznab
parameters.Add("offset", searchCriteria.Offset.ToString()); parameters.Add("offset", searchCriteria.Offset.ToString());
} }
yield return new IndexerRequest(string.Format("{0}&{1}", baseUrl, parameters.GetQueryString()), HttpAccept.Rss); var request = new IndexerRequest(string.Format("{0}&{1}", baseUrl, parameters.GetQueryString()), HttpAccept.Rss);
request.HttpRequest.AllowAutoRedirect = true;
yield return request;
} }
private static string NewsnabifyTitle(string title) private static string NewsnabifyTitle(string title)
@@ -18,7 +18,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -30,10 +29,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class NorBits : TorrentIndexerBase<NorBitsSettings> public class NorBits : TorrentIndexerBase<NorBitsSettings>
{ {
public override string Name => "NorBits"; public override string Name => "NorBits";
public override string[] IndexerUrls => new string[] { "https://norbits.net/" };
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public NorBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public NorBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -114,6 +119,53 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=49", NewznabStandardCategory.MoviesUHD, "Filmer - UHD-2160p");
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=19", NewznabStandardCategory.MoviesHD, "Filmer - HD-1080p/i");
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=20", NewznabStandardCategory.MoviesHD, "Filmer - HD-720p");
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=22", NewznabStandardCategory.MoviesSD, "Filmer - SD");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=49", NewznabStandardCategory.TVUHD, "TV - UHD-2160p");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=19", NewznabStandardCategory.TVHD, "TV - HD-1080p/i");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=20", NewznabStandardCategory.TVHD, "TV - HD-720p");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=22", NewznabStandardCategory.TVSD, "TV - SD");
caps.Categories.AddCategoryMapping("main_cat[]=3", NewznabStandardCategory.PC, "Programmer");
caps.Categories.AddCategoryMapping("main_cat[]=4", NewznabStandardCategory.Console, "Spill");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=42", NewznabStandardCategory.AudioMP3, "Musikk - 192");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=43", NewznabStandardCategory.AudioMP3, "Musikk - 256");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=44", NewznabStandardCategory.AudioMP3, "Musikk - 320");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=45", NewznabStandardCategory.AudioMP3, "Musikk - VBR");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=46", NewznabStandardCategory.AudioLossless, "Musikk - Lossless");
caps.Categories.AddCategoryMapping("main_cat[]=6", NewznabStandardCategory.Books, "Tidsskrift");
caps.Categories.AddCategoryMapping("main_cat[]=7", NewznabStandardCategory.AudioAudiobook, "Lydbøker");
caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=19", NewznabStandardCategory.AudioVideo, "Musikkvideoer - HD-1080p/i");
caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=20", NewznabStandardCategory.AudioVideo, "Musikkvideoer - HD-720p");
caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=22", NewznabStandardCategory.AudioVideo, "Musikkvideoer - SD");
caps.Categories.AddCategoryMapping("main_cat[]=40", NewznabStandardCategory.AudioOther, "Podcasts");
return caps;
}
} }
public class NorBitsRequestGenerator : IIndexerRequestGenerator public class NorBitsRequestGenerator : IIndexerRequestGenerator
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions namespace NzbDrone.Core.Indexers.Definitions
@@ -10,11 +9,46 @@ namespace NzbDrone.Core.Indexers.Definitions
public class NotWhatCD : Gazelle.Gazelle public class NotWhatCD : Gazelle.Gazelle
{ {
public override string Name => "notwhat.cd"; public override string Name => "notwhat.cd";
public override string[] IndexerUrls => new string[] { "https://notwhat.cd/" };
public override string Description => "NotWhat.CD (NWCD) is a private Music tracker that arised after the former (WCD) shut down.";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private; public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public NotWhatCD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public NotWhatCD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q, MusicSearchParam.Album, MusicSearchParam.Artist, MusicSearchParam.Label, MusicSearchParam.Year
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PC, "Applications");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Books, "E-Books");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.AudioAudiobook, "Audiobooks");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Movies, "E-Learning Videos");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.TV, "Comedy");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Books, "Comics");
return caps;
}
} }
} }
File diff suppressed because it is too large Load Diff
@@ -3,7 +3,6 @@ using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Gazelle; using NzbDrone.Core.Indexers.Gazelle;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions namespace NzbDrone.Core.Indexers.Definitions
@@ -11,12 +10,40 @@ namespace NzbDrone.Core.Indexers.Definitions
public class Orpheus : Gazelle.Gazelle public class Orpheus : Gazelle.Gazelle
{ {
public override string Name => "Orpheus"; public override string Name => "Orpheus";
public override string[] IndexerUrls => new string[] { "https://orpheus.network/" };
public override string Description => "Orpheus (APOLLO) is a Private Torrent Tracker for MUSIC";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public Orpheus(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public Orpheus(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q, MusicSearchParam.Album, MusicSearchParam.Artist, MusicSearchParam.Label, MusicSearchParam.Year
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PC, "Applications");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Books, "E-Books");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.AudioAudiobook, "Audiobooks");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Other, "E-Learning Videos");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.Other, "Comedy");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Books, "Comics");
return caps;
}
public override IParseIndexerResponse GetParser() public override IParseIndexerResponse GetParser()
{ {
return new OrpheusParser(Settings, Capabilities); return new OrpheusParser(Settings, Capabilities);
@@ -3,7 +3,6 @@ using NLog;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.PassThePopcorn namespace NzbDrone.Core.Indexers.PassThePopcorn
@@ -11,20 +10,24 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
public class PassThePopcorn : TorrentIndexerBase<PassThePopcornSettings> public class PassThePopcorn : TorrentIndexerBase<PassThePopcornSettings>
{ {
public override string Name => "PassThePopcorn"; public override string Name => "PassThePopcorn";
public override string[] IndexerUrls => new string[] { "https://passthepopcorn.me" };
public override string Description => "PassThePopcorn (PTP) is a Private site for MOVIES / TV";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsRss => true; public override bool SupportsRss => true;
public override bool SupportsSearch => true; public override bool SupportsSearch => true;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override int PageSize => 50; public override int PageSize => 50;
public PassThePopcorn(IIndexerHttpClient httpClient, public PassThePopcorn(IIndexerHttpClient httpClient,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
ICacheManager cacheManager, ICacheManager cacheManager,
IIndexerStatusService indexerStatusService, IIndexerStatusService indexerStatusService,
IIndexerDefinitionUpdateService definitionService, IConfigService configService,
IConfigService configService, Logger logger)
Logger logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger)
{ {
} }
@@ -38,6 +41,43 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
}; };
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
SearchParams = new List<SearchParam>
{
SearchParam.Q
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
Flags = new List<IndexerFlag>
{
IndexerFlag.FreeLeech,
PassThePopcornFlag.Golden,
PassThePopcornFlag.Approved
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Feature Film");
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesForeign);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesOther);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesHD);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies3D);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesBluRay);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesDVD);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesWEBDL);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.Movies, "Short Film");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TV, "Miniseries");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.TV, "Stand-up Comedy");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TV, "Live Performance");
return caps;
}
public override IParseIndexerResponse GetParser() public override IParseIndexerResponse GetParser()
{ {
return new PassThePopcornParser(Settings, Capabilities, _logger); return new PassThePopcornParser(Settings, Capabilities, _logger);
@@ -14,7 +14,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -25,11 +24,17 @@ namespace NzbDrone.Core.Indexers.Definitions
public class PornoLab : TorrentIndexerBase<PornoLabSettings> public class PornoLab : TorrentIndexerBase<PornoLabSettings>
{ {
public override string Name => "PornoLab"; public override string Name => "PornoLab";
public override string[] IndexerUrls => new string[] { "https://pornolab.net/" };
private string LoginUrl => Settings.BaseUrl + "forum/login.php"; private string LoginUrl => Settings.BaseUrl + "forum/login.php";
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;
public override IndexerCapabilities Capabilities => SetCapabilities();
public PornoLab(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public PornoLab(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -89,6 +94,151 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
};
caps.Categories.AddCategoryMapping(1768, NewznabStandardCategory.XXX, "Эротические фильмы / Erotic Movies");
caps.Categories.AddCategoryMapping(60, NewznabStandardCategory.XXX, "Документальные фильмы / Documentary & Reality");
caps.Categories.AddCategoryMapping(1644, NewznabStandardCategory.XXX, "Нудизм-Натуризм / Nudity");
caps.Categories.AddCategoryMapping(1111, NewznabStandardCategory.XXXPack, "Паки полных фильмов / Full Length Movies Packs");
caps.Categories.AddCategoryMapping(508, NewznabStandardCategory.XXX, "Классические фильмы / Classic");
caps.Categories.AddCategoryMapping(555, NewznabStandardCategory.XXX, "Фильмы с сюжетом / Feature & Vignettes");
caps.Categories.AddCategoryMapping(1673, NewznabStandardCategory.XXX, "Гонзо-фильмы 2011-2021 / Gonzo 2011-2021");
caps.Categories.AddCategoryMapping(1112, NewznabStandardCategory.XXX, "Фильмы без сюжета 1991-2010 / All Sex & Amateur 1991-2010");
caps.Categories.AddCategoryMapping(1718, NewznabStandardCategory.XXX, "Фильмы без сюжета 2011-2021 / All Sex & Amateur 2011-2021");
caps.Categories.AddCategoryMapping(553, NewznabStandardCategory.XXX, "Лесбо-фильмы / All Girl & Solo");
caps.Categories.AddCategoryMapping(1143, NewznabStandardCategory.XXX, "Этнические фильмы / Ethnic-Themed");
caps.Categories.AddCategoryMapping(1646, NewznabStandardCategory.XXX, "Видео для телефонов и КПК / Pocket РС & Phone Video");
caps.Categories.AddCategoryMapping(1712, NewznabStandardCategory.XXX, "Эротические и Документальные фильмы (DVD и HD) / EroticDocumentary & Reality (DVD & HD)");
caps.Categories.AddCategoryMapping(1713, NewznabStandardCategory.XXXDVD, "Фильмы с сюжетомКлассические (DVD) / Feature & Vignettes, Classic (DVD)");
caps.Categories.AddCategoryMapping(512, NewznabStandardCategory.XXXDVD, "ГонзоЛесбо и Фильмы без сюжета (DVD) / Gonzo, All Girl & Solo, All Sex (DVD)");
caps.Categories.AddCategoryMapping(1775, NewznabStandardCategory.XXX, "Фильмы с сюжетом (HD Video) / Feature & Vignettes (HD Video)");
caps.Categories.AddCategoryMapping(1450, NewznabStandardCategory.XXX, "ГонзоЛесбо и Фильмы без сюжета (HD Video) / Gonzo, All Girl & Solo, All Sex (HD Video)");
caps.Categories.AddCategoryMapping(902, NewznabStandardCategory.XXX, "Русские порнофильмы / Russian Full Length Movies");
caps.Categories.AddCategoryMapping(1675, NewznabStandardCategory.XXXPack, "Паки русских порнороликов / Russian Clips Packs");
caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 1991-2015 / Russian SiteRip's 1991-2015");
caps.Categories.AddCategoryMapping(1830, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 1991-2015 (HD Video) / Russian SiteRip's 1991-2015 (HD Video)");
caps.Categories.AddCategoryMapping(1803, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 2016-2021 / Russian SiteRip's 2016-2021");
caps.Categories.AddCategoryMapping(1831, NewznabStandardCategory.XXX, "Сайтрипы с русскими актрисами 2016-2021 (HD Video) / Russian SiteRip's 2016-2021 (HD Video)");
caps.Categories.AddCategoryMapping(1741, NewznabStandardCategory.XXX, "Русские Порноролики Разное / Russian Clips (various)");
caps.Categories.AddCategoryMapping(1676, NewznabStandardCategory.XXX, "Русское любительское видео / Russian Amateur Video");
caps.Categories.AddCategoryMapping(1780, NewznabStandardCategory.XXXPack, "Паки сайтрипов (HD Video) / SiteRip's Packs (HD Video)");
caps.Categories.AddCategoryMapping(1110, NewznabStandardCategory.XXXPack, "Паки сайтрипов / SiteRip's Packs");
caps.Categories.AddCategoryMapping(1678, NewznabStandardCategory.XXXPack, "Паки порнороликов по актрисам / Actresses Clips Packs");
caps.Categories.AddCategoryMapping(1124, NewznabStandardCategory.XXX, "Сайтрипы 1991-2010 (HD Video) / SiteRip's 1991-2010 (HD Video)");
caps.Categories.AddCategoryMapping(1784, NewznabStandardCategory.XXX, "Сайтрипы 2011-2012 (HD Video) / SiteRip's 2011-2012 (HD Video)");
caps.Categories.AddCategoryMapping(1769, NewznabStandardCategory.XXX, "Сайтрипы 2013 (HD Video) / SiteRip's 2013 (HD Video)");
caps.Categories.AddCategoryMapping(1793, NewznabStandardCategory.XXX, "Сайтрипы 2014 (HD Video) / SiteRip's 2014 (HD Video)");
caps.Categories.AddCategoryMapping(1797, NewznabStandardCategory.XXX, "Сайтрипы 2015 (HD Video) / SiteRip's 2015 (HD Video)");
caps.Categories.AddCategoryMapping(1804, NewznabStandardCategory.XXX, "Сайтрипы 2016 (HD Video) / SiteRip's 2016 (HD Video)");
caps.Categories.AddCategoryMapping(1819, NewznabStandardCategory.XXX, "Сайтрипы 2017 (HD Video) / SiteRip's 2017 (HD Video)");
caps.Categories.AddCategoryMapping(1825, NewznabStandardCategory.XXX, "Сайтрипы 2018 (HD Video) / SiteRip's 2018 (HD Video)");
caps.Categories.AddCategoryMapping(1836, NewznabStandardCategory.XXX, "Сайтрипы 2019 (HD Video) / SiteRip's 2019 (HD Video)");
caps.Categories.AddCategoryMapping(1842, NewznabStandardCategory.XXX, "Сайтрипы 2020 (HD Video) / SiteRip's 2020 (HD Video)");
caps.Categories.AddCategoryMapping(1846, NewznabStandardCategory.XXX, "Сайтрипы 2021 (HD Video) / SiteRip's 2021 (HD Video)");
caps.Categories.AddCategoryMapping(1857, NewznabStandardCategory.XXX, "Сайтрипы 2022 (HD Video) / SiteRip's 2022 (HD Video)");
caps.Categories.AddCategoryMapping(1451, NewznabStandardCategory.XXX, "Сайтрипы 1991-2010 / SiteRip's 1991-2010");
caps.Categories.AddCategoryMapping(1788, NewznabStandardCategory.XXX, "Сайтрипы 2011-2012 / SiteRip's 2011-2012");
caps.Categories.AddCategoryMapping(1789, NewznabStandardCategory.XXX, "Сайтрипы 2013 / SiteRip's 2013");
caps.Categories.AddCategoryMapping(1792, NewznabStandardCategory.XXX, "Сайтрипы 2014 / SiteRip's 2014");
caps.Categories.AddCategoryMapping(1798, NewznabStandardCategory.XXX, "Сайтрипы 2015 / SiteRip's 2015");
caps.Categories.AddCategoryMapping(1805, NewznabStandardCategory.XXX, "Сайтрипы 2016 / SiteRip's 2016");
caps.Categories.AddCategoryMapping(1820, NewznabStandardCategory.XXX, "Сайтрипы 2017 / SiteRip's 2017");
caps.Categories.AddCategoryMapping(1826, NewznabStandardCategory.XXX, "Сайтрипы 2018 / SiteRip's 2018");
caps.Categories.AddCategoryMapping(1837, NewznabStandardCategory.XXX, "Сайтрипы 2019 / SiteRip's 2019");
caps.Categories.AddCategoryMapping(1843, NewznabStandardCategory.XXX, "Сайтрипы 2020 / SiteRip's 2020");
caps.Categories.AddCategoryMapping(1847, NewznabStandardCategory.XXX, "Сайтрипы 2021 / SiteRip's 2021");
caps.Categories.AddCategoryMapping(1856, NewznabStandardCategory.XXX, "Сайтрипы 2022 / SiteRip's 2022");
caps.Categories.AddCategoryMapping(1707, NewznabStandardCategory.XXX, "Сцены из фильмов / Movie Scenes");
caps.Categories.AddCategoryMapping(284, NewznabStandardCategory.XXX, "Порноролики Разное / Clips (various)");
caps.Categories.AddCategoryMapping(1823, NewznabStandardCategory.XXX, "Порноролики в 3D и Virtual Reality (VR) / 3D & Virtual Reality Videos");
caps.Categories.AddCategoryMapping(1801, NewznabStandardCategory.XXXPack, "Паки японских фильмов и сайтрипов / Full Length Japanese Movies Packs & SiteRip's Packs");
caps.Categories.AddCategoryMapping(1719, NewznabStandardCategory.XXX, "Японские фильмы и сайтрипы (DVD и HD Video) / Japanese Movies & SiteRip's (DVD & HD Video)");
caps.Categories.AddCategoryMapping(997, NewznabStandardCategory.XXX, "Японские фильмы и сайтрипы 1991-2014 / Japanese Movies & SiteRip's 1991-2014");
caps.Categories.AddCategoryMapping(1818, NewznabStandardCategory.XXX, "Японские фильмы и сайтрипы 2015-2019 / Japanese Movies & SiteRip's 2015-2019");
caps.Categories.AddCategoryMapping(1671, NewznabStandardCategory.XXX, "Эротические студии (видео) / Erotic Video Library");
caps.Categories.AddCategoryMapping(1726, NewznabStandardCategory.XXX, "Met-Art & MetModels");
caps.Categories.AddCategoryMapping(883, NewznabStandardCategory.XXXImageSet, "Эротические студии Разное / Erotic Picture Gallery (various)");
caps.Categories.AddCategoryMapping(1759, NewznabStandardCategory.XXXImageSet, "Паки сайтрипов эротических студий / Erotic Picture SiteRip's Packs");
caps.Categories.AddCategoryMapping(1728, NewznabStandardCategory.XXXImageSet, "Любительское фото / Amateur Picture Gallery");
caps.Categories.AddCategoryMapping(1729, NewznabStandardCategory.XXXPack, "Подборки по актрисам / Actresses Picture Packs");
caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.XXXImageSet, "Подборки сайтрипов / SiteRip's Picture Packs");
caps.Categories.AddCategoryMapping(1757, NewznabStandardCategory.XXXImageSet, "Подборки сетов / Picture Sets Packs");
caps.Categories.AddCategoryMapping(1735, NewznabStandardCategory.XXXImageSet, "Тематическое и нетрадиционное фото / Misc & Special Interest Picture Packs");
caps.Categories.AddCategoryMapping(1731, NewznabStandardCategory.XXXImageSet, "Журналы / Magazines");
caps.Categories.AddCategoryMapping(1679, NewznabStandardCategory.XXX, "Хентай: основной подраздел / Hentai: main subsection");
caps.Categories.AddCategoryMapping(1740, NewznabStandardCategory.XXX, "Хентай в высоком качестве (DVD и HD) / Hentai DVD & HD");
caps.Categories.AddCategoryMapping(1834, NewznabStandardCategory.XXX, "Хентай: ролики 2D / Hentai: 2D video");
caps.Categories.AddCategoryMapping(1752, NewznabStandardCategory.XXX, "Хентай: ролики 3D / Hentai: 3D video");
caps.Categories.AddCategoryMapping(1760, NewznabStandardCategory.XXX, "Хентай: Манга / Hentai: Manga");
caps.Categories.AddCategoryMapping(1781, NewznabStandardCategory.XXX, "Хентай: Арт и HCG / Hentai: Artwork & HCG");
caps.Categories.AddCategoryMapping(1711, NewznabStandardCategory.XXX, "Мультфильмы / Cartoons");
caps.Categories.AddCategoryMapping(1296, NewznabStandardCategory.XXX, "Комиксы и рисунки / Comics & Artwork");
caps.Categories.AddCategoryMapping(1750, NewznabStandardCategory.XXX, "Игры: основной подраздел / Games: main subsection");
caps.Categories.AddCategoryMapping(1756, NewznabStandardCategory.XXX, "Игры: визуальные новеллы / Games: Visual Novels");
caps.Categories.AddCategoryMapping(1785, NewznabStandardCategory.XXX, "Игры: ролевые / Games: role-playing (RPG Maker and WOLF RPG Editor)");
caps.Categories.AddCategoryMapping(1790, NewznabStandardCategory.XXX, "Игры и Софт: Анимация / Software: Animation");
caps.Categories.AddCategoryMapping(1827, NewznabStandardCategory.XXX, "Игры: В разработке и Демо (основной подраздел) / Games: In Progress and Demo (main subsection)");
caps.Categories.AddCategoryMapping(1828, NewznabStandardCategory.XXX, "Игры: В разработке и Демо (ролевые) / Games: In Progress and Demo (role-playing - RPG Maker and WOLF RPG Editor)");
caps.Categories.AddCategoryMapping(1715, NewznabStandardCategory.XXX, "Транссексуалы (DVD и HD) / Transsexual (DVD & HD)");
caps.Categories.AddCategoryMapping(1680, NewznabStandardCategory.XXX, "Транссексуалы / Transsexual");
caps.Categories.AddCategoryMapping(1758, NewznabStandardCategory.XXX, "Бисексуалы / Bisexual");
caps.Categories.AddCategoryMapping(1682, NewznabStandardCategory.XXX, "БДСМ / BDSM");
caps.Categories.AddCategoryMapping(1733, NewznabStandardCategory.XXX, "Женское доминирование и страпон / Femdom & Strapon");
caps.Categories.AddCategoryMapping(1754, NewznabStandardCategory.XXX, "Подглядывание / Voyeur");
caps.Categories.AddCategoryMapping(1734, NewznabStandardCategory.XXX, "Фистинг и дилдо / Fisting & Dildo");
caps.Categories.AddCategoryMapping(1791, NewznabStandardCategory.XXX, "Беременные / Pregnant");
caps.Categories.AddCategoryMapping(509, NewznabStandardCategory.XXX, "Буккаке / Bukkake");
caps.Categories.AddCategoryMapping(1685, NewznabStandardCategory.XXX, "Мочеиспускание / Peeing");
caps.Categories.AddCategoryMapping(1762, NewznabStandardCategory.XXX, "Фетиш / Fetish");
caps.Categories.AddCategoryMapping(903, NewznabStandardCategory.XXX, "Полнометражные гей-фильмы / Full Length Movies (Gay)");
caps.Categories.AddCategoryMapping(1765, NewznabStandardCategory.XXX, "Полнометражные азиатские гей-фильмы / Full-length Asian Films (Gay)");
caps.Categories.AddCategoryMapping(1767, NewznabStandardCategory.XXX, "Классические гей-фильмы (до 1990 года) / Classic Gay Films (Pre-1990's)");
caps.Categories.AddCategoryMapping(1755, NewznabStandardCategory.XXX, "Гей-фильмы в высоком качестве (DVD и HD) / High-Quality Full Length Movies (Gay DVD & HD)");
caps.Categories.AddCategoryMapping(1787, NewznabStandardCategory.XXX, "Азиатские гей-фильмы в высоком качестве (DVD и HD) / High-Quality Full Length Asian Movies (Gay DVD & HD)");
caps.Categories.AddCategoryMapping(1763, NewznabStandardCategory.XXXPack, "ПАКи гей-роликов и сайтрипов / Clip's & SiteRip's Packs (Gay)");
caps.Categories.AddCategoryMapping(1777, NewznabStandardCategory.XXX, "Гей-ролики в высоком качестве (HD Video) / Gay Clips (HD Video)");
caps.Categories.AddCategoryMapping(1691, NewznabStandardCategory.XXX, "РоликиSiteRip'ы и сцены из гей-фильмов / Clips & Movie Scenes (Gay)");
caps.Categories.AddCategoryMapping(1692, NewznabStandardCategory.XXXImageSet, "Гей-журналыфото, разное / Magazines, Photo, Rest (Gay)");
caps.Categories.AddCategoryMapping(1817, NewznabStandardCategory.XXX, "Обход блокировки");
caps.Categories.AddCategoryMapping(1670, NewznabStandardCategory.XXX, "Эротическое видео / Erotic&Softcore");
caps.Categories.AddCategoryMapping(1672, NewznabStandardCategory.XXX, "Зарубежные порнофильмы / Full Length Movies");
caps.Categories.AddCategoryMapping(1717, NewznabStandardCategory.XXX, "Зарубежные фильмы в высоком качестве (DVD&HD) / Full Length ..");
caps.Categories.AddCategoryMapping(1674, NewznabStandardCategory.XXX, "Русское порно / Russian Video");
caps.Categories.AddCategoryMapping(1677, NewznabStandardCategory.XXX, "Зарубежные порноролики / Clips");
caps.Categories.AddCategoryMapping(1800, NewznabStandardCategory.XXX, "Японское порно / Japanese Adult Video (JAV)");
caps.Categories.AddCategoryMapping(1815, NewznabStandardCategory.XXX, "Архив (Японское порно)");
caps.Categories.AddCategoryMapping(1723, NewznabStandardCategory.XXX, "Эротические студиифото и журналы / Erotic Picture Gallery ..");
caps.Categories.AddCategoryMapping(1802, NewznabStandardCategory.XXX, "Архив (Фото)");
caps.Categories.AddCategoryMapping(1745, NewznabStandardCategory.XXX, "Хентай и МангаМультфильмы и Комиксы, Рисунки / Hentai&Ma..");
caps.Categories.AddCategoryMapping(1838, NewznabStandardCategory.XXX, "Игры / Games");
caps.Categories.AddCategoryMapping(1829, NewznabStandardCategory.XXX, "Обсуждение игр / Games Discussion");
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.XXX, "Нетрадиционное порно / Special Interest Movies&Clips");
caps.Categories.AddCategoryMapping(1681, NewznabStandardCategory.XXX, "Дефекация / Scat");
caps.Categories.AddCategoryMapping(1683, NewznabStandardCategory.XXX, "Архив (общий)");
caps.Categories.AddCategoryMapping(1688, NewznabStandardCategory.XXX, "Гей-порно / Gay Forum");
caps.Categories.AddCategoryMapping(1720, NewznabStandardCategory.XXX, "Архив (Гей-порно)");
return caps;
}
} }
public class PornoLabRequestGenerator : IIndexerRequestGenerator public class PornoLabRequestGenerator : IIndexerRequestGenerator
@@ -15,7 +15,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -26,11 +25,17 @@ namespace NzbDrone.Core.Indexers.Definitions
public class PreToMe : TorrentIndexerBase<PreToMeSettings> public class PreToMe : TorrentIndexerBase<PreToMeSettings>
{ {
public override string Name => "PreToMe"; public override string Name => "PreToMe";
public override string[] IndexerUrls => new string[] { "https://pretome.info/" };
public override string Description => "PreToMe is a ratioless 0Day/General tracker.";
private string LoginUrl => Settings.BaseUrl + "takelogin.php"; private string LoginUrl => Settings.BaseUrl + "takelogin.php";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1");
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public PreToMe(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public PreToMe(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -91,6 +96,90 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping("cat[]=22", NewznabStandardCategory.PC, "Applications");
caps.Categories.AddCategoryMapping("cat[]=22&tags=Windows", NewznabStandardCategory.PC0day, "Applications/Windows");
caps.Categories.AddCategoryMapping("cat[]=22&tags=MAC", NewznabStandardCategory.PCMac, "Applications/MAC");
caps.Categories.AddCategoryMapping("cat[]=22&tags=Linux", NewznabStandardCategory.PC, "Applications/Linux");
caps.Categories.AddCategoryMapping("cat[]=27", NewznabStandardCategory.BooksEBook, "Ebooks");
caps.Categories.AddCategoryMapping("cat[]=4", NewznabStandardCategory.Console, "Games");
caps.Categories.AddCategoryMapping("cat[]=4&tags=PC", NewznabStandardCategory.PCGames, "Games/PC");
caps.Categories.AddCategoryMapping("cat[]=4&tags=RIP", NewznabStandardCategory.PCGames, "Games/RIP");
caps.Categories.AddCategoryMapping("cat[]=4&tags=ISO", NewznabStandardCategory.PCGames, "Games/ISO");
caps.Categories.AddCategoryMapping("cat[]=4&tags=XBOX360", NewznabStandardCategory.ConsoleXBox360, "Games/XBOX360");
caps.Categories.AddCategoryMapping("cat[]=4&tags=PS3", NewznabStandardCategory.ConsolePS3, "Games/PS3");
caps.Categories.AddCategoryMapping("cat[]=4&tags=Wii", NewznabStandardCategory.ConsoleWii, "Games/Wii");
caps.Categories.AddCategoryMapping("cat[]=4&tags=PSP", NewznabStandardCategory.ConsolePSP, "Games/PSP");
caps.Categories.AddCategoryMapping("cat[]=4&tags=GAMES-NSW", NewznabStandardCategory.ConsoleOther, "Games/NSW");
caps.Categories.AddCategoryMapping("cat[]=4&tags=NDS", NewznabStandardCategory.ConsoleNDS, "Games/NDS");
caps.Categories.AddCategoryMapping("cat[]=4&tags=Xbox", NewznabStandardCategory.ConsoleXBox, "Games/Xbox");
caps.Categories.AddCategoryMapping("cat[]=4&tags=NSW", NewznabStandardCategory.ConsoleOther, "Games/NSW");
caps.Categories.AddCategoryMapping("cat[]=4&tags=PS2", NewznabStandardCategory.ConsoleOther, "Games/PS2");
caps.Categories.AddCategoryMapping("cat[]=31", NewznabStandardCategory.Other, "Miscellaneous");
caps.Categories.AddCategoryMapping("cat[]=31&tags=Ebook", NewznabStandardCategory.BooksEBook, "Miscellaneous/Ebook");
caps.Categories.AddCategoryMapping("cat[]=31&tags=RARFiX", NewznabStandardCategory.Other, "Miscellaneous/RARFiX");
caps.Categories.AddCategoryMapping("cat[]=19", NewznabStandardCategory.Movies, "Movies");
caps.Categories.AddCategoryMapping("cat[]=19&tags=x264", NewznabStandardCategory.Movies, "Movies/x264");
caps.Categories.AddCategoryMapping("cat[]=19&tags=720p", NewznabStandardCategory.MoviesHD, "Movies/720p");
caps.Categories.AddCategoryMapping("cat[]=19&tags=XviD", NewznabStandardCategory.MoviesSD, "Movies/XviD");
caps.Categories.AddCategoryMapping("cat[]=19&tags=BluRay", NewznabStandardCategory.MoviesHD, "Movies/BluRay");
caps.Categories.AddCategoryMapping("cat[]=19&tags=DVDRiP", NewznabStandardCategory.MoviesSD, "Movies/DVDRiP");
caps.Categories.AddCategoryMapping("cat[]=19&tags=1080p", NewznabStandardCategory.MoviesHD, "Movies/1080p");
caps.Categories.AddCategoryMapping("cat[]=19&tags=DVD", NewznabStandardCategory.MoviesSD, "Movies/DVD");
caps.Categories.AddCategoryMapping("cat[]=19&tags=DVDR", NewznabStandardCategory.MoviesSD, "Movies/DVDR");
caps.Categories.AddCategoryMapping("cat[]=19&tags=WMV", NewznabStandardCategory.Movies, "Movies/WMV");
caps.Categories.AddCategoryMapping("cat[]=19&tags=CAM", NewznabStandardCategory.Movies, "Movies/CAM");
caps.Categories.AddCategoryMapping("cat[]=6", NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping("cat[]=6&tags=MP3", NewznabStandardCategory.AudioMP3, "Music/MP3");
caps.Categories.AddCategoryMapping("cat[]=6&tags=V2", NewznabStandardCategory.AudioMP3, "Music/V2");
caps.Categories.AddCategoryMapping("cat[]=6&tags=FLAC", NewznabStandardCategory.AudioLossless, "Music/FLAC");
caps.Categories.AddCategoryMapping("cat[]=6&tags=320kbps", NewznabStandardCategory.AudioMP3, "Music/320kbps");
caps.Categories.AddCategoryMapping("cat[]=7", NewznabStandardCategory.TV, "TV");
caps.Categories.AddCategoryMapping("cat[]=7&tags=x264", NewznabStandardCategory.TVHD, "TV/x264");
caps.Categories.AddCategoryMapping("cat[]=7&tags=720p", NewznabStandardCategory.TVHD, "TV/720p");
caps.Categories.AddCategoryMapping("cat[]=7&tags=HDTV", NewznabStandardCategory.TVHD, "TV/HDTV");
caps.Categories.AddCategoryMapping("cat[]=7&tags=XviD", NewznabStandardCategory.TVSD, "TV/XviD");
caps.Categories.AddCategoryMapping("cat[]=7&tags=BluRay", NewznabStandardCategory.TVHD, "TV/BluRay");
caps.Categories.AddCategoryMapping("cat[]=7&tags=DVDRiP", NewznabStandardCategory.TVSD, "TV/DVDRiP");
caps.Categories.AddCategoryMapping("cat[]=7&tags=DVD", NewznabStandardCategory.TVSD, "TV/DVD");
caps.Categories.AddCategoryMapping("cat[]=7&tags=Documentary", NewznabStandardCategory.TVDocumentary, "TV/Documentary");
caps.Categories.AddCategoryMapping("cat[]=7&tags=PDTV", NewznabStandardCategory.TVSD, "TV/PDTV");
caps.Categories.AddCategoryMapping("cat[]=7&tags=HD-DVD", NewznabStandardCategory.TVSD, "TV/HD-DVD");
caps.Categories.AddCategoryMapping("cat[]=51", NewznabStandardCategory.XXX, "XXX");
caps.Categories.AddCategoryMapping("cat[]=51&tags=XviD", NewznabStandardCategory.XXXXviD, "XXX/XviD");
caps.Categories.AddCategoryMapping("cat[]=51&tags=DVDRiP", NewznabStandardCategory.XXXDVD, "XXX/DVDRiP");
return caps;
}
} }
public class PreToMeRequestGenerator : IIndexerRequestGenerator public class PreToMeRequestGenerator : IIndexerRequestGenerator
@@ -166,6 +255,8 @@ namespace NzbDrone.Core.Indexers.Definitions
var request = new IndexerRequest(searchUrl, HttpAccept.Html); var request = new IndexerRequest(searchUrl, HttpAccept.Html);
request.HttpRequest.AllowAutoRedirect = false;
yield return request; yield return request;
} }
@@ -0,0 +1,63 @@
using System.Collections.Generic;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Definitions.Avistaz;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions
{
public class PrivateHD : Avistaz.AvistazBase
{
public override string Name => "PrivateHD";
public override string[] IndexerUrls => new string[] { "https://privatehd.to/" };
public override string Description => "PrivateHD is a Private Torrent Tracker for HD MOVIES / TV and the sister-site of AvistaZ, CinemaZ, ExoticaZ, and AnimeTorrents";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public PrivateHD(IIndexerRepository indexerRepository, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(indexerRepository, httpClient, eventAggregator, indexerStatusService, configService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new AvistazRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
Logger = _logger,
Capabilities = Capabilities
};
}
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId, TvSearchParam.Genre
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.Genre
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesUHD);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesHD);
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVUHD);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVHD);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD);
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio);
return caps;
}
}
}
@@ -1,6 +1,11 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http.Json;
using System.Threading.Tasks;
using System.Web;
using Newtonsoft.Json;
using NLog; using NLog;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@@ -8,8 +13,9 @@ using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions; using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Http.CloudFlare; using NzbDrone.Core.Http.CloudFlare;
using NzbDrone.Core.IndexerVersions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Rarbg namespace NzbDrone.Core.Indexers.Rarbg
@@ -19,13 +25,19 @@ namespace NzbDrone.Core.Indexers.Rarbg
private readonly IRarbgTokenProvider _tokenProvider; private readonly IRarbgTokenProvider _tokenProvider;
public override string Name => "Rarbg"; public override string Name => "Rarbg";
public override string[] IndexerUrls => new string[] { "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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override TimeSpan RateLimit => TimeSpan.FromSeconds(2); public override TimeSpan RateLimit => TimeSpan.FromSeconds(2);
public Rarbg(IRarbgTokenProvider tokenProvider, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public Rarbg(IRarbgTokenProvider tokenProvider, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
_tokenProvider = tokenProvider; _tokenProvider = tokenProvider;
} }
@@ -40,6 +52,107 @@ namespace NzbDrone.Core.Indexers.Rarbg
return new RarbgParser(Capabilities); return new RarbgParser(Capabilities);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.XXX, "XXX (18+)");
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.MoviesSD, "Movies/XVID");
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.MoviesSD, "Movies/x264");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.TVSD, "TV Episodes");
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.AudioMP3, "Music/MP3");
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.AudioLossless, "Music/FLAC");
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.PCGames, "Games/PC ISO");
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.PCGames, "Games/PC RIP");
caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.ConsoleXBox360, "Games/XBOX-360");
caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.PCISO, "Software/PC ISO");
caps.Categories.AddCategoryMapping(40, NewznabStandardCategory.ConsolePS3, "Games/PS3");
caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.TVHD, "TV HD Episodes");
caps.Categories.AddCategoryMapping(42, NewznabStandardCategory.MoviesBluRay, "Movies/Full BD");
caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.MoviesHD, "Movies/x264/1080");
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.MoviesHD, "Movies/x264/720");
caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.MoviesBluRay, "Movies/BD Remux");
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.Movies3D, "Movies/x264/3D");
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.MoviesHD, "Movies/XVID/720");
caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.TVUHD, "TV UHD Episodes");
// torrentapi.org returns "Movies/TV-UHD-episodes" for some reason
// possibly because thats what the category is called on the /top100.php page
caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.TVUHD, "Movies/TV-UHD-episodes");
caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.MoviesUHD, "Movies/x264/4k");
caps.Categories.AddCategoryMapping(51, NewznabStandardCategory.MoviesUHD, "Movies/x265/4k");
caps.Categories.AddCategoryMapping(52, NewznabStandardCategory.MoviesUHD, "Movs/x265/4k/HDR");
caps.Categories.AddCategoryMapping(53, NewznabStandardCategory.ConsolePS4, "Games/PS4");
caps.Categories.AddCategoryMapping(54, NewznabStandardCategory.MoviesHD, "Movies/x265/1080");
return caps;
}
protected override async Task<IndexerQueryResult> FetchPage(IndexerRequest request, IParseIndexerResponse parser)
{
var response = await FetchIndexerResponse(request);
// try and recover from token or rate limit errors
var jsonResponse = new HttpResponse<RarbgResponse>(response.HttpResponse);
if (jsonResponse.Resource.error_code.HasValue)
{
if (jsonResponse.Resource.error_code == 4 || jsonResponse.Resource.error_code == 2)
{
_logger.Debug("Invalid or expired token, refreshing token from Rarbg");
_tokenProvider.ExpireToken(Settings);
var newToken = _tokenProvider.GetToken(Settings);
var qs = HttpUtility.ParseQueryString(request.HttpRequest.Url.Query);
qs.Set("token", newToken);
request.HttpRequest.Url = request.Url.SetQuery(qs.GetQueryString());
response = await FetchIndexerResponse(request);
}
else if (jsonResponse.Resource.error_code == 5 || jsonResponse.Resource.rate_limit.HasValue)
{
_logger.Debug("Rarbg rate limit hit, retying request");
response = await FetchIndexerResponse(request);
}
}
try
{
var releases = parser.ParseResponse(response).ToList();
if (releases.Count == 0)
{
_logger.Trace(response.Content);
}
return new IndexerQueryResult
{
Releases = releases,
Response = response.HttpResponse
};
}
catch (Exception ex)
{
ex.WithData(response.HttpResponse, 128 * 1024);
_logger.Trace("Unexpected Response content ({0} bytes): {1}", response.HttpResponse.ResponseData.Length, response.HttpResponse.Content);
throw;
}
}
public override object RequestAction(string action, IDictionary<string, string> query) public override object RequestAction(string action, IDictionary<string, string> query)
{ {
if (action == "checkCaptcha") if (action == "checkCaptcha")
@@ -40,9 +40,11 @@ namespace NzbDrone.Core.Indexers.Rarbg
if (jsonResponse.Resource.error_code.HasValue) if (jsonResponse.Resource.error_code.HasValue)
{ {
if (jsonResponse.Resource.error_code == 20 || jsonResponse.Resource.error_code == 8 if (jsonResponse.Resource.error_code == 20 || jsonResponse.Resource.error_code == 8
|| jsonResponse.Resource.error_code == 9 || jsonResponse.Resource.error_code == 10) || jsonResponse.Resource.error_code == 9 || jsonResponse.Resource.error_code == 10
|| jsonResponse.Resource.error_code == 5 || jsonResponse.Resource.error_code == 13
|| jsonResponse.Resource.error_code == 14)
{ {
// No results or imdbid not found // No results, rate limit, or imdbid/tvdb not found
return results; return results;
} }
@@ -36,7 +36,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
{ {
requestBuilder.AddQueryParam("search_themoviedb", tmdbId); requestBuilder.AddQueryParam("search_themoviedb", tmdbId);
} }
else if (tvdbId.HasValue && tmdbId > 0) else if (tvdbId.HasValue && tvdbId > 0)
{ {
requestBuilder.AddQueryParam("search_tvdb", tvdbId); requestBuilder.AddQueryParam("search_tvdb", tvdbId);
} }
@@ -60,7 +60,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
} }
requestBuilder.AddQueryParam("limit", "100"); requestBuilder.AddQueryParam("limit", "100");
requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings, Settings.BaseUrl)); requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings));
requestBuilder.AddQueryParam("format", "json_extended"); requestBuilder.AddQueryParam("format", "json_extended");
requestBuilder.AddQueryParam("app_id", BuildInfo.AppName); requestBuilder.AddQueryParam("app_id", BuildInfo.AppName);
@@ -69,42 +69,36 @@ namespace NzbDrone.Core.Indexers.Rarbg
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{ {
var request = GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories, searchCriteria.FullImdbId, searchCriteria.TmdbId); var pageableRequests = new IndexerPageableRequestChain();
return GetRequestChain(request, 2); pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories, searchCriteria.FullImdbId, searchCriteria.TmdbId));
return pageableRequests;
} }
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{ {
var request = GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories); var pageableRequests = new IndexerPageableRequestChain();
return GetRequestChain(request, 2); pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories));
return pageableRequests;
} }
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{ {
var request = GetRequest(searchCriteria.SanitizedTvSearchString, searchCriteria.Categories, searchCriteria.FullImdbId, tvdbId: searchCriteria.TvdbId); var pageableRequests = new IndexerPageableRequestChain();
return GetRequestChain(request, 2); pageableRequests.Add(GetRequest(searchCriteria.SanitizedTvSearchString, searchCriteria.Categories, searchCriteria.FullImdbId, tvdbId: searchCriteria.TvdbId));
return pageableRequests;
} }
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
{ {
var request = GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories); var pageableRequests = new IndexerPageableRequestChain();
return GetRequestChain(request, 2); pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories));
return pageableRequests;
} }
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria) public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{
var request = GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories);
return GetRequestChain(request, 2);
}
private IndexerPageableRequestChain GetRequestChain(IEnumerable<IndexerRequest> requests, int retry)
{ {
var pageableRequests = new IndexerPageableRequestChain(); var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetRequest(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories));
for (int i = 0; i < retry; i++)
{
pageableRequests.AddTier(requests);
}
return pageableRequests; return pageableRequests;
} }
@@ -7,6 +7,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
{ {
public string error { get; set; } public string error { get; set; }
public int? error_code { get; set; } public int? error_code { get; set; }
public int? rate_limit { get; set; }
public List<RarbgTorrent> torrent_results { get; set; } public List<RarbgTorrent> torrent_results { get; set; }
} }
@@ -3,14 +3,14 @@ using Newtonsoft.Json.Linq;
using NLog; using NLog;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
namespace NzbDrone.Core.Indexers.Rarbg namespace NzbDrone.Core.Indexers.Rarbg
{ {
public interface IRarbgTokenProvider public interface IRarbgTokenProvider
{ {
string GetToken(RarbgSettings settings, string baseUrl); string GetToken(RarbgSettings settings);
void ExpireToken(RarbgSettings settings);
} }
public class RarbgTokenProvider : IRarbgTokenProvider public class RarbgTokenProvider : IRarbgTokenProvider
@@ -26,12 +26,17 @@ namespace NzbDrone.Core.Indexers.Rarbg
_logger = logger; _logger = logger;
} }
public string GetToken(RarbgSettings settings, string baseUrl) public void ExpireToken(RarbgSettings settings)
{ {
return _tokenCache.Get(baseUrl, _tokenCache.Remove(settings.BaseUrl);
}
public string GetToken(RarbgSettings settings)
{
return _tokenCache.Get(settings.BaseUrl,
() => () =>
{ {
var requestBuilder = new HttpRequestBuilder(baseUrl.Trim('/')) var requestBuilder = new HttpRequestBuilder(settings.BaseUrl.Trim('/'))
.WithRateLimit(3.0) .WithRateLimit(3.0)
.Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}") .Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}")
.Accept(HttpAccept.Json); .Accept(HttpAccept.Json);
@@ -15,7 +15,6 @@ using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Gazelle; using NzbDrone.Core.Indexers.Gazelle;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -26,11 +25,17 @@ namespace NzbDrone.Core.Indexers.Definitions
public class Redacted : TorrentIndexerBase<RedactedSettings> public class Redacted : TorrentIndexerBase<RedactedSettings>
{ {
public override string Name => "Redacted"; public override string Name => "Redacted";
public override string[] IndexerUrls => new string[] { "https://redacted.ch/" };
public override string Description => "REDActed (Aka.PassTheHeadPhones) is one of the most well-known music trackers.";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override bool SupportsRedirect => true; public override bool SupportsRedirect => true;
public Redacted(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public Redacted(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -44,6 +49,39 @@ namespace NzbDrone.Core.Indexers.Definitions
return new RedactedParser(Settings, Capabilities.Categories); return new RedactedParser(Settings, Capabilities.Categories);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q, MusicSearchParam.Album, MusicSearchParam.Artist, MusicSearchParam.Label, MusicSearchParam.Year
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PC, "Applications");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.BooksEBook, "E-Books");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.AudioAudiobook, "Audiobooks");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Other, "E-Learning Videos");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.Other, "Comedy");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.BooksComics, "Comics");
return caps;
}
protected override async Task Test(List<ValidationFailure> failures) protected override async Task Test(List<ValidationFailure> failures)
{ {
((RedactedRequestGenerator)GetRequestGenerator()).FetchPasskey(); ((RedactedRequestGenerator)GetRequestGenerator()).FetchPasskey();
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions
{
public class RetroFlix : SpeedAppBase
{
public override string Name => "RetroFlix";
public override string[] IndexerUrls => new string[] { "https://retroflix.net/" };
public override string Description => "Private Torrent Tracker for Classic Movies / TV / General Releases";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.1);
public RetroFlix(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger, indexerRepository)
{
}
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q,
TvSearchParam.Season,
TvSearchParam.Ep,
TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q,
MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q,
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q,
},
};
caps.Categories.AddCategoryMapping(401, NewznabStandardCategory.Movies, "Movies");
caps.Categories.AddCategoryMapping(402, NewznabStandardCategory.TV, "TV Series");
caps.Categories.AddCategoryMapping(406, NewznabStandardCategory.AudioVideo, "Music Videos");
caps.Categories.AddCategoryMapping(407, NewznabStandardCategory.TVSport, "Sports");
caps.Categories.AddCategoryMapping(409, NewznabStandardCategory.Books, "Books");
caps.Categories.AddCategoryMapping(408, NewznabStandardCategory.Audio, "HQ Audio");
return caps;
}
}
}
@@ -15,7 +15,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -27,11 +26,15 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
public override string Name => "RevolutionTT"; public override string Name => "RevolutionTT";
public override string[] IndexerUrls => new string[] { "https://revolutiontt.me/" };
public override string Description => "The Revolution has begun";
private string LoginUrl => Settings.BaseUrl + "takelogin.php"; private string LoginUrl => Settings.BaseUrl + "takelogin.php";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public RevolutionTT(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public RevolutionTT(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -90,6 +93,64 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping("23", NewznabStandardCategory.TVAnime);
caps.Categories.AddCategoryMapping("22", NewznabStandardCategory.PC0day);
caps.Categories.AddCategoryMapping("1", NewznabStandardCategory.PCISO);
caps.Categories.AddCategoryMapping("36", NewznabStandardCategory.Books);
caps.Categories.AddCategoryMapping("36", NewznabStandardCategory.BooksEBook);
caps.Categories.AddCategoryMapping("4", NewznabStandardCategory.PCGames);
caps.Categories.AddCategoryMapping("21", NewznabStandardCategory.PCGames);
caps.Categories.AddCategoryMapping("16", NewznabStandardCategory.ConsolePS3);
caps.Categories.AddCategoryMapping("40", NewznabStandardCategory.ConsoleWii);
caps.Categories.AddCategoryMapping("39", NewznabStandardCategory.ConsoleXBox360);
caps.Categories.AddCategoryMapping("35", NewznabStandardCategory.ConsoleNDS);
caps.Categories.AddCategoryMapping("34", NewznabStandardCategory.ConsolePSP);
caps.Categories.AddCategoryMapping("2", NewznabStandardCategory.PCMac);
caps.Categories.AddCategoryMapping("10", NewznabStandardCategory.MoviesBluRay);
caps.Categories.AddCategoryMapping("20", NewznabStandardCategory.MoviesDVD);
caps.Categories.AddCategoryMapping("12", NewznabStandardCategory.MoviesHD);
caps.Categories.AddCategoryMapping("44", NewznabStandardCategory.MoviesOther);
caps.Categories.AddCategoryMapping("11", NewznabStandardCategory.MoviesSD);
caps.Categories.AddCategoryMapping("19", NewznabStandardCategory.MoviesSD);
caps.Categories.AddCategoryMapping("6", NewznabStandardCategory.Audio);
caps.Categories.AddCategoryMapping("8", NewznabStandardCategory.AudioLossless);
caps.Categories.AddCategoryMapping("46", NewznabStandardCategory.AudioOther);
caps.Categories.AddCategoryMapping("29", NewznabStandardCategory.AudioVideo);
caps.Categories.AddCategoryMapping("43", NewznabStandardCategory.TVOther);
caps.Categories.AddCategoryMapping("42", NewznabStandardCategory.TVHD);
caps.Categories.AddCategoryMapping("45", NewznabStandardCategory.TVOther);
caps.Categories.AddCategoryMapping("41", NewznabStandardCategory.TVSD);
caps.Categories.AddCategoryMapping("7", NewznabStandardCategory.TVSD);
caps.Categories.AddCategoryMapping("9", NewznabStandardCategory.XXX);
caps.Categories.AddCategoryMapping("49", NewznabStandardCategory.XXX);
caps.Categories.AddCategoryMapping("47", NewznabStandardCategory.XXXDVD);
caps.Categories.AddCategoryMapping("48", NewznabStandardCategory.XXX);
return caps;
}
} }
public class RevolutionTTRequestGenerator : IIndexerRequestGenerator public class RevolutionTTRequestGenerator : IIndexerRequestGenerator
@@ -133,6 +194,8 @@ namespace NzbDrone.Core.Indexers.Definitions
var request = new IndexerRequest(searchUrl, HttpAccept.Html); var request = new IndexerRequest(searchUrl, HttpAccept.Html);
request.HttpRequest.AllowAutoRedirect = false;
yield return request; yield return request;
} }
File diff suppressed because it is too large Load Diff
@@ -14,7 +14,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -25,10 +24,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class SceneHD : TorrentIndexerBase<SceneHDSettings> public class SceneHD : TorrentIndexerBase<SceneHDSettings>
{ {
public override string Name => "SceneHD"; public override string Name => "SceneHD";
public override string[] IndexerUrls => new[] { "https://scenehd.org/" };
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public SceneHD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public SceneHD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -46,6 +51,40 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesUHD, "Movie/2160");
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesHD, "Movie/1080");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.MoviesHD, "Movie/720");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.MoviesBluRay, "Movie/BD5/9");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.TVUHD, "TV/2160");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVHD, "TV/1080");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TVHD, "TV/720");
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.MoviesBluRay, "Bluray/Complete");
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.XXX, "XXX");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.MoviesOther, "Subpacks");
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.AudioVideo, "MVID");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.Other, "Other");
return caps;
}
} }
public class SceneHDRequestGenerator : IIndexerRequestGenerator public class SceneHDRequestGenerator : IIndexerRequestGenerator
@@ -13,7 +13,6 @@ using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -24,10 +23,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class SceneTime : TorrentIndexerBase<SceneTimeSettings> public class SceneTime : TorrentIndexerBase<SceneTimeSettings>
{ {
public override string Name => "SceneTime"; public override string Name => "SceneTime";
public override string[] IndexerUrls => new[] { "https://www.scenetime.com/" };
public override string Description => "Always on time";
public override string Language => "en-US";
public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1");
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public SceneTime(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public SceneTime(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -45,6 +50,61 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
return CookieUtil.CookieHeaderToDictionary(Settings.Cookie); return CookieUtil.CookieHeaderToDictionary(Settings.Cookie);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.XXX, "Movies Adult");
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.Movies, "Movie Packs");
caps.Categories.AddCategoryMapping(57, NewznabStandardCategory.MoviesSD, "Movies SD");
caps.Categories.AddCategoryMapping(59, NewznabStandardCategory.MoviesHD, "Movies HD");
caps.Categories.AddCategoryMapping(64, NewznabStandardCategory.Movies3D, "Movies 3D");
caps.Categories.AddCategoryMapping(82, NewznabStandardCategory.MoviesOther, "Movies CAM-TS");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.MoviesUHD, "Movies UHD");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVUHD, "TV UHD");
caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.TV, "TV Packs");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVHD, "TV HD");
caps.Categories.AddCategoryMapping(77, NewznabStandardCategory.TVSD, "TV SD");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.PCGames, "Games PC ISO");
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.ConsoleXBox, "Games XBOX");
caps.Categories.AddCategoryMapping(51, NewznabStandardCategory.ConsoleWii, "Games Wii");
caps.Categories.AddCategoryMapping(55, NewznabStandardCategory.ConsoleNDS, "Games Nintendo DS");
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.ConsolePS4, "Games/PS");
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.ConsoleOther, "Games Dreamcast");
caps.Categories.AddCategoryMapping(52, NewznabStandardCategory.PCMac, "Mac/Linux");
caps.Categories.AddCategoryMapping(53, NewznabStandardCategory.PC0day, "Apps");
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.PCMobileOther, "Mobile Apps");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Books, "Books and Magazines");
caps.Categories.AddCategoryMapping(65, NewznabStandardCategory.BooksComics, "Books Comic");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping(116, NewznabStandardCategory.Audio, "Music Pack");
caps.Flags = new List<IndexerFlag>
{
IndexerFlag.FreeLeech
};
return caps;
}
} }
public class SceneTimeRequestGenerator : IIndexerRequestGenerator public class SceneTimeRequestGenerator : IIndexerRequestGenerator
@@ -16,7 +16,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Gazelle; using NzbDrone.Core.Indexers.Gazelle;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -27,10 +26,14 @@ namespace NzbDrone.Core.Indexers.Definitions
public class SecretCinema : Gazelle.Gazelle public class SecretCinema : Gazelle.Gazelle
{ {
public override string Name => "Secret Cinema"; public override string Name => "Secret Cinema";
public override string[] IndexerUrls => new string[] { "https://secret-cinema.pw/" };
public override string Description => "A tracker for rare movies.";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public SecretCinema(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public SecretCinema(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -39,6 +42,26 @@ namespace NzbDrone.Core.Indexers.Definitions
return new SecretCinemaParser(Settings, Capabilities); return new SecretCinemaParser(Settings, Capabilities);
} }
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q, MusicSearchParam.Album, MusicSearchParam.Artist, MusicSearchParam.Label, MusicSearchParam.Year
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.Audio, "Music");
return caps;
}
public class SecretCinemaParser : IParseIndexerResponse public class SecretCinemaParser : IParseIndexerResponse
{ {
protected readonly GazelleSettings _settings; protected readonly GazelleSettings _settings;
@@ -12,7 +12,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -23,10 +22,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public class Shizaproject : TorrentIndexerBase<NoAuthTorrentBaseSettings> public class Shizaproject : TorrentIndexerBase<NoAuthTorrentBaseSettings>
{ {
public override string Name => "ShizaProject"; public override string Name => "ShizaProject";
public override string[] IndexerUrls => new string[] { "https://shiza-project.com/" };
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 DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();
public Shizaproject(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public Shizaproject(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -39,6 +44,28 @@ namespace NzbDrone.Core.Indexers.Definitions
{ {
return new ShizaprojectParser(Settings, Capabilities.Categories); return new ShizaprojectParser(Settings, Capabilities.Categories);
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TVAnime, "TV");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVAnime, "TV_SPECIAL");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVAnime, "ONA");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.TVAnime, "OVA");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Movies, "MOVIE");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.Movies, "SHORT_MOVIE");
return caps;
}
} }
public class ShizaprojectRequestGenerator : IIndexerRequestGenerator public class ShizaprojectRequestGenerator : IIndexerRequestGenerator
@@ -1,525 +1,97 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using FluentValidation;
using Newtonsoft.Json;
using NLog; using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions namespace NzbDrone.Core.Indexers.Definitions
{ {
public class SpeedApp : TorrentIndexerBase<SpeedAppSettings> public class SpeedApp : SpeedAppBase
{ {
public override string Name => "SpeedApp.io"; public override string Name => "SpeedApp.io";
private string ApiUrl => $"{Settings.BaseUrl}/api"; public override string[] IndexerUrls => new string[] { "https://speedapp.io" };
private string LoginUrl => $"{ApiUrl}/login"; public override string Description => "SpeedApp is a ROMANIAN Private Torrent Tracker for MOVIES / TV / GENERAL";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override string Language => "ro-RO";
private IIndexerRepository _indexerRepository; public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public SpeedApp(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository) public SpeedApp(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository)
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) : base(httpClient, eventAggregator, indexerStatusService, configService, logger, indexerRepository)
{ {
_indexerRepository = indexerRepository;
} }
public override IIndexerRequestGenerator GetRequestGenerator() protected override IndexerCapabilities SetCapabilities()
{ {
return new SpeedAppRequestGenerator(Capabilities, Settings); var caps = new IndexerCapabilities
}
public override IParseIndexerResponse GetParser()
{
return new SpeedAppParser(Settings, Capabilities.Categories);
}
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return Settings.ApiKey.IsNullOrWhiteSpace() || httpResponse.StatusCode == HttpStatusCode.Unauthorized;
}
protected override async Task DoLogin()
{
var requestBuilder = new HttpRequestBuilder(LoginUrl)
{ {
LogResponseContent = true, TvSearchParams = new List<TvSearchParam>
AllowAutoRedirect = true, {
Method = HttpMethod.Post, TvSearchParam.Q,
TvSearchParam.Season,
TvSearchParam.Ep,
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q,
MovieSearchParam.ImdbId,
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q,
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q,
},
}; };
var request = requestBuilder.Build(); caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.Movies, "Movie Packs");
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.MoviesSD, "Movies: SD");
caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.MoviesSD, "Movies: SD Ro");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.MoviesHD, "Movies: HD");
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.MoviesHD, "Movies: HD Ro");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.MoviesDVD, "Movies: DVD");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesDVD, "Movies: DVD Ro");
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.MoviesBluRay, "Movies: BluRay");
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.MoviesBluRay, "Movies: BluRay Ro");
caps.Categories.AddCategoryMapping(59, NewznabStandardCategory.Movies, "Movies: Ro");
caps.Categories.AddCategoryMapping(57, NewznabStandardCategory.MoviesUHD, "Movies: 4K (2160p) Ro");
caps.Categories.AddCategoryMapping(61, NewznabStandardCategory.MoviesUHD, "Movies: 4K (2160p)");
caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.TV, "TV Packs");
caps.Categories.AddCategoryMapping(66, NewznabStandardCategory.TV, "TV Packs Ro");
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.TVSD, "TV Episodes");
caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.TVSD, "TV Episodes Ro");
caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.TVHD, "TV Episodes HD");
caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.TVHD, "TV Episodes HD Ro");
caps.Categories.AddCategoryMapping(60, NewznabStandardCategory.TV, "TV Ro");
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.PCGames, "Games: PC-ISO");
caps.Categories.AddCategoryMapping(52, NewznabStandardCategory.Console, "Games: Console");
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.PC0day, "Applications");
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.PC, "Applications: Linux");
caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.PCMac, "Applications: Mac");
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.PCMobileOther, "Applications: Mobile");
caps.Categories.AddCategoryMapping(62, NewznabStandardCategory.TV, "TV Cartoons");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVAnime, "TV Anime / Hentai");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.BooksEBook, "E-books");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping(64, NewznabStandardCategory.AudioVideo, "Music Video");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.Other, "Images");
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.TVSport, "TV Sports");
caps.Categories.AddCategoryMapping(58, NewznabStandardCategory.TVSport, "TV Sports Ro");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVDocumentary, "TV Documentary");
caps.Categories.AddCategoryMapping(63, NewznabStandardCategory.TVDocumentary, "TV Documentary Ro");
caps.Categories.AddCategoryMapping(65, NewznabStandardCategory.Other, "Tutorial");
caps.Categories.AddCategoryMapping(67, NewznabStandardCategory.OtherMisc, "Miscellaneous");
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.XXX, "XXX Movies");
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.XXX, "XXX DVD");
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.XXX, "XXX HD");
caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.XXXImageSet, "XXX Images");
caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.XXX, "XXX Packs");
caps.Categories.AddCategoryMapping(51, NewznabStandardCategory.XXX, "XXX SD");
var data = new SpeedAppAuthenticationRequest return caps;
{
Email = Settings.Email,
Password = Settings.Password
};
request.SetContent(JsonConvert.SerializeObject(data));
request.Headers.ContentType = MediaTypeNames.Application.Json;
var response = await ExecuteAuth(request);
var statusCode = (int)response.StatusCode;
if (statusCode is < 200 or > 299)
{
throw new HttpException(response);
}
var parsedResponse = JsonConvert.DeserializeObject<SpeedAppAuthenticationResponse>(response.Content);
Settings.ApiKey = parsedResponse.Token;
if (Definition.Id > 0)
{
_indexerRepository.UpdateSettings((IndexerDefinition)Definition);
}
_logger.Debug("SpeedApp authentication succeeded.");
} }
protected override void ModifyRequest(IndexerRequest request)
{
request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}");
}
public override async Task<byte[]> Download(Uri link)
{
Cookies = GetCookies();
if (link.Scheme == "magnet")
{
ValidateMagnet(link.OriginalString);
return Encoding.UTF8.GetBytes(link.OriginalString);
}
var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri);
if (Cookies != null)
{
requestBuilder.SetCookies(Cookies);
}
var request = requestBuilder.Build();
request.AllowAutoRedirect = FollowRedirect;
request.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}");
byte[] torrentData;
try
{
var response = await _httpClient.ExecuteProxiedAsync(request, Definition);
torrentData = response.ResponseData;
}
catch (HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.NotFound)
{
_logger.Error(ex, "Downloading torrent file for release failed since it no longer exists ({0})", link.AbsoluteUri);
throw new ReleaseUnavailableException("Downloading torrent failed", ex);
}
if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests)
{
_logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri);
}
else
{
_logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri);
}
throw new ReleaseDownloadException("Downloading torrent failed", ex);
}
catch (WebException ex)
{
_logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri);
throw new ReleaseDownloadException("Downloading torrent failed", ex);
}
catch (Exception)
{
_indexerStatusService.RecordFailure(Definition.Id);
_logger.Error("Downloading torrent failed");
throw;
}
return torrentData;
}
}
public class SpeedAppRequestGenerator : IIndexerRequestGenerator
{
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
private IndexerCapabilities Capabilities { get; }
private SpeedAppSettings Settings { get; }
public SpeedAppRequestGenerator(IndexerCapabilities capabilities, SpeedAppSettings settings)
{
Capabilities = capabilities;
Settings = settings;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return GetSearch(searchCriteria, searchCriteria.FullImdbId);
}
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{
return GetSearch(searchCriteria);
}
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{
return GetSearch(searchCriteria, searchCriteria.FullImdbId, searchCriteria.Season, searchCriteria.Episode);
}
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
{
return GetSearch(searchCriteria);
}
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{
return GetSearch(searchCriteria);
}
private IndexerPageableRequestChain GetSearch(SearchCriteriaBase searchCriteria, string imdbId = null, int? season = null, string episode = null)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories, imdbId, season, episode));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null, int? season = null, string episode = null)
{
var qc = new NameValueCollection();
if (imdbId.IsNotNullOrWhiteSpace())
{
qc.Add("imdbId", imdbId);
}
else
{
qc.Add("search", term);
}
if (season != null)
{
qc.Add("season", season.Value.ToString());
}
if (episode != null)
{
qc.Add("episode", episode);
}
var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories);
if (cats.Count > 0)
{
foreach (var cat in cats)
{
qc.Add("categories[]", cat);
}
}
var searchUrl = Settings.BaseUrl + "/api/torrent?" + qc.GetQueryString(duplicateKeysIfMulti: true);
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}");
yield return request;
}
}
public class SpeedAppParser : IParseIndexerResponse
{
private readonly SpeedAppSettings _settings;
private readonly IndexerCapabilitiesCategories _categories;
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
public SpeedAppParser(SpeedAppSettings settings, IndexerCapabilitiesCategories categories)
{
_settings = settings;
_categories = categories;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
}
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
{
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
}
var jsonResponse = new HttpResponse<List<SpeedAppTorrent>>(indexerResponse.HttpResponse);
return jsonResponse.Resource.Select(torrent => new TorrentInfo
{
Guid = torrent.Id.ToString(),
Title = torrent.Name,
Description = torrent.ShortDescription,
Size = torrent.Size,
ImdbId = ParseUtil.GetImdbID(torrent.ImdbId).GetValueOrDefault(),
DownloadUrl = $"{_settings.BaseUrl}/api/torrent/{torrent.Id}/download",
PosterUrl = torrent.Poster,
InfoUrl = torrent.Url,
Grabs = torrent.TimesCompleted,
PublishDate = torrent.CreatedAt,
Categories = _categories.MapTrackerCatToNewznab(torrent.Category.Id.ToString()),
InfoHash = null,
Seeders = torrent.Seeders,
Peers = torrent.Leechers + torrent.Seeders,
MinimumRatio = 1,
MinimumSeedTime = 172800,
DownloadVolumeFactor = torrent.DownloadVolumeFactor,
UploadVolumeFactor = torrent.UploadVolumeFactor,
}).ToArray();
}
}
public class SpeedAppSettingsValidator : AbstractValidator<SpeedAppSettings>
{
public SpeedAppSettingsValidator()
{
RuleFor(c => c.Email).NotEmpty();
RuleFor(c => c.Password).NotEmpty();
}
}
public class SpeedAppSettings : NoAuthTorrentBaseSettings
{
private static readonly SpeedAppSettingsValidator Validator = new ();
public SpeedAppSettings()
{
Email = "";
Password = "";
}
[FieldDefinition(2, Label = "Email", HelpText = "Site Email", Privacy = PrivacyLevel.UserName)]
public string Email { get; set; }
[FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(4, Label = "API Key", Hidden = HiddenType.Hidden)]
public string ApiKey { get; set; }
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
public class SpeedAppCategory
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
public class SpeedAppCountry
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("flag_image")]
public string FlagImage { get; set; }
}
public class SpeedAppUploadedBy
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("username")]
public string Username { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty("class")]
public int Class { get; set; }
[JsonProperty("avatar")]
public string Avatar { get; set; }
[JsonProperty("uploaded")]
public int Uploaded { get; set; }
[JsonProperty("downloaded")]
public int Downloaded { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("country")]
public SpeedAppCountry Country { get; set; }
[JsonProperty("passkey")]
public string Passkey { get; set; }
[JsonProperty("invites")]
public int Invites { get; set; }
[JsonProperty("timezone")]
public string Timezone { get; set; }
[JsonProperty("hit_and_run_count")]
public int HitAndRunCount { get; set; }
[JsonProperty("snatch_count")]
public int SnatchCount { get; set; }
[JsonProperty("need_seed")]
public int NeedSeed { get; set; }
[JsonProperty("average_seed_time")]
public int AverageSeedTime { get; set; }
[JsonProperty("free_leech_tokens")]
public int FreeLeechTokens { get; set; }
[JsonProperty("double_upload_tokens")]
public int DoubleUploadTokens { get; set; }
}
public class SpeedAppTag
{
[JsonProperty("translated_name")]
public string TranslatedName { get; set; }
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("match_list")]
public List<string> MatchList { get; set; }
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
}
public class SpeedAppTorrent
{
[JsonProperty("download_volume_factor")]
public float DownloadVolumeFactor { get; set; }
[JsonProperty("upload_volume_factor")]
public float UploadVolumeFactor { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("category")]
public SpeedAppCategory Category { get; set; }
[JsonProperty("size")]
public long Size { get; set; }
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty("times_completed")]
public int TimesCompleted { get; set; }
[JsonProperty("leechers")]
public int Leechers { get; set; }
[JsonProperty("seeders")]
public int Seeders { get; set; }
[JsonProperty("uploaded_by")]
public SpeedAppUploadedBy UploadedBy { get; set; }
[JsonProperty("short_description")]
public string ShortDescription { get; set; }
[JsonProperty("poster")]
public string Poster { get; set; }
[JsonProperty("season")]
public int Season { get; set; }
[JsonProperty("episode")]
public int Episode { get; set; }
[JsonProperty("tags")]
public List<SpeedAppTag> Tags { get; set; }
[JsonProperty("imdb_id")]
public string ImdbId { get; set; }
}
public class SpeedAppAuthenticationRequest
{
[JsonProperty("username")]
public string Email { get; set; }
[JsonProperty("password")]
public string Password { get; set; }
}
public class SpeedAppAuthenticationResponse
{
[JsonProperty("token")]
public string Token { get; set; }
} }
} }
@@ -0,0 +1,533 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using FluentValidation;
using Newtonsoft.Json;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
public abstract class SpeedAppBase : TorrentIndexerBase<SpeedAppSettings>
{
private string ApiUrl => $"{Settings.BaseUrl}/api";
private string LoginUrl => $"{ApiUrl}/login";
public override Encoding Encoding => Encoding.UTF8;
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerCapabilities Capabilities => SetCapabilities();
private IIndexerRepository _indexerRepository;
public SpeedAppBase(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{
_indexerRepository = indexerRepository;
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new SpeedAppRequestGenerator(Capabilities, Settings);
}
public override IParseIndexerResponse GetParser()
{
return new SpeedAppParser(Settings, Capabilities.Categories);
}
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return Settings.ApiKey.IsNullOrWhiteSpace() || httpResponse.StatusCode == HttpStatusCode.Unauthorized;
}
protected override async Task DoLogin()
{
var requestBuilder = new HttpRequestBuilder(LoginUrl)
{
LogResponseContent = true,
AllowAutoRedirect = true,
Method = HttpMethod.Post,
};
var request = requestBuilder.Build();
var data = new SpeedAppAuthenticationRequest
{
Email = Settings.Email,
Password = Settings.Password
};
request.SetContent(JsonConvert.SerializeObject(data));
request.Headers.ContentType = MediaTypeNames.Application.Json;
var response = await ExecuteAuth(request);
var statusCode = (int)response.StatusCode;
if (statusCode is < 200 or > 299)
{
throw new HttpException(response);
}
var parsedResponse = JsonConvert.DeserializeObject<SpeedAppAuthenticationResponse>(response.Content);
Settings.ApiKey = parsedResponse.Token;
if (Definition.Id > 0)
{
_indexerRepository.UpdateSettings((IndexerDefinition)Definition);
}
_logger.Debug("SpeedApp authentication succeeded.");
}
protected override void ModifyRequest(IndexerRequest request)
{
request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}");
}
public override async Task<byte[]> Download(Uri link)
{
Cookies = GetCookies();
if (link.Scheme == "magnet")
{
ValidateMagnet(link.OriginalString);
return Encoding.UTF8.GetBytes(link.OriginalString);
}
var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri);
if (Cookies != null)
{
requestBuilder.SetCookies(Cookies);
}
var request = requestBuilder.Build();
request.AllowAutoRedirect = FollowRedirect;
request.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}");
byte[] torrentData;
try
{
var response = await _httpClient.ExecuteProxiedAsync(request, Definition);
torrentData = response.ResponseData;
}
catch (HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.NotFound)
{
_logger.Error(ex, "Downloading torrent file for release failed since it no longer exists ({0})", link.AbsoluteUri);
throw new ReleaseUnavailableException("Downloading torrent failed", ex);
}
if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests)
{
_logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri);
}
else
{
_logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri);
}
throw new ReleaseDownloadException("Downloading torrent failed", ex);
}
catch (WebException ex)
{
_logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri);
throw new ReleaseDownloadException("Downloading torrent failed", ex);
}
catch (Exception)
{
_indexerStatusService.RecordFailure(Definition.Id);
_logger.Error("Downloading torrent failed");
throw;
}
return torrentData;
}
protected virtual IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities();
return caps;
}
}
public class SpeedAppRequestGenerator : IIndexerRequestGenerator
{
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
private IndexerCapabilities Capabilities { get; }
private SpeedAppSettings Settings { get; }
public SpeedAppRequestGenerator(IndexerCapabilities capabilities, SpeedAppSettings settings)
{
Capabilities = capabilities;
Settings = settings;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return GetSearch(searchCriteria, searchCriteria.FullImdbId);
}
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{
return GetSearch(searchCriteria);
}
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{
return GetSearch(searchCriteria, searchCriteria.FullImdbId, searchCriteria.Season, searchCriteria.Episode);
}
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
{
return GetSearch(searchCriteria);
}
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{
return GetSearch(searchCriteria);
}
private IndexerPageableRequestChain GetSearch(SearchCriteriaBase searchCriteria, string imdbId = null, int? season = null, string episode = null)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories, imdbId, season, episode));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null, int? season = null, string episode = null)
{
var qc = new NameValueCollection();
if (imdbId.IsNotNullOrWhiteSpace())
{
qc.Add("imdbId", imdbId);
}
else
{
qc.Add("search", term);
}
if (season != null)
{
qc.Add("season", season.Value.ToString());
}
if (episode != null)
{
qc.Add("episode", episode);
}
var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories);
if (cats.Count > 0)
{
foreach (var cat in cats)
{
qc.Add("categories[]", cat);
}
}
var searchUrl = Settings.BaseUrl + "/api/torrent?" + qc.GetQueryString(duplicateKeysIfMulti: true);
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}");
yield return request;
}
}
public class SpeedAppParser : IParseIndexerResponse
{
private readonly SpeedAppSettings _settings;
private readonly IndexerCapabilitiesCategories _categories;
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
public SpeedAppParser(SpeedAppSettings settings, IndexerCapabilitiesCategories categories)
{
_settings = settings;
_categories = categories;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
}
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
{
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
}
var jsonResponse = new HttpResponse<List<SpeedAppTorrent>>(indexerResponse.HttpResponse);
return jsonResponse.Resource.Select(torrent => new TorrentInfo
{
Guid = torrent.Id.ToString(),
Title = torrent.Name,
Description = torrent.ShortDescription,
Size = torrent.Size,
ImdbId = ParseUtil.GetImdbID(torrent.ImdbId).GetValueOrDefault(),
DownloadUrl = $"{_settings.BaseUrl}/api/torrent/{torrent.Id}/download",
PosterUrl = torrent.Poster,
InfoUrl = torrent.Url,
Grabs = torrent.TimesCompleted,
PublishDate = torrent.CreatedAt,
Categories = _categories.MapTrackerCatToNewznab(torrent.Category.Id.ToString()),
InfoHash = null,
Seeders = torrent.Seeders,
Peers = torrent.Leechers + torrent.Seeders,
MinimumRatio = 1,
MinimumSeedTime = 172800,
DownloadVolumeFactor = torrent.DownloadVolumeFactor,
UploadVolumeFactor = torrent.UploadVolumeFactor,
}).ToArray();
}
}
public class SpeedAppSettingsValidator : AbstractValidator<SpeedAppSettings>
{
public SpeedAppSettingsValidator()
{
RuleFor(c => c.Email).NotEmpty();
RuleFor(c => c.Password).NotEmpty();
}
}
public class SpeedAppSettings : NoAuthTorrentBaseSettings
{
private static readonly SpeedAppSettingsValidator Validator = new ();
public SpeedAppSettings()
{
Email = "";
Password = "";
}
[FieldDefinition(2, Label = "Email", HelpText = "Site Email", Privacy = PrivacyLevel.UserName)]
public string Email { get; set; }
[FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(4, Label = "API Key", Hidden = HiddenType.Hidden)]
public string ApiKey { get; set; }
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
public class SpeedAppCategory
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
public class SpeedAppCountry
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("flag_image")]
public string FlagImage { get; set; }
}
public class SpeedAppUploadedBy
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("username")]
public string Username { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty("class")]
public int Class { get; set; }
[JsonProperty("avatar")]
public string Avatar { get; set; }
[JsonProperty("uploaded")]
public int Uploaded { get; set; }
[JsonProperty("downloaded")]
public int Downloaded { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("country")]
public SpeedAppCountry Country { get; set; }
[JsonProperty("passkey")]
public string Passkey { get; set; }
[JsonProperty("invites")]
public int Invites { get; set; }
[JsonProperty("timezone")]
public string Timezone { get; set; }
[JsonProperty("hit_and_run_count")]
public int HitAndRunCount { get; set; }
[JsonProperty("snatch_count")]
public int SnatchCount { get; set; }
[JsonProperty("need_seed")]
public int NeedSeed { get; set; }
[JsonProperty("average_seed_time")]
public int AverageSeedTime { get; set; }
[JsonProperty("free_leech_tokens")]
public int FreeLeechTokens { get; set; }
[JsonProperty("double_upload_tokens")]
public int DoubleUploadTokens { get; set; }
}
public class SpeedAppTag
{
[JsonProperty("translated_name")]
public string TranslatedName { get; set; }
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("match_list")]
public List<string> MatchList { get; set; }
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
}
public class SpeedAppTorrent
{
[JsonProperty("download_volume_factor")]
public float DownloadVolumeFactor { get; set; }
[JsonProperty("upload_volume_factor")]
public float UploadVolumeFactor { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("category")]
public SpeedAppCategory Category { get; set; }
[JsonProperty("size")]
public long Size { get; set; }
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty("times_completed")]
public int TimesCompleted { get; set; }
[JsonProperty("leechers")]
public int Leechers { get; set; }
[JsonProperty("seeders")]
public int Seeders { get; set; }
[JsonProperty("uploaded_by")]
public SpeedAppUploadedBy UploadedBy { get; set; }
[JsonProperty("short_description")]
public string ShortDescription { get; set; }
[JsonProperty("poster")]
public string Poster { get; set; }
[JsonProperty("season")]
public int Season { get; set; }
[JsonProperty("episode")]
public int Episode { get; set; }
[JsonProperty("tags")]
public List<SpeedAppTag> Tags { get; set; }
[JsonProperty("imdb_id")]
public string ImdbId { get; set; }
}
public class SpeedAppAuthenticationRequest
{
[JsonProperty("username")]
public string Email { get; set; }
[JsonProperty("password")]
public string Password { get; set; }
}
public class SpeedAppAuthenticationResponse
{
[JsonProperty("token")]
public string Token { get; set; }
}
}
@@ -16,7 +16,6 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings; using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.IndexerVersions;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
@@ -27,10 +26,22 @@ namespace NzbDrone.Core.Indexers.Definitions
public class SpeedCD : TorrentIndexerBase<UserPassTorrentBaseSettings> public class SpeedCD : TorrentIndexerBase<UserPassTorrentBaseSettings>
{ {
public override string Name => "SpeedCD"; public override string Name => "SpeedCD";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent; public override string[] IndexerUrls => new string[]
{
"https://speed.cd/",
"https://speed.click/",
"https://speeders.me/"
};
public SpeedCD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IIndexerDefinitionUpdateService definitionService, IConfigService configService, Logger logger) public override string Description => "Your home now!";
: base(httpClient, eventAggregator, indexerStatusService, definitionService, configService, logger) 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 SpeedCD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{ {
} }
@@ -109,6 +120,64 @@ namespace NzbDrone.Core.Indexers.Definitions
return false; return false;
} }
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesOther, "Movies/XviD");
caps.Categories.AddCategoryMapping(42, NewznabStandardCategory.Movies, "Movies/Packs");
caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.Movies, "Movies/Kids");
caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.MoviesHD, "Movies/HD");
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.Movies, "Movies/DiVERSiTY");
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.MoviesBluRay, "Movies/B-Ray");
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.Movies3D, "Movies/3D");
caps.Categories.AddCategoryMapping(40, NewznabStandardCategory.MoviesDVD, "Movies/DVD-R");
caps.Categories.AddCategoryMapping(56, NewznabStandardCategory.Movies, "Movies/Anime");
caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.TVSport, "TV/Sports");
caps.Categories.AddCategoryMapping(52, NewznabStandardCategory.TVHD, "TV/B-Ray");
caps.Categories.AddCategoryMapping(53, NewznabStandardCategory.TVSD, "TV/DVD-R");
caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.TV, "TV/Packs");
caps.Categories.AddCategoryMapping(55, NewznabStandardCategory.TV, "TV/Kids");
caps.Categories.AddCategoryMapping(57, NewznabStandardCategory.TV, "TV/DiVERSiTY");
caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.TVHD, "TV/HD");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD, "TV/Episodes");
caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.TVAnime, "TV/Anime");
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.PCISO, "Games/PC ISO");
caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.ConsoleWii, "Games/Wii");
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.ConsolePS3, "Games/PS3");
caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.Console, "Games/Nintendo");
caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.ConsoleXBox360, "Games/XboX360");
caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.PCMobileOther, "Mobile");
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.PC0day, "Apps/0DAY");
caps.Categories.AddCategoryMapping(51, NewznabStandardCategory.PCMac, "Mac");
caps.Categories.AddCategoryMapping(54, NewznabStandardCategory.Books, "Educational");
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.Books, "Books-Mags");
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.Audio, "Music/Audio");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music/Flac");
caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.Audio, "Music/Pack");
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.AudioVideo, "Music/Video");
return caps;
}
} }
public class SpeedCDRequestGenerator : IIndexerRequestGenerator public class SpeedCDRequestGenerator : IIndexerRequestGenerator

Some files were not shown because too many files have changed in this diff Show More