Compare commits

...

58 Commits

Author SHA1 Message Date
Mark McDowall
c664eaa9b5 New: Don't treat 400 responses from Notifiarr as errors
(cherry picked from commit 5eb420bbe12f59d0a5392abf3d351be28ca210e6)
2023-10-07 23:02:44 +03:00
Bogdan
b7e57f0c08 Fixed: (Nebulance) Filter releases by season and episode for ID based searches 2023-10-07 03:09:44 +03:00
Bogdan
c06bf0e4ea Fixed: (TorrentDay) Update categories
Fixes #1888
2023-10-05 22:41:59 +03:00
Bogdan
c6db30c35a Parse description in RSS Parser 2023-10-05 01:54:40 +03:00
Bogdan
75c30dd318 Add year to XML results 2023-10-04 19:51:49 +03:00
Bogdan
6e7bf55dbd Add poster URL to PassThePopcorn 2023-10-04 19:16:55 +03:00
Bogdan
eb642dd2f9 Fix document being disposed before returning 2023-10-04 18:36:31 +03:00
Bogdan
19a196e2c7 Ensure the correct use of disposable parsed documents 2023-10-04 18:11:23 +03:00
Weblate
93ec6cf89b Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dimitri <dimitridroeck@gmail.com>
Co-authored-by: Garkus98 <ivan12061998@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: RicardoVelaC <ricardovelac@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 宿命 <331874545@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2023-10-04 07:00:00 +03:00
Bogdan
52c6b56a4c Cleanup BooleanConverter to STJson 2023-10-04 05:19:03 +03:00
Bogdan
82688d8a55 Use ExecuteAuth in AvistazBase 2023-10-04 04:27:04 +03:00
Bogdan
c81cbc801a Fixed: (AvistaZBase) Parse response with STJson
Also ensure GetToken is using a proxied request and rate limit
2023-10-04 02:27:32 +03:00
Bogdan
993d189c61 Fixed: (Nebulance) Parse response with STJson 2023-10-04 02:27:29 +03:00
Bogdan
1901af5a51 Fixed: (BeyondHD) Parse response with STJson 2023-10-04 02:27:24 +03:00
Bogdan
c1b399be39 Fixed: (FileList) Parse response with STJson 2023-10-04 02:27:19 +03:00
Bogdan
2100e96570 Fixed: (PassThePopcorn) Use UTC for publish dates 2023-10-02 04:35:57 +03:00
Bogdan
3ff144421d Fixed: (PassThePopcorn) Cleanup and ensure pagination is working in Radarr 2023-10-02 02:55:34 +03:00
Bogdan
f37ccba3f9 Fixed: (Shizaproject) Title improvements 2023-10-02 00:47:33 +03:00
Bogdan
181cb2e0fe Revert "New: (Orpheus) Add options to prevent downloads without FL tokens"
This reverts commit 93c81bb7d3.
2023-10-01 19:47:28 +03:00
Bogdan
93c81bb7d3 New: (Orpheus) Add options to prevent downloads without FL tokens 2023-10-01 17:03:43 +03:00
Weblate
7dd289b5f9 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Jaspils <jasperkemper@gmail.com>
Co-authored-by: Stevie Robinson <stevie.robinson@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 宿命 <331874545@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2023-10-01 17:03:03 +03:00
Bogdan
09cef8cf94 Bump version to 1.9.3 2023-10-01 17:01:35 +03:00
Bogdan
ca08c818e6 Fixed: (TorrentPotato) Use full IMDb Id 2023-09-30 22:41:25 +03:00
Bogdan
3e95bc4056 Fixed: (TorrentPotato) Title not being decoded 2023-09-30 22:15:25 +03:00
ilike2burnthing
e241112915 Fixed: (Shizaproject) Available again 2023-09-29 22:13:14 +03:00
Bogdan
0d98c12fa2 Fix the description for Use Filenames for Single Episodes 2023-09-29 20:45:04 +03:00
Bogdan
a0bcf5c9ae Allow using filename for single episodes along with generated titles in AnimeBytes 2023-09-29 20:26:35 +03:00
Bogdan
e318a47b3a Extend the torrent settings interface in TorrentPotato settings class 2023-09-27 23:23:43 +03:00
Bogdan
b8df720c6c Bump version to 1.9.2 2023-09-24 16:22:57 +03:00
Bogdan
9625be723d Fixed: (Search) Releases deduplication 2023-09-22 19:54:11 +03:00
Bogdan
d4b037db78 New: (AlphaRatio) Add pagination support 2023-09-21 20:46:34 +03:00
Bogdan
add2988789 Fixed: (Cardigann) Fallback variables to empty string to prevent NullRef 2023-09-20 02:54:25 +03:00
Bogdan
9869c2272a Avoid returning null in static resource mapper Task 2023-09-19 20:17:05 +03:00
Bogdan
4c8b0c9eec Fixed: Ignore releases without title 2023-09-19 14:06:15 +03:00
Bogdan
43cb22ff2b Bump migration timeout to 10 minutes 2023-09-19 00:57:06 +03:00
Bogdan
3cabc0589a Simplify use the group name when the release name is empty 2023-09-18 21:17:36 +03:00
Bogdan
cdb3ed36f6 Fixed: (Nebulance) Use the group name when the release name is empty 2023-09-18 21:16:13 +03:00
Bogdan
840f2ae3e6 Sync static resource controller with upstream
(cherry picked from commit ad1f185330a30a2a9d27c9d3f18d384e66727c2a)
2023-09-18 03:53:14 +03:00
Bogdan
3ed6ef0336 Use await on reading the response content
(cherry picked from commit 82d586e7015d7ea06356ca436024a8af5a4fb677)
2023-09-18 03:49:31 +03:00
Bogdan
c2ae0cce03 Bump version to 1.9.1 2023-09-17 12:01:01 +03:00
Weblate
934b908b37 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: stormaac <yxc.frank@gmail.com>
Co-authored-by: 宿命 <331874545@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2023-09-16 08:51:49 -04:00
Weblate
6c831f11a6 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: leotpp <yangdom_li@126.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/
Translation: Servarr/Prowlarr
2023-09-15 21:49:25 -05:00
Bogdan
9adbfd2391 Return 1 seeder as fallback only in Torrent RSS Feed 2023-09-14 21:48:32 +03:00
bakerboy448
4a7cc82f0d Correction to Improve tags helptext and add warnings 2023-09-14 20:56:24 +03:00
bakerboy448
c061c309bd Improve tags helptext and add warnings 2023-09-14 20:48:28 +03:00
Bogdan
0f3a77c336 Return 1 seeder as fallback in Torrent RSS Feed 2023-09-14 18:55:07 +03:00
Bogdan
478d5a624f Fixed: (Animedia) Removed
Co-authored-by: ilike2burnthing <59480337+ilike2burnthing@users.noreply.github.com>
2023-09-14 18:42:41 +03:00
Bogdan
3283d144f5 Ignore invalid cookies when adding response cookies to CookieContainer
Fixes #1868
2023-09-14 18:22:53 +03:00
Bogdan
1a9ec4febd Fixed: (Apps) Check if the indexers have valid settings 2023-09-14 17:50:54 +03:00
Bogdan
0598211319 Fixed: Ignore inaccessible mount points
(cherry picked from commit 60f18249b05daa20523542beef54bc126d963d1e)
2023-09-14 12:15:37 +03:00
Bogdan
0b0d6b7590 Fixed: (SubsPlease) Update category mappings for movie releases
Co-authored-by: Lemres <45440100+Calemy@users.noreply.github.com>

Fixes #1866
2023-09-13 12:30:06 +03:00
Servarr
86cec51ebe Automated API Docs update 2023-09-12 22:59:27 +03:00
Bogdan
80e5ac4aa9 New: Add custom filter by protocol for indexer stats 2023-09-12 15:25:48 +03:00
Bogdan
ee5ed0c91b Sonarr > Prowlarr 2023-09-11 11:59:51 +03:00
Denis Gheorghescu
ba278930ed New: Pushcut notifications
(cherry picked from commit 5f09f2b25f9144666b8e5182e20e263e74d5f5ca)
2023-09-11 11:57:35 +03:00
Mark McDowall
6449b89eb6 Fixed parsing of multiple languages from Newznab indexer releases
(cherry picked from commit 2a241294b5eeb9e95c46e030828191da09d05e88)
2023-09-11 11:29:07 +03:00
Weblate
73b85e240e Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/
Translation: Servarr/Prowlarr
2023-09-10 20:30:01 +03:00
Bogdan
6338460ff4 Bump version to 1.9.0 2023-09-10 19:09:26 +03:00
124 changed files with 1270 additions and 595 deletions

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '1.8.6'
majorVersion: '1.9.3'
minorVersion: $[counter('minorVersion', 1)]
prowlarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'

View File

@@ -187,6 +187,7 @@ function EditIndexerModalContent(props) {
type={inputTypes.TAG}
name="tags"
helpText={translate('IndexerTagsHelpText')}
helpTextWarning={translate('IndexerTagsHelpTextWarning')}
{...tags}
onChange={onInputChange}
/>

View File

@@ -133,7 +133,8 @@ function EditApplicationModalContent(props) {
<FormInputGroup
type={inputTypes.TAG}
name="tags"
helpText={translate('TagsHelpText')}
helpText={translate('ApplicationTagsHelpText')}
helpTextWarning={translate('ApplicationTagsHelpTextWarning')}
{...tags}
onChange={onInputChange}
/>

View File

@@ -61,6 +61,12 @@ export const defaultState = {
type: filterBuilderTypes.CONTAINS,
valueType: filterBuilderValueTypes.INDEXER
},
{
name: 'protocols',
label: () => translate('Protocols'),
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.PROTOCOL
},
{
name: 'tags',
label: () => translate('Tags'),
@@ -112,6 +118,10 @@ export const actionHandlers = handleThunks({
requestParams.indexers = selectedFilter.value.join(',');
}
if (selectedFilter.key === 'protocols') {
requestParams.protocols = selectedFilter.value.join(',');
}
if (selectedFilter.key === 'tags') {
requestParams.tags = selectedFilter.value.join(',');
}

View File

@@ -160,7 +160,7 @@ namespace NzbDrone.Common.Extensions
{
if (text.IsNullOrWhiteSpace())
{
throw new ArgumentNullException("text");
throw new ArgumentNullException(nameof(text));
}
return text.IndexOfAny(Path.GetInvalidPathChars()) >= 0;

View File

@@ -119,7 +119,7 @@ namespace NzbDrone.Common.Http.Dispatchers
}
else
{
data = responseMessage.Content.ReadAsByteArrayAsync(cts.Token).GetAwaiter().GetResult();
data = await responseMessage.Content.ReadAsByteArrayAsync(cts.Token);
}
}
catch (Exception ex)

View File

@@ -221,11 +221,18 @@ namespace NzbDrone.Common.Http
};
}
sourceContainer.Add((Uri)request.Url, cookie);
if (request.StoreRequestCookie)
try
{
presistentContainer.Add((Uri)request.Url, cookie);
sourceContainer.Add((Uri)request.Url, cookie);
if (request.StoreRequestCookie)
{
presistentContainer.Add((Uri)request.Url, cookie);
}
}
catch (CookieException ex)
{
_logger.Debug(ex, "Invalid cookie in {0}", (Uri)request.Url);
}
}
}
@@ -260,7 +267,14 @@ namespace NzbDrone.Common.Http
};
}
sourceContainer.Add((Uri)request.Url, cookie);
try
{
sourceContainer.Add((Uri)request.Url, cookie);
}
catch (CookieException ex)
{
_logger.Debug(ex, "Invalid cookie in {0}", (Uri)request.Url);
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace NzbDrone.Common.Serializer;
public class BooleanConverter : JsonConverter<bool>
{
public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.TokenType switch
{
JsonTokenType.True => true,
JsonTokenType.False => false,
JsonTokenType.Number => reader.GetInt64() switch
{
1 => true,
0 => false,
_ => throw new JsonException()
},
_ => throw new JsonException()
};
}
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
{
writer.WriteBooleanValue(value);
}
}

View File

@@ -36,6 +36,7 @@ namespace NzbDrone.Common.Serializer
serializerSettings.Converters.Add(new STJTimeSpanConverter());
serializerSettings.Converters.Add(new STJUtcConverter());
serializerSettings.Converters.Add(new DictionaryStringObjectConverter());
serializerSettings.Converters.Add(new BooleanConverter());
}
public static T Deserialize<T>(string json)

View File

@@ -6,9 +6,8 @@ using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.PassThePopcorn;
using NzbDrone.Core.Indexers.Definitions.PassThePopcorn;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
@@ -21,26 +20,22 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
Subject.Definition = new IndexerDefinition
{
Name = "PTP",
Settings = new PassThePopcornSettings() { APIUser = "asdf", APIKey = "sad" }
Settings = new PassThePopcornSettings
{
APIUser = "asdf",
APIKey = "sad"
}
};
}
[TestCase("Files/Indexers/PTP/imdbsearch.json")]
public async Task should_parse_feed_from_PTP(string fileName)
{
var authResponse = new PassThePopcornAuthResponse { Result = "Ok" };
var authStream = new System.IO.StringWriter();
Json.Serialize(authResponse, authStream);
var responseJson = ReadAllText(fileName);
Mocker.GetMock<IIndexerHttpClient>()
.Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Post), Subject.Definition))
.Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader(), new CookieCollection(), authStream.ToString())));
Mocker.GetMock<IIndexerHttpClient>()
.Setup(o => o.ExecuteProxiedAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get), Subject.Definition))
.Returns<HttpRequest, IndexerDefinition>((r, d) => Task.FromResult(new HttpResponse(r, new HttpHeader { ContentType = HttpAccept.Json.Value }, new CookieCollection(), responseJson)));

View File

@@ -202,9 +202,17 @@ namespace NzbDrone.Core.Applications
private bool ShouldHandleIndexer(ProviderDefinition app, ProviderDefinition indexer)
{
if (!indexer.Settings.Validate().IsValid)
{
_logger.Debug("Indexer {0} [{1}] has invalid settings.", indexer.Name, indexer.Id);
return false;
}
if (app.Tags.Empty())
{
_logger.Debug("No tags set to application {0}.", app.Name);
return true;
}
@@ -213,10 +221,12 @@ namespace NzbDrone.Core.Applications
if (intersectingTags.Any())
{
_logger.Debug("Application {0} and indexer {1} [{2}] have {3} intersecting (matching) tags.", app.Name, indexer.Name, indexer.Id, intersectingTags.Length);
return true;
}
_logger.Debug("Application {0} does not have any intersecting (matching) tags with {1} [{2}]. Indexer will neither be synced to nor removed from the application.", app.Name, indexer.Name, indexer.Id);
return false;
}

View File

