Compare commits

..

1 Commits

Author SHA1 Message Date
Bakerboy448
5e15054329 Avistaz response improvements 2023-01-05 15:40:22 -06:00
63 changed files with 650 additions and 1177 deletions

View File

@@ -142,8 +142,8 @@ module.exports = (env) => {
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /[\\/]node_modules[\\/](?!(@sentry\/browser|@sentry\/integrations|chart.js|filesize|normalize.css)[\\/])/,
test: /\.js?$/,
exclude: /(node_modules|JsLibraries)/,
use: [
{
loader: 'babel-loader',

View File

@@ -79,7 +79,6 @@ class IndexerIndexRow extends Component {
privacy,
priority,
status,
fields,
appProfile,
added,
capabilities,
@@ -97,8 +96,6 @@ class IndexerIndexRow extends Component {
isIndexerInfoModalOpen
} = this.state;
const baseUrl = fields.find((field) => field.name === 'baseUrl')?.value ?? indexerUrls[0];
return (
<>
{
@@ -253,7 +250,7 @@ class IndexerIndexRow extends Component {
className={styles.externalLink}
name={icons.EXTERNAL_LINK}
title={translate('Website')}
to={baseUrl.replace('api.', '')}
to={indexerUrls[0].replace('api.', '')}
/> : null
}
@@ -302,7 +299,6 @@ IndexerIndexRow.propTypes = {
name: PropTypes.string.isRequired,
enable: PropTypes.bool.isRequired,
redirect: PropTypes.bool.isRequired,
fields: PropTypes.arrayOf(PropTypes.object).isRequired,
appProfile: PropTypes.object.isRequired,
status: PropTypes.object,
capabilities: PropTypes.object,

View File

@@ -20,14 +20,11 @@ function IndexerInfoModalContent(props) {
encoding,
language,
indexerUrls,
fields,
protocol,
capabilities,
onModalClose
} = props;
const baseUrl = fields.find((field) => field.name === 'baseUrl')?.value ?? indexerUrls[0];
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
@@ -60,7 +57,7 @@ function IndexerInfoModalContent(props) {
/>
<DescriptionListItemTitle>{translate('IndexerSite')}</DescriptionListItemTitle>
<DescriptionListItemDescription>
<Link to={baseUrl}>{baseUrl}</Link>
<Link to={indexerUrls[0]}>{indexerUrls[0]}</Link>
</DescriptionListItemDescription>
<DescriptionListItemTitle>{`${protocol === 'usenet' ? 'Newznab' : 'Torznab'} Url`}</DescriptionListItemTitle>
<DescriptionListItemDescription>
@@ -117,7 +114,6 @@ IndexerInfoModalContent.propTypes = {
encoding: PropTypes.string.isRequired,
language: PropTypes.string.isRequired,
indexerUrls: PropTypes.arrayOf(PropTypes.string).isRequired,
fields: PropTypes.arrayOf(PropTypes.object).isRequired,
protocol: PropTypes.string.isRequired,
capabilities: PropTypes.object.isRequired,
onModalClose: PropTypes.func.isRequired

View File

@@ -11,8 +11,7 @@
"lint": "esprint check",
"lint-fix": "esprint check --fix",
"stylelint-linux": "stylelint $(find frontend -name '*.css') --config frontend/.stylelintrc",
"stylelint-windows": "stylelint frontend/**/*.css --config frontend/.stylelintrc",
"check-modules": "are-you-es5 check . -r"
"stylelint-windows": "stylelint frontend/**/*.css --config frontend/.stylelintrc"
},
"repository": "https://github.com/Prowlarr/Prowlarr",
"author": "Team Prowlarr",
@@ -94,7 +93,6 @@
"@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/preset-env": "7.20.2",
"@babel/preset-react": "7.18.6",
"are-you-es5": "2.1.2",
"autoprefixer": "10.4.13",
"babel-loader": "9.1.0",
"babel-plugin-inline-classnames": "2.0.1",

View File

@@ -53,26 +53,6 @@ namespace NzbDrone.Common.Test.Http
newUri.FullUri.Should().Be(expected);
}
[TestCase("", "./relative", "relative")]
[TestCase("/", "./relative", "/relative")]
[TestCase("/base", "./relative", "/relative")]
[TestCase("/base/sub", "./relative", "/base/relative")]
[TestCase("/base/sub/", "./relative", "/base/sub/relative")]
[TestCase("base/sub", "./relative", "base/relative")]
[TestCase("base/sub/", "./relative", "base/sub/relative")]
[TestCase("", "../relative", "relative")]
[TestCase("/", "../relative", "/relative")]
[TestCase("/base", "../relative", "/relative")]
[TestCase("/base/sub", "../relative", "/base/relative")]
[TestCase("/base/sub/", "../relative", "/base/sub/relative")]
[TestCase("base/sub", "../relative", "base/relative")]
[TestCase("base/sub/", "../relative", "base/sub/relative")]
public void should_combine_uri_with_dot_segment(string basePath, string relativePath, string expected)
{
var newUri = new HttpUri(basePath) + new HttpUri(relativePath);
newUri.FullUri.Should().Be(expected);
}
[TestCase("", "", "")]
[TestCase("/", "", "/")]
[TestCase("base", "", "base")]

View File

@@ -24,16 +24,12 @@ namespace NzbDrone.Common.Test.InstrumentationTests
[TestCase(@"https://beyond-hd.me/api/torrents/2b51db35e1912ffc138825a12b9933d2")]
[TestCase(@"Req: [POST] https://www3.yggtorrent.nz/user/login: id=mySecret&pass=mySecret&ci_csrf_token=2b51db35e1912ffc138825a12b9933d2")]
[TestCase(@"https://torrentseeds.org/api/torrents/filter?api_token=2b51db35e1912ffc138825a12b9933d2&name=&sortField=created_at&sortDirection=desc&perPage=100&page=1")]
[TestCase(@"https://beyond-hd.me/torrent/download/the-next-365-days-2022-2160p-nf-web-dl-dual-ddp-51-dovi-hdr-hevc-apex.225146.2b51db35e1912ffc138825a12b9933d2")]
[TestCase(@"https://anthelion.me/api.php?api_key=2b51db35e1910123321025a12b9933d2&o=json&t=movie&q=&tmdb=&imdb=&cat=&limit=100&offset=0")]
[TestCase(@"https://avistaz.to/api/v1/jackett/auth: username=mySecret&password=mySecret&pid=mySecret")]
// Indexer and Download Client Responses
// avistaz response
[TestCase(@"""download"":""https://avistaz.to/rss/download/2b51db35e1910123321025a12b9933d2/tb51db35e1910123321025a12b9933d2.torrent"",")]
[TestCase(@",""info_hash"":""2b51db35e1910123321025a12b9933d2"",")]
[TestCase(@"""token"":""2b51db35e1910123321025a12b9933d2""")]
// animebytes response
[TestCase(@"""Link"":""https://animebytes.tv/torrent/994064/download/tb51db35e1910123321025a12b9933d2"",")]

View File

@@ -76,7 +76,6 @@ namespace NzbDrone.Common.Http
get
{
var newUrl = Headers["Location"];
if (newUrl == null)
{
newUrl = Headers["Refresh"];

View File

@@ -166,37 +166,6 @@ namespace NzbDrone.Common.Http
return relativePath;
}
if (relativePath.StartsWith("./"))
{
relativePath = relativePath.TrimStart('.').TrimStart('/');
var lastIndex = basePath.LastIndexOf("/");
if (lastIndex > 0)
{
basePath = basePath.Substring(0, lastIndex) + "/";
}
}
if (relativePath.StartsWith("../"))
{
relativePath = relativePath.TrimStart('.').TrimStart('/');
var lastIndex = basePath.LastIndexOf("/");
if (lastIndex > 0)
{
basePath = basePath.Substring(0, lastIndex) + "/";
}
var secondLastIndex = basePath.LastIndexOf("/");
if (lastIndex > 0)
{
basePath = basePath.Substring(0, secondLastIndex) + "/";
}
}
var baseSlashIndex = basePath.LastIndexOf('/');
if (baseSlashIndex >= 0)

View File

@@ -1,3 +1,4 @@
using System;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
@@ -7,10 +8,10 @@ namespace NzbDrone.Common.Instrumentation
{
public class CleanseLogMessage
{
private static readonly Regex[] CleansingRules =
{
private static readonly Regex[] CleansingRules = new[]
{
// Url
new Regex(@"(?<=[?&: ;])(apikey|api_key|(?:(?:access|api)[-_]?)?token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pid|pwd)=(?<secret>[^&=""]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=[?&: ;])(apikey|(?:(?:access|api)[-_]?)?token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pwd)=(?<secret>[^&=""]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=[?& ;])[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"rss\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"rss\.torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
@@ -20,7 +21,6 @@ namespace NzbDrone.Common.Instrumentation
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(@"(?<=beyond-hd\.[a-z]+/api/torrents/)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=beyond-hd\.[a-z]+/torrent/download/[\w\d-]+[.]\d+[.])(?<secret>[a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// UNIT3D
new Regex(@"(?<=[a-z0-9-]+\.[a-z]+/torrent/download/\d+\.)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
@@ -58,10 +58,9 @@ namespace NzbDrone.Common.Instrumentation
new Regex(@"(?:avistaz|exoticaz|cinemaz|privatehd)\.[a-z]{2,3}/rss/download/(?<secret>[^&=]+?)/(?<secret>[^&=]+?)\.torrent", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?:animebytes)\.[a-z]{2,3}/torrent/[0-9]+/download/(?<secret>[^&=]+?)[""]", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@",""info_hash"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"""token"":""(?<secret>[^&=]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@",""pass[- _]?key"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@",""rss[- _]?key"":""(?<secret>[^&=]+?)"",", RegexOptions.Compiled | RegexOptions.IgnoreCase),
};
};
private static readonly Regex CleanseRemoteIPRegex = new Regex(@"(?:Auth-\w+(?<!Failure|Unauthorized) ip|from) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Compiled);

View File

@@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests
torrentInfo.InfoUrl.Should().Be("https://avistaz.to/torrent/187240-japan-sinks-people-of-hope-2021-s01e05-720p-nf-web-dl-ddp20-x264-seikel");
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-11-14 22:26:21"));
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-11-15 04:26:21"));
torrentInfo.Size.Should().Be(935127615);
torrentInfo.InfoHash.Should().Be("a879261d4e6e792402f92401141a21de70d51bf2");
torrentInfo.MagnetUrl.Should().Be(null);

View File

@@ -21,15 +21,10 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition
Subject.Definition = new IndexerDefinition()
{
Name = "FileList",
Settings = new FileListSettings
{
BaseUrl = "https://filelist.io/",
Username = "someuser",
Passkey = "somepass"
}
Settings = new FileListSettings() { Username = "someuser", Passkey = "somepass" }
};
}
@@ -40,9 +35,9 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
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)));
.Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), recentFeed)));
var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new[] { 2000 } })).Releases;
var releases = (await Subject.Fetch(new MovieSearchCriteria { Categories = new int[] { 2000 } })).Releases;
releases.Should().HaveCount(4);
releases.First().Should().BeOfType<TorrentInfo>();
@@ -55,14 +50,12 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
torrentInfo.InfoUrl.Should().Be("https://filelist.io/details.php?id=665873");
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 20:20:19"));
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 20:20:19").ToUniversalTime());
torrentInfo.Size.Should().Be(8300512414);
torrentInfo.InfoHash.Should().Be(null);
torrentInfo.MagnetUrl.Should().Be(null);
torrentInfo.Peers.Should().Be(2 + 12);
torrentInfo.Seeders.Should().Be(12);
releases.Any(t => t.IndexerFlags.Contains(IndexerFlag.Internal)).Should().Be(true);
}
}
}

View File

@@ -16,35 +16,34 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
[SetUp]
public void Setup()
{
Subject.Settings = new FileListSettings
Subject.Settings = new FileListSettings()
{
BaseUrl = "https://filelist.io/",
Passkey = "abcd",
Username = "somename"
Username = "somename",
BaseUrl = "https://filelist.io"
};
Subject.Capabilities = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.ImdbId, TvSearchParam.Season, TvSearchParam.Ep
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
},
{
BookSearchParam.Q
},
Flags = new List<IndexerFlag>
{
IndexerFlag.FreeLeech,
IndexerFlag.Internal,
IndexerFlag.FreeLeech
}
};
@@ -54,7 +53,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
_movieSearchCriteria = new MovieSearchCriteria
{
SearchTerm = "Star Wars",
Categories = new[] { 2000 }
Categories = new int[] { 2000 }
};
}
@@ -66,13 +65,13 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
[Test]
public void should_use_categories_for_feed()
{
var results = Subject.GetSearchRequests(new MovieSearchCriteria { Categories = new[] { NewznabStandardCategory.MoviesSD.Id, NewznabStandardCategory.MoviesDVD.Id } });
var results = Subject.GetSearchRequests(new MovieSearchCriteria { Categories = new int[] { NewznabStandardCategory.MoviesSD.Id, NewznabStandardCategory.MoviesDVD.Id } });
results.GetAllTiers().Should().HaveCount(1);
var page = results.GetAllTiers().First().First();
page.Url.Query.Should().Contain("&category=1%2C2");
page.Url.Query.Should().Contain("&category=1,2&");
}
[Test]
@@ -101,7 +100,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
var page = results.GetAllTiers().First().First();
page.Url.Query.Should().Contain("type=name");
page.Url.Query.Should().Contain("query=Star+Wars");
page.Url.Query.Should().Contain("query=Star Wars");
}
}
}

View File

@@ -24,7 +24,7 @@ namespace NzbDrone.Core.Test.IndexerTests.OrpheusTests
Subject.Definition = new IndexerDefinition()
{
Name = "Orpheus",
Settings = new OrpheusSettings { Apikey = "somekey" }
Settings = new OrpheusSettings() { Apikey = "somekey" }
};
}
@@ -37,14 +37,14 @@ namespace NzbDrone.Core.Test.IndexerTests.OrpheusTests
.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[] { 2000 } })).Releases;
var releases = (await Subject.Fetch(new BasicSearchCriteria { Categories = new int[] { 2000 } })).Releases;
releases.Should().HaveCount(65);
releases.First().Should().BeOfType<GazelleInfo>();
var torrentInfo = releases.First() as GazelleInfo;
torrentInfo.Title.Should().Be("The Beatles - Abbey Road (1969) [2.0 Mix 2019] [MP3 V2 (VBR)] [BD]");
torrentInfo.Title.Should().Be("The Beatles - Abbey Road (1969) [MP3 V2 (VBR)] [BD]");
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("https://orpheus.network/ajax.php?action=download&id=1902448");
torrentInfo.InfoUrl.Should().Be("https://orpheus.network/torrents.php?id=466&torrentid=1902448");

