mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2026-03-30 18:44:19 -04:00
Compare commits
49 Commits
v0.1.0.447
...
cookie-per
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e43c650d45 | ||
|
|
c6b6daaf80 | ||
|
|
3b42b6a7e0 | ||
|
|
b6238f469c | ||
|
|
ae00c3aa6b | ||
|
|
8bf9d1b016 | ||
|
|
19ed7aa804 | ||
|
|
4d129ada95 | ||
|
|
4ec8ea0e4d | ||
|
|
bd79d3c828 | ||
|
|
7fb6c539d4 | ||
|
|
7f6fa2efbe | ||
|
|
b1727d9d91 | ||
|
|
3435d9db6e | ||
|
|
8e597c8179 | ||
|
|
80ec66514e | ||
|
|
88e677d973 | ||
|
|
a00f32c508 | ||
|
|
538db52d16 | ||
|
|
1ce7b0e56e | ||
|
|
87d91a0f15 | ||
|
|
61c1e934a5 | ||
|
|
97b09335df | ||
|
|
5e34fd2a9f | ||
|
|
7e620bd156 | ||
|
|
a97b801b24 | ||
|
|
9e64acd407 | ||
|
|
f72269f91b | ||
|
|
94d7f768a1 | ||
|
|
78cdc78cf9 | ||
|
|
2fc1257f42 | ||
|
|
210311cb38 | ||
|
|
9d7ec89314 | ||
|
|
9c279701a6 | ||
|
|
743e2e9b21 | ||
|
|
4a8daea940 | ||
|
|
bd90b74c12 | ||
|
|
4dff0c075a | ||
|
|
b8f57507dd | ||
|
|
61bfa9e7ed | ||
|
|
bbea256c85 | ||
|
|
5a1186639e | ||
|
|
a8f2700fe6 | ||
|
|
eeec505182 | ||
|
|
66dc53b92f | ||
|
|
334f3514df | ||
|
|
6ce35f6a24 | ||
|
|
f6a5f887ce | ||
|
|
bc90415394 |
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -7,6 +7,7 @@ assignees: ''
|
||||
|
||||
---
|
||||
<!-- Support Requests will be closed immediately, if you are unsure go to our Reddit or Discord first. Exceptions do not mean you found a bug! -->
|
||||
<!-- Note: Text between <!- and -> will be hidden -->
|
||||
**Describe the bug**
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
@@ -33,4 +34,4 @@ assignees: ''
|
||||
|
||||
Turn on Trace logs under Settings -> General and wait for the bug to occur again.
|
||||
**Upload the full log file here (or another site (e.g. pastebin) and link it). Issues will be closed, if they do not include this!**
|
||||
<!-- Trace logs are named Prowlarr.trace.txt or Prowlarr.trace.#.txt and will contain "trace" in them-->
|
||||
<!-- Trace logs are named Prowlarr.trace.txt or Prowlarr.trace.#.txt and will contain "trace" in them-->
|
||||
|
||||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Indexer Requests
|
||||
url: https://requests.prowlarr.com/
|
||||
about: Request new indexers to be added. Vote on existing requests.
|
||||
- name: Support via Discord
|
||||
url: https://prowlarr.com/discord
|
||||
about: Chat with users and devs on support and setup related topics.
|
||||
|
||||
22
.github/ISSUE_TEMPLATE/indexer_request.md
vendored
22
.github/ISSUE_TEMPLATE/indexer_request.md
vendored
@@ -1,22 +0,0 @@
|
||||
---
|
||||
name: Indexer Request
|
||||
about: Request an indexer for Prowlarr. Check the pinned Jackett parity issue prior to submitting a request. Duplicated requests will be closed without warning. Please search GitHub prior to requesting.
|
||||
title: '(Indexer) '
|
||||
labels: 'Type: Indexer Request'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Check the pinned Jackett parity issue prior to submitting a request. Duplicated requests or requests covered in existing GitHub Issues will be closed without warning. Please search GitHub prior to requesting.-->
|
||||
|
||||
**Type:** <Usenet|Torrents>
|
||||
|
||||
**Tracker:** <Indexer/Tracker Name>
|
||||
|
||||
**URL:** <Indexer/Tracker URL>
|
||||
|
||||
**In Jackett?:** <Yes|No>
|
||||
<!-- Check the pinned Jackett parity issue prior to submitting a request. Duplicated requests or requests covered in existing GitHub Issues will be closed without warning. Please search GitHub prior to requesting.-->
|
||||
|
||||
**Additional Context:**
|
||||
<!-- Add any other context or screenshots about the request here. -->
|
||||
@@ -3,7 +3,7 @@
|
||||
We're always looking for people to help make Prowlarr even better, there are a number of ways to contribute.
|
||||
|
||||
## Documentation ##
|
||||
Setup guides, FAQ, the more information we have on the [wiki](https://wikijs.servarr.com/prowlarr) the better.
|
||||
Setup guides, FAQ, the more information we have on the [wiki](https://wiki.servarr.com/prowlarr) the better.
|
||||
|
||||
## Development ##
|
||||
|
||||
@@ -23,7 +23,7 @@ Setup guides, FAQ, the more information we have on the [wiki](https://wikijs.ser
|
||||
4. Start gulp to monitor your dev environment for any changes that need post processing using `yarn start` command.
|
||||
5. Build the project in Visual Studio, Setting startup project to `Prowlarr.Console` and framework to `net5.0`
|
||||
6. Debug the project in Visual Studio
|
||||
7. Open http://localhost:7878
|
||||
7. Open http://localhost:9696
|
||||
|
||||
### Contributing Code ###
|
||||
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Prowlarr/Prowlarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
|
||||
|
||||
17
README.md
17
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
[](https://dev.azure.com/Prowlarr/Prowlarr/_build/latest?definitionId=1&branchName=develop)
|
||||
[](https://translate.servarr.com/engage/prowlarr/?utm_source=widget)
|
||||
[](https://wikijs.servarr.com/prowlarr/installation#docker)
|
||||
[](https://wiki.servarr.com/prowlarr/installation#docker)
|
||||

|
||||
[](#backers)
|
||||
[](#sponsors)
|
||||
@@ -10,12 +10,14 @@
|
||||
Prowlarr is a indexer manager/proxy built on the popular arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Sonarr, Radarr, Lidarr, and Readarr offering complete management of your indexers with no per app Indexer setup required (we do it all).
|
||||
|
||||
## Major Features Include:
|
||||
- Usenet support for any Newznab compatible indexer, including Headphones VIP
|
||||
- Torrent support 400+ trackers & more coming soon
|
||||
- Usenet support for 24 indexers natively, including Headphones VIP, and support for any Newznab compatible indexer via "Generic Newznab"
|
||||
- Torrent support for almost 500 trackers & more coming soon
|
||||
- Torrent support for any Torznab compatible tracker via "Generic Torznab"
|
||||
- Indexer Sync to Sonarr/Radarr/Readarr/Lidarr, so no manual configuration of the other applications are required
|
||||
- Indexer History and Statistics
|
||||
- Manual Searching of Trackers & Indexers at a category level
|
||||
- Support for pushing releases directly to your download clients from Prowlarr
|
||||
- Indexer health and status notifications
|
||||
|
||||
## Support
|
||||
Note: Prowlarr is currently early in life, thus bugs should be expected
|
||||
@@ -23,7 +25,14 @@ Note: Prowlarr is currently early in life, thus bugs should be expected
|
||||
[](https://prowlarr.com/discord)
|
||||
[](https://www.reddit.com/r/Prowlarr)
|
||||
[](https://github.com/Prowlarr/Prowlarr/issues)
|
||||
[](https://wikijs.servarr.com/prowlarr)
|
||||
[](https://wiki.servarr.com/prowlarr)
|
||||
|
||||
## Indexers/Trackers
|
||||
|
||||
[Supported Indexers](https://wiki.servarr.com/en/prowlarr/supported-indexers)
|
||||
|
||||
[Indexer Requests](https://requests.prowlarr.com)
|
||||
- Request or vote on an existing request for a new tracker/indexer
|
||||
|
||||
## Feature Requests
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ class FileBrowserModalContent extends Component {
|
||||
className={styles.mappedDrivesWarning}
|
||||
kind={kinds.WARNING}
|
||||
>
|
||||
<Link to="https://wikijs.servarr.com/prowlarr/faq#why-cant-prowlarr-see-my-files-on-a-remote-server">
|
||||
<Link to="https://wiki.servarr.com/prowlarr/faq#why-cant-prowlarr-see-my-files-on-a-remote-server">
|
||||
{translate('MappedDrivesRunningAsService')}
|
||||
</Link>
|
||||
</Alert>
|
||||
|
||||
@@ -19,6 +19,10 @@ function getAverageResponseTimeData(indexerStats) {
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ function UpdateSettings(props) {
|
||||
type={inputTypes.TEXT}
|
||||
name="branch"
|
||||
helpText={usingExternalUpdateMechanism ? translate('BranchUpdateMechanism') : translate('BranchUpdate')}
|
||||
helpLink="https://wikijs.servarr.com/prowlarr/settings#updates"
|
||||
helpLink="https://wiki.servarr.com/prowlarr/settings#updates"
|
||||
{...branch}
|
||||
onChange={onInputChange}
|
||||
readOnly={usingExternalUpdateMechanism}
|
||||
@@ -92,7 +92,7 @@ function UpdateSettings(props) {
|
||||
name="updateMechanism"
|
||||
values={updateOptions}
|
||||
helpText={translate('UpdateMechanismHelpText')}
|
||||
helpLink="https://wikijs.servarr.com/prowlarr/settings#updates"
|
||||
helpLink="https://wiki.servarr.com/prowlarr/settings#updates"
|
||||
onChange={onInputChange}
|
||||
{...updateMechanism}
|
||||
/>
|
||||
|
||||
@@ -26,7 +26,7 @@ function NotificationEventItems(props) {
|
||||
<div>
|
||||
<FormInputHelpText
|
||||
text={translate('NotificationTriggersHelpText')}
|
||||
link="https://wikijs.servarr.com/prowlarr/settings#connections"
|
||||
link="https://wiki.servarr.com/prowlarr/settings#connections"
|
||||
/>
|
||||
<div className={styles.events}>
|
||||
<div>
|
||||
|
||||
@@ -13,7 +13,7 @@ function createHealthCheckSelector() {
|
||||
source: 'UI',
|
||||
type: 'warning',
|
||||
message: translate('CouldNotConnectSignalR'),
|
||||
wikiUrl: 'https://wikijs.servarr.com/prowlarr/system#could-not-connect-to-signalr'
|
||||
wikiUrl: 'https://wiki.servarr.com/prowlarr/system#could-not-connect-to-signalr'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ class MoreInfo extends Component {
|
||||
|
||||
<DescriptionListItemTitle>{translate('Wiki')}</DescriptionListItemTitle>
|
||||
<DescriptionListItemDescription>
|
||||
<Link to="https://wikijs.servarr.com/prowlarr">wikijs.servarr.com/prowlarr</Link>
|
||||
<Link to="https://wiki.servarr.com/prowlarr">wiki.servarr.com/prowlarr</Link>
|
||||
</DescriptionListItemDescription>
|
||||
|
||||
<DescriptionListItemTitle>{translate('Reddit')}</DescriptionListItemTitle>
|
||||
|
||||
@@ -252,7 +252,7 @@
|
||||
</span>
|
||||
|
||||
<a
|
||||
href="https://wikijs.servarr.com/prowlarr/faq#help-i-have-locked-myself-out"
|
||||
href="https://wiki.servarr.com/prowlarr/faq#help-i-have-locked-myself-out"
|
||||
class="forgot-password"
|
||||
>Forgot your password?</a
|
||||
>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace NzbDrone.Common.Instrumentation
|
||||
{
|
||||
// Url
|
||||
new Regex(@"(?<=\?|&|: |;)(apikey|token|passkey|auth|authkey|user|uid|api|[a-z_]*apikey|account|passwd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"(?<=\?|&| )[^=]*?(_?token|username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"(?<=\?|&| )[^=]*?(_?token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace NzbDrone.Core.Test.HealthCheck
|
||||
[TestFixture]
|
||||
public class HealthCheckFixture : CoreTest
|
||||
{
|
||||
private const string WikiRoot = "https://wikijs.servarr.com/";
|
||||
private const string WikiRoot = "https://wiki.servarr.com/";
|
||||
|
||||
[TestCase("I blew up because of some weird user mistake", null, WikiRoot + "prowlarr/system#i-blew-up-because-of-some-weird-user-mistake")]
|
||||
[TestCase("I blew up because of some weird user mistake", "#my-health-check", WikiRoot + "prowlarr/system#my-health-check")]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using FluentValidation.Results;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
@@ -31,7 +32,25 @@ namespace NzbDrone.Core.Applications.Lidarr
|
||||
{
|
||||
var failures = new List<ValidationFailure>();
|
||||
|
||||
failures.AddIfNotNull(_lidarrV1Proxy.Test(Settings));
|
||||
var testIndexer = new IndexerDefinition
|
||||
{
|
||||
Id = 0,
|
||||
Name = "Test",
|
||||
Protocol = DownloadProtocol.Usenet,
|
||||
Capabilities = new IndexerCapabilities()
|
||||
};
|
||||
|
||||
testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.Audio);
|
||||
|
||||
try
|
||||
{
|
||||
failures.AddIfNotNull(_lidarrV1Proxy.TestConnection(BuildLidarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to send test message");
|
||||
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Lidarr"));
|
||||
}
|
||||
|
||||
return new ValidationResult(failures);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Applications.Lidarr
|
||||
|
||||
public IEnumerable<int> SyncCategories { get; set; }
|
||||
|
||||
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Lidarr sees it, including http(s):// and port if needed")]
|
||||
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Lidarr sees it, including http(s)://, port, and urlbase if needed")]
|
||||
public string ProwlarrUrl { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Lidarr Server", HelpText = "Lidarr server URL, including http(s):// and port if needed")]
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Applications.Lidarr
|
||||
List<LidarrIndexer> GetIndexerSchema(LidarrSettings settings);
|
||||
void RemoveIndexer(int indexerId, LidarrSettings settings);
|
||||
LidarrIndexer UpdateIndexer(LidarrIndexer indexer, LidarrSettings settings);
|
||||
ValidationFailure Test(LidarrSettings settings);
|
||||
ValidationFailure TestConnection(LidarrIndexer indexer, LidarrSettings settings);
|
||||
}
|
||||
|
||||
public class LidarrV1Proxy : ILidarrV1Proxy
|
||||
@@ -91,11 +91,15 @@ namespace NzbDrone.Core.Applications.Lidarr
|
||||
return Execute<LidarrIndexer>(request);
|
||||
}
|
||||
|
||||
public ValidationFailure Test(LidarrSettings settings)
|
||||
public ValidationFailure TestConnection(LidarrIndexer indexer, LidarrSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings, $"/api/v1/indexer/test", HttpMethod.POST);
|
||||
|
||||
request.SetContent(indexer.ToJson());
|
||||
|
||||
try
|
||||
{
|
||||
GetStatus(settings);
|
||||
Execute<LidarrIndexer>(request);
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
@@ -105,8 +109,14 @@ namespace NzbDrone.Core.Applications.Lidarr
|
||||
return new ValidationFailure("ApiKey", "API Key is invalid");
|
||||
}
|
||||
|
||||
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
_logger.Error(ex, "Prowlarr URL is invalid");
|
||||
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Lidarr cannot connect to Prowlarr");
|
||||
}
|
||||
|
||||
_logger.Error(ex, "Unable to send test message");
|
||||
return new ValidationFailure("ApiKey", "Unable to send test message");
|
||||
return new ValidationFailure("BaseUrl", "Unable to complete application test");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using FluentValidation.Results;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
@@ -31,7 +32,25 @@ namespace NzbDrone.Core.Applications.Radarr
|
||||
{
|
||||
var failures = new List<ValidationFailure>();
|
||||
|
||||
failures.AddIfNotNull(_radarrV3Proxy.Test(Settings));
|
||||
var testIndexer = new IndexerDefinition
|
||||
{
|
||||
Id = 0,
|
||||
Name = "Test",
|
||||
Protocol = DownloadProtocol.Usenet,
|
||||
Capabilities = new IndexerCapabilities()
|
||||
};
|
||||
|
||||
testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies);
|
||||
|
||||
try
|
||||
{
|
||||
failures.AddIfNotNull(_radarrV3Proxy.TestConnection(BuildRadarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to send test message");
|
||||
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Radarr"));
|
||||
}
|
||||
|
||||
return new ValidationResult(failures);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Applications.Radarr
|
||||
|
||||
public IEnumerable<int> SyncCategories { get; set; }
|
||||
|
||||
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Radarr sees it, including http(s):// and port if needed")]
|
||||
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Radarr sees it, including http(s)://, port, and urlbase if needed")]
|
||||
public string ProwlarrUrl { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Radarr Server", HelpText = "Radarr server URL, including http(s):// and port if needed")]
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Applications.Radarr
|
||||
List<RadarrIndexer> GetIndexerSchema(RadarrSettings settings);
|
||||
void RemoveIndexer(int indexerId, RadarrSettings settings);
|
||||
RadarrIndexer UpdateIndexer(RadarrIndexer indexer, RadarrSettings settings);
|
||||
ValidationFailure Test(RadarrSettings settings);
|
||||
ValidationFailure TestConnection(RadarrIndexer indexer, RadarrSettings settings);
|
||||
}
|
||||
|
||||
public class RadarrV3Proxy : IRadarrV3Proxy
|
||||
@@ -91,11 +91,15 @@ namespace NzbDrone.Core.Applications.Radarr
|
||||
return Execute<RadarrIndexer>(request);
|
||||
}
|
||||
|
||||
public ValidationFailure Test(RadarrSettings settings)
|
||||
public ValidationFailure TestConnection(RadarrIndexer indexer, RadarrSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings, $"/api/v3/indexer/test", HttpMethod.POST);
|
||||
|
||||
request.SetContent(indexer.ToJson());
|
||||
|
||||
try
|
||||
{
|
||||
GetStatus(settings);
|
||||
Execute<RadarrIndexer>(request);
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
@@ -105,8 +109,14 @@ namespace NzbDrone.Core.Applications.Radarr
|
||||
return new ValidationFailure("ApiKey", "API Key is invalid");
|
||||
}
|
||||
|
||||
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
_logger.Error(ex, "Prowlarr URL is invalid");
|
||||
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Radarr cannot connect to Prowlarr");
|
||||
}
|
||||
|
||||
_logger.Error(ex, "Unable to send test message");
|
||||
return new ValidationFailure("ApiKey", "Unable to send test message");
|
||||
return new ValidationFailure("BaseUrl", "Unable to complete application test");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using FluentValidation.Results;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
@@ -31,7 +32,25 @@ namespace NzbDrone.Core.Applications.Readarr
|
||||
{
|
||||
var failures = new List<ValidationFailure>();
|
||||
|
||||
failures.AddIfNotNull(_readarrV1Proxy.Test(Settings));
|
||||
var testIndexer = new IndexerDefinition
|
||||
{
|
||||
Id = 0,
|
||||
Name = "Test",
|
||||
Protocol = DownloadProtocol.Usenet,
|
||||
Capabilities = new IndexerCapabilities()
|
||||
};
|
||||
|
||||
testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.Books);
|
||||
|
||||
try
|
||||
{
|
||||
failures.AddIfNotNull(_readarrV1Proxy.TestConnection(BuildReadarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to send test message");
|
||||
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Readarr"));
|
||||
}
|
||||
|
||||
return new ValidationResult(failures);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Applications.Readarr
|
||||
|
||||
public IEnumerable<int> SyncCategories { get; set; }
|
||||
|
||||
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Readarr sees it, including http(s):// and port if needed")]
|
||||
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Readarr sees it, including http(s)://, port, and urlbase if needed")]
|
||||
public string ProwlarrUrl { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Readarr Server", HelpText = "Readarr server URL, including http(s):// and port if needed")]
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Applications.Readarr
|
||||
List<ReadarrIndexer> GetIndexerSchema(ReadarrSettings settings);
|
||||
void RemoveIndexer(int indexerId, ReadarrSettings settings);
|
||||
ReadarrIndexer UpdateIndexer(ReadarrIndexer indexer, ReadarrSettings settings);
|
||||
ValidationFailure Test(ReadarrSettings settings);
|
||||
ValidationFailure TestConnection(ReadarrIndexer indexer, ReadarrSettings settings);
|
||||
}
|
||||
|
||||
public class ReadarrV1Proxy : IReadarrV1Proxy
|
||||
@@ -91,11 +91,15 @@ namespace NzbDrone.Core.Applications.Readarr
|
||||
return Execute<ReadarrIndexer>(request);
|
||||
}
|
||||
|
||||
public ValidationFailure Test(ReadarrSettings settings)
|
||||
public ValidationFailure TestConnection(ReadarrIndexer indexer, ReadarrSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings, $"/api/v1/indexer/test", HttpMethod.POST);
|
||||
|
||||
request.SetContent(indexer.ToJson());
|
||||
|
||||
try
|
||||
{
|
||||
GetStatus(settings);
|
||||
Execute<ReadarrIndexer>(request);
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
@@ -105,8 +109,14 @@ namespace NzbDrone.Core.Applications.Readarr
|
||||
return new ValidationFailure("ApiKey", "API Key is invalid");
|
||||
}
|
||||
|
||||
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
_logger.Error(ex, "Prowlarr URL is invalid");
|
||||
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Readarr cannot connect to Prowlarr");
|
||||
}
|
||||
|
||||
_logger.Error(ex, "Unable to send test message");
|
||||
return new ValidationFailure("ApiKey", "Unable to send test message");
|
||||
return new ValidationFailure("BaseUrl", "Unable to complete application test");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using FluentValidation.Results;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
@@ -31,7 +32,25 @@ namespace NzbDrone.Core.Applications.Sonarr
|
||||
{
|
||||
var failures = new List<ValidationFailure>();
|
||||
|
||||
failures.AddIfNotNull(_sonarrV3Proxy.Test(Settings));
|
||||
var testIndexer = new IndexerDefinition
|
||||
{
|
||||
Id = 0,
|
||||
Name = "Test",
|
||||
Protocol = DownloadProtocol.Usenet,
|
||||
Capabilities = new IndexerCapabilities()
|
||||
};
|
||||
|
||||
testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.TV);
|
||||
|
||||
try
|
||||
{
|
||||
failures.AddIfNotNull(_sonarrV3Proxy.TestConnection(BuildSonarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to send test message");
|
||||
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Sonarr"));
|
||||
}
|
||||
|
||||
return new ValidationResult(failures);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Applications.Sonarr
|
||||
|
||||
public IEnumerable<int> SyncCategories { get; set; }
|
||||
|
||||
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s):// and port if needed")]
|
||||
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s)://, port, and urlbase if needed")]
|
||||
public string ProwlarrUrl { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Sonarr Server", HelpText = "Sonarr server URL, including http(s):// and port if needed")]
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Applications.Sonarr
|
||||
List<SonarrIndexer> GetIndexerSchema(SonarrSettings settings);
|
||||
void RemoveIndexer(int indexerId, SonarrSettings settings);
|
||||
SonarrIndexer UpdateIndexer(SonarrIndexer indexer, SonarrSettings settings);
|
||||
ValidationFailure Test(SonarrSettings settings);
|
||||
ValidationFailure TestConnection(SonarrIndexer indexer, SonarrSettings settings);
|
||||
}
|
||||
|
||||
public class SonarrV3Proxy : ISonarrV3Proxy
|
||||
@@ -91,11 +91,15 @@ namespace NzbDrone.Core.Applications.Sonarr
|
||||
return Execute<SonarrIndexer>(request);
|
||||
}
|
||||
|
||||
public ValidationFailure Test(SonarrSettings settings)
|
||||
public ValidationFailure TestConnection(SonarrIndexer indexer, SonarrSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings, $"/api/v3/indexer/test", HttpMethod.POST);
|
||||
|
||||
request.SetContent(indexer.ToJson());
|
||||
|
||||
try
|
||||
{
|
||||
GetStatus(settings);
|
||||
Execute<SonarrIndexer>(request);
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
@@ -105,8 +109,14 @@ namespace NzbDrone.Core.Applications.Sonarr
|
||||
return new ValidationFailure("ApiKey", "API Key is invalid");
|
||||
}
|
||||
|
||||
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
_logger.Error(ex, "Prowlarr URL is invalid");
|
||||
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Sonarr cannot connect to Prowlarr");
|
||||
}
|
||||
|
||||
_logger.Error(ex, "Unable to send test message");
|
||||
return new ValidationFailure("ApiKey", "Unable to send test message");
|
||||
return new ValidationFailure("BaseUrl", "Unable to complete application test");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
36
src/NzbDrone.Core/Datastore/Converters/CookieConverter.cs
Normal file
36
src/NzbDrone.Core/Datastore/Converters/CookieConverter.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using Dapper;
|
||||
using NzbDrone.Common.Serializer;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Converters
|
||||
{
|
||||
public class CookieConverter : SqlMapper.TypeHandler<IDictionary<string, string>>
|
||||
{
|
||||
protected readonly JsonSerializerOptions SerializerSettings;
|
||||
|
||||
public CookieConverter()
|
||||
{
|
||||
var serializerSettings = new JsonSerializerOptions
|
||||
{
|
||||
AllowTrailingCommas = true,
|
||||
IgnoreNullValues = true,
|
||||
PropertyNameCaseInsensitive = true,
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
SerializerSettings = serializerSettings;
|
||||
}
|
||||
|
||||
public override void SetValue(IDbDataParameter parameter, IDictionary<string, string> value)
|
||||
{
|
||||
parameter.Value = JsonSerializer.Serialize(value, SerializerSettings);
|
||||
}
|
||||
|
||||
public override IDictionary<string, string> Parse(object value)
|
||||
{
|
||||
return JsonSerializer.Deserialize<Dictionary<string, string>>((string)value, SerializerSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,10 +108,10 @@ namespace NzbDrone.Core.Datastore
|
||||
|
||||
if (OsInfo.IsOsx)
|
||||
{
|
||||
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wikijs.servarr.com/prowlarr/faq#i-use-prowlarr-on-a-mac-and-it-suddenly-stopped-working-what-happened", e, fileName);
|
||||
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/prowlarr/faq#i-use-prowlarr-on-a-mac-and-it-suddenly-stopped-working-what-happened", e, fileName);
|
||||
}
|
||||
|
||||
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wikijs.servarr.com/prowlarr/faq#i-am-getting-an-error-database-disk-image-is-malformed", e, fileName);
|
||||
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/prowlarr/faq#i-am-getting-an-error-database-disk-image-is-malformed", e, fileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace NzbDrone.Core.Datastore
|
||||
SqlMapper.RemoveTypeMap(typeof(DateTime));
|
||||
SqlMapper.AddTypeHandler(new DapperUtcConverter());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<Dictionary<string, string>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<IDictionary<string, string>>());
|
||||
SqlMapper.AddTypeHandler(new CookieConverter());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<int>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<KeyValuePair<string, int>>>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<KeyValuePair<string, int>>());
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace NzbDrone.Core.HealthCheck
|
||||
|
||||
private static HttpUri MakeWikiUrl(string fragment)
|
||||
{
|
||||
return new HttpUri("https://wikijs.servarr.com/prowlarr/system#") + new HttpUri(fragment);
|
||||
return new HttpUri("https://wiki.servarr.com/prowlarr/system#") + new HttpUri(fragment);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Indexers.Cardigann;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
@@ -24,7 +25,7 @@ namespace NzbDrone.Core.IndexerVersions
|
||||
public class IndexerDefinitionUpdateService : IIndexerDefinitionUpdateService, IExecute<IndexerDefinitionUpdateCommand>
|
||||
{
|
||||
private const int DEFINITION_VERSION = 1;
|
||||
private readonly List<string> _defintionBlacklist = new List<string>() { "aither", "animeworld", "blutopia", "beyond-hd", "beyond-hd-oneurl", "hdbits" };
|
||||
private readonly List<string> _defintionBlacklist = new List<string>() { "aither", "animeworld", "blutopia", "beyond-hd", "beyond-hd-oneurl", "hdbits", "shareisland" };
|
||||
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
@@ -59,6 +60,40 @@ namespace NzbDrone.Core.IndexerVersions
|
||||
var request = new HttpRequest($"https://indexers.prowlarr.com/master/{DEFINITION_VERSION}");
|
||||
var response = _httpClient.Get<List<CardigannMetaDefinition>>(request);
|
||||
indexerList = response.Resource.Where(i => !_defintionBlacklist.Contains(i.File)).ToList();
|
||||
|
||||
var definitionFolder = Path.Combine(_appFolderInfo.AppDataFolder, "Definitions", "Custom");
|
||||
|
||||
var directoryInfo = new DirectoryInfo(definitionFolder);
|
||||
|
||||
if (directoryInfo.Exists)
|
||||
{
|
||||
var files = directoryInfo.GetFiles($"*.yml");
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
_logger.Debug("Loading Custom Cardigann definition " + file.FullName);
|
||||
|
||||
try
|
||||
{
|
||||
var definitionString = File.ReadAllText(file.FullName);
|
||||
var definition = _deserializer.Deserialize<CardigannMetaDefinition>(definitionString);
|
||||
|
||||
definition.File = Path.GetFileNameWithoutExtension(file.Name);
|
||||
|
||||
if (indexerList.Any(i => i.File == definition.File || i.Name == definition.Name))
|
||||
{
|
||||
_logger.Warn("Custom Cardigann definition {0} does not have unique file name or Indexer name", file.FullName);
|
||||
continue;
|
||||
}
|
||||
|
||||
indexerList.Add(definition);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error($"Error while parsing custom Cardigann definition {file.FullName}\n{e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -108,7 +143,7 @@ namespace NzbDrone.Core.IndexerVersions
|
||||
|
||||
if (directoryInfo.Exists)
|
||||
{
|
||||
var files = directoryInfo.GetFiles($"{fileKey}.yml");
|
||||
var files = directoryInfo.GetFiles($"{fileKey}.yml", SearchOption.AllDirectories);
|
||||
|
||||
if (files.Any())
|
||||
{
|
||||
|
||||
@@ -494,10 +494,10 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
Username = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Passkey", HelpText = "Site Passkey")]
|
||||
[FieldDefinition(1, Label = "Passkey", Privacy = PrivacyLevel.Password, Type = FieldType.Password, HelpText = "Site Passkey")]
|
||||
public string Passkey { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site username")]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
@@ -350,10 +350,10 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site username")]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Site password", Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
332
src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs
Normal file
332
src/NzbDrone.Core/Indexers/Definitions/Anthelion.cs
Normal file
@@ -0,0 +1,332 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
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.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 Anthelion : TorrentIndexerBase<AnthelionSettings>
|
||||
{
|
||||
public override string Name => "Anthelion";
|
||||
public override string BaseUrl => "https://anthelion.me/";
|
||||
private string LoginUrl => BaseUrl + "login.php";
|
||||
public override string Description => "A movies tracker";
|
||||
public override string Language => "en-us";
|
||||
public override Encoding Encoding => Encoding.UTF8;
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public Anthelion(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new AnthelionRequestGenerator() { Settings = Settings, Capabilities = Capabilities, BaseUrl = BaseUrl };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new AnthelionParser(Settings, Capabilities.Categories, BaseUrl);
|
||||
}
|
||||
|
||||
protected override async Task DoLogin()
|
||||
{
|
||||
var requestBuilder = new HttpRequestBuilder(LoginUrl)
|
||||
{
|
||||
LogResponseContent = true,
|
||||
AllowAutoRedirect = true
|
||||
};
|
||||
|
||||
requestBuilder.Method = HttpMethod.POST;
|
||||
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
|
||||
|
||||
var cookies = Cookies;
|
||||
|
||||
Cookies = null;
|
||||
var authLoginRequest = requestBuilder
|
||||
.AddFormParameter("username", Settings.Username)
|
||||
.AddFormParameter("password", Settings.Password)
|
||||
.AddFormParameter("keeplogged", "1")
|
||||
.AddFormParameter("login", "Log+In!")
|
||||
.SetHeader("Content-Type", "multipart/form-data")
|
||||
.Build();
|
||||
|
||||
var headers = new NameValueCollection
|
||||
{
|
||||
{ "Referer", LoginUrl }
|
||||
};
|
||||
|
||||
authLoginRequest.Headers.Add(headers);
|
||||
|
||||
var response = await ExecuteAuth(authLoginRequest);
|
||||
|
||||
if (!response.Content.Contains("logout.php"))
|
||||
{
|
||||
throw new IndexerAuthException("Anthelion Auth Failed");
|
||||
}
|
||||
|
||||
cookies = response.GetCookies();
|
||||
UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30));
|
||||
|
||||
_logger.Debug("Anthelion authentication succeeded.");
|
||||
}
|
||||
|
||||
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
|
||||
{
|
||||
if (!httpResponse.Content.Contains("logout.php"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping("1", NewznabStandardCategory.Movies, "Film/Feature");
|
||||
caps.Categories.AddCategoryMapping("2", NewznabStandardCategory.Movies, "Film/Short");
|
||||
caps.Categories.AddCategoryMapping("3", NewznabStandardCategory.TV, "TV/Miniseries");
|
||||
caps.Categories.AddCategoryMapping("4", NewznabStandardCategory.Other, "Other");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class AnthelionRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public AnthelionSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
public AnthelionRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null)
|
||||
{
|
||||
var searchUrl = string.Format("{0}/torrents.php", BaseUrl.TrimEnd('/'));
|
||||
|
||||
// TODO: IMDB search is available but it requires to parse the details page
|
||||
var qc = new NameValueCollection
|
||||
{
|
||||
{ "order_by", "time" },
|
||||
{ "order_way", "desc" },
|
||||
{ "action", "basic" },
|
||||
{ "searchsubmit", "1" },
|
||||
{ "searchstr", imdbId.IsNotNullOrWhiteSpace() ? imdbId : term }
|
||||
};
|
||||
|
||||
var catList = Capabilities.Categories.MapTorznabCapsToTrackers(categories);
|
||||
|
||||
foreach (var cat in catList)
|
||||
{
|
||||
qc.Add($"filter_cat[{cat}]", "1");
|
||||
}
|
||||
|
||||
searchUrl = searchUrl + "?" + qc.GetQueryString();
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Html);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class AnthelionParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly AnthelionSettings _settings;
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
private readonly string _baseUrl;
|
||||
|
||||
public AnthelionParser(AnthelionSettings settings, IndexerCapabilitiesCategories categories, string baseurl)
|
||||
{
|
||||
_settings = settings;
|
||||
_categories = categories;
|
||||
_baseUrl = baseurl;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<ReleaseInfo>();
|
||||
|
||||
var parser = new HtmlParser();
|
||||
var doc = parser.ParseDocument(indexerResponse.Content);
|
||||
var rows = doc.QuerySelectorAll("table.torrent_table > tbody > tr.torrent");
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var qDetailsLink = row.QuerySelector("a.torrent_name");
|
||||
var year = qDetailsLink.NextSibling.TextContent.Replace("[", "").Replace("]", "").Trim();
|
||||
var tags = row.QuerySelector("div.torrent_info").FirstChild.TextContent.Replace(" / ", " ").Trim();
|
||||
var title = $"{qDetailsLink.TextContent} {year} {tags}";
|
||||
var description = row.QuerySelector("div.tags").TextContent.Trim();
|
||||
var details = _baseUrl + qDetailsLink.GetAttribute("href");
|
||||
var torrentId = qDetailsLink.GetAttribute("href").Split('=').Last();
|
||||
var link = _baseUrl + "torrents.php?action=download&id=" + torrentId;
|
||||
var posterStr = qDetailsLink.GetAttribute("data-cover");
|
||||
var poster = !string.IsNullOrWhiteSpace(posterStr) ? new Uri(qDetailsLink.GetAttribute("data-cover")) : null;
|
||||
|
||||
var files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(3)").TextContent);
|
||||
var publishDate = DateTimeUtil.FromTimeAgo(row.QuerySelector("td:nth-child(4)").TextContent);
|
||||
var size = ReleaseInfo.GetBytes(row.QuerySelector("td:nth-child(5)").FirstChild.TextContent);
|
||||
var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(6)").TextContent);
|
||||
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)").TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(8)").TextContent);
|
||||
|
||||
var dlVolumeFactor = row.QuerySelector("strong.tl_free") != null ? 0 : 1;
|
||||
|
||||
var cat = row.QuerySelector("td.cats_col > div").GetAttribute("class").Replace("tooltip cats_", "");
|
||||
var category = new List<IndexerCategory>
|
||||
{
|
||||
cat switch
|
||||
{
|
||||
"featurefilm" => NewznabStandardCategory.Movies,
|
||||
"shortfilm" => NewznabStandardCategory.Movies,
|
||||
"miniseries" => NewznabStandardCategory.TV,
|
||||
"other" => NewznabStandardCategory.Other,
|
||||
_ => throw new Exception($"Unknown category: {cat}")
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: TMDb is also available
|
||||
var qImdb = row.QuerySelector("a[href^=\"https://www.imdb.com\"]");
|
||||
var imdb = qImdb != null ? ParseUtil.GetImdbID(qImdb.GetAttribute("href").Split('/').Last()) : null;
|
||||
|
||||
var release = new TorrentInfo
|
||||
{
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 259200,
|
||||
Description = description,
|
||||
Title = title,
|
||||
PublishDate = publishDate,
|
||||
Categories = category,
|
||||
DownloadUrl = link,
|
||||
InfoUrl = details,
|
||||
Guid = link,
|
||||
ImdbId = imdb.GetValueOrDefault(),
|
||||
Seeders = seeders,
|
||||
Peers = leechers + seeders,
|
||||
Size = size,
|
||||
Grabs = grabs,
|
||||
Files = files,
|
||||
DownloadVolumeFactor = dlVolumeFactor,
|
||||
UploadVolumeFactor = 1
|
||||
};
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class AnthelionSettingsValidator : AbstractValidator<AnthelionSettings>
|
||||
{
|
||||
public AnthelionSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.Username).NotEmpty();
|
||||
RuleFor(c => c.Password).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public class AnthelionSettings : IProviderConfig
|
||||
{
|
||||
private static readonly AnthelionSettingsValidator Validator = new AnthelionSettingsValidator();
|
||||
|
||||
public AnthelionSettings()
|
||||
{
|
||||
Username = "";
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
|
||||
{
|
||||
RuleFor(c => c.Username).NotEmpty();
|
||||
RuleFor(c => c.Password).NotEmpty();
|
||||
RuleFor(c => c.Pid).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +26,10 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
|
||||
|
||||
public string Token { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Username", Privacy = PrivacyLevel.UserName)]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Password", Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "PID", HelpText = "PID from My Account or My Profile page")]
|
||||
|
||||
@@ -402,10 +402,10 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site username")]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Site password", Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Add Romaji Title", Type = FieldType.Checkbox, HelpText = "Add releases for Romaji Title")]
|
||||
|
||||
@@ -190,11 +190,11 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
|
||||
}
|
||||
|
||||
// TODO Have BHD fix their API response content type so we can proper check here
|
||||
// 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}");
|
||||
// }
|
||||
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
|
||||
{
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
|
||||
}
|
||||
|
||||
var jsonResponse = new HttpResponse<BeyondHDResponse>(indexerResponse.HttpResponse);
|
||||
|
||||
foreach (var row in jsonResponse.Resource.Results)
|
||||
@@ -217,10 +217,10 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
ImdbId = ParseUtil.GetImdbID(row.ImdbId).GetValueOrDefault(),
|
||||
TmdbId = row.TmdbId.IsNullOrWhiteSpace() ? 0 : ParseUtil.CoerceInt(row.TmdbId.Split("/")[1]),
|
||||
Peers = row.Leechers + row.Seeders,
|
||||
DownloadVolumeFactor = row.Freeleech ? 0 : row.Promo75 ? 0.25 : row.Promo50 ? 0.5 : row.Promo25 ? 0.75 : 1,
|
||||
DownloadVolumeFactor = row.Freeleech || row.Limited ? 0 : row.Promo75 ? 0.25 : row.Promo50 ? 0.5 : row.Promo25 ? 0.75 : 1,
|
||||
UploadVolumeFactor = 1,
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 172800, // 48 hours
|
||||
MinimumSeedTime = 172800, // 120 hours
|
||||
};
|
||||
|
||||
torrentInfos.Add(release);
|
||||
@@ -300,5 +300,6 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
public bool Promo25 { get; set; }
|
||||
public bool Promo50 { get; set; }
|
||||
public bool Promo75 { get; set; }
|
||||
public bool Limited { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,16 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
};
|
||||
}
|
||||
|
||||
protected override IDictionary<string, string> GetCookies()
|
||||
{
|
||||
if (Settings.ExtraFieldData.TryGetValue("cookie", out var cookies))
|
||||
{
|
||||
return CookieUtil.CookieHeaderToDictionary((string)cookies);
|
||||
}
|
||||
|
||||
return base.GetCookies();
|
||||
}
|
||||
|
||||
public override IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||
{
|
||||
get
|
||||
@@ -108,6 +118,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
Enable = true,
|
||||
Name = definition.Name,
|
||||
Language = definition.Language,
|
||||
Description = definition.Description,
|
||||
Implementation = GetType().Name,
|
||||
Settings = new CardigannSettings { DefinitionFile = definition.File },
|
||||
Protocol = DownloadProtocol.Torrent,
|
||||
@@ -122,6 +133,11 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
|
||||
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
|
||||
{
|
||||
if (httpResponse.HasHttpError)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var generator = (CardigannRequestGenerator)GetRequestGenerator();
|
||||
|
||||
SetCookieFunctions(generator);
|
||||
@@ -207,6 +223,11 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
}
|
||||
}
|
||||
|
||||
public override IDictionary<string, string> GrabCookies()
|
||||
{
|
||||
return ((CardigannRequestGenerator)GetRequestGenerator()).Cookies;
|
||||
}
|
||||
|
||||
public override object RequestAction(string action, IDictionary<string, string> query)
|
||||
{
|
||||
if (action == "checkCaptcha")
|
||||
|
||||
@@ -557,7 +557,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
case "querystring":
|
||||
var param = (string)filter.Args;
|
||||
|
||||
// data = ParseUtil.GetArgumentFromQueryString(data, param);
|
||||
data = ParseUtil.GetArgumentFromQueryString(data, param);
|
||||
break;
|
||||
case "timeparse":
|
||||
case "dateparse":
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Indexers.Cardigann
|
||||
.ContainsIgnoreCase("login.php"))
|
||||
{
|
||||
CookiesUpdater(null, null);
|
||||
throw new IndexerException(indexerResponse, "We are being redirected to the PTP login page. Most likely your session expired or was killed. Try testing the indexer in the settings.");
|
||||
throw new IndexerException(indexerResponse, "We are being redirected to the login page. Most likely your session expired or was killed. Try testing the indexer in the settings.");
|
||||
}
|
||||
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
|
||||
|
||||
@@ -40,11 +40,6 @@ namespace NzbDrone.Core.Indexers.FileList
|
||||
|
||||
var flags = new List<IndexerFlag>();
|
||||
|
||||
if (result.FreeLeech)
|
||||
{
|
||||
flags.Add(IndexerFlag.FreeLeech);
|
||||
}
|
||||
|
||||
var imdbId = 0;
|
||||
if (result.ImdbId != null && result.ImdbId.Length > 2)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace NzbDrone.Core.Indexers.FileList
|
||||
{
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Username", Privacy = PrivacyLevel.UserName)]
|
||||
[FieldDefinition(0, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Passkey", Privacy = PrivacyLevel.ApiKey)]
|
||||
|
||||
@@ -11,9 +11,9 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
{
|
||||
public class GazelleParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly GazelleSettings _settings;
|
||||
private readonly IndexerCapabilities _capabilities;
|
||||
private readonly string _baseUrl;
|
||||
protected readonly GazelleSettings _settings;
|
||||
protected readonly IndexerCapabilities _capabilities;
|
||||
protected readonly string _baseUrl;
|
||||
|
||||
public GazelleParser(GazelleSettings settings, IndexerCapabilities capabilities, string baseUrl)
|
||||
{
|
||||
@@ -138,11 +138,12 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private string GetDownloadUrl(int torrentId)
|
||||
protected virtual string GetDownloadUrl(int torrentId)
|
||||
{
|
||||
var url = new HttpUri(_baseUrl)
|
||||
.CombinePath("/torrents.php")
|
||||
.AddQueryParam("action", "download")
|
||||
.AddQueryParam("useToken", _settings.UseFreeleechToken ? "1" : "0")
|
||||
.AddQueryParam("id", torrentId);
|
||||
|
||||
return url.FullUri;
|
||||
|
||||
@@ -17,8 +17,6 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
public Logger Logger { get; set; }
|
||||
|
||||
protected virtual string APIUrl => BaseUrl + "ajax.php";
|
||||
protected virtual string DownloadUrl => BaseUrl + "torrents.php?action=download&usetoken=" + (Settings.UseFreeleechToken ? "1" : "0") + "&id=";
|
||||
protected virtual string DetailsUrl => BaseUrl + "torrents.php?torrentid=";
|
||||
protected virtual bool ImdbInTags => false;
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
|
||||
@@ -25,10 +25,10 @@ namespace NzbDrone.Core.Indexers.Gazelle
|
||||
public string AuthKey;
|
||||
public string PassKey;
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Username", Privacy = PrivacyLevel.UserName)]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Password", Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[FieldDefinition(3, Type = FieldType.Checkbox, Label = "Use Freeleech Token", HelpText = "Use Freeleech Token")]
|
||||
|
||||
426
src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs
Normal file
426
src/NzbDrone.Core/Indexers/Definitions/GazelleGames.cs
Normal file
@@ -0,0 +1,426 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using AngleSharp.Html.Parser;
|
||||
using FluentValidation;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Configuration;
|
||||
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 GazelleGames : TorrentIndexerBase<GazelleGamesSettings>
|
||||
{
|
||||
public override string Name => "GazelleGames";
|
||||
public override string BaseUrl => "https://gazellegames.net/";
|
||||
public override string Description => "A gaming tracker.";
|
||||
public override string Language => "en-us";
|
||||
public override Encoding Encoding => Encoding.UTF8;
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public GazelleGames(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new GazelleGamesRequestGenerator() { Settings = Settings, Capabilities = Capabilities, BaseUrl = BaseUrl };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new GazelleGamesParser(Settings, Capabilities.Categories, BaseUrl);
|
||||
}
|
||||
|
||||
protected override IDictionary<string, string> GetCookies()
|
||||
{
|
||||
return CookieUtil.CookieHeaderToDictionary(Settings.Cookie);
|
||||
}
|
||||
|
||||
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
|
||||
{
|
||||
if (httpResponse.HasHttpRedirect && httpResponse.RedirectUrl.EndsWith("login.php"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping("Mac", NewznabStandardCategory.ConsoleOther, "Mac");
|
||||
caps.Categories.AddCategoryMapping("iOS", NewznabStandardCategory.PCMobileiOS, "iOS");
|
||||
caps.Categories.AddCategoryMapping("Apple Bandai Pippin", NewznabStandardCategory.ConsoleOther, "Apple Bandai Pippin");
|
||||
|
||||
caps.Categories.AddCategoryMapping("Android", NewznabStandardCategory.PCMobileAndroid, "Android");
|
||||
|
||||
caps.Categories.AddCategoryMapping("DOS", NewznabStandardCategory.PCGames, "DOS");
|
||||
caps.Categories.AddCategoryMapping("Windows", NewznabStandardCategory.PCGames, "Windows");
|
||||
caps.Categories.AddCategoryMapping("Xbox", NewznabStandardCategory.ConsoleXBox, "Xbox");
|
||||
caps.Categories.AddCategoryMapping("Xbox 360", NewznabStandardCategory.ConsoleXBox360, "Xbox 360");
|
||||
|
||||
caps.Categories.AddCategoryMapping("Game Boy", NewznabStandardCategory.ConsoleOther, "Game Boy");
|
||||
caps.Categories.AddCategoryMapping("Game Boy Advance", NewznabStandardCategory.ConsoleOther, "Game Boy Advance");
|
||||
caps.Categories.AddCategoryMapping("Game Boy Color", NewznabStandardCategory.ConsoleOther, "Game Boy Color");
|
||||
caps.Categories.AddCategoryMapping("NES", NewznabStandardCategory.ConsoleOther, "NES");
|
||||
caps.Categories.AddCategoryMapping("Nintendo 64", NewznabStandardCategory.ConsoleOther, "Nintendo 64");
|
||||
caps.Categories.AddCategoryMapping("Nintendo 3DS", NewznabStandardCategory.ConsoleOther, "Nintendo 3DS");
|
||||
caps.Categories.AddCategoryMapping("New Nintendo 3DS", NewznabStandardCategory.ConsoleOther, "New Nintendo 3DS");
|
||||
caps.Categories.AddCategoryMapping("Nintendo DS", NewznabStandardCategory.ConsoleNDS, "Nintendo DS");
|
||||
caps.Categories.AddCategoryMapping("Nintendo GameCube", NewznabStandardCategory.ConsoleOther, "Nintendo GameCube");
|
||||
caps.Categories.AddCategoryMapping("Pokemon Mini", NewznabStandardCategory.ConsoleOther, "Pokemon Mini");
|
||||
caps.Categories.AddCategoryMapping("SNES", NewznabStandardCategory.ConsoleOther, "SNES");
|
||||
caps.Categories.AddCategoryMapping("Virtual Boy", NewznabStandardCategory.ConsoleOther, "Virtual Boy");
|
||||
caps.Categories.AddCategoryMapping("Wii", NewznabStandardCategory.ConsoleWii, "Wii");
|
||||
caps.Categories.AddCategoryMapping("Wii U", NewznabStandardCategory.ConsoleWiiU, "Wii U");
|
||||
|
||||
caps.Categories.AddCategoryMapping("PlayStation 1", NewznabStandardCategory.ConsoleOther, "PlayStation 1");
|
||||
caps.Categories.AddCategoryMapping("PlayStation 2", NewznabStandardCategory.ConsoleOther, "PlayStation 2");
|
||||
caps.Categories.AddCategoryMapping("PlayStation 3", NewznabStandardCategory.ConsolePS3, "PlayStation 3");
|
||||
caps.Categories.AddCategoryMapping("PlayStation 4", NewznabStandardCategory.ConsolePS4, "PlayStation 4");
|
||||
caps.Categories.AddCategoryMapping("PlayStation Portable", NewznabStandardCategory.ConsolePSP, "PlayStation Portable");
|
||||
caps.Categories.AddCategoryMapping("PlayStation Vita", NewznabStandardCategory.ConsolePSVita, "PlayStation Vita");
|
||||
|
||||
caps.Categories.AddCategoryMapping("Dreamcast", NewznabStandardCategory.ConsoleOther, "Dreamcast");
|
||||
caps.Categories.AddCategoryMapping("Game Gear", NewznabStandardCategory.ConsoleOther, "Game Gear");
|
||||
caps.Categories.AddCategoryMapping("Master System", NewznabStandardCategory.ConsoleOther, "Master System");
|
||||
caps.Categories.AddCategoryMapping("Mega Drive", NewznabStandardCategory.ConsoleOther, "Mega Drive");
|
||||
caps.Categories.AddCategoryMapping("Pico", NewznabStandardCategory.ConsoleOther, "Pico");
|
||||
caps.Categories.AddCategoryMapping("Saturn", NewznabStandardCategory.ConsoleOther, "Saturn");
|
||||
caps.Categories.AddCategoryMapping("SG-1000", NewznabStandardCategory.ConsoleOther, "SG-1000");
|
||||
|
||||
caps.Categories.AddCategoryMapping("Atari 2600", NewznabStandardCategory.ConsoleOther, "Atari 2600");
|
||||
caps.Categories.AddCategoryMapping("Atari 5200", NewznabStandardCategory.ConsoleOther, "Atari 5200");
|
||||
caps.Categories.AddCategoryMapping("Atari 7800", NewznabStandardCategory.ConsoleOther, "Atari 7800");
|
||||
caps.Categories.AddCategoryMapping("Atari Jaguar", NewznabStandardCategory.ConsoleOther, "Atari Jaguar");
|
||||
caps.Categories.AddCategoryMapping("Atari Lynx", NewznabStandardCategory.ConsoleOther, "Atari Lynx");
|
||||
caps.Categories.AddCategoryMapping("Atari ST", NewznabStandardCategory.ConsoleOther, "Atari ST");
|
||||
|
||||
caps.Categories.AddCategoryMapping("Amstrad CPC", NewznabStandardCategory.ConsoleOther, "Amstrad CPC");
|
||||
|
||||
caps.Categories.AddCategoryMapping("ZX Spectrum", NewznabStandardCategory.ConsoleOther, "ZX Spectrum");
|
||||
|
||||
caps.Categories.AddCategoryMapping("MSX", NewznabStandardCategory.ConsoleOther, "MSX");
|
||||
caps.Categories.AddCategoryMapping("MSX 2", NewznabStandardCategory.ConsoleOther, "MSX 2");
|
||||
|
||||
caps.Categories.AddCategoryMapping("Game.com", NewznabStandardCategory.ConsoleOther, "Game.com");
|
||||
caps.Categories.AddCategoryMapping("Gizmondo", NewznabStandardCategory.ConsoleOther, "Gizmondo");
|
||||
|
||||
caps.Categories.AddCategoryMapping("V.Smile", NewznabStandardCategory.ConsoleOther, "V.Smile");
|
||||
caps.Categories.AddCategoryMapping("CreatiVision", NewznabStandardCategory.ConsoleOther, "CreatiVision");
|
||||
|
||||
caps.Categories.AddCategoryMapping("Board Game", NewznabStandardCategory.ConsoleOther, "Board Game");
|
||||
caps.Categories.AddCategoryMapping("Card Game", NewznabStandardCategory.ConsoleOther, "Card Game");
|
||||
caps.Categories.AddCategoryMapping("Miniature Wargames", NewznabStandardCategory.ConsoleOther, "Miniature Wargames");
|
||||
caps.Categories.AddCategoryMapping("Pen and Paper RPG", NewznabStandardCategory.ConsoleOther, "Pen and Paper RPG");
|
||||
|
||||
caps.Categories.AddCategoryMapping("3DO", NewznabStandardCategory.ConsoleOther, "3DO");
|
||||
caps.Categories.AddCategoryMapping("Bandai WonderSwan", NewznabStandardCategory.ConsoleOther, "Bandai WonderSwan");
|
||||
caps.Categories.AddCategoryMapping("Bandai WonderSwan Color", NewznabStandardCategory.ConsoleOther, "Bandai WonderSwan Color");
|
||||
caps.Categories.AddCategoryMapping("Casio Loopy", NewznabStandardCategory.ConsoleOther, "Casio Loopy");
|
||||
caps.Categories.AddCategoryMapping("Casio PV-1000", NewznabStandardCategory.ConsoleOther, "Casio PV-1000");
|
||||
caps.Categories.AddCategoryMapping("Colecovision", NewznabStandardCategory.ConsoleOther, "Colecovision");
|
||||
caps.Categories.AddCategoryMapping("Commodore 64", NewznabStandardCategory.ConsoleOther, "Commodore 64");
|
||||
caps.Categories.AddCategoryMapping("Commodore 128", NewznabStandardCategory.ConsoleOther, "Commodore 128");
|
||||
caps.Categories.AddCategoryMapping("Commodore Amiga", NewznabStandardCategory.ConsoleOther, "Commodore Amiga");
|
||||
caps.Categories.AddCategoryMapping("Commodore Plus-4", NewznabStandardCategory.ConsoleOther, "Commodore Plus-4");
|
||||
caps.Categories.AddCategoryMapping("Commodore VIC-20", NewznabStandardCategory.ConsoleOther, "Commodore VIC-20");
|
||||
caps.Categories.AddCategoryMapping("Emerson Arcadia 2001", NewznabStandardCategory.ConsoleOther, "Emerson Arcadia 2001");
|
||||
caps.Categories.AddCategoryMapping("Entex Adventure Vision", NewznabStandardCategory.ConsoleOther, "Entex Adventure Vision");
|
||||
caps.Categories.AddCategoryMapping("Epoch Super Casette Vision", NewznabStandardCategory.ConsoleOther, "Epoch Super Casette Vision");
|
||||
caps.Categories.AddCategoryMapping("Fairchild Channel F", NewznabStandardCategory.ConsoleOther, "Fairchild Channel F");
|
||||
caps.Categories.AddCategoryMapping("Funtech Super Acan", NewznabStandardCategory.ConsoleOther, "Funtech Super Acan");
|
||||
caps.Categories.AddCategoryMapping("GamePark GP32", NewznabStandardCategory.ConsoleOther, "GamePark GP32");
|
||||
caps.Categories.AddCategoryMapping("General Computer Vectrex", NewznabStandardCategory.ConsoleOther, "General Computer Vectrex");
|
||||
caps.Categories.AddCategoryMapping("Interactive DVD", NewznabStandardCategory.ConsoleOther, "Interactive DVD");
|
||||
caps.Categories.AddCategoryMapping("Linux", NewznabStandardCategory.ConsoleOther, "Linux");
|
||||
caps.Categories.AddCategoryMapping("Hartung Game Master", NewznabStandardCategory.ConsoleOther, "Hartung Game Master");
|
||||
caps.Categories.AddCategoryMapping("Magnavox-Phillips Odyssey", NewznabStandardCategory.ConsoleOther, "Magnavox-Phillips Odyssey");
|
||||
caps.Categories.AddCategoryMapping("Mattel Intellivision", NewznabStandardCategory.ConsoleOther, "Mattel Intellivision");
|
||||
caps.Categories.AddCategoryMapping("Memotech MTX", NewznabStandardCategory.ConsoleOther, "Memotech MTX");
|
||||
caps.Categories.AddCategoryMapping("Miles Gordon Sam Coupe", NewznabStandardCategory.ConsoleOther, "Miles Gordon Sam Coupe");
|
||||
caps.Categories.AddCategoryMapping("NEC PC-98", NewznabStandardCategory.ConsoleOther, "NEC PC-98");
|
||||
caps.Categories.AddCategoryMapping("NEC PC-FX", NewznabStandardCategory.ConsoleOther, "NEC PC-FX");
|
||||
caps.Categories.AddCategoryMapping("NEC SuperGrafx", NewznabStandardCategory.ConsoleOther, "NEC SuperGrafx");
|
||||
caps.Categories.AddCategoryMapping("NEC TurboGrafx-16", NewznabStandardCategory.ConsoleOther, "NEC TurboGrafx-16");
|
||||
caps.Categories.AddCategoryMapping("Nokia N-Gage", NewznabStandardCategory.ConsoleOther, "Nokia N-Gage");
|
||||
caps.Categories.AddCategoryMapping("Ouya", NewznabStandardCategory.ConsoleOther, "Ouya");
|
||||
caps.Categories.AddCategoryMapping("Philips Videopac+", NewznabStandardCategory.ConsoleOther, "Philips Videopac+");
|
||||
caps.Categories.AddCategoryMapping("Phone/PDA", NewznabStandardCategory.ConsoleOther, "Phone/PDA");
|
||||
caps.Categories.AddCategoryMapping("RCA Studio II", NewznabStandardCategory.ConsoleOther, "RCA Studio II");
|
||||
caps.Categories.AddCategoryMapping("Sharp X1", NewznabStandardCategory.ConsoleOther, "Sharp X1");
|
||||
caps.Categories.AddCategoryMapping("Sharp X68000", NewznabStandardCategory.ConsoleOther, "Sharp X68000");
|
||||
caps.Categories.AddCategoryMapping("SNK Neo Geo", NewznabStandardCategory.ConsoleOther, "SNK Neo Geo");
|
||||
caps.Categories.AddCategoryMapping("SNK Neo Geo Pocket", NewznabStandardCategory.ConsoleOther, "SNK Neo Geo Pocket");
|
||||
caps.Categories.AddCategoryMapping("Taito Type X", NewznabStandardCategory.ConsoleOther, "Taito Type X");
|
||||
caps.Categories.AddCategoryMapping("Tandy Color Computer", NewznabStandardCategory.ConsoleOther, "Tandy Color Computer");
|
||||
caps.Categories.AddCategoryMapping("Tangerine Oric", NewznabStandardCategory.ConsoleOther, "Tangerine Oric");
|
||||
caps.Categories.AddCategoryMapping("Thomson MO5", NewznabStandardCategory.ConsoleOther, "Thomson MO5");
|
||||
caps.Categories.AddCategoryMapping("Watara Supervision", NewznabStandardCategory.ConsoleOther, "Watara Supervision");
|
||||
caps.Categories.AddCategoryMapping("Retro - Other", NewznabStandardCategory.ConsoleOther, "Retro - Other");
|
||||
|
||||
caps.Categories.AddCategoryMapping("OST", NewznabStandardCategory.AudioOther, "OST");
|
||||
caps.Categories.AddCategoryMapping("Applications", NewznabStandardCategory.PC0day, "Applications");
|
||||
caps.Categories.AddCategoryMapping("E-Books", NewznabStandardCategory.BooksEBook, "E-Books");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class GazelleGamesRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public GazelleGamesSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
public GazelleGamesRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories)
|
||||
{
|
||||
var searchUrl = string.Format("{0}/torrents.php", BaseUrl.TrimEnd('/'));
|
||||
|
||||
var searchString = term;
|
||||
|
||||
var searchType = Settings.SearchGroupNames ? "groupname" : "searchstr";
|
||||
|
||||
var queryCollection = new NameValueCollection
|
||||
{
|
||||
{ searchType, searchString },
|
||||
{ "order_by", "time" },
|
||||
{ "order_way", "desc" },
|
||||
{ "action", "basic" },
|
||||
{ "searchsubmit", "1" }
|
||||
};
|
||||
|
||||
var i = 0;
|
||||
|
||||
foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories))
|
||||
{
|
||||
queryCollection.Add($"artistcheck[{i++}]", cat);
|
||||
}
|
||||
|
||||
searchUrl += "?" + queryCollection.GetQueryString();
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Html);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class GazelleGamesParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly GazelleGamesSettings _settings;
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
private readonly string _baseUrl;
|
||||
|
||||
public GazelleGamesParser(GazelleGamesSettings settings, IndexerCapabilitiesCategories categories, string baseurl)
|
||||
{
|
||||
_settings = settings;
|
||||
_categories = categories;
|
||||
_baseUrl = baseurl;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<ReleaseInfo>();
|
||||
|
||||
var rowsSelector = ".torrent_table > tbody > tr";
|
||||
|
||||
var searchResultParser = new HtmlParser();
|
||||
var searchResultDocument = searchResultParser.ParseDocument(indexerResponse.Content);
|
||||
var rows = searchResultDocument.QuerySelectorAll(rowsSelector);
|
||||
|
||||
var stickyGroup = false;
|
||||
string categoryStr;
|
||||
ICollection<IndexerCategory> groupCategory = null;
|
||||
string groupTitle = null;
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
if (row.ClassList.Contains("torrent"))
|
||||
{
|
||||
// garbage rows
|
||||
continue;
|
||||
}
|
||||
else if (row.ClassList.Contains("group"))
|
||||
{
|
||||
stickyGroup = row.ClassList.Contains("sticky");
|
||||
var dispalyname = row.QuerySelector("#displayname");
|
||||
var qCat = row.QuerySelector("td.cats_col > div");
|
||||
categoryStr = qCat.GetAttribute("title");
|
||||
var qArtistLink = dispalyname.QuerySelector("#groupplatform > a");
|
||||
if (qArtistLink != null)
|
||||
{
|
||||
categoryStr = ParseUtil.GetArgumentFromQueryString(qArtistLink.GetAttribute("href"), "artistname");
|
||||
}
|
||||
|
||||
groupCategory = _categories.MapTrackerCatToNewznab(categoryStr);
|
||||
|
||||
var qDetailsLink = dispalyname.QuerySelector("#groupname > a");
|
||||
groupTitle = qDetailsLink.TextContent;
|
||||
}
|
||||
else if (row.ClassList.Contains("group_torrent"))
|
||||
{
|
||||
if (row.QuerySelector("td.edition_info") != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var sizeString = row.QuerySelector("td:nth-child(4)").TextContent;
|
||||
if (string.IsNullOrEmpty(sizeString))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var qDetailsLink = row.QuerySelector("a[href^=\"torrents.php?id=\"]");
|
||||
var title = qDetailsLink.TextContent.Replace(", Freeleech!", "").Replace(", Neutral Leech!", "");
|
||||
|
||||
//if (stickyGroup && (query.ImdbID == null || !NewznabStandardCategory.MovieSearchImdbAvailable) && !query.MatchQueryStringAND(title)) // AND match for sticky releases
|
||||
//{
|
||||
// continue;
|
||||
//}
|
||||
var qDescription = qDetailsLink.QuerySelector("span.torrent_info_tags");
|
||||
var qDLLink = row.QuerySelector("a[href^=\"torrents.php?action=download\"]");
|
||||
var qTime = row.QuerySelector("span.time");
|
||||
var qGrabs = row.QuerySelector("td:nth-child(5)");
|
||||
var qSeeders = row.QuerySelector("td:nth-child(6)");
|
||||
var qLeechers = row.QuerySelector("td:nth-child(7)");
|
||||
var qFreeLeech = row.QuerySelector("strong.freeleech_label");
|
||||
var qNeutralLeech = row.QuerySelector("strong.neutralleech_label");
|
||||
var time = qTime.GetAttribute("title");
|
||||
var link = _baseUrl + qDLLink.GetAttribute("href");
|
||||
var seeders = ParseUtil.CoerceInt(qSeeders.TextContent);
|
||||
var publishDate = DateTime.SpecifyKind(
|
||||
DateTime.ParseExact(time, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture),
|
||||
DateTimeKind.Unspecified).ToLocalTime();
|
||||
var details = _baseUrl + qDetailsLink.GetAttribute("href");
|
||||
var grabs = ParseUtil.CoerceInt(qGrabs.TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(qLeechers.TextContent);
|
||||
var size = ReleaseInfo.GetBytes(sizeString);
|
||||
|
||||
var release = new TorrentInfo
|
||||
{
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 288000, //80 hours
|
||||
Categories = groupCategory,
|
||||
PublishDate = publishDate,
|
||||
Size = size,
|
||||
InfoUrl = details,
|
||||
DownloadUrl = link,
|
||||
Guid = link,
|
||||
Grabs = grabs,
|
||||
Seeders = seeders,
|
||||
Peers = leechers + seeders,
|
||||
Title = title,
|
||||
Description = qDescription?.TextContent,
|
||||
UploadVolumeFactor = qNeutralLeech is null ? 1 : 0,
|
||||
DownloadVolumeFactor = qFreeLeech != null || qNeutralLeech != null ? 0 : 1
|
||||
};
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class GazelleGamesSettingsValidator : AbstractValidator<GazelleGamesSettings>
|
||||
{
|
||||
public GazelleGamesSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.Cookie).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public class GazelleGamesSettings : IProviderConfig
|
||||
{
|
||||
private static readonly GazelleGamesSettingsValidator Validator = new GazelleGamesSettingsValidator();
|
||||
|
||||
public GazelleGamesSettings()
|
||||
{
|
||||
Cookie = "";
|
||||
SearchGroupNames = false;
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Cookie", HelpText = "Login cookie from website")]
|
||||
public string Cookie { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Search Group Names", Type = FieldType.Checkbox, HelpText = "Search Group Names Only")]
|
||||
public bool SearchGroupNames { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,11 +57,6 @@ namespace NzbDrone.Core.Indexers.HDBits
|
||||
|
||||
var flags = new List<IndexerFlag>();
|
||||
|
||||
if (result.FreeLeech == "yes")
|
||||
{
|
||||
flags.Add(IndexerFlag.FreeLeech);
|
||||
}
|
||||
|
||||
if (internalRelease)
|
||||
{
|
||||
flags.Add(IndexerFlag.Internal);
|
||||
@@ -83,6 +78,8 @@ namespace NzbDrone.Core.Indexers.HDBits
|
||||
Internal = internalRelease,
|
||||
ImdbId = result.ImdbInfo?.Id ?? 0,
|
||||
TvdbId = result.TvdbInfo?.Id ?? 0,
|
||||
DownloadVolumeFactor = result.FreeLeech == "yes" ? 0 : 1,
|
||||
UploadVolumeFactor = 1,
|
||||
IndexerFlags = flags
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace NzbDrone.Core.Indexers.HDBits
|
||||
Mediums = System.Array.Empty<int>();
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Username", Privacy = PrivacyLevel.UserName)]
|
||||
[FieldDefinition(0, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey)]
|
||||
|
||||
@@ -375,10 +375,10 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site username")]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Site password", Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
@@ -28,10 +28,10 @@ namespace NzbDrone.Core.Indexers.Headphones
|
||||
|
||||
public string ApiKey { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Username")]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public virtual NzbDroneValidationResult Validate()
|
||||
|
||||
@@ -345,10 +345,10 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site username")]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Site password", Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
306
src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs
Normal file
306
src/NzbDrone.Core/Indexers/Definitions/Nebulance.cs
Normal file
@@ -0,0 +1,306 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
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.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 Nebulance : TorrentIndexerBase<NebulanceSettings>
|
||||
{
|
||||
public override string Name => "Nebulance";
|
||||
public override string BaseUrl => "https://nebulance.io/";
|
||||
private string LoginUrl => BaseUrl + "login.php";
|
||||
public override string Description => "At Nebulance we will change the way you think about 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();
|
||||
|
||||
public Nebulance(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new NebulanceRequestGenerator() { Settings = Settings, Capabilities = Capabilities, BaseUrl = BaseUrl };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new NebulanceParser(Settings, Capabilities.Categories, BaseUrl);
|
||||
}
|
||||
|
||||
protected override async Task DoLogin()
|
||||
{
|
||||
var requestBuilder = new HttpRequestBuilder(LoginUrl)
|
||||
{
|
||||
LogResponseContent = true
|
||||
};
|
||||
|
||||
requestBuilder.Method = HttpMethod.POST;
|
||||
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
|
||||
|
||||
var cookies = Cookies;
|
||||
|
||||
Cookies = null;
|
||||
var authLoginRequest = requestBuilder
|
||||
.AddFormParameter("username", Settings.Username)
|
||||
.AddFormParameter("password", Settings.Password)
|
||||
.AddFormParameter("twofa", Settings.TwoFactorAuth)
|
||||
.AddFormParameter("keeplogged", "on")
|
||||
.AddFormParameter("login", "Login")
|
||||
.SetHeader("Content-Type", "multipart/form-data")
|
||||
.Build();
|
||||
|
||||
var response = await ExecuteAuth(authLoginRequest);
|
||||
|
||||
cookies = response.GetCookies();
|
||||
UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30));
|
||||
|
||||
_logger.Debug("Nebulance authentication succeeded.");
|
||||
}
|
||||
|
||||
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
|
||||
{
|
||||
if (!httpResponse.Content.Contains("logout.php"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TV);
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD);
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVHD);
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class NebulanceRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public NebulanceSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
public NebulanceRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories)
|
||||
{
|
||||
var searchUrl = string.Format("{0}/torrents.php", BaseUrl.TrimEnd('/'));
|
||||
|
||||
var searchTerm = term;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchTerm))
|
||||
{
|
||||
searchTerm = Regex.Replace(searchTerm, @"[-._]", " ");
|
||||
}
|
||||
|
||||
var qc = new NameValueCollection
|
||||
{
|
||||
{ "action", "basic" },
|
||||
{ "order_by", "time" },
|
||||
{ "order_way", "desc" },
|
||||
{ "searchtext", searchTerm }
|
||||
};
|
||||
|
||||
searchUrl = searchUrl + "?" + qc.GetQueryString();
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Html);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class NebulanceParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly NebulanceSettings _settings;
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
private readonly string _baseUrl;
|
||||
|
||||
public NebulanceParser(NebulanceSettings settings, IndexerCapabilitiesCategories categories, string baseurl)
|
||||
{
|
||||
_settings = settings;
|
||||
_categories = categories;
|
||||
_baseUrl = baseurl;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<ReleaseInfo>();
|
||||
|
||||
var parser = new HtmlParser();
|
||||
var document = parser.ParseDocument(indexerResponse.Content);
|
||||
var rows = document.QuerySelectorAll(".torrent_table > tbody > tr[class^='torrent row']");
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var title = row.QuerySelector("a[data-src]").GetAttribute("data-src");
|
||||
if (string.IsNullOrEmpty(title) || title == "0")
|
||||
{
|
||||
title = row.QuerySelector("a[data-src]").TextContent;
|
||||
title = Regex.Replace(title, @"[\[\]\/]", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (title.Length > 5 && title.Substring(title.Length - 5).Contains("."))
|
||||
{
|
||||
title = title.Remove(title.LastIndexOf(".", StringComparison.Ordinal));
|
||||
}
|
||||
}
|
||||
|
||||
var posterStr = row.QuerySelector("img")?.GetAttribute("src");
|
||||
Uri.TryCreate(posterStr, UriKind.Absolute, out var poster);
|
||||
|
||||
var details = _baseUrl + row.QuerySelector("a[data-src]").GetAttribute("href");
|
||||
var link = _baseUrl + row.QuerySelector("a[href*='action=download']").GetAttribute("href");
|
||||
|
||||
var qColSize = row.QuerySelector("td:nth-child(3)");
|
||||
var size = ReleaseInfo.GetBytes(qColSize.Children[0].TextContent);
|
||||
var files = ParseUtil.CoerceInt(qColSize.Children[1].TextContent.Split(':')[1].Trim());
|
||||
|
||||
var qPublishdate = row.QuerySelector("td:nth-child(4) span");
|
||||
var publishDateStr = qPublishdate.GetAttribute("title");
|
||||
var publishDate = !string.IsNullOrEmpty(publishDateStr) && publishDateStr.Contains(",")
|
||||
? DateTime.ParseExact(publishDateStr, "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture)
|
||||
: DateTime.ParseExact(qPublishdate.TextContent.Trim(), "MMM dd yyyy, HH:mm", CultureInfo.InvariantCulture);
|
||||
|
||||
var grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(5)").TextContent);
|
||||
var seeds = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(6)").TextContent);
|
||||
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-child(7)").TextContent);
|
||||
|
||||
var release = new TorrentInfo
|
||||
{
|
||||
Title = title,
|
||||
Guid = details,
|
||||
InfoUrl = details,
|
||||
DownloadUrl = link,
|
||||
Categories = new List<IndexerCategory> { TvCategoryFromQualityParser.ParseTvShowQuality(title) },
|
||||
Size = size,
|
||||
Files = files,
|
||||
PublishDate = publishDate,
|
||||
Grabs = grabs,
|
||||
Seeders = seeds,
|
||||
Peers = seeds + leechers,
|
||||
MinimumRatio = 0, // ratioless
|
||||
MinimumSeedTime = 86400, // 24 hours
|
||||
DownloadVolumeFactor = 0, // ratioless tracker
|
||||
UploadVolumeFactor = 1
|
||||
};
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class NebulanceSettingsValidator : AbstractValidator<NebulanceSettings>
|
||||
{
|
||||
public NebulanceSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.Username).NotEmpty();
|
||||
RuleFor(c => c.Password).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public class NebulanceSettings : IProviderConfig
|
||||
{
|
||||
private static readonly NebulanceSettingsValidator Validator = new NebulanceSettingsValidator();
|
||||
|
||||
public NebulanceSettings()
|
||||
{
|
||||
Username = "";
|
||||
Password = "";
|
||||
TwoFactorAuth = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Two Factor Auth", HelpText = "Two-Factor Auth")]
|
||||
public string TwoFactorAuth { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,8 +98,8 @@ namespace NzbDrone.Core.Indexers.Newznab
|
||||
yield return GetDefinition("NZBFinder", GetSettings("https://nzbfinder.ws"));
|
||||
yield return GetDefinition("NZBgeek", GetSettings("https://api.nzbgeek.info"));
|
||||
yield return GetDefinition("NzbNoob", GetSettings("https://www.nzbnoob.com"));
|
||||
yield return GetDefinition("NZBNDX", GetSettings("https://www.nzbndx.com"));
|
||||
yield return GetDefinition("NzbPlanet", GetSettings("https://api.nzbplanet.net"));
|
||||
yield return GetDefinition("NZBs2GO", GetSettings("https://nzbs2go.com", apiPath: @"/api/v1/api"));
|
||||
yield return GetDefinition("NZBStars", GetSettings("https://nzbstars.com"));
|
||||
yield return GetDefinition("NZBXS", GetSettings("https://www.nzbxs.com"));
|
||||
yield return GetDefinition("OZnzb", GetSettings("https://api.oznzb.com"));
|
||||
|
||||
@@ -50,4 +50,4 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,11 +78,6 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
||||
flags.Add(PassThePopcornFlag.Approved); //title = $"{title} ✔";
|
||||
}
|
||||
|
||||
if (torrent.FreeleechType == "Freeleech")
|
||||
{
|
||||
flags.Add(IndexerFlag.FreeLeech);
|
||||
}
|
||||
|
||||
if (torrent.Scene)
|
||||
{
|
||||
flags.Add(IndexerFlag.Scene);
|
||||
|
||||
@@ -401,13 +401,13 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Pin", Advanced = true, HelpText = "Site Pin")]
|
||||
[FieldDefinition(1, Label = "Pin", HelpText = "Site Pin")]
|
||||
public string Pin { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Username", Advanced = true, HelpText = "Site username")]
|
||||
[FieldDefinition(2, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Password", Advanced = true, HelpText = "Site Password")]
|
||||
[FieldDefinition(3, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
@@ -66,6 +66,8 @@ namespace NzbDrone.Core.Indexers.Rarbg
|
||||
torrentInfo.PublishDate = torrent.pubdate.ToUniversalTime();
|
||||
torrentInfo.Seeders = torrent.seeders;
|
||||
torrentInfo.Peers = torrent.leechers + torrent.seeders;
|
||||
torrentInfo.DownloadVolumeFactor = 0;
|
||||
torrentInfo.UploadVolumeFactor = 1;
|
||||
|
||||
if (torrent.movie_info != null)
|
||||
{
|
||||
|
||||
@@ -343,10 +343,10 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site username")]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Site password", Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
57
src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs
Normal file
57
src/NzbDrone.Core/Indexers/Definitions/ShareIsland.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Definitions.UNIT3D;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
public class ShareIsland : Unit3dBase
|
||||
{
|
||||
public override string Name => "ShareIsland";
|
||||
public override string BaseUrl => "https://shareisland.org/";
|
||||
public override string Description => "A general italian tracker";
|
||||
public override string Language => "it-it";
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
|
||||
public ShareIsland(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movie");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "Serie TV");
|
||||
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.BooksEBook, "Ebook");
|
||||
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.BooksMags, "Riviste e Giornali");
|
||||
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.XXX, "XXX");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music");
|
||||
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.PCGames, "Games");
|
||||
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.PC, "Software");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
}
|
||||
196
src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs
Normal file
196
src/NzbDrone.Core/Indexers/Definitions/ShowRSS.cs
Normal file
@@ -0,0 +1,196 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using FluentValidation;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
public class ShowRSS : TorrentIndexerBase<ShowRSSSettings>
|
||||
{
|
||||
public override string Name => "ShowRSS";
|
||||
public override string BaseUrl => "https://showrss.info/";
|
||||
public override string Language => "en-us";
|
||||
public override string Description => "showRSS is a service that allows you to keep track of your favorite TV shows";
|
||||
public override Encoding Encoding => Encoding.UTF8;
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public ShowRSS(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new ShowRSSRequestGenerator() { Settings = Settings, Capabilities = Capabilities, BaseUrl = BaseUrl };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new ShowRSSParser(BaseUrl);
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TV);
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD);
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVHD);
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class ShowRSSRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public ShowRSSSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
public ShowRSSRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories)
|
||||
{
|
||||
var searchUrl = string.Format("{0}/other/all.rss", BaseUrl.TrimEnd('/'));
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Html);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class ShowRSSParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly string _baseUrl;
|
||||
private string BrowseUrl => _baseUrl + "browse/";
|
||||
|
||||
public ShowRSSParser(string baseurl)
|
||||
{
|
||||
_baseUrl = baseurl;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<ReleaseInfo>();
|
||||
|
||||
var xmlDoc = new XmlDocument();
|
||||
xmlDoc.LoadXml(indexerResponse.Content);
|
||||
foreach (XmlNode node in xmlDoc.GetElementsByTagName("item"))
|
||||
{
|
||||
var title = node.SelectSingleNode(".//*[local-name()='raw_title']").InnerText;
|
||||
|
||||
// TODO: Make sure we don't return all sorts of trash
|
||||
//if (!query.MatchQueryStringAND(title))
|
||||
//{
|
||||
// continue;
|
||||
//}
|
||||
var category = title.Contains("720p") || title.Contains("1080p") ?
|
||||
NewznabStandardCategory.TVHD :
|
||||
NewznabStandardCategory.TVSD;
|
||||
|
||||
var magnetUri = node.SelectSingleNode("link")?.InnerText;
|
||||
var publishDate = DateTime.Parse(node.SelectSingleNode("pubDate").InnerText, CultureInfo.InvariantCulture);
|
||||
var infoHash = node.SelectSingleNode(".//*[local-name()='info_hash']").InnerText;
|
||||
var details = BrowseUrl + node.SelectSingleNode(".//*[local-name()='show_id']").InnerText;
|
||||
|
||||
var release = new TorrentInfo
|
||||
{
|
||||
Title = title,
|
||||
InfoUrl = details,
|
||||
Categories = new List<IndexerCategory> { category },
|
||||
Guid = magnetUri,
|
||||
PublishDate = publishDate,
|
||||
InfoHash = infoHash,
|
||||
MagnetUrl = magnetUri,
|
||||
Size = 512,
|
||||
Seeders = 1,
|
||||
Peers = 2,
|
||||
DownloadVolumeFactor = 0,
|
||||
UploadVolumeFactor = 1
|
||||
};
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class ShowRSSSettingsValidator : AbstractValidator<ShowRSSSettings>
|
||||
{
|
||||
}
|
||||
|
||||
public class ShowRSSSettings : IProviderConfig
|
||||
{
|
||||
private static readonly ShowRSSSettingsValidator Validator = new ShowRSSSettingsValidator();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
606
src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs
Normal file
606
src/NzbDrone.Core/Indexers/Definitions/SpeedApp.cs
Normal file
@@ -0,0 +1,606 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentValidation;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.Core.Indexers.Exceptions;
|
||||
using NzbDrone.Core.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 SpeedApp : TorrentIndexerBase<SpeedAppSettings>
|
||||
{
|
||||
public override string Name => "SpeedApp.io";
|
||||
|
||||
public override string BaseUrl => "https://speedapp.io";
|
||||
|
||||
private string ApiUrl => $"{BaseUrl}/api";
|
||||
|
||||
private string LoginUrl => $"{ApiUrl}/login";
|
||||
|
||||
public override string Description => "SpeedApp is a ROMANIAN Private Torrent Tracker for MOVIES / TV / GENERAL";
|
||||
|
||||
public override string Language => "ro-ro";
|
||||
|
||||
public override Encoding Encoding => Encoding.UTF8;
|
||||
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
private IIndexerRepository _indexerRepository;
|
||||
|
||||
public SpeedApp(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, IIndexerRepository indexerRepository)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
_indexerRepository = indexerRepository;
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new SpeedAppRequestGenerator(Capabilities, Settings, ApiUrl);
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new SpeedAppParser(ApiUrl);
|
||||
}
|
||||
|
||||
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
|
||||
{
|
||||
return Settings.ApiKey.IsNullOrWhiteSpace() || httpResponse.StatusCode == HttpStatusCode.Unauthorized;
|
||||
}
|
||||
|
||||
protected override async Task DoLogin()
|
||||
{
|
||||
var requestBuilder = new HttpRequestBuilder(LoginUrl)
|
||||
{
|
||||
LogResponseContent = true,
|
||||
AllowAutoRedirect = true,
|
||||
Method = HttpMethod.POST,
|
||||
};
|
||||
|
||||
var request = requestBuilder.Build();
|
||||
|
||||
var data = new SpeedAppAuthenticationRequest
|
||||
{
|
||||
Email = Settings.Email,
|
||||
Password = Settings.Password
|
||||
};
|
||||
|
||||
request.SetContent(JsonConvert.SerializeObject(data));
|
||||
|
||||
request.Headers.ContentType = MediaTypeNames.Application.Json;
|
||||
|
||||
var response = await ExecuteAuth(request);
|
||||
|
||||
var statusCode = (int)response.StatusCode;
|
||||
|
||||
if (statusCode is < 200 or > 299)
|
||||
{
|
||||
throw new HttpException(response);
|
||||
}
|
||||
|
||||
var parsedResponse = JsonConvert.DeserializeObject<SpeedAppAuthenticationResponse>(response.Content);
|
||||
|
||||
Settings.ApiKey = parsedResponse.Token;
|
||||
|
||||
if (Definition.Id > 0)
|
||||
{
|
||||
_indexerRepository.UpdateSettings((IndexerDefinition)Definition);
|
||||
}
|
||||
|
||||
_logger.Debug("SpeedApp authentication succeeded.");
|
||||
}
|
||||
|
||||
protected override void ModifyRequest(IndexerRequest request)
|
||||
{
|
||||
request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}");
|
||||
}
|
||||
|
||||
public override async Task<byte[]> Download(Uri link)
|
||||
{
|
||||
Cookies = GetCookies();
|
||||
|
||||
if (link.Scheme == "magnet")
|
||||
{
|
||||
ValidateMagnet(link.OriginalString);
|
||||
return Encoding.UTF8.GetBytes(link.OriginalString);
|
||||
}
|
||||
|
||||
var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri);
|
||||
|
||||
if (Cookies != null)
|
||||
{
|
||||
requestBuilder.SetCookies(Cookies);
|
||||
}
|
||||
|
||||
var request = requestBuilder.Build();
|
||||
request.AllowAutoRedirect = FollowRedirect;
|
||||
request.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}");
|
||||
|
||||
byte[] torrentData;
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.ExecuteAsync(request);
|
||||
torrentData = response.ResponseData;
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
if (ex.Response.StatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
_logger.Error(ex, "Downloading torrent file for release failed since it no longer exists ({0})", link.AbsoluteUri);
|
||||
throw new ReleaseUnavailableException("Downloading torrent failed", ex);
|
||||
}
|
||||
|
||||
if ((int)ex.Response.StatusCode == 429)
|
||||
{
|
||||
_logger.Error("API Grab Limit reached for {0}", link.AbsoluteUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri);
|
||||
}
|
||||
|
||||
throw new ReleaseDownloadException("Downloading torrent failed", ex);
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
_logger.Error(ex, "Downloading torrent file for release failed ({0})", link.AbsoluteUri);
|
||||
|
||||
throw new ReleaseDownloadException("Downloading torrent failed", ex);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_indexerStatusService.RecordFailure(Definition.Id);
|
||||
_logger.Error("Downloading torrent failed");
|
||||
throw;
|
||||
}
|
||||
|
||||
return torrentData;
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q,
|
||||
TvSearchParam.Season,
|
||||
TvSearchParam.Ep,
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q,
|
||||
MovieSearchParam.ImdbId,
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q,
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q,
|
||||
},
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.Movies, "Movie Packs");
|
||||
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.MoviesSD, "Movies: SD");
|
||||
caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.MoviesSD, "Movies: SD Ro");
|
||||
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.MoviesHD, "Movies: HD");
|
||||
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.MoviesHD, "Movies: HD Ro");
|
||||
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.MoviesDVD, "Movies: DVD");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesDVD, "Movies: DVD Ro");
|
||||
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.MoviesBluRay, "Movies: BluRay");
|
||||
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.MoviesBluRay, "Movies: BluRay Ro");
|
||||
caps.Categories.AddCategoryMapping(59, NewznabStandardCategory.Movies, "Movies: Ro");
|
||||
caps.Categories.AddCategoryMapping(57, NewznabStandardCategory.MoviesUHD, "Movies: 4K (2160p) Ro");
|
||||
caps.Categories.AddCategoryMapping(61, NewznabStandardCategory.MoviesUHD, "Movies: 4K (2160p)");
|
||||
caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.TV, "TV Packs");
|
||||
caps.Categories.AddCategoryMapping(66, NewznabStandardCategory.TV, "TV Packs Ro");
|
||||
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.TVSD, "TV Episodes");
|
||||
caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.TVSD, "TV Episodes Ro");
|
||||
caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.TVHD, "TV Episodes HD");
|
||||
caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.TVHD, "TV Episodes HD Ro");
|
||||
caps.Categories.AddCategoryMapping(60, NewznabStandardCategory.TV, "TV Ro");
|
||||
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.PCGames, "Games: PC-ISO");
|
||||
caps.Categories.AddCategoryMapping(52, NewznabStandardCategory.Console, "Games: Console");
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.PC0day, "Applications");
|
||||
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.PC, "Applications: Linux");
|
||||
caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.PCMac, "Applications: Mac");
|
||||
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.PCMobileOther, "Applications: Mobile");
|
||||
caps.Categories.AddCategoryMapping(62, NewznabStandardCategory.TV, "TV Cartoons");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVAnime, "TV Anime / Hentai");
|
||||
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.BooksEBook, "E-books");
|
||||
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Audio, "Music");
|
||||
caps.Categories.AddCategoryMapping(64, NewznabStandardCategory.AudioVideo, "Music Video");
|
||||
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.Other, "Images");
|
||||
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.TVSport, "TV Sports");
|
||||
caps.Categories.AddCategoryMapping(58, NewznabStandardCategory.TVSport, "TV Sports Ro");
|
||||
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVDocumentary, "TV Documentary");
|
||||
caps.Categories.AddCategoryMapping(63, NewznabStandardCategory.TVDocumentary, "TV Documentary Ro");
|
||||
caps.Categories.AddCategoryMapping(65, NewznabStandardCategory.Other, "Tutorial");
|
||||
caps.Categories.AddCategoryMapping(67, NewznabStandardCategory.OtherMisc, "Miscellaneous");
|
||||
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.XXX, "XXX Movies");
|
||||
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.XXX, "XXX DVD");
|
||||
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.XXX, "XXX HD");
|
||||
caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.XXXImageSet, "XXX Images");
|
||||
caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.XXX, "XXX Packs");
|
||||
caps.Categories.AddCategoryMapping(51, NewznabStandardCategory.XXX, "XXX SD");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class SpeedAppRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
|
||||
private IndexerCapabilities Capabilities { get; }
|
||||
|
||||
private SpeedAppSettings Settings { get; }
|
||||
|
||||
private string BaseUrl { get; }
|
||||
|
||||
public SpeedAppRequestGenerator(IndexerCapabilities capabilities, SpeedAppSettings settings, string baseUrl)
|
||||
{
|
||||
Capabilities = capabilities;
|
||||
Settings = settings;
|
||||
BaseUrl = baseUrl;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
return GetSearch(searchCriteria, searchCriteria.FullImdbId);
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
return GetSearch(searchCriteria);
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
return GetSearch(searchCriteria, searchCriteria.FullImdbId, searchCriteria.Season, searchCriteria.Episode);
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
return GetSearch(searchCriteria);
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
return GetSearch(searchCriteria);
|
||||
}
|
||||
|
||||
private IndexerPageableRequestChain GetSearch(SearchCriteriaBase searchCriteria, string imdbId = null, int? season = null, string episode = null)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories, imdbId, season, episode));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null, int? season = null, string episode = null)
|
||||
{
|
||||
var qc = new NameValueCollection();
|
||||
|
||||
if (imdbId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
qc.Add("imdbId", imdbId);
|
||||
}
|
||||
else
|
||||
{
|
||||
qc.Add("search", term);
|
||||
}
|
||||
|
||||
if (season != null)
|
||||
{
|
||||
qc.Add("season", season.Value.ToString());
|
||||
}
|
||||
|
||||
if (episode != null)
|
||||
{
|
||||
qc.Add("episode", episode);
|
||||
}
|
||||
|
||||
var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories);
|
||||
|
||||
if (cats.Count > 0)
|
||||
{
|
||||
foreach (var cat in cats)
|
||||
{
|
||||
qc.Add("categories[]", cat);
|
||||
}
|
||||
}
|
||||
|
||||
var searchUrl = BaseUrl + "/torrent?" + qc.GetQueryString();
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
|
||||
|
||||
request.HttpRequest.Headers.Set("Authorization", $"Bearer {Settings.ApiKey}");
|
||||
|
||||
yield return request;
|
||||
}
|
||||
}
|
||||
|
||||
public class SpeedAppParser : IParseIndexerResponse
|
||||
{
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
|
||||
public SpeedAppParser(string baseUrl)
|
||||
{
|
||||
BaseUrl = baseUrl;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
|
||||
}
|
||||
|
||||
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
|
||||
{
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
|
||||
}
|
||||
|
||||
var jsonResponse = new HttpResponse<List<SpeedAppTorrent>>(indexerResponse.HttpResponse);
|
||||
|
||||
return jsonResponse.Resource.Select(torrent => new TorrentInfo
|
||||
{
|
||||
Guid = torrent.Id.ToString(),
|
||||
Title = torrent.Name,
|
||||
Description = torrent.ShortDescription,
|
||||
Size = torrent.Size,
|
||||
ImdbId = ParseUtil.GetImdbID(torrent.ImdbId).GetValueOrDefault(),
|
||||
DownloadUrl = $"{BaseUrl}/torrent/{torrent.Id}/download",
|
||||
InfoUrl = torrent.Url,
|
||||
Grabs = torrent.TimesCompleted,
|
||||
PublishDate = torrent.CreatedAt,
|
||||
Categories = new List<IndexerCategory> { new (torrent.Category.Id, torrent.Category.Name), },
|
||||
InfoHash = null,
|
||||
Seeders = torrent.Seeders,
|
||||
Peers = torrent.Leechers + torrent.Seeders,
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 172800,
|
||||
DownloadVolumeFactor = torrent.DownloadVolumeFactor,
|
||||
UploadVolumeFactor = torrent.UploadVolumeFactor,
|
||||
}).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class SpeedAppSettingsValidator : AbstractValidator<SpeedAppSettings>
|
||||
{
|
||||
public SpeedAppSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.Email).NotEmpty();
|
||||
RuleFor(c => c.Password).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public class SpeedAppSettings : IProviderConfig
|
||||
{
|
||||
private static readonly SpeedAppSettingsValidator Validator = new ();
|
||||
|
||||
public SpeedAppSettings()
|
||||
{
|
||||
Email = "";
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Email", HelpText = "Site email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[FieldDefinition(0, Label = "Api Key", Hidden = HiddenType.Hidden)]
|
||||
public string ApiKey { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
|
||||
public class SpeedAppCategory
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class SpeedAppCountry
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("flag_image")]
|
||||
public string FlagImage { get; set; }
|
||||
}
|
||||
|
||||
public class SpeedAppUploadedBy
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonProperty("username")]
|
||||
public string Username { get; set; }
|
||||
|
||||
[JsonProperty("email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[JsonProperty("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
[JsonProperty("class")]
|
||||
public int Class { get; set; }
|
||||
|
||||
[JsonProperty("avatar")]
|
||||
public string Avatar { get; set; }
|
||||
|
||||
[JsonProperty("uploaded")]
|
||||
public int Uploaded { get; set; }
|
||||
|
||||
[JsonProperty("downloaded")]
|
||||
public int Downloaded { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("country")]
|
||||
public SpeedAppCountry Country { get; set; }
|
||||
|
||||
[JsonProperty("passkey")]
|
||||
public string Passkey { get; set; }
|
||||
|
||||
[JsonProperty("invites")]
|
||||
public int Invites { get; set; }
|
||||
|
||||
[JsonProperty("timezone")]
|
||||
public string Timezone { get; set; }
|
||||
|
||||
[JsonProperty("hit_and_run_count")]
|
||||
public int HitAndRunCount { get; set; }
|
||||
|
||||
[JsonProperty("snatch_count")]
|
||||
public int SnatchCount { get; set; }
|
||||
|
||||
[JsonProperty("need_seed")]
|
||||
public int NeedSeed { get; set; }
|
||||
|
||||
[JsonProperty("average_seed_time")]
|
||||
public int AverageSeedTime { get; set; }
|
||||
|
||||
[JsonProperty("free_leech_tokens")]
|
||||
public int FreeLeechTokens { get; set; }
|
||||
|
||||
[JsonProperty("double_upload_tokens")]
|
||||
public int DoubleUploadTokens { get; set; }
|
||||
}
|
||||
|
||||
public class SpeedAppTag
|
||||
{
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
|
||||
[JsonProperty("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("match_list")]
|
||||
public List<string> MatchList { get; set; }
|
||||
|
||||
[JsonProperty("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
public class SpeedAppTorrent
|
||||
{
|
||||
[JsonProperty("download_volume_factor")]
|
||||
public float DownloadVolumeFactor { get; set; }
|
||||
|
||||
[JsonProperty("upload_volume_factor")]
|
||||
public float UploadVolumeFactor { get; set; }
|
||||
|
||||
[JsonProperty("url")]
|
||||
public string Url { get; set; }
|
||||
|
||||
[JsonProperty("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
[JsonProperty("category")]
|
||||
public SpeedAppCategory Category { get; set; }
|
||||
|
||||
[JsonProperty("size")]
|
||||
public long Size { get; set; }
|
||||
|
||||
[JsonProperty("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
[JsonProperty("times_completed")]
|
||||
public int TimesCompleted { get; set; }
|
||||
|
||||
[JsonProperty("leechers")]
|
||||
public int Leechers { get; set; }
|
||||
|
||||
[JsonProperty("seeders")]
|
||||
public int Seeders { get; set; }
|
||||
|
||||
[JsonProperty("uploaded_by")]
|
||||
public SpeedAppUploadedBy UploadedBy { get; set; }
|
||||
|
||||
[JsonProperty("short_description")]
|
||||
public string ShortDescription { get; set; }
|
||||
|
||||
[JsonProperty("poster")]
|
||||
public string Poster { get; set; }
|
||||
|
||||
[JsonProperty("season")]
|
||||
public int Season { get; set; }
|
||||
|
||||
[JsonProperty("episode")]
|
||||
public int Episode { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<SpeedAppTag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("imdb_id")]
|
||||
public string ImdbId { get; set; }
|
||||
}
|
||||
|
||||
public class SpeedAppAuthenticationRequest
|
||||
{
|
||||
[JsonProperty("username")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[JsonProperty("password")]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
|
||||
public class SpeedAppAuthenticationResponse
|
||||
{
|
||||
[JsonProperty("token")]
|
||||
public string Token { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -345,10 +345,10 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site username")]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Site password", Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")]
|
||||
|
||||
@@ -20,10 +20,10 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
|
||||
{
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "The username you use at your indexer.", Privacy = PrivacyLevel.UserName)]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string User { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Passkey", HelpText = "The password you use at your Indexer.", Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Passkey { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
@@ -354,10 +354,10 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site username")]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Site password", Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(2, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
@@ -30,11 +30,13 @@ namespace NzbDrone.Core.Indexers.Definitions.UNIT3D
|
||||
if (searchCriteria.ImdbId != null)
|
||||
{
|
||||
parameters.Add("imdb", searchCriteria.ImdbId);
|
||||
parameters.Add("imdbId", searchCriteria.ImdbId);
|
||||
}
|
||||
|
||||
if (searchCriteria.TmdbId > 0)
|
||||
{
|
||||
parameters.Add("tmdb", searchCriteria.TmdbId.ToString());
|
||||
parameters.Add("tmdbId", searchCriteria.TmdbId.ToString());
|
||||
}
|
||||
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
@@ -58,11 +60,13 @@ namespace NzbDrone.Core.Indexers.Definitions.UNIT3D
|
||||
if (searchCriteria.ImdbId != null)
|
||||
{
|
||||
parameters.Add("imdb", searchCriteria.ImdbId);
|
||||
parameters.Add("imdbId", searchCriteria.ImdbId);
|
||||
}
|
||||
|
||||
if (searchCriteria.TvdbId > 0)
|
||||
{
|
||||
parameters.Add("tmdb", searchCriteria.TvdbId.ToString());
|
||||
parameters.Add("tvdb", searchCriteria.TvdbId.ToString());
|
||||
parameters.Add("tvdbId", searchCriteria.TvdbId.ToString());
|
||||
}
|
||||
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
.SetHeader("X-Requested-With", "XMLHttpRequest")
|
||||
.Build();
|
||||
|
||||
response = await ExecuteAuth(authLoginRequest);
|
||||
response = await ExecuteAuth(authLoginRequest2);
|
||||
message = JObject.Parse(response.Content)["msg"]?.ToString();
|
||||
}
|
||||
|
||||
@@ -131,7 +131,9 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
};
|
||||
|
||||
requestBuilder4.SetCookies(response.GetCookies());
|
||||
response = await _httpClient.ExecuteAsync(new HttpRequest(Login4Url));
|
||||
var authLoginRequest3 = requestBuilder4.Build();
|
||||
|
||||
response = await _httpClient.ExecuteAsync(authLoginRequest3);
|
||||
|
||||
UpdateCookies(response.GetCookies(), DateTime.Now + TimeSpan.FromDays(30));
|
||||
}
|
||||
@@ -417,10 +419,10 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Username", Advanced = true, HelpText = "Site username")]
|
||||
[FieldDefinition(1, Label = "Username", HelpText = "Site Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Password", Advanced = true, HelpText = "Site Password")]
|
||||
[FieldDefinition(1, Label = "Password", HelpText = "Site Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
@@ -176,12 +176,16 @@ namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
var pagedReleases = new List<ReleaseInfo>();
|
||||
|
||||
var pageSize = PageSize;
|
||||
|
||||
foreach (var request in pageableRequest)
|
||||
{
|
||||
url = request.Url.FullUri;
|
||||
|
||||
var page = await FetchPage(request, parser);
|
||||
|
||||
pageSize = pageSize == 1 ? page.Releases.Count : pageSize;
|
||||
|
||||
result.Queries.Add(page);
|
||||
|
||||
pagedReleases.AddRange(page.Releases);
|
||||
@@ -213,7 +217,7 @@ namespace NzbDrone.Core.Indexers
|
||||
break;
|
||||
}
|
||||
|
||||
if (!IsFullPage(page.Releases))
|
||||
if (!IsFullPage(page.Releases, pageSize))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -336,9 +340,9 @@ namespace NzbDrone.Core.Indexers
|
||||
return Capabilities ?? ((IndexerDefinition)Definition).Capabilities;
|
||||
}
|
||||
|
||||
protected virtual bool IsFullPage(IList<ReleaseInfo> page)
|
||||
protected virtual bool IsFullPage(IList<ReleaseInfo> page, int pageSize)
|
||||
{
|
||||
return PageSize != 0 && page.Count >= PageSize;
|
||||
return pageSize != 0 && page.Count >= pageSize;
|
||||
}
|
||||
|
||||
protected virtual async Task<IndexerQueryResult> FetchPage(IndexerRequest request, IParseIndexerResponse parser)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
@@ -28,6 +29,8 @@ namespace NzbDrone.Core.Indexers
|
||||
|
||||
Task<byte[]> Download(Uri link);
|
||||
|
||||
IDictionary<string, string> GrabCookies();
|
||||
|
||||
IndexerCapabilities GetCapabilities();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,12 @@ namespace NzbDrone.Core.Indexers
|
||||
c.Indexer = Definition.Name;
|
||||
c.DownloadProtocol = Protocol;
|
||||
c.IndexerPriority = ((IndexerDefinition)Definition).Priority;
|
||||
|
||||
//Add common flags
|
||||
if (Protocol == DownloadProtocol.Torrent && ((TorrentInfo)c).DownloadVolumeFactor == 0)
|
||||
{
|
||||
c.IndexerFlags.Add(IndexerFlag.FreeLeech);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
@@ -119,5 +125,10 @@ namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
return Definition.Name;
|
||||
}
|
||||
|
||||
public virtual IDictionary<string, string> GrabCookies()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +267,13 @@ namespace NzbDrone.Core.Indexers
|
||||
MapCardigannDefinition(definition);
|
||||
}
|
||||
|
||||
return base.Create(definition);
|
||||
var newDef = base.Create(definition);
|
||||
|
||||
provider.Definition = newDef;
|
||||
|
||||
_indexerStatusService.UpdateCookies(newDef.Id, provider.GrabCookies(), DateTime.Now + TimeSpan.FromDays(30));
|
||||
|
||||
return newDef;
|
||||
}
|
||||
|
||||
public override void Update(IndexerDefinition definition)
|
||||
@@ -276,7 +282,7 @@ namespace NzbDrone.Core.Indexers
|
||||
|
||||
SetProviderCharacteristics(provider, definition);
|
||||
|
||||
if (definition.Implementation == typeof(Newznab.Newznab).Name || definition.Implementation == typeof(Torznab.Torznab).Name)
|
||||
if (definition.Enable && (definition.Implementation == typeof(Newznab.Newznab).Name || definition.Implementation == typeof(Torznab.Torznab).Name))
|
||||
{
|
||||
var settings = (NewznabSettings)definition.Settings;
|
||||
settings.Categories = _newznabCapabilitiesProvider.GetCapabilities(settings)?.Categories.GetTorznabCategoryList() ?? null;
|
||||
|
||||
@@ -905,5 +905,6 @@
|
||||
"FeatureRequests": "Funktionsanfragen",
|
||||
"AppProfileSelectHelpText": "App-Profile werden verwendet, um die Einstellungen für RSS, automatische Suche und interaktive Suche bei der Anwendungssynchronisierung zu steuern",
|
||||
"Discord": "Discord",
|
||||
"PrioritySettings": "Priorität"
|
||||
"PrioritySettings": "Priorität",
|
||||
"NotificationTriggersHelpText": "Auslöser für diese Benachrichtigung auswählen"
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
"Grabbed": "Attrapé",
|
||||
"Genres": "Genres",
|
||||
"Forecast": "Prévision",
|
||||
"DownloadClientsSettingsSummary": "Clients de Téléchargement, la gestion des téléchargements et les mappages de chemins d'accès à distance",
|
||||
"DownloadClientsSettingsSummary": "Clients de Téléchargement configuration pour l'intégration dans la recherche de l'interface utilisateur Prowlarr",
|
||||
"DownloadClientCheckUnableToCommunicateMessage": "Impossible de communiquer avec {0}.",
|
||||
"DownloadClient": "Client de Téléchargement",
|
||||
"DotNetVersionCheckOldUnsupportedMessage": "Le .Net Framework {0} actuellement installé est ancien et n'est pas pris en charge. Veuillez mettre à niveau .Net Framework à au moins {1}.",
|
||||
@@ -566,9 +566,9 @@
|
||||
"Mode": "Mode",
|
||||
"MissingNotMonitored": "Manquant, non surveillé",
|
||||
"MissingMonitoredAndConsideredAvailable": "Manquant, surveillé et considéré comme disponible",
|
||||
"MinutesSixty": "60 Minutes: {0}",
|
||||
"MinutesNinety": "90 Minutes: {0}",
|
||||
"MinutesHundredTwenty": "120 Minutes: {0}",
|
||||
"MinutesSixty": "60 Minutes : {0}",
|
||||
"MinutesNinety": "90 Minutes : {0}",
|
||||
"MinutesHundredTwenty": "120 Minutes : {0}",
|
||||
"MinimumLimits": "Limites minimales",
|
||||
"MinimumFreeSpace": "Espace libre minimum",
|
||||
"MinimumAge": "Âge minimum",
|
||||
@@ -813,10 +813,10 @@
|
||||
"MustContain": "Doit contenir",
|
||||
"MovieYear": "Année du film",
|
||||
"MovieTitleHelpText": "Le titre du film à exclure (peut être quelque chose de significatif)",
|
||||
"MovieIndexScrollTop": "Index des films: faire défiler vers le haut",
|
||||
"MovieIndexScrollBottom": "Index des films: faire défiler vers le bas",
|
||||
"MovieDetailsPreviousMovie": "Détails du film: Film précédent",
|
||||
"MovieDetailsNextMovie": "Détails du film: prochain film",
|
||||
"MovieIndexScrollTop": "Index des films : faire défiler vers le haut",
|
||||
"MovieIndexScrollBottom": "Index des Films : faire défiler vers le bas",
|
||||
"MovieDetailsPreviousMovie": "Détails du film : Film Précédent",
|
||||
"MovieDetailsNextMovie": "Détails du film : Prochain Film",
|
||||
"MoviesSelectedInterp": "{0} Film(s) Sélectionner",
|
||||
"MovieIsUnmonitored": "Le film n'est pas surveillé",
|
||||
"MovieIsOnImportExclusionList": "Film sur la liste d'exclusion d'importation",
|
||||
@@ -926,5 +926,12 @@
|
||||
"Torrent": "Torrent",
|
||||
"UnableToAddANewApplicationPleaseTryAgain": "Impossible d'ajouter une nouvelle application, veuillez réessayer.",
|
||||
"UnableToAddANewAppProfilePleaseTryAgain": "Impossible d'ajouter un nouveau profil d'application, veuillez réessayer.",
|
||||
"UnableToLoadAppProfiles": "Impossible de charger les profils d'application"
|
||||
"UnableToLoadAppProfiles": "Impossible de charger les profils d'application",
|
||||
"Add": "Ajouter",
|
||||
"SyncLevelFull": "Synchronisation complète : gardera cette application entièrement synchronisée. Les modifications apportées dans Prowlarr sont ensuite synchronisées avec cette application. Toute modification effectuée à distance sera annulée par Prowlarr lors de la prochaine synchronisation.",
|
||||
"SyncLevelAddRemove": "Ajouter et supprimer uniquement : lorsqu'il est ajouté ou supprimé de Prowlarr, il mettra à jour cette application distante.",
|
||||
"SyncLevel": "Niveau de synchronisation",
|
||||
"FullSync": "Synchronisation complète",
|
||||
"AddRemoveOnly": "Ajouter et supprimer uniquement",
|
||||
"AddDownloadClientToProwlarr": "L'ajout d'un client de téléchargement permet à Prowlarr d'envoyer des fichers directement depuis l'interface utilisateur tout en effectuant une recherche manuelle."
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"DownloadClientUnavailable": "Letöltőkliens nem elérhető",
|
||||
"DownloadClientStatusCheckSingleClientMessage": "Letöltőkliens hiba miatt nem elérhető: {0}",
|
||||
"DownloadClientStatusCheckAllClientMessage": "Az összes letöltőkliens elérhetetlen, hiba miatt",
|
||||
"DownloadClientsSettingsSummary": "Letöltőkliensek, letöltések kezelése, és távoli elérési útvonalak",
|
||||
"DownloadClientsSettingsSummary": "Letöltőkliens konfigurációja a Prowlarr felhasználói felület keresésbe történő integráláshoz",
|
||||
"DownloadClientSettings": "Letöltőkliens Beállítások",
|
||||
"DownloadClients": "Letöltőkliensek",
|
||||
"DownloadClientCheckUnableToCommunicateMessage": "Nem lehet kommunikálni a következővel: {0}.",
|
||||
@@ -919,5 +919,12 @@
|
||||
"Stats": "Statisztikák",
|
||||
"Torrent": "Torrent",
|
||||
"UnableToLoadAppProfiles": "Nem sikerült betölteni az alkalmazásprofilokat",
|
||||
"PrioritySettings": "Prioritás"
|
||||
"PrioritySettings": "Prioritás",
|
||||
"SyncLevelFull": "Teljes szinkron: Teljesen szinkronban tartja ezt az alkalmazást. A Prowlarr-ban végrehajtott módosításokat ezután szinkronizálja ezzel az alkalmazással. A távolról végrehajtott módosításokat a Prowlarr felülírja a következő szinkronizáláskor.",
|
||||
"SyncLevelAddRemove": "Csak hozzáadás és eltávolítás: Amikor hozzáadja vagy eltávolítja a Prowlarr-ból, frissíti ezt a távoli alkalmazást.",
|
||||
"SyncLevel": "Szinkronizálás Szintje",
|
||||
"FullSync": "Teljes Szinkron",
|
||||
"AddRemoveOnly": "Csak hozzáadás és eltávolítás",
|
||||
"AddDownloadClientToProwlarr": "Letöltőkliens hozzáadásával a Prowlarr kézi keresés közben közvetlenül a felhasználói felületről küldhet kiadásokat.",
|
||||
"Add": "Hozzáadás"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"Peers": "Peers",
|
||||
"Peers": "Elementos",
|
||||
"AppDataLocationHealthCheckMessage": "Não será possível atualizar para evitar a exclusão de AppData",
|
||||
"Year": "Ano",
|
||||
"Week": "Semana",
|
||||
@@ -9,32 +9,32 @@
|
||||
"VideoCodec": "Codec de Video",
|
||||
"UpdateSelected": "Atualização Selecionada",
|
||||
"Updates": "Atualizações",
|
||||
"UpdateCheckUINotWritableMessage": "Não foi possível instalar a atualização porque a pasta de IU \"{0}\" não tem permissões de escrita para o utilizador \"{1}\".",
|
||||
"UpdateCheckStartupNotWritableMessage": "Não foi possível instalar a atualização porque a pasta de inicialização \"{0}\" não tem permissões de escrita para o utilizador \"{1}\".",
|
||||
"UpdateCheckStartupTranslocationMessage": "Não foi possível instalar a atualização porque a pasta de inicialização '{0}' está em uma pasta de \"App Translocation\".",
|
||||
"UpdateCheckUINotWritableMessage": "Não é possível instalar a atualização porque a pasta de IU \"{0}\" não tem permissões de escrita para o utilizador \"{1}\".",
|
||||
"UpdateCheckStartupNotWritableMessage": "Não é possível instalar a atualização porque a pasta de arranque \"{0}\" não tem permissões de escrita para o utilizador \"{1}\".",
|
||||
"UpdateCheckStartupTranslocationMessage": "Não é possível instalar a atualização porque a pasta de arranque \"{0}\" está em uma pasta de transposição de aplicações.",
|
||||
"UpdateAll": "Atualizar Tudo",
|
||||
"UnselectAll": "Desselecionar tudo",
|
||||
"UnsavedChanges": "Mudanças Não Salvas",
|
||||
"UnselectAll": "Desmarcar tudo",
|
||||
"UnsavedChanges": "Mudanças não salvas",
|
||||
"UnmappedFolders": "Pastas Não Mapeadas",
|
||||
"Unmonitored": "Não Monitorado",
|
||||
"Unavailable": "Indisponível",
|
||||
"UISettingsSummary": "Calendário, data e opções de modo daltônico",
|
||||
"UISettingsSummary": "Opções do calendário, da data e do modo de daltonismo",
|
||||
"UI": "IU",
|
||||
"Type": "Tipo",
|
||||
"TotalSpace": "Espaço Total",
|
||||
"Titles": "Títulos",
|
||||
"Title": "Título",
|
||||
"Timeleft": "Tempo Restante",
|
||||
"Time": "Data",
|
||||
"TestAll": "Testar tudo",
|
||||
"Test": "Teste",
|
||||
"Time": "Hora",
|
||||
"TestAll": "Testar todos",
|
||||
"Test": "Testar",
|
||||
"Tasks": "Tarefas",
|
||||
"TagsSettingsSummary": "Ver todas as etiquetas e como são usadas. Etiquetas não usadas podem ser removidas",
|
||||
"Tags": "Etiquetas",
|
||||
"TableOptionsColumnsMessage": "Escolher quais colunas são visíveis e qual ordem elas aparecem",
|
||||
"TableOptions": "Opções de Tabela",
|
||||
"TableOptionsColumnsMessage": "Escolha quais colunas são visíveis e em qual ordem aparecem",
|
||||
"TableOptions": "Opções da tabela",
|
||||
"Table": "Tabela",
|
||||
"SystemTimeCheckMessage": "O horário do sistema esta mais de 1 dia atrasado. As tarefas agendadas podem não ocorrer corretamente até a hora ser corrigida",
|
||||
"SystemTimeCheckMessage": "A hora do sistema está atrasada em mais de 1 dia. As tarefas agendadas podem não ocorrer corretamente até a hora ser corrigida",
|
||||
"System": "Sistema",
|
||||
"Style": "Estilo",
|
||||
"Studio": "Estúdio",
|
||||
@@ -54,29 +54,29 @@
|
||||
"ShowPath": "Mostrar Caminho",
|
||||
"ShowMonitored": "Mostrar Monitorado",
|
||||
"ShowDateAdded": "Mostrar Data Adicionado",
|
||||
"ShowAdvanced": "Mostrar Avançado",
|
||||
"ShowAdvanced": "Mostrar avançado",
|
||||
"SettingsWeekColumnHeaderHelpText": "Mostrar acima de cada coluna quando a semana é a visualização ativa",
|
||||
"SettingsWeekColumnHeader": "Cabeçalho de Coluna Semanal",
|
||||
"SettingsUiLanguageHelpText": "Idioma que o Prowlarr usará para a UI",
|
||||
"SettingsUiLanguage": "Idioma da UI",
|
||||
"SettingsTimeFormat": "Formato de Hora",
|
||||
"SettingsTimeFormat": "Formato de hora",
|
||||
"SettingsShowRelativeDatesHelpText": "Mostrar datas relativas (Hoje/Ontem/etc.) ou absolutas",
|
||||
"SettingsShowRelativeDates": "Mostra Datas Relativas",
|
||||
"SettingsShortDateFormat": "Formato Curto de Data",
|
||||
"SettingsShowRelativeDates": "Mostrar datas relativas",
|
||||
"SettingsShortDateFormat": "Formato curto da data",
|
||||
"SettingsRemotePathMappingRemotePathHelpText": "Caminho raiz para o diretório que o Cliente de Download acessa",
|
||||
"SettingsRemotePathMappingRemotePath": "Caminho Remoto",
|
||||
"SettingsRemotePathMappingLocalPathHelpText": "Caminho que o Prowlarr deve usar para acessar localmente o caminho remoto",
|
||||
"SettingsRemotePathMappingLocalPath": "Caminho Local",
|
||||
"SettingsRemotePathMappingHostHelpText": "O mesmo host que você especificou para o Cliente de Download remoto",
|
||||
"SettingsLongDateFormat": "Formato Longo de Data",
|
||||
"SettingsLongDateFormat": "Formato longo da data",
|
||||
"SettingsFirstDayOfWeek": "Primeiro Dia da Semana",
|
||||
"SettingsEnableColorImpairedMode": "Ativar Modo Daltônico",
|
||||
"SettingsEnableColorImpairedMode": "Ativar modo de daltonismo",
|
||||
"SettingsEnableColorImpairedModeHelpText": "Estilo alterado para permitir utilizadores daltônicos a distinguir melhor informações coloridas",
|
||||
"Settings": "Definições",
|
||||
"SetTags": "Definir etiquetas",
|
||||
"SelectFolder": "Selecionar Pasta",
|
||||
"SelectAll": "Selecionar Todos",
|
||||
"Seeders": "Seeders",
|
||||
"SelectAll": "Selecionar todos",
|
||||
"Seeders": "Semeadores",
|
||||
"Security": "Segurança",
|
||||
"SearchSelected": "Buscar Selecionado",
|
||||
"SearchOnAdd": "Buscar ao Adicionar",
|
||||
@@ -86,7 +86,7 @@
|
||||
"SearchAll": "Buscar Todos",
|
||||
"Search": "Pesquisar",
|
||||
"Scheduled": "Agendado",
|
||||
"SaveChanges": "Salvar Mudanças",
|
||||
"SaveChanges": "Salvar mudanças",
|
||||
"Save": "Salvar",
|
||||
"Runtime": "Tempo de Execução",
|
||||
"RSSSync": "Sincronia RSS",
|
||||
@@ -106,9 +106,9 @@
|
||||
"RemotePathMappings": "Mapeamento de Caminho Remoto",
|
||||
"Reload": "Recarregar",
|
||||
"ReleaseTitle": "Título da Versão",
|
||||
"ReleaseStatus": "Status da Versão",
|
||||
"ReleaseStatus": "Estado da versão",
|
||||
"ReleaseGroup": "Grupo da Versão",
|
||||
"ReleaseBranchCheckPreviousVersionMessage": "A ramificação {0} é para versões anteriores do Prowlarr, utilize a ramificação 'Nightly' para futuras atualizações",
|
||||
"ReleaseBranchCheckPreviousVersionMessage": "A ramificação {0} é para versões anteriores do Prowlarr, utilize a ramificação \"Nightly\" para futuras atualizações",
|
||||
"ReleaseBranchCheckOfficialBranchMessage": "A ramificação {0} não é uma ramificação de versões válida do Prowlarr, você não receberá atualizações",
|
||||
"RelativePath": "Caminho Relativo",
|
||||
"RejectionCount": "Contagem de Rejeição",
|
||||
@@ -123,10 +123,10 @@
|
||||
"QualityProfile": "Perfil de Qualidade",
|
||||
"QualityDefinitions": "Definições de qualidade",
|
||||
"Quality": "Qualidade",
|
||||
"PtpOldSettingsCheckMessage": "Os seguintes indexadores PassThePopcorn tem configurações obsoletas e precisam ser atualizados: {0}",
|
||||
"ProxyCheckResolveIpMessage": "Não foi possível Resolver o Endereço IP do Host Proxy Configurado {0}",
|
||||
"PtpOldSettingsCheckMessage": "As definições dos seguintes indexadores do PassThePopcorn são obsoletas e precisam ser atualizadas: {0}",
|
||||
"ProxyCheckResolveIpMessage": "Não é possível resolver o Endereço IP para o Anfitrião de proxy {0} definido",
|
||||
"ProxyCheckFailedToTestMessage": "Falha ao testar proxy: {0}",
|
||||
"ProxyCheckBadRequestMessage": "Falha ao testar proxy. StatusCode: {0}",
|
||||
"ProxyCheckBadRequestMessage": "Falha ao testar proxy. Código de estado: {0}",
|
||||
"Proxy": "Proxy",
|
||||
"Protocol": "Protocolo",
|
||||
"Progress": "Progresso",
|
||||
@@ -138,10 +138,10 @@
|
||||
"PosterOptions": "Opções de Poster",
|
||||
"PhysicalRelease": "Versão Física",
|
||||
"PendingChangesStayReview": "Ficar e rever mudanças",
|
||||
"PendingChangesMessage": "Você tem mudanças não salvas, tem certeza que deseja sair da pagina?",
|
||||
"PendingChangesMessage": "Há mudanças não salvas, tem a certeza que deseja sair da página?",
|
||||
"PendingChangesDiscardChanges": "Descartar mudanças e sair",
|
||||
"Path": "Caminho",
|
||||
"PageSize": "Tamanho de página",
|
||||
"PageSize": "Tamanho da página",
|
||||
"OverviewOptions": "Opções de Resumo",
|
||||
"Overview": "Resumo",
|
||||
"OutputPath": "Caminho de Saida",
|
||||
@@ -153,9 +153,9 @@
|
||||
"Organize": "Organizar",
|
||||
"Options": "Opções",
|
||||
"Ok": "Ok",
|
||||
"OAuthPopupMessage": "Pop-ups estão sendo bloqueados por seu navegador",
|
||||
"NoChanges": "Sem Mudanças",
|
||||
"NoChange": "Sem Mudança",
|
||||
"OAuthPopupMessage": "Pop-ups estão sendo bloqueados por seu browser",
|
||||
"NoChanges": "Sem mudanças",
|
||||
"NoChange": "Sem mudança",
|
||||
"NetImportStatusCheckSingleClientMessage": "Listas indisponíveis devido a falhas: {0}",
|
||||
"NetImportStatusCheckAllClientMessage": "Todas listas estão indisponíveis devido a falhas",
|
||||
"Name": "Nome",
|
||||
@@ -169,11 +169,11 @@
|
||||
"MountCheckMessage": "O ponto de montagem que leva a um filme esta montado como apenas leitura: ",
|
||||
"MoreInfo": "Mais informações",
|
||||
"Month": "Mes",
|
||||
"MonoVersionCheckUpgradeRecommendedMessage": "O Mono versão {0} instalado atualmente é suportado, mas atualizar para {1} é recomendado.",
|
||||
"MonoVersionCheckUpgradeRecommendedMessage": "A versão {0} do Mono instalada atualmente é suportada, mas recomenda-se atualizar para {1}.",
|
||||
"MonoVersionCheckOldNotSupportedMessage": "O Mono versão {0} instalado atualmente é velho e obsoleto. Por favor atualize para o Mono versão {1}.",
|
||||
"MonoVersionCheckNotSupportedMessage": "Instalado atualmente o Mono versão {0} o qual não é mais suportado. Por favor atualize para o Mono versão {1}.",
|
||||
"MonoTlsCheckMessage": "Uma gambiarra para o Prowlarr Mono 4.x tls ainda esta ativa, considere remover a opção MONO_TLS_PROVIDER=legacy",
|
||||
"MonoNotNetCoreCheckMessage": "Por favor, atualize para versão a versão .NET Core do Prowlarr",
|
||||
"MonoTlsCheckMessage": "Uma solução para o Prowlarr Mono 4.x tls ainda está ativa, considere remover a opção de ambiente MONO_TLS_PROVIDER=legacy",
|
||||
"MonoNotNetCoreCheckMessage": "Atualiza para a versão .NET Core do Prowlarr",
|
||||
"MonitorMovie": "Monitorar Filme",
|
||||
"MonitoredOnly": "Apenas Monitorado",
|
||||
"Monitored": "Monitorado",
|
||||
@@ -197,12 +197,12 @@
|
||||
"Lists": "Listas",
|
||||
"ListExclusions": "Lista de Exclusões",
|
||||
"Level": "Nível",
|
||||
"LastWriteTime": "Horário da Ultima Escrita",
|
||||
"LastWriteTime": "Hora da última escrita",
|
||||
"Language": "Idioma",
|
||||
"Languages": "Idiomas",
|
||||
"KeyboardShortcuts": "Atalhos de Teclado",
|
||||
"KeyboardShortcuts": "Atalhos do teclado",
|
||||
"InteractiveImport": "Importação Interativa",
|
||||
"Info": "Info",
|
||||
"Info": "Informações",
|
||||
"IndexerStatusCheckSingleClientMessage": "Indexadores indisponíveis devido a falhas: {0}",
|
||||
"IndexerStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a falhas",
|
||||
"IndexersSettingsSummary": "Indexadores e restrições de versões",
|
||||
@@ -226,12 +226,12 @@
|
||||
"iCalLink": "Vincular iCal",
|
||||
"Host": "Anfitrião",
|
||||
"History": "Histórico",
|
||||
"HideAdvanced": "Ocultar Avançado",
|
||||
"HealthNoIssues": "Sem problemas com sua configuração",
|
||||
"Health": "Status",
|
||||
"HideAdvanced": "Ocultar avançado",
|
||||
"HealthNoIssues": "Não há problemas com suas definições",
|
||||
"Health": "Estado de funcionamento",
|
||||
"HardlinkCopyFiles": "Hardlink/Copiar Arquivos",
|
||||
"GrabSelected": "Capturar Selecionado",
|
||||
"Grabbed": "Pegado",
|
||||
"Grabbed": "Capturado",
|
||||
"Genres": "Gêneros",
|
||||
"GeneralSettingsSummary": "Porta, SSL, utilizador/palavra-passe, proxy, análises e atualizações",
|
||||
"General": "Geral",
|
||||
@@ -239,7 +239,7 @@
|
||||
"Formats": "Formatos",
|
||||
"Forecast": "Previsão",
|
||||
"Folder": "Pasta",
|
||||
"Filter": "Filtro",
|
||||
"Filter": "Filtrar",
|
||||
"Filesize": "Tamanho do Arquivo",
|
||||
"Files": "Ficheiros",
|
||||
"Filename": "Nome do ficheiro",
|
||||
@@ -248,25 +248,25 @@
|
||||
"Failed": "Falhado",
|
||||
"Extension": "Extensão",
|
||||
"ExistingMovies": "Filme(s) existente(s)",
|
||||
"EventType": "Tipo de Evento",
|
||||
"EventType": "Tipo de evento",
|
||||
"Events": "Eventos",
|
||||
"Error": "Erro",
|
||||
"EditRemotePathMapping": "Editar Mapeamento de Caminho Remoto",
|
||||
"Edit": "Editar",
|
||||
"Downloaded": "Baixado",
|
||||
"DownloadClientStatusCheckSingleClientMessage": "Gerenciadores de downloads indisponíveis devido a falhas: {0}",
|
||||
"DownloadClientStatusCheckAllClientMessage": "Todos os gerenciadores de downloads estão indisponíveis devido a falhas",
|
||||
"DownloadClientsSettingsSummary": "Gerenciadores de downloads, tratamento de downloads e mapeamento de caminhos remotos",
|
||||
"DownloadClientStatusCheckSingleClientMessage": "Clientes de transferências indisponíveis devido a falhas: {0}",
|
||||
"DownloadClientStatusCheckAllClientMessage": "Todos os clientes de transferências estão indisponíveis devido a falhas",
|
||||
"DownloadClientsSettingsSummary": "Definições do cliente de transferências para integração à pesquisa da IU do Prowlarr",
|
||||
"DownloadClients": "Clientes de transferências",
|
||||
"DownloadClientCheckUnableToCommunicateMessage": "Incapaz de comunicar com {0}.",
|
||||
"DownloadClientCheckNoneAvailableMessage": "Nenhum gerenciador de downloads disponível",
|
||||
"DownloadClientCheckUnableToCommunicateMessage": "Não é possível ligar-se a {0}.",
|
||||
"DownloadClientCheckNoneAvailableMessage": "Nenhum cliente de transferências disponível",
|
||||
"DownloadClient": "Cliente de transferências",
|
||||
"DotNetVersionCheckOldUnsupportedMessage": "O Framework .Net {0} instalado atualmente é velho e não suportado. Por favor atualize para o Framework .Net para ao menos {1}.",
|
||||
"DotNetVersionCheckNotRecommendedMessage": "O Framework .Net {0} instalado atualmente é suportado, mas nós recomendamos atualizar para ao menos {1}.",
|
||||
"DiskSpace": "Espaço em Disco",
|
||||
"Discover": "Descobrir",
|
||||
"DigitalRelease": "Versão Digital",
|
||||
"Details": "Detalhes",
|
||||
"Details": "Pormenores",
|
||||
"DetailedProgressBarHelpText": "Mostrar texto na barra de progresso",
|
||||
"DetailedProgressBar": "Barra de Progresso Detalhada",
|
||||
"Deleted": "Excluído",
|
||||
@@ -279,14 +279,14 @@
|
||||
"CustomFormatsSettingsSummary": "Formatos Customizados e Configurações",
|
||||
"CustomFormatScore": "Pontos do Formato Customizado",
|
||||
"CustomFormats": "Formatos Customizados",
|
||||
"CustomFilters": "Filtros Customizados",
|
||||
"CustomFilters": "Filtros personalizados",
|
||||
"Crew": "Equipe Técnica",
|
||||
"ConnectSettingsSummary": "Notificações, conexões para servidores de midia/players e scripts customizados",
|
||||
"Connections": "Conexões",
|
||||
"ConnectionLostMessage": "O Prowlarr perdeu a conexão com o backend e precisará ser recarregado para restaurar a funcionalidade.",
|
||||
"ConnectionLostAutomaticMessage": "Prowlarr tentará conectar automaticamente, ou você pode clicar recarregar abaixo.",
|
||||
"ConnectionLost": "Conexão Perdida",
|
||||
"Connect": "Conexões",
|
||||
"ConnectSettingsSummary": "Notificações, ligações para servidores/leitores de multimédia e scripts personalizados",
|
||||
"Connections": "Ligações",
|
||||
"ConnectionLostMessage": "O Prowlarr perdeu a ligação com o back-end e precisará ser recarregado para restaurar a funcionalidade.",
|
||||
"ConnectionLostAutomaticMessage": "O Prowlarr tentará ligar automaticamente, ou você pode clicar em Recarregar abaixo.",
|
||||
"ConnectionLost": "Ligação perdida",
|
||||
"Connect": "Ligar",
|
||||
"Component": "Componente",
|
||||
"CompletedDownloadHandling": "Manuseio de Download Completado",
|
||||
"Columns": "Colunas",
|
||||
@@ -330,7 +330,7 @@
|
||||
"AuthenticationMethodHelpText": "Solicitar nome de utilizador e palavra-passe para acessar ao Prowlarr",
|
||||
"Authentication": "Autenticação",
|
||||
"AsAllDayHelpText": "Eventos aparecerão como eventos de dia inteiro em seu calendário",
|
||||
"AreYouSureYouWantToResetYourAPIKey": "Tem a certeza que quer redefinir sua Chave da API?",
|
||||
"AreYouSureYouWantToResetYourAPIKey": "Tem a certeza que quer repor a Chave da API?",
|
||||
"AreYouSureYouWantToDeleteThisRemotePathMapping": "Tem certeza que quer deletar este mapeamento de pasta remota?",
|
||||
"AreYouSureYouWantToDeleteThisImportListExclusion": "Tem certeza que quer deletar esta exclusão de lista de importação?",
|
||||
"AreYouSureYouWantToDeleteThisDelayProfile": "Tem certeza que quer deletar este perfil de espera?",
|
||||
@@ -372,7 +372,7 @@
|
||||
"NoLimitForAnyRuntime": "Sem limite de tempo de execução",
|
||||
"NoLeaveIt": "Não, deixe-o",
|
||||
"New": "Novo",
|
||||
"NetCore": "Core .NET",
|
||||
"NetCore": ".NET",
|
||||
"NamingSettings": "Ajustes de Nomeação",
|
||||
"MustNotContain": "Não Deve Conter",
|
||||
"MustContain": "Deve Conter",
|
||||
@@ -410,7 +410,7 @@
|
||||
"LanguageHelpText": "Idioma das Versões",
|
||||
"Interval": "Intervalo",
|
||||
"IndexerSettings": "Ajustes do Indexador",
|
||||
"IndexerFlags": "Flags do Indexador",
|
||||
"IndexerFlags": "Sinalizadores do indexador",
|
||||
"IncludeUnmonitored": "Incluir Não Monitorados",
|
||||
"IncludeUnknownMovieItemsHelpText": "Mostrar items sem um filme na fila, isso pode incluir filmes removidos, filmes ou qualquer outra coisa na categoria Prowlarr",
|
||||
"IncludeHealthWarningsHelpText": "Incluir avisos de estado de funcionamento",
|
||||
@@ -428,7 +428,7 @@
|
||||
"IconForCutoffUnmet": "Ícone para Ponto de Corte Não-alcançado",
|
||||
"ICalHttpUrlHelpText": "Copie este endereço para sua aplicação ou clique para registrar-se caso seu navegador suporte webcal",
|
||||
"ICalFeed": "Feed iCal",
|
||||
"Hostname": "Nome do servidor",
|
||||
"Hostname": "Nome do anfitrião",
|
||||
"HelpText": "Intervalo em minutos. Coloque zero para desabilitar (isso irá parar toda a captura automática)",
|
||||
"Group": "Grupo",
|
||||
"GrabRelease": "Capturar Versão",
|
||||
@@ -450,14 +450,14 @@
|
||||
"EnableRSS": "Ativar RSS",
|
||||
"EnableMediaInfoHelpText": "Extraia informações de vídeo como resolução, tempo de execução e informações de codec dos ficheiros. Isso requer que o Prowlarr leia partes do ficheiro, o que pode causar alta atividade de disco ou de rede durante as análises.",
|
||||
"EnableInteractiveSearch": "Ativar pesquisa interativa",
|
||||
"EnableHelpText": "Ativar criação de ficheiro de metadados para este tipo de metadados",
|
||||
"EnableHelpText": "Ativar criação do ficheiro de metadados para este tipo de metadados",
|
||||
"EnabledHelpText": "Ativar esta lista para uso no Prowlarr",
|
||||
"EnableCompletedDownloadHandlingHelpText": "Automaticamente importar transferências concluídas do cliente de transferências",
|
||||
"EnableColorImpairedModeHelpText": "Estilo alterado para permitir que utilizadores com daltonismo possam melhor distinguir informações de cores",
|
||||
"EnableColorImpairedMode": "Ativar modo de daltonismo",
|
||||
"EnableAutomaticSearch": "Ativar pesquisa automática",
|
||||
"EnableAutomaticAdd": "Ativar adição automática",
|
||||
"EnableAutoHelpText": "Se ativado, Filmes desta lista serão automaticamente adicionados ao Prowlarr",
|
||||
"EnableAutoHelpText": "Se ativado, os filmes desta lista serão automaticamente adicionados ao Prowlarr",
|
||||
"Enable": "Ativar",
|
||||
"EditPerson": "Editar Pessoa",
|
||||
"EditMovie": "Editar Filme",
|
||||
@@ -469,7 +469,7 @@
|
||||
"Docker": "Docker",
|
||||
"DestinationRelativePath": "Caminho Relativo de Destino",
|
||||
"DestinationPath": "Caminho de Destino",
|
||||
"DeleteTag": "Excluir etiqueta",
|
||||
"DeleteTag": "Eliminar etiqueta",
|
||||
"DeleteSelectedMovieFiles": "Deletar Arquivos de Filme Selecionados",
|
||||
"DeleteRestriction": "Deletar Restrição",
|
||||
"DeleteQualityProfile": "Deletar Perfil de Qualidade",
|
||||
@@ -480,7 +480,7 @@
|
||||
"DeleteFile": "Apagar arquivo",
|
||||
"DeleteEmptyFoldersHelpText": "Deletar pastas de filmes vazias durante a varredura de disco e quando arquivos de filmes são apagados",
|
||||
"DeleteEmptyFolders": "Deletar pastas vazias",
|
||||
"DeleteDownloadClient": "Deletar Gerenciador de Download",
|
||||
"DeleteDownloadClient": "Eliminar cliente de transferências",
|
||||
"DeleteDelayProfile": "Deletar Perfil de Espera",
|
||||
"DeleteCustomFormat": "Deletar Formato Personalizado",
|
||||
"DeleteBackup": "Eliminar cópia de segurança",
|
||||
@@ -494,18 +494,18 @@
|
||||
"CreateEmptyMovieFolders": "Criar pastas vazias para filmes",
|
||||
"CopyUsingHardlinksHelpTextWarning": "Ocasionalmente, bloqueios de arquivos podem impedir a renomeação de arquivos que ainda estão em modo seed. Você pode temporariamente desabilitar o seeding e usar a função de renomeação do Prowlarr como uma solução alternativa.",
|
||||
"CopyUsingHardlinksHelpText": "Usar Hardlinks ao tentar copiar arquivos a partir de torrents que ainda estão em modo seed",
|
||||
"ConnectSettings": "Configurações de conexão",
|
||||
"ConnectSettings": "Definições de ligação",
|
||||
"Conditions": "Condições",
|
||||
"ColonReplacementFormatHelpText": "Mude a forma como o Prowlarr lida com a substituição de dois-pontos",
|
||||
"ColonReplacement": "Substituição de dois-pontos",
|
||||
"CloneProfile": "Clonar Perfil",
|
||||
"CloneIndexer": "Clonar Indexador",
|
||||
"CloneProfile": "Clonar perfil",
|
||||
"CloneIndexer": "Clonar indexador",
|
||||
"CloneFormatTag": "Clonar Tag de Formato",
|
||||
"ClickToChangeQuality": "Clique para mudar a qualidade",
|
||||
"ClickToChangeLanguage": "Clique para mudar o idioma",
|
||||
"CleanLibraryLevel": "Limpar Nível da Biblioteca",
|
||||
"CheckForFinishedDownloadsInterval": "Intervalo de verificação de Downloads Terminados",
|
||||
"ChangeHasNotBeenSavedYet": "Modificação ainda não foi salva",
|
||||
"ChangeHasNotBeenSavedYet": "Mudança ainda não foi salva",
|
||||
"ChangeFileDate": "Modificar Data do Arquivo",
|
||||
"CertificationCountryHelpText": "Selecionar País para Certificação de Filmes",
|
||||
"CertificationCountry": "País de certificação",
|
||||
@@ -519,7 +519,7 @@
|
||||
"BindAddress": "Endereço de vínculo",
|
||||
"Backups": "Cópias de segurança",
|
||||
"BackupFolderHelpText": "Caminhos relativos estarão na pasta AppData do Prowlarr",
|
||||
"BackupIntervalHelpText": "Intervalo entre backups automáticos",
|
||||
"BackupIntervalHelpText": "Intervalo entre cópias de segurança automáticas",
|
||||
"BackupRetentionHelpText": "Cópias de segurança automáticas anteriores ao período de retenção serão eliminadas automaticamente",
|
||||
"Cutoff": "Corte",
|
||||
"CustomFormatJSON": "JSON Personalizado",
|
||||
@@ -528,13 +528,13 @@
|
||||
"ClickToChangeMovie": "Clique para modificar filme",
|
||||
"CheckDownloadClientForDetails": "verifique o gerenciador de downloads para mais detalhes",
|
||||
"CantFindMovie": "Por que não consigo encontrar meu filme?",
|
||||
"CancelPendingTask": "Tem certeza que quer cancelar esta tarefa pendente?",
|
||||
"CancelPendingTask": "Tem a certeza que quer cancelar esta tarefa pendente?",
|
||||
"BranchUpdateMechanism": "Ramificação usada pelo mecanismo externo de atualização",
|
||||
"BranchUpdate": "Ramificação utilizada para atualizar o Prowlarr",
|
||||
"BeforeUpdate": "Antes de atualizar",
|
||||
"AvailabilityDelayHelpText": "Quantidade de tempo antes ou depois da data de disponibilidade para buscar por Filme",
|
||||
"ApplyTagsHelpTexts4": "Substituir: mudar as etiquetas pelas adicionadas (deixe em branco para limpar todas as etiquetas)",
|
||||
"ApplyTagsHelpTexts3": "Remover: excluir as etiquetas adicionadas",
|
||||
"ApplyTagsHelpTexts3": "Remover: eliminar as etiquetas adicionadas",
|
||||
"ApplyTagsHelpTexts2": "Adicionar: agregar as etiquetas à lista existente de etiquetas",
|
||||
"ApplyTagsHelpTexts1": "Como adicionar etiquetas aos filmes selecionados",
|
||||
"AllowMovieChangeClickToChangeMovie": "Clique para trocar o filme",
|
||||
@@ -553,18 +553,18 @@
|
||||
"CustomFormatUnknownCondition": "Condição de Formato Personalizado '{0}' desconhecida",
|
||||
"CloneCustomFormat": "Clonar Formato Personalizado",
|
||||
"AutomaticSearch": "Pesquisa automática",
|
||||
"UnableToLoadIndexers": "Não foi possível carregar os Indexadores",
|
||||
"UnableToLoadIndexers": "Não é possível carregar os indexadores",
|
||||
"UnableToLoadIndexerOptions": "Não é possível carregar as opções do indexador",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Não foi possível adicionar um novo indexador, tente novamente.",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Não é possível adicionar um novo indexador, tenta novamente.",
|
||||
"TestAllIndexers": "Testar Todos os Indexadores",
|
||||
"RSSSyncIntervalHelpTextWarning": "Isto se aplicará a todos os indexadores, siga as regras estabelecidas por eles",
|
||||
"RSSIsNotSupportedWithThisIndexer": "RSS não é suportado por esse indexador",
|
||||
"ProwlarrSupportsAnyIndexer": "O Prowlarr suporta qualquer indexador que use o padrão Newznab, bem como outros indexadores listados abaixo.",
|
||||
"IndexerPriorityHelpText": "Prioridade do Indexador de 1 (mais alta) a 50 (mais baixa). Padrão: 25.",
|
||||
"ProwlarrSupportsAnyIndexer": "O Prowlarr suporta qualquer indexador que use o padrão Newznab, bem como os outros indexadores listados abaixo.",
|
||||
"IndexerPriorityHelpText": "Prioridade do indexador de 1 (mais alta) a 50 (mais baixa). Padrão: 25.",
|
||||
"IndexerPriority": "Prioridade do indexador",
|
||||
"ForMoreInformationOnTheIndividualIndexers": "Para mais informações sobre cada indexador, clique nos botões de informação.",
|
||||
"EnableInteractiveSearchHelpTextWarning": "Este indexador não suporta busca",
|
||||
"EditIndexer": "Modificar Indexador",
|
||||
"EnableInteractiveSearchHelpTextWarning": "Este indexador não suporta pesquisas",
|
||||
"EditIndexer": "Editar indexador",
|
||||
"DeleteIndexerMessageText": "Tem a certeza que quer eliminar o indexador \"{0}\"?",
|
||||
"AddIndexer": "Adicionar indexador",
|
||||
"UsenetDelayHelpText": "Tempo de espera, em minutos, para aguardar antes de capturar uma versão de Usenet",
|
||||
@@ -576,7 +576,7 @@
|
||||
"Retention": "Retenção",
|
||||
"Result": "Resultado",
|
||||
"Restore": "Restaurar",
|
||||
"RestartProwlarr": "Reiniciar Prowlarr",
|
||||
"RestartProwlarr": "Reiniciar o Prowlarr",
|
||||
"RestartNow": "Reiniciar agora",
|
||||
"ResetAPIKey": "Repor chave da API",
|
||||
"Reset": "Repor",
|
||||
@@ -584,11 +584,11 @@
|
||||
"ReplaceIllegalCharacters": "Substituir Caracteres Ilegais",
|
||||
"Reorder": "Reordenar",
|
||||
"RenameMovies": "Renomear Filmes",
|
||||
"RemovingTag": "Removendo etiqueta",
|
||||
"RemovingTag": "Eliminando etiqueta",
|
||||
"RemoveFromQueue": "Remover da fila",
|
||||
"RemoveFromDownloadClient": "Remover do Gerenciador de Downloads",
|
||||
"RemoveFromBlacklist": "Remover da blacklist",
|
||||
"RemoveFilter": "Remover filtro",
|
||||
"RemoveFilter": "Eliminar filtro",
|
||||
"Remove": "Remover",
|
||||
"RefreshMovie": "Atualizar filme",
|
||||
"RefreshInformationAndScanDisk": "Atualizar informações e varrer o disco",
|
||||
@@ -612,10 +612,10 @@
|
||||
"NoBackupsAreAvailable": "Não há cópias de segurança disponíveis",
|
||||
"MoviesSelectedInterp": "{0} Filme(s) Selecionado(s)",
|
||||
"MovieIsUnmonitored": "O filme não é monitorado",
|
||||
"MinutesSixty": "60 Minutos: {0}",
|
||||
"MinutesNinety": "90 Minutos: {0}",
|
||||
"MinutesHundredTwenty": "120 Minutos: {0}",
|
||||
"MIA": "MIA",
|
||||
"MinutesSixty": "60 minutos: {0}",
|
||||
"MinutesNinety": "90 minutos: {0}",
|
||||
"MinutesHundredTwenty": "120 minutos: {0}",
|
||||
"MIA": "Desaparecidos",
|
||||
"MarkAsFailedMessageText": "Tem certeza de que quer marcar '{0}' como falhado?",
|
||||
"MarkAsFailed": "Marcar como falhado",
|
||||
"Manual": "Manual",
|
||||
@@ -624,7 +624,7 @@
|
||||
"LoadingMovieCreditsFailed": "Falha no carregamento dos créditos do filme",
|
||||
"LinkHere": "aqui",
|
||||
"LastDuration": "Duração",
|
||||
"InteractiveSearch": "Busca Interativa",
|
||||
"InteractiveSearch": "Pesquisa interativa",
|
||||
"IncludeProwlarrRecommendations": "Incluir recomendações do Prowlarr",
|
||||
"ImportListSyncIntervalHelpText": "Frequência com que o Prowlarr sincroniza suas listas.",
|
||||
"ImportListStatusCheckSingleClientMessage": "Listas indisponíveis devido a erros: {0}",
|
||||
@@ -637,8 +637,8 @@
|
||||
"GrabReleaseMessageText": "O Prowlarr não foi capaz de determinar a que filme pertence esta versão. O Prowlarr pode ser incapaz de automaticamente importar esta versão. Deseja capturar '{0}'?",
|
||||
"GoToInterp": "Ir para {0}",
|
||||
"ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Para mais informações sobre cada lista de importação, clique nos botões de informação.",
|
||||
"ForMoreInformationOnTheIndividualDownloadClients": "Para mais informações sobre cada gerenciador de download, clique nos botões de informação.",
|
||||
"FilterPlaceHolder": "Buscar filmes",
|
||||
"ForMoreInformationOnTheIndividualDownloadClients": "Para obter mais informações sobre cada cliente de transferências, clique nos botões de informação.",
|
||||
"FilterPlaceHolder": "Indexadores de pesquisa",
|
||||
"FileChmodHelpTexts2": "O mesmo modo é aplicado às pastas e subpastas dos filmes com o bit de executável adicionado. P. ex. 0644 torna-se 0755",
|
||||
"FileChmodHelpTexts1": "Octal, aplicado aos arquivos multimídia ao serem importados/renomeados pelo Prowlarr",
|
||||
"FailedLoadingSearchResults": "Erro ao carregar resultados da busca. Por favor, tente novamente.",
|
||||
@@ -653,28 +653,28 @@
|
||||
"Exception": "Exceção",
|
||||
"ErrorLoadingPreviews": "Erro ao carregar pré-visualizações",
|
||||
"ErrorLoadingContents": "Erro ao carregar conteúdo",
|
||||
"EnableInteractiveSearchHelpText": "Será utilizado ao realizar uma busca interativa",
|
||||
"EnableAutomaticSearchHelpTextWarning": "Será utilizado ao realizar uma busca interativa",
|
||||
"EnableAutomaticSearchHelpText": "Será utilizado ao realizar buscas automáticas através da IU ou pelo Prowlarr",
|
||||
"EnableInteractiveSearchHelpText": "Será utilizado ao realizar uma pesquisa interativa",
|
||||
"EnableAutomaticSearchHelpTextWarning": "Será utilizado ao realizar uma pesquisa interativa",
|
||||
"EnableAutomaticSearchHelpText": "Será utilizado ao realizar pesquisas automáticas através da IU ou pelo Prowlarr",
|
||||
"DownloadWarning": "Alerta de download: {0}",
|
||||
"DownloadPropersAndRepacksHelpTextWarning": "Use palavras preferidas para atualizações automáticas a propers/repacks",
|
||||
"PreferredSize": "Tamanho Preferido",
|
||||
"PreferredSize": "Tamanho preferido",
|
||||
"DownloadPropersAndRepacksHelpText2": "Use 'Não Preferir' para ordenar por score de palavras preferidas em vez de propers/repacks",
|
||||
"DownloadPropersAndRepacksHelpText1": "Atualizar automaticamente ou não para Propers/Repacks",
|
||||
"DownloadPropersAndRepacks": "Propers e Repacks",
|
||||
"Downloading": "Baixando",
|
||||
"Downloading": "Transferindo",
|
||||
"DownloadFailedInterp": "Falha no download: {0}",
|
||||
"DownloadFailed": "Falha no download",
|
||||
"DownloadedButNotMonitored": "Baixado, mas não Monitorado",
|
||||
"DownloadedAndMonitored": "Baixado e Monitorado",
|
||||
"DownloadClientUnavailable": "O gerenciador de downloads não está disponível",
|
||||
"DownloadClientUnavailable": "O cliente de transferências está indisponível",
|
||||
"Disabled": "Desativado",
|
||||
"DeleteTagMessageText": "Tem a certeza que quer eliminar a etiqueta \"{0}\"?",
|
||||
"DeleteSelectedMovieFilesMessage": "Tem certeza que quer apagar os arquivos de filme selecionados?",
|
||||
"DeleteRestrictionHelpText": "Tem certeza que quer deletar esta restrição?",
|
||||
"DeleteNotificationMessageText": "Tem a certeza que quer eliminar a notificação \"{0}\"?",
|
||||
"DeleteListMessageText": "Tem certeza que quer deletar a lista '{0}'?",
|
||||
"DeleteDownloadClientMessageText": "Tem certeza que quer deletar o gerenciador de downloads '{0}'?",
|
||||
"DeleteDownloadClientMessageText": "Tem a certeza que quer eliminar o cliente de transferências \"{0}\"?",
|
||||
"DeleteBackupMessageText": "Tem a certeza que quer eliminar a cópia de segurança \"{0}\"?",
|
||||
"RenameMoviesHelpText": "O Prowlarr usará o nome atual do arquivo se a renomeação estiver desabilitada",
|
||||
"IncludeRecommendationsHelpText": "Incluir filmes recomendados pelo Prowlarr na visão de descobrimento",
|
||||
@@ -682,12 +682,12 @@
|
||||
"WhitelistedSubtitleTags": "Tags de Legendas Permitidas",
|
||||
"WhitelistedHardcodedSubsHelpText": "As tags de legenda aqui definidas não serão consideradas como hardcoded",
|
||||
"WeekColumnHeader": "Cabeçalho da Coluna de Semanas",
|
||||
"UrlBaseHelpText": "Para suporte a proxy reverso, vazio por padrão",
|
||||
"UrlBaseHelpText": "Para suporte a proxy inverso, vazio por padrão",
|
||||
"UpgradeUntilThisQualityIsMetOrExceeded": "Atualizar até que esta qualidade seja atingida ou superada",
|
||||
"UpgradeAllowedHelpText": "Se desabilitado, as qualidades não serão atualizadas",
|
||||
"UpdateScriptPathHelpText": "Caminho para um script personalizado que toma um pacote de atualização extraído e lida com o restante do processo de atualização",
|
||||
"UpdateMechanismHelpText": "Usar o atualizador do Prowlarr ou um script",
|
||||
"UpdateAutomaticallyHelpText": "Baixar e instalar atualizações automaticamente. Ainda é possível instalar a partir de Sistema: Atualizações",
|
||||
"UpdateAutomaticallyHelpText": "Transferir e instalar atualizações automaticamente. Ainda é possível instalar a partir de Sistema: Atualizações",
|
||||
"UnmonitoredHelpText": "Incluir filmes não monitorados no feed iCal",
|
||||
"TMDBId": "ID TMDb",
|
||||
"TimeFormat": "Formato de Hora",
|
||||
@@ -695,13 +695,13 @@
|
||||
"TestAllLists": "Testar Todas as Listas",
|
||||
"TestAllClients": "Testar todos os clientes",
|
||||
"TagsHelpText": "Aplica-se a indexadores com pelo menos uma etiqueta correspondente",
|
||||
"TagIsNotUsedAndCanBeDeleted": "A etiqueta não é utilizada e pode ser excluída",
|
||||
"TagIsNotUsedAndCanBeDeleted": "A etiqueta não é utilizada e pode ser eliminada",
|
||||
"SubfolderWillBeCreatedAutomaticallyInterp": "A subpasta '{0}' será criada automaticamente",
|
||||
"StartTypingOrSelectAPathBelow": "Comece a digitar ou selecione um caminho abaixo",
|
||||
"StandardMovieFormat": "Formato Padrão de Filme",
|
||||
"SSLCertPathHelpText": "Caminho para o arquivo PFX",
|
||||
"SSLCertPathHelpText": "Caminho para o ficheiro PFX",
|
||||
"SSLCertPath": "Caminho do certificado SSL",
|
||||
"SSLCertPasswordHelpText": "Senha do arquivo PFX",
|
||||
"SSLCertPasswordHelpText": "Palavra-passe do ficheiro PFX",
|
||||
"SSLCertPassword": "Palavra-passe do certificado SSL",
|
||||
"SourceRelativePath": "Caminho Relativo de Origem",
|
||||
"SourcePath": "Caminho de Origem",
|
||||
@@ -741,11 +741,11 @@
|
||||
"RecycleBinCleanupDaysHelpText": "Ajuste para 0 para desabilitar a limpeza automática",
|
||||
"ProwlarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "O Radar suporta condições personalizadas em relação às propriedades das versões abaixo.",
|
||||
"ProwlarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "O Prowlarr suporta qualquer lista RSS de filmes, bem como os demais listados abaixo.",
|
||||
"ProwlarrSupportsAnyDownloadClient": "O Prowlarr suporta qualquer gerenciador de download que utilize o padrão Newznab, bem como os demais listados abaixo.",
|
||||
"ProwlarrSupportsAnyDownloadClient": "O Prowlarr suporta qualquer dos clientes de transferências listados abaixo.",
|
||||
"QualityProfileDeleteConfirm": "Tem certeza que quer deletar o perfil de qualidade {0}",
|
||||
"ProxyUsernameHelpText": "Apenas insira o utilizador e a palavra-passe caso seja requerido. Caso contrário, deixe em branco.",
|
||||
"ProxyPasswordHelpText": "Apenas insira o utilizador e a palavra-passe caso seja requerido. Caso contrário, deixe em branco.",
|
||||
"ProxyBypassFilterHelpText": "Use \",\" como separador e \"*.\" como caráter universal para subdomínios",
|
||||
"ProxyBypassFilterHelpText": "Usar \",\" como separador e \"*.\" como caráter universal para subdomínios",
|
||||
"Proper": "Proper",
|
||||
"MovieInfoLanguage": "Idioma das Informações dos Filmes",
|
||||
"MaintenanceRelease": "Versão de manutenção",
|
||||
@@ -753,7 +753,7 @@
|
||||
"UsenetDelay": "Espera para Usenet",
|
||||
"UnableToLoadDelayProfiles": "Não foi possível carregar os Perfis de Espera",
|
||||
"TorrentDelayHelpText": "Espera em minutos para aguardar antes de capturar um torrent",
|
||||
"PriorityHelpText": "Priorizar múltiplos Gerenciadores de Downloads. Será utilizado Round-Robin para gerenciadores com a mesma prioridade.",
|
||||
"PriorityHelpText": "Priorizar múltiplos clientes de transferências. Utilizaremos round robin para clientes com a mesma prioridade.",
|
||||
"RemovedFromTaskQueue": "Eliminar da fila de tarefas",
|
||||
"ReleaseWillBeProcessedInterp": "A versão será processada {0}",
|
||||
"RegularExpressionsCanBeTested": "Expressões regulares podem ser testadas ",
|
||||
@@ -766,35 +766,35 @@
|
||||
"MoreDetails": "Mais detalhes",
|
||||
"MissingNotMonitored": "Ausente, não Monitorado",
|
||||
"MissingMonitoredAndConsideredAvailable": "Ausente, Monitorado e considerado Disponível",
|
||||
"LogLevelTraceHelpTextWarning": "Log em modo trace somente deve ser habilitado temporariamente",
|
||||
"LogLevelTraceHelpTextWarning": "O registo de rasteio somente deve ser ativado temporariamente",
|
||||
"ListSyncLevelHelpText": "Filmes na biblioteca serão removidos ou não mais monitorados se não estiverem em sua lista",
|
||||
"LaunchBrowserHelpText": " Abrir o navegador e abrir a página principal do Prowlarr ao iniciar a aplicação.",
|
||||
"TagCannotBeDeletedWhileInUse": "Não é possível excluir enquanto estiver em uso",
|
||||
"LaunchBrowserHelpText": " Abrir o browser e a página principal do Prowlarr ao iniciar a aplicação.",
|
||||
"TagCannotBeDeletedWhileInUse": "Não é possível eliminar enquanto estiver em uso",
|
||||
"SuggestTranslationChange": "Sugerir mudança na tradução",
|
||||
"StartupDirectory": "Diretório de início",
|
||||
"SSLPort": "Porta SSL",
|
||||
"YesCancel": "Sim, Cancelar",
|
||||
"YesCancel": "Sim, cancelar",
|
||||
"WaitingToProcess": "Aguardando para Processar",
|
||||
"WaitingToImport": "Aguardando para Importar",
|
||||
"Version": "Versão",
|
||||
"Username": "Nome de utilizador",
|
||||
"UseProxy": "Usar Proxy",
|
||||
"UseProxy": "Usar proxy",
|
||||
"Usenet": "Usenet",
|
||||
"UseHardlinksInsteadOfCopy": "Usar Hardlinks em vez de Copiar",
|
||||
"URLBase": "URL Base",
|
||||
"Uptime": "Tempo de Atividade",
|
||||
"URLBase": "URL base",
|
||||
"Uptime": "Tempo de atividade",
|
||||
"Unreleased": "Não Lançado",
|
||||
"Ungroup": "Desagrupar",
|
||||
"UnableToLoadUISettings": "Não foi possível carregar as definições da IU",
|
||||
"UnableToLoadUISettings": "Não é possível carregar as definições da IU",
|
||||
"UnableToLoadTheCalendar": "Não foi possível carregar o calendário",
|
||||
"UnableToLoadTags": "Não foi possível carregar as etiquetas",
|
||||
"UnableToLoadTags": "Não é possível carregar as etiquetas",
|
||||
"UnableToLoadRootFolders": "Não foi possível carregar as pastas raízes",
|
||||
"UnableToLoadRestrictions": "Não foi possível carregar as Restrições",
|
||||
"UnableToLoadRemotePathMappings": "Não foi possível carregar os Mapeamentos de Caminhos Remotos",
|
||||
"UnableToLoadQualityProfiles": "Não foi possível carregar os Perfis de Qualidade",
|
||||
"UnableToLoadQualityDefinitions": "Não foi possível carregar as Definições de Qualidade",
|
||||
"UnableToLoadQualityDefinitions": "Não é possível carregar as definições de qualidade",
|
||||
"UnableToLoadQualities": "Não foi possível carregar as qualidades",
|
||||
"UnableToLoadNotifications": "Não foi possível carregar as Notificações",
|
||||
"UnableToLoadNotifications": "Não é possível carregar as notificações",
|
||||
"UnableToLoadNamingSettings": "Não foi possível carregar os ajustes de Nomenclatura",
|
||||
"UnableToLoadMovies": "Não foi possível carregar os filmes",
|
||||
"UnableToLoadMetadata": "Não foi possível carregar os Metadados",
|
||||
@@ -803,34 +803,34 @@
|
||||
"UnableToLoadListOptions": "Não foi possível carregar as opções de lista",
|
||||
"UnableToLoadListExclusions": "Não foi possível carregar as Exclusões de Lista",
|
||||
"UnableToLoadLanguages": "Não foi possível carregar os idiomas",
|
||||
"UnableToLoadHistory": "Não foi possível carregar o histórico",
|
||||
"UnableToLoadGeneralSettings": "Não foi possível carregar os Ajustes Gerais",
|
||||
"UnableToLoadDownloadClients": "Não foi possível carregar os gerenciadores de download",
|
||||
"UnableToLoadHistory": "Não é possível carregar o histórico",
|
||||
"UnableToLoadGeneralSettings": "Não é possível carregar as definições gerais",
|
||||
"UnableToLoadDownloadClients": "Não é possível carregar os clientes de transferências",
|
||||
"UnableToLoadDownloadClientOptions": "Não foi possível carregar as opções do gerenciador de downloads",
|
||||
"UnableToLoadBlacklist": "Não foi possível carregar a blacklist",
|
||||
"UnableToAddANewConditionPleaseTryAgain": "Não foi possível adicionar uma nova condição, tente novamente.",
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "Não foi possível adicionar um novo gerenciador de downloads, tente novamente.",
|
||||
"UnableToLoadBackups": "Não foi possível carregar os backups",
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "Não é possível adicionar um novo cliente de transferências, tenta novamente.",
|
||||
"UnableToLoadBackups": "Não é possível carregar as cópias de segurança",
|
||||
"UnableToAddANewRemotePathMappingPleaseTryAgain": "Não foi possível adicionar um novo caminho remoto, tente novamente.",
|
||||
"UnableToAddANewQualityProfilePleaseTryAgain": "Não foi possível adicionar um novo perfil de qualidade, tente novamente.",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Não foi possível adicionar uma nova notificação, tente novamente.",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Não é possível adicionar uma nova notificação, tenta novamente.",
|
||||
"UnableToAddANewListExclusionPleaseTryAgain": "Não foi possível adicionar uma nova exclusão de lista, tente novamente.",
|
||||
"UnableToAddANewListPleaseTryAgain": "Não foi possível adicionar uma nova lista, tente novamente.",
|
||||
"UISettings": "Definições da IU",
|
||||
"UILanguageHelpTextWarning": "É necessário reiniciar o navegador",
|
||||
"UILanguageHelpTextWarning": "É preciso reiniciar o browser",
|
||||
"UILanguageHelpText": "Idioma que o Prowlarr usará para a IU",
|
||||
"UILanguage": "Idioma da IU",
|
||||
"TotalFileSize": "Tamanho Total do Arquivo",
|
||||
"Torrents": "Torrents",
|
||||
"FocusSearchBox": "Focar no Campo de Busca",
|
||||
"CloseCurrentModal": "Fechar Pop-up Atual",
|
||||
"FocusSearchBox": "Focar no campo de pesquisa",
|
||||
"CloseCurrentModal": "Fechar pop-up atual",
|
||||
"AcceptConfirmationModal": "Aceitar pop-up de confirmação",
|
||||
"OpenThisModal": "Abrir este Pop-up",
|
||||
"SaveSettings": "Salvar Ajustes",
|
||||
"MovieIndexScrollTop": "Índice de Filmes: Rolar para Cima",
|
||||
"MovieIndexScrollBottom": "Índice de Filmes: Rolar para Baixo",
|
||||
"MovieDetailsPreviousMovie": "Detalhes do Filme: Filme Anterior",
|
||||
"MovieDetailsNextMovie": "Detalhes do Filme: Próximo Filme",
|
||||
"OpenThisModal": "Abrir este pop-up",
|
||||
"SaveSettings": "Salvar definições",
|
||||
"MovieIndexScrollTop": "Índice do filme: deslocar para cima",
|
||||
"MovieIndexScrollBottom": "Índice do filme: deslocar para baixo",
|
||||
"MovieDetailsPreviousMovie": "Pormenores do filme: filme anterior",
|
||||
"MovieDetailsNextMovie": "Pormenores do filme: próximo filme",
|
||||
"Blacklisted": "Na Lista Negra",
|
||||
"StartSearchForMissingMovie": "Iniciar busca por filme",
|
||||
"StartProcessing": "Iniciar Processamento",
|
||||
@@ -865,10 +865,10 @@
|
||||
"EnableIndexer": "Ativar indexador",
|
||||
"EnableRss": "Ativar RSS",
|
||||
"EditAppProfile": "Editar perfil da aplicação",
|
||||
"DevelopmentSettings": "Configurações de desenvolvimento",
|
||||
"DeleteApplicationMessageText": "Tem certeza que deseja excluir a aplicação \"{0}\"?",
|
||||
"DeleteApplication": "Excluir aplicação",
|
||||
"ClearHistoryMessageText": "Tem certeza que deseja limpar todo o histórico do Prowlarr?",
|
||||
"DevelopmentSettings": "Definições de desenvolvimento",
|
||||
"DeleteApplicationMessageText": "Tem a certeza que deseja eliminar a aplicação \"{0}\"?",
|
||||
"DeleteApplication": "Eliminar aplicação",
|
||||
"ClearHistoryMessageText": "Tem a certeza que deseja limpar todo o histórico do Prowlarr?",
|
||||
"ClearHistory": "Limpar histórico",
|
||||
"AppProfiles": "Perfis de aplicações",
|
||||
"ApplicationStatusCheckSingleClientMessage": "Aplicações indisponíveis devido a falhas: {0}",
|
||||
@@ -882,24 +882,24 @@
|
||||
"SettingsFilterSentryEventsHelpText": "Filtrar eventos de erro de utilizador conhecidos para que não sejam enviados para análise",
|
||||
"Yesterday": "Ontem",
|
||||
"Wiki": "Wiki",
|
||||
"UnableToLoadDevelopmentSettings": "Não foi possível carregar as configurações de desenvolvimento",
|
||||
"UnableToLoadDevelopmentSettings": "Não é possível carregar as definições de desenvolvimento",
|
||||
"Tomorrow": "Amanhã",
|
||||
"Today": "Hoje",
|
||||
"TestAllApps": "Testar todos os aplicativos",
|
||||
"SyncAppIndexers": "Sincronizar indexadores do aplicativo",
|
||||
"SettingsSqlLoggingHelpText": "Registrar todas as consultas de SQL do Prowlarr",
|
||||
"SettingsLogSql": "Registrar SQL",
|
||||
"SettingsLogRotateHelpText": "Quantidade máxima de arquivos de log a manter na pasta",
|
||||
"TestAllApps": "Testar todas as aplicações",
|
||||
"SyncAppIndexers": "Sincronizar indexadores da aplicação",
|
||||
"SettingsSqlLoggingHelpText": "Registar todas as consultas de SQL do Prowlarr",
|
||||
"SettingsLogSql": "Registar SQL",
|
||||
"SettingsLogRotateHelpText": "Quantidade máxima de ficheiros de log a manter na pasta",
|
||||
"SettingsLogRotate": "Rotação de logs",
|
||||
"SettingsIndexerLoggingHelpText": "Registrar dados adicionar do indexador, incluindo resposta",
|
||||
"SettingsIndexerLogging": "Registro em log avançado do indexador",
|
||||
"SettingsIndexerLoggingHelpText": "Registar dados adicionais do indexador, incluindo resposta",
|
||||
"SettingsIndexerLogging": "Registo em log avançado do indexador",
|
||||
"SettingsFilterSentryEvents": "Filtrar eventos de análises",
|
||||
"RSS": "RSS",
|
||||
"RedirectHelpText": "Redirecionar as solicitações de download de entrada para o indexador, em vez de por proxy usando o Prowlarr",
|
||||
"RedirectHelpText": "Redirecionar as solicitações de transferência de entrada para o indexador, em vez de por proxy usando o Prowlarr",
|
||||
"Redirect": "Redirecionar",
|
||||
"Reddit": "Reddit",
|
||||
"HomePage": "Página inicial",
|
||||
"FeatureRequests": "Solicitações de recursos",
|
||||
"FeatureRequests": "Solicitações de funcionalidades",
|
||||
"AppProfileSelectHelpText": "Os perfis de aplicações são utilizados para controlar as definições de RSS, Pesquisa automática e Pesquisa interativa ao sincronizar a aplicação",
|
||||
"Discord": "Discord",
|
||||
"Presets": "Pré-sintonizações",
|
||||
@@ -910,7 +910,7 @@
|
||||
"Enabled": "Ativado",
|
||||
"Donations": "Doações",
|
||||
"Description": "Descrição",
|
||||
"DeleteAppProfile": "Eliminar perfil de aplicação",
|
||||
"DeleteAppProfile": "Eliminar perfil da aplicação",
|
||||
"Custom": "Personalizado",
|
||||
"Category": "Categoria",
|
||||
"Auth": "Autenticação",
|
||||
@@ -919,6 +919,17 @@
|
||||
"AppProfileDeleteConfirm": "Tem a certeza que quer eliminar {0}?",
|
||||
"Applications": "Aplicações",
|
||||
"AddDownloadClient": "Adicionar cliente de transferências",
|
||||
"CouldNotConnectSignalR": "Não é possível conectar-se ao SignalR, a IU não será atualizada",
|
||||
"PrioritySettings": "Prioridade"
|
||||
"CouldNotConnectSignalR": "Não é possível ligar-se ao SignalR, a IU não atualizará",
|
||||
"PrioritySettings": "Prioridade",
|
||||
"UnableToLoadAppProfiles": "Não é possível carregar os perfis das aplicações",
|
||||
"UnableToAddANewAppProfilePleaseTryAgain": "Não é possível adicionar um novo perfil da aplicação, tenta novamente.",
|
||||
"UnableToAddANewApplicationPleaseTryAgain": "Não é possível adicionar uma nova aplicação, tenta novamente.",
|
||||
"Torrent": "Torrent",
|
||||
"SyncLevelFull": "Sincronização completa: a aplicação estará sempre sincronizada. Mudanças feitas no Prowlar serão sincronizadas posteriormente com a aplicação. Qualquer mudança feita remotamente será substituída pelo Prowlarr na sincronização seguinte.",
|
||||
"SyncLevelAddRemove": "Adicionar e remover apenas: esta aplicação remota será atualizada quando da adição e remoção do Prowlarr.",
|
||||
"SyncLevel": "Nível da sincronização",
|
||||
"Stats": "Estatísticas",
|
||||
"Query": "Consulta",
|
||||
"Privacy": "Privacidade",
|
||||
"FullSync": "Sincronização completa"
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
"General": "Geral",
|
||||
"GeneralSettings": "Configurações gerais",
|
||||
"GeneralSettingsSummary": "Porta, SSL, nome de usuário/senha, proxy, análises e atualizações",
|
||||
"Grabbed": "Baixado",
|
||||
"Grabbed": "Obtido",
|
||||
"Health": "Integridade",
|
||||
"HealthNoIssues": "Não há problemas com sua configuração",
|
||||
"HiddenClickToShow": "Oculto, clique para mostrar",
|
||||
@@ -206,7 +206,7 @@
|
||||
"MaximumLimits": "Limites máximos",
|
||||
"Mechanism": "Mecanismo",
|
||||
"Message": "Mensagem",
|
||||
"MIA": "MIA",
|
||||
"MIA": "Desaparecidos",
|
||||
"MinimumLimits": "Limites mínimos",
|
||||
"MinutesHundredTwenty": "120 minutos: {0}",
|
||||
"MinutesNinety": "90 minutos: {0}",
|
||||
@@ -264,7 +264,7 @@
|
||||
"ReadTheWikiForMoreInformation": "Leia a Wiki para saber mais",
|
||||
"Refresh": "Atualizar",
|
||||
"RefreshMovie": "Atualizar filme",
|
||||
"ReleaseBranchCheckPreviousVersionMessage": "A ramificação {0} é para uma versão anterior do Prowlarr, defina a ramificação como \"Noturna\" para obter mais atualizações",
|
||||
"ReleaseBranchCheckPreviousVersionMessage": "A ramificação {0} é para uma versão anterior do Prowlarr, defina a ramificação como \"Nightly\" para obter mais atualizações",
|
||||
"ReleaseStatus": "Status do lançamento",
|
||||
"Reload": "Recarregar",
|
||||
"RemovedFromTaskQueue": "Removido da fila de tarefas",
|
||||
@@ -395,7 +395,7 @@
|
||||
"Query": "Consulta",
|
||||
"Privacy": "Privacidade",
|
||||
"Presets": "Predefinições",
|
||||
"NotificationTriggersHelpText": "Selecione quais eventos devem acionar esta notificação",
|
||||
"NotificationTriggersHelpText": "Selecionar quais eventos devem acionar esta notificação",
|
||||
"Id": "ID",
|
||||
"Grabs": "Obtenções",
|
||||
"Failed": "Falhou",
|
||||
|
||||
@@ -18,7 +18,266 @@
|
||||
"AddedToDownloadClient": "发布已添加档案到客户端",
|
||||
"Added": "已添加",
|
||||
"AddAppProfile": "添加应用同步档案",
|
||||
"AppProfile": "应用档案",
|
||||
"AppProfile": "程序档案",
|
||||
"Actions": "动作",
|
||||
"About": "关于"
|
||||
"About": "关于",
|
||||
"MoreInfo": "更多信息",
|
||||
"MonoVersionCheckUpgradeRecommendedMessage": "当前安装的Mono版本 {0} 在支持范围但建议升级Mono到版本 {1} 。",
|
||||
"MonoVersion": "Mono版本",
|
||||
"MonoTlsCheckMessage": "Prowlarr Mono 4.x tls 功能仍然启用,请删除 MONO_TLS_PROVIDER=legacy 环境选项",
|
||||
"MonoNotNetCoreCheckMessage": "请升级至.NET核心版本的Prowlarr",
|
||||
"Mode": "模式",
|
||||
"MinutesSixty": "60分钟: {0}",
|
||||
"MinutesNinety": "90分钟: {0}",
|
||||
"MinutesHundredTwenty": "120分钟: {0}",
|
||||
"MinimumLimits": "最小限制",
|
||||
"MIA": "MIA",
|
||||
"Message": "信息",
|
||||
"Mechanism": "机制",
|
||||
"MaximumLimits": "最大限制",
|
||||
"Manual": "手动",
|
||||
"MaintenanceRelease": "维护版本",
|
||||
"Logs": "日志",
|
||||
"LogLevelTraceHelpTextWarning": "追踪日志只应该暂时启用",
|
||||
"LogLevel": "日志等级",
|
||||
"Logging": "日志记录中",
|
||||
"LogFiles": "日志文件",
|
||||
"Level": "等级",
|
||||
"LaunchBrowserHelpText": " 启动浏览器时导航到Prowlarr 主页。",
|
||||
"LastWriteTime": "最后写入时间",
|
||||
"Languages": "语言",
|
||||
"Language": "语言",
|
||||
"KeyboardShortcuts": "键盘快捷键",
|
||||
"Interval": "间隔",
|
||||
"InteractiveSearch": "手动搜索",
|
||||
"Info": "信息",
|
||||
"IndexerStatusCheckSingleClientMessage": "搜刮器因错误不可用:{0}",
|
||||
"IndexerStatusCheckAllClientMessage": "所有搜刮器都因错误不可用",
|
||||
"IndexersSelectedInterp": "已选择 {0} 个搜刮器",
|
||||
"Indexers": "搜刮器",
|
||||
"IndexerRss": "搜刮器RSS",
|
||||
"IndexerQuery": "搜刮器查询",
|
||||
"IndexerPriorityHelpText": "搜刮器优先级从1(最高)到50(最低),默认25。",
|
||||
"IndexerPriority": "搜刮器优先级",
|
||||
"IndexerObsoleteCheckMessage": "搜刮器已过弃用或已更新:{0}。请将其删除和(或)重新添加到 Prowlarr",
|
||||
"IndexerLongTermStatusCheckSingleClientMessage": "所有搜刮器由于故障都已不可用6小时:{0}",
|
||||
"IndexerLongTermStatusCheckAllClientMessage": "所有搜刮器由于故障都已不可用6小时",
|
||||
"IndexerHealthCheckNoIndexers": "未启用任何搜刮器,Prowlarr将不会返回搜索结果",
|
||||
"IndexerFlags": "搜刮器标记",
|
||||
"IndexerAuth": "搜刮器认证",
|
||||
"Indexer": "搜刮器",
|
||||
"IncludeHealthWarningsHelpText": "包含健康度警告",
|
||||
"Importing": "导入中",
|
||||
"IllRestartLater": "稍后重启",
|
||||
"IgnoredAddresses": "已忽略地址",
|
||||
"Id": "Id",
|
||||
"Hostname": "主机名",
|
||||
"Host": "主机",
|
||||
"HomePage": "主页",
|
||||
"History": "历史记录",
|
||||
"HideAdvanced": "隐藏高级设置",
|
||||
"HiddenClickToShow": "已隐藏,点击显示",
|
||||
"HealthNoIssues": "您的设置没有问题",
|
||||
"Health": "健康度",
|
||||
"Grabs": "抓取",
|
||||
"Grabbed": "已抓取",
|
||||
"GeneralSettingsSummary": "端口、SSL、用户名/密码、代理、分析、更新",
|
||||
"GeneralSettings": "通用设置",
|
||||
"General": "通用",
|
||||
"FullSync": "完全同步",
|
||||
"ForMoreInformationOnTheIndividualDownloadClients": "有关个别下载客户端的详细信息,请单击info按钮。",
|
||||
"Folder": "文件夹",
|
||||
"FocusSearchBox": "聚焦搜索框",
|
||||
"Fixed": "已修复",
|
||||
"FilterPlaceHolder": "搜刮器搜索",
|
||||
"Filter": "过滤",
|
||||
"Files": "文件",
|
||||
"Filename": "文件名",
|
||||
"FeatureRequests": "功能建议",
|
||||
"Failed": "失败",
|
||||
"ExistingTag": "已有标签",
|
||||
"ExistingMovies": "已有影片",
|
||||
"Exception": "例外",
|
||||
"EventType": "事件类型",
|
||||
"Events": "事件",
|
||||
"ErrorLoadingContents": "读取内容错误",
|
||||
"Error": "错误",
|
||||
"Encoding": "编码",
|
||||
"EnableSslHelpText": " 重启生效",
|
||||
"EnableSSL": "启用SSL",
|
||||
"EnableRssHelpText": "为搜刮器启用 RSS订阅",
|
||||
"EnableRss": "启用RSS",
|
||||
"EnableMediaInfoHelpText": "从文件中提取视频信息,如分辨率,时长和编解码器信息。这需要Prowlarr 在扫描期间读取文件并可能导致高磁盘或网络占用。",
|
||||
"EnableInteractiveSearchHelpTextWarning": "该搜刮器不支持搜索",
|
||||
"EnableInteractiveSearchHelpText": "当手动搜索启用时使用",
|
||||
"EnableInteractiveSearch": "启用手动搜索",
|
||||
"EnableIndexer": "启用搜刮器",
|
||||
"EnableHelpText": "启用此元数据类型的元数据文件创建",
|
||||
"EnabledHelpText": "在 Prowlarr 中启用该列表",
|
||||
"Enabled": "已启用",
|
||||
"EnableCompletedDownloadHandlingHelpText": "自动从下载客户端导入已下载的影片",
|
||||
"EnableColorImpairedModeHelpText": "改变样式,以允许有颜色障碍的用户更好地区分颜色编码信息",
|
||||
"EnableColorImpairedMode": "启用色障模式",
|
||||
"EnableAutomaticSearchHelpTextWarning": "当手动搜索启用时使用",
|
||||
"EnableAutomaticSearchHelpText": "当自动搜索通过UI或Prowlarr执行时将被使用",
|
||||
"EnableAutomaticSearch": "启用自动搜索",
|
||||
"EnableAutomaticAdd": "启用自动添加",
|
||||
"EnableAutoHelpText": "如已启用,影片会自动从列表中添加到 Prowlarr",
|
||||
"Enable": "启用",
|
||||
"EditIndexer": "编辑搜刮器",
|
||||
"EditAppProfile": "编辑应用配置",
|
||||
"Edit": "编辑",
|
||||
"Downloading": "下载中",
|
||||
"DownloadClientUnavailable": "下载客户端不可用",
|
||||
"DownloadClientStatusCheckSingleClientMessage": "所有下载客户端都不可用: {0}",
|
||||
"DownloadClientStatusCheckAllClientMessage": "所有下载客户端都不可用",
|
||||
"DownloadClientsSettingsSummary": "下载客户端配置以集成到 Prowlarr UI 搜索中",
|
||||
"DownloadClientSettings": "下载客户端设置",
|
||||
"DownloadClients": "下载客户端",
|
||||
"DownloadClientCheckUnableToCommunicateMessage": "无法与{0}进行通讯。",
|
||||
"DownloadClientCheckNoneAvailableMessage": "无可用的下载客户端",
|
||||
"DownloadClient": "下载客户端",
|
||||
"Donations": "捐赠",
|
||||
"Docker": "Docker",
|
||||
"Discord": "Discord",
|
||||
"Disabled": "禁用",
|
||||
"DevelopmentSettings": "开发设置",
|
||||
"Details": "详情",
|
||||
"Description": "描述",
|
||||
"DeleteTagMessageText": "您确定要删除标签 '{0}' 吗?",
|
||||
"DeleteTag": "删除标签",
|
||||
"DeleteNotificationMessageText": "您确定要删除推送 '{0}' 吗?",
|
||||
"DeleteNotification": "删除消息推送",
|
||||
"DeleteIndexerMessageText": "您确定要删除索引 '{0}'吗?",
|
||||
"DeleteIndexer": "删除索引",
|
||||
"DeleteDownloadClientMessageText": "您确定要删除下载客户端 '{0}' 吗?",
|
||||
"DeleteDownloadClient": "删除下载客户端",
|
||||
"DeleteBackupMessageText": "您确定要删除备份 '{0}' 吗?",
|
||||
"DeleteBackup": "删除备份",
|
||||
"DeleteAppProfile": "删除应用配置文件",
|
||||
"DeleteApplicationMessageText": "您确定要删除应用程序“{0}”吗?",
|
||||
"DeleteApplication": "删除应用程序",
|
||||
"Delete": "删除",
|
||||
"DelayProfile": "延时配置",
|
||||
"DBMigration": "数据库迁移版本",
|
||||
"Dates": "日期",
|
||||
"Date": "日期",
|
||||
"CustomFilters": "自定义过滤",
|
||||
"Custom": "自定义",
|
||||
"CouldNotConnectSignalR": "无法连接至SignalR,不会升级UI",
|
||||
"ConnectSettingsSummary": "通知、与媒体服务器/播放器的链接、自定义脚本",
|
||||
"ConnectSettings": "连接设置",
|
||||
"Connections": "连接",
|
||||
"ConnectionLostMessage": "Prowlarr 已与服务端断开链接,请尝试刷新来恢复使用。",
|
||||
"ConnectionLostAutomaticMessage": "Prowlarr 将会自动重连,您也可以点击下方的重新加载。",
|
||||
"ConnectionLost": "连接丢失",
|
||||
"Connect": "通知连接",
|
||||
"Component": "组件",
|
||||
"Columns": "列",
|
||||
"CloseCurrentModal": "关闭当前模组",
|
||||
"Close": "关闭",
|
||||
"CloneProfile": "复制配置",
|
||||
"CloneIndexer": "复制索引",
|
||||
"ClientPriority": "客户端优先级",
|
||||
"ClearHistoryMessageText": "您确定要清除Prowlarr所有的历史记录吗?",
|
||||
"ClearHistory": "清楚历史",
|
||||
"Clear": "清除",
|
||||
"ChangeHasNotBeenSavedYet": "修改暂未保存",
|
||||
"CertificateValidationHelpText": "改变HTTPS证书验证的严格程度",
|
||||
"CertificateValidation": "验证证书",
|
||||
"Category": "类别",
|
||||
"CancelPendingTask": "您确定要取消这个挂起的任务吗?",
|
||||
"Cancel": "取消",
|
||||
"BypassProxyForLocalAddresses": "对局域网地址不使用代理",
|
||||
"BranchUpdateMechanism": "外部更新机制使用的分支",
|
||||
"BranchUpdate": "更新Prowlarr的分支",
|
||||
"Branch": "分支",
|
||||
"BindAddressHelpText": "有效的IPV4地址或以“*”代表所以地址",
|
||||
"BindAddress": "绑定地址",
|
||||
"BeforeUpdate": "更新前",
|
||||
"Backups": "备份",
|
||||
"BackupRetentionHelpText": "早于保留周期的自动备份将被自动清除",
|
||||
"BackupNow": "现在备份",
|
||||
"BackupFolderHelpText": "相对路径将在 Prowlarr 的 AppData 目录下",
|
||||
"Backup": "备份",
|
||||
"AutomaticSearch": "自动搜索",
|
||||
"Automatic": "自动化",
|
||||
"AuthenticationMethodHelpText": "需要账号和密码以登录Prowlarr",
|
||||
"Authentication": "认证",
|
||||
"Auth": "认证",
|
||||
"AreYouSureYouWantToResetYourAPIKey": "你确认希望重置API密钥吗?",
|
||||
"Apps": "应用程序",
|
||||
"AppProfileSelectHelpText": "应用程序配置用于控制应用程序同步设置 RSS、自动搜索和交互式搜索设置",
|
||||
"AppProfiles": "应用配置文件",
|
||||
"AppProfileInUse": "正在使用的应用程序配置文件",
|
||||
"AppProfileDeleteConfirm": "您确认您想删除吗?",
|
||||
"ApplyTagsHelpTexts4": "替换:用输入的标签替换标签(不输入标签将清除所有标签)",
|
||||
"ApplyTagsHelpTexts3": "删除:删除输入的标签",
|
||||
"ApplyTagsHelpTexts2": "添加:将标签添加到现有标签列表",
|
||||
"Applications": "程序",
|
||||
"AppDataLocationHealthCheckMessage": "由于防止程序数据在升级中被删除升级不可用",
|
||||
"AddRemoveOnly": "仅添加和删除",
|
||||
"AddDownloadClientToProwlarr": "添加下载客户端允许 Prowlarr 在进行手动搜索时从 UI直接发送结果",
|
||||
"AddDownloadClient": "添加下载客户端",
|
||||
"Add": "添加",
|
||||
"SettingsEnableColorImpairedModeHelpText": "改变样式,以允许有颜色障碍的用户更好地区分颜色编码信息",
|
||||
"SettingsEnableColorImpairedMode": "启用色障模式",
|
||||
"QualitySettings": "影片质量配置设置",
|
||||
"QualityDefinitions": "影片质量定义",
|
||||
"PtpOldSettingsCheckMessage": "下列PassThePopcorn搜刮器有已启用的设置,请更新:{0}",
|
||||
"ProxyUsernameHelpText": "如果需要,您只需要输入用户名和密码。否则就让它们为空。",
|
||||
"ProxyType": "代理类型",
|
||||
"ProxyPasswordHelpText": "如果需要,您只需要输入用户名和密码,否则就让它们为空。",
|
||||
"ProxyCheckResolveIpMessage": "无法解析已设置的代理服务器主机{0}的IP地址",
|
||||
"ProxyCheckFailedToTestMessage": "测试代理失败: {0}",
|
||||
"ProxyCheckBadRequestMessage": "测试代理失败,状态码: {0}",
|
||||
"ProxyBypassFilterHelpText": "使用“ , ”作为分隔符,和“ *. ”作为二级域名的通配符",
|
||||
"Proxy": "代理",
|
||||
"ProwlarrSupportsAnyIndexer": "Prowlarr支持任何符合Newznab标准的搜刮器,以及以下列出的其他索引器。",
|
||||
"ProwlarrSupportsAnyDownloadClient": "Prowlarr 支持以下列出的下载客户端。",
|
||||
"Protocol": "协议",
|
||||
"Privacy": "隐私",
|
||||
"PrioritySettings": "优先级",
|
||||
"PriorityHelpText": "优先考虑多个下载客户端,循环查询用于具有相同优先级的客户端。",
|
||||
"Priority": "优先级",
|
||||
"Presets": "预设",
|
||||
"PreferredSize": "首选影片大小",
|
||||
"PortNumber": "端口号",
|
||||
"Port": "端口",
|
||||
"PendingChangesStayReview": "留下检查更改",
|
||||
"PendingChangesMessage": "您有未保存的修改,确定要退出本页么?",
|
||||
"PendingChangesDiscardChanges": "舍弃修改并退出",
|
||||
"Pending": "挂起",
|
||||
"Peers": "用户",
|
||||
"Password": "密码",
|
||||
"PageSizeHelpText": "每页显示的项目数",
|
||||
"PageSize": "页面大小",
|
||||
"PackageVersion": "Package版本",
|
||||
"Options": "选项",
|
||||
"OpenThisModal": "打开该模组",
|
||||
"OpenBrowserOnStart": "打开浏览器时启动",
|
||||
"OnHealthIssueHelpText": "健康度异常",
|
||||
"Ok": "完成",
|
||||
"OAuthPopupMessage": "您的浏览器已禁止弹出页面",
|
||||
"NoUpdatesAreAvailable": "无可用更新",
|
||||
"NotificationTriggersHelpText": "选择触发此通知的事件",
|
||||
"NotificationTriggers": "通知触发器",
|
||||
"NoTagsHaveBeenAddedYet": "未添加标签",
|
||||
"NoMinimumForAnyRuntime": "影片时间没有最小限制",
|
||||
"NoLogFiles": "没有日志文件",
|
||||
"NoLimitForAnyRuntime": "不限制任何影片时长",
|
||||
"NoLeaveIt": "不,就这样",
|
||||
"NoChanges": "无修改",
|
||||
"NoChange": "无修改",
|
||||
"NoBackupsAreAvailable": "无备份可用",
|
||||
"NewznabVipCheckExpiringClientMessage": "搜刮器VIP权益即将到期:{0}",
|
||||
"NewznabVipCheckExpiredClientMessage": "搜刮器VIP权益已过期:{0}",
|
||||
"New": "新的",
|
||||
"NetCore": ".NET",
|
||||
"Name": "名字",
|
||||
"Movies": "电影",
|
||||
"MovieIndexScrollTop": "影片索引:滚动到顶部",
|
||||
"MovieIndexScrollBottom": "影片索引:滚动到底部",
|
||||
"MovieDetailsPreviousMovie": "影片详细:前一个",
|
||||
"MovieDetailsNextMovie": "影片详细:下一个"
|
||||
}
|
||||
|
||||
1
src/NzbDrone.Core/Localization/Core/zh_Hans.json
Normal file
1
src/NzbDrone.Core/Localization/Core/zh_Hans.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -27,7 +27,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
||||
|
||||
public override string Name => "Custom Script";
|
||||
|
||||
public override string Link => "https://wikijs.servarr.com/prowlarr/settings#connections";
|
||||
public override string Link => "https://wiki.servarr.com/prowlarr/settings#connections";
|
||||
|
||||
public override ProviderMessage Message => new ProviderMessage("Testing will execute the script with the EventType set to Test, ensure your script handles this correctly", ProviderMessageType.Warning);
|
||||
|
||||
|
||||
@@ -49,10 +49,10 @@ namespace NzbDrone.Core.Notifications.Email
|
||||
[FieldDefinition(2, Label = "Require Encryption", HelpText = "Require SSL (Port 465 only) or StartTLS (any other port)", Type = FieldType.Checkbox)]
|
||||
public bool RequireEncryption { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Username", Privacy = PrivacyLevel.UserName)]
|
||||
[FieldDefinition(3, Label = "Username", HelpText = "Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(4, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(4, Label = "Password", HelpText = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[FieldDefinition(5, Label = "From Address")]
|
||||
|
||||
@@ -38,10 +38,10 @@ namespace NzbDrone.Core.Notifications.Twitter
|
||||
AuthorizeNotification = "startOAuth";
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Consumer Key", Privacy = PrivacyLevel.ApiKey, HelpText = "Consumer key from a Twitter application", HelpLink = "https://wikijs.servarr.com/useful-tools#twitter-connect")]
|
||||
[FieldDefinition(0, Label = "Consumer Key", Privacy = PrivacyLevel.ApiKey, HelpText = "Consumer key from a Twitter application", HelpLink = "https://wiki.servarr.com/useful-tools#twitter-connect")]
|
||||
public string ConsumerKey { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Consumer Secret", Privacy = PrivacyLevel.ApiKey, HelpText = "Consumer secret from a Twitter application", HelpLink = "https://wikijs.servarr.com/useful-tools#twitter-connect")]
|
||||
[FieldDefinition(1, Label = "Consumer Secret", Privacy = PrivacyLevel.ApiKey, HelpText = "Consumer secret from a Twitter application", HelpLink = "https://wiki.servarr.com/useful-tools#twitter-connect")]
|
||||
public string ConsumerSecret { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Access Token", Privacy = PrivacyLevel.ApiKey, Advanced = true)]
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace NzbDrone.Core.Notifications.Webhook
|
||||
_proxy = proxy;
|
||||
}
|
||||
|
||||
public override string Link => "https://wikijs.servarr.com/prowlarr/settings#connect";
|
||||
public override string Link => "https://wiki.servarr.com/prowlarr/settings#connect";
|
||||
|
||||
public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck)
|
||||
{
|
||||
|
||||
@@ -29,10 +29,10 @@ namespace NzbDrone.Core.Notifications.Webhook
|
||||
[FieldDefinition(1, Label = "Method", Type = FieldType.Select, SelectOptions = typeof(WebhookMethod), HelpText = "Which HTTP method to use submit to the Webservice")]
|
||||
public int Method { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Username", Privacy = PrivacyLevel.UserName)]
|
||||
[FieldDefinition(2, Label = "Username", HelpText = "Username", Type = FieldType.Textbox, Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
[FieldDefinition(3, Label = "Password", HelpText = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
|
||||
namespace NzbDrone.Core.Parser
|
||||
{
|
||||
@@ -83,5 +85,18 @@ namespace NzbDrone.Core.Parser
|
||||
|
||||
return "tt" + ((int)imdbid).ToString("D7");
|
||||
}
|
||||
|
||||
public static string GetArgumentFromQueryString(string url, string argument)
|
||||
{
|
||||
if (url == null || argument == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var qsStr = url.Split(new char[] { '?' }, 2)[1];
|
||||
qsStr = qsStr.Split(new char[] { '#' }, 2)[0];
|
||||
var qs = QueryHelpers.ParseQuery(qsStr);
|
||||
return qs[argument].FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
109
src/NzbDrone.Core/Parser/TvCategoryFromQualityParser.cs
Normal file
109
src/NzbDrone.Core/Parser/TvCategoryFromQualityParser.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using NzbDrone.Core.Indexers;
|
||||
|
||||
namespace NzbDrone.Core.Parser
|
||||
{
|
||||
public static class TvCategoryFromQualityParser
|
||||
{
|
||||
private static readonly Regex SourceRegex = new Regex(@"\b(?:
|
||||
(?<bluray>BluRay|Blu-Ray|HDDVD|BD)|
|
||||
(?<webdl>WEB[-_. ]DL|WEBDL|WebRip|iTunesHD|WebHD)|
|
||||
(?<hdtv>HDTV)|
|
||||
(?<bdrip>BDRip)|
|
||||
(?<brrip>BRRip)|
|
||||
(?<dvd>DVD|DVDRip|NTSC|PAL|xvidvd)|
|
||||
(?<dsr>WS[-_. ]DSR|DSR)|
|
||||
(?<pdtv>PDTV)|
|
||||
(?<sdtv>SDTV)|
|
||||
(?<tvrip>TVRip)
|
||||
)\b",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
private static readonly Regex RawHdRegex = new Regex(@"\b(?<rawhd>TrollHD|RawHD|1080i[-_. ]HDTV|Raw[-_. ]HD|MPEG[-_. ]?2)\b",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex ResolutionRegex = new Regex(@"\b(?:(?<q480p>480p|640x480|848x480)|(?<q576p>576p)|(?<q720p>720p|1280x720)|(?<q1080p>1080p|1920x1080))\b",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex CodecRegex = new Regex(@"\b(?:(?<x264>x264)|(?<h264>h264)|(?<xvidhd>XvidHD)|(?<xvid>Xvid)|(?<divx>divx))\b",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex HighDefPdtvRegex = new Regex(@"hr[-_. ]ws", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static IndexerCategory ParseTvShowQuality(string tvShowFileName)
|
||||
{
|
||||
var normalizedName = tvShowFileName.Trim().Replace('_', ' ').Trim().ToLower();
|
||||
|
||||
var sourceMatch = SourceRegex.Match(normalizedName);
|
||||
var resolutionMatch = ResolutionRegex.Match(normalizedName);
|
||||
var codecMatch = CodecRegex.Match(normalizedName);
|
||||
|
||||
if (sourceMatch.Groups["webdl"].Success)
|
||||
{
|
||||
if (resolutionMatch.Groups["q1080p"].Success || resolutionMatch.Groups["q720p"].Success)
|
||||
{
|
||||
return NewznabStandardCategory.TVHD;
|
||||
}
|
||||
|
||||
if (resolutionMatch.Groups["q480p"].Success)
|
||||
{
|
||||
return NewznabStandardCategory.TVSD;
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceMatch.Groups["hdtv"].Success)
|
||||
{
|
||||
if (resolutionMatch.Groups["q1080p"].Success || resolutionMatch.Groups["q720p"].Success)
|
||||
{
|
||||
return NewznabStandardCategory.TVHD;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NewznabStandardCategory.TVSD;
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceMatch.Groups["bluray"].Success || sourceMatch.Groups["bdrip"].Success || sourceMatch.Groups["brrip"].Success)
|
||||
{
|
||||
if (codecMatch.Groups["xvid"].Success || codecMatch.Groups["divx"].Success)
|
||||
{
|
||||
return NewznabStandardCategory.TVSD;
|
||||
}
|
||||
|
||||
if (resolutionMatch.Groups["q1080p"].Success || resolutionMatch.Groups["q720p"].Success)
|
||||
{
|
||||
return NewznabStandardCategory.TVHD;
|
||||
}
|
||||
|
||||
if (resolutionMatch.Groups["q480p"].Success || resolutionMatch.Groups["q576p"].Success)
|
||||
{
|
||||
return NewznabStandardCategory.TVSD;
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceMatch.Groups["dvd"].Success)
|
||||
{
|
||||
return NewznabStandardCategory.TVSD;
|
||||
}
|
||||
|
||||
if (sourceMatch.Groups["pdtv"].Success || sourceMatch.Groups["sdtv"].Success || sourceMatch.Groups["dsr"].Success || sourceMatch.Groups["tvrip"].Success)
|
||||
{
|
||||
if (HighDefPdtvRegex.IsMatch(normalizedName))
|
||||
{
|
||||
return NewznabStandardCategory.TVHD;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NewznabStandardCategory.TVSD;
|
||||
}
|
||||
}
|
||||
|
||||
if (RawHdRegex.IsMatch(normalizedName))
|
||||
{
|
||||
return NewznabStandardCategory.TVHD;
|
||||
}
|
||||
|
||||
return NewznabStandardCategory.TV;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,8 @@ namespace Prowlarr.Api.V1.Indexers
|
||||
|
||||
var resource = base.ToResource(definition);
|
||||
|
||||
var infoLinkName = definition.ImplementationName;
|
||||
|
||||
if (definition.Implementation == typeof(Cardigann).Name)
|
||||
{
|
||||
var extraFields = definition.ExtraFields?.Select((x, i) => MapField(x, i)).ToList() ?? new List<Field>();
|
||||
@@ -66,8 +68,11 @@ namespace Prowlarr.Api.V1.Indexers
|
||||
field.Value = setting.Value;
|
||||
}
|
||||
}
|
||||
|
||||
infoLinkName = settings.DefinitionFile;
|
||||
}
|
||||
|
||||
resource.InfoLink = string.Format("https://wiki.servarr.com/prowlarr/supported-indexers#{0}", infoLinkName.ToLower().Replace(' ', '-'));
|
||||
resource.AppProfileId = definition.AppProfileId;
|
||||
resource.BaseUrl = definition.BaseUrl;
|
||||
resource.Description = definition.Description;
|
||||
|
||||
@@ -62,6 +62,39 @@ namespace NzbDrone.Api.V1.Indexers
|
||||
}
|
||||
}
|
||||
|
||||
if (id == 0)
|
||||
{
|
||||
switch (requestType)
|
||||
{
|
||||
case "caps":
|
||||
var caps = new IndexerCapabilities();
|
||||
foreach (var cat in NewznabStandardCategory.AllCats)
|
||||
{
|
||||
caps.Categories.AddCategoryMapping(1, cat);
|
||||
}
|
||||
|
||||
return Content(caps.ToXml(), "application/rss+xml");
|
||||
case "search":
|
||||
case "tvsearch":
|
||||
case "music":
|
||||
case "book":
|
||||
case "movie":
|
||||
var results = new NewznabResults();
|
||||
results.Releases = new List<ReleaseInfo>
|
||||
{
|
||||
new ReleaseInfo
|
||||
{
|
||||
Title = "Test Release",
|
||||
Guid = "https://prowlarr.com",
|
||||
DownloadUrl = "https://prowlarr.com",
|
||||
PublishDate = DateTime.Now
|
||||
}
|
||||
};
|
||||
|
||||
return Content(results.ToXml(DownloadProtocol.Usenet), "application/rss+xml");
|
||||
}
|
||||
}
|
||||
|
||||
var indexer = _indexerFactory.Get(id);
|
||||
|
||||
if (indexer == null)
|
||||
|
||||
@@ -38,9 +38,10 @@ namespace Prowlarr.Api.V1
|
||||
Tags = definition.Tags,
|
||||
Fields = SchemaBuilder.ToSchema(definition.Settings),
|
||||
|
||||
//Radarr_Supported_{0} are custom build redirect pages; if passing a new var, create a new redirect
|
||||
InfoLink = string.Format("https://wikijs.servarr.com/prowlarr/supported_{0}",
|
||||
definition.Implementation.ToLower())
|
||||
//prowlarr/supported#{0} are custom build redirect pages; if passing a new var, create a new redirect
|
||||
// note: indexers get a different link
|
||||
InfoLink = string.Format("https://wiki.servarr.com/prowlarr/supported#{0}",
|
||||
definition.Implementation.ToLower().Replace(' ', '-'))
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -766,13 +766,13 @@
|
||||
"source": "ImportMechanismCheck",
|
||||
"type": "warning",
|
||||
"message": "Enable Completed Download Handling",
|
||||
"wikiUrl": "https://wikijs.servarr.com/prowlarr/system#completed.2FFailed_Download_Handling"
|
||||
"wikiUrl": "https://wiki.servarr.com/prowlarr/system#completed.2FFailed_Download_Handling"
|
||||
},
|
||||
{
|
||||
"source": "DownloadClientCheck",
|
||||
"type": "error",
|
||||
"message": "Unable to communicate with qBittorrent. Failed to connect to qBittorrent, check your settings.",
|
||||
"wikiUrl": "https://wikijs.servarr.com/prowlarr/system#download-clients"
|
||||
"wikiUrl": "https://wiki.servarr.com/prowlarr/system#download-clients"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user