@@ -52,7 +52,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
.Configure<ProcessorOptions>(opt =>
{
opt.PreviewOnly = false;
opt.Timeout = TimeSpan.FromSeconds(60);
opt.Timeout = TimeSpan.FromMinutes(10);
})
.Configure<SelectingProcessorAccessorOptions>(cfg =>
{

View File

@@ -108,6 +108,7 @@ namespace NzbDrone.Core.IndexerSearch
GetNabElement("files", r.Files, protocol),
GetNabElement("grabs", r.Grabs, protocol),
GetNabElement("peers", t.Peers, protocol),
r.Year == 0 ? null : GetNabElement("year", r.Year, protocol),
GetNabElement("author", RemoveInvalidXMLChars(r.Author), protocol),
GetNabElement("booktitle", RemoveInvalidXMLChars(r.BookTitle), protocol),
GetNabElement("artist", RemoveInvalidXMLChars(r.Artist), protocol),

View File

@@ -67,7 +67,9 @@ namespace NzbDrone.Core.IndexerSearch
searchSpec.Year = request.year;
searchSpec.Genre = request.genre;
return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
var releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
return new NewznabResults { Releases = DeDupeReleases(releases) };
}
private async Task<NewznabResults> MusicSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
@@ -81,7 +83,9 @@ namespace NzbDrone.Core.IndexerSearch
searchSpec.Track = request.track;
searchSpec.Year = request.year;
return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
var releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
return new NewznabResults { Releases = DeDupeReleases(releases) };
}
private async Task<NewznabResults> TvSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
@@ -102,7 +106,9 @@ namespace NzbDrone.Core.IndexerSearch
searchSpec.Year = request.year;
searchSpec.Genre = request.genre;
return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
var releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
return new NewznabResults { Releases = DeDupeReleases(releases) };
}
private async Task<NewznabResults> BookSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
@@ -115,14 +121,18 @@ namespace NzbDrone.Core.IndexerSearch
searchSpec.Year = request.year;
searchSpec.Genre = request.genre;
return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
var releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
return new NewznabResults { Releases = DeDupeReleases(releases) };
}
private async Task<NewznabResults> BasicSearch(NewznabRequest request, List<int> indexerIds, bool interactiveSearch)
{
var searchSpec = Get<BasicSearchCriteria>(request, indexerIds, interactiveSearch);
return new NewznabResults { Releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec) };
var releases = await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec);
return new NewznabResults { Releases = DeDupeReleases(releases) };
}
private TSpec Get<TSpec>(NewznabRequest query, List<int> indexerIds, bool interactiveSearch)
@@ -265,5 +275,13 @@ namespace NzbDrone.Core.IndexerSearch
return Array.Empty<ReleaseInfo>();
}
private List<ReleaseInfo> DeDupeReleases(IList<ReleaseInfo> releases)
{
// De-dupe reports by guid so duplicate results aren't returned. Pick the one with the higher indexer priority.
return releases.GroupBy(r => r.Guid)
.Select(r => r.OrderBy(v => v.IndexerPriority).First())
.ToList();
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using NLog;
@@ -5,6 +6,7 @@ using NzbDrone.Common.Http;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Definitions.Gazelle;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions;
@@ -15,6 +17,9 @@ public class AlphaRatio : GazelleBase<AlphaRatioSettings>
public override string[] IndexerUrls => new[] { "https://alpharatio.cc/" };
public override string Description => "AlphaRatio(AR) is a Private Torrent Tracker for 0DAY / GENERAL";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsPagination => true;
public override int PageSize => 50;
public override TimeSpan RateLimit => TimeSpan.FromSeconds(3);
public AlphaRatio(IIndexerHttpClient httpClient,
IEventAggregator eventAggregator,
@@ -39,6 +44,8 @@ public class AlphaRatio : GazelleBase<AlphaRatioSettings>
{
var caps = new IndexerCapabilities
{
LimitsDefault = PageSize,
LimitsMax = PageSize,
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
@@ -98,9 +105,9 @@ public class AlphaRatioRequestGenerator : GazelleRequestGenerator
_settings = settings;
}
protected override NameValueCollection GetBasicSearchParameters(string term, int[] categories)
protected override NameValueCollection GetBasicSearchParameters(SearchCriteriaBase searchCriteria, string term)
{
var parameters = base.GetBasicSearchParameters(term, categories);
var parameters = base.GetBasicSearchParameters(searchCriteria, term);
if (_settings.FreeleechOnly)
{
@@ -112,6 +119,12 @@ public class AlphaRatioRequestGenerator : GazelleRequestGenerator
parameters.Set("scene", "0");
}
if (searchCriteria.Limit is > 0 && searchCriteria.Offset is > 0)
{
var page = (int)(searchCriteria.Offset / searchCriteria.Limit) + 1;
parameters.Set("page", page.ToString());
}
return parameters;
}
}

View File

@@ -200,7 +200,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("div#content table > tbody > tr");
foreach (var row in rows)

View File

@@ -77,7 +77,7 @@ namespace NzbDrone.Core.Indexers.Definitions
else
{
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(response.Content);
using var document = await parser.ParseDocumentAsync(response.Content);
var errorMessage = document.QuerySelector("#content .berror .berror_c")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -433,7 +433,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var torrentInfos = new List<TorrentInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
foreach (var t in dom.QuerySelectorAll("#tabs .torrent_c > div"))
{
@@ -465,7 +465,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var links = dom.QuerySelectorAll(".searchitem > h3 > a[href], #dle-content > .story > .story_h > .lcol > h2 > a[href]");
foreach (var link in links)

View File

@@ -571,8 +571,6 @@ namespace NzbDrone.Core.Indexers.Definitions
};
releaseInfos.Add(release);
continue;
}
}
@@ -699,7 +697,7 @@ namespace NzbDrone.Core.Indexers.Definitions
[FieldDefinition(8, Label = "Enable Sonarr Compatibility", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr try to add Season information into Release names, without this Sonarr can't match any Seasons, but it has a lot of false positives as well")]
public bool EnableSonarrCompatibility { get; set; }
[FieldDefinition(9, Label = "Use Filenames for Single Episodes", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr replace AnimeBytes release names with the actual filename, this currently only works for single episode releases")]
[FieldDefinition(9, Label = "Use Filenames for Single Episodes", Type = FieldType.Checkbox, HelpText = "Add a release using the actual filename, this currently only works for single episode releases")]
public bool UseFilenameForSingleEpisodes { get; set; }
[FieldDefinition(10, Label = "Add Japanese title as a synonym", Type = FieldType.Checkbox, HelpText = "Makes Prowlarr add Japanese titles as synonyms, i.e kanji/hiragana/katakana.")]

View File

@@ -275,7 +275,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("table tr");
foreach (var (row, index) in rows.Skip(1).Select((v, i) => (v, i)))

View File

@@ -17,6 +17,7 @@ using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete("Site is unusable due to a mix of HTTP errors")]
public class Animedia : TorrentIndexerBase<NoAuthTorrentBaseSettings>
{
public override string Name => "Animedia";
@@ -252,7 +253,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var torrentInfos = new List<TorrentInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
foreach (var t in dom.QuerySelectorAll("ul.media__tabs__nav > li > a"))
{
@@ -290,7 +291,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var links = dom.QuerySelectorAll("a.ads-list__item__title");
foreach (var link in links)

View File

@@ -72,7 +72,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var errorMessage = dom.QuerySelector("form#loginform")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -206,7 +206,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var doc = parser.ParseDocument(indexerResponse.Content);
using var doc = parser.ParseDocument(indexerResponse.Content);
var rows = doc.QuerySelectorAll("table.torrent_table > tbody > tr.torrent");
foreach (var row in rows)
{

View File

@@ -37,7 +37,7 @@ public class AroLol : GazelleBase<AroLolSettings>
if (response.Content.Contains("loginform"))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var errorMessage = dom.QuerySelector("#loginform > .warning")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");

View File

@@ -88,7 +88,7 @@ public class AudioBookBay : TorrentIndexerBase<NoAuthTorrentBaseSettings>
var response = await _httpClient.ExecuteProxiedAsync(request, Definition);
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var hash = dom.QuerySelector("td:contains(\"Info Hash:\") ~ td")?.TextContent.Trim();
if (hash == null)
@@ -269,7 +269,7 @@ public class AudioBookBayParser : IParseIndexerResponse
{
var releaseInfos = new List<ReleaseInfo>();
var doc = ParseHtmlDocument(indexerResponse.Content);
using var doc = ParseHtmlDocument(indexerResponse.Content);
var rows = doc.QuerySelectorAll("div.post:has(div[class=\"postTitle\"])");
foreach (var row in rows)

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace NzbDrone.Core.Indexers.Definitions.Avistaz
{
@@ -9,34 +9,34 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public string Download { get; set; }
public Dictionary<string, string> Category { get; set; }
[JsonProperty(PropertyName = "movie_tv")]
[JsonPropertyName("movie_tv")]
public AvistazIdInfo MovieTvinfo { get; set; }
[JsonProperty(PropertyName = "created_at")]
[JsonPropertyName("created_at")]
public string CreatedAt { get; set; }
[JsonProperty(PropertyName = "file_name")]
[JsonPropertyName("file_name")]
public string FileName { get; set; }
[JsonProperty(PropertyName = "info_hash")]
[JsonPropertyName("info_hash")]
public string InfoHash { get; set; }
public int? Leech { get; set; }
public int? Completed { get; set; }
public int? Seed { get; set; }
[JsonProperty(PropertyName = "file_size")]
[JsonPropertyName("file_size")]
public long? FileSize { get; set; }
[JsonProperty(PropertyName = "file_count")]
[JsonPropertyName("file_count")]
public int? FileCount { get; set; }
[JsonProperty(PropertyName = "download_multiply")]
[JsonPropertyName("download_multiply")]
public double? DownloadMultiply { get; set; }
[JsonProperty(PropertyName = "upload_multiply")]
[JsonPropertyName("upload_multiply")]
public double? UploadMultiply { get; set; }
[JsonProperty(PropertyName = "video_quality")]
[JsonPropertyName("video_quality")]
public string VideoQuality { get; set; }
public string Type { get; set; }
public List<AvistazLanguage> Audio { get; set; }
@@ -64,21 +64,10 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
public string Tmdb { get; set; }
public string Tvdb { get; set; }
public string Imdb { get; set; }
public string Title { get; set; }
[JsonProperty(PropertyName = "tv_episode")]
public string TvEpisode { get; set; }
[JsonProperty(PropertyName = "tv_season")]
public string TVSeason { get; set; }
[JsonProperty(PropertyName = "tv_full_season")]
public bool TVFullSeason { get; set; }
}
public class AvistazAuthResponse
{
public string Token { get; set; }
public string Expiry { get; set; }
}
}

View File

@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Messaging.Events;
@@ -122,10 +123,11 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
.Accept(HttpAccept.Json)
.Build();
var response = await _httpClient.PostAsync<AvistazAuthResponse>(authLoginRequest);
var token = response.Resource.Token;
var response = await ExecuteAuth(authLoginRequest);
return token;
var authResponse = STJson.Deserialize<AvistazAuthResponse>(response.Content);
return authResponse.Token;
}
}
}

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Net;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@@ -42,9 +43,9 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from indexer request, expected {HttpAccept.Json.Value}");
}
var jsonResponse = new HttpResponse<AvistazResponse>(indexerResponse.HttpResponse);
var jsonResponse = STJson.Deserialize<AvistazResponse>(indexerResponse.HttpResponse.Content);
foreach (var row in jsonResponse.Resource.Data)
foreach (var row in jsonResponse.Data)
{
var details = row.Url;
var link = row.Download;

View File

@@ -72,7 +72,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var messageEl = dom.QuerySelectorAll("#loginform");
var messages = new List<string>();
for (var i = 0; i < 13; i++)
@@ -242,7 +242,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("#torrent_table > tbody > tr.torrent");
foreach (var row in rows)

View File

@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var response = await _httpClient.ExecuteProxiedAsync(request, Definition);
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var downloadLink = dom.QuerySelector(".download_link")?.GetAttribute("href");
if (downloadLink.IsNullOrWhiteSpace())
@@ -82,7 +82,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var loginPage = await ExecuteAuth(new HttpRequest(loginUrl));
var parser = new HtmlParser();
var dom = await parser.ParseDocumentAsync(loginPage.Content);
using var dom = await parser.ParseDocumentAsync(loginPage.Content);
var loginKey = dom.QuerySelector("input[name=\"loginKey\"]");
if (loginKey != null)
{
@@ -102,7 +102,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (CheckIfLoginNeeded(response))
{
var htmlParser = new HtmlParser();
var document = await htmlParser.ParseDocumentAsync(response.Content);
using var document = await htmlParser.ParseDocumentAsync(response.Content);
var errorMessage = document.QuerySelector("#loginError, .error")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -247,7 +247,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll(".torrents tr.torrent, .torrents tr.torrent_alt");
var currentCategories = new List<IndexerCategory> { NewznabStandardCategory.TVAnime };

View File

@@ -4,8 +4,8 @@ using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json.Serialization;
using FluentValidation;
using Newtonsoft.Json;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
@@ -19,6 +19,7 @@ using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
using static Newtonsoft.Json.Formatting;
namespace NzbDrone.Core.Indexers.Definitions
{
@@ -163,7 +164,7 @@ namespace NzbDrone.Core.Indexers.Definitions
Method = HttpMethod.Post
};
request.SetContent(body.ToJson());
request.ContentSummary = body.ToJson(Formatting.None);
request.ContentSummary = body.ToJson(None);
yield return new IndexerRequest(request);
}
@@ -245,16 +246,16 @@ namespace NzbDrone.Core.Indexers.Definitions
throw new IndexerAuthException("API Key invalid or not authorized");
}
var jsonResponse = new HttpResponse<BeyondHDResponse>(indexerHttpResponse);
var jsonResponse = STJson.Deserialize<BeyondHDResponse>(indexerResponse.Content);
if (jsonResponse.Resource.StatusCode == 0)
if (jsonResponse.StatusCode == 0)
{
throw new IndexerException(indexerResponse, $"Indexer Error: {jsonResponse.Resource.StatusMessage}");
throw new IndexerException(indexerResponse, $"Indexer Error: {jsonResponse.StatusMessage}");
}
var releaseInfos = new List<ReleaseInfo>();
foreach (var row in jsonResponse.Resource.Results)
foreach (var row in jsonResponse.Results)
{
var details = row.InfoUrl;
var link = row.DownloadLink;
@@ -412,10 +413,10 @@ namespace NzbDrone.Core.Indexers.Definitions
public class BeyondHDResponse
{
[JsonProperty(PropertyName = "status_code")]
[JsonPropertyName("status_code")]
public int StatusCode { get; set; }
[JsonProperty(PropertyName = "status_message")]
[JsonPropertyName("status_message")]
public string StatusMessage { get; set; }
public List<BeyondHDTorrent> Results { get; set; }
}
@@ -424,36 +425,42 @@ namespace NzbDrone.Core.Indexers.Definitions
{
public string Name { get; set; }
[JsonProperty(PropertyName = "info_hash")]
[JsonPropertyName("info_hash")]
public string InfoHash { get; set; }
public string Category { get; set; }
public string Type { get; set; }
public long Size { get; set; }
[JsonProperty(PropertyName = "times_completed")]
[JsonPropertyName("times_completed")]
public int Grabs { get; set; }
public int Seeders { get; set; }
public int Leechers { get; set; }
[JsonProperty(PropertyName = "created_at")]
[JsonPropertyName("created_at")]
public string CreatedAt { get; set; }
[JsonProperty(PropertyName = "download_url")]
[JsonPropertyName("download_url")]
public string DownloadLink { get; set; }
[JsonProperty(PropertyName = "url")]
[JsonPropertyName("url")]
public string InfoUrl { get; set; }
[JsonProperty(PropertyName = "imdb_id")]
[JsonPropertyName("imdb_id")]
public string ImdbId { get; set; }
[JsonProperty(PropertyName = "tmdb_id")]
[JsonPropertyName("tmdb_id")]
public string TmdbId { get; set; }
public bool Freeleech { get; set; }
public bool Promo25 { get; set; }
public bool Promo50 { get; set; }
public bool Promo75 { get; set; }
public bool Limited { get; set; }
public bool Internal { get; set; }
}
}

View File

@@ -161,7 +161,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var doc = parser.ParseDocument(indexerResponse.Content);
using var doc = parser.ParseDocument(indexerResponse.Content);
var rows = doc.QuerySelectorAll("table.xMenuT > tbody > tr").Skip(1);
foreach (var row in rows)
{

View File

@@ -185,7 +185,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
foreach (var child in dom.QuerySelectorAll("#needseed"))
{
child.Remove();

View File

@@ -374,7 +374,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
var newvalue = reReplaceRegexMatches.Groups[3].Value;
var replaceRegex = new Regex(regexp);
var input = (string)variables[variable];
var input = (string)variables[variable] ?? string.Empty;
var expanded = replaceRegex.Replace(input, newvalue);
if (modifier != null)

View File

@@ -598,7 +598,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
}
var resultParser = new HtmlParser();
var resultDocument = resultParser.ParseDocument(loginResult.Content);
using var resultDocument = resultParser.ParseDocument(loginResult.Content);
foreach (var error in errorBlocks)
{
var selection = resultDocument.QuerySelector(error.Selector);
@@ -984,7 +984,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
var selectorText = ApplyGoTemplateText(selector.Selector, variables);
var parser = new HtmlParser();
var resultDocument = parser.ParseDocument(response.Content);
using var resultDocument = parser.ParseDocument(response.Content);
var element = resultDocument.QuerySelector(selectorText);
if (element == null)
@@ -1045,7 +1045,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
if (_definition.Login.Test?.Selector != null && (response.Headers.ContentType?.Contains("text/html") ?? true))
{
var parser = new HtmlParser();
var document = parser.ParseDocument(response.Content);
using var document = parser.ParseDocument(response.Content);
var selection = document.QuerySelectorAll(_definition.Login.Test.Selector);
if (selection.Length == 0)

View File

@@ -1,28 +1,40 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace NzbDrone.Core.Indexers.Definitions.FileList;
public class FileListTorrent
{
public string Id { get; set; }
public uint Id { get; set; }
public string Name { get; set; }
public long Size { get; set; }
public int Leechers { get; set; }
public int Seeders { get; set; }
[JsonProperty(PropertyName = "times_completed")]
[JsonPropertyName("times_completed")]
public uint TimesCompleted { get; set; }
public uint Comments { get; set; }
public uint Files { get; set; }
[JsonProperty(PropertyName = "imdb")]
[JsonPropertyName("imdb")]
public string ImdbId { get; set; }
public bool Internal { get; set; }
[JsonProperty(PropertyName = "freeleech")]
[JsonPropertyName("freeleech")]
public bool FreeLeech { get; set; }
[JsonProperty(PropertyName = "doubleup")]
[JsonPropertyName("doubleup")]
public bool DoubleUp { get; set; }
[JsonProperty(PropertyName = "upload_date")]
[JsonPropertyName("upload_date")]
public string UploadDate { get; set; }
public string Category { get; set; }
[JsonProperty(PropertyName = "small_description")]
[JsonPropertyName("small_description")]
public string SmallDescription { get; set; }
}

View File

@@ -3,8 +3,8 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using Newtonsoft.Json;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser.Model;
@@ -35,7 +35,7 @@ public class FileListParser : IParseIndexerResponse
var releaseInfos = new List<ReleaseInfo>();
var results = JsonConvert.DeserializeObject<List<FileListTorrent>>(indexerResponse.Content);
var results = STJson.Deserialize<List<FileListTorrent>>(indexerResponse.Content);
foreach (var row in results)
{
@@ -54,7 +54,7 @@ public class FileListParser : IParseIndexerResponse
}
var imdbId = 0;
if (row.ImdbId != null && row.ImdbId.Length > 2)
if (row.ImdbId is { Length: > 2 })
{
imdbId = int.Parse(row.ImdbId.Substring(2));
}
@@ -64,7 +64,7 @@ public class FileListParser : IParseIndexerResponse
releaseInfos.Add(new TorrentInfo
{
Guid = string.Format("FileList-{0}", id),
Guid = $"FileList-{id}",
Title = row.Name,
Size = row.Size,
Categories = _categories.MapTrackerCatDescToNewznab(row.Category),
@@ -91,21 +91,21 @@ public class FileListParser : IParseIndexerResponse
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
private string GetDownloadUrl(string torrentId)
private string GetDownloadUrl(uint torrentId)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/download.php")
.AddQueryParam("id", torrentId)
.AddQueryParam("id", torrentId.ToString())
.AddQueryParam("passkey", _settings.Passkey);
return url.FullUri;
}
private string GetInfoUrl(string torrentId)
private string GetInfoUrl(uint torrentId)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/details.php")
.AddQueryParam("id", torrentId);
.AddQueryParam("id", torrentId.ToString());
return url.FullUri;
}

View File

@@ -70,7 +70,7 @@ public class FunFile : TorrentIndexerBase<UserPassTorrentBaseSettings>
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = await parser.ParseDocumentAsync(response.Content);
var errorMessage = dom.QuerySelector("td.mf_content")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -276,7 +276,7 @@ public class FunFileParser : IParseIndexerResponse
var releaseInfos = new List<TorrentInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("table.mainframe table[cellpadding=\"2\"] > tbody > tr:has(td.row3)");
foreach (var row in rows)

View File

@@ -46,7 +46,7 @@ public class GazelleRequestGenerator : IIndexerRequestGenerator
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = GetBasicSearchParameters(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories);
var parameters = GetBasicSearchParameters(searchCriteria, searchCriteria.SanitizedSearchTerm);
if (searchCriteria.ImdbId != null)
{
@@ -62,7 +62,7 @@ public class GazelleRequestGenerator : IIndexerRequestGenerator
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = GetBasicSearchParameters(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories);
var parameters = GetBasicSearchParameters(searchCriteria, searchCriteria.SanitizedSearchTerm);
if (searchCriteria.Artist.IsNotNullOrWhiteSpace() && searchCriteria.Artist != "VA")
{
@@ -88,7 +88,7 @@ public class GazelleRequestGenerator : IIndexerRequestGenerator
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = GetBasicSearchParameters(searchCriteria.SanitizedTvSearchString, searchCriteria.Categories);
var parameters = GetBasicSearchParameters(searchCriteria, searchCriteria.SanitizedTvSearchString);
if (searchCriteria.ImdbId != null)
{
@@ -104,7 +104,7 @@ public class GazelleRequestGenerator : IIndexerRequestGenerator
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = GetBasicSearchParameters(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories);
var parameters = GetBasicSearchParameters(searchCriteria, searchCriteria.SanitizedSearchTerm);
pageableRequests.Add(GetRequest(parameters));
return pageableRequests;
@@ -114,7 +114,7 @@ public class GazelleRequestGenerator : IIndexerRequestGenerator
{
var pageableRequests = new IndexerPageableRequestChain();
var parameters = GetBasicSearchParameters(searchCriteria.SanitizedSearchTerm, searchCriteria.Categories);
var parameters = GetBasicSearchParameters(searchCriteria, searchCriteria.SanitizedSearchTerm);
pageableRequests.Add(GetRequest(parameters));
return pageableRequests;
@@ -123,7 +123,7 @@ public class GazelleRequestGenerator : IIndexerRequestGenerator
// hook to adjust the search term
protected virtual string GetSearchTerm(string term) => term;
protected virtual NameValueCollection GetBasicSearchParameters(string term, int[] categories)
protected virtual NameValueCollection GetBasicSearchParameters(SearchCriteriaBase searchCriteria, string term)
{
var parameters = new NameValueCollection
{
@@ -139,9 +139,10 @@ public class GazelleRequestGenerator : IIndexerRequestGenerator
parameters.Set("searchstr", searchTerm.Replace(".", " "));
}
if (categories != null)
if (searchCriteria.Categories != null && searchCriteria.Categories.Any())
{
var queryCats = Capabilities.Categories.MapTorznabCapsToTrackers(categories);
var queryCats = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories);
if (queryCats.Any())
{
queryCats.ForEach(cat => parameters.Set($"filter_cat[{cat}]", "1"));

View File

@@ -89,7 +89,7 @@ public class GreatPosterWallRequestGenerator : GazelleRequestGenerator
public override IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var parameters = GetBasicSearchParameters(searchCriteria.SearchTerm, searchCriteria.Categories);
var parameters = GetBasicSearchParameters(searchCriteria, searchCriteria.SearchTerm);
if (searchCriteria.ImdbId != null)
{
@@ -101,9 +101,9 @@ public class GreatPosterWallRequestGenerator : GazelleRequestGenerator
return pageableRequests;
}
protected override NameValueCollection GetBasicSearchParameters(string term, int[] categories)
protected override NameValueCollection GetBasicSearchParameters(SearchCriteriaBase searchCriteria, string term)
{
var parameters = base.GetBasicSearchParameters(term, categories);
var parameters = base.GetBasicSearchParameters(searchCriteria, term);
if (_settings.FreeleechOnly)
{

View File

@@ -73,7 +73,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var errorMessages = dom
.QuerySelectorAll("table.lista td.lista span[style*=\"#FF0000\"], table.lista td.header:contains(\"login attempts\")")
.Select(r => r.TextContent.Trim())

View File

@@ -74,7 +74,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (response.Content != null && !response.Content.ContainsIgnoreCase("If your browser doesn't have javascript enabled"))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = await parser.ParseDocumentAsync(response.Content);
var errorMessage = dom.QuerySelector("div > font[color=\"#FF0000\"]")?.TextContent.Trim();
@@ -256,7 +256,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var userInfo = dom.QuerySelector("table.navus tr");
var userRank = userInfo?.Children[1].TextContent.Replace("Rank:", string.Empty).Trim();

View File

@@ -291,7 +291,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var doc = parser.ParseDocument(indexerResponse.Content);
using var doc = parser.ParseDocument(indexerResponse.Content);
var rows = doc.QuerySelectorAll("table[id=\"torrents\"] > tbody > tr");
foreach (var row in rows)

View File

@@ -266,7 +266,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("table#sortabletable > tbody > tr:has(a[href*=\"details.php?id=\"])");
foreach (var row in rows)

View File

@@ -77,7 +77,7 @@ public class Libble : TorrentIndexerBase<LibbleSettings>
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var errorMessage = dom.QuerySelector("#loginform > .warning")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -238,7 +238,7 @@ public class LibbleParser : IParseIndexerResponse
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var doc = parser.ParseDocument(indexerResponse.Content);
using var doc = parser.ParseDocument(indexerResponse.Content);
var groups = doc.QuerySelectorAll("table#torrent_table > tbody > tr.group:has(strong > a[href*=\"torrents.php?id=\"])");
foreach (var group in groups)

View File

@@ -177,7 +177,7 @@ public class MoreThanTVParser : IParseIndexerResponse
try
{
var parser = new HtmlParser();
var document = parser.ParseDocument(indexerResponse.Content);
using var document = parser.ParseDocument(indexerResponse.Content);
var torrents = document.QuerySelectorAll("#torrent_table > tbody > tr.torrent");
var movies = new[] { "movie" };
var tv = new[] { "season", "episode" };

View File

@@ -1,14 +1,17 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions;
@@ -65,6 +68,26 @@ namespace NzbDrone.Core.Indexers.Definitions
return Task.FromResult(request);
}
protected override IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
{
var cleanReleases = base.CleanupReleases(releases, searchCriteria);
return FilterReleasesByQuery(cleanReleases, searchCriteria).ToList();
}
protected override IEnumerable<ReleaseInfo> FilterReleasesByQuery(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
{
if (!searchCriteria.IsRssSearch &&
searchCriteria.IsIdSearch &&
searchCriteria is TvSearchCriteria tvSearchCriteria &&
tvSearchCriteria.EpisodeSearchString.IsNotNullOrWhiteSpace())
{
releases = releases.Where(r => r.Title.IsNotNullOrWhiteSpace() && r.Title.ContainsIgnoreCase(tvSearchCriteria.EpisodeSearchString)).ToList();
}
return releases;
}
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
@@ -208,7 +231,7 @@ namespace NzbDrone.Core.Indexers.Definitions
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request");
}
var jsonResponse = new HttpResponse<JsonRpcResponse<NebulanceTorrents>>(indexerResponse.HttpResponse).Resource;
var jsonResponse = STJson.Deserialize<JsonRpcResponse<NebulanceTorrents>>(indexerResponse.HttpResponse.Content);
if (jsonResponse.Error != null || jsonResponse.Result == null)
{
@@ -226,9 +249,11 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var details = _settings.BaseUrl + "torrents.php?id=" + row.TorrentId;
var title = row.ReleaseTitle.IsNotNullOrWhiteSpace() ? row.ReleaseTitle : row.GroupName;
var release = new TorrentInfo
{
Title = row.ReleaseTitle,
Title = title,
Guid = details,
InfoUrl = details,
PosterUrl = row.Banner,
@@ -297,23 +322,24 @@ namespace NzbDrone.Core.Indexers.Definitions
public class NebulanceTorrent
{
[JsonProperty(PropertyName = "rls_name")]
[JsonPropertyName("rls_name")]
public string ReleaseTitle { get; set; }
public string Title { get; set; }
[JsonProperty(PropertyName = "cat")]
[JsonPropertyName("cat")]
public string Category { get; set; }
public string Size { get; set; }
public string Seed { get; set; }
public string Leech { get; set; }
public string Snatch { get; set; }
public string Download { get; set; }
[JsonProperty(PropertyName = "file_list")]
[JsonPropertyName("file_list")]
public string[] FileList { get; set; }
[JsonProperty(PropertyName = "series_banner")]
[JsonPropertyName("group_name")]
public string GroupName { get; set; }
[JsonPropertyName("series_banner")]
public string Banner { get; set; }
[JsonProperty(PropertyName = "group_id")]
[JsonPropertyName("group_id")]
public string TorrentId { get; set; }
[JsonProperty(PropertyName = "rls_utc")]
[JsonPropertyName("rls_utc")]
public string PublishDateUtc { get; set; }
}

View File

@@ -156,20 +156,26 @@ namespace NzbDrone.Core.Indexers.Newznab
protected override List<string> GetLanguages(XElement item)
{
var languages = TryGetMultipleNewznabAttributes(item, "language");
var languageElements = TryGetMultipleNewznabAttributes(item, "language");
var results = new List<string>();
// Try to find <language> elements for some indexers that suck at following the rules.
if (languages.Count == 0)
if (languageElements.Count == 0)
{
languages = item.Elements("language").Select(e => e.Value).ToList();
languageElements = item.Elements("language").Select(e => e.Value).ToList();
}
foreach (var language in languages)
foreach (var languageElement in languageElements)
{
if (language.IsNotNullOrWhiteSpace())
var languages = languageElement.Split(',',
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
foreach (var language in languages)
{
results.Add(language);
if (language.IsNotNullOrWhiteSpace())
{
results.Add(language);
}
}
}

View File

@@ -263,7 +263,7 @@ public class NorBitsParser : IParseIndexerResponse
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("#torrentTable > tbody > tr").Skip(1).ToCollection();

View File

@@ -3,7 +3,7 @@ using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.PassThePopcorn
namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
{
public class PassThePopcorn : TorrentIndexerBase<PassThePopcornSettings>
{
@@ -29,22 +29,20 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new PassThePopcornRequestGenerator
{
Settings = Settings,
HttpClient = _httpClient,
Logger = _logger
};
return new PassThePopcornRequestGenerator(Settings);
}
public override IParseIndexerResponse GetParser()
{
return new PassThePopcornParser(Settings, _logger);
}
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
SearchParams = new List<SearchParam>
{
SearchParam.Q
},
LimitsDefault = PageSize,
LimitsMax = PageSize,
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
@@ -73,16 +71,11 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
return caps;
}
public override IParseIndexerResponse GetParser()
{
return new PassThePopcornParser(Settings, Capabilities, _logger);
}
}
public class PassThePopcornFlag : IndexerFlag
{
public static IndexerFlag Golden => new IndexerFlag("golden", "Release follows Golden Popcorn quality rules");
public static IndexerFlag Approved => new IndexerFlag("approved", "Release approved by PTP");
public static IndexerFlag Golden => new ("golden", "Release follows Golden Popcorn quality rules");
public static IndexerFlag Approved => new ("approved", "Release approved by PTP");
}
}

View File

@@ -1,15 +1,28 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
namespace NzbDrone.Core.Indexers.PassThePopcorn
namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
{
public class Director
public class PassThePopcornResponse
{
public string Name { get; set; }
public string Id { get; set; }
public string TotalResults { get; set; }
public List<PassThePopcornMovie> Movies { get; set; }
public string Page { get; set; }
public string AuthKey { get; set; }
public string PassKey { get; set; }
}
public class Torrent
public class PassThePopcornMovie
{
public string GroupId { get; set; }
public string Title { get; set; }
public string Year { get; set; }
public string Cover { get; set; }
public List<string> Tags { get; set; }
public string ImdbId { get; set; }
public List<PassThePopcornTorrent> Torrents { get; set; }
}
public class PassThePopcornTorrent
{
public int Id { get; set; }
public string Quality { get; set; }
@@ -19,7 +32,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
public string Resolution { get; set; }
public bool Scene { get; set; }
public string Size { get; set; }
public DateTime UploadTime { get; set; }
public string UploadTime { get; set; }
public string RemasterTitle { get; set; }
public string Snatched { get; set; }
public string Seeders { get; set; }
@@ -29,32 +42,4 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
public bool GoldenPopcorn { get; set; }
public string FreeleechType { get; set; }
}
public class Movie
{
public string GroupId { get; set; }
public string Title { get; set; }
public string Year { get; set; }
public string Cover { get; set; }
public List<string> Tags { get; set; }
public List<Director> Directors { get; set; }
public string ImdbId { get; set; }
public List<Torrent> Torrents { get; set; }
}
public class PassThePopcornResponse
{
public string TotalResults { get; set; }
public List<Movie> Movies { get; set; }
public string Page { get; set; }
public string AuthKey { get; set; }
public string PassKey { get; set; }
}
public class PassThePopcornAuthResponse
{
public string Result { get; set; }
public string Popcron { get; set; }
public string AntiCsrfToken { get; set; }
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using NLog;
using NzbDrone.Common.Extensions;
@@ -8,36 +9,28 @@ using NzbDrone.Common.Serializer;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.PassThePopcorn
namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
{
public class PassThePopcornParser : IParseIndexerResponse
{
private readonly IndexerCapabilities _capabilities;
private readonly PassThePopcornSettings _settings;
private readonly Logger _logger;
public PassThePopcornParser(PassThePopcornSettings settings, IndexerCapabilities capabilities, Logger logger)
public PassThePopcornParser(PassThePopcornSettings settings, Logger logger)
{
_settings = settings;
_capabilities = capabilities;
_logger = logger;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
var torrentInfos = new List<ReleaseInfo>();
var indexerHttpResponse = indexerResponse.HttpResponse;
if (indexerHttpResponse.StatusCode != HttpStatusCode.OK)
var httpResponse = indexerResponse.HttpResponse;
if (httpResponse.StatusCode != HttpStatusCode.OK)
{
// Remove cookie cache
if (indexerHttpResponse.HasHttpRedirect && indexerHttpResponse.RedirectUrl
.ContainsIgnoreCase("login.php"))
{
CookiesUpdater(null, null);
throw new IndexerAuthException("We are being redirected to the PTP login page. Most likely your session expired or was killed. Recheck your cookie or credentials and try testing the indexer.");
}
if (indexerHttpResponse.StatusCode == HttpStatusCode.Forbidden)
if (httpResponse.StatusCode == HttpStatusCode.Forbidden)
{
throw new RequestLimitReachedException(indexerResponse, "PTP Query Limit Reached. Please try again later.");
}
@@ -45,19 +38,13 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request");
}
if (indexerHttpResponse.Headers.ContentType != HttpAccept.Json.Value)
if (httpResponse.Headers.ContentType != HttpAccept.Json.Value)
{
if (indexerHttpResponse.Request.Url.Path.ContainsIgnoreCase("login.php"))
{
CookiesUpdater(null, null);
throw new IndexerAuthException("We are currently on the login page. Most likely your session expired or was killed. Try testing the indexer in the settings.");
}
// Remove cookie cache
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from indexer request, expected {HttpAccept.Json.Value}");
}
var jsonResponse = STJson.Deserialize<PassThePopcornResponse>(indexerResponse.Content);
if (jsonResponse.TotalResults == "0" ||
jsonResponse.TotalResults.IsNullOrWhiteSpace() ||
jsonResponse.Movies == null)
@@ -70,7 +57,6 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
foreach (var torrent in result.Torrents)
{
var id = torrent.Id;
var title = torrent.ReleaseName;
var flags = new HashSet<IndexerFlag>();
@@ -81,51 +67,32 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
if (torrent.Checked)
{
flags.Add(PassThePopcornFlag.Approved); //title = $"{title} ✔";
flags.Add(PassThePopcornFlag.Approved);
}
if (torrent.Scene)
torrentInfos.Add(new TorrentInfo
{
flags.Add(IndexerFlag.Scene);
}
var free = !(torrent.FreeleechType is null);
// Only add approved torrents
try
{
torrentInfos.Add(new TorrentInfo
{
Guid = string.Format("PassThePopcorn-{0}", id),
Title = title,
Size = long.Parse(torrent.Size),
DownloadUrl = GetDownloadUrl(id, jsonResponse.AuthKey, jsonResponse.PassKey),
InfoUrl = GetInfoUrl(result.GroupId, id),
Grabs = int.Parse(torrent.Snatched),
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = torrent.UploadTime.ToUniversalTime(),
ImdbId = result.ImdbId.IsNotNullOrWhiteSpace() ? int.Parse(result.ImdbId) : 0,
IndexerFlags = flags,
MinimumRatio = 1,
MinimumSeedTime = 345600,
DownloadVolumeFactor = free ? 0 : 1,
UploadVolumeFactor = 1,
Categories = new List<IndexerCategory> { NewznabStandardCategory.Movies }
});
}
catch (Exception e)
{
_logger.Error(e, "Encountered exception parsing PTP torrent: {" +
$"Size: {torrent.Size}" +
$"UploadTime: {torrent.UploadTime}" +
$"Seeders: {torrent.Seeders}" +
$"Leechers: {torrent.Leechers}" +
$"ReleaseName: {torrent.ReleaseName}" +
$"ID: {torrent.Id}" +
"}. Please immediately report this info on https://github.com/Prowlarr/Prowlarr/issues/1584.");
throw;
}
Guid = $"PassThePopcorn-{id}",
Title = torrent.ReleaseName,
Year = int.Parse(result.Year),
InfoUrl = GetInfoUrl(result.GroupId, id),
DownloadUrl = GetDownloadUrl(id, jsonResponse.AuthKey, jsonResponse.PassKey),
Categories = new List<IndexerCategory> { NewznabStandardCategory.Movies },
Size = long.Parse(torrent.Size),
Grabs = int.Parse(torrent.Snatched),
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = DateTime.Parse(torrent.UploadTime + " +0000", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
ImdbId = result.ImdbId.IsNotNullOrWhiteSpace() ? int.Parse(result.ImdbId) : 0,
Scene = torrent.Scene,
IndexerFlags = flags,
DownloadVolumeFactor = torrent.FreeleechType is "Freeleech" ? 0 : 1,
UploadVolumeFactor = 1,
MinimumRatio = 1,
MinimumSeedTime = 345600,
Genres = result.Tags ?? new List<string>(),
PosterUrl = GetPosterUrl(result.Cover)
});
}
}
@@ -155,5 +122,17 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
return url.FullUri;
}
private static string GetPosterUrl(string cover)
{
if (cover.IsNotNullOrWhiteSpace() &&
Uri.TryCreate(cover, UriKind.Absolute, out var posterUri) &&
(posterUri.Scheme == Uri.UriSchemeHttp || posterUri.Scheme == Uri.UriSchemeHttps))
{
return posterUri.AbsoluteUri;
}
return null;
}
}
}

View File

@@ -1,22 +1,21 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.PassThePopcorn
namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
{
public class PassThePopcornRequestGenerator : IIndexerRequestGenerator
{
public PassThePopcornSettings Settings { get; set; }
private readonly PassThePopcornSettings _settings;
public IDictionary<string, string> Cookies { get; set; }
public IIndexerHttpClient HttpClient { get; set; }
public Logger Logger { get; set; }
public PassThePopcornRequestGenerator(PassThePopcornSettings settings)
{
_settings = settings;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
@@ -34,51 +33,6 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
return pageableRequests;
}
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
private IEnumerable<IndexerRequest> GetRequest(string searchParameters, SearchCriteriaBase searchCriteria)
{
var queryParams = new NameValueCollection
{
{ "action", "advanced" },
{ "json", "noredirect" },
{ "grouping", "0" },
{ "searchstr", searchParameters }
};
if (searchCriteria.Limit is > 0 && searchCriteria.Offset is > 0)
{
var page = (int)(searchCriteria.Offset / searchCriteria.Limit) + 1;
queryParams.Set("page", page.ToString());
}
if (Settings.FreeleechOnly)
{
queryParams.Set("freetorrent", "1");
}
var request =
new IndexerRequest(
$"{Settings.BaseUrl.Trim().TrimEnd('/')}/torrents.php?{queryParams.GetQueryString()}",
HttpAccept.Json);
request.HttpRequest.Headers["ApiUser"] = Settings.APIUser;
request.HttpRequest.Headers["ApiKey"] = Settings.APIKey;
if (Settings.APIKey.IsNullOrWhiteSpace())
{
foreach (var cookie in Cookies)
{
request.HttpRequest.Cookies[cookie.Key] = cookie.Value;
}
CookiesUpdater(Cookies, DateTime.Now.AddDays(30));
}
yield return request;
}
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
@@ -102,5 +56,38 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetRequest(string searchParameters, SearchCriteriaBase searchCriteria)
{
var parameters = new NameValueCollection
{
{ "action", "advanced" },
{ "json", "noredirect" },
{ "grouping", "0" },
{ "searchstr", searchParameters }
};
if (searchCriteria.Limit is > 0 && searchCriteria.Offset is > 0)
{
var page = (int)(searchCriteria.Offset / searchCriteria.Limit) + 1;
parameters.Set("page", page.ToString());
}
if (_settings.FreeleechOnly)
{
parameters.Set("freetorrent", "1");
}
var searchUrl = $"{_settings.BaseUrl.Trim().TrimEnd('/')}/torrents.php?{parameters.GetQueryString()}";
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
request.HttpRequest.Headers.Add("ApiUser", _settings.APIUser);
request.HttpRequest.Headers.Add("ApiKey", _settings.APIKey);
yield return request;
}
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
}

View File

@@ -3,7 +3,7 @@ using NzbDrone.Core.Annotations;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.PassThePopcorn
namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
{
public class PassThePopcornSettingsValidator : NoAuthSettingsValidator<PassThePopcornSettings>
{

View File

@@ -234,7 +234,7 @@ public class PirateTheNetParser : IParseIndexerResponse
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("table.main > tbody > tr");
foreach (var row in rows.Skip(1))

View File

@@ -171,7 +171,7 @@ public class PixelHDParser : IParseIndexerResponse
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var groups = dom.QuerySelectorAll("div.browsePoster");
foreach (var group in groups)

View File

@@ -85,7 +85,7 @@ public class PreToMe : TorrentIndexerBase<PreToMeSettings>
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var errorMessage = dom.QuerySelector("table.body_table font[color~=\"red\"]")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -340,7 +340,7 @@ public class PreToMeParser : IParseIndexerResponse
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("table > tbody > tr.browse");
foreach (var row in rows)

View File

@@ -249,7 +249,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentInfos = new List<TorrentInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("#torrents-table > tbody > tr");
foreach (var row in rows.Skip(1))

View File

@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var response = await _httpClient.ExecuteProxiedAsync(request, Definition);
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var magnetLink = dom.QuerySelector("table.attach a.magnet-link[href^=\"magnet:?\"]")?.GetAttribute("href");
if (magnetLink == null)
@@ -104,7 +104,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (!response.Content.Contains("id=\"logged-in-username\""))
{
var parser = new HtmlParser();
var document = await parser.ParseDocumentAsync(response.Content);
using var document = await parser.ParseDocumentAsync(response.Content);
var errorMessage = document.QuerySelector("h4.warnColor1.tCenter.mrg_16, div.msg-main")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "RuTracker Auth Failed");
@@ -1580,7 +1580,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var doc = parser.ParseDocument(indexerResponse.Content);
using var doc = parser.ParseDocument(indexerResponse.Content);
var rows = doc.QuerySelectorAll("table#tor-tbl > tbody > tr");
foreach (var row in rows)

View File

@@ -225,7 +225,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var table = dom.QuerySelector("table.movehere");
if (table == null)

View File

@@ -78,7 +78,7 @@ public class Shazbat : TorrentIndexerBase<ShazbatSettings>
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = await parser.ParseDocumentAsync(response.Content);
var errorMessage = dom.QuerySelector("div#fail .modal-body")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -223,7 +223,7 @@ public class ShazbatParser : IParseIndexerResponse
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var hasGlobalFreeleech = dom.QuerySelector("span:contains(\"Freeleech until:\"):has(span.datetime)") != null;
@@ -303,7 +303,7 @@ public class ShazbatParser : IParseIndexerResponse
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
if (!hasGlobalFreeleech)
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
@@ -16,12 +17,11 @@ using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete("Site unavailable")]
public class Shizaproject : TorrentIndexerBase<NoAuthTorrentBaseSettings>
{
public override string Name => "ShizaProject";
public override string[] IndexerUrls => new string[] { "https://shiza-project.com/" };
public override string Description => "Shizaproject is russian anime voiceover group and eponymous anime tracker.";
public override string[] IndexerUrls => new[] { "https://shiza-project.com/" };
public override string Description => "ShizaProject Tracker is a Public RUSSIAN tracker and release group for ANIME";
public override string Language => "ru-RU";
public override Encoding Encoding => Encoding.UTF8;
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
@@ -34,7 +34,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new ShizaprojectRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
return new ShizaprojectRequestGenerator { Settings = Settings, Capabilities = Capabilities };
}
public override IParseIndexerResponse GetParser()
@@ -47,20 +47,22 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
}
{
MovieSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TVAnime, "TV");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVAnime, "TV_SPECIAL");
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.TVAnime, "ONA");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.TVAnime, "OVA");
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Movies, "MOVIE");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.Movies, "SHORT_MOVIE");
return caps;
}
}
@@ -93,6 +95,7 @@ namespace NzbDrone.Core.Indexers.Definitions
publishedAt
slug
torrents {
synopsis
downloaded
seeders
leechers
@@ -112,7 +115,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var queryCollection = new NameValueCollection
{
{ "query", query.Replace('\n', ' ').Trim() },
{ "variables", Newtonsoft.Json.JsonConvert.SerializeObject(variables) }
{ "variables", JsonConvert.SerializeObject(variables) }
};
var requestUrl = string.Format("{0}/graphql?", Settings.BaseUrl.TrimEnd('/')) + queryCollection.GetQueryString();
@@ -175,25 +178,26 @@ namespace NzbDrone.Core.Indexers.Definitions
_categories = categories;
}
private string composeTitle(ShizaprojectNode n, ShizaprojectTorrent tr)
private string ComposeTitle(ShizaprojectNode n, ShizaprojectTorrent tr)
{
var title = string.Format("{0} / {1}", n.Name, n.OriginalName);
foreach (var tl in n.AlternativeNames)
var allNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
title += " / " + tl;
n.Name,
n.OriginalName
};
allNames.UnionWith(n.AlternativeNames.ToHashSet());
var title = $"{string.Join(" / ", allNames)} {tr.Synopsis}";
if (tr.VideoQualities.Length > 0)
{
title += $" [{string.Join(" ", tr.VideoQualities)}]";
}
title += " [";
foreach (var q in tr.VideoQualities)
{
title += " " + q;
}
title += " ]";
return title;
}
private DateTime getActualPublishDate(ShizaprojectNode n, ShizaprojectTorrent t)
private DateTime GetActualPublishDate(ShizaprojectNode n, ShizaprojectTorrent t)
{
if (n.PublishedAt == null)
{
@@ -205,7 +209,7 @@ namespace NzbDrone.Core.Indexers.Definitions
}
}
private string getResolution(string[] qualities)
private string GetResolution(string[] qualities)
{
var resPrefix = "RESOLUTION_";
var res = Array.Find(qualities, s => s.StartsWith(resPrefix));
@@ -234,7 +238,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var torrentInfo = new TorrentInfo
{
Title = composeTitle(e.Node, tr),
Title = ComposeTitle(e.Node, tr),
InfoUrl = string.Format("{0}/releases/{1}/", _settings.BaseUrl.TrimEnd('/'), e.Node.Slug),
DownloadVolumeFactor = 0,
UploadVolumeFactor = 1,
@@ -242,12 +246,12 @@ namespace NzbDrone.Core.Indexers.Definitions
Peers = tr.Leechers + tr.Seeders,
Grabs = tr.Downloaded,
Categories = _categories.MapTrackerCatDescToNewznab(e.Node.Type),
PublishDate = getActualPublishDate(e.Node, tr),
PublishDate = GetActualPublishDate(e.Node, tr),
Guid = tr.File.Url,
DownloadUrl = tr.File.Url,
MagnetUrl = tr.MagnetUri,
Size = tr.Size,
Resolution = getResolution(tr.VideoQualities)
Resolution = GetResolution(tr.VideoQualities)
};
torrentInfos.Add(torrentInfo);
@@ -310,6 +314,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public class ShizaprojectTorrent
{
public string Synopsis { get; set; }
public int Downloaded { get; set; }
public int Seeders { get; set; }
public int Leechers { get; set; }

View File

@@ -96,7 +96,7 @@ public class SpeedCD : TorrentIndexerBase<SpeedCDSettings>
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var errorMessage = dom.QuerySelector("h5")?.TextContent.Trim();
if (response.Content.Contains("Wrong Captcha!"))
@@ -323,7 +323,7 @@ public class SpeedCDParser : IParseIndexerResponse
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("div.boxContent > table > tbody > tr");
foreach (var row in rows)

View File

@@ -43,7 +43,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new SubsPleaseRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
return new SubsPleaseRequestGenerator { Settings = Settings, Capabilities = Capabilities };
}
public override IParseIndexerResponse GetParser()
@@ -56,12 +56,17 @@ namespace NzbDrone.Core.Indexers.Definitions
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TVAnime, "Anime");
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.TVAnime);
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesOther);
return caps;
}
@@ -205,6 +210,11 @@ namespace NzbDrone.Core.Indexers.Definitions
UploadVolumeFactor = 1
};
if (value.Episode.ToLowerInvariant() == "movie")
{
release.Categories.Add(NewznabStandardCategory.MoviesOther);
}
// Ex: [SubsPlease] Shingeki no Kyojin (The Final Season) - 64 (1080p)
release.Title += $"[SubsPlease] {value.Show} - {value.Episode} ({d.Res}p)";
release.MagnetUrl = d.Magnet;

View File

@@ -75,7 +75,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var errorMessage = dom.QuerySelector("form#loginform")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -224,7 +224,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var doc = parser.ParseDocument(indexerResponse.Content);
using var doc = parser.ParseDocument(indexerResponse.Content);
// get params to build download link (user could be banned without those params)
var rssFeedUri = new Uri(_settings.BaseUrl + doc.QuerySelector("link[href^=\"/feeds.php?feed=\"]")

View File

@@ -74,7 +74,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = await parser.ParseDocumentAsync(response.Content);
var errorMessage = dom.QuerySelector("table.forumline table span.gen")?.FirstChild?.TextContent;
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -367,7 +367,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("table.forumline > tbody > tr[class*=prow]");
foreach (var row in rows)

View File

@@ -71,7 +71,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var errorMessage = dom.QuerySelector("td.embedded")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -245,7 +245,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var doc = parser.ParseDocument(indexerResponse.Content);
using var doc = parser.ParseDocument(indexerResponse.Content);
var rows = doc.QuerySelectorAll("table > tbody:has(tr > td.colhead) > tr:not(:has(td.colhead))");
foreach (var row in rows)
{

View File

@@ -77,14 +77,6 @@ namespace NzbDrone.Core.Indexers.Definitions
}
};
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.TVAnime, "Anime");
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.PC, "Appz/Packs");
caps.Categories.AddCategoryMapping(42, NewznabStandardCategory.AudioAudiobook, "Audio Books");
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.Books, "Books");
caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.TVDocumentary, "Documentary");
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.Other, "Fonts");
caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.PCMac, "Mac");
caps.Categories.AddCategoryMapping(96, NewznabStandardCategory.MoviesUHD, "Movie/4K");
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.MoviesSD, "Movies/480p");
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.MoviesBluRay, "Movies/Bluray");
@@ -97,31 +89,43 @@ namespace NzbDrone.Core.Indexers.Definitions
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.Movies, "Movies/x265");
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Movies/XviD");
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.AudioMP3, "Music/Audio");
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.AudioForeign, "Music/Non-English");
caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.Audio, "Music/Packs");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.AudioVideo, "Music/Video");
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.Audio, "Music/Flac");
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.AudioOther, "Podcast");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.PCGames, "PC/Games");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.ConsolePS3, "PS3");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.ConsolePSP, "PSP");
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.ConsoleWii, "Wii");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.ConsoleXBox360, "Xbox-360");
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVSD, "TV/480p");
caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.TVHD, "TV/Bluray");
caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.TVSD, "TV/DVD-R");
caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.TVSD, "TV/DVD-Rip");
caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.TVSD, "TV/Mobile");
caps.Categories.AddCategoryMapping(82, NewznabStandardCategory.TVForeign, "TV/Non-English");
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.TV, "TV/Packs");
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.TVSD, "TV/SD/x264");
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TVHD, "TV/x264");
caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.TVUHD, "TV/x265");
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVSD, "TV/XviD");
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.PCGames, "PC/Games");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.ConsolePS3, "PS");
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.ConsolePSP, "PSP");
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.ConsoleNDS, "Nintendo");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.ConsoleXBox, "Xbox");
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.AudioMP3, "Music/Audio");
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.Audio, "Music/Flac");
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.AudioForeign, "Music/Non-English");
caps.Categories.AddCategoryMapping(41, NewznabStandardCategory.Audio, "Music/Packs");
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.AudioVideo, "Music/Video");
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.TVAnime, "Anime");
caps.Categories.AddCategoryMapping(42, NewznabStandardCategory.AudioAudiobook, "Audio Books");
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.Books, "Books");
caps.Categories.AddCategoryMapping(102, NewznabStandardCategory.BooksForeign, "Books/Non-English");
caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.TVDocumentary, "Documentary");
caps.Categories.AddCategoryMapping(95, NewznabStandardCategory.TVDocumentary, "Educational");
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.Other, "Fonts");
caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.PCMac, "Mac");
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.AudioOther, "Podcast");
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.PC, "Softwa/Packs");
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.PC, "Software");
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.XXX, "XXX/0Day");
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.XXX, "XXX/Movies");
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.XXXPack, "XXX/Packs");