View File

@@ -1,14 +0,0 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(025)]
public class speedcd_userpasssettings_to_speedcdsettings : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Update.Table("Indexers").Set(new { ConfigContract = "SpeedCDSettings" }).Where(new { Implementation = "SpeedCD" });
}
}
}

View File

@@ -29,11 +29,7 @@ namespace NzbDrone.Core.Http.CloudFlare
response.StatusCode.Equals(HttpStatusCode.Forbidden))
{
var responseHtml = response.Content;
if (responseHtml.Contains("<title>Just a moment...</title>") ||
responseHtml.Contains("<title>Access denied</title>") ||
responseHtml.Contains("<title>Attention Required! | Cloudflare</title>") ||
responseHtml.Trim().Equals("error code: 1020") ||
responseHtml.Contains("<title>DDOS-GUARD</title>"))
if (responseHtml.Contains("<title>Just a moment...") || responseHtml.Contains("<title>DDOS-GUARD"))
{
return true;
}

View File

@@ -170,7 +170,6 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
newRequest.Headers.ContentType = "application/json";
newRequest.Method = HttpMethod.Post;
newRequest.LogResponseContent = true;
newRequest.RequestTimeout = TimeSpan.FromSeconds(Settings.RequestTimeout + 5);
newRequest.SetContent(req.ToJson());
_logger.Debug("Cloudflare Detected, Applying FlareSolverr Proxy {0} to request {1}", Name, request.Url);

View File

@@ -29,7 +29,7 @@ namespace NzbDrone.Core.IndexerVersions
/* Update Service will fall back if version # does not exist for an indexer per Ta */
private const string DEFINITION_BRANCH = "master";
private const int DEFINITION_VERSION = 8;
private const int DEFINITION_VERSION = 7;
//Used when moving yml to C#
private readonly List<string> _defintionBlocklist = new List<string>()

View File

@@ -1,5 +1,6 @@
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;
@@ -9,23 +10,18 @@ namespace NzbDrone.Core.Indexers.Definitions
public class AvistaZ : AvistazBase
{
public override string Name => "AvistaZ";
public override string[] IndexerUrls => new[] { "https://avistaz.to/" };
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)
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
return new AvistazRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
@@ -34,23 +30,18 @@ namespace NzbDrone.Core.Indexers.Definitions
};
}
public override IParseIndexerResponse GetParser()
{
return new AvistaZParser();
}
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId, TvSearchParam.Genre
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId, TvSearchParam.Genre
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.Genre
}
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.Genre
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies);
@@ -61,13 +52,9 @@ namespace NzbDrone.Core.Indexers.Definitions
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;
}
}
public class AvistaZParser : AvistazParserBase
{
protected override string TimezoneOffset => "+01:00";
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;

View File

@@ -13,11 +13,12 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public abstract class AvistazBase : TorrentIndexerBase<AvistazSettings>
{
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override string[] IndexerUrls => new string[] { "" };
protected virtual string LoginUrl => Settings.BaseUrl + "api/v1/jackett/auth";
public override bool SupportsRss => true;
public override bool SupportsSearch => true;
public override int PageSize => 50;
public override IndexerCapabilities Capabilities => SetCapabilities();
protected virtual string LoginUrl => Settings.BaseUrl + "api/v1/jackett/auth";
private IIndexerRepository _indexerRepository;
public AvistazBase(IIndexerRepository indexerRepository,
@@ -33,7 +34,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new AvistazRequestGenerator
return new AvistazRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
@@ -44,12 +45,14 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public override IParseIndexerResponse GetParser()
{
return new AvistazParserBase();
return new AvistazParser();
}
protected virtual IndexerCapabilities SetCapabilities()
{
return new IndexerCapabilities();
var caps = new IndexerCapabilities();
return caps;
}
protected override async Task DoLogin()
@@ -95,6 +98,12 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
var jsonResponse = new HttpResponse<AvistazErrorResponse>(ex.Response);
return new ValidationFailure(string.Empty, jsonResponse.Resource?.Message ?? "Unauthorized request to indexer");
}
else if (ex.Response.StatusCode == HttpStatusCode.TooManyRequests)
{
_logger.Warn(ex, "Too Many Requests");
return new ValidationFailure(string.Empty, "Too Many Requests");
}
else
{
_logger.Warn(ex, "Unable to connect to indexer");

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using NzbDrone.Common.Extensions;
@@ -11,10 +10,13 @@ using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions.Avistaz
{
public class AvistazParserBase : IParseIndexerResponse
public class AvistazParser : IParseIndexerResponse
{
protected virtual string TimezoneOffset => "-05:00"; // Avistaz does not specify a timezone & returns server time
private readonly HashSet<string> _hdResolutions = new () { "1080p", "1080i", "720p" };
private readonly HashSet<string> _hdResolutions = new HashSet<string> { "1080p", "1080i", "720p" };
public AvistazParser()
{
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
@@ -22,24 +24,26 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
{
var torrentInfos = new List<TorrentInfo>();
if (indexerResponse.HttpResponse.StatusCode == HttpStatusCode.NotFound)
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
{
return torrentInfos.ToArray();
}
if (indexerResponse.HttpResponse.StatusCode == HttpStatusCode.TooManyRequests)
{
throw new RequestLimitReachedException(indexerResponse, "API Request Limit Reached");
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
}
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
}
if (indexerResponse.HttpResponse.StatusCode == HttpStatusCode.NotFound)
{
// No results found
return torrentInfos.ToArray();
}
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}");
HttpResponse<AvistazErrorResponse> jsonErrorResponse = new HttpResponse<AvistazErrorResponse>(indexerResponse.HttpResponse);
if (indexerResponse.HttpResponse.StatusCode == HttpStatusCode.Unauthorized)
{
throw new IndexerAuthException(string.Empty, jsonErrorResponse.Resource?.Message ?? "Unauthorized request to indexer");
}
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
}
var jsonResponse = new HttpResponse<AvistazResponse>(indexerResponse.HttpResponse);
@@ -59,7 +63,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
InfoUrl = details,
Guid = details,
Categories = cats,
PublishDate = DateTime.Parse($"{row.CreatedAt} {TimezoneOffset}", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
PublishDate = DateTime.Parse(row.CreatedAt + "-05:00").ToUniversalTime(), // Avistaz does not specify a timezone & returns server time
Size = row.FileSize,
Files = row.FileCount,
Grabs = row.Completed,

View File

@@ -12,12 +12,17 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public class AvistazRequestGenerator : IIndexerRequestGenerator
{
public AvistazSettings Settings { get; set; }
public IDictionary<string, string> AuthCookieCache { get; set; }
public IIndexerHttpClient HttpClient { get; set; }
public IndexerCapabilities Capabilities { get; set; }
public Logger Logger { get; set; }
protected virtual string SearchUrl => Settings.BaseUrl + "api/v1/jackett/torrents";
protected virtual bool ImdbInTags => false;
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
protected virtual string SearchUrl => Settings.BaseUrl + "api/v1/jackett/torrents";
// hook to adjust the search category
protected virtual List<KeyValuePair<string, string>> GetBasicSearchParameters(int[] categories, string genre)
@@ -40,8 +45,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
}
// 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))
{
if (categories.Contains(NewznabStandardCategory.MoviesUHD.Id) || categories.Contains(NewznabStandardCategory.TVUHD.Id))

View File

@@ -30,24 +30,9 @@ namespace NzbDrone.Core.Indexers.Cardigann
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
// Page size is different per indexer, setting to 1 ensures we don't break out of paging logic
// thinking its a partial page and instead 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
public override int PageSize => 1;
public override TimeSpan RateLimit
{
get
{
var definition = _definitionService.GetCachedDefinition(Settings.DefinitionFile);
if (definition.RequestDelay.HasValue && definition.RequestDelay.Value > base.RateLimit.TotalSeconds)
{
return TimeSpan.FromSeconds(definition.RequestDelay.Value);
}
return base.RateLimit;
}
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
var generator = _generatorCache.Get(Settings.DefinitionFile, () =>

View File

@@ -2,7 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using AngleSharp.Dom;
@@ -680,12 +680,6 @@ namespace NzbDrone.Core.Indexers.Cardigann
case "urlencode":
data = data.UrlEncode(_encoding);
break;
case "htmldecode":
data = WebUtility.HtmlDecode(data);
break;
case "htmlencode":
data = WebUtility.HtmlEncode(data);
break;
case "timeago":
case "reltime":
data = DateTimeUtil.FromTimeAgo(data).ToString(DateTimeUtil.Rfc1123ZPattern);

View File

@@ -41,7 +41,6 @@ namespace NzbDrone.Core.Indexers.Cardigann
public string Type { get; set; }
public string Language { get; set; }
public string Encoding { get; set; }
public double? RequestDelay { get; set; }
public List<string> Links { get; set; }
public List<string> Legacylinks { get; set; }
public bool Followredirect { get; set; } = false;

View File

@@ -1,5 +1,6 @@
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;
@@ -9,23 +10,18 @@ namespace NzbDrone.Core.Indexers.Definitions
public class CinemaZ : AvistazBase
{
public override string Name => "CinemaZ";
public override string[] IndexerUrls => new[] { "https://cinemaz.to/" };
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)
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
return new AvistazRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
@@ -56,6 +52,7 @@ namespace NzbDrone.Core.Indexers.Definitions
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;
}

View File

@@ -10,23 +10,18 @@ namespace NzbDrone.Core.Indexers.Definitions
public class ExoticaZ : AvistazBase
{
public override string Name => "ExoticaZ";
public override string[] IndexerUrls => new[] { "https://exoticaz.to/" };
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)
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
return new AvistazRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
@@ -57,7 +52,7 @@ namespace NzbDrone.Core.Indexers.Definitions
}
}
public class ExoticaZParser : AvistazParserBase
public class ExoticaZParser : AvistazParser
{
private readonly IndexerCapabilitiesCategories _categories;

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Messaging.Events;
@@ -8,8 +9,7 @@ namespace NzbDrone.Core.Indexers.FileList
public class FileList : TorrentIndexerBase<FileListSettings>
{
public override string Name => "FileList.io";
public override string[] IndexerUrls => new[] { "https://filelist.io/" };
public override string[] LegacyUrls => new[] { "https://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 IndexerPrivacy Privacy => IndexerPrivacy.Private;
@@ -18,18 +18,14 @@ namespace NzbDrone.Core.Indexers.FileList
public override bool SupportsRedirect => true;
public override IndexerCapabilities Capabilities => SetCapabilities();
public FileList(IIndexerHttpClient httpClient,
IEventAggregator eventAggregator,
IIndexerStatusService indexerStatusService,
IConfigService configService,
Logger logger)
public FileList(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new FileListRequestGenerator { Settings = Settings, Capabilities = Capabilities };
return new FileListRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
}
public override IParseIndexerResponse GetParser()
@@ -42,21 +38,21 @@ namespace NzbDrone.Core.Indexers.FileList
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.ImdbId, TvSearchParam.Season, TvSearchParam.Ep
},
{
TvSearchParam.Q, TvSearchParam.ImdbId, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
},
{
BookSearchParam.Q
},
Flags = new List<IndexerFlag>
{
IndexerFlag.Internal,

View File

@@ -1,3 +1,4 @@
using System;
using Newtonsoft.Json;
namespace NzbDrone.Core.Indexers.FileList
@@ -23,7 +24,5 @@ namespace NzbDrone.Core.Indexers.FileList
[JsonProperty(PropertyName = "upload_date")]
public string UploadDate { get; set; }
public string Category { get; set; }
[JsonProperty(PropertyName = "small_description")]
public string SmallDescription { get; set; }
}
}

View File

@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using Newtonsoft.Json;
using NzbDrone.Common.Http;
@@ -27,12 +25,9 @@ namespace NzbDrone.Core.Indexers.FileList
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, "Unexpected response status {0} code from API request", indexerResponse.HttpResponse.StatusCode);
}
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}");
throw new IndexerException(indexerResponse,
"Unexpected response status {0} code from API request",
indexerResponse.HttpResponse.StatusCode);
}
var queryResults = JsonConvert.DeserializeObject<List<FileListTorrent>>(indexerResponse.Content);
@@ -41,7 +36,7 @@ namespace NzbDrone.Core.Indexers.FileList
{
var id = result.Id;
var flags = new HashSet<IndexerFlag>();
var flags = new List<IndexerFlag>();
if (result.Internal)
{
@@ -54,10 +49,10 @@ namespace NzbDrone.Core.Indexers.FileList
imdbId = int.Parse(result.ImdbId.Substring(2));
}
var downloadVolumeFactor = result.FreeLeech ? 0 : 1;
var uploadVolumeFactor = result.DoubleUp ? 2 : 1;
var downloadVolumeFactor = result.FreeLeech == true ? 0 : 1;
var uploadVolumeFactor = result.DoubleUp == true ? 2 : 1;
torrentInfos.Add(new TorrentInfo
torrentInfos.Add(new TorrentInfo()
{
Guid = string.Format("FileList-{0}", id),
Title = result.Name,
@@ -67,9 +62,7 @@ namespace NzbDrone.Core.Indexers.FileList
InfoUrl = GetInfoUrl(id),
Seeders = result.Seeders,
Peers = result.Leechers + result.Seeders,
PublishDate = DateTime.Parse(result.UploadDate + " +0200", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
Description = result.SmallDescription,
Genres = result.SmallDescription.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList(),
PublishDate = DateTime.Parse(result.UploadDate + " +0200"),
ImdbId = imdbId,
IndexerFlags = flags,
Files = (int)result.Files,
@@ -77,7 +70,7 @@ namespace NzbDrone.Core.Indexers.FileList
DownloadVolumeFactor = downloadVolumeFactor,
UploadVolumeFactor = uploadVolumeFactor,
MinimumRatio = 1,
MinimumSeedTime = 172800, // 48 hours
MinimumSeedTime = 172800, //48 hours
});
}

View File

@@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.FileList
{
@@ -15,57 +13,23 @@ namespace NzbDrone.Core.Indexers.FileList
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = GetDefaultParameters();
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace() || searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
{
parameters.Add("action", "search-torrents");
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
{
parameters.Add("type", "imdb");
parameters.Add("query", searchCriteria.FullImdbId);
}
else if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
{
parameters.Add("type", "name");
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
}
if (searchCriteria.Season.HasValue)
{
parameters.Add("season", searchCriteria.Season.ToString());
parameters.Add("episode", searchCriteria.Episode);
}
}
pageableRequests.Add(GetRequest(searchCriteria, parameters));
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = GetDefaultParameters();
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
{
parameters.Add("action", "search-torrents");
parameters.Add("type", "imdb");
parameters.Add("query", searchCriteria.FullImdbId);
pageableRequests.Add(GetRequest("search-torrents", searchCriteria.Categories, string.Format("&type=imdb&query={0}", searchCriteria.FullImdbId)));
}
else if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
{
parameters.Add("action", "search-torrents");
parameters.Add("type", "name");
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
var titleYearSearchQuery = string.Format("{0}", searchCriteria.SanitizedSearchTerm);
pageableRequests.Add(GetRequest("search-torrents", searchCriteria.Categories, string.Format("&type=name&query={0}", titleYearSearchQuery.Trim())));
}
else
{
pageableRequests.Add(GetRequest("latest-torrents", searchCriteria.Categories, ""));
}
pageableRequests.Add(GetRequest(searchCriteria, parameters));
return pageableRequests;
}
@@ -73,16 +37,36 @@ namespace NzbDrone.Core.Indexers.FileList
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = GetDefaultParameters();
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
{
parameters.Add("action", "search-torrents");
parameters.Add("type", "name");
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
var titleYearSearchQuery = string.Format("{0}", searchCriteria.SanitizedSearchTerm);
pageableRequests.Add(GetRequest("search-torrents", searchCriteria.Categories, string.Format("&type=name&query={0}", titleYearSearchQuery.Trim())));
}
else
{
pageableRequests.Add(GetRequest("latest-torrents", searchCriteria.Categories, ""));
}
pageableRequests.Add(GetRequest(searchCriteria, parameters));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
{
pageableRequests.Add(GetRequest("search-torrents", searchCriteria.Categories, string.Format("&type=imdb&query={0}&season={1}&episode={2}", searchCriteria.FullImdbId, searchCriteria.Season, searchCriteria.Episode)));
}
else if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
{
var titleYearSearchQuery = string.Format("{0}", searchCriteria.SanitizedSearchTerm);
pageableRequests.Add(GetRequest("search-torrents", searchCriteria.Categories, string.Format("&type=name&query={0}&season={1}&episode={2}", titleYearSearchQuery.Trim(), searchCriteria.Season, searchCriteria.Episode)));
}
else
{
pageableRequests.Add(GetRequest("latest-torrents", searchCriteria.Categories, ""));
}
return pageableRequests;
}
@@ -90,16 +74,15 @@ namespace NzbDrone.Core.Indexers.FileList
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = GetDefaultParameters();
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
{
parameters.Add("action", "search-torrents");
parameters.Add("type", "name");
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
var titleYearSearchQuery = string.Format("{0}", searchCriteria.SanitizedSearchTerm);
pageableRequests.Add(GetRequest("search-torrents", searchCriteria.Categories, string.Format("&type=name&query={0}", titleYearSearchQuery.Trim())));
}
else
{
pageableRequests.Add(GetRequest("latest-torrents", searchCriteria.Categories, ""));
}
pageableRequests.Add(GetRequest(searchCriteria, parameters));
return pageableRequests;
}
@@ -107,48 +90,31 @@ namespace NzbDrone.Core.Indexers.FileList
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = GetDefaultParameters();
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
{
parameters.Add("action", "search-torrents");
parameters.Add("type", "name");
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
var titleYearSearchQuery = string.Format("{0}", searchCriteria.SanitizedSearchTerm);
pageableRequests.Add(GetRequest("search-torrents", searchCriteria.Categories, string.Format("&type=name&query={0}", titleYearSearchQuery.Trim())));
}
else
{
pageableRequests.Add(GetRequest("latest-torrents", searchCriteria.Categories, ""));
}
pageableRequests.Add(GetRequest(searchCriteria, parameters));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetRequest(SearchCriteriaBase searchCriteria, NameValueCollection parameters)
private IEnumerable<IndexerRequest> GetRequest(string searchType, int[] categories, string parameters)
{
if (parameters.Get("action") is null)
{
parameters.Add("action", "latest-torrents");
}
var categoriesQuery = string.Join(",", Capabilities.Categories.MapTorznabCapsToTrackers(categories));
parameters.Add("category", string.Join(",", Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories)));
var searchUrl = $"{Settings.BaseUrl.TrimEnd('/')}/api.php?{parameters.GetQueryString()}";
yield return new IndexerRequest(searchUrl, HttpAccept.Json);
}
private NameValueCollection GetDefaultParameters()
{
var parameters = new NameValueCollection
{
{ "username", Settings.Username.Trim() },
{ "passkey", Settings.Passkey.Trim() }
};
var baseUrl = string.Format("{0}/api.php?action={1}&category={2}&username={3}&passkey={4}{5}", Settings.BaseUrl.TrimEnd('/'), searchType, categoriesQuery, Settings.Username.Trim(), Settings.Passkey.Trim(), parameters);
if (Settings.FreeleechOnly)
{
parameters.Add("freeleech", "1");
baseUrl += "&freeleech=1";
}
return parameters;
yield return new IndexerRequest(baseUrl, HttpAccept.Json);
}
}
}

