mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2026-04-16 21:35:04 -04:00
Compare commits
1 Commits
v1.1.0.232
...
ratelimit-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e15054329 |
@@ -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',
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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"",")]
|
||||
|
||||
@@ -76,7 +76,6 @@ namespace NzbDrone.Common.Http
|
||||
get
|
||||
{
|
||||
var newUrl = Headers["Location"];
|
||||
|
||||
if (newUrl == null)
|
||||
{
|
||||
newUrl = Headers["Refresh"];
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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" });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>()
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
@@ -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))
|
||||
|
||||
@@ -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, () =>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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("&", "&")
|
||||
.Replace("'", "'")
|
||||
.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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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 dell’applicazione, 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"
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
"BackupFolderHelpText": "Относительные пути будут в каталоге AppData Radarr",
|
||||
"BeforeUpdate": "До обновления",
|
||||
"BindAddress": "Привязать адрес",
|
||||
"BindAddressHelpText": "Действительный IP-адрес, локальный адрес или '*' для всех интерфейсов",
|
||||
"BindAddressHelpText": "Действительный IP4-адрес или '*' для всех интерфейсов",
|
||||
"Branch": "Ветка",
|
||||
"BranchUpdate": "Ветвь для обновления Radarr",
|
||||
"BranchUpdateMechanism": "Ветвь, используемая внешним механизмом обновления",
|
||||
|
||||
@@ -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 день. Заплановані завдання можуть не працювати належним чином, доки час не буде виправлено"
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
22
yarn.lock
22
yarn.lock
@@ -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==
|
||||
|
||||
Reference in New Issue
Block a user