View File

@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
var torrentInfo = new TorrentInfo
{
Guid = GetGuid(torrent),
Title = torrent.release_name,
Title = WebUtility.HtmlDecode(torrent.release_name),
Categories = new List<IndexerCategory> { NewznabStandardCategory.Movies },
Size = torrent.size * 1000 * 1000,
DownloadUrl = torrent.download_url,

View File

@@ -19,7 +19,7 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(BuildRequest(searchCriteria.SearchTerm, searchCriteria.ImdbId));
pageableRequests.Add(BuildRequest(searchCriteria.SearchTerm, searchCriteria.FullImdbId));
return pageableRequests;
}

View File

@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentPotato
}
}
public class TorrentPotatoSettings : IIndexerSettings
public class TorrentPotatoSettings : ITorrentIndexerSettings
{
private static readonly TorrentPotatoSettingsValidator Validator = new ();

View File

@@ -46,7 +46,8 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentRss
ParseSizeInDescription = parserSettings.ParseSizeInDescription,
SizeElementName = parserSettings.SizeElementName,
DefaultReleaseSize = indexerSettings.DefaultReleaseSize
DefaultReleaseSize = indexerSettings.DefaultReleaseSize,
DefaultReleaseSeeders = 1
};
}

View File

@@ -65,7 +65,7 @@ public class Uniotaku : TorrentIndexerBase<UniotakuSettings>
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = await parser.ParseDocumentAsync(response.Content);
var errorMessage = dom.QuerySelector(".login-content span.text-red")?.TextContent.Trim();
throw new IndexerAuthException(errorMessage ?? "Unknown error message, please report.");
@@ -92,7 +92,7 @@ public class Uniotaku : TorrentIndexerBase<UniotakuSettings>
var response = await _httpClient.ExecuteProxiedAsync(request, Definition);
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = parser.ParseDocument(response.Content);
var downloadLink = dom.QuerySelector("a[href^=\"download.php?id=\"]")?.GetAttribute("href")?.Trim();
if (downloadLink == null)
@@ -250,9 +250,9 @@ public class UniotakuParser : IParseIndexerResponse
var publishDate = DateTime.Now;
foreach (var item in jsonContent.Value<JArray>("data"))
{
var detailsDom = parser.ParseDocument(item.SelectToken("[0]").Value<string>());
var categoryDom = parser.ParseDocument(item.SelectToken("[1]").Value<string>());
var groupDom = parser.ParseDocument(item.SelectToken("[7]").Value<string>());
using var detailsDom = parser.ParseDocument(item.SelectToken("[0]").Value<string>());
using var categoryDom = parser.ParseDocument(item.SelectToken("[1]").Value<string>());
using var groupDom = parser.ParseDocument(item.SelectToken("[7]").Value<string>());
var qTitleLink = detailsDom.QuerySelector("a[href^=\"torrents-details.php?id=\"]");
var title = qTitleLink?.TextContent.Trim();

View File

@@ -72,7 +72,7 @@ public class XSpeeds : TorrentIndexerBase<UserPassTorrentBaseSettings>
if (CheckIfLoginNeeded(response))
{
var parser = new HtmlParser();
var dom = parser.ParseDocument(response.Content);
using var dom = await parser.ParseDocumentAsync(response.Content);
var errorMessage = dom.QuerySelector(".left_side table:nth-of-type(1) tr:nth-of-type(2)")?.TextContent.Trim().Replace("\n\t", " ");
if (errorMessage.IsNullOrWhiteSpace())
{
@@ -289,7 +289,7 @@ public class XSpeedsParser : IParseIndexerResponse
var releaseInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var dom = parser.ParseDocument(indexerResponse.Content);
using var dom = parser.ParseDocument(indexerResponse.Content);
var rows = dom.QuerySelectorAll("table#sortabletable > tbody > tr:has(a[href*=\"details.php?id=\"])");
foreach (var row in rows)

View File

@@ -59,7 +59,7 @@ namespace NzbDrone.Core.Indexers.Definitions
// The first page set the cookies and the session_id
var loginPage = await ExecuteAuth(new HttpRequest(Login1Url));
var parser = new HtmlParser();
var dom = parser.ParseDocument(loginPage.Content);
using var dom = parser.ParseDocument(loginPage.Content);
var sessionId = dom.QuerySelector("input#session_id")?.GetAttribute("value");
if (string.IsNullOrWhiteSpace(sessionId))
{
@@ -315,7 +315,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var torrentInfos = new List<ReleaseInfo>();
var parser = new HtmlParser();
var doc = parser.ParseDocument(indexerResponse.Content);
using var doc = parser.ParseDocument(indexerResponse.Content);
var rows = doc.QuerySelectorAll("table.torrent_list > tbody > tr");

View File

@@ -363,7 +363,7 @@ namespace NzbDrone.Core.Indexers
}
}
releases.AddRange(pagedReleases);
releases.AddRange(pagedReleases.Where(IsValidRelease));
}
if (releases.Any())
@@ -469,6 +469,18 @@ namespace NzbDrone.Core.Indexers
return Capabilities ?? ((IndexerDefinition)Definition).Capabilities;
}
protected virtual bool IsValidRelease(ReleaseInfo release)
{
if (release.Title.IsNullOrWhiteSpace())
{
_logger.Error("Invalid Release: '{0}' from indexer: {1}. No title provided.", release.InfoUrl, Definition.Name);
return false;
}
return true;
}
protected virtual bool IsFullPage(IList<ReleaseInfo> page, int pageSize)
{
return pageSize != 0 && page.Count >= pageSize;

View File

@@ -149,7 +149,7 @@ namespace NzbDrone.Core.Indexers
return result.DistinctBy(v => v.Guid).ToList();
}
protected IEnumerable<ReleaseInfo> FilterReleasesByQuery(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
protected virtual IEnumerable<ReleaseInfo> FilterReleasesByQuery(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
{
var commonWords = new[] { "and", "the", "an", "of" };

View File

@@ -161,6 +161,7 @@ namespace NzbDrone.Core.Indexers
{
releaseInfo.Guid = GetGuid(item);
releaseInfo.Title = GetTitle(item);
releaseInfo.Description = GetDescription(item);
releaseInfo.PublishDate = GetPublishDate(item);
releaseInfo.DownloadUrl = GetDownloadUrl(item);
releaseInfo.InfoUrl = GetInfoUrl(item);
@@ -195,6 +196,11 @@ namespace NzbDrone.Core.Indexers
return item.TryGetValue("title", "Unknown");
}
protected virtual string GetDescription(XElement item)
{
return item.TryGetValue("description", null);
}
protected virtual ICollection<IndexerCategory> GetCategory(XElement item)
{
return new List<IndexerCategory> { NewznabStandardCategory.Other };

View File

@@ -34,6 +34,9 @@ namespace NzbDrone.Core.Indexers
// Default size for when release sizes aren't available
public double? DefaultReleaseSize { get; set; }
// Default value for when release seeders aren't available
public int? DefaultReleaseSeeders { get; set; }
public TorrentRssParser()
{
PreferredEnclosureMimeTypes = TorrentEnclosureMimeTypes;
@@ -145,7 +148,7 @@ namespace NzbDrone.Core.Indexers
return (int)seeds;
}
return null;
return DefaultReleaseSeeders;
}
protected virtual int? GetPeers(XElement item)
@@ -174,7 +177,7 @@ namespace NzbDrone.Core.Indexers
return int.Parse(itempeers.Value);
}
return null;
return DefaultReleaseSeeders;
}
protected override long GetSize(XElement item)

View File

@@ -347,5 +347,10 @@
"WhatsNew": "ما هو الجديد؟",
"minutes": "الدقائق",
"NotificationStatusAllClientHealthCheckMessage": "جميع القوائم غير متاحة بسبب الإخفاقات",
"NotificationStatusSingleClientHealthCheckMessage": "القوائم غير متاحة بسبب الإخفاقات: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "القوائم غير متاحة بسبب الإخفاقات: {0}",
"AuthBasic": "أساسي (المتصفح المنبثق)",
"AuthForm": "النماذج (صفحة تسجيل الدخول)",
"DisabledForLocalAddresses": "معطل بسبب العناوين المحلية",
"None": "لا شيء",
"ResetAPIKeyMessageText": "هل أنت متأكد أنك تريد إعادة تعيين مفتاح API الخاص بك؟"
}