View File

@@ -16,7 +16,12 @@ namespace NzbDrone.Core.Indexers.FileList
public class FileListSettings : NoAuthTorrentBaseSettings
{
private static readonly FileListSettingsValidator Validator = new ();
private static readonly FileListSettingsValidator Validator = new FileListSettingsValidator();
public FileListSettings()
{
BaseUrl = "https://filelist.io";
}
[FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)]
public string Username { get; set; }

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Newtonsoft.Json;
using NLog;
@@ -19,7 +18,7 @@ namespace NzbDrone.Core.Indexers.Definitions;
public class GreatPosterWall : Gazelle.Gazelle
{
public override string Name => "GreatPosterWall";
public override string[] IndexerUrls => new[] { "https://greatposterwall.com/" };
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;
@@ -30,7 +29,7 @@ public class GreatPosterWall : Gazelle.Gazelle
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new GreatPosterWallRequestGenerator
return new GreatPosterWallRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
@@ -119,6 +118,7 @@ public class GreatPosterWallParser : GazelleParser
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
@@ -130,7 +130,7 @@ public class GreatPosterWallParser : GazelleParser
Guid = infoUrl,
PosterUrl = GetPosterUrl(result.Cover),
DownloadUrl = GetDownloadUrl(torrent.TorrentId, torrent.CanUseToken),
PublishDate = new DateTimeOffset(time, TimeSpan.FromHours(8)).UtcDateTime, // Time is Chinese Time, add 8 hours difference from UTC
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,
@@ -173,12 +173,10 @@ public class GreatPosterWallParser : GazelleParser
}
}
return torrentInfos
.OrderByDescending(o => o.PublishDate)
.ToArray();
return torrentInfos;
}
private string GetDownloadUrl(int torrentId, bool canUseToken)
protected string GetDownloadUrl(int torrentId, bool canUseToken)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/torrents.php")

View File

@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Indexers.HDBits
var id = result.Id;
var internalRelease = result.TypeOrigin == 1 ? true : false;
var flags = new HashSet<IndexerFlag>();
var flags = new List<IndexerFlag>();
if (internalRelease)
{

View File

@@ -7,9 +7,10 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AngleSharp.Html.Parser;
using FluentValidation;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings;
@@ -17,20 +18,21 @@ using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
public class HDSpace : TorrentIndexerBase<UserPassTorrentBaseSettings>
{
public override string Name => "HD-Space";
public override string[] IndexerUrls => new[] { "https://hd-space.org/" };
public override string[] IndexerUrls => new string[] { "https://hd-space.org/" };
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 IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
private string LoginUrl => Settings.BaseUrl + "index.php?page=login";
public HDSpace(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
@@ -39,7 +41,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new HDSpaceRequestGenerator { Settings = Settings, Capabilities = Capabilities };
return new HDSpaceRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
}
public override IParseIndexerResponse GetParser()
@@ -54,10 +56,10 @@ namespace NzbDrone.Core.Indexers.Definitions
var requestBuilder = new HttpRequestBuilder(LoginUrl)
{
LogResponseContent = true,
AllowAutoRedirect = true,
Method = HttpMethod.Post
AllowAutoRedirect = true
};
requestBuilder.Method = HttpMethod.Post;
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
var cookies = Cookies;
@@ -68,7 +70,7 @@ namespace NzbDrone.Core.Indexers.Definitions
.AddFormParameter("uid", Settings.Username)
.AddFormParameter("pwd", Settings.Password)
.SetCookies(loginPage.GetCookies())
.SetHeader("Content-Type", "application/x-www-form-urlencoded")
.SetHeader("Content-Type", "multipart/form-data")
.SetHeader("Referer", LoginUrl)
.Build();
@@ -106,17 +108,17 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
}
{
MusicSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.MoviesBluRay, "Movie / Blu-ray");
@@ -153,6 +155,10 @@ namespace NzbDrone.Core.Indexers.Definitions
public UserPassTorrentBaseSettings Settings { get; set; }
public IndexerCapabilities Capabilities { get; set; }
public HDSpaceRequestGenerator()
{
}
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdb = null)
{
var searchUrl = string.Format("{0}/index.php?page=torrents&", Settings.BaseUrl.TrimEnd('/'));
@@ -243,7 +249,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var resultParser = new HtmlParser();
var searchResultDocument = resultParser.ParseDocument(indexerResponse.Content);
var rows = searchResultDocument.QuerySelectorAll("div#bodyarea table.lista:not(:contains(\"Our Team Recommend\")) > tbody > tr:has(a[href^=\"index.php?page=torrent-details&id=\"])");
var rows = searchResultDocument.QuerySelectorAll("table.lista > tbody > tr");
foreach (var row in rows)
{
@@ -258,46 +264,30 @@ namespace NzbDrone.Core.Indexers.Definitions
release.MinimumRatio = 1;
release.MinimumSeedTime = 86400; // 24 hours
var qLink = row.QuerySelector("td:nth-child(2) a[href^=\"index.php?page=torrent-details&id=\"]");
release.Title = qLink?.TextContent.Trim();
release.InfoUrl = _settings.BaseUrl + qLink?.GetAttribute("href");
var qLink = row.Children[1].FirstElementChild;
release.Title = qLink.TextContent.Trim();
release.InfoUrl = _settings.BaseUrl + qLink.GetAttribute("href");
release.Guid = release.InfoUrl;
var downloadUrl = row.QuerySelector("td:nth-child(4) a[href^=\"download.php?id=\"]")?.GetAttribute("href");
release.DownloadUrl = _settings.BaseUrl + downloadUrl;
// Use the torrent filename as release title
var torrentTitle = ParseUtil.GetArgumentFromQueryString(downloadUrl, "f")?
.Replace("&amp;", "&")
.Replace("&#039;", "'")
.Replace(".torrent", "")
.Trim();
if (torrentTitle.IsNotNullOrWhiteSpace())
{
release.Title = torrentTitle;
}
var qGenres = row.QuerySelector("td:nth-child(2) span[style=\"color: #000000 \"]");
if (qGenres != null)
{
var description = qGenres.TextContent.Split('\xA0').Last().Replace(" ", "");
release.Description = description;
release.Genres = description.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList();
}
var imdbLink = row.QuerySelector("td:nth-child(2) a[href*=imdb]");
var imdbLink = row.Children[1].QuerySelector("a[href*=imdb]");
if (imdbLink != null)
{
release.ImdbId = ParseUtil.GetImdbID(imdbLink.GetAttribute("href").Split('/').Last()).GetValueOrDefault();
}
var qDownload = row.Children[3].FirstElementChild;
release.DownloadUrl = _settings.BaseUrl + qDownload.GetAttribute("href");
var dateStr = row.Children[4].TextContent.Trim();
//"July 11, 2015, 13:34:09", "Today|Yesterday at 20:04:23"
release.PublishDate = DateTimeUtil.FromUnknown(row.QuerySelector("td:nth-child(5)")?.TextContent.Trim());
release.Size = ParseUtil.GetBytes(row.QuerySelector("td:nth-child(6)")?.TextContent.Trim());
release.Seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)")?.TextContent);
release.Peers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(9)")?.TextContent) + release.Seeders;
var grabs = row.QuerySelector("td:nth-child(10)")?.TextContent.Trim().Replace("---", "0");
release.PublishDate = DateTimeUtil.FromUnknown(dateStr);
var sizeStr = row.Children[5].TextContent;
release.Size = ParseUtil.GetBytes(sizeStr);
release.Seeders = ParseUtil.CoerceInt(row.Children[7].TextContent);
release.Peers = ParseUtil.CoerceInt(row.Children[8].TextContent) + release.Seeders;
var grabs = row.QuerySelector("td:nth-child(10)").TextContent;
grabs = grabs.Replace("---", "0");
release.Grabs = ParseUtil.CoerceInt(grabs);
if (row.QuerySelector("img[title=\"FreeLeech\"]") != null)
@@ -321,7 +311,6 @@ namespace NzbDrone.Core.Indexers.Definitions
var qCat = row.QuerySelector("a[href^=\"index.php?page=torrents&category=\"]");
var cat = qCat.GetAttribute("href").Split('=')[2];
release.Categories = _categories.MapTrackerCatToNewznab(cat);
torrentInfos.Add(release);
}

View File