View File

@@ -347,5 +347,10 @@
"WhatsNew": "Какво ново?",
"minutes": "Минути",
"NotificationStatusSingleClientHealthCheckMessage": "Списъци, недостъпни поради неуспехи: {0}",
"NotificationStatusAllClientHealthCheckMessage": "Всички списъци са недостъпни поради неуспехи"
"NotificationStatusAllClientHealthCheckMessage": "Всички списъци са недостъпни поради неуспехи",
"AuthBasic": "Основно (изскачащ прозорец на браузъра)",
"AuthForm": "Формуляри (Страница за вход)",
"DisabledForLocalAddresses": "Забранено за местни адреси",
"None": "Нито един",
"ResetAPIKeyMessageText": "Наистина ли искате да нулирате своя API ключ?"
}

View File

@@ -371,5 +371,10 @@
"DeleteAppProfileMessageText": "Esteu segur que voleu suprimir el perfil de qualitat {0}",
"NotificationStatusSingleClientHealthCheckMessage": "Llistes no disponibles a causa d'errors: {0}",
"AddConnection": "Edita la col·lecció",
"NotificationStatusAllClientHealthCheckMessage": "Totes les llistes no estan disponibles a causa d'errors"
"NotificationStatusAllClientHealthCheckMessage": "Totes les llistes no estan disponibles a causa d'errors",
"AuthBasic": "Basic (finestra emergent del navegador)",
"AuthForm": "Formularis (pàgina d'inici de sessió)",
"DisabledForLocalAddresses": "Desactivat per a adreces locals",
"None": "Cap",
"ResetAPIKeyMessageText": "Esteu segur que voleu restablir la clau de l'API?"
}

View File

@@ -383,5 +383,17 @@
"Applications": "Aplikace",
"Connect": "Oznámení",
"EditConnectionImplementation": "Přidat spojení - {implementationName}",
"EditDownloadClientImplementation": "Přidat klienta pro stahování - {implementationName}"
"EditDownloadClientImplementation": "Přidat klienta pro stahování - {implementationName}",
"AuthForm": "Formuláře (přihlašovací stránka)",
"Clone": "Klonovat",
"DefaultNameCopiedProfile": "{name} - Kopírovat",
"DisabledForLocalAddresses": "Zakázáno pro místní adresy",
"EditApplicationImplementation": "Přidat spojení - {implementationName}",
"None": "Žádný",
"ResetAPIKeyMessageText": "Opravdu chcete resetovat klíč API?",
"Database": "Databáze",
"CountDownloadClientsSelected": "{count} vybraných klientů ke stahování",
"CountIndexersSelected": "{count} vybraných indexátorů",
"EditIndexerProxyImplementation": "Přidat indexátor - {implementationName}",
"AuthBasic": "Základní (vyskakovací okno prohlížeče)"
}

View File

@@ -363,5 +363,10 @@
"ConnectionLostReconnect": "Radarr vil prøve at tilslutte automatisk, eller du kan klikke genindlæs forneden.",
"minutes": "Protokoller",
"NotificationStatusAllClientHealthCheckMessage": "Alle lister er utilgængelige på grund af fejl",
"NotificationStatusSingleClientHealthCheckMessage": "Lister utilgængelige på grund af fejl: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "Lister utilgængelige på grund af fejl: {0}",
"AuthForm": "Formularer (login-side)",
"DisabledForLocalAddresses": "Deaktiveret for lokale adresser",
"ResetAPIKeyMessageText": "Er du sikker på, at du vil nulstille din API-nøgle?",
"AuthBasic": "Grundlæggende (pop op-browser)",
"None": "Ingen"
}

View File

@@ -499,5 +499,10 @@
"DeleteAppProfileMessageText": "Qualitätsprofil '{0}' wirklich löschen?",
"AddConnection": "Sammlung bearbeiten",
"NotificationStatusAllClientHealthCheckMessage": "Wegen Fehlern sind keine Applikationen verfügbar",
"NotificationStatusSingleClientHealthCheckMessage": "Applikationen wegen folgender Fehler nicht verfügbar: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "Applikationen wegen folgender Fehler nicht verfügbar: {0}",
"AuthBasic": "Einfach (Browser Popup)",
"AuthForm": "Formular (Login Seite)",
"DisabledForLocalAddresses": "Für Lokale Adressen deaktivieren",
"None": "Keine",
"ResetAPIKeyMessageText": "Bist du sicher, dass du den API-Schlüssel zurücksetzen willst?"
}

View File

@@ -501,5 +501,11 @@
"DeleteAppProfileMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το προφίλ ποιότητας '{0}'?",
"AddConnection": "Προσθήκη Σύνδεσης",
"NotificationStatusAllClientHealthCheckMessage": "Όλες οι λίστες δεν είναι διαθέσιμες λόγω αστοχιών",
"NotificationStatusSingleClientHealthCheckMessage": "Μη διαθέσιμες λίστες λόγω αποτυχιών: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "Μη διαθέσιμες λίστες λόγω αποτυχιών: {0}",
"AuthBasic": "Βασικό (Αναδυόμενο παράθυρο προγράμματος περιήγησης)",
"AuthForm": "Φόρμες (σελίδα σύνδεσης)",
"Clone": "Κλωνοποίηση",
"DisabledForLocalAddresses": "Απενεργοποιήθηκε για τοπικές διευθύνσεις",
"None": "Κανένας",
"ResetAPIKeyMessageText": "Είστε βέβαιοι ότι θέλετε να επαναφέρετε το κλειδί API σας;"
}

View File

@@ -47,6 +47,8 @@
"ApplicationLongTermStatusCheckSingleClientMessage": "Applications unavailable due to failures for more than 6 hours: {0}",
"ApplicationStatusCheckAllClientMessage": "All applications are unavailable due to failures",
"ApplicationStatusCheckSingleClientMessage": "Applications unavailable due to failures: {0}",
"ApplicationTagsHelpText": "Sync Indexers to this application that have no tags or that have 1 or more matching tags",
"ApplicationTagsHelpTextWarning": "Tags should be used with caution, they can have unintended effects. An app with a tag will only sync with indexers having the same tag.",
"ApplicationURL": "Application URL",
"ApplicationUrlHelpText": "This application's external URL including http(s)://, port and URL base",
"Applications": "Applications",
@@ -280,7 +282,8 @@
"IndexerStatus": "Indexer Status",
"IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures",
"IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}",
"IndexerTagsHelpText": "Use tags to specify Indexer Proxies or which apps the indexer is synced to. Applications without 1 or more matching Indexer Tags will not be synced to.",
"IndexerTagsHelpText": "Use tags to specify Indexer Proxies or which apps the indexer is synced to.",
"IndexerTagsHelpTextWarning": "Tags should be used with caution, they can have unintended effects. An indexer with a tag will only sync to apps with the same tag.",
"IndexerVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}",
"IndexerVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}",
"Indexers": "Indexers",

View File

@@ -391,7 +391,7 @@
"UpdateAvailable": "La nueva actualización está disponible",
"Genre": "Géneros",
"Publisher": "Editor",
"AuthenticationRequired": "Autenticación Requerida",
"AuthenticationRequired": "Autenticación requerida",
"ApplyChanges": "Aplicar Cambios",
"CountIndexersSelected": "{0} indexador(es) seleccionado(s)",
"CountDownloadClientsSelected": "{0} cliente(s) de descarga seleccionado(s)",
@@ -412,5 +412,31 @@
"DeleteAppProfileMessageText": "Seguro que quieres eliminar el perfil de calidad {0}",
"AddConnection": "Añadir Conexión",
"NotificationStatusAllClientHealthCheckMessage": "Las listas no están disponibles debido a errores",
"NotificationStatusSingleClientHealthCheckMessage": "Listas no disponibles debido a errores: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "Listas no disponibles debido a errores: {0}",
"EditIndexerImplementation": "Agregar Condición - { implementationName}",
"AuthBasic": "Básico (ventana emergente del navegador)",
"AuthForm": "Formularios (página de inicio de sesión)",
"Author": "Autor",
"Book": "Libro",
"Clone": "Clonar",
"DisabledForLocalAddresses": "Deshabilitado para direcciones locales",
"External": "Externo",
"None": "Ninguna",
"ResetAPIKeyMessageText": "¿Está seguro de que desea restablecer su clave API?",
"EditIndexerProxyImplementation": "Agregar Condición - { implementationName}",
"AppUpdated": "{appName} Actualizada",
"AppUpdatedVersion": "{appName} ha sido actualizado a la versión `{version}`, para obtener los cambios más recientes, necesitaras recargar {appName}",
"AddApplicationImplementation": "Agregar Condición - { implementationName}",
"AddConnectionImplementation": "Añadir Conexión - {implementationName}",
"AddIndexerImplementation": "Agregar Condición - { implementationName}",
"AddIndexerProxyImplementation": "Agregar Condición - { implementationName}",
"EditApplicationImplementation": "Agregar Condición - { implementationName}",
"EditConnectionImplementation": "Agregar Condición - { implementationName}",
"AddDownloadClientImplementation": "Añadir Cliente de Descarga - {implementationName}",
"AuthenticationMethod": "Método de autenticación",
"AuthenticationMethodHelpTextWarning": "Por favor selecciona un método válido de autenticación",
"AuthenticationRequiredHelpText": "Cambiar para que las solicitudes requieran autenticación. No lo cambie a menos que entienda los riesgos.",
"AuthenticationRequiredPasswordHelpTextWarning": "Introduzca una nueva contraseña",
"AuthenticationRequiredUsernameHelpTextWarning": "Introduzca un nuevo nombre de usuario",
"AuthenticationRequiredWarning": "Para evitar el acceso remoto sin autenticación, {appName} ahora requiere que la autenticación esté habilitada. Opcionalmente puede desactivar la autenticación desde una dirección local."
}

View File