@@ -7,14 +7,17 @@ using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AngleSharp.Html.Parser;
using FluentValidation;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
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.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
@@ -22,18 +25,12 @@ namespace NzbDrone.Core.Indexers.Definitions
{
public override string Name => "HD-Torrents";
public override string[] IndexerUrls => new[]
{
"https://hdts.ru/",
"https://hd-torrents.org/",
"https://hd-torrents.net/",
"https://hd-torrents.me/",
};
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";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
private string LoginUrl => Settings.BaseUrl + "login.php";
public HDTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
@@ -42,7 +39,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new HDTorrentsRequestGenerator { Settings = Settings, Capabilities = Capabilities };
return new HDTorrentsRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
}
public override IParseIndexerResponse GetParser()
@@ -54,10 +51,10 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var requestBuilder = new HttpRequestBuilder(LoginUrl)
{
LogResponseContent = true,
Method = HttpMethod.Post
LogResponseContent = true
};
requestBuilder.Method = HttpMethod.Post;
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
var cookies = Cookies;
@@ -66,8 +63,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var authLoginRequest = requestBuilder
.AddFormParameter("uid", Settings.Username)
.AddFormParameter("pwd", Settings.Password)
.SetHeader("Content-Type", "application/x-www-form-urlencoded")
.SetHeader("Referer", LoginUrl)
.SetHeader("Content-Type", "multipart/form-data")
.Build();
var response = await ExecuteAuth(authLoginRequest);
@@ -80,7 +76,12 @@ namespace NzbDrone.Core.Indexers.Definitions
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return httpResponse.Content.Contains("Error:You're not authorized");
if (httpResponse.Content.Contains("Error:You're not authorized"))
{
return true;
}
return false;
}
private IndexerCapabilities SetCapabilities()
@@ -88,25 +89,21 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
Flags = new List<IndexerFlag>
{
IndexerFlag.Internal
}
{
MusicSearchParam.Q
}
};
caps.Categories.AddCategoryMapping("70", NewznabStandardCategory.MoviesBluRay, "Movie/UHD/Blu-Ray");
caps.Categories.AddCategoryMapping("1", NewznabStandardCategory.MoviesBluRay, "Movie/Blu-Ray");
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");
@@ -147,6 +144,10 @@ namespace NzbDrone.Core.Indexers.Definitions
public UserPassTorrentBaseSettings Settings { get; set; }
public IndexerCapabilities Capabilities { get; set; }
public HDTorrentsRequestGenerator()
{
}
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null)
{
var searchUrl = Settings.BaseUrl + "torrents.php?" + string.Join(string.Empty, Capabilities.Categories.MapTorznabCapsToTrackers(categories).Select(cat => $"category[]={cat}&"));
@@ -223,7 +224,7 @@ namespace NzbDrone.Core.Indexers.Definitions
private readonly IndexerCapabilitiesCategories _categories;
private readonly Regex _posterRegex = new Regex(@"src=\\'./([^']+)\\'", RegexOptions.IgnoreCase);
private readonly HashSet<string> _freeleechRanks = new (StringComparer.OrdinalIgnoreCase)
private readonly HashSet<string> _freeleechRanks = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"VIP",
"Uploader",
@@ -247,7 +248,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var dom = parser.ParseDocument(indexerResponse.Content);
var userInfo = dom.QuerySelector("table.navus tr");
var userRank = userInfo?.Children[1].TextContent.Replace("Rank:", string.Empty).Trim();
var userRank = userInfo.Children[1].TextContent.Replace("Rank:", string.Empty).Trim();
var hasFreeleech = _freeleechRanks.Contains(userRank);
var rows = dom.QuerySelectorAll("table.mainblockcontenttt tr:has(td.mainblockcontent)");
@@ -258,9 +259,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var details = new Uri(_settings.BaseUrl + mainLink.GetAttribute("href"));
var posterMatch = _posterRegex.Match(mainLink.GetAttribute("onmouseover"));
var poster = posterMatch.Success
? _settings.BaseUrl + posterMatch.Groups[1].Value.Replace("\\", "/")
: null;
var poster = posterMatch.Success ? _settings.BaseUrl + posterMatch.Groups[1].Value.Replace("\\", "/") : null;
var link = new Uri(_settings.BaseUrl + row.Children[4].FirstElementChild.GetAttribute("href"));
var description = row.Children[2].QuerySelector("span").TextContent;
@@ -330,13 +329,6 @@ namespace NzbDrone.Core.Indexers.Definitions
var imdbLink = row.QuerySelector("a[href*=\"www.imdb.com/title/\"]")?.GetAttribute("href");
var imdb = !string.IsNullOrWhiteSpace(imdbLink) ? ParseUtil.GetImdbID(imdbLink) : null;
var flags = new HashSet<IndexerFlag>();
if (row.QuerySelector("img[src$=\"internal.png\"]") != null)
{
flags.Add(IndexerFlag.Internal);
}
var release = new TorrentInfo
{
Title = title,
@@ -351,7 +343,6 @@ namespace NzbDrone.Core.Indexers.Definitions
Grabs = grabs,
Seeders = seeders,
Peers = peers,
IndexerFlags = flags,
DownloadVolumeFactor = dlVolumeFactor,
UploadVolumeFactor = upVolumeFactor,
MinimumRatio = 1,

View File

@@ -20,7 +20,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
public override string Name => "IPTorrents";
public override string[] IndexerUrls => new[]
public override string[] IndexerUrls => new string[]
{
"https://iptorrents.com/",
"https://iptorrents.me/",
@@ -46,7 +46,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new IPTorrentsRequestGenerator { Settings = Settings, Capabilities = Capabilities };
return new IPTorrentsRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
}
public override IParseIndexerResponse GetParser()
@@ -64,21 +64,21 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(72, NewznabStandardCategory.Movies, "Movies");
@@ -161,7 +161,11 @@ namespace NzbDrone.Core.Indexers.Definitions
public IPTorrentsSettings Settings { get; set; }
public IndexerCapabilities Capabilities { get; set; }
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, int limit, int offset, string imdbId = null)
public IPTorrentsRequestGenerator()
{
}
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null)
{
var searchUrl = Settings.BaseUrl + "t";
@@ -190,16 +194,7 @@ namespace NzbDrone.Core.Indexers.Definitions
qc.Add(cat, string.Empty);
}
if (offset > 0 && limit > 0)
{
var page = (int)(offset / limit) + 1;
qc.Add("p", page.ToString());
}
if (qc.Count > 0)
{
searchUrl += $"?{qc.GetQueryString()}";
}
searchUrl = searchUrl + "?" + qc.GetQueryString();
var request = new IndexerRequest(searchUrl, HttpAccept.Html);
@@ -215,7 +210,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories, searchCriteria.Limit ?? 100, searchCriteria.Offset ?? 0, searchCriteria.FullImdbId));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
return pageableRequests;
}
@@ -224,7 +219,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.Limit ?? 100, searchCriteria.Offset ?? 0));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -233,7 +228,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.Limit ?? 100, searchCriteria.Offset ?? 0, searchCriteria.FullImdbId));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId));
return pageableRequests;
}
@@ -242,7 +237,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.Limit ?? 100, searchCriteria.Offset ?? 0));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -251,7 +246,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.Limit ?? 100, searchCriteria.Offset ?? 0));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -359,10 +354,14 @@ namespace NzbDrone.Core.Indexers.Definitions
public class IPTorrentsSettings : CookieTorrentBaseSettings
{
public IPTorrentsSettings()
{
}
[FieldDefinition(2, Label = "Cookie User-Agent", Type = FieldType.Textbox, HelpText = "User-Agent associated with cookie used from Browser")]
public string UserAgent { get; set; }
[FieldDefinition(3, Label = "FreeLeech Only", Type = FieldType.Checkbox, HelpText = "Search Freeleech torrents only")]
[FieldDefinition(3, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")]
public bool FreeLeechOnly { get; set; }
}
}

View File

@@ -1,14 +1,16 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using AngleSharp.Html.Parser;
using FluentValidation;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings;
@@ -16,18 +18,21 @@ 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 class ImmortalSeed : TorrentIndexerBase<UserPassTorrentBaseSettings>
{
public override string Name => "ImmortalSeed";
public override string[] IndexerUrls => new[] { "https://immortalseed.me/" };
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";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
private string LoginUrl => Settings.BaseUrl + "takelogin.php";
public ImmortalSeed(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
@@ -36,7 +41,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new ImmortalSeedRequestGenerator { Settings = Settings, Capabilities = Capabilities };
return new ImmortalSeedRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
}
public override IParseIndexerResponse GetParser()
@@ -48,8 +53,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var requestBuilder = new HttpRequestBuilder(LoginUrl)
{
LogResponseContent = true,
AllowAutoRedirect = true
LogResponseContent = true
};
requestBuilder.Method = HttpMethod.Post;
@@ -61,12 +65,12 @@ namespace NzbDrone.Core.Indexers.Definitions
var authLoginRequest = requestBuilder
.AddFormParameter("username", Settings.Username)
.AddFormParameter("password", Settings.Password)
.SetHeader("Content-Type", "application/x-www-form-urlencoded")
.SetHeader("Content-Type", "multipart/form-data")
.Build();
var response = await ExecuteAuth(authLoginRequest);
if (!response.Content.Contains("logout.php"))
if (!response.Content.Contains("You have successfully logged in"))
{
throw new IndexerAuthException("ImmortalSeed Auth Failed");
}
@@ -79,7 +83,12 @@ namespace NzbDrone.Core.Indexers.Definitions
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return httpResponse.Content.Contains("You do not have permission to access this page.");
if (httpResponse.Content.Contains("You do not have permission to access this page."))
{
return true;
}
return false;
}
private IndexerCapabilities SetCapabilities()
@@ -87,21 +96,21 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Other, "Nuked");
@@ -110,45 +119,42 @@ namespace NzbDrone.Core.Indexers.Definitions
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(53, NewznabStandardCategory.TVDocumentary, "Documentary - SD");
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.BooksEBook, "Ebooks");
caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.BooksComics, "Ebooks -- Comics");
caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.BooksMags, "Ebooks -- Magazines");
caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.BooksComics, "Comics");
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.PCGames, "Games");
caps.Categories.AddCategoryMapping(61, NewznabStandardCategory.ConsoleNDS, "Games -- Nintendo");
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.PCGames, "Games -- PC");
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.ConsolePS3, "Games -- Playstation");
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.ConsoleXBox, "Games -- Xbox");
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(51, NewznabStandardCategory.PCMobileAndroid, "Mobile -- Android");
caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.PCMobileiOS, "Mobile -- IOS");
caps.Categories.AddCategoryMapping(52, NewznabStandardCategory.PCMobileOther, "Mobile -- Windows");
caps.Categories.AddCategoryMapping(59, NewznabStandardCategory.MoviesUHD, "Movies-4k");
caps.Categories.AddCategoryMapping(60, NewznabStandardCategory.MoviesForeign, "Movies-4k -- Non-English");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.MoviesHD, "Movies-HD");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.MoviesForeign, "Movies-HD -- Non-English");
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.MoviesSD, "Movies-Low Def");
caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.MoviesForeign, "Movies-Low Def -- Non-English");
caps.Categories.AddCategoryMapping(62, NewznabStandardCategory.Movies, "Movies-Packs");
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(33, NewznabStandardCategory.MoviesForeign, "Movies SD Non-English");
caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.AudioOther, "Music");
caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.AudioLossless, "Music -- FLAC");
caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.AudioMP3, "Music -- MP3");
caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.AudioOther, "Music -- Other");
caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.AudioVideo, "Music -- Video");
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 Tv -- Fitness-Instructional");
caps.Categories.AddCategoryMapping(58, NewznabStandardCategory.TVSport, "Sports Tv -- Olympics");
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(64, NewznabStandardCategory.TVUHD, "TV - 4K");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TVHD, "TV - High Definition");
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.TVSD, "TV SD - x264");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVSD, "TV SD - XviD");
caps.Categories.AddCategoryMapping(63, NewznabStandardCategory.TVUHD, "TV Season Packs - 4K");
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;
}
@@ -159,33 +165,27 @@ namespace NzbDrone.Core.Indexers.Definitions
public UserPassTorrentBaseSettings Settings { get; set; }
public IndexerCapabilities Capabilities { get; set; }
private IEnumerable<IndexerRequest> GetPagedRequests(SearchCriteriaBase searchCriteria)
public ImmortalSeedRequestGenerator()
{
var parameters = new NameValueCollection();
}
var term = searchCriteria.SanitizedSearchTerm;
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null)
{
var searchUrl = Settings.BaseUrl + "browse.php?";
if (term.IsNotNullOrWhiteSpace())
{
parameters.Add("do", "search");
parameters.Add("keywords", term.Trim());
parameters.Add("search_type", "t_name");
parameters.Add("category", "0");
parameters.Add("include_dead_torrents", "no");
searchUrl += string.Format("do=search&keywords={0}&search_type=t_name&category=0&include_dead_torrents=no", WebUtility.UrlEncode(term));
}
var queryCats = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories);
if (queryCats.Count > 0)
if (categories != null && categories.Length > 0)
{
parameters.Add("selectedcats2", string.Join(",", queryCats));
}
if (term.IsNotNullOrWhiteSpace())
{
searchUrl += "&";
}
var searchUrl = Settings.BaseUrl + "browse.php";
if (parameters.Count > 0)
{
searchUrl += $"?{parameters.GetQueryString()}";
searchUrl += "selectedcats2=" + string.Join(",", Capabilities.Categories.MapTorznabCapsToTrackers(categories));
}
var request = new IndexerRequest(searchUrl, HttpAccept.Html);
@@ -196,7 +196,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(searchCriteria));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
return pageableRequests;
}
@@ -204,7 +205,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(searchCriteria));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -212,7 +214,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(searchCriteria));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId));
return pageableRequests;
}
@@ -220,7 +223,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(searchCriteria));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -228,7 +232,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(searchCriteria));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}

View File