@@ -12,7 +12,7 @@
"Indexers": "Tietolähteet",
"MovieIndexScrollBottom": "Elokuvakirjasto: vieritä alas",
"SSLCertPassword": "SSL-varmenteen salasana",
"Style": "Tyyli",
"Style": "Ulkoasu",
"Tags": "Tunnisteet",
"Today": "Tänään",
"About": "Tietoja",
@@ -22,7 +22,7 @@
"ApplicationStatusCheckSingleClientMessage": "Sovellukset eivät ole käytettävissä virheiden vuoksi: {0}",
"Date": "Päiväys",
"Dates": "Päiväykset",
"SettingsTimeFormat": "Ajan esitystapa",
"SettingsTimeFormat": "Kellonajan esitys",
"Message": "Viesti",
"Seeders": "Jakajat",
"TestAll": "Testaa kaikki",
@@ -48,15 +48,15 @@
"RestartRequiredHelpTextWarning": "Käyttöönotto vaatii uudelleenkäynnistyksen.",
"Result": "Tulos",
"Settings": "Asetukset",
"SettingsLongDateFormat": "Päiväyksen pitkä esitystapa",
"SettingsShortDateFormat": "Päiväyksen lyhyt esitystapa",
"SettingsLongDateFormat": "Pitkän päiväyksen esitys",
"SettingsShortDateFormat": "Lyhyen päiväyksen esitys",
"UnselectAll": "Poista kaikkien valinta",
"UpdateCheckStartupTranslocationMessage": "Päivitystä ei voi asentaa, koska käynnistyskansio '{0}' sijaitsee 'App Translocation' -kansiossa.",
"UpdateCheckUINotWritableMessage": "Päivitystä ei voi asentaa, koska käyttäjällä '{1}' ei ole kirjoitusoikeutta käyttöliittymäkansioon '{0}'.",
"UpdateMechanismHelpText": "Käytä Prowlarrin sisäänrakennettua päivitystoimintoa tai omaa komentosarjaasi.",
"Enable": "Käytä",
"UI": "Käyttöliittymä",
"UrlBaseHelpText": "Käänteisen välityspalvelimen tuki (esim. 'http://[host]:[port]/[urlBase]'). Käytä oletusta jättämällä tyhjäksi.",
"UrlBaseHelpText": "Käänteisen välityspalvelimen tuki (esim. \"http://[host]:[port]/[urlBase]\"). Käytä oletusta jättämällä tyhjäksi.",
"Usenet": "Usenet",
"BackupNow": "Varmuuskopioi nyt",
"NoBackupsAreAvailable": "Varmuuskopioita ei ole saatavilla",
@@ -71,8 +71,8 @@
"NoTagsHaveBeenAddedYet": "Tunnisteita ei ole vielä lisätty.",
"ApplyTags": "Tunnistetoimenpide",
"Authentication": "Todennus",
"AuthenticationMethodHelpText": "Vaadi käyttäjätunnus ja salasana.",
"BindAddressHelpText": "Toimiva IP-osoite, localhost tai '*' (tähti) kaikille yhteyksille.",
"AuthenticationMethodHelpText": "Vaadi käyttäjätunnus ja salasana {appName}in käyttöön.",
"BindAddressHelpText": "Toimiva IP-osoite, \"localhost\" tai \"*\" (tähti) kaikille verkkoliitännöille.",
"Close": "Sulje",
"DeleteNotification": "Poista kytkentä",
"Docker": "Docker",
@@ -96,7 +96,7 @@
"Protocol": "Protokolla",
"ProxyCheckBadRequestMessage": "Välityspalvelintesti epäonnistui. Tilakoodi: {0}",
"ProxyCheckFailedToTestMessage": "Välityspalvelintesti epäonnistui: {0}",
"ProxyCheckResolveIpMessage": "Määritetyn välityspalvelimen '{0}' IP-osoitteen selvitys epäonnistui.",
"ProxyCheckResolveIpMessage": "Määritetyn välityspalvelimen \"{0}\" IP-osoitteen selvitys epäonnistui.",
"ProxyPasswordHelpText": "Käyttäjätunnus ja salasana tulee syöttää vain tarvittaessa. Muussa tapauksessa jätä kentät tyhjiksi.",
"ProxyType": "Välityspalvelimen tyyppi",
"ProxyUsernameHelpText": "Käyttäjätunnus ja salasana tulee syöttää vain tarvittaessa. Muussa tapauksessa jätä kentät tyhjiksi.",
@@ -145,7 +145,7 @@
"All": "Kaikki",
"AllIndexersHiddenDueToFilter": "Aktiivinen suodatin on piilottanut kaikki tietolähteet.",
"Analytics": "Analytiikka",
"AnalyticsEnabledHelpText": "Lähetä nimettömiä käyttö- ja virhetietoja sovelluksen palvelimille. Tämä sisältää tietoja selaimestasi, verkkokäyttöliittymän sivujen käytöstä, virheraportoinnista sekä käyttöjärjestelmästäsi ja versiosta. Käytämme näitä tietoja ominaisuuksien ja virhekorjauksien painotukseen.",
"AnalyticsEnabledHelpText": "Lähetä nimettömiä käyttö- ja virhetietoja palvelimillemme. Tämä sisältää tietoja selaimestasi, käyttöliittymän sivujen käytöstä, virheraportoinnista, käyttöjärjestelmästä ja suoritusalustasta. Käytämme näitä tietoja ominaisuuksien ja vikakorjausten painotukseen.",
"ApiKey": "API-avain",
"AppDataDirectory": "AppData-kansio",
"DBMigration": "Tietokannan siirto",
@@ -181,7 +181,7 @@
"Discord": "Discord",
"Donations": "Lahjoitukset",
"Edit": "Muokkaa",
"EnableAutomaticSearchHelpText": "Profiilia käytetään automaattihaun yhteydessä, kun haku suoritetaan käyttöliittymästä tai Prowlarrin toimesta.",
"EnableAutomaticSearchHelpText": "Profiilia käytetään automaattihauille, jotka suoritetaan käyttöliittymästä tai Prowlarrin toimesta.",
"Enabled": "Käytössä",
"EventType": "Tapahtumatyyppi",
"Exception": "Poikkeus",
@@ -199,9 +199,9 @@
"SaveChanges": "Tallenna muutokset",
"SaveSettings": "Tallenna asetukset",
"Scheduled": "Ajoitettu",
"SettingsEnableColorImpairedModeHelpText": "Muokattu tyyli käyttäjille, joiden värinäkö on heikentynyt. Auttaa erottamaan värikoodatun tiedon.",
"SettingsShowRelativeDates": "Näytä suhteutetut päiväykset",
"SettingsShowRelativeDatesHelpText": "Näytä suhteutetut (tänään/eilen/yms.) tai absoluuttiset päiväykset.",
"SettingsEnableColorImpairedModeHelpText": "Vaihtoehtoinen tyyli, joka auttaa erottamaan värikoodatut tiedot paremmin",
"SettingsShowRelativeDates": "Suhteellisten päiväysten esitys",
"SettingsShowRelativeDatesHelpText": "Näytä suhteutetut (tänään/eilen/yms.) absoluuttisten sijaan",
"ShowSearch": "Näytä haku",
"Source": "Lähde",
"SSLPort": "SSL-portti",
@@ -435,7 +435,7 @@
"EditSyncProfile": "Muokkaa synkronointiprofiilia",
"InstanceName": "Instanssin nimi",
"InstanceNameHelpText": "Instanssin nimi välilehdellä ja järjestelmälokissa",
"ThemeHelpText": "Vaihda sovelluksen käyttöliittymän ulkoasua. \"Automaattinen\" vaihtaa vaalean ja tumman tilan käyttöjärjestelmäsi teemaa vastaavaksi. Innoittanut {0}.",
"ThemeHelpText": "Vaihda sovelluksen käyttöliittymän ulkoasu. \"Automaattinen\" vaihtaa vaalean ja tumman tilan välillä järjestelmän teeman mukaan. Innoittanut Theme.Park.",
"Duration": "Kesto",
"ElapsedTime": "Kulunut aika",
"EnabledRedirected": "Kulunut, uudelleenohjattu",
@@ -485,13 +485,24 @@
"Episode": "Jakso",
"Label": "Tunniste",
"Theme": "Teema",
"ConnectionLostReconnect": "Radarr pyrkii muodostamaan yhteyden automaattisesti tai voit painaa alta \"Lataa uudelleen\".",
"ConnectionLostReconnect": "{appName} pyrkii ajoittain muodostamaan yhteyden automaattisesti tai sitä voidaan yrittää manuaalisesti painamalla alta \"Lataa uudelleen\".",
"DeleteAppProfileMessageText": "Haluatko varmasti poistaa laatuprofiilin '{0}'?",
"RecentChanges": "Viimeaikaiset muutokset",
"WhatsNew": "Mikä on uutta?",
"ConnectionLostToBackend": "Radarr on menettänyt yhteyden taustajärjestelmään ja sivu on päivitettävä toiminnallisuuden palauttamiseksi.",
"ConnectionLostToBackend": "{appName} kadotti yhteyden taustajärjestelmään ja käytettävyyden palauttamiseksi se on ladattava uudelleen.",
"minutes": "Minuuttia",
"AddConnection": "Lisää yhteys",
"NotificationStatusAllClientHealthCheckMessage": "Sovellukset eivät ole käytettävissä virheiden vuoksi",
"NotificationStatusSingleClientHealthCheckMessage": "Sovellukset eivät ole käytettävissä virheiden vuoksi: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "Sovellukset eivät ole käytettävissä virheiden vuoksi: {0}",
"AuthBasic": "Perus (selaimen ponnahdus)",
"AuthForm": "Lomake (kirjautumissivu)",
"DisabledForLocalAddresses": "Ei käytetä paikallisille osoittelle",
"None": "Ei mitään",
"ResetAPIKeyMessageText": "Haluatko varmasti uudistaa API-avaimesi?",
"TotalIndexerSuccessfulGrabs": "Onnistuneiden tietolähdesieppausten kokonaismäärä",
"AppUpdated": "{appName} on päivitetty",
"AppUpdatedVersion": "{appName} on päivitetty versioon {version} ja muutosten käyttöönottamiseksi se on ladattava uudelleen.",
"IndexerDownloadClientHelpText": "Määritä tämän tietolähteen kanssa käytettävä lataustyökalu",
"AuthenticationRequiredWarning": "Etäkäytön estämiseksi ilman tunnistautumista {appName} vaatii nyt todennuksen käyttöönoton. Todennus voidaan poistaa käytöstä paikallisille osoitteille.",
"TotalGrabs": "Sieppausten kokonaismäärä"
}

View File

@@ -3,16 +3,16 @@
"Indexers": "Indexeurs",
"Host": "Hôte",
"History": "Historique",
"HideAdvanced": "Masquer avancé",
"HideAdvanced": "Masquer param. av.",
"Health": "Santé",
"General": "Général",
"Folder": "Dossier",
"Filter": "Filtre",
"Filter": "Filtrer",
"Files": "Fichiers",
"Events": "Événements",
"Edit": "Éditer",
"Edit": "Modifier",
"DownloadClientStatusCheckAllClientMessage": "Aucun client de téléchargement n'est disponible en raison d'échecs",
"DownloadClients": "Clients télécharg.",
"DownloadClients": "Clients de télécharg.",
"Dates": "Dates",
"Date": "Date",
"Delete": "Supprimer",
@@ -28,19 +28,19 @@
"About": "À propos",
"IndexerStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison d'échecs : {0}",
"DownloadClientStatusCheckSingleClientMessage": "Clients de Téléchargement indisponibles en raison d'échecs: {0}",
"SetTags": "Définir Tags",
"SetTags": "Définir les étiquettes",
"ReleaseStatus": "Statut de la version",
"UpdateCheckUINotWritableMessage": "Impossible d'installer la mise à jour car le dossier d'interface utilisateur '{0}' n'est pas accessible en écriture par l'utilisateur '{1}'.",
"UpdateCheckStartupTranslocationMessage": "Impossible d'installer la mise à jour car le dossier de démarrage '{0}' se trouve dans un dossier App Translocation.",
"UpdateCheckStartupNotWritableMessage": "Impossible d'installer la mise à jour car le dossier de démarrage '{0}' n'est pas accessible en écriture par l'utilisateur '{1}'.",
"UnselectAll": "Tout déselectionner",
"UnselectAll": "Tout désélectionner",
"UISettingsSummary": "Date, langue, et perceptions des couleurs",
"TagsSettingsSummary": "Voir tous les tags et leur utilisation. Les tags inutilisés peuvent être supprimés",
"TagsSettingsSummary": "Voir toutes les étiquettes et leur utilisation. Les étiquettes inutilisées peuvent être supprimées",
"Style": "Style",
"Status": "Statut",
"Status": "État",
"Sort": "Trier",
"Size": "Taille",
"ShowAdvanced": "Afficher avancés",
"ShowAdvanced": "Afficher param. av.",
"Settings": "Paramètres",
"SelectAll": "Tout sélectionner",
"Security": "Sécurité",
@@ -53,15 +53,15 @@
"Queue": "File d'attente",
"ProxyCheckResolveIpMessage": "Impossible de résoudre l'adresse IP de l'hôte proxy configuré {0}",
"ProxyCheckFailedToTestMessage": "Échec du test du proxy : {0}",
"ProxyCheckBadRequestMessage": "Échec du test du proxy. StatusCode: {0}",
"ProxyCheckBadRequestMessage": "Échec du test du proxy. Code d'état : {0}",
"Proxy": "Proxy",
"Protocol": "Protocole",
"Options": "Options",
"NoChanges": "Aucun changement",
"NoChanges": "Aucune modification",
"NoChange": "Pas de changement",
"MoreInfo": "Plus d'informations",
"Grabbed": "Récupéré",
"DownloadClientsSettingsSummary": "Clients de Téléchargement configuration pour l'intégration dans la recherche de l'interface utilisateur Prowlarr",
"DownloadClientsSettingsSummary": "Configuration des clients de téléchargement pour intégration dans la recherche de l'interface utilisateur de Prowlarr",
"DownloadClient": "Client de Téléchargement",
"Logging": "Enregistrement",
"LogFiles": "Fichiers Log",
@@ -69,7 +69,7 @@
"Updates": "Mises à jour",
"UI": "UI",
"Tasks": "Tâches",
"Tags": "Tags",
"Tags": "Étiquettes",
"System": "Système",
"LastWriteTime": "Heure de la dernière écriture",
"Language": "Langue",
@@ -116,18 +116,18 @@
"HealthNoIssues": "Aucun problème avec votre configuration",
"SystemTimeCheckMessage": "L'heure du système est décalée de plus d'un jour. Les tâches planifiées peuvent ne pas s'exécuter correctement tant que l'heure ne sera pas corrigée",
"SettingsShowRelativeDates": "Afficher les dates relatives",
"UnsavedChanges": "Changement non sauvegardés",
"ShowSearchHelpText": "Afficher le bouton de recherche au survol de la souris",
"UnsavedChanges": "Modifications non sauvegardées",
"ShowSearchHelpText": "Affiche le bouton de recherche au survol du curseur",
"ShowSearch": "Afficher la recherche",
"SettingsTimeFormat": "Format de l'heure",
"SettingsShowRelativeDatesHelpText": "Afficher les dates relatives (Aujourd'hui/ Hier/ etc) ou absolues",
"SettingsShowRelativeDatesHelpText": "Afficher les dates relatives (aujourd'hui, hier, etc.) ou absolues",
"SettingsShortDateFormat": "Format de date court",
"SettingsLongDateFormat": "Format de date long",
"SettingsEnableColorImpairedModeHelpText": "Style altéré pour aider les personnes daltoniennes à distinguer les informations en couleurs",
"SettingsEnableColorImpairedMode": "Activer le mode daltonien",
"PendingChangesStayReview": "Rester et vérifier les changements",
"PendingChangesMessage": "Vous avez effectué des changements non sauvegardés, souhaitez vous quitter cette page?",
"PendingChangesDiscardChanges": "Abandonner les changements et quitter",
"PendingChangesStayReview": "Rester et vérifier les modifications",
"PendingChangesMessage": "Vous avez des modifications non sauvegardées, voulez-vous vraiment quitter cette page ?",
"PendingChangesDiscardChanges": "Abandonner les modifications et quitter",
"CloneProfile": "Dupliqué le profil",
"ClientPriority": "Priorité du client",
"ChangeHasNotBeenSavedYet": "Les changements n'ont pas encore été sauvegardés",
@@ -135,15 +135,15 @@
"CertificateValidation": "Validation du certificat",
"BypassProxyForLocalAddresses": "Contourner le proxy pour les adresses locales",
"Branch": "Branche",
"BindAddressHelpText": "Adresse IP valide, localhost ou '*' pour toutes les interfaces",
"BindAddressHelpText": "Adresse IP valide, localhost ou « * » pour toutes les interfaces",
"BindAddress": "Adresse d'attache",
"Backups": "Sauvegardes",
"BackupRetentionHelpText": "Les sauvegardes automatiques plus anciennes que la période de conservation seront automatiquement effacées",
"BackupIntervalHelpText": "Intervalle entre les sauvegardes automatiques",
"Automatic": "Automatique",
"AuthenticationMethodHelpText": "Exiger un identifiant et un mot de passe pour accéder à Prowlarr",
"AuthenticationMethodHelpText": "Exiger un nom d'utilisateur et un mot de passe pour accéder à {appName}",
"Authentication": "Authentification",
"ApplyTags": "Appliquer les tags",
"ApplyTags": "Appliquer les étiquettes",
"AppDataDirectory": "Dossier AppData",
"ApiKey": "Clé API",
"AnalyticsEnabledHelpText": "Envoyer des informations anonymes sur l'utilisation et les erreurs vers les serveurs de Prowlarr. Cela inclut des informations sur votre navigateur, quelle page Prowlarr WebUI vous utilisez, les rapports d'erreurs, ainsi que le système d'exploitation et sa version. Nous utiliserons ces informations pour prioriser les nouvelles fonctionnalités et les corrections de bugs.",
@@ -170,8 +170,8 @@
"BranchUpdateMechanism": "Branche utilisée par le mécanisme de mise à jour extérieur",
"BranchUpdate": "Branche à utiliser pour mettre Prowlarr à jour",
"BeforeUpdate": "Avant la mise à jour",
"DeleteDownloadClientMessageText": "Êtes-vous sûr de vouloir supprimer le client de téléchargement '{0}' ?",
"DeleteBackupMessageText": "Êtes-vous sûr de vouloir supprimer la sauvegarde '{0}' ?",
"DeleteDownloadClientMessageText": "Voulez-vous supprimer le client de téléchargement « {name} » ?",
"DeleteBackupMessageText": "Voulez-vous supprimer la sauvegarde « {name} » ?",
"ErrorLoadingContents": "Erreur lors du chargement du contenu",
"EnableInteractiveSearchHelpText": "Sera utilisé lorsque la recherche interactive est utilisée",
"EnableAutomaticSearchHelpText": "Sera utilisé lorsque les recherches automatiques sont effectuées via l'interface utilisateur ou par Prowlarr",
@@ -180,7 +180,7 @@
"Exception": "Exception",
"EditIndexer": "Modifier l'indexeur",
"Disabled": "Désactivé",
"DeleteNotificationMessageText": "Êtes-vous sûr de vouloir supprimer la notification '{0}' ?",
"DeleteNotificationMessageText": "Voulez-vous supprimer la notification « {name} » ?",
"AutomaticSearch": "Recherche automatique",
"AddIndexer": "Ajouter un indexeur",
"Interval": "Intervalle",
@@ -203,14 +203,14 @@
"LogLevelTraceHelpTextWarning": "La journalisation des traces ne doit être activée que temporairement",
"LogLevel": "Niveau du journal",
"IncludeHealthWarningsHelpText": "Inclure avertissements santé",
"FocusSearchBox": "Zone de recherche de focus",
"FocusSearchBox": "Placer le curseur sur la barre de recherche",
"ProxyBypassFilterHelpText": "Utiliser ',' comme séparateur et '*.' comme caractère générique pour les sous-domaines",
"Uptime": "Durée de fonctionnent",
"UpdateScriptPathHelpText": "Chemin vers un script personnalisé qui prend un package de mise à jour extraite et gère le reste du processus de mise à jour",
"UpdateMechanismHelpText": "Utiliser le programme de mise à jour intégré de Prowlarr ou un script",
"UpdateAutomaticallyHelpText": "Télécharger et installer automatiquement les mises à jour. Vous pourrez toujours installer à partir de System : Updates",
"UnableToLoadUISettings": "Impossible de charger les paramètres de l'interface utilisateur",
"UnableToLoadTags": "Impossible de charger les balises",
"UnableToLoadTags": "Impossible de charger les étiquettes",
"UnableToLoadHistory": "Impossible de charger l'historique",
"UnableToLoadGeneralSettings": "Impossible de charger les paramètres généraux",
"UnableToLoadDownloadClients": "Impossible de charger les clients de téléchargement",
@@ -218,16 +218,16 @@
"UnableToAddANewNotificationPleaseTryAgain": "Impossible d'ajouter une nouvelle notification, veuillez réessayer.",
"UnableToAddANewIndexerPleaseTryAgain": "Impossible d'ajouter un nouvel indexeur, veuillez réessayer.",
"UnableToAddANewDownloadClientPleaseTryAgain": "Impossible d'ajouter un nouveau client de téléchargement, veuillez réessayer.",
"TagIsNotUsedAndCanBeDeleted": "La balise n'est pas utilisée et peut être supprimée",
"TagsHelpText": "S'applique aux films avec au moins une balise correspondante",
"StartTypingOrSelectAPathBelow": "Commencer à taper ou sélectionner un chemin ci-dessous",
"NoTagsHaveBeenAddedYet": "Aucune identification n'a été ajoutée pour l'instant",
"TagIsNotUsedAndCanBeDeleted": "L'étiquette n'est pas utilisée et peut être supprimée",
"TagsHelpText": "S'applique aux indexeurs avec au moins une étiquette correspondante",
"StartTypingOrSelectAPathBelow": "Commencer à écrire ou sélectionner un chemin ci-dessous",
"NoTagsHaveBeenAddedYet": "Aucune étiquette n'a encore été ajoutée",
"IndexerFlags": "Indicateurs d'indexeur",
"DeleteTagMessageText": "Voulez-vous vraiment supprimer la balise '{0}' ?",
"DeleteTagMessageText": "Voulez-vous vraiment supprimer l'étiquette « {label} » ?",
"UISettings": "Paramètres UI",
"UILanguageHelpTextWarning": "Rechargement du navigateur requis",
"UILanguageHelpText": "Langue que Prowlarr utilisera pour l'interface utilisateur",
"UILanguage": "UI Langue",
"UILanguage": "Langue de l'IU",
"Torrents": "Torrents",
"TestAllClients": "Tester tous les clients",
"TagCannotBeDeletedWhileInUse": "Ne peut pas être supprimé pendant l'utilisation",
@@ -254,7 +254,7 @@
"ExistingTag": "Tag existant",
"RemoveFilter": "Supprimer le filtre",
"RemovedFromTaskQueue": "Supprimé de la file d'attente des tâches",
"RefreshMovie": "Actualiser film",
"RefreshMovie": "Actualiser le film",
"ReadTheWikiForMoreInformation": "Consultez le Wiki pour plus d'informations",
"ProwlarrSupportsAnyIndexer": "Prowlarr prend en charge de nombreux indexeurs en plus de tout indexeur qui utilise la norme Newznab/Torznab en utilisant « Generic Newznab » (pour usenet) ou « Generic Torznab » (pour les torrents). Recherchez et sélectionnez votre indexeur ci-dessous.",
"ProwlarrSupportsAnyDownloadClient": "Prowlarr prend en charge tout client de téléchargement qui utilise le standard Newznab, ainsi que d'autres clients de téléchargement répertoriés ci-dessous.",
@@ -276,14 +276,14 @@
"New": "Nouveau",
"NetCore": ".NET Core",
"MovieIndexScrollTop": "Index des films : faire défiler vers le haut",
"MovieIndexScrollBottom": "Index des Films : faire défiler vers le bas",
"MovieIndexScrollBottom": "Index des films : faire défiler vers le bas",
"MIA": "MIA",
"LaunchBrowserHelpText": " Ouvrer un navigateur Web et accéder à la page d'accueil de Prowlarr au démarrage de l'application.",
"CloseCurrentModal": "Fermer le modal actuel",
"AddingTag": "Ajouter un tag",
"CloseCurrentModal": "Fermer cette fenêtre modale",
"AddingTag": "Ajout d'une étiquette",
"OnHealthIssueHelpText": "Sur un problème de santé",
"AcceptConfirmationModal": "Accepter les modalités d'utilisations",
"OpenThisModal": "Ouvrer ce modal",
"OpenThisModal": "Ouvrir cette fenêtre modale",
"IndexerLongTermStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison de pannes pendant plus de 6 heures : {0}",
"IndexerLongTermStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs de plus de 6 heures",
"Yesterday": "Hier",
@@ -311,9 +311,9 @@
"EnableRss": "Activer RSS",
"EnableIndexer": "Activer l'indexeur",
"DevelopmentSettings": "Paramètres de développement",
"DeleteApplicationMessageText": "Etes-vous sûr de vouloir supprimer l'application '{0}' ?",
"DeleteApplicationMessageText": "Voulez-vous supprimer l'application « {name} » ?",
"DeleteApplication": "Supprimer l'application",
"ClearHistoryMessageText": "Vous êtes sûr de vouloir effacer tout l'historique de Prowlarr ?",
"ClearHistoryMessageText": "Voulez-vous vraiment effacer tout l'historique de Prowlarr ?",
"ClearHistory": "Effacer l'historique",
"ApplicationStatusCheckSingleClientMessage": "Applications indisponibles en raison de dysfonctionnements : {0}",
"ApplicationStatusCheckAllClientMessage": "Toutes les applications sont indisponibles en raison de dysfonctionnements",
@@ -347,7 +347,7 @@
"Grabs": "Complétés",
"Id": "Id",
"Presets": "Préconfigurations",
"Privacy": "Vie privée",
"Privacy": "Visibilité",
"Query": "Requête",
"Stats": "Stats",
"Torrent": "Torrent",
@@ -363,14 +363,14 @@
"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.",
"NoSearchResultsFound": "Aucun résultat de recherche trouvé, essayez d'effectuer une nouvelle recherche ci-dessous.",
"DeleteIndexerProxy": "Supprimer le proxy indexeur",
"DeleteIndexerProxyMessageText": "Êtes-vous sur de vouloir supprimer le proxy '{0}' ?",
"DeleteIndexerProxyMessageText": "Voulez-vous supprimer le proxy d'indexeur « {name} » ?",
"AddIndexerProxy": "Ajouter proxy indexeur",
"AppSettingsSummary": "Applications et paramètres pour configurer comment Prowlarr interagit avec vos programmes PVR",
"IndexerTagsHelpText": "Utilisez des balises pour spécifier les proxys d'indexation ou les applications avec lesquelles l'indexeur est synchronisé. Les applications sans 1 ou plusieurs balises d'indexation correspondantes ne seront pas synchronisées.",
"IndexerTagsHelpText": "Utilisez des étiquettes pour spécifier les proxies d'indexation ou les applications avec lesquelles l'indexeur est synchronisé.",
"Notifications": "Notifications",
"IndexerVipCheckExpiredClientMessage": "Les avantages VIP de l'indexeur ont expiré : {0}",
"IndexerProxy": "Proxy d'indexation",
"IndexerSettingsSummary": "Configuration de divers paramètres globaux de l'indexeur, y compris les proxys.",
"IndexerSettingsSummary": "Configuration de divers paramètres globaux de l'indexeur, y compris les proxies.",
"IndexerProxies": "Proxys d'indexation",
"IndexerProxyStatusCheckAllClientMessage": "Tous les proxys sont indisponibles en raison d'échecs",
"IndexerProxyStatusCheckSingleClientMessage": "Proxys indisponibles en raison d'échecs : {0}",
@@ -440,7 +440,7 @@
"Started": "Démarré",
"EditSyncProfile": "Modifier le profil de synchronisation",
"AddSyncProfile": "Ajouter un profil de synchronisation",
"ThemeHelpText": "Changez le thème de l'interface de l'application. Le thème \"Auto\" utilisera celui de votre système d'exploitation pour définir le mode clair ou foncé. Inspiré par {0}",
"ThemeHelpText": "Changez le thème de l'interface de l'application. Le thème « Auto » utilisera celui de votre système d'exploitation pour déterminer entre le mode clair ou foncé. Inspiré par {inspiredBy}.",
"SyncProfile": "Profil de synchronisation",
"SyncProfiles": "Profils de synchronisation",
"MinimumSeeders": "Nombre minimum de seeders",
@@ -449,18 +449,18 @@
"ElapsedTime": "Temps écoulé",
"Parameters": "Paramètres",
"AuthenticationRequired": "Authentification requise",
"AuthenticationRequiredHelpText": "Modifier les demandes pour lesquelles l'authentification est requise. Ne changez rien si vous ne comprenez pas les risques.",
"AuthenticationRequiredHelpText": "Modifier les demandes pour lesquelles l'authentification est requise. Ne rien modifier si vous n'en comprenez pas les risques.",
"DeleteClientCategory": "Supprimer la catégorie du client de téléchargement",
"DownloadClientCategory": "Catégorie du client de téléchargement",
"MappedCategories": "Catégories mappées",
"EnabledRedirected": "Activé, Redirigé",
"GrabTitle": "Récupérer le titre",
"AuthenticationRequiredWarning": "Pour empêcher l'accès à distance sans authentification, Prowlarr exige désormais que l'authentification soit activée. Configurez votre méthode d'authentification et vos informations d'identification. Vous pouvez éventuellement désactiver l'authentification à partir des adresses locales. Reportez-vous à la FAQ pour plus d'informations.",
"AuthenticationRequiredWarning": "Pour empêcher l'accès à distance sans authentification, {appName} exige désormais que l'authentification soit activée. Vous pouvez éventuellement désactiver l'authentification pour les adresses locales.",
"Remove": "Retirer",
"Replace": "Remplacer",
"TheLatestVersionIsAlreadyInstalled": "La dernière version de Prowlarr est déjà installée",
"TheLatestVersionIsAlreadyInstalled": "La dernière version de {appName} est déjà installée",
"AddCustomFilter": "Ajouter filtre personnalisé",
"AddApplication": "Ajouter application",
"AddApplication": "Ajouter une application",
"IncludeManualGrabsHelpText": "Inclure les saisies manuelles effectuées dans Prowlarr",
"OnGrabHelpText": "Récupéré à la sortie",
"RssFeed": "Flux RSS",
@@ -480,7 +480,7 @@
"Book": "Livre",
"Artist": "Artiste",
"Author": "Auteur",
"AverageResponseTimesMs": "Temps de réponse moyen (Ms)",
"AverageResponseTimesMs": "Temps de réponse moyen des indexeurs (ms)",
"IndexerFailureRate": "Taux d'échec de l'indexeur",
"Label": "Label",
"More": "Plus",
@@ -494,48 +494,104 @@
"Year": "Année",
"ApplicationURL": "URL de l'application",
"ApiKeyValidationHealthCheckMessage": "Veuillez mettre à jour votre clé API pour qu'elle contienne au moins {0} caractères. Vous pouvez le faire via les paramètres ou le fichier de configuration",
"ApplicationUrlHelpText": "URL externe de cette application, y compris http(s)://, le port ainsi que la base de URL",
"ApplicationUrlHelpText": "L'URL externe de cette application, y compris http(s)://, le port ainsi que la base de URL",
"ApplyChanges": "Appliquer les modifications",
"ApplyTagsHelpTextAdd": "Ajouter : Ajouter les tags à la liste de tags existantes",
"ApplyTagsHelpTextHowToApplyApplications": "Comment appliquer des tags à l'auteur sélectionné",
"CountIndexersSelected": "{0} indexeur(s) sélectionné(s)",
"DeleteSelectedApplicationsMessageText": "Voulez-vous vraiment supprimer l'indexeur '{0}' ?",
"DeleteSelectedIndexersMessageText": "Voulez-vous vraiment supprimer l'indexeur '{0}' ?",
"ApplyTagsHelpTextAdd": "Ajouter : ajoute les étiquettes à la liste de étiquettes existantes",
"ApplyTagsHelpTextHowToApplyApplications": "Comment appliquer les étiquettes aux applications sélectionnées",
"CountIndexersSelected": "{count} indexeur(s) sélectionné(s)",
"DeleteSelectedApplicationsMessageText": "Voulez-vous vraiment supprimer {count} application(s) sélectionnée(s) ?",
"DeleteSelectedIndexersMessageText": "Voulez-vous vraiment supprimer les {count} indexeur(s) sélectionné(s) ?",
"DownloadClientPriorityHelpText": "Donnez la priorité à plusieurs clients de téléchargement. Le Round-Robin est utilisé pour les clients ayant la même priorité.",
"SelectIndexers": "Recherche indexeurs",
"ApplyTagsHelpTextHowToApplyIndexers": "Comment appliquer des tags aux indexeurs sélectionnés",
"ApplyTagsHelpTextRemove": "Suprimer : Suprime les étiquettes renseignées",
"ApplyTagsHelpTextReplace": "Remplacer : Remplace les tags par les tags renseignés (ne pas renseigner de tags pour effacer tous les tags)",
"SelectIndexers": "Sélectionner les indexeurs",
"ApplyTagsHelpTextHowToApplyIndexers": "Comment appliquer des étiquettes aux indexeurs sélectionnés",
"ApplyTagsHelpTextRemove": "Supprimer : supprime les étiquettes renseignées",
"ApplyTagsHelpTextReplace": "Remplacer : remplace les étiquettes par les étiquettes renseignées (ne pas renseigner d'étiquette pour toutes les effacer)",
"DeleteSelectedDownloadClients": "Supprimer le client de téléchargement",
"DeleteSelectedDownloadClientsMessageText": "Voulez-vous vraiment supprimer l'indexeur '{0}' ?",
"StopSelecting": "Arrêtez la sélection",
"DeleteSelectedDownloadClientsMessageText": "Voulez-vous vraiment supprimer {count} client(s) de téléchargement sélectionné(s) ?",
"StopSelecting": "Effacer la sélection",
"UpdateAvailable": "Une nouvelle mise à jour est disponible",
"AdvancedSettingsHiddenClickToShow": "Paramètres avancés masqués, cliquez pour afficher",
"AdvancedSettingsShownClickToHide": "Paramètres avancés affichés, cliquez pour masquer",
"AppsMinimumSeeders": "Apps avec le nombre minimum de seeders disponibles",
"AppsMinimumSeedersHelpText": "Minimum de seeders requis par les applications pour que lindexeur les récupère, laisser vide utilise la valeur par défaut du profil Sync",
"BasicSearch": "Recherche de base",
"CountIndexersAvailable": "{0} indexeur(s) disponible(s)",
"CountIndexersAvailable": "{count} indexeur(s) disponible(s)",
"DeleteSelectedApplications": "Supprimer les applications sélectionnées",
"DeleteSelectedIndexer": "Supprimer les indexeurs sélectionnés",
"DeleteSelectedIndexers": "Supprimer les indexeurs sélectionnés",
"EditSelectedDownloadClients": "Modifier les clients de téléchargement sélectionnés",
"EditSelectedIndexers": "Modifier les indexeurs sélectionnés",
"AreYouSureYouWantToDeleteIndexer": "Êtes-vous sûr de vouloir supprimer “{0}” de Prowlarr ?",
"AreYouSureYouWantToDeleteIndexer": "Voulez-vous supprimer « {name} » de Prowlarr ?",
"AuthQueries": "Requêtes dauthentification",
"CountApplicationsSelected": "{0} application(s) sélectionnée(s)",
"CountDownloadClientsSelected": "{0} client(s) de téléchargement sélectionné(s)",
"ConnectionLostReconnect": "Radarr essaiera de se connecter automatiquement, ou vous pouvez cliquer sur \"Recharger\" en bas.",
"ConnectionLostToBackend": "Radarr a perdu sa connexion au backend et devra être rechargé pour fonctionner à nouveau.",
"CountApplicationsSelected": "{count} application(s) sélectionnée(s)",
"CountDownloadClientsSelected": "{count} client(s) de téléchargement sélectionné(s)",
"ConnectionLostReconnect": "{appName} essaiera de se connecter automatiquement, ou vous pouvez cliquer sur « Recharger » en bas.",
"ConnectionLostToBackend": "{appName} a perdu sa connexion au backend et devra être rechargé pour fonctionner à nouveau.",
"RecentChanges": "Changements récents",
"WhatsNew": "Quoi de neuf ?",
"minutes": "Minutes",
"DeleteAppProfileMessageText": "Voulez-vous vraiment supprimer le profil de qualité {0} ?",
"minutes": "minutes",
"DeleteAppProfileMessageText": "Voulez-vous vraiment supprimer le profil d'application « {name} » ?",
"AddConnection": "Ajouter une connexion",
"AddConnectionImplementation": "Ajouter une connexion - {implementationName}",
"AddApplicationImplementation": "Ajouter une condition - {implementationName}",
"AddIndexerImplementation": "Ajouter une condition - {implementationName}",
"AddApplicationImplementation": "Ajouter une application - {implementationName}",
"AddIndexerImplementation": "Ajouter un indexeur - {implementationName}",
"EditConnectionImplementation": "Ajouter une connexion - {implementationName}",
"NotificationStatusAllClientHealthCheckMessage": "Toutes les applications sont indisponibles en raison de dysfonctionnements",
"NotificationStatusSingleClientHealthCheckMessage": "Applications indisponibles en raison de dysfonctionnements : {0}"
"NotificationStatusAllClientHealthCheckMessage": "Toutes les notifications sont indisponibles en raison de dysfonctionnements",
"NotificationStatusSingleClientHealthCheckMessage": "Notifications indisponibles en raison de dysfonctionnements : {0}",
"EditApplicationImplementation": "Ajouter une condition - {implementationName}",
"EditIndexerImplementation": "Ajouter une condition - {implementationName}",
"EditIndexerProxyImplementation": "Modifier un proxy d'indexeur - {implementationName}",
"AuthBasic": "Basique (fenêtre surgissante du navigateur)",
"AuthForm": "Formulaire (page de connexion)",
"DisabledForLocalAddresses": "Désactivée pour les adresses IP locales",
"None": "Aucun",
"ResetAPIKeyMessageText": "Voulez-vous réinitialiser votre clé d'API ?",
"AddIndexerProxyImplementation": "Ajouter un proxy d'indexeur - {implementationName}",
"IndexerStatus": "État de l'indexeur",
"ManageApplications": "Gérer les applications",
"NoIndexersFound": "Aucun indexeur n'a été trouvé",
"NoHistoryFound": "Aucun historique n'a été trouvé",
"QueryType": "Type de requête",
"SeedTimeHelpText": "Le temps qu'un torrent doit rester en seed avant de s'arrêter, la valeur vide est la valeur par défaut de l'application",
"GoToApplication": "Aller sur l'application",
"IndexerCategories": "Catégories d'indexeur",
"NoDownloadClientsFound": "Aucun client de téléchargement n'a été trouvé",
"AppUpdated": "{appName} mis à jour",
"AppUpdatedVersion": "{appName} a été mis à jour vers la version `{version}`, pour profiter des derniers changements, vous devrez relancer {appName}",
"IndexerDownloadClientHelpText": "Préciser quel client de téléchargement est utilisé pour les saisies créées au sein de Prowlarr provenant de cet indexeur",
"Implementation": "Implémentation",
"SearchCountIndexers": "Rechercher {count} indexeur(s)",
"SearchAllIndexers": "Rechercher tous les indexeurs",
"NewznabUrl": "URL Newznab",
"RssQueries": "Requêtes RSS",
"SeedTime": "Temps de seed",
"SearchQueries": "Requêtes de recherche",
"days": "jours",
"ApplicationTagsHelpTextWarning": "Les étiquettes doivent être utilisées avec prudence, elles peuvent avoir des effets indésirables. Une application avec une étiquette va uniquement synchroniser les indexeurs ayant la même étiquette.",
"DefaultNameCopiedProfile": "{name} - Copier",
"EditCategory": "Modifier la catégorie",
"EditDownloadClientImplementation": "Modifier le client de téléchargement - {implementationName}",
"External": "Externe",
"FoundCountReleases": "{itemCount} release(s) trouvée(s)",
"IndexerHistoryLoadError": "Erreur lors du chargement de l'historique de l'indexeur",
"IndexerTagsHelpTextWarning": "Les étiquettes doivent être utilisées avec prudence, elles peuvent avoir des effets indésirables. Un indexeur avec une étiquette va uniquement synchroniser les applications ayant la même étiquette.",
"NoIndexerHistory": "Aucun historique n'a été trouvé pour cet indexeur",
"PackSeedTimeHelpText": "Le temps qu'un pack (saison ou discographie) doit être seedé avant de s'arrêter, la valeur vide est la valeur par défaut de l'application",
"SeedRatioHelpText": "Le ratio qu'un torrent doit atteindre avant de s'arrêter, une valeur vide est la valeur par défaut de l'application",
"TorznabUrl": "URL Torznab",
"TotalGrabs": "Récupéré au total",
"TotalQueries": "Requêtes totales",
"SeedRatio": "Ratio de seed",
"SelectedCountOfCountReleases": "{selectedCount} sur {itemCount} releases sélectionnées",
"AddCategory": "Ajouter une catégorie",
"AddDownloadClientImplementation": "Ajouter un client de téléchargement - {implementationName}",
"ManageDownloadClients": "Gérer les clients de téléchargement",
"AuthenticationRequiredPasswordHelpTextWarning": "Saisir un nouveau mot de passe",
"IndexerDownloadClientHealthCheckMessage": "Indexeurs avec des clients de téléchargement invalides : {0].",
"AuthenticationMethod": "Méthode d'authentification",
"AuthenticationMethodHelpTextWarning": "Veuillez choisir une méthode d'authentification valide",
"ActiveIndexers": "Indexeurs actifs",
"ActiveApps": "Applications actives",
"AuthenticationRequiredUsernameHelpTextWarning": "Saisir un nouveau nom d'utilisateur",
"Clone": "Cloner"
}