@@ -9,8 +9,6 @@ using System.Threading.Tasks;
using FluentValidation;
using Newtonsoft.Json;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Annotations;
@@ -27,30 +25,29 @@ namespace NzbDrone.Core.Indexers.Definitions
{
public class MyAnonamouse : TorrentIndexerBase<MyAnonamouseSettings>
{
private static readonly Regex TorrentIdRegex = new Regex(@"tor/download.php\?tid=(?<id>\d+)$");
public override string Name => "MyAnonamouse";
public override string[] IndexerUrls => new[] { "https://www.myanonamouse.net/" };
public override string[] IndexerUrls => new string[] { "https://www.myanonamouse.net/" };
public override string Description => "MyAnonaMouse (MAM) is a large ebook and audiobook tracker.";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override int PageSize => 100;
public override IndexerCapabilities Capabilities => SetCapabilities();
private readonly ICacheManager _cacheManager;
private static readonly Regex TorrentIdRegex = new Regex(@"tor/download.php\?tid=(?<id>\d+)$");
public MyAnonamouse(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, ICacheManager cacheManager)
public MyAnonamouse(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{
_cacheManager = cacheManager;
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new MyAnonamouseRequestGenerator { Settings = Settings, Capabilities = Capabilities };
return new MyAnonamouseRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
}
public override IParseIndexerResponse GetParser()
{
return new MyAnonamouseParser(Settings, Capabilities.Categories, _httpClient, _cacheManager, _logger);
return new MyAnonamouseParser(Settings, Capabilities.Categories);
}
public override async Task<byte[]> Download(Uri link)
@@ -74,7 +71,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var indexerReq = new IndexerRequest(freeleechRequest);
var response = await FetchIndexerResponse(indexerReq).ConfigureAwait(false);
var resource = Json.Deserialize<MyAnonamouseBuyPersonalFreeleechResponse>(response.Content);
var resource = Json.Deserialize<MyAnonamouseFreeleechResponse>(response.Content);
if (resource.Success)
{
@@ -104,9 +101,9 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping("13", NewznabStandardCategory.AudioAudiobook, "AudioBooks");
@@ -213,97 +210,84 @@ namespace NzbDrone.Core.Indexers.Definitions
public MyAnonamouseSettings Settings { get; set; }
public IndexerCapabilities Capabilities { get; set; }
private IEnumerable<IndexerRequest> GetPagedRequests(SearchCriteriaBase searchCriteria)
public MyAnonamouseRequestGenerator()
{
var term = searchCriteria.SanitizedSearchTerm.Trim();
}
var searchType = Settings.SearchType switch
{
(int)MyAnonamouseSearchType.Active => "active",
(int)MyAnonamouseSearchType.Freeleech => "fl",
(int)MyAnonamouseSearchType.FreeleechOrVip => "fl-VIP",
(int)MyAnonamouseSearchType.Vip => "VIP",
(int)MyAnonamouseSearchType.NotVip => "nVIP",
_ => "all"
};
var parameters = new NameValueCollection
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories)
{
var qParams = new NameValueCollection
{
{ "tor[text]", term },
{ "tor[searchType]", searchType },
{ "tor[srchIn][title]", "true" },
{ "tor[srchIn][author]", "true" },
{ "tor[srchIn][narrator]", "true" },
{ "tor[searchType]", Settings.ExcludeVip ? "nVIP" : "all" }, // exclude VIP torrents
{ "tor[searchIn]", "torrents" },
{ "tor[hash]", "" },
{ "tor[sortType]", "default" },
{ "tor[perpage]", searchCriteria.Limit?.ToString() ?? "100" },
{ "tor[startNumber]", searchCriteria.Offset?.ToString() ?? "0" },
{ "tor[startNumber]", "0" },
{ "thumbnails", "1" }, // gives links for thumbnail sized versions of their posters
//{ "posterLink", "1"}, // gives links for a full sized poster
//{ "dlLink", "1"}, // include the url to download the torrent
{ "description", "1" } // include the description
//{"bookmarks", "0"} // include if the item is bookmarked or not
};
if (Settings.SearchInDescription)
{
parameters.Add("tor[srchIn][description]", "true");
}
if (Settings.SearchInSeries)
{
parameters.Add("tor[srchIn][series]", "true");
}
if (Settings.SearchInFilenames)
{
parameters.Add("tor[srchIn][filenames]", "true");
}
var catList = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories);
var catList = Capabilities.Categories.MapTorznabCapsToTrackers(categories);
if (catList.Any())
{
var index = 0;
foreach (var cat in catList)
{
parameters.Add("tor[cat][" + index + "]", cat);
qParams.Add("tor[cat][" + index + "]", cat);
index++;
}
}
else
{
parameters.Add("tor[cat][]", "0");
qParams.Add("tor[cat][]", "0");
}
var searchUrl = Settings.BaseUrl + "tor/js/loadSearchJSONbasic.php";
var urlSearch = Settings.BaseUrl + "tor/js/loadSearchJSONbasic.php";
if (parameters.Count > 0)
if (qParams.Count > 0)
{
searchUrl += $"?{parameters.GetQueryString()}";
urlSearch += $"?{qParams.GetQueryString()}";
}
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
var request = new IndexerRequest(urlSearch, HttpAccept.Json);
yield return request;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
var pageableRequests = new IndexerPageableRequestChain();
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
var pageableRequests = new IndexerPageableRequestChain();
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
var pageableRequests = new IndexerPageableRequestChain();
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(searchCriteria));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -312,7 +296,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(searchCriteria));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -325,26 +309,11 @@ namespace NzbDrone.Core.Indexers.Definitions
{
private readonly MyAnonamouseSettings _settings;
private readonly IndexerCapabilitiesCategories _categories;
private readonly IIndexerHttpClient _httpClient;
private readonly Logger _logger;
private readonly ICached<string> _userClassCache;
private readonly HashSet<string> _vipFreeleechUserClasses = new (StringComparer.OrdinalIgnoreCase)
{
"VIP",
"Elite VIP",
};
public MyAnonamouseParser(MyAnonamouseSettings settings,
IndexerCapabilitiesCategories categories,
IIndexerHttpClient httpClient,
ICacheManager cacheManager,
Logger logger)
public MyAnonamouseParser(MyAnonamouseSettings settings, IndexerCapabilitiesCategories categories)
{
_settings = settings;
_categories = categories;
_httpClient = httpClient;
_logger = logger;
_userClassCache = cacheManager.GetCache<string>(GetType());
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
@@ -352,7 +321,7 @@ namespace NzbDrone.Core.Indexers.Definitions
// Throw auth errors here before we try to parse
if (indexerResponse.HttpResponse.StatusCode == HttpStatusCode.Forbidden)
{
throw new IndexerAuthException("[403 Forbidden] - mam_id expired or invalid");
throw new IndexerAuthException("[403 Forbidden] - mam_session_id expired or invalid");
}
// Throw common http errors here before we try to parse
@@ -382,46 +351,45 @@ namespace NzbDrone.Core.Indexers.Definitions
return torrentInfos.ToArray();
}
var hasUserVip = HasUserVip();
foreach (var item in jsonResponse.Data)
{
//TODO shift to ReleaseInfo object initializer for consistency
var release = new TorrentInfo();
var id = item.Id;
release.Title = item.Title;
release.Description = item.Description;
// release.Description = item.Value<string>("description");
var author = string.Empty;
if (item.AuthorInfo != null)
{
var authorInfo = JsonConvert.DeserializeObject<Dictionary<string, string>>(item.AuthorInfo);
var author = authorInfo?.Take(5).Select(v => v.Value).Join(", ");
author = authorInfo?.First().Value;
}
if (author.IsNotNullOrWhiteSpace())
{
release.Title += " by " + author;
}
if (author != null)
{
release.Title += " by " + author;
}
var flags = new List<string>();
var languageCode = item.LanguageCode;
if (!string.IsNullOrEmpty(languageCode))
var langCode = item.LangCode;
if (!string.IsNullOrEmpty(langCode))
{
flags.Add(languageCode);
flags.Add(langCode);
}
var filetype = item.Filetype;
if (!string.IsNullOrEmpty(filetype))
{
flags.Add(filetype.ToUpper());
flags.Add(filetype);
}
if (flags.Count > 0)
{
release.Title += " [" + flags.Join(" / ") + "]";
release.Title += " [" + string.Join(" / ", flags) + "]";
}
if (item.Vip)
@@ -429,20 +397,26 @@ namespace NzbDrone.Core.Indexers.Definitions
release.Title += " [VIP]";
}
release.DownloadUrl = _settings.BaseUrl + "tor/download.php?tid=" + id;
release.InfoUrl = _settings.BaseUrl + "t/" + id;
var category = item.Category;
release.Categories = _categories.MapTrackerCatToNewznab(category);
release.DownloadUrl = _settings.BaseUrl + "/tor/download.php?tid=" + id;
release.InfoUrl = _settings.BaseUrl + "/t/" + id;
release.Guid = release.InfoUrl;
release.Categories = _categories.MapTrackerCatToNewznab(item.Category);
release.PublishDate = DateTime.ParseExact(item.Added, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime();
var dateStr = item.Added;
var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
release.PublishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime();
release.Grabs = item.Grabs;
release.Files = item.NumFiles;
release.Seeders = item.Seeders;
release.Peers = item.Leechers + release.Seeders;
release.Size = ParseUtil.GetBytes(item.Size);
release.DownloadVolumeFactor = item.Free ? 0 : hasUserVip && item.FreeVip ? 0 : 1;
var size = item.Size;
release.Size = ParseUtil.GetBytes(size);
release.DownloadVolumeFactor = item.Free ? 0 : 1;
release.UploadVolumeFactor = 1;
release.MinimumRatio = 1;
release.MinimumSeedTime = 259200; // 72 hours
torrentInfos.Add(release);
}
@@ -450,33 +424,6 @@ namespace NzbDrone.Core.Indexers.Definitions
return torrentInfos.ToArray();
}
private bool HasUserVip()
{
var cacheKey = "myanonamouse_user_class_" + _settings.ToJson().SHA256Hash();
var userClass = _userClassCache.Get(
cacheKey,
() =>
{
var request = new HttpRequestBuilder(_settings.BaseUrl.Trim('/'))
.Resource("/jsonLoad.php")
.Accept(HttpAccept.Json)
.Build();
_logger.Debug("Fetching user data: " + request.Url.FullUri);
request.Cookies.Add("mam_id", _settings.MamId);
var response = _httpClient.Get(request);
var jsonResponse = JsonConvert.DeserializeObject<MyAnonamouseUserDataResponse>(response.Content);
return jsonResponse.UserClass?.Trim();
},
TimeSpan.FromHours(1));
return _vipFreeleechUserClasses.Contains(userClass);
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
@@ -495,68 +442,39 @@ namespace NzbDrone.Core.Indexers.Definitions
public MyAnonamouseSettings()
{
MamId = "";
SearchType = (int)MyAnonamouseSearchType.All;
SearchInDescription = false;
SearchInSeries = false;
SearchInFilenames = false;
}
[FieldDefinition(2, Type = FieldType.Textbox, Label = "Mam Id", HelpText = "Mam Session Id (Created Under Preferences -> Security)")]
[FieldDefinition(2, Label = "Mam Id", HelpText = "Mam Session Id (Created Under Preferences -> Security)")]
public string MamId { get; set; }
[FieldDefinition(3, Type = FieldType.Select, Label = "Search Type", SelectOptions = typeof(MyAnonamouseSearchType), HelpText = "Specify the desired search type")]
public int SearchType { get; set; }
[FieldDefinition(3, Type = FieldType.Checkbox, Label = "Exclude VIP", HelpText = "Exclude VIP Torrents from search results")]
public bool ExcludeVip { get; set; }
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "Buy Freeleech Token", HelpText = "Buy personal freeleech token for download")]
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "Freeleech", HelpText = "Use freeleech token for download")]
public bool Freeleech { get; set; }
[FieldDefinition(5, Type = FieldType.Checkbox, Label = "Search in description", HelpText = "Search text in the description")]
public bool SearchInDescription { get; set; }
[FieldDefinition(6, Type = FieldType.Checkbox, Label = "Search in series", HelpText = "Search text in the series")]
public bool SearchInSeries { get; set; }
[FieldDefinition(7, Type = FieldType.Checkbox, Label = "Search in filenames", HelpText = "Search text in the filenames")]
public bool SearchInFilenames { get; set; }
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
public enum MyAnonamouseSearchType
{
[FieldOption(Label="All torrents", Hint = "Search everything")]
All = 0,
[FieldOption(Label="Only active", Hint = "Last update had 1+ seeders")]
Active = 1,
[FieldOption(Label="Freeleech", Hint = "Freeleech torrents")]
Freeleech = 2,
[FieldOption(Label="Freeleech or VIP", Hint = "Freeleech or VIP torrents")]
FreeleechOrVip = 3,
[FieldOption(Label="VIP", Hint = "VIP torrents")]
Vip = 4,
[FieldOption(Label="Not VIP", Hint = "Torrents not VIP")]
NotVip = 5,
}
public class MyAnonamouseTorrent
{
public int Id { get; set; }
public string Title { get; set; }
[JsonProperty(PropertyName = "author_info")]
public string AuthorInfo { get; set; }
public string Description { get; set; }
[JsonProperty(PropertyName = "lang_code")]
public string LanguageCode { get; set; }
public string LangCode { get; set; }
public string Filetype { get; set; }
public bool Vip { get; set; }
public bool Free { get; set; }
[JsonProperty(PropertyName = "fl_vip")]
public bool FreeVip { get; set; }
public string Category { get; set; }
public string Added { get; set; }
[JsonProperty(PropertyName = "times_completed")]
public int Grabs { get; set; }
public int Seeders { get; set; }
@@ -571,15 +489,9 @@ namespace NzbDrone.Core.Indexers.Definitions
public List<MyAnonamouseTorrent> Data { get; set; }
}
public class MyAnonamouseBuyPersonalFreeleechResponse
public class MyAnonamouseFreeleechResponse
{
public bool Success { get; set; }
public string Error { get; set; }
}
public class MyAnonamouseUserDataResponse
{
[JsonProperty(PropertyName = "class")]
public string UserClass { get; set; }
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using FluentValidation;
using NLog;
@@ -24,7 +25,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public class Orpheus : TorrentIndexerBase<OrpheusSettings>
{
public override string Name => "Orpheus";
public override string[] IndexerUrls => new[] { "https://orpheus.network/" };
public override string[] IndexerUrls => new string[] { "https://orpheus.network/" };
public override string Description => "Orpheus (APOLLO) is a Private Torrent Tracker for MUSIC";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
@@ -38,7 +39,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new OrpheusRequestGenerator { Settings = Settings, Capabilities = Capabilities, HttpClient = _httpClient };
return new OrpheusRequestGenerator() { Settings = Settings, Capabilities = Capabilities, HttpClient = _httpClient };
}
public override IParseIndexerResponse GetParser()
@@ -51,13 +52,13 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q, MusicSearchParam.Album, MusicSearchParam.Artist, MusicSearchParam.Label, MusicSearchParam.Year
},
{
MusicSearchParam.Q, MusicSearchParam.Album, MusicSearchParam.Artist, MusicSearchParam.Label, MusicSearchParam.Year
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Audio, "Music");
@@ -120,6 +121,10 @@ namespace NzbDrone.Core.Indexers.Definitions
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
public IIndexerHttpClient HttpClient { get; set; }
public OrpheusRequestGenerator()
{
}
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
@@ -255,14 +260,24 @@ namespace NzbDrone.Core.Indexers.Definitions
foreach (var torrent in result.Torrents)
{
var id = torrent.TorrentId;
var artist = WebUtility.HtmlDecode(result.Artist);
var album = WebUtility.HtmlDecode(result.GroupName);
var title = $"{result.Artist} - {result.GroupName} ({result.GroupYear}) [{torrent.Format} {torrent.Encoding}] [{torrent.Media}]";
if (torrent.HasCue)
{
title += " [Cue]";
}
var title = GetTitle(result, torrent);
var infoUrl = GetInfoUrl(result.GroupId, id);
var release = new GazelleInfo
GazelleInfo release = new GazelleInfo()
{
Guid = infoUrl,
// Splice Title from info to avoid calling API again for every torrent.
Title = WebUtility.HtmlDecode(title),
Container = torrent.Encoding,
Codec = torrent.Format,
Size = long.Parse(torrent.Size),
@@ -299,7 +314,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var id = result.TorrentId;
var infoUrl = GetInfoUrl(result.GroupId, id);
var release = new GazelleInfo
GazelleInfo release = new GazelleInfo()
{
Guid = infoUrl,
Title = WebUtility.HtmlDecode(result.GroupName),
@@ -337,25 +352,6 @@ namespace NzbDrone.Core.Indexers.Definitions
.ToArray();
}
private string GetTitle(GazelleRelease result, GazelleTorrent torrent)
{
var title = $"{result.Artist} - {result.GroupName} ({result.GroupYear})";
if (torrent.RemasterTitle.IsNotNullOrWhiteSpace())
{
title += $" [{string.Format("{0} {1}", torrent.RemasterTitle, torrent.RemasterYear).Trim()}]";
}
title += $" [{torrent.Format} {torrent.Encoding}] [{torrent.Media}]";
if (torrent.HasCue)
{
title += " [Cue]";
}
return title;
}
private string GetDownloadUrl(int torrentId, bool canUseToken)
{
// AuthKey is required but not checked, just pass in a dummy variable
@@ -395,7 +391,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public class OrpheusSettings : NoAuthTorrentBaseSettings
{
private static readonly OrpheusSettingsValidator Validator = new ();
private static readonly OrpheusSettingsValidator Validator = new OrpheusSettingsValidator();
public OrpheusSettings()
{

View File

@@ -72,7 +72,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
var id = torrent.Id;
var title = torrent.ReleaseName;
var flags = new HashSet<IndexerFlag>();
var flags = new List<IndexerFlag>();
if (torrent.GoldenPopcorn)
{

View File

@@ -6,26 +6,21 @@ using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions
{
public class PrivateHD : AvistazBase
public class PrivateHD : Avistaz.AvistazBase
{
public override string Name => "PrivateHD";
public override string[] IndexerUrls => new[] { "https://privatehd.to/" };
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)
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
return new AvistazRequestGenerator()
{
Settings = Settings,
HttpClient = _httpClient,
@@ -39,13 +34,13 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId, TvSearchParam.Genre
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId, TvSearchParam.Genre
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.Genre
}
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId, MovieSearchParam.Genre
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies);

View File

@@ -17,16 +17,20 @@ namespace NzbDrone.Core.Indexers.Rarbg
{
public class Rarbg : TorrentIndexerBase<RarbgSettings>
{
public override string Name => "Rarbg";
public override string[] IndexerUrls => new[] { "https://torrentapi.org/" };
public override string[] LegacyUrls => new[] { "https://torrentapi.org" };
public override string Description => "RARBG is a Public torrent site for MOVIES / TV / GENERAL";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override TimeSpan RateLimit => TimeSpan.FromSeconds(5);
private readonly IRarbgTokenProvider _tokenProvider;
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 IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();
public override TimeSpan RateLimit => TimeSpan.FromSeconds(4);
public Rarbg(IRarbgTokenProvider tokenProvider, IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{
@@ -40,7 +44,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
public override IParseIndexerResponse GetParser()
{
return new RarbgParser(Capabilities, _logger);
return new RarbgParser(Capabilities);
}
private IndexerCapabilities SetCapabilities()
@@ -48,17 +52,17 @@ namespace NzbDrone.Core.Indexers.Rarbg
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
},
{
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
}
{
MusicSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.XXX, "XXX (18+)");
@@ -102,7 +106,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
if (jsonResponse.Resource.error_code.HasValue)
{
if (jsonResponse.Resource.error_code is 4 or 2)
if (jsonResponse.Resource.error_code == 4 || jsonResponse.Resource.error_code == 2)
{
_logger.Debug("Invalid or expired token, refreshing token from Rarbg");
_tokenProvider.ExpireToken(Settings);
@@ -114,7 +118,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
request.HttpRequest.Url = request.Url.SetQuery(qs.GetQueryString());
response = await FetchIndexerResponse(request);
}
else if (jsonResponse.Resource.error_code is 5)
else if (jsonResponse.Resource.error_code == 5)
{
_logger.Debug("Rarbg temp rate limit hit, retrying request");
response = await FetchIndexerResponse(request);
@@ -151,9 +155,9 @@ namespace NzbDrone.Core.Indexers.Rarbg
Settings.Validate().Filter("BaseUrl").ThrowOnError();
var request = new HttpRequestBuilder(Settings.BaseUrl.Trim('/'))
.Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}")
.Accept(HttpAccept.Json)
.Build();
.Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}")
.Accept(HttpAccept.Json)
.Build();
_httpClient.Get(request);
@@ -162,8 +166,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
captchaToken = ""
};
}
if (action == "getCaptchaCookie")
else if (action == "getCaptchaCookie")
{
if (query["responseUrl"].IsNullOrWhiteSpace())
{
@@ -197,8 +200,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
captchaToken = cfClearanceCookie
};
}
if (action == "getUrls")
else if (action == "getUrls")
{
var links = IndexerUrls;

View File

@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers.Exceptions;
@@ -15,12 +14,10 @@ namespace NzbDrone.Core.Indexers.Rarbg
private static readonly Regex RegexGuid = new Regex(@"^magnet:\?xt=urn:btih:([a-f0-9]+)", RegexOptions.Compiled);
private readonly IndexerCapabilities _capabilities;
private readonly Logger _logger;
public RarbgParser(IndexerCapabilities capabilities, Logger logger)
public RarbgParser(IndexerCapabilities capabilities)
{
_capabilities = capabilities;
_logger = logger;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
@@ -44,19 +41,12 @@ namespace NzbDrone.Core.Indexers.Rarbg
if (jsonResponse.Resource.error_code.HasValue)
{
if (jsonResponse.Resource.error_code is 20 or 8 or 9 or 10 or 5 or 13 or 14)
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 == 5 || jsonResponse.Resource.error_code == 13
|| jsonResponse.Resource.error_code == 14)
{
var reason = $"{jsonResponse.Resource.error} ({jsonResponse.Resource.error_code})";
if (jsonResponse.Resource.rate_limit is 1)
{
_logger.Debug("No results due to rate limiting. Reason: {0}", reason);
}
else
{
_logger.Debug("No results or imdbid/tvdb not found. Reason: {0}", reason);
}
// No results, rate limit, or imdbid/tvdb not found
return results;
}

View File

@@ -22,11 +22,12 @@ namespace NzbDrone.Core.Indexers.Rarbg
private IEnumerable<IndexerRequest> GetRequest(string term, int[] categories, string imdbId = null, int? tmdbId = null, int? tvdbId = null)
{
var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl.Trim('/'))
var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl)
.Resource("/pubapi_v2.php")
.AddQueryParam("mode", "search")
.Accept(HttpAccept.Json);
requestBuilder.AddQueryParam("mode", "search");
if (imdbId.IsNotNullOrWhiteSpace())
{
requestBuilder.AddQueryParam("search_imdb", imdbId);

View File

@@ -37,7 +37,7 @@ namespace NzbDrone.Core.Indexers.Rarbg
() =>
{
var requestBuilder = new HttpRequestBuilder(settings.BaseUrl.Trim('/'))
.WithRateLimit(5.0)
.WithRateLimit(3.0)
.Resource($"/pubapi_v2.php?get_token=get_token&app_id={BuildInfo.AppName}")
.Accept(HttpAccept.Json);

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using AngleSharp.Html.Parser;
using FluentValidation;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
@@ -15,6 +16,7 @@ using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
@@ -36,7 +38,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new SceneTimeRequestGenerator { Settings = Settings, Capabilities = Capabilities };
return new SceneTimeRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
}
public override IParseIndexerResponse GetParser()
@@ -54,21 +56,21 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.XXX, "Movies Adult");
@@ -110,6 +112,10 @@ namespace NzbDrone.Core.Indexers.Definitions
public SceneTimeSettings Settings { get; set; }
public IndexerCapabilities Capabilities { get; set; }
public SceneTimeRequestGenerator()
{
}
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories)
{
var qc = new NameValueCollection
@@ -274,7 +280,11 @@ namespace NzbDrone.Core.Indexers.Definitions
public class SceneTimeSettings : CookieTorrentBaseSettings
{
[FieldDefinition(3, Label = "FreeLeech Only", Type = FieldType.Checkbox, HelpText = "Search Freeleech torrents only")]
public SceneTimeSettings()
{
}
[FieldDefinition(3, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")]
public bool FreeLeechOnly { get; set; }
}
}

View File

@@ -19,7 +19,6 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete("Site unavailable")]
public class Shizaproject : TorrentIndexerBase<NoAuthTorrentBaseSettings>
{
public override string Name => "ShizaProject";

View File

@@ -7,6 +7,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AngleSharp.Html.Parser;
using FluentValidation;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
@@ -18,13 +19,14 @@ using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
public class SpeedCD : TorrentIndexerBase<SpeedCDSettings>
public class SpeedCD : TorrentIndexerBase<UserPassTorrentBaseSettings>
{
public override string Name => "SpeedCD";
public override string[] IndexerUrls => new[]
public override string[] IndexerUrls => new string[]
{
"https://speed.cd/",
"https://speed.click/",
@@ -38,18 +40,14 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
public SpeedCD(IIndexerHttpClient httpClient,
IEventAggregator eventAggregator,
IIndexerStatusService indexerStatusService,
IConfigService configService,
Logger logger)
public SpeedCD(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new SpeedCDRequestGenerator { Settings = Settings, Capabilities = Capabilities, Encoding = Encoding };
return new SpeedCDRequestGenerator() { Settings = Settings, Capabilities = Capabilities, Encoding = Encoding };
}
public override IParseIndexerResponse GetParser()
@@ -115,7 +113,12 @@ namespace NzbDrone.Core.Indexers.Definitions
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return !httpResponse.Content.Contains("/browse.php");
if (!httpResponse.Content.Contains("/browse.php"))
{
return true;
}
return false;
}
private IndexerCapabilities SetCapabilities()
@@ -123,21 +126,21 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesOther, "Movies/XviD");
@@ -179,13 +182,17 @@ namespace NzbDrone.Core.Indexers.Definitions
public class SpeedCDRequestGenerator : IIndexerRequestGenerator
{
public SpeedCDSettings Settings { get; set; }
public UserPassTorrentBaseSettings Settings { get; set; }
public IndexerCapabilities Capabilities { get; set; }
public Encoding Encoding { get; set; }
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, bool deep = false)
public SpeedCDRequestGenerator()
{
var searchUrl = $"{Settings.BaseUrl.TrimEnd('/')}/browse/";
}
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null)
{
var searchUrl = string.Format("{0}/browse/", Settings.BaseUrl.TrimEnd('/'));
var qc = new List<string>();
@@ -195,18 +202,17 @@ namespace NzbDrone.Core.Indexers.Definitions
qc.Add(cat);
}
if (Settings.FreeleechOnly)
{
qc.Add("freeleech");
}
if (deep)
if (imdbId.IsNotNullOrWhiteSpace())
{
qc.Add("deep");
qc.Add("q");
qc.Add(imdbId);
}
else
{
qc.Add("q");
qc.Add(term.UrlEncode(Encoding));
}
qc.Add("q");
qc.Add(term.UrlEncode(Encoding));
searchUrl += string.Join("/", qc);
@@ -219,14 +225,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
var term = $"{searchCriteria.SanitizedSearchTerm}";
if (searchCriteria.FullImdbId.IsNotNullOrWhiteSpace())
{
term = $"{searchCriteria.FullImdbId}";
}
pageableRequests.Add(GetPagedRequests(term.Trim(), searchCriteria.Categories, searchCriteria.FullImdbId.IsNotNullOrWhiteSpace()));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
return pageableRequests;
}
@@ -235,7 +234,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -244,24 +243,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
var term = $"{searchCriteria.SanitizedTvSearchString}";
if (searchCriteria.FullImdbId.IsNotNullOrWhiteSpace())
{
term = $"{searchCriteria.FullImdbId}";
if (searchCriteria.EpisodeSearchString.IsNotNullOrWhiteSpace())
{
term += $" {searchCriteria.EpisodeSearchString}";
}
if (searchCriteria.Season.HasValue)
{
term += "*";
}
}
pageableRequests.Add(GetPagedRequests(term.Trim(), searchCriteria.Categories, searchCriteria.FullImdbId.IsNotNullOrWhiteSpace()));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId));
return pageableRequests;
}
@@ -270,7 +252,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -279,7 +261,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories));
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
return pageableRequests;
}
@@ -290,10 +272,10 @@ namespace NzbDrone.Core.Indexers.Definitions
public class SpeedCDParser : IParseIndexerResponse
{
private readonly SpeedCDSettings _settings;
private readonly UserPassTorrentBaseSettings _settings;
private readonly IndexerCapabilitiesCategories _categories;
public SpeedCDParser(SpeedCDSettings settings, IndexerCapabilitiesCategories categories)
public SpeedCDParser(UserPassTorrentBaseSettings settings, IndexerCapabilitiesCategories categories)
{
_settings = settings;
_categories = categories;
@@ -309,26 +291,28 @@ namespace NzbDrone.Core.Indexers.Definitions
foreach (var row in rows)
{
var title = Regex.Replace(row.QuerySelector("td:nth-child(2) > div > a[href^=\"/t/\"]").TextContent, @"(?i:\[REQ\])", "").Trim(' ', '.');
var downloadUrl = new Uri(_settings.BaseUrl + row.QuerySelector("td:nth-child(4) a[href^=\"/download/\"]").GetAttribute("href").TrimStart('/'));
var infoUrl = new Uri(_settings.BaseUrl + row.QuerySelector("td:nth-child(2) > div > a[href^=\"/t/\"]").GetAttribute("href").TrimStart('/'));
var size = ParseUtil.GetBytes(row.QuerySelector("td:nth-child(6)").TextContent);
var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)").TextContent);
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)").TextContent);
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(9)").TextContent);
var cells = row.QuerySelectorAll("td");
var pubDateStr = row.QuerySelector("td:nth-child(2) span[class^=\"elapsedDate\"]").GetAttribute("title").Replace(" at", "");
var title = row.QuerySelector("td[class='lft'] > div > a").TextContent.Trim();
var link = new Uri(_settings.BaseUrl + row.QuerySelector("img[title='Download']").ParentElement.GetAttribute("href").TrimStart('/'));
var details = new Uri(_settings.BaseUrl + row.QuerySelector("td[class='lft'] > div > a").GetAttribute("href").TrimStart('/'));
var size = ParseUtil.GetBytes(cells[5].TextContent);
var grabs = ParseUtil.CoerceInt(cells[6].TextContent);
var seeders = ParseUtil.CoerceInt(cells[7].TextContent);
var leechers = ParseUtil.CoerceInt(cells[8].TextContent);
var pubDateStr = row.QuerySelector("span[class^='elapsedDate']").GetAttribute("title").Replace(" at", "");
var publishDate = DateTime.ParseExact(pubDateStr, "dddd, MMMM d, yyyy h:mmtt", CultureInfo.InvariantCulture);
var cat = row.QuerySelector("td:nth-child(1) a").GetAttribute("href").Split('/').Last();
var downloadVolumeFactor = row.QuerySelector("td:nth-child(2) span:contains(\"[Freeleech]\")") != null ? 0 : 1;
var cat = row.QuerySelector("a").GetAttribute("href").Split('/').Last();
var downloadVolumeFactor = row.QuerySelector("span:contains(\"[Freeleech]\")") != null ? 0 : 1;
var release = new TorrentInfo
{
Title = title,
DownloadUrl = downloadUrl.AbsoluteUri,
Guid = infoUrl.AbsoluteUri,
InfoUrl = infoUrl.AbsoluteUri,
DownloadUrl = link.AbsoluteUri,
Guid = link.AbsoluteUri,
InfoUrl = details.AbsoluteUri,
PublishDate = publishDate,
Categories = _categories.MapTrackerCatToNewznab(cat),
Size = size,
@@ -349,10 +333,4 @@ namespace NzbDrone.Core.Indexers.Definitions
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
public class SpeedCDSettings : UserPassTorrentBaseSettings
{
[FieldDefinition(4, Label = "Freeleech Only", Type = FieldType.Checkbox, HelpText = "Search freeleech torrents only")]
public bool FreeleechOnly { get; set; }
}
}

View File

@@ -229,14 +229,15 @@ namespace NzbDrone.Core.Indexers.Torznab
return base.GetPeers(item);
}
protected HashSet<IndexerFlag> GetFlags(XElement item)
protected List<IndexerFlag> GetFlags(XElement item)
{
var flags = new HashSet<IndexerFlag>();
var flags = new List<IndexerFlag>();
var downloadFactor = TryGetFloatTorznabAttribute(item, "downloadvolumefactor", 1);
var uploadFactor = TryGetFloatTorznabAttribute(item, "uploadvolumefactor", 1);
if (uploadFactor == 2.0)
if (uploadFactor == 2)
{
flags.Add(IndexerFlag.DoubleUpload);
}

View File

@@ -466,6 +466,5 @@
"AreYouSureYouWantToDeleteCategory": "Haluatko varmasti poistaa kartoitetun kategorian?",
"DeleteClientCategory": "Poista lataustyökalukategoria",
"DownloadClientCategory": "Lataustyökalukategoria",
"MappedCategories": "Kartoitetut kategoriat",
"AuthenticationRequired": "Todennus vaaditaan"
"MappedCategories": "Kartoitetut kategoriat"
}

View File

@@ -466,8 +466,5 @@
"AreYouSureYouWantToDeleteCategory": "Biztosan törölni szeretnéd a leképezett kategóriát?",
"DeleteClientCategory": "Letöltési kliens kategória törlése",
"MappedCategories": "Térképezett kategóriák",
"DownloadClientCategory": "Letöltési kliens kategória",
"AuthenticationRequired": "Azonosítás szükséges",
"AuthenticationRequiredHelpText": "Módosítsd, hogy mely kérésekhez van szükség hitelesítésre. Ne változtasson, hacsak nem érti a kockázatokat.",
"AuthenticationRequiredWarning": "A hitelesítés nélküli távoli hozzáférés megakadályozása érdekében a Prowlarrnak mostantól engedélyezni kell a hitelesítést. Konfigurálja a hitelesítési módszert és a hitelesítési adatokat. Opcionálisan letilthatja a helyi címekről történő hitelesítést. További információkért tekintsd meg a GYIK-et."
"DownloadClientCategory": "Letöltési kliens kategória"
}

View File

@@ -20,7 +20,7 @@
"AppDataLocationHealthCheckMessage": "L'aggiornamento non sarà possibile per evitare la cancellazione di AppData durante l'aggiornamento",
"Analytics": "Analitica",
"Added": "Aggiunto",
"About": "Info",
"About": "Informazioni",
"Updates": "Aggiornamenti",
"UpdateCheckUINotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella dell'interfaccia '{0}'.",
"UpdateCheckStartupNotWritableMessage": "Impossibile installare l'aggiornamento perché l'utente '{1}' non ha i permessi di scrittura per la cartella di avvio '{0}'.",
@@ -79,7 +79,7 @@
"Connect": "Notifiche",
"Connections": "Collegamenti",
"ConnectSettingsSummary": "Notifiche e script personalizzati",
"BackupNow": "Esegui backup ora",
"BackupNow": "Effettua il Backup adesso",
"Backup": "Backup",
"All": "Tutti",
"Actions": "Azioni",
@@ -112,7 +112,7 @@
"Type": "Tipo",
"Title": "Titolo",
"Time": "Ora",
"TestAll": "Prova Tutti",
"TestAll": "Testa Tutti",
"Test": "Test",
"TableOptionsColumnsMessage": "Scegli quali colonne rendere visibili ed il loro ordine",
"TableOptions": "Opzioni della tabella",
@@ -260,7 +260,7 @@
"UILanguageHelpText": "Lingua che Prowlarr userà per l'interfaccia",
"UILanguage": "Lingua dell'Interfaccia",
"Torrents": "Torrents",
"TestAllClients": "Testa tutti i client",
"TestAllClients": "Testa Tutti i Client",
"TagsHelpText": "Si applica agli Indicizzatori con almeno un etichetta corrispondente",
"TagIsNotUsedAndCanBeDeleted": "L'etichetta non è in uso e può essere eliminata",
"TagCannotBeDeletedWhileInUse": "Non può essere cancellato mentre è in uso",
@@ -294,7 +294,7 @@
"MovieIndexScrollBottom": "Indice Film: scorri in basso",
"FocusSearchBox": "Evidenzia casella di ricerca",
"CloseCurrentModal": "Chiudi la Modale Attuale",
"AcceptConfirmationModal": "Accetta Conferma Modale",
"AcceptConfirmationModal": "Acetta Conferma Modale",
"IndexerLongTermStatusCheckSingleClientMessage": "Alcuni Indicizzatori non sono disponibili da più di 6 ore a causa di errori: {0}",
"IndexerLongTermStatusCheckAllClientMessage": "Nessun Indicizzatore è disponibile da più di 6 ore a causa di errori",
"PrioritySettings": "Priorità",
@@ -305,7 +305,7 @@
"EnableIndexer": "Abilita Indicizzatore",
"AddNewIndexer": "Aggiungi nuovo Indicizzatore",
"IndexerAuth": "Autenticazione dell'Indicizzatore",
"AddDownloadClient": "Aggiungi Downloader",
"AddDownloadClient": "Aggiungi Client di Download",
"Category": "Categoria",
"ClearHistory": "Cancella cronologia",
"ClearHistoryMessageText": "Sei sicuro di voler cancellare tutta la cronologia di Prowlarr?",
@@ -348,7 +348,7 @@
"OnApplicationUpdateHelpText": "All'aggiornamento dell'applicazione",
"OnGrab": "Al Prelievo",
"OnHealthIssue": "Quando c'è un problema",
"TestAllIndexers": "Prova tutti gli indicizzatori",
"TestAllIndexers": "Testa tutti gli Indicizzatori",
"UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent fornito dalla app che ha chiamato la API",
"GrabReleases": "Prendi Release(s)",
"Link": "Collegamenti",
@@ -360,7 +360,7 @@
"AudioSearch": "Ricerca Audio",
"BookSearch": "Ricerca Libri",
"AddRemoveOnly": "Solo Aggiunta e Rimozione",
"AppProfileSelectHelpText": "I profili delle App sono usati per controllare l'RSS, la ricerca automatica e ricerca interattiva durante la sincronizzazione dell'app",
"AppProfileSelectHelpText": "I profili delle App sono utilizzati per controllare la sincronizzazione delle impostazioni RSS, Ricerca Automatica e Ricerca Interattiva",
"DeleteApplication": "Cancella Applicazione",
"DeleteAppProfile": "Cancella Profilo App",
"AddedToDownloadClient": "Release aggiunta al client",
@@ -383,7 +383,7 @@
"IndexerVipCheckExpiringClientMessage": "I benefici VIP dell'Indicizzatore scadranno a breve: {0}",
"IndexerProxies": "Proxy degli Indicizzatori",
"Stats": "Statistiche",
"SyncAppIndexers": "Sincronizza tutti gli indicizzatori",
"SyncAppIndexers": "Sincronizza gli Indicizzatori dell'App",
"SyncLevel": "Livello Sincronizzazione",
"IndexerProxy": "Proxy dell'Indicizzatore",
"Proxies": "Proxy",
@@ -392,7 +392,7 @@
"IndexersSelectedInterp": "{0} Indicizzatore(i) Selezionato(i)",
"Privacy": "Privacy",
"SettingsIndexerLogging": "Logging Migliorato dell'Indicizzatore",
"TestAllApps": "Prova Tutte le App",
"TestAllApps": "Testa Tutte le App",
"UnableToLoadAppProfiles": "Impossibile caricare i profili delle app",
"UnableToLoadIndexerProxies": "Impossibile caricare i Proxy degli Indicizzatori",
"FullSync": "Sincronizzazione completa",
@@ -405,7 +405,7 @@
"IndexerRss": "RSS dell'Indicizzatore",
"IndexerSite": "Sito dell'Indicizzatore",
"MassEditor": "Editor di Massa",
"IndexerTagsHelpText": "Usa le etichette per specificare i Proxy degli Indicizzatori, con che app un indicizzatore si sincronizza o semplicemente per organizzarli.",
"IndexerTagsHelpText": "Usa le etichette per specificare i Proxy degli Indicizzatori, con che app un indicizzatore si sincronizza o semplcemente per organizzarli.",
"MovieSearch": "Ricerca Film",
"MovieSearchTypes": "Tipi di Ricerca Film",
"MusicSearchTypes": "Tipi di Ricerca Musica",
@@ -440,21 +440,21 @@
"SettingsIndexerLoggingHelpText": "Logga i dati aggiuntivi dell'indicizzatore includendo la risposta",
"SettingsSqlLoggingHelpText": "Scrivi a log tutte le query SQL di Prowlarr",
"SyncLevelAddRemove": "Solo aggiunte e rimozioni: Quando gli indicizzatori vengono aggiunti o rimossi da Prowlarr, verrà aggiornata questa applicazione remota.",
"SyncLevelFull": "Sincronizzazione completa: Mantiene gli indicizzatori dell'app completamente sincronizzati. Le modifiche apportate agli indicizzatori in Prowlarr sono sincronizzate in questa app. Qualsiasi cambiamento fatto agli indicizzatori da remoto all'interno di questa applicazione verrà sovrascritto da Prowlarr alla prossima sincronizzazione.",
"SyncLevelFull": "Sincronizzazione completa: Manterrà gli indicizzatori di questa app completamente sincronizzati. Le modifiche apportate agli indicizzatori in Prowlarr sono poi sincronizzate con questa applicazione. Qualsiasi cambiamento fatto agli indicizzatori da remoto all'interno di questa applicazione sarà sovrascritto da Prowlarr alla prossima sincronizzazione.",
"MinimumSeedersHelpText": "Seeder minimi richiesti dall'Applicazione per far sì che l'indicizzatore li prenda",
"SyncProfile": "Profilo Sincronizzazione",
"SyncProfiles": "Profili di sincronizzazione",
"SyncProfiles": "Profili Sincronizzazione",
"AddSyncProfile": "Aggiungi Profilo di Sincronizzazione",
"EditSyncProfile": "Modifica Profilo di Sincronizzazione",
"MinimumSeeders": "Seeder Minimi",
"InstanceName": "Nome Istanza",
"InstanceNameHelpText": "Nome istanza nella scheda e per il nome dell'app nel Syslog",
"InstanceNameHelpText": "Nome dell'istanza nella scheda e per il nome dell'applicazione Syslog",
"ThemeHelpText": "Cambia il Tema dell'interfaccia dellapplicazione, il Tema 'Auto' userà il suo Tema di Sistema per impostare la modalità Chiara o Scura. Ispirato da {0}",
"LastDuration": "Ultima Durata",
"LastExecution": "Ultima esecuzione",
"Queued": "In coda",
"ApplicationLongTermStatusCheckAllClientMessage": "Tutte le app non disponibili da almeno 6 ore a causa di errori",
"ApplicationLongTermStatusCheckSingleClientMessage": "Alcune app non sono disponibili da almeno 6 ore a causa di errori: {0}",
"Queued": "Messo in coda",
"ApplicationLongTermStatusCheckAllClientMessage": "Nessun Indicizzatore è disponibile da più di 6 ore a causa di errori",
"ApplicationLongTermStatusCheckSingleClientMessage": "Alcuni Indicizzatori non sono disponibili da più di 6 ore a causa di errori: {0}",
"Duration": "Durata",
"Ended": "Finito",
"NextExecution": "Prossima esecuzione",
@@ -462,12 +462,5 @@
"Parameters": "Parametri",
"ElapsedTime": "Tempo trascorso",
"EnabledRedirected": "Abilitato, Reindirizzato",
"Started": "Iniziato",
"AreYouSureYouWantToDeleteCategory": "Vuoi davvero cancellare la categoria mappata?",
"AuthenticationRequired": "Autenticazione richiesta",
"AuthenticationRequiredHelpText": "Cambia a quali richieste l'autenticazione verrà richiesta. Non cambiare se non comprendi i rischi.",
"AuthenticationRequiredWarning": "Per impedire accessi remoti senza autenticazione, Prowlarr ora richiede che l'autenticazione venga attivata. Puoi disattivare l'autenticazione per indirizzi privati.",
"DeleteClientCategory": "Cancella categoria del client di download",
"DownloadClientCategory": "Categoria client di download",
"MappedCategories": "Categorie mappate"
"Started": "Iniziato"
}