View File

@@ -347,5 +347,10 @@
"minutes": "मिनट",
"DeleteAppProfileMessageText": "क्या आप वाकई गुणवत्ता प्रोफ़ाइल {0} को हटाना चाहते हैं",
"NotificationStatusAllClientHealthCheckMessage": "सभी सूचियाँ विफल होने के कारण अनुपलब्ध हैं",
"NotificationStatusSingleClientHealthCheckMessage": "विफलताओं के कारण अनुपलब्ध सूची: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "विफलताओं के कारण अनुपलब्ध सूची: {0}",
"AuthBasic": "बेसिक (ब्राउज़र पॉपअप)",
"AuthForm": "प्रपत्र (लॉग इन पेज)",
"DisabledForLocalAddresses": "स्थानीय पते के लिए अक्षम",
"None": "कोई नहीं",
"ResetAPIKeyMessageText": "क्या आप वाकई अपनी API कुंजी को रीसेट करना चाहते हैं?"
}

View File

@@ -496,5 +496,10 @@
"minutes": "percek",
"AddConnection": "Gyűjtemény módosítása",
"NotificationStatusAllClientHealthCheckMessage": "Összes alkalmazás elérhetetlen hiba miatt",
"NotificationStatusSingleClientHealthCheckMessage": "Az alkalmazás nem áll rendelkezésre az alábbi hibák miatt: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "Az alkalmazás nem áll rendelkezésre az alábbi hibák miatt: {0}",
"AuthBasic": "Alap (Böngésző felugró ablak)",
"AuthForm": "Felhasználó (Bejelentkezési oldal)",
"DisabledForLocalAddresses": "Letiltva a helyi címeknél",
"None": "Nincs",
"ResetAPIKeyMessageText": "Biztos hogy vissza szeretnéd állítani az API-Kulcsod?"
}

View File

@@ -58,5 +58,7 @@
"Actions": "Tindakan",
"AllIndexersHiddenDueToFilter": "Semua film disembunyikan karena penyaringan yang diterapkan.",
"AnalyticsEnabledHelpText": "Kirimkan informasi penggunaan secara anonim ke server Radarr. Informasi tersebut mengandung browser kamu, halaman WebUI Radarr yang kamu gunakan, pelaporan masalah serta OS dan versi runtime. Kami akan memanfaatkan informasi ini untuk memprioritaskan fitur dan perbaikan bug.",
"ConnectionLostReconnect": "Radarr akan mencoba untuk menghubungi secara otomatis, atau klik muat ulang di bawah."
"ConnectionLostReconnect": "Radarr akan mencoba untuk menghubungi secara otomatis, atau klik muat ulang di bawah.",
"AuthBasic": "Dasar (Popup Browser)",
"AuthForm": "Formulir (Halaman Login)"
}

View File

@@ -347,5 +347,10 @@
"ConnectionLostReconnect": "Radarr mun reyna að tengjast sjálfkrafa eða þú getur smellt á endurhlaða hér að neðan.",
"minutes": "Fundargerð",
"NotificationStatusAllClientHealthCheckMessage": "Allir listar eru ekki tiltækir vegna bilana",
"NotificationStatusSingleClientHealthCheckMessage": "Listar ekki tiltækir vegna bilana: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "Listar ekki tiltækir vegna bilana: {0}",
"AuthBasic": "Grunn (sprettiglugga vafra)",
"AuthForm": "Eyðublöð (Innskráningarsíða)",
"DisabledForLocalAddresses": "Óvirkt vegna heimilisfanga",
"None": "Enginn",
"ResetAPIKeyMessageText": "Ertu viss um að þú viljir endurstilla API lykilinn þinn?"
}

View File

@@ -497,5 +497,10 @@
"minutes": "Minuti",
"AddConnection": "Aggiungi Connessione",
"NotificationStatusAllClientHealthCheckMessage": "Tutte le applicazioni non sono disponibili a causa di errori",
"NotificationStatusSingleClientHealthCheckMessage": "Applicazioni non disponibili a causa di errori: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "Applicazioni non disponibili a causa di errori: {0}",
"AuthForm": "Moduli (Pagina di Accesso)",
"DisabledForLocalAddresses": "Disabilitato per Indirizzi Locali",
"None": "Nessuna",
"ResetAPIKeyMessageText": "Sei sicuro di voler reimpostare la tua chiave API?",
"AuthBasic": "Base (Popup del Browser)"
}

View File

@@ -347,5 +347,10 @@
"WhatsNew": "新着情報?",
"minutes": "議事録",
"NotificationStatusSingleClientHealthCheckMessage": "失敗のため利用できないリスト:{0}",
"NotificationStatusAllClientHealthCheckMessage": "障害のため、すべてのリストを利用できません"
"NotificationStatusAllClientHealthCheckMessage": "障害のため、すべてのリストを利用できません",
"AuthBasic": "基本(ブラウザポップアップ)",
"AuthForm": "フォーム(ログインページ)",
"DisabledForLocalAddresses": "ローカルアドレスでは無効",
"None": "なし",
"ResetAPIKeyMessageText": "APIキーをリセットしてもよろしいですか"
}

View File

@@ -346,5 +346,10 @@
"ConnectionLostToBackend": "Radarr는 백엔드와의 연결이 끊어졌으며 기능을 복원하려면 다시 로딩해야 합니다.",
"DeleteAppProfileMessageText": "품질 프로필 {0}을 (를) 삭제 하시겠습니까?",
"NotificationStatusAllClientHealthCheckMessage": "실패로 인해 모든 목록을 사용할 수 없습니다.",
"NotificationStatusSingleClientHealthCheckMessage": "실패로 인해 사용할 수없는 목록 : {0}"
"NotificationStatusSingleClientHealthCheckMessage": "실패로 인해 사용할 수없는 목록 : {0}",
"AuthBasic": "기본 (브라우저 팝업)",
"AuthForm": "양식 (로그인 페이지)",
"DisabledForLocalAddresses": "로컬 주소에 대해 비활성화됨",
"None": "없음",
"ResetAPIKeyMessageText": "API 키를 재설정하시겠습니까?"
}

View File

@@ -131,5 +131,9 @@
"ConnectionLostReconnect": "Radarr vil forsøke å koble til automatisk, eller du kan klikke oppdater nedenfor.",
"ConnectionLostToBackend": "Radarr har mistet tilkoblingen til baksystemet og må lastes inn på nytt for å gjenopprette funksjonalitet.",
"DeleteAppProfileMessageText": "Er du sikker på at du vil slette denne forsinkelsesprofilen?",
"AddConnection": "Legg til kobling"
"AddConnection": "Legg til kobling",
"AuthBasic": "Grunnleggende (nettleser -popup)",
"AuthForm": "Skjemaer (påloggingsside)",
"DisabledForLocalAddresses": "Deaktivert for lokale adresser",
"ResetAPIKeyMessageText": "Er du sikker på at du vil tilbakestille API -nøkkelen din?"
}

View File

@@ -450,6 +450,14 @@
"minutes": "Minuten",
"DeleteAppProfileMessageText": "Bent u zeker dat u het kwaliteitsprofiel {0} wilt verwijderen",
"NotificationStatusSingleClientHealthCheckMessage": "Applicaties onbeschikbaar door fouten",
"AddConnection": "Bewerk collectie",
"NotificationStatusAllClientHealthCheckMessage": "Alle applicaties onbeschikbaar door fouten"
"AddConnection": "Voeg connectie toe",
"NotificationStatusAllClientHealthCheckMessage": "Alle applicaties onbeschikbaar door fouten",
"AuthBasic": "Basis (Browser Pop-up)",
"AuthForm": "Formulier (Login Pagina)",
"DisabledForLocalAddresses": "Uitgeschakeld voor lokale adressen",
"None": "Geen",
"ResetAPIKeyMessageText": "Bent u zeker dat u uw API-sleutel wilt resetten?",
"AddConnectionImplementation": "Voeg connectie toe - {implementationName}",
"AddDownloadClientImplementation": "Voeg Downloadclient toe - {implementationName}",
"AddIndexerImplementation": "Indexeerder toevoegen - {implementationName}"
}

View File

@@ -369,5 +369,10 @@
"minutes": "Minuty",
"NotificationStatusSingleClientHealthCheckMessage": "Listy niedostępne z powodu błędów: {0}",
"AddConnection": "Edytuj kolekcję",
"NotificationStatusAllClientHealthCheckMessage": "Wszystkie listy są niedostępne z powodu błędów"
"NotificationStatusAllClientHealthCheckMessage": "Wszystkie listy są niedostępne z powodu błędów",
"AuthForm": "Formularze (strona logowania)",
"DisabledForLocalAddresses": "Wyłączone dla adresów lokalnych",
"None": "Żaden",
"AuthBasic": "Podstawowe (wyskakujące okienko przeglądarki)",
"ResetAPIKeyMessageText": "Czy na pewno chcesz zresetować swój klucz API?"
}

View File

@@ -439,5 +439,10 @@
"RecentChanges": "Mudanças recentes",
"minutes": "Minutos",
"DeleteAppProfileMessageText": "Tem a certeza que quer eliminar o perfil de qualidade \"{0}\"?",
"AddConnection": "Editar Coleção"
"AddConnection": "Editar Coleção",
"AuthBasic": "Básico (pop-up do browser)",
"AuthForm": "Formulários (página de início de sessão)",
"DisabledForLocalAddresses": "Desativado para endereços locais",
"None": "Nenhum",
"ResetAPIKeyMessageText": "Tem a certeza que quer repor a Chave da API?"
}

View File

@@ -45,14 +45,14 @@
"AudioSearch": "Pesquisar Áudio",
"Auth": "Autenticação",
"Authentication": "Autenticação",
"AuthenticationMethodHelpText": "Requer nome de usuário e senha para acessar o Prowlarr",
"AuthenticationMethodHelpText": "Exigir nome de usuário e senha para acessar {appName}",
"AuthenticationRequired": "Autentificação Requerida",
"AuthenticationRequiredHelpText": "Altere para quais solicitações a autenticação é necessária. Não mude a menos que você entenda os riscos.",
"AuthenticationRequiredWarning": "Para impedir o acesso remoto sem autenticação, o Prowlarr agora exige que a autenticação seja habilitada. Configure seu método de autenticação e credenciais. Você pode, opcionalmente, desabilitar a autenticação de endereços locais. Consulte o FAQ para obter informações adicionais.",
"AuthenticationRequiredWarning": "Para evitar o acesso remoto sem autenticação, {appName} agora exige que a autenticação esteja habilitada. Opcionalmente, você pode desabilitar a autenticação de endereços locais.",
"Author": "Autor",
"Automatic": "Automático",
"AutomaticSearch": "Pesquisa Automática",
"AverageResponseTimesMs": "Tempos Médios de Resposta (Ms)",
"AverageResponseTimesMs": "Tempos Médios de Resposta do Indexador (ms)",
"Backup": "Backup",
"BackupFolderHelpText": "Os caminhos relativos estarão no diretório AppData do Prowlarr",
"BackupIntervalHelpText": "Intervalo entre backups automáticos",
@@ -215,7 +215,7 @@
"IndexerSite": "Site do Indexador",
"IndexerStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a falhas",
"IndexerStatusCheckSingleClientMessage": "Indexadores indisponíveis devido a falhas: {0}",
"IndexerTagsHelpText": "Usar etiquetas para especificar os proxies do indexador ou com quais aplicativos o indexador está sincronizado. Aplicativos sem 1 ou mais etiquetas de indexador correspondentes não serão sincronizados.",
"IndexerTagsHelpText": "Use tags para especificar Proxies do indexador ou com quais aplicativos o indexador está sincronizado.",
"IndexerVipCheckExpiredClientMessage": "Benefícios VIP do Indexador expiraram: {0}",
"IndexerVipCheckExpiringClientMessage": "Os benefícios VIPS do Indexador expirarão em breve: {0}",
"Indexers": "Indexadores",
@@ -576,5 +576,26 @@
"EditIndexerImplementation": "Editar Indexador - {implementationName}",
"EditIndexerProxyImplementation": "Editar Proxy do Indexador - {implementationName}",
"NotificationStatusAllClientHealthCheckMessage": "Todas as notificações estão indisponíveis devido a falhas",
"NotificationStatusSingleClientHealthCheckMessage": "Notificações indisponíveis devido a falhas: {0}"
"NotificationStatusSingleClientHealthCheckMessage": "Notificações indisponíveis devido a falhas: {0}",
"AuthForm": "Formulário (Página de login)",
"AuthenticationMethod": "Método de Autenticação",
"AuthenticationMethodHelpTextWarning": "Selecione um método de autenticação válido",
"AuthenticationRequiredPasswordHelpTextWarning": "Insira uma nova senha",
"AuthenticationRequiredUsernameHelpTextWarning": "Digite um novo nome de usuário",
"Clone": "Clonar",
"DefaultNameCopiedProfile": "{name} - Cópia",
"DisabledForLocalAddresses": "Desativado para Endereços Locais",
"External": "Externo",
"None": "Vazio",
"ResetAPIKeyMessageText": "Tem certeza de que deseja redefinir sua chave de API?",
"AuthBasic": "Básico (Balão do Navegador)",
"ActiveIndexers": "Indexadores Ativos",
"ActiveApps": "Apps Ativos",
"IndexerHistoryLoadError": "Erro ao carregar o histórico do indexador",
"NoIndexerHistory": "Nenhum histórico encontrado para este indexador",
"TotalGrabs": "Total de Capturas",
"TotalQueries": "Total de Consultas",
"ApplicationTagsHelpText": "Sincronize indexadores com este aplicativo que não possuem tags ou que possuem 1 ou mais tags correspondentes",
"ApplicationTagsHelpTextWarning": "As tags devem ser usadas com cautela, pois podem ter efeitos indesejados. Um aplicativo com uma tag só será sincronizado com indexadores que tenham a mesma tag.",
"IndexerTagsHelpTextWarning": "As tags devem ser usadas com cautela, pois podem ter efeitos indesejados. Um indexador com uma tag sincronizará apenas com aplicativos com a mesma tag."
}

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