View File

@@ -154,7 +154,7 @@
"CertificateValidation": "Certificaat Validatie",
"BypassProxyForLocalAddresses": "Omzeil Proxy voor Lokale Adressen",
"Branch": "Branch",
"BindAddressHelpText": "Geldig IP-adres, localhost of '*' voor alle interfaces",
"BindAddressHelpText": "Geldig IPv4 adres of '*' voor alle interfaces",
"DeleteBackup": "Verwijder Veiligheidskopie",
"BackupIntervalHelpText": "Tussentijd voor automatische back-up",
"Backups": "Veiligheidskopieën",

View File

@@ -229,7 +229,7 @@
"Reset": "Redefinir",
"Restart": "Reiniciar",
"RestartNow": "Reiniciar agora",
"RestartRequiredHelpTextWarning": "Requer reinicialização para ter efeito",
"RestartRequiredHelpTextWarning": "Requer reinício para ter efeito",
"Restore": "Restaurar",
"RestoreBackup": "Restaurar backup",
"Result": "Resultado",
@@ -469,5 +469,5 @@
"MappedCategories": "Categorias Mapeadas",
"AuthenticationRequired": "Autenticação Requerida",
"AuthenticationRequiredHelpText": "Altera para quais solicitações a autenticação é necessária. Não mude a menos que você entenda os riscos.",
"AuthenticationRequiredWarning": "Para impedir o acesso remoto sem autenticação, o Prowlarr agora exige que a autenticação seja habilitada. Configure seu método de autenticação e credenciais. Você pode, opcionalmente, desabilitar a autenticação de endereços locais. Consulte o FAQ para obter informações adicionais."
"AuthenticationRequiredWarning": "Para impedir o acesso remoto sem autenticação, o Prowlarr agora exige que a autenticação seja habilitada. Você pode, opcionalmente, desabilitar a autenticação de endereços locais."
}

View File

@@ -99,7 +99,7 @@
"BackupFolderHelpText": "Относительные пути будут в каталоге AppData Radarr",
"BeforeUpdate": "До обновления",
"BindAddress": "Привязать адрес",
"BindAddressHelpText": "Действительный IP-адрес, локальный адрес или '*' для всех интерфейсов",
"BindAddressHelpText": "Действительный IP4-адрес или '*' для всех интерфейсов",
"Branch": "Ветка",
"BranchUpdate": "Ветвь для обновления Radarr",
"BranchUpdateMechanism": "Ветвь, используемая внешним механизмом обновления",

View File

@@ -60,7 +60,7 @@
"ApplyTagsHelpTexts2": "Додати: додати теги до наявного списку тегів",
"AuthenticationMethodHelpText": "Для доступу до Radarr потрібні ім’я користувача та пароль",
"BackupFolderHelpText": "Відносні шляхи будуть у каталозі AppData Radarr",
"BindAddressHelpText": "Дійсна адреса IP або '*' для всіх інтерфейсів",
"BindAddressHelpText": "Дійсна адреса IPv4 або '*' для всіх інтерфейсів",
"BranchUpdate": "Гілка для оновлення Radarr",
"AllIndexersHiddenDueToFilter": "Всі фільми заховані відповідно до фільтра.",
"AnalyticsEnabledHelpText": "Надсилайте анонімну інформацію про використання та помилки на сервери Radarr. Це включає інформацію про ваш веб-переглядач, які сторінки Radarr WebUI ви використовуєте, звіти про помилки, а також версію ОС і часу виконання. Ми будемо використовувати цю інформацію, щоб визначити пріоритети функцій і виправлення помилок.",
@@ -212,7 +212,7 @@
"Exception": "Виняток",
"ExistingTag": "Існуючий тег",
"Failed": "Не вдалося",
"FeatureRequests": "Майбутні запити",
"FeatureRequests": "Запити щодо функцій",
"Events": "Події",
"Fixed": "Виправлено",
"Filters": "Фільтри",
@@ -293,7 +293,7 @@
"Enable": "Увімкнути",
"Filename": "Ім'я файлу",
"Host": "Хост",
"PriorityHelpText": "Надайте пріоритет кільком клієнтам завантаження. Круговий алгоритм використовується для клієнтів з таким же пріоритетом.",
"PriorityHelpText": "Надайте пріоритет кільком клієнтам завантаження. Round-Robin використовується для клієнтів з однаковим пріоритетом.",
"SSLCertPathHelpText": "Шлях до файлу pfx",
"SSLPort": "Порт SSL",
"Started": "Розпочато",
@@ -303,19 +303,5 @@
"Style": "Стиль",
"SuggestTranslationChange": "Запропонуйте зміну перекладу",
"TableOptionsColumnsMessage": "Виберіть, які стовпці відображаються та в якому порядку вони відображаються",
"SystemTimeCheckMessage": "Системний час вимкнено більш ніж на 1 день. Заплановані завдання можуть не працювати належним чином, доки час не буде виправлено",
"OnGrab": "При захопленні",
"SSLCertPath": "Шлях сертифіката SSL",
"UI": "Інтерфейс користувача",
"Reddit": "Reddit",
"RSS": "RSS",
"Seeders": "Сиди",
"Wiki": "Wiki",
"Grabbed": "Захоплений",
"Logging": "Журналування",
"NetCore": ".NET",
"Peers": "Піри",
"Usenet": "Usenet",
"SSLCertPassword": "Пароль SSL сертифіката",
"MaintenanceRelease": "Випуск для обслуговування: виправлення помилок та інші покращення. Щоб отримати докладнішу інформацію, перегляньте історію фіксації Github"
"SystemTimeCheckMessage": "Системний час вимкнено більш ніж на 1 день. Заплановані завдання можуть не працювати належним чином, доки час не буде виправлено"
}

View File

@@ -1,53 +0,0 @@
using System;
using System.Collections.Generic;
using FluentValidation.Results;
using NLog;
namespace NzbDrone.Core.Notifications.Mailgun
{
public class MailGun : NotificationBase<MailgunSettings>
{
private readonly IMailgunProxy _proxy;
private readonly Logger _logger;
public MailGun(IMailgunProxy proxy, Logger logger)
{
_proxy = proxy;
_logger = logger;
}
public override string Name => "Mailgun";
public override string Link => "https://mailgun.com";
public override void OnHealthIssue(HealthCheck.HealthCheck healthCheckMessage)
{
_proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheckMessage.Message, Settings);
}
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
{
_proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings);
}
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();
try
{
const string title = "Test Notification";
const string body = "This is a test message from Prowlarr, though Mailgun.";
_proxy.SendNotification(title, body, Settings);
_logger.Info("Successsfully sent email though Mailgun.");
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message though Mailgun.");
failures.Add(new ValidationFailure("", "Unable to send test message though Mailgun."));
}
return new ValidationResult(failures);
}
}
}

View File

@@ -1,18 +0,0 @@
using System;
using NzbDrone.Common.Exceptions;
namespace NzbDrone.Core.Notifications.Mailgun
{
public class MailgunException : NzbDroneException
{
public MailgunException(string message)
: base(message)
{
}
public MailgunException(string message, Exception innerException, params object[] args)
: base(message, innerException, args)
{
}
}
}

View File

@@ -1,68 +0,0 @@
using System.Net;
using System.Net.Http;
using NLog;
using NzbDrone.Common.Http;
namespace NzbDrone.Core.Notifications.Mailgun
{
public interface IMailgunProxy
{
void SendNotification(string title, string message, MailgunSettings settings);
}
public class MailgunProxy : IMailgunProxy
{
private const string BaseUrlEu = "https://api.eu.mailgun.net/v3";
private const string BaseUrlUs = "https://api.mailgun.net/v3";
private readonly IHttpClient _httpClient;
private readonly Logger _logger;
public MailgunProxy(IHttpClient httpClient, Logger logger)
{
_httpClient = httpClient;
_logger = logger;
}
public void SendNotification(string title, string message, MailgunSettings settings)
{
try
{
var request = BuildRequest(settings, $"{settings.SenderDomain}/messages", HttpMethod.Post, title, message).Build();
_httpClient.Execute(request);
}
catch (HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{
_logger.Error("Unathorized - ApiKey is invalid");
throw new MailgunException("Unauthorized - ApiKey is invalid");
}
_logger.Error(ex, "Unable to connect to Mailgun. Status code: " + ex.Message);
throw new MailgunException("Unable to connect to Mailgun. Status code: {0}", ex);
}
}
private HttpRequestBuilder BuildRequest(MailgunSettings settings, string resource, HttpMethod method, string messageSubject, string messageBody)
{
var loginCredentials = new NetworkCredential("api", settings.ApiKey);
var url = settings.UseEuEndpoint ? BaseUrlEu : BaseUrlUs;
var requestBuilder = new HttpRequestBuilder(url).Resource(resource);
requestBuilder.Method = method;
requestBuilder.NetworkCredential = loginCredentials;
requestBuilder.AddFormParameter("from", $"{settings.From}");
foreach (var recipient in settings.Recipients)
{
requestBuilder.AddFormParameter("to", $"{recipient}");
}
requestBuilder.AddFormParameter("subject", $"{messageSubject}");
requestBuilder.AddFormParameter("text", $"{messageBody}");
return requestBuilder;
}
}
}

View File

@@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Notifications.Mailgun
{
public class MailGunSettingsValidator : AbstractValidator<MailgunSettings>
{
public MailGunSettingsValidator()
{
RuleFor(c => c.ApiKey).NotEmpty();
RuleFor(c => c.From).NotEmpty();
RuleFor(c => c.Recipients).NotEmpty();
}
}
public class MailgunSettings : IProviderConfig
{
private static readonly MailGunSettingsValidator Validator = new MailGunSettingsValidator();
public MailgunSettings()
{
Recipients = Array.Empty<string>();
}
[FieldDefinition(0, Label = "API Key", HelpText = "The API key generated from MailGun")]
public string ApiKey { get; set; }
[FieldDefinition(1, Label = "Use EU Endpoint?", HelpText = "Use the EU MailGun endpoint", Type = FieldType.Checkbox)]
public bool UseEuEndpoint { get; set; }
[FieldDefinition(2, Label = "From Address")]
public string From { get; set; }
[FieldDefinition(3, Label = "Sender Domain")]
public string SenderDomain { get; set; }
[FieldDefinition(4, Label = "Recipient Address(es)", Type = FieldType.Tag, Placeholder = "example@email.com,example1@email.com")]
public IEnumerable<string> Recipients { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

View File

@@ -10,7 +10,7 @@ namespace NzbDrone.Core.Parser.Model
{
public ReleaseInfo()
{
IndexerFlags = new HashSet<IndexerFlag>();
IndexerFlags = new List<IndexerFlag>();
Categories = new List<IndexerCategory>();
Languages = new List<string>();
Subs = new List<string>();
@@ -57,7 +57,7 @@ namespace NzbDrone.Core.Parser.Model
public ICollection<string> Languages { get; set; }
public ICollection<string> Subs { get; set; }
public ICollection<IndexerCategory> Categories { get; set; }
public HashSet<IndexerFlag> IndexerFlags { get; set; }
public ICollection<IndexerFlag> IndexerFlags { get; set; }
public int Age
{

View File

@@ -1577,11 +1577,6 @@ acorn-jsx@^5.3.2:
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn@^6.0.6:
version "6.4.2"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6"
integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==
acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0:
version "8.8.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
@@ -1731,16 +1726,6 @@ archiver@^5.3.1:
tar-stream "^2.2.0"
zip-stream "^4.1.0"
are-you-es5@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/are-you-es5/-/are-you-es5-2.1.2.tgz#d75511a174a3f842d70cc784aec0bcaff5a57547"
integrity sha512-gkT2bLCfzyJJr3lYoxZKScdD/Yp5zzghi+3KawONTvH/7rrgU3RMXYvGQnOTlqEFVgZFpEGj/6bZ6sF/9YtddA==
dependencies:
acorn "^6.0.6"
array-flatten "^2.1.0"
commander "^2.19.0"
find-up "^4.1.0"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
@@ -1764,11 +1749,6 @@ arr-union@^2.0.1:
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d"
integrity sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==
array-flatten@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==
array-includes@^3.1.4, array-includes@^3.1.5, array-includes@^3.1.6:
version "3.1.6"
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f"
@@ -2217,7 +2197,7 @@ colorette@^2.0.14:
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
commander@^2.19.0, commander@^2.20.0, commander@^2.20.3:
commander@^2.20.0, commander@^2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==