Compare commits

...

59 Commits

Author SHA1 Message Date
Bogdan
94634234ff Update categories for M-Team TP 2024-04-13 23:33:30 +03:00
Bogdan
a48d6029d9 Show releases with issues in the interactive search 2024-04-13 09:48:33 +03:00
Bogdan
9cc150b105 Fix AB tests 2024-04-13 09:14:43 +03:00
Bogdan
6a97d99876 Fixed: (AnimeBytes) Enable Use Filenames for Single Episodes by default 2024-04-13 07:52:33 +03:00
Josh McKinney
c957168040 Add DevContainer, VSCode config and extensions.json
(cherry picked from commit 5061dc4b5e5ea9925740496a5939a1762788b793)
2024-04-10 23:51:13 +03:00
Mark McDowall
61bc35b3fa New: Option to prefix app name on Telegram notification titles
(cherry picked from commit 37863a8deb339ef730b2dd5be61e1da1311fdd23)
2024-04-10 23:46:09 +03:00
Weblate
a84210c452 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Michael5564445 <michaelvelosk@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translation: Servarr/Prowlarr
2024-04-09 22:56:41 +03:00
Bogdan
8af6ea1d8f New: Retry on failed indexer requests 2024-04-09 22:05:11 +03:00
Bogdan
1a894ac583 Fixed: Matching at least 2 terms in the filter releases by query 2024-04-09 18:07:55 +03:00
bakerboy448
4f6e05414c Drop beta (Preview) from login meta description (#2097) 2024-04-09 17:30:26 +03:00
Bogdan
5096a088d4 Fixed: (IPTorrents) Improve category selector 2024-04-09 04:49:27 +03:00
Bogdan
6581bddba3 Detect shfs mounts 2024-04-08 22:27:42 +03:00
Bogdan
292af28d42 Bump version to 1.16.1 2024-04-07 07:59:28 +03:00
Bogdan
37a6d03d52 Fixed: (XSpeeds) Update categories
Co-authored-by: Garfield69 <garfield69@outlook.com>
2024-04-07 01:37:26 +03:00
Bogdan
fe35d450f0 Use info urls as guid and add remaster name to title for SecretCinema 2024-04-06 21:36:58 +03:00
Mark McDowall
6a9e27bc06 Fixed: Sending ntfy.sh notifications with unicode characters
(cherry picked from commit a169ebff2adda5c8585c6aae6249b1c1f7c12264)
2024-04-06 16:49:03 +03:00
Bogdan
a989bf82ea Fixed: (Gazelle) Ignore ineligible releases with Use Freeleech Token 2024-04-06 00:51:34 +03:00
Mark McDowall
ccc8d8002f Fixed: Testing SABnzbd when no categories are configured
(cherry picked from commit 0e31281828c737e3f6eecbb870960194888a970a)
2024-04-05 19:42:19 +03:00
Bogdan
eaaf8db486 Update timezone for ExoticaZ 2024-04-04 00:51:22 +03:00
Bogdan
c32fa7a84b Update timezone for FL & AvistaZ 2024-04-04 00:47:03 +03:00
Weblate
57e21a78ee Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Fixer <ygj59783@zslsz.com>
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/el/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
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/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/pt/
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/th/
Translation: Servarr/Prowlarr
2024-04-02 17:34:07 +03:00
Bogdan
9cdf5d18d8 Fixed: Categories for Newznab/Torznab in add indexer 2024-04-02 16:01:41 +03:00
Bogdan
41b0a1211b Fixed: Migrate categories to capabilities in Newznab/Torznab settings 2024-04-02 13:07:11 +03:00
Bogdan
1b8f09f2ce Fixed: Improve capabilities fetching for applications sync 2024-04-01 17:55:26 +03:00
Bogdan
2f85de6b69 Add capabilities to Newznab & Torznab tests 2024-04-01 04:37:13 +03:00
Bogdan
b2ef9d5b0a Fixed: Filter invalid releases without categories or size 2024-04-01 03:54:02 +03:00
Bogdan
c80262d75b Translation fixes for health checks 2024-04-01 02:43:31 +03:00
Weblate
2a312d93ec Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Jason54 <jason54700.jg@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translation: Servarr/Prowlarr
2024-04-01 02:26:50 +03:00
Weblate
e09df2fff3 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translation: Servarr/Prowlarr
2024-04-01 02:22:47 +03:00
Mark McDowall
f0c7d13b20 Translations for health checks
Use named tokens for backend translations

(cherry picked from commit 11f96c31048c2d1aafca0c91736d439f7f9a95a8)
2024-04-01 02:18:17 +03:00
Bogdan
4dac60bef9 Fixed: Displaying capabilities for Newznab and Torznab feeds (#2083) 2024-04-01 00:49:31 +03:00
Bogdan
5aefb46790 Fixed: Check VIP expiration only for enabled indexers
Check on ProviderBulkUpdatedEvent as well

Fixes #2082
2024-03-31 15:11:15 +03:00
Bogdan
41b043e551 Fixed: (Cardigann) Log invalid category values 2024-03-30 16:48:02 +02:00
Bogdan
5447fad1fc Fixed: (Cardigann) Deprecate noappend for category and categorydesc 2024-03-30 16:46:30 +02:00
Bogdan
6a1e01abbd Disable Shizaproject due to being unusable 2024-03-29 02:54:56 +02:00
Bogdan
2803ad5ba0 Update name for RuTracker.org
Co-authored-by: ilike2burnthing <59480337+ilike2burnthing@users.noreply.github.com>
2024-03-29 01:43:52 +02:00
Bogdan
8fa8a13036 Bump version to 1.16.0 2024-03-28 03:41:53 +02:00
Servarr
41ce79ccce Automated API Docs update 2024-03-28 02:24:29 +02:00
Bogdan
14ae062db2 Fixed: Http Client getting network interfaces on aarch64
Co-authored-by: Louis R <covert8@noreply.github.com>

Fixes #2076
2024-03-28 01:49:38 +02:00
Bogdan
d55a38da4a New: Allow HEAD requests to ping endpoint 2024-03-27 18:54:57 +02:00
Weblate
ab289cfc86 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Altair <villagermd@outlook.com>
Co-authored-by: Charles Follet <follet2004@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Stanislav <prekop3@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translation: Servarr/Prowlarr
2024-03-27 18:54:49 +02:00
Bogdan
12671e9905 New: Advanced settings toggle in indexer, notification and download client modals 2024-03-26 19:24:49 +02:00
Bogdan
a33023b8c6 New: Migrate M-Team - TP to API 2024-03-25 20:24:32 +02:00
Bogdan
a3e134ce0b Link indexer proxy settings from health page 2024-03-23 15:59:26 +02:00
Weblate
ee7c821cab Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Jason54 <jason54700.jg@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translation: Servarr/Prowlarr
2024-03-23 15:58:31 +02:00
Bogdan
ee4cf93aee Improve Indexer Proxy healthcheck messaging 2024-03-23 15:56:34 +02:00
Mark McDowall
2cacfba81f Fixed: Task progress messages in the UI
(cherry picked from commit c6417337812f3578a27f9dc1e44fdad80f557271)
2024-03-22 11:38:56 +02:00
Bogdan
02e420580e Fixed: (SubsPlease) Season search improvements and support for movie searches
Co-authored-by: Florent Delrieu <fdelrieu@klanik.com>
2024-03-21 18:40:44 +02:00
Bogdan
d99398d3f8 Fix tests for PHD 2024-03-21 14:02:19 +02:00
Bogdan
9ea8335aa0 Update timezone offset for PHD/CZ 2024-03-20 02:57:29 +02:00
Bogdan
52a91a50b2 Remove duplicated parameter 2024-03-19 21:35:43 +02:00
Bogdan
680bf46e25 Fixed: (SceneHD) Category filtering
Fixes #2028
2024-03-19 21:34:20 +02:00
Bogdan
d279c97f15 New: Pass general proxy credentials to FlareSolverr
Fixes #2073
2024-03-19 15:02:11 +02:00
Bogdan
7d5d338c8e Improve search page button colors
Also show all buttons on one line for info indexer modal

Fixes #2046
2024-03-19 14:40:20 +02:00
Bogdan
721ae1cac0 Fixed: (Cardigann) Avoid NullRef on forms with multipart/form-data 2024-03-19 00:39:42 +02:00
Bogdan
3881c9d753 Remove bulk edit for Reject Blocklisted Torrent Hashes While Grabbing 2024-03-17 19:57:34 +02:00
Servarr
131b344119 Automated API Docs update 2024-03-17 19:55:36 +02:00
Bogdan
d226e52881 Fixed: Move Reject Blocklisted Torrent Hashes While Grabbing to applications 2024-03-17 19:40:44 +02:00
Bogdan
583815b4f7 Bump version to 1.15.0 2024-03-17 15:11:07 +02:00
132 changed files with 2657 additions and 1003 deletions

View File

@@ -0,0 +1,19 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
{
"name": "Prowlarr",
"image": "mcr.microsoft.com/devcontainers/dotnet:1-6.0",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"nodeGypDependencies": true,
"version": "16",
"nvmVersion": "latest"
}
},
"forwardPorts": [9696],
"customizations": {
"vscode": {
"extensions": ["esbenp.prettier-vscode"]
}
}
}

12
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for more information:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
# https://containers.dev/guide/dependabot
version: 2
updates:
- package-ecosystem: "devcontainers"
directory: "/"
schedule:
interval: weekly

1
.gitignore vendored
View File

@@ -127,6 +127,7 @@ coverage*.xml
coverage*.json
setup/Output/
*.~is
.mono
# VS outout folders
bin

7
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"ms-dotnettools.csdevkit",
"ms-vscode-remote.remote-containers"
]
}

26
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md
"name": "Run Prowlarr",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build dotnet",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/_output/net6.0/Prowlarr",
"args": [],
"cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "integratedTerminal",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

44
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,44 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build dotnet",
"command": "dotnet",
"type": "process",
"args": [
"msbuild",
"-restore",
"${workspaceFolder}/src/Prowlarr.sln",
"-p:GenerateFullPaths=true",
"-p:Configuration=Debug",
"-p:Platform=Posix",
"-consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/src/Prowlarr.sln",
"-property:GenerateFullPaths=true",
"-consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/src/Prowlarr.sln"
],
"problemMatcher": "$msCompile"
}
]
}

View File

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

View File

@@ -19,7 +19,6 @@ interface SavePayload {
seedRatio?: number;
seedTime?: number;
packSeedTime?: number;
rejectBlocklistedTorrentHashesWhileGrabbing?: boolean;
}
interface EditIndexerModalContentProps {
@@ -66,10 +65,6 @@ function EditIndexerModalContent(props: EditIndexerModalContentProps) {
const [packSeedTime, setPackSeedTime] = useState<null | string | number>(
null
);
const [
rejectBlocklistedTorrentHashesWhileGrabbing,
setRejectBlocklistedTorrentHashesWhileGrabbing,
] = useState(NO_CHANGE);
const save = useCallback(() => {
let hasChanges = false;
@@ -110,12 +105,6 @@ function EditIndexerModalContent(props: EditIndexerModalContentProps) {
payload.packSeedTime = packSeedTime as number;
}
if (rejectBlocklistedTorrentHashesWhileGrabbing !== NO_CHANGE) {
hasChanges = true;
payload.rejectBlocklistedTorrentHashesWhileGrabbing =
rejectBlocklistedTorrentHashesWhileGrabbing === 'true';
}
if (hasChanges) {
onSavePress(payload);
}
@@ -129,7 +118,6 @@ function EditIndexerModalContent(props: EditIndexerModalContentProps) {
seedRatio,
seedTime,
packSeedTime,
rejectBlocklistedTorrentHashesWhileGrabbing,
onSavePress,
onModalClose,
]);
@@ -158,9 +146,6 @@ function EditIndexerModalContent(props: EditIndexerModalContentProps) {
case 'packSeedTime':
setPackSeedTime(value);
break;
case 'rejectBlocklistedTorrentHashesWhileGrabbing':
setRejectBlocklistedTorrentHashesWhileGrabbing(value);
break;
default:
console.warn(`EditIndexersModalContent Unknown Input: '${name}'`);
}
@@ -268,23 +253,6 @@ function EditIndexerModalContent(props: EditIndexerModalContentProps) {
onChange={onInputChange}
/>
</FormGroup>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>
{translate('IndexerSettingsRejectBlocklistedTorrentHashes')}
</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="rejectBlocklistedTorrentHashesWhileGrabbing"
value={rejectBlocklistedTorrentHashesWhileGrabbing}
values={enableOptions}
helpText={translate(
'IndexerSettingsRejectBlocklistedTorrentHashesHelpText'
)}
onChange={onInputChange}
/>
</FormGroup>
</ModalBody>
<ModalFooter className={styles.modalFooter}>

View File

@@ -47,9 +47,3 @@
justify-content: space-between;
}
@media only screen and (max-width: $breakpointExtraSmall) {
.modalFooter {
flex-direction: column;
gap: 10px;
}
}

View File

@@ -212,7 +212,11 @@ class SearchFooter extends Component {
name="searchQuery"
value={searchQuery}
buttons={
<FormInputButton onPress={this.onQueryParameterModalOpenClick}>
<FormInputButton
kind={kinds.DEFAULT}
onPress={this.onQueryParameterModalOpenClick}
title={translate('ClickToChangeQueryOptions')}
>
<Icon
name={icon}
/>
@@ -275,6 +279,7 @@ class SearchFooter extends Component {
}
<SpinnerButton
kind={kinds.PRIMARY}
className={styles.searchButton}
isSpinning={isFetching}
isDisabled={isFetching || !hasIndexers}

View File

@@ -17,6 +17,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { icons, inputTypes, kinds } from 'Helpers/Props';
import AdvancedSettingsButton from 'Settings/AdvancedSettingsButton';
import translate from 'Utilities/String/translate';
import AddCategoryModalConnector from './Categories/AddCategoryModalConnector';
import Category from './Categories/Category';
@@ -61,6 +62,7 @@ class EditDownloadClientModalContent extends Component {
onModalClose,
onSavePress,
onTestPress,
onAdvancedSettingsPress,
onDeleteDownloadClientPress,
onConfirmDeleteCategory,
...otherProps
@@ -219,6 +221,12 @@ class EditDownloadClientModalContent extends Component {
</Button>
}
<AdvancedSettingsButton
advancedSettings={advancedSettings}
onAdvancedSettingsPress={onAdvancedSettingsPress}
showLabel={false}
/>
<SpinnerErrorButton
isSpinning={isTesting}
error={saveError}
@@ -260,6 +268,7 @@ EditDownloadClientModalContent.propTypes = {
onModalClose: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onTestPress: PropTypes.func.isRequired,
onAdvancedSettingsPress: PropTypes.func.isRequired,
onDeleteDownloadClientPress: PropTypes.func,
onConfirmDeleteCategory: PropTypes.func.isRequired
};

View File

@@ -2,7 +2,15 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { deleteDownloadClientCategory, fetchDownloadClientCategories, saveDownloadClient, setDownloadClientFieldValue, setDownloadClientValue, testDownloadClient } from 'Store/Actions/settingsActions';
import {
deleteDownloadClientCategory,
fetchDownloadClientCategories,
saveDownloadClient,
setDownloadClientFieldValue,
setDownloadClientValue,
testDownloadClient,
toggleAdvancedSettings
} from 'Store/Actions/settingsActions';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import EditDownloadClientModalContent from './EditDownloadClientModalContent';
@@ -27,7 +35,8 @@ const mapDispatchToProps = {
saveDownloadClient,
testDownloadClient,
fetchDownloadClientCategories,
deleteDownloadClientCategory
deleteDownloadClientCategory,
toggleAdvancedSettings
};
class EditDownloadClientModalContentConnector extends Component {
@@ -68,6 +77,10 @@ class EditDownloadClientModalContentConnector extends Component {
this.props.testDownloadClient({ id: this.props.id });
};
onAdvancedSettingsPress = () => {
this.props.toggleAdvancedSettings();
};
onConfirmDeleteCategory = (id) => {
this.props.deleteDownloadClientCategory({ id });
};
@@ -81,6 +94,7 @@ class EditDownloadClientModalContentConnector extends Component {
{...this.props}
onSavePress={this.onSavePress}
onTestPress={this.onTestPress}
onAdvancedSettingsPress={this.onAdvancedSettingsPress}
onInputChange={this.onInputChange}
onFieldChange={this.onFieldChange}
onConfirmDeleteCategory={this.onConfirmDeleteCategory}
@@ -102,6 +116,7 @@ EditDownloadClientModalContentConnector.propTypes = {
setDownloadClientFieldValue: PropTypes.func.isRequired,
saveDownloadClient: PropTypes.func.isRequired,
testDownloadClient: PropTypes.func.isRequired,
toggleAdvancedSettings: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};

View File

@@ -14,6 +14,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props';
import AdvancedSettingsButton from 'Settings/AdvancedSettingsButton';
import translate from 'Utilities/String/translate';
import styles from './EditIndexerProxyModalContent.css';
@@ -31,6 +32,7 @@ function EditIndexerProxyModalContent(props) {
onModalClose,
onSavePress,
onTestPress,
onAdvancedSettingsPress,
onDeleteIndexerProxyPress,
...otherProps
} = props;
@@ -130,6 +132,12 @@ function EditIndexerProxyModalContent(props) {
</Button>
}
<AdvancedSettingsButton
advancedSettings={advancedSettings}
onAdvancedSettingsPress={onAdvancedSettingsPress}
showLabel={false}
/>
<SpinnerErrorButton
isSpinning={isTesting}
error={saveError}
@@ -169,6 +177,7 @@ EditIndexerProxyModalContent.propTypes = {
onModalClose: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onTestPress: PropTypes.func.isRequired,
onAdvancedSettingsPress: PropTypes.func.isRequired,
onDeleteIndexerProxyPress: PropTypes.func
};

View File

@@ -2,7 +2,13 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { saveIndexerProxy, setIndexerProxyFieldValue, setIndexerProxyValue, testIndexerProxy } from 'Store/Actions/settingsActions';
import {
saveIndexerProxy,
setIndexerProxyFieldValue,
setIndexerProxyValue,
testIndexerProxy,
toggleAdvancedSettings
} from 'Store/Actions/settingsActions';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import EditIndexerProxyModalContent from './EditIndexerProxyModalContent';
@@ -23,7 +29,8 @@ const mapDispatchToProps = {
setIndexerProxyValue,
setIndexerProxyFieldValue,
saveIndexerProxy,
testIndexerProxy
testIndexerProxy,
toggleAdvancedSettings
};
class EditIndexerProxyModalContentConnector extends Component {
@@ -56,6 +63,10 @@ class EditIndexerProxyModalContentConnector extends Component {
this.props.testIndexerProxy({ id: this.props.id });
};
onAdvancedSettingsPress = () => {
this.props.toggleAdvancedSettings();
};
//
// Render
@@ -65,6 +76,7 @@ class EditIndexerProxyModalContentConnector extends Component {
{...this.props}
onSavePress={this.onSavePress}
onTestPress={this.onTestPress}
onAdvancedSettingsPress={this.onAdvancedSettingsPress}
onInputChange={this.onInputChange}
onFieldChange={this.onFieldChange}
/>
@@ -82,6 +94,7 @@ EditIndexerProxyModalContentConnector.propTypes = {
setIndexerProxyFieldValue: PropTypes.func.isRequired,
saveIndexerProxy: PropTypes.func.isRequired,
testIndexerProxy: PropTypes.func.isRequired,
toggleAdvancedSettings: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};

View File

@@ -14,6 +14,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props';
import AdvancedSettingsButton from 'Settings/AdvancedSettingsButton';
import translate from 'Utilities/String/translate';
import NotificationEventItems from './NotificationEventItems';
import styles from './EditNotificationModalContent.css';
@@ -32,6 +33,7 @@ function EditNotificationModalContent(props) {
onModalClose,
onSavePress,
onTestPress,
onAdvancedSettingsPress,
onDeleteNotificationPress,
...otherProps
} = props;
@@ -136,6 +138,12 @@ function EditNotificationModalContent(props) {
</Button>
}
<AdvancedSettingsButton
advancedSettings={advancedSettings}
onAdvancedSettingsPress={onAdvancedSettingsPress}
showLabel={false}
/>
<SpinnerErrorButton
isSpinning={isTesting}
error={saveError}
@@ -175,6 +183,7 @@ EditNotificationModalContent.propTypes = {
onModalClose: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onTestPress: PropTypes.func.isRequired,
onAdvancedSettingsPress: PropTypes.func.isRequired,
onDeleteNotificationPress: PropTypes.func
};

View File

@@ -2,7 +2,13 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { saveNotification, setNotificationFieldValue, setNotificationValue, testNotification } from 'Store/Actions/settingsActions';
import {
saveNotification,
setNotificationFieldValue,
setNotificationValue,
testNotification,
toggleAdvancedSettings
} from 'Store/Actions/settingsActions';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import EditNotificationModalContent from './EditNotificationModalContent';
@@ -23,7 +29,8 @@ const mapDispatchToProps = {
setNotificationValue,
setNotificationFieldValue,
saveNotification,
testNotification
testNotification,
toggleAdvancedSettings
};
class EditNotificationModalContentConnector extends Component {
@@ -56,6 +63,10 @@ class EditNotificationModalContentConnector extends Component {
this.props.testNotification({ id: this.props.id });
};
onAdvancedSettingsPress = () => {
this.props.toggleAdvancedSettings();
};
//
// Render
@@ -65,6 +76,7 @@ class EditNotificationModalContentConnector extends Component {
{...this.props}
onSavePress={this.onSavePress}
onTestPress={this.onTestPress}
onAdvancedSettingsPress={this.onAdvancedSettingsPress}
onInputChange={this.onInputChange}
onFieldChange={this.onFieldChange}
/>
@@ -82,6 +94,7 @@ EditNotificationModalContentConnector.propTypes = {
setNotificationFieldValue: PropTypes.func.isRequired,
saveNotification: PropTypes.func.isRequired,
testNotification: PropTypes.func.isRequired,
toggleAdvancedSettings: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};

View File

@@ -41,6 +41,14 @@ function getInternalLink(source) {
to="/settings/connect"
/>
);
case 'IndexerProxyStatusCheck':
return (
<IconButton
name={icons.SETTINGS}
title={translate('Settings')}
to="/settings/indexers"
/>
);
case 'IndexerRssCheck':
case 'IndexerSearchCheck':
case 'IndexerStatusCheck':

View File

@@ -14,7 +14,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="format-detection" content="telephone=no">
<meta name="description" content="Prowlarr (Preview)" />
<meta name="description" content="Prowlarr" />
<link
rel="apple-touch-icon"

View File

@@ -144,16 +144,46 @@
</Otherwise>
</Choose>
<!--
Set architecture to RuntimeInformation.ProcessArchitecture if not specified -->
<Choose>
<When Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)' == 'X64'">
<PropertyGroup>
<Architecture>x64</Architecture>
</PropertyGroup>
</When>
<When Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)' == 'X86'">
<PropertyGroup>
<Architecture>x86</Architecture>
</PropertyGroup>
</When>
<When Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)' == 'Arm64'">
<PropertyGroup>
<Architecture>arm64</Architecture>
</PropertyGroup>
</When>
<When Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)' == 'Arm'">
<PropertyGroup>
<Architecture>arm</Architecture>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<Architecture></Architecture>
</PropertyGroup>
</Otherwise>
</Choose>
<PropertyGroup Condition="'$(IsWindows)' == 'true' and
'$(RuntimeIdentifier)' == ''">
<_UsingDefaultRuntimeIdentifier>true</_UsingDefaultRuntimeIdentifier>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<RuntimeIdentifier>win-$(Architecture)</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(IsLinux)' == 'true' and
'$(RuntimeIdentifier)' == ''">
<_UsingDefaultRuntimeIdentifier>true</_UsingDefaultRuntimeIdentifier>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<RuntimeIdentifier>linux-$(Architecture)</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(IsOSX)' == 'true' and

View File

@@ -10,6 +10,7 @@ using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http.Proxy;
@@ -31,11 +32,14 @@ namespace NzbDrone.Common.Http.Dispatchers
private readonly ICached<System.Net.Http.HttpClient> _httpClientCache;
private readonly ICached<CredentialCache> _credentialCache;
private readonly Logger _logger;
public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider,
ICreateManagedWebProxy createManagedWebProxy,
ICertificateValidationService certificateValidationService,
IUserAgentBuilder userAgentBuilder,
ICacheManager cacheManager)
ICacheManager cacheManager,
Logger logger)
{
_proxySettingsProvider = proxySettingsProvider;
_createManagedWebProxy = createManagedWebProxy;
@@ -44,6 +48,8 @@ namespace NzbDrone.Common.Http.Dispatchers
_httpClientCache = cacheManager.GetCache<System.Net.Http.HttpClient>(typeof(ManagedHttpDispatcher));
_credentialCache = cacheManager.GetCache<CredentialCache>(typeof(ManagedHttpDispatcher), "credentialcache");
_logger = logger;
}
public async Task<HttpResponse> GetResponseAsync(HttpRequest request, CookieContainer cookies)
@@ -277,19 +283,27 @@ namespace NzbDrone.Common.Http.Dispatchers
return _credentialCache.Get("credentialCache", () => new CredentialCache());
}
private static bool HasRoutableIPv4Address()
private bool HasRoutableIPv4Address()
{
// Get all IPv4 addresses from all interfaces and return true if there are any with non-loopback addresses
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
try
{
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
return networkInterfaces.Any(ni =>
ni.OperationalStatus == OperationalStatus.Up &&
ni.GetIPProperties().UnicastAddresses.Any(ip =>
ip.Address.AddressFamily == AddressFamily.InterNetwork &&
!IPAddress.IsLoopback(ip.Address)));
return networkInterfaces.Any(ni =>
ni.OperationalStatus == OperationalStatus.Up &&
ni.GetIPProperties().UnicastAddresses.Any(ip =>
ip.Address.AddressFamily == AddressFamily.InterNetwork &&
!IPAddress.IsLoopback(ip.Address)));
}
catch (Exception e)
{
_logger.Debug(e, "Caught exception while GetAllNetworkInterfaces assuming IPv4 connectivity: {0}", e.Message);
return true;
}
}
private static async ValueTask<Stream> onConnect(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
private async ValueTask<Stream> onConnect(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
{
// Until .NET supports an implementation of Happy Eyeballs (https://tools.ietf.org/html/rfc8305#section-2), let's make IPv4 fallback work in a simple way.
// This issue is being tracked at https://github.com/dotnet/runtime/issues/26177 and expected to be fixed in .NET 6.
@@ -313,7 +327,9 @@ namespace NzbDrone.Common.Http.Dispatchers
catch
{
// Do not retry IPv6 if a routable IPv4 address is available, otherwise continue to attempt IPv6 connections.
useIPv6 = !HasRoutableIPv4Address();
var routableIPv4 = HasRoutableIPv4Address();
_logger.Info("IPv4 is available: {0}, IPv6 will be {1}", routableIPv4, routableIPv4 ? "disabled" : "left enabled");
useIPv6 = !routableIPv4;
}
finally
{

View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class newznab_category_to_capabilities_settingsFixture : MigrationTest<newznab_category_to_capabilities_settings>
{
[Test]
public void should_migrate_categories_when_capabilities_is_not_defined()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Indexers").Row(new
{
Name = "Usenet Indexer",
Redirect = false,
AppProfileId = 0,
DownloadClientId = 0,
Priority = 25,
Added = DateTime.UtcNow,
Implementation = "Newznab",
Settings = new
{
Categories = new[]
{
new { Id = 2000, Name = "Movies" },
new { Id = 5000, Name = "TV" }
}
}.ToJson(),
ConfigContract = "NewznabSettings"
});
});
var items = db.Query<IndexerDefinition40>("SELECT \"Id\", \"Implementation\", \"ConfigContract\", \"Settings\" FROM \"Indexers\"");
items.Should().HaveCount(1);
items.First().Implementation.Should().Be("Newznab");
items.First().ConfigContract.Should().Be("NewznabSettings");
items.First().Settings.Should().ContainKey("capabilities");
items.First().Settings.Should().NotContainKey("categories");
var newznabSettings = items.First().Settings.ToObject<NewznabSettings40>();
newznabSettings.Capabilities.Should().NotBeNull();
newznabSettings.Capabilities.SupportsRawSearch.Should().Be(false);
newznabSettings.Capabilities.Categories.Should().HaveCount(2);
newznabSettings.Capabilities.Categories.Should().Contain(c => c.Id == 2000 && c.Name == "Movies");
newznabSettings.Capabilities.Categories.Should().Contain(c => c.Id == 5000 && c.Name == "TV");
}
[Test]
public void should_migrate_categories_when_capabilities_is_defined()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Indexers").Row(new
{
Name = "Usenet Indexer",
Redirect = false,
AppProfileId = 0,
DownloadClientId = 0,
Priority = 25,
Added = DateTime.UtcNow,
Implementation = "Newznab",
Settings = new
{
Capabilities = new
{
SupportsRawSearch = true
},
Categories = new[]
{
new { Id = 2000, Name = "Movies" },
new { Id = 5000, Name = "TV" }
}
}.ToJson(),
ConfigContract = "NewznabSettings"
});
});
var items = db.Query<IndexerDefinition40>("SELECT \"Id\", \"Implementation\", \"ConfigContract\", \"Settings\" FROM \"Indexers\"");
items.Should().HaveCount(1);
items.First().Implementation.Should().Be("Newznab");
items.First().ConfigContract.Should().Be("NewznabSettings");
items.First().Settings.Should().ContainKey("capabilities");
items.First().Settings.Should().NotContainKey("categories");
var newznabSettings = items.First().Settings.ToObject<NewznabSettings40>();
newznabSettings.Capabilities.Should().NotBeNull();
newznabSettings.Capabilities.SupportsRawSearch.Should().Be(true);
newznabSettings.Capabilities.Categories.Should().HaveCount(2);
newznabSettings.Capabilities.Categories.Should().Contain(c => c.Id == 2000 && c.Name == "Movies");
newznabSettings.Capabilities.Categories.Should().Contain(c => c.Id == 5000 && c.Name == "TV");
}
[Test]
public void should_use_defaults_when_categories_are_empty()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Indexers").Row(new
{
Name = "Usenet Indexer",
Redirect = false,
AppProfileId = 0,
DownloadClientId = 0,
Priority = 25,
Added = DateTime.UtcNow,
Implementation = "Newznab",
Settings = new
{
Categories = Array.Empty<object>()
}.ToJson(),
ConfigContract = "NewznabSettings"
});
});
var items = db.Query<IndexerDefinition40>("SELECT \"Id\", \"Implementation\", \"ConfigContract\", \"Settings\" FROM \"Indexers\"");
items.Should().HaveCount(1);
items.First().Implementation.Should().Be("Newznab");
items.First().ConfigContract.Should().Be("NewznabSettings");
items.First().Settings.Should().ContainKey("capabilities");
items.First().Settings.Should().NotContainKey("categories");
var newznabSettings = items.First().Settings.ToObject<NewznabSettings40>();
newznabSettings.Capabilities.Should().NotBeNull();
newznabSettings.Capabilities.SupportsRawSearch.Should().Be(false);
newznabSettings.Capabilities.Categories.Should().NotBeNull();
newznabSettings.Capabilities.Categories.Should().HaveCount(0);
}
[Test]
public void should_use_defaults_when_settings_are_empty()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Indexers").Row(new
{
Name = "Usenet Indexer",
Redirect = false,
AppProfileId = 0,
DownloadClientId = 0,
Priority = 25,
Added = DateTime.UtcNow,
Implementation = "Newznab",
Settings = new { }.ToJson(),
ConfigContract = "NewznabSettings"
});
});
var items = db.Query<IndexerDefinition40>("SELECT \"Id\", \"Implementation\", \"ConfigContract\", \"Settings\" FROM \"Indexers\"");
items.Should().HaveCount(1);
items.First().Implementation.Should().Be("Newznab");
items.First().ConfigContract.Should().Be("NewznabSettings");
items.First().Settings.Should().NotContainKey("capabilities");
items.First().Settings.Should().NotContainKey("categories");
items.First().Settings.ToObject<NewznabSettings40>().Capabilities.Should().BeNull();
}
}
public class IndexerDefinition40
{
public int Id { get; set; }
public string Implementation { get; set; }
public string ConfigContract { get; set; }
public JObject Settings { get; set; }
}
public class NewznabSettings39
{
public object Categories { get; set; }
}
public class NewznabSettings40
{
public NewznabCapabilitiesSettings40 Capabilities { get; set; }
}
public class NewznabCapabilitiesSettings40
{
public bool SupportsRawSearch { get; set; }
public List<IndexerCategory40> Categories { get; set; }
}
public class IndexerCategory40
{
public int Id { get; set; }
public string Name { get; set; }
}
}

View File

@@ -25,7 +25,7 @@ namespace NzbDrone.Core.Test.Framework
Mocker.SetConstant<IHttpProxySettingsProvider>(new HttpProxySettingsProvider(Mocker.Resolve<ConfigService>()));
Mocker.SetConstant<ICreateManagedWebProxy>(new ManagedWebProxyFactory(Mocker.Resolve<CacheManager>()));
Mocker.SetConstant<ICertificateValidationService>(new X509CertificateValidationService(Mocker.Resolve<ConfigService>(), TestLogger));
Mocker.SetConstant<IHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<ICertificateValidationService>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<CacheManager>()));
Mocker.SetConstant<IHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<ICertificateValidationService>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<CacheManager>(), TestLogger));
Mocker.SetConstant<IHttpClient>(new HttpClient(Array.Empty<IHttpRequestInterceptor>(), Mocker.Resolve<CacheManager>(), Mocker.Resolve<RateLimitService>(), Mocker.Resolve<IHttpDispatcher>(), TestLogger));
Mocker.SetConstant<IProwlarrCloudRequestBuilder>(new ProwlarrCloudRequestBuilder());
}

View File

@@ -45,10 +45,10 @@ namespace NzbDrone.Core.Test.IndexerTests.AnimeBytesTests
var releases = (await Subject.Fetch(new BasicSearchCriteria { SearchTerm = "test", Categories = new[] { 2000, 5000 } })).Releases;
releases.Should().HaveCount(33);
releases.Should().HaveCount(39);
releases.First().Should().BeOfType<TorrentInfo>();
var firstTorrentInfo = releases.ElementAt(2) as TorrentInfo;
var firstTorrentInfo = releases.ElementAt(3) as TorrentInfo;
firstTorrentInfo.Title.Should().Be("[SubsPlease] One Piece: The Great Gold Pirate - 1059 [Web][MKV][h264][720p][AAC 2.0][Softsubs (SubsPlease)][Episode 1059]");
firstTorrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
@@ -66,7 +66,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AnimeBytesTests
firstTorrentInfo.Files.Should().Be(1);
firstTorrentInfo.MinimumSeedTime.Should().Be(259200);
var secondTorrentInfo = releases.ElementAt(16) as TorrentInfo;
var secondTorrentInfo = releases.ElementAt(20) as TorrentInfo;
secondTorrentInfo.Title.Should().Be("[GHOST] BLEACH S03 [Blu-ray][MKV][h265 10-bit][1080p][AC3 2.0][Dual Audio][Softsubs (GHOST)]");
secondTorrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
@@ -84,7 +84,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AnimeBytesTests
secondTorrentInfo.Files.Should().Be(22);
secondTorrentInfo.MinimumSeedTime.Should().Be(655200);
var thirdTorrentInfo = releases.ElementAt(18) as TorrentInfo;
var thirdTorrentInfo = releases.ElementAt(23) as TorrentInfo;
thirdTorrentInfo.Title.Should().Be("[Polarwindz] Cowboy Bebop: Tengoku no Tobira 2001 [Blu-ray][MKV][h265 10-bit][1080p][Opus 5.1][Softsubs (Polarwindz)]");
thirdTorrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
@@ -102,7 +102,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AnimeBytesTests
thirdTorrentInfo.Files.Should().Be(1);
thirdTorrentInfo.MinimumSeedTime.Should().Be(475200);
var fourthTorrentInfo = releases.ElementAt(3) as TorrentInfo;
var fourthTorrentInfo = releases.ElementAt(5) as TorrentInfo;
fourthTorrentInfo.Title.Should().Be("[SubsPlease] Dr. STONE: NEW WORLD S03E03 - 03 [Web][MKV][h264][720p][AAC 2.0][Softsubs (SubsPlease)][Episode 3]");
fourthTorrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
@@ -120,7 +120,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AnimeBytesTests
fourthTorrentInfo.Files.Should().Be(1);
fourthTorrentInfo.MinimumSeedTime.Should().Be(259200);
var fifthTorrentInfo = releases.ElementAt(23) as TorrentInfo;
var fifthTorrentInfo = releases.ElementAt(28) as TorrentInfo;
fifthTorrentInfo.Title.Should().Be("[-ZR-] Dr. STONE: STONE WARS S02 [Web][MKV][h264][1080p][AAC 2.0][Dual Audio][Softsubs (-ZR-)]");
fifthTorrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
@@ -138,7 +138,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AnimeBytesTests
fifthTorrentInfo.Files.Should().Be(11);
fifthTorrentInfo.MinimumSeedTime.Should().Be(529200);
var sixthTorrentInfo = releases.ElementAt(31) as TorrentInfo;
var sixthTorrentInfo = releases.ElementAt(37) as TorrentInfo;
sixthTorrentInfo.Title.Should().Be("[HorribleSubs] Dr. STONE S01 [Web][MKV][h264][720p][AAC 2.0][Softsubs (HorribleSubs)]");
sixthTorrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);

View File

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

View File

@@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests
torrentInfo.InfoUrl.Should().Be("https://exoticaz.to/torrent/64040-ssis-419-my-first-experience-is-yua-mikami-from-the-day-i-lost-my-virginity-i-was-devoted-to-sex");
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-06-11 10:04:50"));
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-06-11 09:04:50"));
torrentInfo.Size.Should().Be(7085405541);
torrentInfo.InfoHash.Should().Be("asdjfiasdf54asd7f4a2sdf544asdf");
torrentInfo.MagnetUrl.Should().Be(null);

View File

@@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AvistazTests
torrentInfo.InfoUrl.Should().Be("https://privatehd.to/torrent/78506-godzilla-2014-2160p-uhd-bluray-remux-hdr-hevc-atmos-triton");
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-03-21 05:24:49"));
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2021-03-21 04:24:49"));
torrentInfo.Size.Should().Be(69914591044);
torrentInfo.InfoHash.Should().Be("a879261d4e6e792402f92401141a21de70d51bf2");
torrentInfo.MagnetUrl.Should().Be(null);

View File

@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
torrentInfo.InfoUrl.Should().Be("https://filelist.io/details.php?id=665873");
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 20:20:19"));
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 19:20:19"));
torrentInfo.Size.Should().Be(8300512414);
torrentInfo.InfoHash.Should().Be(null);
torrentInfo.MagnetUrl.Should().Be(null);

View File

@@ -33,6 +33,10 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
};
_caps = new IndexerCapabilities();
_caps.Categories.AddCategoryMapping(2000, NewznabStandardCategory.Movies, "Movies");
_caps.Categories.AddCategoryMapping(5000, NewznabStandardCategory.TV, "TV");
Mocker.GetMock<INewznabCapabilitiesProvider>()
.Setup(v => v.GetCapabilities(It.IsAny<NewznabSettings>(), It.IsAny<IndexerDefinition>()))
.Returns(_caps);

View File

@@ -37,6 +37,9 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests
_caps.Categories.AddCategoryMapping(2000, NewznabStandardCategory.Movies, "Movies");
_caps.Categories.AddCategoryMapping(2040, NewznabStandardCategory.MoviesHD, "Movies/HD");
_caps.Categories.AddCategoryMapping(5000, NewznabStandardCategory.TV, "TV");
_caps.Categories.AddCategoryMapping(5040, NewznabStandardCategory.TVHD, "TV/HD");
_caps.Categories.AddCategoryMapping(5070, NewznabStandardCategory.TVAnime, "TV/Anime");
Mocker.GetMock<INewznabCapabilitiesProvider>()
.Setup(v => v.GetCapabilities(It.IsAny<NewznabSettings>(), It.IsAny<IndexerDefinition>()))
@@ -83,23 +86,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests
var releases = (await Subject.Fetch(new MovieSearchCriteria())).Releases;
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var releaseInfo = releases.First() as TorrentInfo;
releaseInfo.Title.Should().Be("Series Title S05E02 HDTV x264-Xclusive [eztv]");
releaseInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
releaseInfo.MagnetUrl.Should().Be("magnet:?xt=urn:btih:9fb267cff5ae5603f07a347676ec3bf3e35f75e1&dn=Game+of+Thrones+S05E02+HDTV+x264-Xclusive+%5Beztv%5D&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969");
releaseInfo.DownloadUrl.Should().Be("magnet:?xt=urn:btih:9fb267cff5ae5603f07a347676ec3bf3e35f75e1&dn=Game+of+Thrones+S05E02+HDTV+x264-Xclusive+%5Beztv%5D&tr=udp:%2F%2Fopen.demonii.com:1337&tr=udp:%2F%2Ftracker.coppersurfer.tk:6969&tr=udp:%2F%2Ftracker.leechers-paradise.org:6969&tr=udp:%2F%2Fexodus.desync.com:6969");
releaseInfo.InfoUrl.Should().Be("https://thepiratebay.se/torrent/11811366/Series_Title_S05E02_HDTV_x264-Xclusive_%5Beztv%5D");
releaseInfo.CommentUrl.Should().Be("https://thepiratebay.se/torrent/11811366/Series_Title_S05E02_HDTV_x264-Xclusive_%5Beztv%5D");
releaseInfo.Indexer.Should().Be(Subject.Definition.Name);
releaseInfo.PublishDate.Should().Be(DateTime.Parse("Sat, 11 Apr 2015 21:34:00 -0600").ToUniversalTime());
releaseInfo.Size.Should().Be(388895872);
releaseInfo.InfoHash.Should().Be("9fb267cff5ae5603f07a347676ec3bf3e35f75e1");
releaseInfo.Seeders.Should().Be(34128);
releaseInfo.Peers.Should().Be(36724);
releases.Should().HaveCount(0);
}
[Test]

View File

@@ -13,6 +13,6 @@ namespace NzbDrone.Core.Applications
public override bool SendUpdatesToClient => true;
public override string CompletionMessage => null;
public override string CompletionMessage => "Completed";
}
}

View File

@@ -15,12 +15,14 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
private readonly ILazyLibrarianV1Proxy _lazyLibrarianV1Proxy;
private readonly IConfigFileProvider _configFileProvider;
private readonly IIndexerFactory _indexerFactory;
public LazyLibrarian(ILazyLibrarianV1Proxy lazyLibrarianV1Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger)
public LazyLibrarian(ILazyLibrarianV1Proxy lazyLibrarianV1Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, IIndexerFactory indexerFactory, Logger logger)
: base(appIndexerMapService, logger)
{
_lazyLibrarianV1Proxy = lazyLibrarianV1Proxy;
_configFileProvider = configFileProvider;
_indexerFactory = indexerFactory;
}
public override ValidationResult Test()
@@ -65,7 +67,9 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
public override void AddIndexer(IndexerDefinition indexer)
{
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
@@ -74,7 +78,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
_logger.Trace("Adding indexer {0} [{1}]", indexer.Name, indexer.Id);
var lazyLibrarianIndexer = BuildLazyLibrarianIndexer(indexer, indexer.Protocol);
var lazyLibrarianIndexer = BuildLazyLibrarianIndexer(indexer, indexerCapabilities, indexer.Protocol);
var remoteIndexer = _lazyLibrarianV1Proxy.AddIndexer(lazyLibrarianIndexer, Settings);
@@ -107,11 +111,12 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
{
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id);
var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id);
var indexerProps = indexerMapping.RemoteIndexerName.Split(",");
var lazyLibrarianIndexer = BuildLazyLibrarianIndexer(indexer, indexer.Protocol, indexerProps[1]);
var lazyLibrarianIndexer = BuildLazyLibrarianIndexer(indexer, indexerCapabilities, indexer.Protocol, indexerProps[1]);
//Use the old remote id to find the indexer on LazyLibrarian incase the update was from a name change in Prowlarr
var remoteIndexer = _lazyLibrarianV1Proxy.GetIndexer(indexerProps[1], lazyLibrarianIndexer.Type, Settings);
@@ -133,7 +138,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to LazyLibrarian", indexer.Name, indexer.Id);
var newRemoteIndexer = _lazyLibrarianV1Proxy.AddIndexer(lazyLibrarianIndexer, Settings);
@@ -146,7 +151,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
}
}
private LazyLibrarianIndexer BuildLazyLibrarianIndexer(IndexerDefinition indexer, DownloadProtocol protocol, string originalName = null)
private LazyLibrarianIndexer BuildLazyLibrarianIndexer(IndexerDefinition indexer, IndexerCapabilities indexerCapabilities, DownloadProtocol protocol, string originalName = null)
{
var schema = protocol == DownloadProtocol.Usenet ? LazyLibrarianProviderType.Newznab : LazyLibrarianProviderType.Torznab;
@@ -156,7 +161,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
Altername = $"{indexer.Name} (Prowlarr)",
Host = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/api",
Apikey = _configFileProvider.ApiKey,
Categories = string.Join(",", indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())),
Categories = string.Join(",", indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())),
Enabled = indexer.Enable,
Type = schema,
Priority = indexer.Priority

View File

@@ -21,13 +21,15 @@ namespace NzbDrone.Core.Applications.Lidarr
private readonly ILidarrV1Proxy _lidarrV1Proxy;
private readonly ICached<List<LidarrIndexer>> _schemaCache;
private readonly IConfigFileProvider _configFileProvider;
private readonly IIndexerFactory _indexerFactory;
public Lidarr(ICacheManager cacheManager, ILidarrV1Proxy lidarrV1Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger)
public Lidarr(ICacheManager cacheManager, ILidarrV1Proxy lidarrV1Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, IIndexerFactory indexerFactory, Logger logger)
: base(appIndexerMapService, logger)
{
_schemaCache = cacheManager.GetCache<List<LidarrIndexer>>(GetType());
_lidarrV1Proxy = lidarrV1Proxy;
_configFileProvider = configFileProvider;
_indexerFactory = indexerFactory;
}
public override ValidationResult Test()
@@ -49,7 +51,7 @@ namespace NzbDrone.Core.Applications.Lidarr
try
{
failures.AddIfNotNull(_lidarrV1Proxy.TestConnection(BuildLidarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
failures.AddIfNotNull(_lidarrV1Proxy.TestConnection(BuildLidarrIndexer(testIndexer, testIndexer.Capabilities, DownloadProtocol.Usenet), Settings));
}
catch (HttpException ex)
{
@@ -118,7 +120,9 @@ namespace NzbDrone.Core.Applications.Lidarr
public override void AddIndexer(IndexerDefinition indexer)
{
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
@@ -127,7 +131,7 @@ namespace NzbDrone.Core.Applications.Lidarr
_logger.Trace("Adding indexer {0} [{1}]", indexer.Name, indexer.Id);
var lidarrIndexer = BuildLidarrIndexer(indexer, indexer.Protocol);
var lidarrIndexer = BuildLidarrIndexer(indexer, indexerCapabilities, indexer.Protocol);
var remoteIndexer = _lidarrV1Proxy.AddIndexer(lidarrIndexer, Settings);
@@ -159,10 +163,11 @@ namespace NzbDrone.Core.Applications.Lidarr
{
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id);
var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id);
var lidarrIndexer = BuildLidarrIndexer(indexer, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0);
var lidarrIndexer = BuildLidarrIndexer(indexer, indexerCapabilities, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0);
var remoteIndexer = _lidarrV1Proxy.GetIndexer(indexerMapping.RemoteIndexerId, Settings);
@@ -174,7 +179,7 @@ namespace NzbDrone.Core.Applications.Lidarr
{
_logger.Debug("Syncing remote indexer with current settings");
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
// Retain user fields not-affiliated with Prowlarr
lidarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => lidarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -200,7 +205,7 @@ namespace NzbDrone.Core.Applications.Lidarr
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Lidarr", indexer.Name, indexer.Id);
lidarrIndexer.Id = 0;
@@ -214,7 +219,7 @@ namespace NzbDrone.Core.Applications.Lidarr
}
}
private LidarrIndexer BuildLidarrIndexer(IndexerDefinition indexer, DownloadProtocol protocol, int id = 0)
private LidarrIndexer BuildLidarrIndexer(IndexerDefinition indexer, IndexerCapabilities indexerCapabilities, DownloadProtocol protocol, int id = 0)
{
var cacheKey = $"{Settings.BaseUrl}";
var schemas = _schemaCache.Get(cacheKey, () => _lidarrV1Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7));
@@ -250,7 +255,7 @@ namespace NzbDrone.Core.Applications.Lidarr
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/";
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api";
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
if (indexer.Protocol == DownloadProtocol.Torrent)
{
@@ -265,7 +270,7 @@ namespace NzbDrone.Core.Applications.Lidarr
if (lidarrIndexer.Fields.Any(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing"))
{
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.RejectBlocklistedTorrentHashesWhileGrabbing;
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing").Value = Settings.SyncRejectBlocklistedTorrentHashesWhileGrabbing;
}
}

View File

@@ -36,9 +36,12 @@ namespace NzbDrone.Core.Applications.Lidarr
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Lidarr in Settings/General")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), HelpText = "Only Indexers that support these categories will be synced", Advanced = true)]
public IEnumerable<int> SyncCategories { get; set; }
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "ApplicationSettingsSyncRejectBlocklistedTorrentHashes", HelpText = "ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool SyncRejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -15,12 +15,14 @@ namespace NzbDrone.Core.Applications.Mylar
private readonly IMylarV3Proxy _mylarV3Proxy;
private readonly IConfigFileProvider _configFileProvider;
private readonly IIndexerFactory _indexerFactory;
public Mylar(IMylarV3Proxy mylarV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger)
public Mylar(IMylarV3Proxy mylarV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, IIndexerFactory indexerFactory, Logger logger)
: base(appIndexerMapService, logger)
{
_mylarV3Proxy = mylarV3Proxy;
_configFileProvider = configFileProvider;
_indexerFactory = indexerFactory;
}
public override ValidationResult Test()
@@ -65,7 +67,9 @@ namespace NzbDrone.Core.Applications.Mylar
public override void AddIndexer(IndexerDefinition indexer)
{
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
@@ -74,7 +78,7 @@ namespace NzbDrone.Core.Applications.Mylar
_logger.Trace("Adding indexer {0} [{1}]", indexer.Name, indexer.Id);
var mylarIndexer = BuildMylarIndexer(indexer, indexer.Protocol);
var mylarIndexer = BuildMylarIndexer(indexer, indexerCapabilities, indexer.Protocol);
var remoteIndexer = _mylarV3Proxy.AddIndexer(mylarIndexer, Settings);
@@ -107,11 +111,12 @@ namespace NzbDrone.Core.Applications.Mylar
{
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id);
var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id);
var indexerProps = indexerMapping.RemoteIndexerName.Split(",");
var mylarIndexer = BuildMylarIndexer(indexer, indexer.Protocol, indexerProps[1]);
var mylarIndexer = BuildMylarIndexer(indexer, indexerCapabilities, indexer.Protocol, indexerProps[1]);
//Use the old remote id to find the indexer on Mylar incase the update was from a name change in Prowlarr
var remoteIndexer = _mylarV3Proxy.GetIndexer(indexerProps[1], mylarIndexer.Type, Settings);
@@ -133,7 +138,7 @@ namespace NzbDrone.Core.Applications.Mylar
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Mylar", indexer.Name, indexer.Id);
var newRemoteIndexer = _mylarV3Proxy.AddIndexer(mylarIndexer, Settings);
@@ -146,7 +151,7 @@ namespace NzbDrone.Core.Applications.Mylar
}
}
private MylarIndexer BuildMylarIndexer(IndexerDefinition indexer, DownloadProtocol protocol, string originalName = null)
private MylarIndexer BuildMylarIndexer(IndexerDefinition indexer, IndexerCapabilities indexerCapabilities, DownloadProtocol protocol, string originalName = null)
{
var schema = protocol == DownloadProtocol.Usenet ? MylarProviderType.Newznab : MylarProviderType.Torznab;
@@ -156,7 +161,7 @@ namespace NzbDrone.Core.Applications.Mylar
Altername = $"{indexer.Name} (Prowlarr)",
Host = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/api",
Apikey = _configFileProvider.ApiKey,
Categories = string.Join(",", indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())),
Categories = string.Join(",", indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray())),
Enabled = indexer.Enable,
Type = schema,
};

View File

@@ -21,13 +21,15 @@ namespace NzbDrone.Core.Applications.Radarr
private readonly IRadarrV3Proxy _radarrV3Proxy;
private readonly ICached<List<RadarrIndexer>> _schemaCache;
private readonly IConfigFileProvider _configFileProvider;
private readonly IIndexerFactory _indexerFactory;
public Radarr(ICacheManager cacheManager, IRadarrV3Proxy radarrV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger)
public Radarr(ICacheManager cacheManager, IRadarrV3Proxy radarrV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, IIndexerFactory indexerFactory, Logger logger)
: base(appIndexerMapService, logger)
{
_schemaCache = cacheManager.GetCache<List<RadarrIndexer>>(GetType());
_radarrV3Proxy = radarrV3Proxy;
_configFileProvider = configFileProvider;
_indexerFactory = indexerFactory;
}
public override ValidationResult Test()
@@ -49,7 +51,7 @@ namespace NzbDrone.Core.Applications.Radarr
try
{
failures.AddIfNotNull(_radarrV3Proxy.TestConnection(BuildRadarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
failures.AddIfNotNull(_radarrV3Proxy.TestConnection(BuildRadarrIndexer(testIndexer, testIndexer.Capabilities, DownloadProtocol.Usenet), Settings));
}
catch (HttpException ex)
{
@@ -118,7 +120,9 @@ namespace NzbDrone.Core.Applications.Radarr
public override void AddIndexer(IndexerDefinition indexer)
{
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
@@ -127,7 +131,7 @@ namespace NzbDrone.Core.Applications.Radarr
_logger.Trace("Adding indexer {0} [{1}]", indexer.Name, indexer.Id);
var radarrIndexer = BuildRadarrIndexer(indexer, indexer.Protocol);
var radarrIndexer = BuildRadarrIndexer(indexer, indexerCapabilities, indexer.Protocol);
var remoteIndexer = _radarrV3Proxy.AddIndexer(radarrIndexer, Settings);
@@ -159,10 +163,11 @@ namespace NzbDrone.Core.Applications.Radarr
{
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id);
var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id);
var radarrIndexer = BuildRadarrIndexer(indexer, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0);
var radarrIndexer = BuildRadarrIndexer(indexer, indexerCapabilities, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0);
var remoteIndexer = _radarrV3Proxy.GetIndexer(indexerMapping.RemoteIndexerId, Settings);
@@ -172,7 +177,7 @@ namespace NzbDrone.Core.Applications.Radarr
if (!radarrIndexer.Equals(remoteIndexer) || forceSync)
{
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
// Retain user fields not-affiliated with Prowlarr
radarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => radarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -198,7 +203,7 @@ namespace NzbDrone.Core.Applications.Radarr
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Radarr", indexer.Name, indexer.Id);
radarrIndexer.Id = 0;
@@ -212,7 +217,7 @@ namespace NzbDrone.Core.Applications.Radarr
}
}
private RadarrIndexer BuildRadarrIndexer(IndexerDefinition indexer, DownloadProtocol protocol, int id = 0)
private RadarrIndexer BuildRadarrIndexer(IndexerDefinition indexer, IndexerCapabilities indexerCapabilities, DownloadProtocol protocol, int id = 0)
{
var cacheKey = $"{Settings.BaseUrl}";
var schemas = _schemaCache.Get(cacheKey, () => _radarrV3Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7));
@@ -248,7 +253,7 @@ namespace NzbDrone.Core.Applications.Radarr
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/";
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api";
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
if (indexer.Protocol == DownloadProtocol.Torrent)
{
@@ -258,7 +263,7 @@ namespace NzbDrone.Core.Applications.Radarr
if (radarrIndexer.Fields.Any(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing"))
{
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.RejectBlocklistedTorrentHashesWhileGrabbing;
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing").Value = Settings.SyncRejectBlocklistedTorrentHashesWhileGrabbing;
}
}

View File

@@ -37,9 +37,12 @@ namespace NzbDrone.Core.Applications.Radarr
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Radarr in Settings/General")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), HelpText = "Only Indexers that support these categories will be synced", Advanced = true)]
public IEnumerable<int> SyncCategories { get; set; }
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "ApplicationSettingsSyncRejectBlocklistedTorrentHashes", HelpText = "ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool SyncRejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -21,13 +21,15 @@ namespace NzbDrone.Core.Applications.Readarr
private readonly ICached<List<ReadarrIndexer>> _schemaCache;
private readonly IReadarrV1Proxy _readarrV1Proxy;
private readonly IConfigFileProvider _configFileProvider;
private readonly IIndexerFactory _indexerFactory;
public Readarr(ICacheManager cacheManager, IReadarrV1Proxy readarrV1Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger)
public Readarr(ICacheManager cacheManager, IReadarrV1Proxy readarrV1Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, IIndexerFactory indexerFactory, Logger logger)
: base(appIndexerMapService, logger)
{
_schemaCache = cacheManager.GetCache<List<ReadarrIndexer>>(GetType());
_readarrV1Proxy = readarrV1Proxy;
_configFileProvider = configFileProvider;
_indexerFactory = indexerFactory;
}
public override ValidationResult Test()
@@ -49,7 +51,7 @@ namespace NzbDrone.Core.Applications.Readarr
try
{
failures.AddIfNotNull(_readarrV1Proxy.TestConnection(BuildReadarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
failures.AddIfNotNull(_readarrV1Proxy.TestConnection(BuildReadarrIndexer(testIndexer, testIndexer.Capabilities, DownloadProtocol.Usenet), Settings));
}
catch (HttpException ex)
{
@@ -118,7 +120,9 @@ namespace NzbDrone.Core.Applications.Readarr
public override void AddIndexer(IndexerDefinition indexer)
{
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
@@ -127,7 +131,7 @@ namespace NzbDrone.Core.Applications.Readarr
_logger.Trace("Adding indexer {0} [{1}]", indexer.Name, indexer.Id);
var readarrIndexer = BuildReadarrIndexer(indexer, indexer.Protocol);
var readarrIndexer = BuildReadarrIndexer(indexer, indexerCapabilities, indexer.Protocol);
var remoteIndexer = _readarrV1Proxy.AddIndexer(readarrIndexer, Settings);
@@ -159,10 +163,11 @@ namespace NzbDrone.Core.Applications.Readarr
{
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id);
var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id);
var readarrIndexer = BuildReadarrIndexer(indexer, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0);
var readarrIndexer = BuildReadarrIndexer(indexer, indexerCapabilities, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0);
var remoteIndexer = _readarrV1Proxy.GetIndexer(indexerMapping.RemoteIndexerId, Settings);
@@ -174,7 +179,7 @@ namespace NzbDrone.Core.Applications.Readarr
{
_logger.Debug("Syncing remote indexer with current settings");
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
// Retain user fields not-affiliated with Prowlarr
readarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => readarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -200,7 +205,7 @@ namespace NzbDrone.Core.Applications.Readarr
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Readarr", indexer.Name, indexer.Id);
readarrIndexer.Id = 0;
@@ -214,7 +219,7 @@ namespace NzbDrone.Core.Applications.Readarr
}
}
private ReadarrIndexer BuildReadarrIndexer(IndexerDefinition indexer, DownloadProtocol protocol, int id = 0)
private ReadarrIndexer BuildReadarrIndexer(IndexerDefinition indexer, IndexerCapabilities indexerCapabilities, DownloadProtocol protocol, int id = 0)
{
var cacheKey = $"{Settings.BaseUrl}";
var schemas = _schemaCache.Get(cacheKey, () => _readarrV1Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7));
@@ -244,7 +249,7 @@ namespace NzbDrone.Core.Applications.Readarr
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/";
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api";
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
if (indexer.Protocol == DownloadProtocol.Torrent)
{
@@ -259,7 +264,7 @@ namespace NzbDrone.Core.Applications.Readarr
if (readarrIndexer.Fields.Any(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing"))
{
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.RejectBlocklistedTorrentHashesWhileGrabbing;
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing").Value = Settings.SyncRejectBlocklistedTorrentHashesWhileGrabbing;
}
}

View File

@@ -37,9 +37,12 @@ namespace NzbDrone.Core.Applications.Readarr
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Readarr in Settings/General")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), HelpText = "Only Indexers that support these categories will be synced", Advanced = true)]
public IEnumerable<int> SyncCategories { get; set; }
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "ApplicationSettingsSyncRejectBlocklistedTorrentHashes", HelpText = "ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool SyncRejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -21,13 +21,15 @@ namespace NzbDrone.Core.Applications.Sonarr
private readonly ICached<List<SonarrIndexer>> _schemaCache;
private readonly ISonarrV3Proxy _sonarrV3Proxy;
private readonly IConfigFileProvider _configFileProvider;
private readonly IIndexerFactory _indexerFactory;
public Sonarr(ICacheManager cacheManager, ISonarrV3Proxy sonarrV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger)
public Sonarr(ICacheManager cacheManager, ISonarrV3Proxy sonarrV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, IIndexerFactory indexerFactory, Logger logger)
: base(appIndexerMapService, logger)
{
_schemaCache = cacheManager.GetCache<List<SonarrIndexer>>(GetType());
_sonarrV3Proxy = sonarrV3Proxy;
_configFileProvider = configFileProvider;
_indexerFactory = indexerFactory;
}
public override ValidationResult Test()
@@ -49,7 +51,7 @@ namespace NzbDrone.Core.Applications.Sonarr
try
{
failures.AddIfNotNull(_sonarrV3Proxy.TestConnection(BuildSonarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
failures.AddIfNotNull(_sonarrV3Proxy.TestConnection(BuildSonarrIndexer(testIndexer, testIndexer.Capabilities, DownloadProtocol.Usenet), Settings));
}
catch (HttpException ex)
{
@@ -122,8 +124,10 @@ namespace NzbDrone.Core.Applications.Sonarr
public override void AddIndexer(IndexerDefinition indexer)
{
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty() &&
indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Empty())
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty() &&
indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
@@ -132,7 +136,7 @@ namespace NzbDrone.Core.Applications.Sonarr
_logger.Trace("Adding indexer {0} [{1}]", indexer.Name, indexer.Id);
var sonarrIndexer = BuildSonarrIndexer(indexer, indexer.Protocol);
var sonarrIndexer = BuildSonarrIndexer(indexer, indexerCapabilities, indexer.Protocol);
var remoteIndexer = _sonarrV3Proxy.AddIndexer(sonarrIndexer, Settings);
@@ -164,10 +168,11 @@ namespace NzbDrone.Core.Applications.Sonarr
{
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id);
var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id);
var sonarrIndexer = BuildSonarrIndexer(indexer, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0);
var sonarrIndexer = BuildSonarrIndexer(indexer, indexerCapabilities, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0);
var remoteIndexer = _sonarrV3Proxy.GetIndexer(indexerMapping.RemoteIndexerId, Settings);
@@ -179,7 +184,7 @@ namespace NzbDrone.Core.Applications.Sonarr
{
_logger.Debug("Syncing remote indexer with current settings");
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any())
{
// Retain user fields not-affiliated with Prowlarr
sonarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => sonarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -206,7 +211,7 @@ namespace NzbDrone.Core.Applications.Sonarr
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any())
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Sonarr", indexer.Name, indexer.Id);
sonarrIndexer.Id = 0;
@@ -220,7 +225,7 @@ namespace NzbDrone.Core.Applications.Sonarr
}
}
private SonarrIndexer BuildSonarrIndexer(IndexerDefinition indexer, DownloadProtocol protocol, int id = 0)
private SonarrIndexer BuildSonarrIndexer(IndexerDefinition indexer, IndexerCapabilities indexerCapabilities, DownloadProtocol protocol, int id = 0)
{
var cacheKey = $"{Settings.BaseUrl}";
var schemas = _schemaCache.Get(cacheKey, () => _sonarrV3Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7));
@@ -256,8 +261,8 @@ namespace NzbDrone.Core.Applications.Sonarr
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/";
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api";
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "animeCategories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()));
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "animeCategories").Value = JArray.FromObject(indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()));
if (sonarrIndexer.Fields.Any(x => x.Name == "animeStandardFormatSearch"))
{
@@ -273,7 +278,7 @@ namespace NzbDrone.Core.Applications.Sonarr
if (sonarrIndexer.Fields.Any(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing"))
{
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.RejectBlocklistedTorrentHashesWhileGrabbing;
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing").Value = Settings.SyncRejectBlocklistedTorrentHashesWhileGrabbing;
}
}

View File

@@ -43,9 +43,12 @@ namespace NzbDrone.Core.Applications.Sonarr
[FieldDefinition(4, Label = "Anime Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]
public IEnumerable<int> AnimeSyncCategories { get; set; }
[FieldDefinition(5, Label = "Sync Anime Standard Format Search", Type = FieldType.Checkbox, Advanced = true, HelpText = "Sync also searching for anime using the standard numbering")]
[FieldDefinition(5, Label = "Sync Anime Standard Format Search", Type = FieldType.Checkbox, HelpText = "Sync also searching for anime using the standard numbering", Advanced = true)]
public bool SyncAnimeStandardFormatSearch { get; set; }
[FieldDefinition(6, Type = FieldType.Checkbox, Label = "ApplicationSettingsSyncRejectBlocklistedTorrentHashes", HelpText = "ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool SyncRejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -21,13 +21,15 @@ namespace NzbDrone.Core.Applications.Whisparr
private readonly IWhisparrV3Proxy _whisparrV3Proxy;
private readonly ICached<List<WhisparrIndexer>> _schemaCache;
private readonly IConfigFileProvider _configFileProvider;
private readonly IIndexerFactory _indexerFactory;
public Whisparr(ICacheManager cacheManager, IWhisparrV3Proxy whisparrV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, Logger logger)
public Whisparr(ICacheManager cacheManager, IWhisparrV3Proxy whisparrV3Proxy, IConfigFileProvider configFileProvider, IAppIndexerMapService appIndexerMapService, IIndexerFactory indexerFactory, Logger logger)
: base(appIndexerMapService, logger)
{
_schemaCache = cacheManager.GetCache<List<WhisparrIndexer>>(GetType());
_whisparrV3Proxy = whisparrV3Proxy;
_configFileProvider = configFileProvider;
_indexerFactory = indexerFactory;
}
public override ValidationResult Test()
@@ -49,7 +51,7 @@ namespace NzbDrone.Core.Applications.Whisparr
try
{
failures.AddIfNotNull(_whisparrV3Proxy.TestConnection(BuildWhisparrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
failures.AddIfNotNull(_whisparrV3Proxy.TestConnection(BuildWhisparrIndexer(testIndexer, testIndexer.Capabilities, DownloadProtocol.Usenet), Settings));
}
catch (HttpException ex)
{
@@ -118,7 +120,9 @@ namespace NzbDrone.Core.Applications.Whisparr
public override void AddIndexer(IndexerDefinition indexer)
{
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
@@ -127,7 +131,7 @@ namespace NzbDrone.Core.Applications.Whisparr
_logger.Trace("Adding indexer {0} [{1}]", indexer.Name, indexer.Id);
var whisparrIndexer = BuildWhisparrIndexer(indexer, indexer.Protocol);
var whisparrIndexer = BuildWhisparrIndexer(indexer, indexerCapabilities, indexer.Protocol);
var remoteIndexer = _whisparrV3Proxy.AddIndexer(whisparrIndexer, Settings);
@@ -159,10 +163,11 @@ namespace NzbDrone.Core.Applications.Whisparr
{
_logger.Debug("Updating indexer {0} [{1}]", indexer.Name, indexer.Id);
var indexerCapabilities = _indexerFactory.GetInstance(indexer).GetCapabilities();
var appMappings = _appIndexerMapService.GetMappingsForApp(Definition.Id);
var indexerMapping = appMappings.FirstOrDefault(m => m.IndexerId == indexer.Id);
var whisparrIndexer = BuildWhisparrIndexer(indexer, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0);
var whisparrIndexer = BuildWhisparrIndexer(indexer, indexerCapabilities, indexer.Protocol, indexerMapping?.RemoteIndexerId ?? 0);
var remoteIndexer = _whisparrV3Proxy.GetIndexer(indexerMapping.RemoteIndexerId, Settings);
@@ -174,7 +179,7 @@ namespace NzbDrone.Core.Applications.Whisparr
{
_logger.Debug("Syncing remote indexer with current settings");
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
// Retain user fields not-affiliated with Prowlarr
whisparrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => whisparrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -200,7 +205,7 @@ namespace NzbDrone.Core.Applications.Whisparr
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Whisparr", indexer.Name, indexer.Id);
whisparrIndexer.Id = 0;
@@ -214,7 +219,7 @@ namespace NzbDrone.Core.Applications.Whisparr
}
}
private WhisparrIndexer BuildWhisparrIndexer(IndexerDefinition indexer, DownloadProtocol protocol, int id = 0)
private WhisparrIndexer BuildWhisparrIndexer(IndexerDefinition indexer, IndexerCapabilities indexerCapabilities, DownloadProtocol protocol, int id = 0)
{
var cacheKey = $"{Settings.BaseUrl}";
var schemas = _schemaCache.Get(cacheKey, () => _whisparrV3Proxy.GetIndexerSchema(Settings), TimeSpan.FromDays(7));
@@ -244,7 +249,7 @@ namespace NzbDrone.Core.Applications.Whisparr
whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/";
whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api";
whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));
if (indexer.Protocol == DownloadProtocol.Torrent)
{
@@ -259,7 +264,7 @@ namespace NzbDrone.Core.Applications.Whisparr
if (whisparrIndexer.Fields.Any(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing"))
{
whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing").Value = ((ITorrentIndexerSettings)indexer.Settings).TorrentBaseSettings.RejectBlocklistedTorrentHashesWhileGrabbing;
whisparrIndexer.Fields.FirstOrDefault(x => x.Name == "rejectBlocklistedTorrentHashesWhileGrabbing").Value = Settings.SyncRejectBlocklistedTorrentHashesWhileGrabbing;
}
}

View File

@@ -37,9 +37,12 @@ namespace NzbDrone.Core.Applications.Whisparr
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Whisparr in Settings/General")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), HelpText = "Only Indexers that support these categories will be synced", Advanced = true)]
public IEnumerable<int> SyncCategories { get; set; }
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "ApplicationSettingsSyncRejectBlocklistedTorrentHashes", HelpText = "ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool SyncRejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Data;
using Dapper;
using FluentMigrator;
using Newtonsoft.Json.Linq;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(40)]
public class newznab_category_to_capabilities_settings : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(MoveCategoriesToCapabilities);
}
private void MoveCategoriesToCapabilities(IDbConnection conn, IDbTransaction tran)
{
var updated = new List<object>();
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Indexers\" WHERE \"Implementation\" IN ('Newznab', 'Torznab')";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var id = reader.GetInt32(0);
var settings = Json.Deserialize<JObject>(reader.GetString(1));
if ((settings.Value<JObject>("capabilities")?.ContainsKey("categories") ?? false) == false
&& settings.ContainsKey("categories")
&& settings.TryGetValue("categories", out var categories))
{
if (!settings.ContainsKey("capabilities"))
{
settings.Add("capabilities", new JObject());
}
settings.Value<JObject>("capabilities")?.Add(new JProperty("categories", JArray.FromObject(categories)));
if (settings.ContainsKey("categories"))
{
settings.Remove("categories");
}
}
updated.Add(new
{
Settings = settings.ToJson(),
Id = id
});
}
}
}
var updateSql = "UPDATE \"Indexers\" SET \"Settings\" = @Settings WHERE \"Id\" = @Id";
conn.Execute(updateSql, updated, transaction: tran);
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Newtonsoft.Json;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters;
@@ -7,10 +7,14 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
public class SabnzbdConfig
{
public SabnzbdConfig()
{
Categories = new List<SabnzbdCategory>();
Servers = new List<object>();
}
public SabnzbdConfigMisc Misc { get; set; }
public List<SabnzbdCategory> Categories { get; set; }
public List<object> Servers { get; set; }
}

View File

@@ -1,4 +1,5 @@
using NLog;
using System.Collections.Generic;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Configuration.Events;
using NzbDrone.Core.Lifecycle;
@@ -28,7 +29,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
_logger.Warn("Please update your API key to be at least {0} characters long. You can do this via settings or the config file", MinimumLength);
return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("ApiKeyValidationHealthCheckMessage"), MinimumLength), "#invalid-api-key");
return new HealthCheck(GetType(), HealthCheckResult.Warning, _localizationService.GetLocalizedString("ApiKeyValidationHealthCheckMessage", new Dictionary<string, object> { { "length", MinimumLength } }), "#invalid-api-key");
}
return new HealthCheck(GetType());

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Download;
@@ -39,10 +40,19 @@ namespace NzbDrone.Core.HealthCheck.Checks
if (backOffProviders.Count == enabledProviders.Count)
{
return new HealthCheck(GetType(), HealthCheckResult.Error, _localizationService.GetLocalizedString("DownloadClientStatusCheckAllClientMessage"), "#download-clients-are-unavailable-due-to-failures");
return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("DownloadClientStatusAllClientHealthCheckMessage"),
"#download-clients-are-unavailable-due-to-failures");
}
return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("DownloadClientStatusCheckSingleClientMessage"), string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))), "#download-clients-are-unavailable-due-to-failures");
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
_localizationService.GetLocalizedString("DownloadClientStatusSingleClientHealthCheckMessage", new Dictionary<string, object>
{
{ "downloadClientNames", string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name)) }
}),
"#download-clients-are-unavailable-due-to-failures");
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Download;
using NzbDrone.Core.Indexers;
@@ -39,7 +40,10 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("IndexerDownloadClientHealthCheckMessage"), string.Join(", ", invalidIndexers.Select(v => v.Name).ToArray())),
_localizationService.GetLocalizedString("IndexerDownloadClientHealthCheckMessage", new Dictionary<string, object>
{
{ "indexerNames", string.Join(", ", invalidIndexers.Select(v => v.Name).ToArray()) }
}),
"#invalid-indexer-download-client-setting");
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers;
@@ -17,9 +18,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
private readonly IIndexerFactory _providerFactory;
private readonly IIndexerStatusService _providerStatusService;
public IndexerLongTermStatusCheck(IIndexerFactory providerFactory,
IIndexerStatusService providerStatusService,
ILocalizationService localizationService)
public IndexerLongTermStatusCheck(IIndexerFactory providerFactory, IIndexerStatusService providerStatusService, ILocalizationService localizationService)
: base(localizationService)
{
_providerFactory = providerFactory;
@@ -46,14 +45,16 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("IndexerLongTermStatusCheckAllClientMessage"),
_localizationService.GetLocalizedString("IndexerLongTermStatusAllUnavailableHealthCheckMessage"),
"#indexers-are-unavailable-due-to-failures");
}
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("IndexerLongTermStatusCheckSingleClientMessage"),
string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))),
_localizationService.GetLocalizedString("IndexerLongTermStatusUnavailableHealthCheckMessage", new Dictionary<string, object>
{
{ "indexerNames", string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name)) }
}),
"#indexers-are-unavailable-due-to-failures");
}
}

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.IndexerProxies;
@@ -9,11 +10,11 @@ namespace NzbDrone.Core.HealthCheck.Checks
[CheckOn(typeof(ProviderDeletedEvent<IIndexerProxy>))]
[CheckOn(typeof(ProviderAddedEvent<IIndexerProxy>))]
[CheckOn(typeof(ProviderUpdatedEvent<IIndexerProxy>))]
public class IndexerProxyCheck : HealthCheckBase
public class IndexerProxyStatusCheck : HealthCheckBase
{
private readonly IIndexerProxyFactory _proxyFactory;
public IndexerProxyCheck(IIndexerProxyFactory proxyFactory,
public IndexerProxyStatusCheck(IIndexerProxyFactory proxyFactory,
ILocalizationService localizationService)
: base(localizationService)
{
@@ -37,15 +38,17 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("IndexerProxyStatusCheckAllClientMessage"),
"#proxies-are-unavailable-due-to-failures");
_localizationService.GetLocalizedString("IndexerProxyStatusAllUnavailableHealthCheckMessage"),
"#indexer-proxies-are-unavailable-due-to-failures");
}
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("IndexerProxyStatusCheckSingleClientMessage"),
string.Join(", ", badProxies.Select(v => v.Definition.Name))),
"#proxies-are-unavailable-due-to-failures");
_localizationService.GetLocalizedString("IndexerProxyStatusUnavailableHealthCheckMessage", new Dictionary<string, object>
{
{ "indexerProxyNames", string.Join(", ", badProxies.Select(v => v.Definition.Name)) }
}),
"#indexer-proxies-are-unavailable-due-to-failures");
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers;
@@ -44,14 +45,16 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("IndexerStatusCheckAllClientMessage"),
_localizationService.GetLocalizedString("IndexerStatusAllUnavailableHealthCheckMessage"),
"#indexers-are-unavailable-due-to-failures");
}
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("IndexerStatusCheckSingleClientMessage"),
string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))),
_localizationService.GetLocalizedString("IndexerStatusUnavailableHealthCheckMessage", new Dictionary<string, object>
{
{ "indexerNames", string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name)) }
}),
"#indexers-are-unavailable-due-to-failures");
}
}

View File

@@ -11,6 +11,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
[CheckOn(typeof(ProviderAddedEvent<IIndexer>))]
[CheckOn(typeof(ProviderUpdatedEvent<IIndexer>))]
[CheckOn(typeof(ProviderDeletedEvent<IIndexer>))]
[CheckOn(typeof(ProviderBulkUpdatedEvent<IIndexer>))]
[CheckOn(typeof(ProviderBulkDeletedEvent<IIndexer>))]
public class IndexerVIPCheck : HealthCheckBase
{
@@ -24,7 +25,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check()
{
var indexers = _indexerFactory.AllProviders(false);
var indexers = _indexerFactory.Enabled(false);
var expiringProviders = new List<IIndexer>();
foreach (var provider in indexers)
@@ -39,12 +40,8 @@ namespace NzbDrone.Core.HealthCheck.Checks
var expiration = (string)vipProp.GetValue(provider.Definition.Settings);
if (expiration.IsNullOrWhiteSpace())
{
continue;
}
if (DateTime.Parse(expiration).Between(DateTime.Now, DateTime.Now.AddDays(7)))
if (expiration.IsNotNullOrWhiteSpace() &&
DateTime.Parse(expiration).Between(DateTime.Now, DateTime.Now.AddDays(7)))
{
expiringProviders.Add(provider);
}
@@ -53,10 +50,12 @@ namespace NzbDrone.Core.HealthCheck.Checks
if (!expiringProviders.Empty())
{
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("IndexerVipCheckExpiringClientMessage"),
string.Join(", ", expiringProviders.Select(v => v.Definition.Name))),
"#indexer-vip-expiring");
HealthCheckResult.Warning,
_localizationService.GetLocalizedString("IndexerVipExpiringHealthCheckMessage", new Dictionary<string, object>
{
{ "indexerNames", string.Join(", ", expiringProviders.Select(v => v.Definition.Name).ToArray()) }
}),
"#indexer-vip-expiring");
}
return new HealthCheck(GetType());

View File

@@ -11,6 +11,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
[CheckOn(typeof(ProviderAddedEvent<IIndexer>))]
[CheckOn(typeof(ProviderUpdatedEvent<IIndexer>))]
[CheckOn(typeof(ProviderDeletedEvent<IIndexer>))]
[CheckOn(typeof(ProviderBulkUpdatedEvent<IIndexer>))]
[CheckOn(typeof(ProviderBulkDeletedEvent<IIndexer>))]
public class IndexerVIPExpiredCheck : HealthCheckBase
{
@@ -24,7 +25,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check()
{
var indexers = _indexerFactory.AllProviders(false);
var indexers = _indexerFactory.Enabled(false);
var expiredProviders = new List<IIndexer>();
foreach (var provider in indexers)
@@ -39,12 +40,8 @@ namespace NzbDrone.Core.HealthCheck.Checks
var expiration = (string)vipProp.GetValue(provider.Definition.Settings);
if (expiration.IsNullOrWhiteSpace())
{
continue;
}
if (DateTime.Parse(expiration).Before(DateTime.Now))
if (expiration.IsNotNullOrWhiteSpace() &&
DateTime.Parse(expiration).Before(DateTime.Now))
{
expiredProviders.Add(provider);
}
@@ -53,10 +50,12 @@ namespace NzbDrone.Core.HealthCheck.Checks
if (!expiredProviders.Empty())
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
string.Format(_localizationService.GetLocalizedString("IndexerVipCheckExpiredClientMessage"),
string.Join(", ", expiredProviders.Select(v => v.Definition.Name))),
"#indexer-vip-expired");
HealthCheckResult.Error,
_localizationService.GetLocalizedString("IndexerVipExpiredHealthCheckMessage", new Dictionary<string, object>
{
{ "indexerNames", string.Join(", ", expiredProviders.Select(v => v.Definition.Name).ToArray()) }
}),
"#indexer-vip-expired");
}
return new HealthCheck(GetType());

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Localization;
@@ -45,7 +46,10 @@ namespace NzbDrone.Core.HealthCheck.Checks
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("NotificationStatusSingleClientHealthCheckMessage"), string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))),
_localizationService.GetLocalizedString("NotificationStatusSingleClientHealthCheckMessage", new Dictionary<string, object>
{
{ "notificationNames", string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name)) }
}),
"#notifications-are-unavailable-due-to-failures");
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using NLog;
@@ -19,7 +20,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
private readonly IHttpRequestBuilderFactory _cloudRequestBuilder;
public ProxyCheck(IProwlarrCloudRequestBuilder cloudRequestBuilder, IConfigService configService, IHttpClient client, ILocalizationService localizationService, Logger logger)
public ProxyCheck(IProwlarrCloudRequestBuilder cloudRequestBuilder, IConfigService configService, IHttpClient client, Logger logger, ILocalizationService localizationService)
: base(localizationService)
{
_configService = configService;
@@ -31,35 +32,58 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check()
{
if (_configService.ProxyEnabled)
if (!_configService.ProxyEnabled)
{
var addresses = Dns.GetHostAddresses(_configService.ProxyHostname);
if (!addresses.Any())
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("ProxyCheckResolveIpMessage"), _configService.ProxyHostname));
}
return new HealthCheck(GetType());
}
var request = _cloudRequestBuilder.Create()
.Resource("/ping")
.Build();
var addresses = Dns.GetHostAddresses(_configService.ProxyHostname);
try
{
var response = _client.Execute(request);
// We only care about 400 responses, other error codes can be ignored
if (response.StatusCode == HttpStatusCode.BadRequest)
if (!addresses.Any())
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("ProxyResolveIpHealthCheckMessage", new Dictionary<string, object>
{
_logger.Error("Proxy Health Check failed: {0}", response.StatusCode);
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("ProxyCheckBadRequestMessage"), response.StatusCode));
}
}
catch (Exception ex)
{ "proxyHostName", _configService.ProxyHostname }
}),
"#proxy-failed-resolve-ip");
}
var request = _cloudRequestBuilder.Create()
.Resource("/ping")
.Build();
try
{
var response = _client.Execute(request);
// We only care about 400 responses, other error codes can be ignored
if (response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Proxy Health Check failed");
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("ProxyCheckFailedToTestMessage"), request.Url));
_logger.Error("Proxy Health Check failed: {0}", response.StatusCode);
return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("ProxyBadRequestHealthCheckMessage", new Dictionary<string, object>
{
{ "statusCode", response.StatusCode }
}),
"#proxy-failed-test");
}
}
catch (Exception ex)
{
_logger.Error(ex, "Proxy Health Check failed");
return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("ProxyFailedToTestHealthCheckMessage", new Dictionary<string, object>
{
{ "url", request.Url }
}),
"#proxy-failed-test");
}
return new HealthCheck(GetType());
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
@@ -47,7 +48,12 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
string.Format(_localizationService.GetLocalizedString("UpdateCheckStartupTranslocationMessage"), startupFolder),
_localizationService.GetLocalizedString(
"UpdateStartupTranslocationHealthCheckMessage",
new Dictionary<string, object>
{
{ "startupFolder", startupFolder }
}),
"#cannot-install-update-because-startup-folder-is-in-an-app-translocation-folder.");
}
@@ -55,7 +61,13 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
string.Format(_localizationService.GetLocalizedString("UpdateCheckStartupNotWritableMessage"), startupFolder, Environment.UserName),
_localizationService.GetLocalizedString(
"UpdateStartupNotWritableHealthCheckMessage",
new Dictionary<string, object>
{
{ "startupFolder", startupFolder },
{ "userName", Environment.UserName }
}),
"#cannot-install-update-because-startup-folder-is-not-writable-by-the-user");
}
@@ -63,14 +75,20 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
string.Format(_localizationService.GetLocalizedString("UpdateCheckUINotWritableMessage"), uiFolder, Environment.UserName),
_localizationService.GetLocalizedString(
"UpdateUiNotWritableHealthCheckMessage",
new Dictionary<string, object>
{
{ "uiFolder", uiFolder },
{ "userName", Environment.UserName }
}),
"#cannot-install-update-because-ui-folder-is-not-writable-by-the-user");
}
}
if (BuildInfo.BuildDateTime < DateTime.UtcNow.AddDays(-14) && _checkUpdateService.AvailableUpdate() != null)
{
return new HealthCheck(GetType(), HealthCheckResult.Warning, _localizationService.GetLocalizedString("UpdateAvailable"), "#new-update-is-available");
return new HealthCheck(GetType(), HealthCheckResult.Warning, _localizationService.GetLocalizedString("UpdateAvailableHealthCheckMessage"));
}
return new HealthCheck(GetType());

View File

@@ -102,9 +102,15 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
var url = request.Url.ToString();
var maxTimeout = Settings.RequestTimeout * 1000;
// Use Proxy if no credentials are set (creds not supported as of FS 2.2.9)
var proxySettings = _proxySettingsProvider.GetProxySettings();
var proxyUrl = proxySettings != null && proxySettings.Username.IsNullOrWhiteSpace() && proxySettings.Password.IsNullOrWhiteSpace() ? GetProxyUri(proxySettings) : null;
var proxyUrl = proxySettings != null ? GetProxyUri(proxySettings) : null;
var requestProxy = new FlareSolverrProxy
{
Url = proxyUrl?.OriginalString,
Username = proxySettings != null && proxySettings.Username.IsNotNullOrWhiteSpace() ? proxySettings.Username : null,
Password = proxySettings != null && proxySettings.Password.IsNotNullOrWhiteSpace() ? proxySettings.Password : null
};
if (request.Method == HttpMethod.Get)
{
@@ -113,10 +119,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
Cmd = "request.get",
Url = url,
MaxTimeout = maxTimeout,
Proxy = new FlareSolverrProxy
{
Url = proxyUrl?.OriginalString
}
Proxy = requestProxy
};
}
else if (request.Method == HttpMethod.Post)
@@ -139,10 +142,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
ContentLength = null
},
MaxTimeout = maxTimeout,
Proxy = new FlareSolverrProxy
{
Url = proxyUrl?.OriginalString
}
Proxy = requestProxy
};
}
else if (contentTypeType.Contains("multipart/form-data")
@@ -169,6 +169,7 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
newRequest.LogResponseContent = true;
newRequest.RequestTimeout = TimeSpan.FromSeconds(Settings.RequestTimeout + 5);
newRequest.SetContent(req.ToJson());
newRequest.ContentSummary = req.ToJson(Formatting.None);
_logger.Debug("Cloudflare Detected, Applying FlareSolverr Proxy {0} to request {1}", Name, request.Url);
@@ -243,6 +244,8 @@ namespace NzbDrone.Core.IndexerProxies.FlareSolverr
private class FlareSolverrProxy
{
public string Url { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
private class HeadersPost

View File

@@ -177,8 +177,8 @@ namespace NzbDrone.Core.IndexerSearch
if (criteriaBase.Categories is { Length: > 0 })
{
//Only query supported indexers
indexers = indexers.Where(i => ((IndexerDefinition)i.Definition).Capabilities.Categories.SupportedCategories(criteriaBase.Categories).Any()).ToList();
// Only query supported indexers
indexers = indexers.Where(i => i.GetCapabilities().Categories.SupportedCategories(criteriaBase.Categories).Any()).ToList();
if (indexers.Count == 0)
{
@@ -196,7 +196,7 @@ namespace NzbDrone.Core.IndexerSearch
var reports = batch.SelectMany(x => x).ToList();
_logger.Debug("Total of {0} reports were found for {1} from {2} indexer(s)", reports.Count, criteriaBase, indexers.Count);
_logger.ProgressDebug("Total of {0} reports were found for {1} from {2} indexer(s)", reports.Count, criteriaBase, indexers.Count);
return reports;
}
@@ -217,7 +217,7 @@ namespace NzbDrone.Core.IndexerSearch
//Filter results to only those in searched categories
if (criteriaBase.Categories.Length > 0)
{
var expandedQueryCats = ((IndexerDefinition)indexer.Definition).Capabilities.Categories.ExpandTorznabQueryCategories(criteriaBase.Categories);
var expandedQueryCats = indexer.GetCapabilities().Categories.ExpandTorznabQueryCategories(criteriaBase.Categories);
releases = releases.Where(result => result.Categories?.Any() != true || expandedQueryCats.Intersect(result.Categories.Select(c => c.Id)).Any()).ToList();

View File

@@ -46,6 +46,8 @@ namespace NzbDrone.Core.IndexerVersions
"desitorrents",
"hdbits",
"lat-team",
"mteamtp",
"mteamtp2fa",
"reelflix",
"shareisland",
"skipthecommercials",

View File

@@ -467,6 +467,11 @@ namespace NzbDrone.Core.Indexers.Definitions
// Ignore these categories as they'll cause hell with the matcher
// TV Special, DVD Special, BD Special
if (groupName is "TV Special" or "DVD Special" or "BD Special")
{
continue;
}
if (groupName is "TV Series" or "OVA" or "ONA")
{
categories = new List<IndexerCategory> { NewznabStandardCategory.TVAnime };
@@ -695,7 +700,7 @@ namespace NzbDrone.Core.Indexers.Definitions
ExcludeHentai = false;
SearchByYear = false;
EnableSonarrCompatibility = true;
UseFilenameForSingleEpisodes = false;
UseFilenameForSingleEpisodes = true;
AddJapaneseTitle = true;
AddRomajiTitle = true;
AddAlternativeTitle = true;

View File

@@ -84,6 +84,6 @@ namespace NzbDrone.Core.Indexers.Definitions
public class AvistaZParser : AvistazParserBase
{
protected override string TimezoneOffset => "+01:00";
protected override string TimezoneOffset => "+02:00";
}
}

View File

@@ -14,7 +14,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
{
public class AvistazParserBase : IParseIndexerResponse
{
protected virtual string TimezoneOffset => "-05:00"; // Avistaz does not specify a timezone & returns server time
protected virtual string TimezoneOffset => "-04:00"; // Avistaz does not specify a timezone & returns server time
private readonly HashSet<string> _hdResolutions = new () { "1080p", "1080i", "720p" };
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }

View File

@@ -771,13 +771,14 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
protected Dictionary<string, string> ParseCustomHeaders(Dictionary<string, List<string>> customHeaders, Dictionary<string, object> variables)
{
var headers = new Dictionary<string, string>();
if (customHeaders == null)
{
return null;
return headers;
}
// FIXME: fix jackett header handling (allow it to specifiy the same header multipe times)
var headers = new Dictionary<string, string>();
foreach (var header in customHeaders)
{
headers.Add(header.Key, ApplyGoTemplateText(header.Value[0], variables));

View File

@@ -502,36 +502,54 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
value = release.Description;
break;
case "category":
if (fieldModifiers.Contains("noappend"))
{
_logger.Warn("The \"noappend\" modifier is deprecated. Please switch to \"default\". See the Definition Format in the Wiki for more information.");
}
var cats = _categories.MapTrackerCatToNewznab(value);
if (cats.Any())
{
if (release.Categories == null || fieldModifiers.Contains("noappend"))
{
release.Categories = cats;
}
else
{
release.Categories = release.Categories.Union(cats).ToList();
}
release.Categories = release.Categories == null || fieldModifiers.Contains("noappend")
? cats
: release.Categories.Union(cats).ToList();
}
if (value.IsNotNullOrWhiteSpace() && !release.Categories.Any())
{
_logger.Warn("[{0}] Invalid category for value: '{1}'", _definition.Id, value);
}
else
{
value = release.Categories.ToString();
}
value = release.Categories.ToString();
break;
case "categorydesc":
var catsDesc = _categories.MapTrackerCatDescToNewznab(value);
if (catsDesc.Any())
if (fieldModifiers.Contains("noappend"))
{
if (release.Categories == null || fieldModifiers.Contains("noappend"))
{
release.Categories = catsDesc;
}
else
{
release.Categories = release.Categories.Union(catsDesc).ToList();
}
_logger.Warn("The \"noappend\" modifier is deprecated. Please switch to \"default\". See the Definition Format in the Wiki for more information.");
}
var catsDesc = _categories.MapTrackerCatDescToNewznab(value);
if (catsDesc.Any())
{
release.Categories = release.Categories == null || fieldModifiers.Contains("noappend")
? catsDesc
: release.Categories.Union(catsDesc).ToList();
}
if (value.IsNotNullOrWhiteSpace() && !release.Categories.Any())
{
_logger.Warn("[{0}] Invalid category for value: '{1}'", _definition.Id, value);
}
else
{
value = release.Categories.ToString();
}
value = release.Categories.ToString();
break;
case "size":
release.Size = ParseUtil.GetBytes(value);

View File

@@ -54,7 +54,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
private readonly IndexerCapabilitiesCategories _categories;
protected override string TimezoneOffset => "+01:00";
protected override string TimezoneOffset => "+02:00";
public ExoticaZParser(IndexerCapabilitiesCategories categories)
{

View File

@@ -77,7 +77,7 @@ public class FileListParser : IParseIndexerResponse
InfoUrl = GetInfoUrl(id),
Seeders = row.Seeders,
Peers = row.Leechers + row.Seeders,
PublishDate = DateTime.Parse(row.UploadDate + " +0200", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
PublishDate = DateTime.Parse(row.UploadDate + " +0300", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
Description = row.SmallDescription,
Genres = row.SmallDescription.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList(),
ImdbId = imdbId,

View File

@@ -59,6 +59,12 @@ public class GazelleParser : IParseIndexerResponse
{
foreach (var torrent in result.Torrents)
{
// skip releases that cannot be used with freeleech tokens when the option is enabled
if (Settings.UseFreeleechToken && !torrent.CanUseToken)
{
continue;
}
var id = torrent.TorrentId;
var title = $"{result.Artist} - {result.GroupName} ({result.GroupYear}) [{torrent.Format} {torrent.Encoding}] [{torrent.Media}]";
@@ -72,14 +78,14 @@ public class GazelleParser : IParseIndexerResponse
var release = new TorrentInfo
{
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id, !torrent.IsFreeLeech && !torrent.IsNeutralLeech && !torrent.IsPersonalFreeLeech),
Title = WebUtility.HtmlDecode(title),
Container = torrent.Encoding,
Files = torrent.FileCount,
Grabs = torrent.Snatches,
Codec = torrent.Format,
Size = long.Parse(torrent.Size),
DownloadUrl = GetDownloadUrl(id, torrent.CanUseToken),
InfoUrl = infoUrl,
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = torrent.Time.ToUniversalTime(),
@@ -104,6 +110,12 @@ public class GazelleParser : IParseIndexerResponse
}
else
{
// skip releases that cannot be used with freeleech tokens when the option is enabled
if (Settings.UseFreeleechToken && !result.CanUseToken)
{
continue;
}
var id = result.TorrentId;
var groupName = WebUtility.HtmlDecode(result.GroupName);
var infoUrl = GetInfoUrl(result.GroupId, id);
@@ -111,10 +123,10 @@ public class GazelleParser : IParseIndexerResponse
var release = new TorrentInfo
{
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id, !result.IsFreeLeech && !result.IsNeutralLeech && !result.IsPersonalFreeLeech),
Title = groupName,
Size = long.Parse(result.Size),
DownloadUrl = GetDownloadUrl(id, result.CanUseToken),
InfoUrl = infoUrl,
Seeders = int.Parse(result.Seeders),
Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders),
Files = result.FileCount,

View File

@@ -168,16 +168,22 @@ public class GreatPosterWallParser : GazelleParser
{
foreach (var torrent in result.Torrents)
{
// skip releases that cannot be used with freeleech tokens when the option is enabled
if (_settings.UseFreeleechToken && !torrent.CanUseToken)
{
continue;
}
var infoUrl = GetInfoUrl(result.GroupId.ToString(), torrent.TorrentId);
var time = DateTime.SpecifyKind(torrent.Time, DateTimeKind.Unspecified);
var release = new TorrentInfo
{
Title = WebUtility.HtmlDecode(torrent.FileName).Trim(),
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(torrent.TorrentId, !torrent.IsFreeleech && !torrent.IsNeutralLeech && !torrent.IsPersonalFreeleech),
Title = WebUtility.HtmlDecode(torrent.FileName).Trim(),
PosterUrl = GetPosterUrl(result.Cover),
DownloadUrl = GetDownloadUrl(torrent.TorrentId, torrent.CanUseToken),
PublishDate = new DateTimeOffset(time, TimeSpan.FromHours(8)).UtcDateTime, // Time is Chinese Time, add 8 hours difference from UTC
Categories = ParseCategories(torrent),
Size = torrent.Size,

View File

@@ -333,7 +333,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var publishDate = DateTimeUtil.FromTimeAgo(dateSplit.First());
var description = descrSplit.Length > 1 ? "Tags: " + descrSplit.First().Trim() : "";
var catIcon = row.QuerySelector("td:nth-of-type(1) a");
var catIcon = row.QuerySelector("td:nth-of-type(1) a[href^=\"?\"]");
if (catIcon == null)
{
// Torrents - Category column == Text or Code
@@ -342,7 +342,7 @@ namespace NzbDrone.Core.Indexers.Definitions
}
// Torrents - Category column == Icons
var cat = _categories.MapTrackerCatToNewznab(catIcon.GetAttribute("href").Substring(1));
var cat = _categories.MapTrackerCatToNewznab(catIcon.GetAttribute("href")?.Substring(1));
var size = ParseUtil.GetBytes(row.Children[sizeIndex].TextContent);

View File

@@ -0,0 +1,496 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using FluentValidation;
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.Exceptions;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions;
public class MTeamTp : TorrentIndexerBase<MTeamTpSettings>
{
public override string Name => "M-Team - TP";
public override string[] IndexerUrls => new[]
{
"https://kp.m-team.cc/",
"https://tp.m-team.cc/",
"https://pt.m-team.cc/"
};
public override string Description => "M-Team TP (MTTP) is a CHINESE Private Torrent Tracker for HD MOVIES / TV / 3X";
public override string Language => "zh-CN";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override int PageSize => 100;
public override TimeSpan RateLimit => TimeSpan.FromSeconds(5);
public override IndexerCapabilities Capabilities => SetCapabilities();
public const string UserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.35";
public MTeamTp(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new MTeamTpRequestGenerator(Settings, Capabilities);
}
public override IParseIndexerResponse GetParser()
{
return new MTeamTpParser(Settings, Capabilities.Categories);
}
public override async Task<byte[]> Download(Uri link)
{
var request = new HttpRequestBuilder(link.ToString())
.SetHeader("x-api-key", Settings.ApiKey)
.Accept(HttpAccept.Json)
.Post()
.Build();
request.Headers.UserAgent = UserAgent;
var response = await _httpClient.ExecuteProxiedAsync(request, Definition);
if (!STJson.TryDeserialize<MTeamTpApiDownloadTokenResponse>(response.Content, out var jsonResponse))
{
throw new ReleaseDownloadException("Invalid response received from M-Team, not a valid JSON");
}
if (jsonResponse.Data.IsNullOrWhiteSpace())
{
throw new ReleaseDownloadException($"Unable to find download link for: {link}");
}
return await base.Download(new Uri(jsonResponse.Data));
}
protected override Task<HttpRequest> GetDownloadRequest(Uri link)
{
var request = new HttpRequest(link.AbsoluteUri)
{
AllowAutoRedirect = true,
Headers =
{
UserAgent = UserAgent
}
};
return Task.FromResult(request);
}
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return false;
}
private static IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(401, NewznabStandardCategory.MoviesSD, "Movie(電影)/SD");
caps.Categories.AddCategoryMapping(419, NewznabStandardCategory.MoviesHD, "Movie(電影)/HD");
caps.Categories.AddCategoryMapping(420, NewznabStandardCategory.MoviesDVD, "Movie(電影)/DVDiSo");
caps.Categories.AddCategoryMapping(421, NewznabStandardCategory.MoviesBluRay, "Movie(電影)/Blu-Ray");
caps.Categories.AddCategoryMapping(439, NewznabStandardCategory.MoviesHD, "Movie(電影)/Remux");
caps.Categories.AddCategoryMapping(403, NewznabStandardCategory.TVSD, "TV Series(影劇/綜藝)/SD");
caps.Categories.AddCategoryMapping(402, NewznabStandardCategory.TVHD, "TV Series(影劇/綜藝)/HD");
caps.Categories.AddCategoryMapping(435, NewznabStandardCategory.TVSD, "TV Series(影劇/綜藝)/DVDiSo");
caps.Categories.AddCategoryMapping(438, NewznabStandardCategory.TVHD, "TV Series(影劇/綜藝)/BD");
caps.Categories.AddCategoryMapping(404, NewznabStandardCategory.TVDocumentary, "紀錄教育");
caps.Categories.AddCategoryMapping(405, NewznabStandardCategory.TVAnime, "Anime(動畫)");
caps.Categories.AddCategoryMapping(407, NewznabStandardCategory.TVSport, "Sports(運動)");
caps.Categories.AddCategoryMapping(422, NewznabStandardCategory.PC0day, "Software(軟體)");
caps.Categories.AddCategoryMapping(423, NewznabStandardCategory.PCGames, "PCGame(PC遊戲)");
caps.Categories.AddCategoryMapping(427, NewznabStandardCategory.BooksEBook, "Study/Edu ebook(教育書面)");
caps.Categories.AddCategoryMapping(441, NewznabStandardCategory.BooksOther, "Study/Edu video(教育影片)");
caps.Categories.AddCategoryMapping(442, NewznabStandardCategory.AudioAudiobook, "Study/Edu audio(教育音檔)");
caps.Categories.AddCategoryMapping(409, NewznabStandardCategory.Other, "Misc(其他)");
// music
caps.Categories.AddCategoryMapping(406, NewznabStandardCategory.AudioVideo, "MV(演唱)");
caps.Categories.AddCategoryMapping(408, NewznabStandardCategory.AudioOther, "Music(AAC/ALAC)");
caps.Categories.AddCategoryMapping(434, NewznabStandardCategory.Audio, "Music(無損)");
// adult
caps.Categories.AddCategoryMapping(410, NewznabStandardCategory.XXX, "AV(有碼)/HD Censored");
caps.Categories.AddCategoryMapping(429, NewznabStandardCategory.XXX, "AV(無碼)/HD Uncensored");
caps.Categories.AddCategoryMapping(424, NewznabStandardCategory.XXXSD, "AV(有碼)/SD Censored");
caps.Categories.AddCategoryMapping(430, NewznabStandardCategory.XXXSD, "AV(無碼)/SD Uncensored");
caps.Categories.AddCategoryMapping(426, NewznabStandardCategory.XXXDVD, "AV(無碼)/DVDiSo Uncensored");
caps.Categories.AddCategoryMapping(437, NewznabStandardCategory.XXXDVD, "AV(有碼)/DVDiSo Censored");
caps.Categories.AddCategoryMapping(431, NewznabStandardCategory.XXX, "AV(有碼)/Blu-Ray Censored");
caps.Categories.AddCategoryMapping(432, NewznabStandardCategory.XXX, "AV(無碼)/Blu-Ray Uncensored");
caps.Categories.AddCategoryMapping(436, NewznabStandardCategory.XXX, "AV(網站)/0Day");
caps.Categories.AddCategoryMapping(425, NewznabStandardCategory.XXX, "IV(寫真影集)/Video Collection");
caps.Categories.AddCategoryMapping(433, NewznabStandardCategory.XXXImageSet, "IV(寫真圖集)/Picture Collection");
caps.Categories.AddCategoryMapping(411, NewznabStandardCategory.XXX, "H-Game(遊戲)");
caps.Categories.AddCategoryMapping(412, NewznabStandardCategory.XXX, "H-Anime(動畫)");
caps.Categories.AddCategoryMapping(413, NewznabStandardCategory.XXX, "H-Comic(漫畫)");
caps.Categories.AddCategoryMapping(440, NewznabStandardCategory.XXX, "AV(Gay)/HD");
return caps;
}
}
public class MTeamTpRequestGenerator : IIndexerRequestGenerator
{
private readonly MTeamTpSettings _settings;
private readonly IndexerCapabilities _capabilities;
private readonly int[] _trackerAdultCategories = { 410, 429, 424, 430, 426, 437, 431, 432, 436, 425, 433, 411, 412, 413, 440 };
public MTeamTpRequestGenerator(MTeamTpSettings settings, IndexerCapabilities capabilities)
{
_settings = settings;
_capabilities = capabilities;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(MTeamTpRequestType.Normal, searchCriteria, searchCriteria.SanitizedSearchTerm, searchCriteria.FullImdbId));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(MTeamTpRequestType.Normal, searchCriteria, searchCriteria.SanitizedTvSearchString, searchCriteria.FullImdbId));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(MTeamTpRequestType.Normal, searchCriteria, searchCriteria.SanitizedSearchTerm));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(MTeamTpRequestType.Normal, searchCriteria, searchCriteria.SanitizedSearchTerm));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(MTeamTpRequestType.Normal, searchCriteria, searchCriteria.SanitizedSearchTerm));
pageableRequests.Add(GetPagedRequests(MTeamTpRequestType.Adult, searchCriteria, searchCriteria.SanitizedSearchTerm));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetPagedRequests(MTeamTpRequestType mTeamTpRequestType, SearchCriteriaBase searchCriteria, string searchTerm, string imdbId = null)
{
var categoryMapping = _capabilities.Categories
.MapTorznabCapsToTrackers(searchCriteria.Categories)
.Select(int.Parse)
.Distinct()
.ToList();
var adultCategories = categoryMapping.Where(c => _trackerAdultCategories.Contains(c)).ToList();
var normalCategories = categoryMapping.Except(adultCategories).ToList();
switch (mTeamTpRequestType)
{
case MTeamTpRequestType.Adult when adultCategories.Any():
yield return BuildSearchRequest(mTeamTpRequestType, adultCategories, searchTerm, imdbId);
break;
case MTeamTpRequestType.Normal when !categoryMapping.Any() || normalCategories.Any():
yield return BuildSearchRequest(mTeamTpRequestType, normalCategories, searchTerm, imdbId);
break;
}
}
private IndexerRequest BuildSearchRequest(MTeamTpRequestType requestType, IEnumerable<int> categoryMapping, string searchTerm, string imdbId)
{
var request = new HttpRequestBuilder(_settings.BaseUrl)
.Resource("/api/torrent/search")
.SetHeader("x-api-key", _settings.ApiKey)
.Accept(HttpAccept.Json)
.Post()
.Build();
var query = new MTeamTpApiSearchQuery
{
Mode = requestType,
Categories = categoryMapping?.Select(x => x.ToString()).ToArray() ?? Array.Empty<string>(),
PageNumber = 1,
PageSize = 100
};
if (imdbId.IsNotNullOrWhiteSpace())
{
query.Imdb = imdbId.Trim();
}
if (searchTerm.IsNotNullOrWhiteSpace())
{
query.Keyword = searchTerm.Trim();
}
if (_settings.FreeleechOnly)
{
query.Discount = "FREE";
}
request.Headers.ContentType = "application/json";
request.SetContent(query.ToJson());
request.ContentSummary = query.ToJson(Formatting.None);
request.Headers.UserAgent = MTeamTp.UserAgent;
return new IndexerRequest(request);
}
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
public class MTeamTpParser : IParseIndexerResponse
{
private readonly MTeamTpSettings _settings;
private readonly IndexerCapabilitiesCategories _categories;
public MTeamTpParser(MTeamTpSettings settings, IndexerCapabilitiesCategories categories)
{
_settings = settings;
_categories = categories;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
var httpResponse = indexerResponse.HttpResponse;
if (httpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request");
}
if (!httpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
{
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from indexer request, expected {HttpAccept.Json.Value}");
}
if (!STJson.TryDeserialize<MTeamTpApiResponse>(indexerResponse.Content, out var jsonResponse))
{
throw new IndexerException(indexerResponse, "Invalid response received from M-Team, not a valid JSON");
}
var releaseInfos = new List<ReleaseInfo>();
if (jsonResponse?.Data?.Torrents == null)
{
return releaseInfos;
}
foreach (var torrent in jsonResponse.Data.Torrents)
{
var torrentId = int.Parse(torrent.Id);
var infoUrl = $"{_settings.BaseUrl.TrimEnd('/')}/detail/{torrentId}";
var release = new TorrentInfo
{
Guid = infoUrl,
Title = CleanTitle(torrent.Name),
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(torrentId),
Categories = _categories.MapTrackerCatToNewznab(torrent.Category),
Description = torrent.Description,
Files = int.Parse(torrent.NumFiles),
Size = long.Parse(torrent.Size),
Grabs = int.Parse(torrent.Status.TimesCompleted),
Seeders = int.Parse(torrent.Status.Seeders),
Peers = int.Parse(torrent.Status.Seeders) + int.Parse(torrent.Status.Leechers),
DownloadVolumeFactor = torrent.Status.Discount.ToUpperInvariant() switch
{
"FREE" => 0,
"_2X_FREE" => 0,
"PERCENT_50" => 0.5,
"_2X_PERCENT_50" => 0.5,
"PERCENT_70" => 0.3,
_ => 1
},
UploadVolumeFactor = torrent.Status.Discount.ToUpperInvariant() switch
{
"_2X_FREE" => 2,
"_2X_PERCENT_50" => 2,
_ => 1
},
MinimumRatio = 1,
MinimumSeedTime = 172800 // 2 days
};
if (torrent.Imdb.IsNotNullOrWhiteSpace())
{
release.ImdbId = ParseUtil.GetImdbId(torrent.Imdb.Split('/').LastOrDefault()).GetValueOrDefault();
}
if (torrent.Status?.CreatedDate != null &&
DateTime.TryParseExact($"{torrent.Status.CreatedDate} +08:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var publishDate))
{
release.PublishDate = publishDate;
}
releaseInfos.Add(release);
}
return releaseInfos
.OrderByDescending(o => o.PublishDate)
.ToArray();
}
private string GetDownloadUrl(int torrentId)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/api/torrent/genDlToken")
.AddQueryParam("id", torrentId);
return url.FullUri;
}
private static string CleanTitle(string title)
{
title = Regex.Replace(title, @"\s+", " ", RegexOptions.Compiled);
return title.Trim();
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
public class MTeamTpValidator : NoAuthSettingsValidator<MTeamTpSettings>
{
public MTeamTpValidator()
{
RuleFor(c => c.ApiKey).NotEmpty();
}
}
public class MTeamTpSettings : NoAuthTorrentBaseSettings
{
private static readonly MTeamTpValidator Validator = new ();
[FieldDefinition(2, Label = "ApiKey", HelpText = "IndexerMTeamTpSettingsApiKeyHelpText", Privacy = PrivacyLevel.ApiKey)]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "IndexerSettingsFreeleechOnly", Type = FieldType.Checkbox, HelpText = "IndexerMTeamTpSettingsFreeleechOnlyHelpText")]
public bool FreeleechOnly { get; set; }
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
internal enum MTeamTpRequestType
{
Normal,
Adult
}
internal class MTeamTpApiSearchQuery
{
[JsonProperty(Required = Required.Always)]
public MTeamTpRequestType Mode { get; set; }
[JsonProperty(Required = Required.Always)]
public IEnumerable<string> Categories { get; set; }
public string Discount { get; set; }
public string Imdb { get; set; }
public string Keyword { get; set; }
public int? PageNumber { get; set; }
public int? PageSize { get; set; }
}
internal class MTeamTpApiResponse
{
public MTeamTpApiData Data { get; set; }
}
internal class MTeamTpApiData
{
[JsonPropertyName("data")]
public IReadOnlyCollection<MTeamTpApiTorrent> Torrents { get; set; }
}
internal class MTeamTpApiTorrent
{
public string Id { get; set; }
public string Name { get; set; }
[JsonPropertyName("smallDescr")]
public string Description { get; set; }
public string Category { get; set; }
[JsonPropertyName("numfiles")]
public string NumFiles { get; set; }
public string Imdb { get; set; }
public string Size { get; set; }
public MTeamTpApiReleaseStatus Status { get; set; }
}
internal class MTeamTpApiReleaseStatus
{
public string CreatedDate { get; set; }
public string Discount { get; set; }
public string TimesCompleted { get; set; }
public string Seeders { get; set; }
public string Leechers { get; set; }
}
internal class MTeamTpApiDownloadTokenResponse
{
public string Data { get; set; }
}

View File

@@ -44,7 +44,7 @@ namespace NzbDrone.Core.Indexers.Newznab
public string[] GetBaseUrlFromSettings()
{
if (Definition == null || Settings?.Categories == null)
if (Definition == null || Settings?.Capabilities == null)
{
return new[] { "" };
}
@@ -61,16 +61,23 @@ namespace NzbDrone.Core.Indexers.Newznab
{
var caps = new IndexerCapabilities();
if (Definition == null || Settings?.Categories == null)
if (Definition == null || Settings?.Capabilities?.Categories == null)
{
return caps;
}
foreach (var category in Settings.Categories)
foreach (var category in Settings.Capabilities.Categories)
{
caps.Categories.AddCategoryMapping(category.Name, category);
}
caps.SupportsRawSearch = Settings?.Capabilities?.SupportsRawSearch ?? false;
caps.SearchParams = Settings?.Capabilities?.SearchParams ?? new List<SearchParam> { SearchParam.Q };
caps.TvSearchParams = Settings?.Capabilities?.TvSearchParams ?? new List<TvSearchParam>();
caps.MovieSearchParams = Settings?.Capabilities?.MovieSearchParams ?? new List<MovieSearchParam>();
caps.MusicSearchParams = Settings?.Capabilities?.MusicSearchParams ?? new List<MusicSearchParam>();
caps.BookSearchParams = Settings?.Capabilities?.BookSearchParams ?? new List<BookSearchParam>();
return caps;
}
@@ -84,25 +91,24 @@ namespace NzbDrone.Core.Indexers.Newznab
{
get
{
yield return GetDefinition("abNZB", GetSettings("https://abnzb.com"));
yield return GetDefinition("altHUB", GetSettings("https://api.althub.co.za"));
yield return GetDefinition("AnimeTosho (Usenet)", GetSettings("https://feed.animetosho.org"));
yield return GetDefinition("DOGnzb", GetSettings("https://api.dognzb.cr"));
yield return GetDefinition("DrunkenSlug", GetSettings("https://drunkenslug.com"));
yield return GetDefinition("abNZB", GetSettings("https://abnzb.com"), categories: new[] { 2000, 3000, 4000, 5000, 6000, 7000, 8000 });
yield return GetDefinition("altHUB", GetSettings("https://api.althub.co.za"), categories: new[] { 2000, 3000, 4000, 5000, 7000 });
yield return GetDefinition("AnimeTosho (Usenet)", GetSettings("https://feed.animetosho.org"), categories: new[] { 2020, 5070 });
yield return GetDefinition("DOGnzb", GetSettings("https://api.dognzb.cr"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 });
yield return GetDefinition("DrunkenSlug", GetSettings("https://drunkenslug.com"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000 });
yield return GetDefinition("GingaDADDY", GetSettings("https://www.gingadaddy.com"));
yield return GetDefinition("Miatrix", GetSettings("https://www.miatrix.com"));
yield return GetDefinition("Newz-Complex", GetSettings("https://newz-complex.org/www"));
yield return GetDefinition("Newz69", GetSettings("https://newz69.keagaming.com"));
yield return GetDefinition("NinjaCentral", GetSettings("https://ninjacentral.co.za"));
yield return GetDefinition("Nzb.su", GetSettings("https://api.nzb.su"));
yield return GetDefinition("NZBCat", GetSettings("https://nzb.cat"));
yield return GetDefinition("NZBFinder", GetSettings("https://nzbfinder.ws"));
yield return GetDefinition("NZBgeek", GetSettings("https://api.nzbgeek.info"));
yield return GetDefinition("NzbNoob", GetSettings("https://www.nzbnoob.com"));
yield return GetDefinition("NZBNDX", GetSettings("https://www.nzbndx.com"));
yield return GetDefinition("NzbPlanet", GetSettings("https://api.nzbplanet.net"));
yield return GetDefinition("NZBStars", GetSettings("https://nzbstars.com"));
yield return GetDefinition("Tabula Rasa", GetSettings("https://www.tabula-rasa.pw", apiPath: @"/api/v1/api"));
yield return GetDefinition("Miatrix", GetSettings("https://www.miatrix.com"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 });
yield return GetDefinition("Newz69", GetSettings("https://newz69.keagaming.com"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 });
yield return GetDefinition("NinjaCentral", GetSettings("https://ninjacentral.co.za"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 });
yield return GetDefinition("Nzb.su", GetSettings("https://api.nzb.su"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 });
yield return GetDefinition("NZBCat", GetSettings("https://nzb.cat"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000 });
yield return GetDefinition("NZBFinder", GetSettings("https://nzbfinder.ws"), categories: new[] { 2000, 3000, 5000, 6000, 7000 });
yield return GetDefinition("NZBgeek", GetSettings("https://api.nzbgeek.info"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 });
yield return GetDefinition("NzbNoob", GetSettings("https://www.nzbnoob.com"), categories: new[] { 2000, 3000, 4000, 5000, 6000, 7000, 8000 });
yield return GetDefinition("NZBNDX", GetSettings("https://www.nzbndx.com"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 });
yield return GetDefinition("NzbPlanet", GetSettings("https://api.nzbplanet.net"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000 });
yield return GetDefinition("NZBStars", GetSettings("https://nzbstars.com"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000 });
yield return GetDefinition("Tabula Rasa", GetSettings("https://www.tabula-rasa.pw", apiPath: @"/api/v1/api"), categories: new[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000 });
yield return GetDefinition("Generic Newznab", GetSettings(""));
}
}
@@ -113,8 +119,23 @@ namespace NzbDrone.Core.Indexers.Newznab
_capabilitiesProvider = capabilitiesProvider;
}
private IndexerDefinition GetDefinition(string name, NewznabSettings settings)
private IndexerDefinition GetDefinition(string name, NewznabSettings settings, IEnumerable<int> categories = null)
{
var caps = new IndexerCapabilities();
if (categories != null)
{
foreach (var categoryId in categories)
{
var mappedCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Id == categoryId);
if (mappedCat != null)
{
caps.Categories.AddCategoryMapping(mappedCat.Id, mappedCat);
}
}
}
return new IndexerDefinition
{
Enable = true,
@@ -127,7 +148,7 @@ namespace NzbDrone.Core.Indexers.Newznab
SupportsSearch = SupportsSearch,
SupportsRedirect = SupportsRedirect,
SupportsPagination = SupportsPagination,
Capabilities = Capabilities
Capabilities = caps
};
}

View File

@@ -124,7 +124,7 @@ namespace NzbDrone.Core.Indexers.Newznab
{
foreach (var param in xmlBasicSearch.Attribute("supportedParams").Value.Split(','))
{
if (Enum.TryParse(param, true, out SearchParam searchParam))
if (Enum.TryParse(param, true, out SearchParam searchParam) && !capabilities.SearchParams.Contains(searchParam))
{
capabilities.SearchParams.AddIfNotNull(searchParam);
}
@@ -146,7 +146,7 @@ namespace NzbDrone.Core.Indexers.Newznab
{
foreach (var param in xmlMovieSearch.Attribute("supportedParams").Value.Split(','))
{
if (Enum.TryParse(param, true, out MovieSearchParam searchParam))
if (Enum.TryParse(param, true, out MovieSearchParam searchParam) && !capabilities.MovieSearchParams.Contains(searchParam))
{
capabilities.MovieSearchParams.AddIfNotNull(searchParam);
}
@@ -166,7 +166,7 @@ namespace NzbDrone.Core.Indexers.Newznab
{
foreach (var param in xmlTvSearch.Attribute("supportedParams").Value.Split(','))
{
if (Enum.TryParse(param, true, out TvSearchParam searchParam))
if (Enum.TryParse(param, true, out TvSearchParam searchParam) && !capabilities.TvSearchParams.Contains(searchParam))
{
capabilities.TvSearchParams.AddIfNotNull(searchParam);
}
@@ -186,7 +186,7 @@ namespace NzbDrone.Core.Indexers.Newznab
{
foreach (var param in xmlAudioSearch.Attribute("supportedParams").Value.Split(','))
{
if (Enum.TryParse(param, true, out MusicSearchParam searchParam))
if (Enum.TryParse(param, true, out MusicSearchParam searchParam) && !capabilities.MusicSearchParams.Contains(searchParam))
{
capabilities.MusicSearchParams.AddIfNotNull(searchParam);
}
@@ -206,7 +206,7 @@ namespace NzbDrone.Core.Indexers.Newznab
{
foreach (var param in xmlBookSearch.Attribute("supportedParams").Value.Split(','))
{
if (Enum.TryParse(param, true, out BookSearchParam searchParam))
if (Enum.TryParse(param, true, out BookSearchParam searchParam) && !capabilities.BookSearchParams.Contains(searchParam))
{
capabilities.BookSearchParams.AddIfNotNull(searchParam);
}

View File

@@ -0,0 +1,35 @@
using System.Collections.Generic;
namespace NzbDrone.Core.Indexers.Newznab;
public class NewznabCapabilitiesSettings
{
public bool SupportsRawSearch { get; set; }
public List<SearchParam> SearchParams { get; set; }
public List<TvSearchParam> TvSearchParams { get; set; }
public List<MovieSearchParam> MovieSearchParams { get; set; }
public List<MusicSearchParam> MusicSearchParams { get; set; }
public List<BookSearchParam> BookSearchParams { get; set; }
public List<IndexerCategory> Categories { get; set; }
public NewznabCapabilitiesSettings()
{
}
public NewznabCapabilitiesSettings(IndexerCapabilities capabilities)
{
SupportsRawSearch = capabilities?.SupportsRawSearch ?? false;
SearchParams = capabilities?.SearchParams;
TvSearchParams = capabilities?.TvSearchParams;
MovieSearchParams = capabilities?.MovieSearchParams;
MusicSearchParams = capabilities?.MusicSearchParams;
BookSearchParams = capabilities?.BookSearchParams;
Categories = capabilities?.Categories.GetTorznabCategoryList();
}
}

View File

@@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using FluentValidation;
@@ -76,7 +75,7 @@ namespace NzbDrone.Core.Indexers.Newznab
[FieldDefinition(7)]
public IndexerBaseSettings BaseSettings { get; set; } = new ();
public List<IndexerCategory> Categories { get; set; }
public NewznabCapabilitiesSettings Capabilities { get; set; }
// Field 8 is used by TorznabSettings MinimumSeeders
// If you need to add another field here, update TorznabSettings as well and this comment

View File

@@ -276,6 +276,12 @@ namespace NzbDrone.Core.Indexers.Definitions
{
foreach (var torrent in result.Torrents)
{
// skip releases that cannot be used with freeleech tokens when the option is enabled
if (_settings.UseFreeleechToken && !torrent.CanUseToken)
{
continue;
}
var id = torrent.TorrentId;
var title = GetTitle(result, torrent);
@@ -285,7 +291,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id, torrent.CanUseToken),
DownloadUrl = GetDownloadUrl(id, !torrent.IsFreeLeech && !torrent.IsNeutralLeech && !torrent.IsPersonalFreeLeech),
Title = WebUtility.HtmlDecode(title),
Artist = WebUtility.HtmlDecode(result.Artist),
Album = WebUtility.HtmlDecode(result.GroupName),
@@ -320,16 +326,22 @@ namespace NzbDrone.Core.Indexers.Definitions
// Non-Audio files are formatted a little differently (1:1 for group and torrents)
else
{
// skip releases that cannot be used with freeleech tokens when the option is enabled
if (_settings.UseFreeleechToken && !result.CanUseToken)
{
continue;
}
var id = result.TorrentId;
var infoUrl = GetInfoUrl(result.GroupId, id);
var release = new TorrentInfo
{
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id, !result.IsFreeLeech && !result.IsNeutralLeech && !result.IsPersonalFreeLeech),
Title = WebUtility.HtmlDecode(result.GroupName),
Size = long.Parse(result.Size),
DownloadUrl = GetDownloadUrl(id, result.CanUseToken),
InfoUrl = infoUrl,
Seeders = int.Parse(result.Seeders),
Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders),
PublishDate = long.TryParse(result.GroupTime, out var num) ? DateTimeOffset.FromUnixTimeSeconds(num).UtcDateTime : DateTimeUtil.FromFuzzyTime(result.GroupTime),

View File

@@ -247,6 +247,12 @@ namespace NzbDrone.Core.Indexers.Definitions
{
foreach (var torrent in result.Torrents)
{
// skip releases that cannot be used with freeleech tokens when the option is enabled
if (_settings.UseFreeleechToken && !torrent.CanUseToken)
{
continue;
}
// skip non-freeload results when freeload only is set
if (_settings.FreeloadOnly && !torrent.IsFreeload)
{
@@ -262,7 +268,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id, torrent.CanUseToken && !torrent.IsFreeload),
DownloadUrl = GetDownloadUrl(id, !torrent.IsFreeLeech && !torrent.IsNeutralLeech && !torrent.IsFreeload && !torrent.IsPersonalFreeLeech),
Title = WebUtility.HtmlDecode(title),
Artist = WebUtility.HtmlDecode(result.Artist),
Album = WebUtility.HtmlDecode(result.GroupName),
@@ -297,6 +303,12 @@ namespace NzbDrone.Core.Indexers.Definitions
// Non-Audio files are formatted a little differently (1:1 for group and torrents)
else
{
// skip releases that cannot be used with freeleech tokens when the option is enabled
if (_settings.UseFreeleechToken && !result.CanUseToken)
{
continue;
}
// skip non-freeload results when freeload only is set
if (_settings.FreeloadOnly && !result.IsFreeload)
{
@@ -309,10 +321,10 @@ namespace NzbDrone.Core.Indexers.Definitions
var release = new TorrentInfo
{
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id, !result.IsFreeLeech && !result.IsNeutralLeech && !result.IsFreeload && !result.IsPersonalFreeLeech),
Title = WebUtility.HtmlDecode(result.GroupName),
Size = long.Parse(result.Size),
DownloadUrl = GetDownloadUrl(id, result.CanUseToken && !result.IsFreeload),
InfoUrl = infoUrl,
Seeders = int.Parse(result.Seeders),
Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders),
PublishDate = DateTimeOffset.FromUnixTimeSeconds(ParseUtil.CoerceLong(result.GroupTime)).UtcDateTime,

View File

@@ -23,14 +23,14 @@ namespace NzbDrone.Core.Indexers.Definitions
{
public class RuTracker : TorrentIndexerBase<RuTrackerSettings>
{
public override string Name => "RuTracker";
public override string Name => "RuTracker.org";
public override string[] IndexerUrls => new[]
{
"https://rutracker.org/",
"https://rutracker.net/",
"https://rutracker.nl/"
};
public override string Description => "RuTracker is a Semi-Private Russian torrent site with a thriving file-sharing community";
public override string Description => "RuTracker.org is a Semi-Private Russian torrent site with a thriving file-sharing community";
public override string Language => "ru-RU";
public override Encoding Encoding => Encoding.GetEncoding("windows-1251");
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;

View File

@@ -38,7 +38,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new SceneHDRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
return new SceneHDRequestGenerator(Settings, Capabilities);
}
public override IParseIndexerResponse GetParser()
@@ -88,38 +88,41 @@ namespace NzbDrone.Core.Indexers.Definitions
public class SceneHDRequestGenerator : IIndexerRequestGenerator
{
public SceneHDSettings Settings { get; set; }
public IndexerCapabilities Capabilities { get; set; }
public string BaseUrl { get; set; }
private readonly SceneHDSettings _settings;
private readonly IndexerCapabilities _capabilities;
public SceneHDRequestGenerator(SceneHDSettings settings, IndexerCapabilities capabilities)
{
_settings = settings;
_capabilities = capabilities;
}
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null)
{
var search = new[] { imdbId, term };
var qc = new NameValueCollection
var parameters = new NameValueCollection
{
{ "api", "" },
{ "passkey", Settings.Passkey },
{ "passkey", _settings.Passkey },
{ "search", string.Join(" ", search.Where(s => s.IsNotNullOrWhiteSpace())) }
};
foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories))
if (categories?.Length > 0)
{
qc.Add("categories[" + cat + "]", "1");
parameters.Add("cat", _capabilities.Categories.MapTorznabCapsToTrackers(categories).Distinct().Join(","));
}
var searchUrl = string.Format("{0}/browse.php?{1}", Settings.BaseUrl.TrimEnd('/'), qc.GetQueryString());
var searchUrl = $"{_settings.BaseUrl.TrimEnd('/')}/browse.php?{parameters.GetQueryString()}";
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
yield return request;
yield return new IndexerRequest(searchUrl, HttpAccept.Json);
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories, searchCriteria.FullImdbId));
return pageableRequests;
}
@@ -128,7 +131,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories));
return pageableRequests;
}
@@ -137,7 +140,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId));
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedTvSearchString}", searchCriteria.Categories, searchCriteria.FullImdbId));
return pageableRequests;
}
@@ -146,7 +149,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories));
return pageableRequests;
}
@@ -155,7 +158,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
pageableRequests.Add(GetPagedRequests($"{searchCriteria.SanitizedSearchTerm}", searchCriteria.Categories));
return pageableRequests;
}

View File

@@ -104,6 +104,7 @@ public class SecretCinemaParser : IParseIndexerResponse
foreach (var torrent in result.Torrents)
{
var id = torrent.TorrentId;
var infoUrl = GetInfoUrl(result.GroupId, id);
// in SC movies, artist=director and GroupName=title
var artist = WebUtility.HtmlDecode(result.Artist);
@@ -112,15 +113,15 @@ public class SecretCinemaParser : IParseIndexerResponse
var release = new TorrentInfo
{
Guid = $"SecretCinema-{id}",
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id),
Title = title,
Container = torrent.Encoding,
Files = torrent.FileCount,
Grabs = torrent.Snatches,
Codec = torrent.Format,
Size = long.Parse(torrent.Size),
DownloadUrl = GetDownloadUrl(id),
InfoUrl = GetInfoUrl(result.GroupId, id),
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = new DateTimeOffset(time, TimeSpan.FromHours(2)).UtcDateTime,
@@ -143,7 +144,12 @@ public class SecretCinemaParser : IParseIndexerResponse
{
// Remove director from title
// SC API returns no more useful information than this
release.Title = $"{title} ({result.GroupYear}) {torrent.Media}";
release.Title = $"{title} ({result.GroupYear}) {torrent.Media}".Trim();
if (torrent.RemasterTitle.IsNotNullOrWhiteSpace())
{
release.Title += $" [{torrent.RemasterTitle.Trim()}]";
}
// Replace media formats with standards
release.Title = Regex.Replace(release.Title, @"\bBDMV\b", "COMPLETE BLURAY", RegexOptions.IgnoreCase);
@@ -168,15 +174,16 @@ public class SecretCinemaParser : IParseIndexerResponse
else
{
var id = result.TorrentId;
var infoUrl = GetInfoUrl(result.GroupId, id);
var groupName = WebUtility.HtmlDecode(result.GroupName);
var release = new TorrentInfo
{
Guid = $"SecretCinema-{id}",
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id),
Title = groupName,
Size = long.Parse(result.Size),
DownloadUrl = GetDownloadUrl(id),
InfoUrl = GetInfoUrl(result.GroupId, id),
Seeders = int.Parse(result.Seeders),
Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders),
Files = result.FileCount,
@@ -209,7 +216,7 @@ public class SecretCinemaParser : IParseIndexerResponse
private bool IsAnyMovieCategory(ICollection<IndexerCategory> category)
{
return category.Contains(NewznabStandardCategory.Movies) || NewznabStandardCategory.Movies.SubCategories.Any(subCat => category.Contains(subCat));
return category.Contains(NewznabStandardCategory.Movies) || NewznabStandardCategory.Movies.SubCategories.Any(category.Contains);
}
private string GetDownloadUrl(int torrentId)

View File

@@ -17,6 +17,7 @@ using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete("Site unusable due to lack of new releases")]
public class Shizaproject : TorrentIndexerBase<NoAuthTorrentBaseSettings>
{
public override string Name => "ShizaProject";

View File

@@ -82,49 +82,13 @@ namespace NzbDrone.Core.Indexers.Definitions
_settings = settings;
}
private IEnumerable<IndexerRequest> GetSearchRequests(string term)
{
var searchUrl = $"{_settings.BaseUrl.TrimEnd('/')}/api/?";
var searchTerm = Regex.Replace(term, "\\[?SubsPlease\\]?\\s*", string.Empty, RegexOptions.IgnoreCase).Trim();
// If the search terms contain a resolution, remove it from the query sent to the API
var resMatch = Regex.Match(searchTerm, "\\d{3,4}[p|P]");
if (resMatch.Success)
{
searchTerm = searchTerm.Replace(resMatch.Value, string.Empty);
}
var queryParameters = new NameValueCollection
{
{ "f", "search" },
{ "tz", "UTC" },
{ "s", searchTerm }
};
var request = new IndexerRequest(searchUrl + queryParameters.GetQueryString(), HttpAccept.Json);
yield return request;
}
private IEnumerable<IndexerRequest> GetRssRequest()
{
var searchUrl = $"{_settings.BaseUrl.TrimEnd('/')}/api/?";
var queryParameters = new NameValueCollection
{
{ "f", "latest" },
{ "tz", "UTC" }
};
var request = new IndexerRequest(searchUrl + queryParameters.GetQueryString(), HttpAccept.Json);
yield return request;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetSearchRequests(searchCriteria.SanitizedSearchTerm, searchCriteria));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
@@ -136,31 +100,69 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(searchCriteria.IsRssSearch
? GetRssRequest()
: GetSearchRequests(searchCriteria.SanitizedTvSearchString));
var searchTerm = searchCriteria.SanitizedSearchTerm.Trim();
// Only include season > 1 in searchTerm, format as S2 rather than S02
if (searchCriteria.Season is > 1)
{
searchTerm += $" S{searchCriteria.Season}";
}
if (int.TryParse(searchCriteria.Episode, out var episode) && episode > 0)
{
searchTerm += $" {episode:00}";
}
pageableRequests.Add(GetSearchRequests(searchTerm, searchCriteria));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
return pageableRequests;
return new IndexerPageableRequestChain();
}
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(searchCriteria.IsRssSearch
? GetRssRequest()
: GetSearchRequests(searchCriteria.SanitizedSearchTerm));
pageableRequests.Add(GetSearchRequests(searchCriteria.SanitizedSearchTerm, searchCriteria));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetSearchRequests(string term, SearchCriteriaBase searchCriteria)
{
var searchTerm = Regex.Replace(term, "\\[?SubsPlease\\]?\\s*", string.Empty, RegexOptions.IgnoreCase).Trim();
// If the search terms contain a resolution, remove it from the query sent to the API
var resMatch = Regex.Match(searchTerm, "\\d{3,4}[p|P]");
if (resMatch.Success)
{
searchTerm = searchTerm.Replace(resMatch.Value, string.Empty).Trim();
}
var queryParameters = new NameValueCollection
{
{ "tz", "UTC" }
};
if (searchCriteria.IsRssSearch)
{
queryParameters.Set("f", "latest");
}
else
{
queryParameters.Set("f", "search");
queryParameters.Set("s", searchTerm);
}
var searchUrl = $"{_settings.BaseUrl.TrimEnd('/')}/api/?{queryParameters.GetQueryString()}";
yield return new IndexerRequest(searchUrl, HttpAccept.Json);
}
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}

View File

@@ -44,7 +44,7 @@ namespace NzbDrone.Core.Indexers.Torznab
public string[] GetBaseUrlFromSettings()
{
if (Definition == null || Settings?.Categories == null)
if (Definition == null || Settings?.Capabilities == null)
{
return new[] { "" };
}
@@ -61,16 +61,23 @@ namespace NzbDrone.Core.Indexers.Torznab
{
var caps = new IndexerCapabilities();
if (Definition == null || Settings?.Categories == null)
if (Definition == null || Settings?.Capabilities?.Categories == null)
{
return caps;
}
foreach (var category in Settings.Categories)
foreach (var category in Settings.Capabilities.Categories)
{
caps.Categories.AddCategoryMapping(category.Name, category);
}
caps.SupportsRawSearch = Settings?.Capabilities?.SupportsRawSearch ?? false;
caps.SearchParams = Settings?.Capabilities?.SearchParams ?? new List<SearchParam> { SearchParam.Q };
caps.TvSearchParams = Settings?.Capabilities?.TvSearchParams ?? new List<TvSearchParam>();
caps.MovieSearchParams = Settings?.Capabilities?.MovieSearchParams ?? new List<MovieSearchParam>();
caps.MusicSearchParams = Settings?.Capabilities?.MusicSearchParams ?? new List<MusicSearchParam>();
caps.BookSearchParams = Settings?.Capabilities?.BookSearchParams ?? new List<BookSearchParam>();
return caps;
}
@@ -84,8 +91,8 @@ namespace NzbDrone.Core.Indexers.Torznab
{
get
{
yield return GetDefinition("AnimeTosho", "Anime NZB/DDL mirror", settings: GetSettings("https://feed.animetosho.org"));
yield return GetDefinition("MoreThanTV", "Private torrent tracker for TV / MOVIES", settings: GetSettings("https://www.morethantv.me", apiPath: @"/api/torznab"));
yield return GetDefinition("AnimeTosho", "Anime NZB/DDL mirror", settings: GetSettings("https://feed.animetosho.org"), categories: new[] { 2020, 5070 });
yield return GetDefinition("MoreThanTV", "Private torrent tracker for TV / MOVIES", settings: GetSettings("https://www.morethantv.me", apiPath: @"/api/torznab"), categories: new[] { 2000, 5000 });
yield return GetDefinition("Torrent Network", "Torrent Network (TN) is a GERMAN Private site for TV / MOVIES / GENERAL", language: "de-DE", settings: GetSettings("https://tntracker.org", apiPath: @"/api/torznab/api"));
yield return GetDefinition("Generic Torznab", "A Newznab-like api for torrents.", settings: GetSettings(""));
}
@@ -97,8 +104,23 @@ namespace NzbDrone.Core.Indexers.Torznab
_capabilitiesProvider = capabilitiesProvider;
}
private IndexerDefinition GetDefinition(string name, string description, string language = null, TorznabSettings settings = null)
private IndexerDefinition GetDefinition(string name, string description, string language = null, TorznabSettings settings = null, IEnumerable<int> categories = null)
{
var caps = new IndexerCapabilities();
if (categories != null)
{
foreach (var categoryId in categories)
{
var mappedCat = NewznabStandardCategory.AllCats.FirstOrDefault(x => x.Id == categoryId);
if (mappedCat != null)
{
caps.Categories.AddCategoryMapping(mappedCat.Id, mappedCat);
}
}
}
return new IndexerDefinition
{
Enable = true,
@@ -112,7 +134,7 @@ namespace NzbDrone.Core.Indexers.Torznab
SupportsSearch = SupportsSearch,
SupportsRedirect = SupportsRedirect,
SupportsPagination = SupportsPagination,
Capabilities = Capabilities
Capabilities = caps
};
}

View File

@@ -120,6 +120,7 @@ public class XSpeeds : TorrentIndexerBase<XSpeedsSettings>
caps.Categories.AddCategoryMapping(113, NewznabStandardCategory.TVAnime, "Anime Boxsets");
caps.Categories.AddCategoryMapping(112, NewznabStandardCategory.MoviesOther, "Anime Movies");
caps.Categories.AddCategoryMapping(111, NewznabStandardCategory.MoviesOther, "Anime TV");
caps.Categories.AddCategoryMapping(150, NewznabStandardCategory.PC, "Apps");
caps.Categories.AddCategoryMapping(80, NewznabStandardCategory.AudioAudiobook, "Audiobooks");
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.Books, "Books Magazines");
caps.Categories.AddCategoryMapping(68, NewznabStandardCategory.MoviesOther, "Cams/TS");
@@ -154,7 +155,7 @@ public class XSpeeds : TorrentIndexerBase<XSpeedsSettings>
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping(135, NewznabStandardCategory.AudioLossless, "Music/FLAC");
caps.Categories.AddCategoryMapping(136, NewznabStandardCategory.Audio, "Music Boxset");
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.AudioVideo, "Music Videos");
caps.Categories.AddCategoryMapping(148, NewznabStandardCategory.AudioVideo, "Music Videos");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.Other, "Other");
caps.Categories.AddCategoryMapping(125, NewznabStandardCategory.Other, "Other/Pictures");
caps.Categories.AddCategoryMapping(54, NewznabStandardCategory.TVOther, "Soaps");
@@ -168,6 +169,7 @@ public class XSpeeds : TorrentIndexerBase<XSpeedsSettings>
caps.Categories.AddCategoryMapping(86, NewznabStandardCategory.TVSport, "Sports/MotorSports");
caps.Categories.AddCategoryMapping(89, NewznabStandardCategory.TVSport, "Sports/Olympics");
caps.Categories.AddCategoryMapping(126, NewznabStandardCategory.TV, "TV");
caps.Categories.AddCategoryMapping(149, NewznabStandardCategory.TV, "TV Specials");
caps.Categories.AddCategoryMapping(127, NewznabStandardCategory.TVUHD, "TV 4K");
caps.Categories.AddCategoryMapping(129, NewznabStandardCategory.TVHD, "TV HD");
caps.Categories.AddCategoryMapping(130, NewznabStandardCategory.TVHD, "TV HEVC");

View File

@@ -18,6 +18,8 @@ using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser.Model;
using Polly;
using Polly.Retry;
namespace NzbDrone.Core.Indexers
{
@@ -28,6 +30,38 @@ namespace NzbDrone.Core.Indexers
protected readonly IIndexerHttpClient _httpClient;
protected readonly IEventAggregator _eventAggregator;
protected ResiliencePipeline<HttpResponse> RetryStrategy => new ResiliencePipelineBuilder<HttpResponse>()
.AddRetry(new RetryStrategyOptions<HttpResponse>
{
ShouldHandle = static args => args.Outcome switch
{
{ Result.HasHttpServerError: true } => PredicateResult.True(),
{ Result.StatusCode: HttpStatusCode.RequestTimeout } => PredicateResult.True(),
_ => PredicateResult.False()
},
Delay = RateLimit,
MaxRetryAttempts = 2,
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
OnRetry = args =>
{
var exception = args.Outcome.Exception;
if (exception is not null)
{
_logger.Warn(exception, "Request for {0} failed with exception '{1}'. Retrying in {2}s.", Definition.Name, exception.Message, args.RetryDelay.TotalSeconds);
}
else
{
_logger.Warn("Request for {0} failed with status {1}. Retrying in {2}s.", Definition.Name, args.Outcome.Result?.StatusCode, args.RetryDelay.TotalSeconds);
}
return default;
}
})
.Build();
public IDictionary<string, string> Cookies { get; set; }
public override bool SupportsRss => true;
@@ -363,7 +397,7 @@ namespace NzbDrone.Core.Indexers
}
}
releases.AddRange(pagedReleases.Where(IsValidRelease));
releases.AddRange(pagedReleases.Where(r => IsValidRelease(r, searchCriteria.InteractiveSearch)));
}
if (releases.Any())
@@ -469,7 +503,7 @@ namespace NzbDrone.Core.Indexers
return Capabilities ?? ((IndexerDefinition)Definition).Capabilities;
}
protected virtual bool IsValidRelease(ReleaseInfo release)
protected virtual bool IsValidRelease(ReleaseInfo release, bool interactiveSearch = false)
{
if (release.Title.IsNullOrWhiteSpace())
{
@@ -478,6 +512,26 @@ namespace NzbDrone.Core.Indexers
return false;
}
if (interactiveSearch)
{
// Show releases with issues in the interactive search
return true;
}
if (release.Size == null)
{
_logger.Warn("Invalid Release: '{0}' from indexer: {1}. No size provided.", release.Title, Definition.Name);
return false;
}
if (release.Categories == null || !release.Categories.Any())
{
_logger.Warn("Invalid Release: '{0}' from indexer: {1}. No categories provided.", release.Title, Definition.Name);
return false;
}
return true;
}
@@ -570,7 +624,9 @@ namespace NzbDrone.Core.Indexers
request.HttpRequest.SuppressHttpError = true;
request.HttpRequest.Encoding ??= Encoding;
var response = await _httpClient.ExecuteProxiedAsync(request.HttpRequest, Definition);
var response = await RetryStrategy
.ExecuteAsync(static async (state, _) => await state._httpClient.ExecuteProxiedAsync(state.HttpRequest, state.Definition), (_httpClient, request.HttpRequest, Definition))
.ConfigureAwait(false);
// Check response to see if auth is needed, if needed try again
if (CheckIfLoginNeeded(response))

View File

@@ -171,10 +171,15 @@ namespace NzbDrone.Core.Indexers
var splitRegex = new Regex("[^\\w]+");
// split search term to individual terms for less aggressive filtering, filter common terms
var terms = splitRegex.Split(searchCriteria.SearchTerm).Where(t => t.IsNotNullOrWhiteSpace() && t.Length > 1 && !commonWords.ContainsIgnoreCase(t));
var terms = splitRegex.Split(searchCriteria.SearchTerm).Where(t => t.IsNotNullOrWhiteSpace() && t.Length > 1 && !commonWords.ContainsIgnoreCase(t)).ToArray();
// check in title and description for any term searched for
releases = releases.Where(r => terms.Any(t => (r.Title.IsNotNullOrWhiteSpace() && r.Title.ContainsIgnoreCase(t)) || (r.Description.IsNotNullOrWhiteSpace() && r.Description.ContainsIgnoreCase(t)))).ToList();
releases = releases.Where(r =>
{
var matches = terms.Where(t => (r.Title.IsNotNullOrWhiteSpace() && r.Title.ContainsIgnoreCase(t)) || (r.Description.IsNotNullOrWhiteSpace() && r.Description.ContainsIgnoreCase(t)));
return terms.Length > 1 ? matches.Skip(1).Any() : matches.Any();
}).ToList();
}
return releases;

View File

@@ -208,7 +208,7 @@ namespace NzbDrone.Core.Indexers
definition.Description ??= provider.Description;
definition.Encoding = provider.Encoding;
definition.Language ??= provider.Language;
definition.Capabilities = provider.Capabilities;
definition.Capabilities ??= provider.Capabilities;
}
}
@@ -284,7 +284,9 @@ namespace NzbDrone.Core.Indexers
if (definition.Enable && definition.Implementation is nameof(Newznab.Newznab) or nameof(Torznab.Torznab))
{
var settings = (NewznabSettings)definition.Settings;
settings.Categories = _newznabCapabilitiesProvider.GetCapabilities(settings, definition)?.Categories.GetTorznabCategoryList();
var capabilities = _newznabCapabilitiesProvider.GetCapabilities(settings, definition);
settings.Capabilities = new NewznabCapabilitiesSettings(capabilities);
}
if (definition.Implementation == nameof(Cardigann))
@@ -304,7 +306,9 @@ namespace NzbDrone.Core.Indexers
if (definition.Enable && definition.Implementation is nameof(Newznab.Newznab) or nameof(Torznab.Torznab))
{
var settings = (NewznabSettings)definition.Settings;
settings.Categories = _newznabCapabilitiesProvider.GetCapabilities(settings, definition)?.Categories.GetTorznabCategoryList();
var capabilities = _newznabCapabilitiesProvider.GetCapabilities(settings, definition);
settings.Capabilities = new NewznabCapabilitiesSettings(capabilities);
}
if (definition.Implementation == nameof(Cardigann))

View File

@@ -63,8 +63,5 @@ namespace NzbDrone.Core.Indexers
[FieldDefinition(4, Type = FieldType.Number, Label = "IndexerSettingsPackSeedTime", HelpText = "IndexerSettingsPackSeedTimeIndexerHelpText", Unit = "minutes", Advanced = true)]
public int? PackSeedTime { get; set; }
[FieldDefinition(5, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
}
}

View File

@@ -29,7 +29,7 @@
"DeleteDownloadClientMessageText": "هل أنت متأكد أنك تريد حذف برنامج التنزيل \"{0}\"؟",
"Filename": "اسم الملف",
"HomePage": "الصفحة الرئيسية",
"IndexerProxyStatusCheckSingleClientMessage": "المفهرسات غير متاحة بسبب الإخفاقات: {0}",
"IndexerProxyStatusUnavailableHealthCheckMessage": "المفهرسات غير متاحة بسبب الإخفاقات: {indexerProxyNames}",
"Language": "لغة",
"Usenet": "يوزنت",
"MovieIndexScrollTop": "فهرس الفيلم: قم بالتمرير لأعلى",
@@ -47,8 +47,8 @@
"Protocol": "بروتوكول",
"Analytics": "تحليلات",
"ProxyBypassFilterHelpText": "استخدم \"،\" كفاصل ، و \"*.\" كحرف بدل للنطاقات الفرعية",
"ProxyCheckBadRequestMessage": "فشل اختبار الوكيل. رمز الحالة: {0}",
"ProxyCheckFailedToTestMessage": "فشل اختبار الوكيل: {0}",
"ProxyBadRequestHealthCheckMessage": "فشل اختبار الوكيل. رمز الحالة: {statusCode}",
"ProxyFailedToTestHealthCheckMessage": "فشل اختبار الوكيل: {url}",
"ProxyPasswordHelpText": "ما عليك سوى إدخال اسم مستخدم وكلمة مرور إذا كان أحدهما مطلوبًا. اتركها فارغة وإلا.",
"ProxyUsernameHelpText": "ما عليك سوى إدخال اسم مستخدم وكلمة مرور إذا كان أحدهما مطلوبًا. اتركها فارغة وإلا.",
"Queue": "طابور",
@@ -68,7 +68,7 @@
"UnableToAddANewIndexerPleaseTryAgain": "غير قادر على إضافة مفهرس جديد ، يرجى المحاولة مرة أخرى.",
"UnableToLoadBackups": "تعذر تحميل النسخ الاحتياطية",
"UnsavedChanges": "التغييرات غير المحفوظة",
"UpdateCheckUINotWritableMessage": "لا يمكن تثبيت التحديث لأن مجلد واجهة المستخدم '{0}' غير قابل للكتابة بواسطة المستخدم '{1}'",
"UpdateUiNotWritableHealthCheckMessage": "لا يمكن تثبيت التحديث لأن مجلد واجهة المستخدم '{uiFolder}' غير قابل للكتابة بواسطة المستخدم '{userName}'",
"UpdateScriptPathHelpText": "المسار إلى برنامج نصي مخصص يأخذ حزمة تحديث مستخرجة ويتعامل مع ما تبقى من عملية التحديث",
"Username": "اسم المستخدم",
"Warn": "حذر",
@@ -76,7 +76,7 @@
"EnableInteractiveSearch": "تمكين البحث التفاعلي",
"Source": "مصدر",
"SSLCertPassword": "كلمة مرور شهادة SSL",
"UpdateCheckStartupNotWritableMessage": "لا يمكن تثبيت التحديث لأن مجلد بدء التشغيل \"{0}\" غير قابل للكتابة بواسطة المستخدم \"{1}\".",
"UpdateStartupNotWritableHealthCheckMessage": "لا يمكن تثبيت التحديث لأن مجلد بدء التشغيل \"{startupFolder}\" غير قابل للكتابة بواسطة المستخدم \"{userName}\".",
"UpdateMechanismHelpText": "استخدم المحدث أو البرنامج النصي المدمج في {appName}",
"AppDataDirectory": "دليل AppData",
"ConnectSettings": "ربط الإعدادات",
@@ -87,8 +87,8 @@
"Details": "تفاصيل",
"Donations": "التبرعات",
"DownloadClient": "تحميل العميل",
"IndexerStatusCheckAllClientMessage": "جميع المفهرسات غير متوفرة بسبب الفشل",
"IndexerStatusCheckSingleClientMessage": "المفهرسات غير متاحة بسبب الإخفاقات: {0}",
"IndexerStatusAllUnavailableHealthCheckMessage": "جميع المفهرسات غير متوفرة بسبب الفشل",
"IndexerStatusUnavailableHealthCheckMessage": "المفهرسات غير متاحة بسبب الإخفاقات: {indexerNames}",
"Info": "معلومات",
"Interval": "فترة",
"Manual": "كتيب",
@@ -130,10 +130,10 @@
"IncludeHealthWarningsHelpText": "قم بتضمين التحذيرات الصحية",
"Indexer": "مفهرس",
"IndexerFlags": "أعلام المفهرس",
"IndexerLongTermStatusCheckAllClientMessage": "جميع المفهرسات غير متوفرة بسبب الفشل لأكثر من 6 ساعات",
"IndexerLongTermStatusCheckSingleClientMessage": "المفهرسات غير متاحة بسبب الإخفاقات لأكثر من 6 ساعات: {0}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "جميع المفهرسات غير متوفرة بسبب الفشل لأكثر من 6 ساعات",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "المفهرسات غير متاحة بسبب الإخفاقات لأكثر من 6 ساعات: {indexerNames}",
"IndexerPriorityHelpText": "أولوية المفهرس من 1 (الأعلى) إلى 50 (الأدنى). الافتراضي: 25.",
"IndexerProxyStatusCheckAllClientMessage": "جميع المفهرسات غير متوفرة بسبب الفشل",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "جميع المفهرسات غير متوفرة بسبب الفشل",
"NoChange": "لا تغيير",
"NoLogFiles": "لا توجد ملفات سجل",
"NoTagsHaveBeenAddedYet": "لم يتم إضافة أي علامات حتى الان",
@@ -185,7 +185,7 @@
"NetCore": ".شبكة",
"Password": "كلمه السر",
"Proxy": "الوكيل",
"ProxyCheckResolveIpMessage": "فشل حل عنوان IP لمضيف الخادم الوكيل المكون {0}",
"ProxyResolveIpHealthCheckMessage": "فشل حل عنوان IP لمضيف الخادم الوكيل المكون {proxyHostName}",
"ProxyType": "نوع الوكيل",
"ReleaseStatus": "حالة الإصدار",
"Search": "بحث",
@@ -212,8 +212,8 @@
"DeleteIndexerProxyMessageText": "هل أنت متأكد أنك تريد حذف العلامة \"{0}\"؟",
"DeleteNotification": "حذف الإعلام",
"DownloadClients": "تحميل العملاء",
"DownloadClientStatusCheckAllClientMessage": "جميع عملاء التنزيل غير متاحين بسبب الفشل",
"DownloadClientStatusCheckSingleClientMessage": "برامج التنزيل غير متاحة بسبب الإخفاقات: {0}",
"DownloadClientStatusAllClientHealthCheckMessage": "جميع عملاء التنزيل غير متاحين بسبب الفشل",
"DownloadClientStatusSingleClientHealthCheckMessage": "برامج التنزيل غير متاحة بسبب الإخفاقات: {downloadClientNames}",
"Edit": "تعديل",
"EditIndexer": "تحرير المفهرس",
"Enable": "ممكن",
@@ -260,7 +260,7 @@
"DownloadClientsLoadError": "تعذر تحميل عملاء التنزيل",
"UnableToLoadTags": "تعذر تحميل العلامات",
"UnableToLoadUISettings": "تعذر تحميل إعدادات واجهة المستخدم",
"UpdateCheckStartupTranslocationMessage": "لا يمكن تثبيت التحديث لأن مجلد بدء التشغيل \"{0}\" موجود في مجلد App Translocation.",
"UpdateStartupTranslocationHealthCheckMessage": "لا يمكن تثبيت التحديث لأن مجلد بدء التشغيل \"{startupFolder}\" موجود في مجلد App Translocation.",
"Updates": "التحديثات",
"Version": "الإصدار",
"ApiKey": "مفتاح API",
@@ -347,11 +347,13 @@
"WhatsNew": "ما هو الجديد؟",
"minutes": "الدقائق",
"NotificationStatusAllClientHealthCheckMessage": "جميع القوائم غير متاحة بسبب الإخفاقات",
"NotificationStatusSingleClientHealthCheckMessage": "القوائم غير متاحة بسبب الإخفاقات: {0}",
"NotificationStatusSingleClientHealthCheckMessage": "القوائم غير متاحة بسبب الإخفاقات: {notificationNames}",
"AuthBasic": "أساسي (المتصفح المنبثق)",
"AuthForm": "النماذج (صفحة تسجيل الدخول)",
"DisabledForLocalAddresses": "معطل بسبب العناوين المحلية",
"None": "لا شيء",
"ResetAPIKeyMessageText": "هل أنت متأكد أنك تريد إعادة تعيين مفتاح API الخاص بك؟",
"RestartProwlarr": "أعد تشغيل {appName}"
"RestartProwlarr": "أعد تشغيل {appName}",
"CustomFilter": "مرشحات مخصصة",
"IndexerHDBitsSettingsMediums": "متوسط"
}

View File

@@ -61,11 +61,11 @@
"DeleteBackupMessageText": "Наистина ли искате да изтриете резервното копие '{0}'?",
"DeleteTag": "Изтриване на маркера",
"DeleteTagMessageText": "Наистина ли искате да изтриете маркера '{0}'?",
"IndexerProxyStatusCheckAllClientMessage": "Всички списъци са недостъпни поради неуспехи",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Всички списъци са недостъпни поради неуспехи",
"LastWriteTime": "Време за последно писане",
"Columns": "Колони",
"EnableRss": "Активиране на RSS",
"IndexerProxyStatusCheckSingleClientMessage": "Списъци, недостъпни поради неуспехи: {0}",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Списъци, недостъпни поради неуспехи: {indexerProxyNames}",
"LogLevel": "Log Level",
"MovieIndexScrollTop": "Индекс на филма: Превъртете отгоре",
"Queue": "Опашка",
@@ -102,7 +102,7 @@
"UnableToAddANewIndexerProxyPleaseTryAgain": "Не може да се добави нов индексатор, моля, опитайте отново.",
"UnableToAddANewNotificationPleaseTryAgain": "Не може да се добави ново известие, моля, опитайте отново.",
"UpdateAutomaticallyHelpText": "Автоматично изтегляне и инсталиране на актуализации. Все още ще можете да инсталирате от System: Updates",
"UpdateCheckStartupTranslocationMessage": "Не може да се инсталира актуализация, защото стартовата папка „{0}“ е в папка за преместване на приложения.",
"UpdateStartupTranslocationHealthCheckMessage": "Не може да се инсталира актуализация, защото стартовата папка „{startupFolder}“ е в папка за преместване на приложения.",
"ReleaseStatus": "Състояние на освобождаване",
"UpdateScriptPathHelpText": "Път към персонализиран скрипт, който взема извлечен пакет за актуализация и обработва останалата част от процеса на актуализация",
"UseProxy": "Използвай прокси",
@@ -200,9 +200,9 @@
"PortNumber": "Номер на пристанище",
"Proxy": "Прокси",
"ProxyBypassFilterHelpText": "Използвайте „,“ като разделител и „*“. като заместващ знак за поддомейни",
"ProxyCheckBadRequestMessage": "Неуспешно тестване на прокси. Код на състоянието: {0}",
"ProxyCheckFailedToTestMessage": "Неуспешно тестване на прокси: {0}",
"ProxyCheckResolveIpMessage": "Неуспешно разрешаване на IP адреса за конфигурирания прокси хост {0}",
"ProxyBadRequestHealthCheckMessage": "Неуспешно тестване на прокси. Код на състоянието: {statusCode}",
"ProxyFailedToTestHealthCheckMessage": "Неуспешно тестване на прокси: {url}",
"ProxyResolveIpHealthCheckMessage": "Неуспешно разрешаване на IP адреса за конфигурирания прокси хост {proxyHostName}",
"ProxyPasswordHelpText": "Трябва само да въведете потребителско име и парола, ако е необходимо. В противен случай ги оставете празни.",
"ProxyType": "Тип прокси",
"ExistingTag": "Съществуващ маркер",
@@ -239,8 +239,8 @@
"Test": "Тест",
"UI": "Потребителски интерфейс",
"UILanguage": "Език на потребителския интерфейс",
"UpdateCheckStartupNotWritableMessage": "Не може да се инсталира актуализация, тъй като стартовата папка „{0}“ не може да се записва от потребителя „{1}“.",
"UpdateCheckUINotWritableMessage": "Не може да се инсталира актуализация, защото папката „{0}“ на потребителския интерфейс не може да се записва от потребителя „{1}“.",
"UpdateStartupNotWritableHealthCheckMessage": "Не може да се инсталира актуализация, тъй като стартовата папка „{startupFolder}“ не може да се записва от потребителя „{userName}“.",
"UpdateUiNotWritableHealthCheckMessage": "Не може да се инсталира актуализация, защото папката „{uiFolder}“ на потребителския интерфейс не може да се записва от потребителя „{userName}“.",
"Enable": "Активиране",
"EventType": "Тип на събитието",
"Failed": "Се провали",
@@ -253,13 +253,13 @@
"HideAdvanced": "Скрий Разширено",
"Indexer": "Индексатор",
"IndexerFlags": "Индексиращи знамена",
"IndexerLongTermStatusCheckAllClientMessage": "Всички индексатори са недостъпни поради грешки за повече от 6 часа",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Всички индексатори са недостъпни поради грешки за повече от 6 часа",
"SSLCertPathHelpText": "Път към pfx файл",
"UrlBaseHelpText": "За обратна поддръжка на прокси по подразбиране е празно",
"View": "Изглед",
"BranchUpdate": "Клон, който да се използва за актуализиране на {appName}",
"Indexers": "Индексатори",
"IndexerStatusCheckAllClientMessage": "Всички индексатори са недостъпни поради грешки",
"IndexerStatusAllUnavailableHealthCheckMessage": "Всички индексатори са недостъпни поради грешки",
"Mode": "Режим",
"TagsSettingsSummary": "Вижте всички тагове и как се използват. Неизползваните маркери могат да бъдат премахнати",
"TestAllClients": "Тествайте всички клиенти",
@@ -272,8 +272,8 @@
"Updates": "Актуализации",
"Uptime": "Време за работа",
"DownloadClientSettings": "Изтеглете настройките на клиента",
"DownloadClientStatusCheckAllClientMessage": "Всички клиенти за изтегляне са недостъпни поради неуспехи",
"DownloadClientStatusCheckSingleClientMessage": "Клиентите за изтегляне са недостъпни поради грешки: {0}",
"DownloadClientStatusAllClientHealthCheckMessage": "Всички клиенти за изтегляне са недостъпни поради неуспехи",
"DownloadClientStatusSingleClientHealthCheckMessage": "Клиентите за изтегляне са недостъпни поради грешки: {downloadClientNames}",
"Edit": "редактиране",
"EnableAutomaticSearch": "Активирайте автоматичното търсене",
"EnableAutomaticSearchHelpText": "Ще се използва, когато се извършват автоматични търсения чрез потребителския интерфейс или от {appName}",
@@ -288,9 +288,9 @@
"GeneralSettingsSummary": "Порт, SSL, потребителско име / парола, прокси, анализи и актуализации",
"History": "История",
"Host": "Водещ",
"IndexerLongTermStatusCheckSingleClientMessage": "Индексатори не са налични поради неуспехи за повече от 6 часа: {0}",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Индексатори не са налични поради неуспехи за повече от 6 часа: {indexerNames}",
"IndexerPriorityHelpText": "Приоритет на индексатора от 1 (най-висок) до 50 (най-нисък). По подразбиране: 25.",
"IndexerStatusCheckSingleClientMessage": "Индексатори не са налични поради грешки: {0}",
"IndexerStatusUnavailableHealthCheckMessage": "Индексатори не са налични поради грешки: {indexerNames}",
"LaunchBrowserHelpText": " Отворете уеб браузър и отворете началната страница на {appName} при стартиране на приложението.",
"ResetAPIKey": "Нулиране на API ключ",
"Restart": "Рестартирам",
@@ -346,12 +346,14 @@
"RecentChanges": "Последни промени",
"WhatsNew": "Какво ново?",
"minutes": "Минути",
"NotificationStatusSingleClientHealthCheckMessage": "Списъци, недостъпни поради неуспехи: {0}",
"NotificationStatusSingleClientHealthCheckMessage": "Списъци, недостъпни поради неуспехи: {notificationNames}",
"NotificationStatusAllClientHealthCheckMessage": "Всички списъци са недостъпни поради неуспехи",
"AuthBasic": "Основно (изскачащ прозорец на браузъра)",
"AuthForm": "Формуляри (Страница за вход)",
"DisabledForLocalAddresses": "Забранено за местни адреси",
"None": "Нито един",
"ResetAPIKeyMessageText": "Наистина ли искате да нулирате своя API ключ?",
"RestartProwlarr": "Рестартирайте {appName}"
"RestartProwlarr": "Рестартирайте {appName}",
"IndexerHDBitsSettingsMediums": "Среден",
"CustomFilter": "Персонализирани филтри"
}

View File

@@ -74,7 +74,7 @@
"Retention": "Retenció",
"Title": "Títol",
"DeleteNotification": "Suprimeix la notificació",
"ProxyCheckBadRequestMessage": "No s'ha pogut provar el servidor intermediari. Codi d'estat: {0}",
"ProxyBadRequestHealthCheckMessage": "No s'ha pogut provar el servidor intermediari. Codi d'estat: {statusCode}",
"Reddit": "Reddit",
"System": "Sistema",
"Username": "Nom d'usuari",
@@ -128,8 +128,8 @@
"Filters": "Filtres",
"FocusSearchBox": "Posa el focus a la caixa de cerca",
"Grabbed": "Capturat",
"IndexerStatusCheckAllClientMessage": "Tots els indexadors no estan disponibles a causa d'errors",
"IndexerStatusCheckSingleClientMessage": "Els indexadors no estan disponibles a causa d'errors: {0}",
"IndexerStatusAllUnavailableHealthCheckMessage": "Tots els indexadors no estan disponibles a causa d'errors",
"IndexerStatusUnavailableHealthCheckMessage": "Els indexadors no estan disponibles a causa d'errors: {indexerNames}",
"MovieIndexScrollTop": "Índex de pel·lícules: Desplaçament superior",
"NotificationTriggers": "Activadors de notificacions",
"NotificationTriggersHelpText": "Seleccioneu quins esdeveniments haurien d'activar aquesta notificació",
@@ -175,7 +175,7 @@
"DeleteTagMessageText": "Esteu segur que voleu suprimir l'etiqueta '{label}'?",
"Details": "Detalls",
"Disabled": "Desactivat",
"DownloadClientStatusCheckAllClientMessage": "Tots els clients de descàrrega no estan disponibles a causa d'errors",
"DownloadClientStatusAllClientHealthCheckMessage": "Tots els clients de descàrrega no estan disponibles a causa d'errors",
"Edit": "Edita",
"EnableInteractiveSearchHelpText": "S'utilitzarà quan s'utilitzi la cerca interactiva",
"EnableInteractiveSearch": "Activa la cerca interactiva",
@@ -198,8 +198,8 @@
"OnApplicationUpdateHelpText": "A l'actualitzar de l'aplicació",
"OnGrab": "Al capturar",
"PackageVersion": "Versió del paquet",
"ProxyCheckFailedToTestMessage": "No s'ha pogut provar el servidor intermediari: {0}",
"ProxyCheckResolveIpMessage": "No s'ha pogut resoldre l'adreça IP de l'amfitrió intermediari configurat {0}",
"ProxyFailedToTestHealthCheckMessage": "No s'ha pogut provar el servidor intermediari: {url}",
"ProxyResolveIpHealthCheckMessage": "No s'ha pogut resoldre l'adreça IP de l'amfitrió intermediari configurat {proxyHostName}",
"Queued": "En cua",
"ReadTheWikiForMoreInformation": "Llegiu el Wiki per a més informació",
"RestartRequiredHelpTextWarning": "Cal reiniciar perquè tingui efecte",
@@ -235,13 +235,13 @@
"Enable": "Activa",
"IndexerFlags": "Indicadors de l'indexador",
"UnableToLoadNotifications": "No es poden carregar les notificacions",
"IndexerLongTermStatusCheckAllClientMessage": "Tots els indexadors no estan disponibles a causa d'errors durant més de 6 hores",
"IndexerLongTermStatusCheckSingleClientMessage": "Els indexadors no estan disponibles a causa d'errors durant més de 6 hores: {0}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Tots els indexadors no estan disponibles a causa d'errors durant més de 6 hores",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Els indexadors no estan disponibles a causa d'errors durant més de 6 hores: {indexerNames}",
"IndexerPriority": "Prioritat de l'indexador",
"UnsavedChanges": "Canvis no desats",
"UpdateAutomaticallyHelpText": "Baixeu i instal·leu les actualitzacions automàticament. Encara podreu instal·lar des de Sistema: Actualitzacions",
"UpdateCheckStartupTranslocationMessage": "No es pot instal·lar l'actualització perquè la carpeta d'inici \"{0}\" es troba en una carpeta de translocació d'aplicacions.",
"UpdateCheckUINotWritableMessage": "No es pot instal·lar l'actualització perquè l'usuari '{1}' no pot escriure la carpeta de la IU '{0}'.",
"UpdateStartupTranslocationHealthCheckMessage": "No es pot instal·lar l'actualització perquè la carpeta d'inici \"{startupFolder}\" es troba en una carpeta de translocació d'aplicacions.",
"UpdateUiNotWritableHealthCheckMessage": "No es pot instal·lar l'actualització perquè l'usuari '{userName}' no pot escriure la carpeta de la IU '{uiFolder}'.",
"UpdateScriptPathHelpText": "Camí a un script personalitzat que pren un paquet d'actualització i gestiona la resta del procés d'actualització",
"Uptime": "Temps de funcionament",
"Info": "Informació",
@@ -266,7 +266,7 @@
"Discord": "Discord",
"Docker": "Docker",
"Donations": "Donacions",
"DownloadClientStatusCheckSingleClientMessage": "Baixa els clients no disponibles a causa d'errors: {0}",
"DownloadClientStatusSingleClientHealthCheckMessage": "Baixa els clients no disponibles a causa d'errors: {downloadClientNames}",
"HealthNoIssues": "No hi ha cap problema amb la configuració",
"HideAdvanced": "Amaga avançat",
"History": "Història",
@@ -294,7 +294,7 @@
"UnableToAddANewNotificationPleaseTryAgain": "No es pot afegir una notificació nova, torneu-ho a provar.",
"UnableToLoadGeneralSettings": "No es pot carregar la configuració general",
"UnableToLoadHistory": "No es pot carregar l'historial",
"UpdateCheckStartupNotWritableMessage": "No es pot instal·lar l'actualització perquè l'usuari \"{1}\" no pot escriure la carpeta d'inici \"{0}\".",
"UpdateStartupNotWritableHealthCheckMessage": "No es pot instal·lar l'actualització perquè l'usuari \"{userName}\" no pot escriure la carpeta d'inici \"{startupFolder}\".",
"URLBase": "Base URL",
"Usenet": "Usenet",
"View": "Visualitza",
@@ -333,8 +333,8 @@
"UnableToAddANewIndexerProxyPleaseTryAgain": "No es pot afegir un indexador nou, torneu-ho a provar.",
"UpdateMechanismHelpText": "Utilitzeu l'actualitzador integrat de {appName} o un script",
"UserAgentProvidedByTheAppThatCalledTheAPI": "Agent d'usuari proporcionat per l'aplicació per fer peticions a l'API",
"IndexerProxyStatusCheckAllClientMessage": "Tots els indexadors no estan disponibles a causa d'errors",
"IndexerProxyStatusCheckSingleClientMessage": "Els indexadors no estan disponibles a causa d'errors: {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Tots els indexadors no estan disponibles a causa d'errors",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Els indexadors no estan disponibles a causa d'errors: {indexerProxyNames}",
"LaunchBrowserHelpText": " Obriu un navegador web i navegueu a la pàgina d'inici de {appName} a l'inici de l'aplicació.",
"Link": "Enllaços",
"UILanguageHelpText": "Idioma que utilitzarà {appName} per a la interfície d'usuari",
@@ -362,14 +362,14 @@
"Theme": "Tema",
"Track": "Traça",
"Year": "Any",
"UpdateAvailable": "Nova actualització disponible",
"UpdateAvailableHealthCheckMessage": "Nova actualització disponible",
"ConnectionLostReconnect": "{appName} intentarà connectar-se automàticament, o podeu fer clic a recarregar.",
"ConnectionLostToBackend": "{appName} ha perdut la connexió amb el backend i s'haurà de tornar a carregar per a restaurar la funcionalitat.",
"RecentChanges": "Canvis recents",
"WhatsNew": "Que hi ha de nou?",
"minutes": "Minuts",
"DeleteAppProfileMessageText": "Esteu segur que voleu suprimir el perfil de qualitat {0}",
"NotificationStatusSingleClientHealthCheckMessage": "Llistes no disponibles a causa d'errors: {0}",
"NotificationStatusSingleClientHealthCheckMessage": "Llistes no disponibles a causa d'errors: {notificationNames}",
"AddConnection": "Afegeix una connexió",
"NotificationStatusAllClientHealthCheckMessage": "Totes les notificacions no estan disponibles a causa d'errors",
"AuthBasic": "Basic (finestra emergent del navegador)",
@@ -394,7 +394,7 @@
"EditIndexerImplementation": "Edita l'indexador - {implementationName}",
"EditSelectedDownloadClients": "Editeu els clients de descàrrega seleccionats",
"EditSelectedIndexers": "Edita els indexadors seleccionats",
"IndexerDownloadClientHealthCheckMessage": "Indexadors amb clients de baixada no vàlids: {0}.",
"IndexerDownloadClientHealthCheckMessage": "Indexadors amb clients de baixada no vàlids: {indexerNames}.",
"AddCustomFilter": "Afegeix un filtre personalitzat",
"AddDownloadClientImplementation": "Afegeix un client de descàrrega - {implementationName}",
"AddIndexerImplementation": "Afegeix un indexador - {implementationName}",
@@ -431,5 +431,17 @@
"Id": "ID",
"Author": "Autor",
"ManageClients": "Gestiona els clients",
"CountApplicationsSelected": "{count} Col·lecció(ns) seleccionades"
"CountApplicationsSelected": "{count} Col·lecció(ns) seleccionades",
"DownloadClientAriaSettingsDirectoryHelpText": "Ubicació opcional per a les baixades, deixeu-lo en blanc per utilitzar la ubicació predeterminada d'Aria2",
"Donate": "Dona",
"BlackholeFolderHelpText": "Carpeta on {appName} emmagatzemarà els fitxers {extension}",
"Destination": "Destinació",
"Directory": "Directori",
"DownloadClientDelugeSettingsUrlBaseHelpText": "Afegeix un prefix a l'url json del Deluge, vegeu {url}",
"CustomFilter": "Filtres personalitzats",
"IndexerHDBitsSettingsCodecs": "Còdec",
"DownloadClientSettingsUrlBaseHelpText": "Afegeix un prefix a l'URL {connectionName}, com ara {url}",
"DownloadClientTransmissionSettingsDirectoryHelpText": "Ubicació opcional per a les baixades, deixeu-lo en blanc per utilitzar la ubicació predeterminada d'Aria2",
"DownloadClientRTorrentSettingsDirectoryHelpText": "Ubicació opcional de les baixades completades, deixeu-lo en blanc per utilitzar la ubicació predeterminada de Deluge",
"IndexerHDBitsSettingsMediums": "Suport"
}

View File

@@ -23,7 +23,7 @@
"ProxyType": "Typ serveru proxy",
"Reddit": "Reddit",
"ErrorLoadingContents": "Chyba při načítání obsahu",
"IndexerLongTermStatusCheckAllClientMessage": "Všechny indexery nejsou k dispozici z důvodu selhání po dobu delší než 6 hodin",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Všechny indexery nejsou k dispozici z důvodu selhání po dobu delší než 6 hodin",
"RemovedFromTaskQueue": "Odebráno z fronty úkolů",
"ResetAPIKey": "Resetovat klíč API",
"SSLCertPassword": "Heslo SSL Cert",
@@ -41,8 +41,8 @@
"Docker": "Přístavní dělník",
"Donations": "Dary",
"DownloadClientSettings": "Stáhněte si nastavení klienta",
"DownloadClientStatusCheckAllClientMessage": "Všichni klienti pro stahování nejsou kvůli chybám k dispozici",
"DownloadClientStatusCheckSingleClientMessage": "Stahování klientů není k dispozici z důvodu selhání: {0}",
"DownloadClientStatusAllClientHealthCheckMessage": "Všichni klienti pro stahování nejsou kvůli chybám k dispozici",
"DownloadClientStatusSingleClientHealthCheckMessage": "Stahování klientů není k dispozici z důvodu selhání: {downloadClientNames}",
"Folder": "Složka",
"Grabs": "Urvat",
"HealthNoIssues": "Žádné problémy s vaší konfigurací",
@@ -55,7 +55,7 @@
"IndexerPriority": "Priorita indexování",
"IndexerPriorityHelpText": "Priorita indexování od 1 (nejvyšší) do 50 (nejnižší). Výchozí: 25.",
"Indexers": "Indexery",
"IndexerStatusCheckAllClientMessage": "Všechny indexery nejsou k dispozici z důvodu selhání",
"IndexerStatusAllUnavailableHealthCheckMessage": "Všechny indexery nejsou k dispozici z důvodu selhání",
"LastWriteTime": "Čas posledního zápisu",
"Level": "Úroveň",
"LogLevel": "Úroveň protokolu",
@@ -67,7 +67,7 @@
"Ok": "OK",
"SendAnonymousUsageData": "Odesílejte anonymní údaje o používání",
"UnselectAll": "Odznačit vše",
"UpdateCheckStartupNotWritableMessage": "Aktualizaci nelze nainstalovat, protože spouštěcí složku „{0}“ nelze zapisovat uživatelem „{1}“.",
"UpdateStartupNotWritableHealthCheckMessage": "Aktualizaci nelze nainstalovat, protože spouštěcí složku „{startupFolder}“ nelze zapisovat uživatelem „{userName}“.",
"Version": "Verze",
"AnalyticsEnabledHelpText": "Odesílejte anonymní informace o použití a chybách na servery {appName}u. To zahrnuje informace o vašem prohlížeči, které stránky {appName} WebUI používáte, hlášení chyb a také verzi operačního systému a běhového prostředí. Tyto informace použijeme k upřednostnění funkcí a oprav chyb.",
"ApiKey": "Klíč API",
@@ -105,7 +105,7 @@
"Tasks": "Úkoly",
"Test": "Test",
"UnableToLoadTags": "Značky nelze načíst",
"IndexerProxyStatusCheckAllClientMessage": "Všechny indexery nejsou k dispozici z důvodu selhání",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Všechny indexery nejsou k dispozici z důvodu selhání",
"ApplyTags": "Použít značky",
"MoreInfo": "Více informací",
"System": "Systém",
@@ -124,9 +124,9 @@
"Grabbed": "Popadl",
"Health": "Zdraví",
"LogLevelTraceHelpTextWarning": "Trasování protokolování by mělo být povoleno pouze dočasně",
"ProxyCheckBadRequestMessage": "Nepodařilo se otestovat proxy. StatusCode: {0}",
"ProxyCheckFailedToTestMessage": "Nepodařilo se otestovat proxy: {0}",
"ProxyCheckResolveIpMessage": "Nepodařilo se vyřešit adresu IP konfigurovaného hostitele proxy {0}",
"ProxyBadRequestHealthCheckMessage": "Nepodařilo se otestovat proxy. StatusCode: {statusCode}",
"ProxyFailedToTestHealthCheckMessage": "Nepodařilo se otestovat proxy: {url}",
"ProxyResolveIpHealthCheckMessage": "Nepodařilo se vyřešit adresu IP konfigurovaného hostitele proxy {proxyHostName}",
"ProxyPasswordHelpText": "Musíte pouze zadat uživatelské jméno a heslo, pokud je požadováno. Jinak je nechte prázdné.",
"ProxyUsernameHelpText": "Musíte pouze zadat uživatelské jméno a heslo, pokud je požadováno. Jinak je nechte prázdné.",
"Queue": "Fronta",
@@ -161,8 +161,8 @@
"UnableToAddANewIndexerPleaseTryAgain": "Nelze přidat nový indexer, zkuste to znovu.",
"UnableToAddANewIndexerProxyPleaseTryAgain": "Nelze přidat nový indexer, zkuste to znovu.",
"UnableToLoadNotifications": "Nelze načíst oznámení",
"UpdateCheckStartupTranslocationMessage": "Aktualizaci nelze nainstalovat, protože spouštěcí složka „{0}“ je ve složce Translocation aplikace.",
"UpdateCheckUINotWritableMessage": "Aktualizaci nelze nainstalovat, protože uživatelská složka „{0}“ není zapisovatelná uživatelem „{1}“.",
"UpdateStartupTranslocationHealthCheckMessage": "Aktualizaci nelze nainstalovat, protože spouštěcí složka „{startupFolder}“ je ve složce Translocation aplikace.",
"UpdateUiNotWritableHealthCheckMessage": "Aktualizaci nelze nainstalovat, protože uživatelská složka „{uiFolder}“ není zapisovatelná uživatelem „{userName}“.",
"UpdateMechanismHelpText": "Použijte vestavěný aktualizátor {appName} nebo skript",
"UpdateScriptPathHelpText": "Cesta k vlastnímu skriptu, který přebírá extrahovaný balíček aktualizace a zpracovává zbytek procesu aktualizace",
"Uptime": "Provozuschopnost",
@@ -183,7 +183,7 @@
"BypassProxyForLocalAddresses": "Obcházení proxy serveru pro místní adresy",
"DeleteIndexerProxyMessageText": "Opravdu chcete smazat značku „{0}“?",
"DeleteTag": "Smazat značku",
"IndexerProxyStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání: {0}",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Indexery nedostupné z důvodu selhání: {indexerProxyNames}",
"Name": "název",
"New": "Nový",
"Protocol": "Protokol",
@@ -265,8 +265,8 @@
"Exception": "Výjimka",
"ExistingTag": "Stávající značka",
"IllRestartLater": "Restartuji později",
"IndexerLongTermStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání po dobu delší než 6 hodin: {0}",
"IndexerStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání: {0}",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexery nedostupné z důvodu selhání po dobu delší než 6 hodin: {indexerNames}",
"IndexerStatusUnavailableHealthCheckMessage": "Indexery nedostupné z důvodu selhání: {indexerNames}",
"SettingsTimeFormat": "Časový formát",
"ShowAdvanced": "Zobrazit pokročilé",
"ShowSearch": "Zobrazit vyhledávání",
@@ -353,7 +353,7 @@
"ApplicationURL": "URL aplikace",
"ApplicationUrlHelpText": "Externí adresa URL této aplikace včetně http(s)://, portu a základní adresy URL",
"ApplyChanges": "Použít změny",
"ApiKeyValidationHealthCheckMessage": "Aktualizujte svůj klíč API tak, aby měl alespoň {0} znaků. Můžete to provést prostřednictvím nastavení nebo konfiguračního souboru",
"ApiKeyValidationHealthCheckMessage": "Aktualizujte svůj klíč API tak, aby měl alespoň {length} znaků. Můžete to provést prostřednictvím nastavení nebo konfiguračního souboru",
"AppUpdated": "{appName} aktualizován",
"AddDownloadClientImplementation": "Přidat klienta pro stahování - {implementationName}",
"AuthenticationRequired": "Vyžadované ověření",
@@ -371,7 +371,7 @@
"EditIndexerImplementation": "Upravit indexer - {implementationName}",
"Episode": "epizoda",
"NotificationStatusAllClientHealthCheckMessage": "Všechny seznamy nejsou k dispozici z důvodu selhání",
"NotificationStatusSingleClientHealthCheckMessage": "Seznamy nejsou k dispozici z důvodu selhání: {0}",
"NotificationStatusSingleClientHealthCheckMessage": "Seznamy nejsou k dispozici z důvodu selhání: {notificationNames}",
"Application": "Aplikace",
"AppUpdatedVersion": "{appName} byl aktualizován na verzi `{version}`, abyste získali nejnovější změny, musíte znovu načíst {appName}",
"Encoding": "Kódování",
@@ -408,5 +408,9 @@
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Potvrďte nové heslo",
"days": "dnů",
"Id": "ID",
"CountApplicationsSelected": "Vybráno {0} kolekcí"
"CountApplicationsSelected": "Vybráno {0} kolekcí",
"IndexerHDBitsSettingsCodecs": "Kodek",
"IndexerHDBitsSettingsMediums": "Střední",
"Directory": "Adresář",
"CustomFilter": "Vlastní filtry"
}

View File

@@ -3,8 +3,8 @@
"Language": "Sprog",
"KeyboardShortcuts": "Keyboard Genveje",
"Info": "Information",
"IndexerStatusCheckSingleClientMessage": "Indexere utilgængelige på grund af fejl: {0}",
"IndexerStatusCheckAllClientMessage": "Alle indeksører er utilgængelige på grund af fejl",
"IndexerStatusUnavailableHealthCheckMessage": "Indexere utilgængelige på grund af fejl: {indexerNames}",
"IndexerStatusAllUnavailableHealthCheckMessage": "Alle indeksører er utilgængelige på grund af fejl",
"Indexers": "Indexere",
"History": "Historie",
"HideAdvanced": "Gemt Avancerede",
@@ -21,8 +21,8 @@
"Events": "Begivenheder",
"Error": "Fejl",
"Edit": "Rediger",
"DownloadClientStatusCheckSingleClientMessage": "Download klienter er ikke tilgængelige på grund af fejl: {0}",
"DownloadClientStatusCheckAllClientMessage": "Alle download klienter er utilgængelige på grund af fejl",
"DownloadClientStatusSingleClientHealthCheckMessage": "Download klienter er ikke tilgængelige på grund af fejl: {downloadClientNames}",
"DownloadClientStatusAllClientHealthCheckMessage": "Alle download klienter er utilgængelige på grund af fejl",
"DownloadClientsSettingsSummary": "Indstilling af downloadklienter til brug for {appName}s søgefunktion",
"DownloadClients": "Download Klienter",
"DownloadClient": "Download Klient",
@@ -135,12 +135,12 @@
"IllRestartLater": "Jeg genstarter senere",
"IncludeHealthWarningsHelpText": "Inkluder sundhedsadvarsler",
"Indexer": "Indekser",
"IndexerLongTermStatusCheckAllClientMessage": "Alle indeksatorer er ikke tilgængelige på grund af fejl i mere end 6 timer",
"IndexerLongTermStatusCheckSingleClientMessage": "Indeksatorer er ikke tilgængelige på grund af fejl i mere end 6 timer: {0}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Alle indeksatorer er ikke tilgængelige på grund af fejl i mere end 6 timer",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indeksatorer er ikke tilgængelige på grund af fejl i mere end 6 timer: {indexerNames}",
"IndexerPriority": "Indekseringsprioritet",
"IndexerPriorityHelpText": "Indekseringsprioritet fra 1 (højest) til 50 (lavest). Standard: 25.",
"IndexerProxyStatusCheckAllClientMessage": "Alle indexere er utilgængelige på grund af fejl",
"IndexerProxyStatusCheckSingleClientMessage": "Indexere utilgængelige på grund af fejl: {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Alle indexere er utilgængelige på grund af fejl",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Indexere utilgængelige på grund af fejl: {indexerProxyNames}",
"LaunchBrowserHelpText": " Åbn en webbrowser, og naviger til {appName}-hjemmesiden ved start af appen.",
"Logging": "Logning",
"LogLevel": "Logniveau",
@@ -173,9 +173,9 @@
"Priority": "Prioritet",
"Protocol": "Protokol",
"ProxyBypassFilterHelpText": "Brug ',' som en separator og '*.' som et jokertegn for underdomæner",
"ProxyCheckBadRequestMessage": "Kunne ikke teste proxy. Statuskode: {0}",
"ProxyCheckFailedToTestMessage": "Kunne ikke teste proxy: {0}",
"ProxyCheckResolveIpMessage": "Mislykkedes at løse IP-adressen til den konfigurerede proxyhost {0}",
"ProxyBadRequestHealthCheckMessage": "Kunne ikke teste proxy. Statuskode: {statusCode}",
"ProxyFailedToTestHealthCheckMessage": "Kunne ikke teste proxy: {url}",
"ProxyResolveIpHealthCheckMessage": "Mislykkedes at løse IP-adressen til den konfigurerede proxyhost {proxyHostName}",
"ProxyPasswordHelpText": "Du skal kun indtaste et brugernavn og en adgangskode, hvis der kræves et. Lad dem være tomme ellers.",
"ProxyUsernameHelpText": "Du skal kun indtaste et brugernavn og en adgangskode, hvis der kræves et. Lad dem være tomme ellers.",
"ReadTheWikiForMoreInformation": "Læs Wiki for mere information",
@@ -239,8 +239,8 @@
"UnableToLoadUISettings": "UI-indstillingerne kunne ikke indlæses",
"UnselectAll": "Fravælg alle",
"UpdateAutomaticallyHelpText": "Download og installer opdateringer automatisk. Du kan stadig installere fra System: Updates",
"UpdateCheckStartupNotWritableMessage": "Kan ikke installere opdatering, fordi startmappen '{0}' ikke kan skrives af brugeren '{1}'.",
"UpdateCheckUINotWritableMessage": "Kan ikke installere opdatering, fordi brugergrænsefladen \"{0}\" ikke kan skrives af brugeren \"{1}\".",
"UpdateStartupNotWritableHealthCheckMessage": "Kan ikke installere opdatering, fordi startmappen '{startupFolder}' ikke kan skrives af brugeren '{userName}'.",
"UpdateUiNotWritableHealthCheckMessage": "Kan ikke installere opdatering, fordi brugergrænsefladen \"{uiFolder}\" ikke kan skrives af brugeren \"{userName}\".",
"UpdateScriptPathHelpText": "Sti til et brugerdefineret script, der tager en udpakket opdateringspakke og håndterer resten af opdateringsprocessen",
"Uptime": "Oppetid",
"URLBase": "URL-base",
@@ -265,7 +265,7 @@
"StartupDirectory": "Startmappe",
"Status": "Status",
"DownloadClientsLoadError": "Kunne ikke indlæse downloadklienter",
"UpdateCheckStartupTranslocationMessage": "Kan ikke installere opdatering, fordi startmappen '{0}' er i en App Translocation-mappe.",
"UpdateStartupTranslocationHealthCheckMessage": "Kan ikke installere opdatering, fordi startmappen '{startupFolder}' er i en App Translocation-mappe.",
"UpdateMechanismHelpText": "Brug den indbyggede opdateringsfunktion eller et script",
"View": "Udsigt",
"Warn": "Advare",
@@ -363,7 +363,7 @@
"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: {notificationNames}",
"AuthForm": "Formularer (login-side)",
"DisabledForLocalAddresses": "Deaktiveret for lokale adresser",
"ResetAPIKeyMessageText": "Er du sikker på, at du vil nulstille din API-nøgle?",
@@ -377,5 +377,20 @@
"AddApplicationImplementation": "Tilføj forbindelse - {implementationName}",
"AddIndexerImplementation": "Tilføj betingelse - {implementationName}",
"ApplyChanges": "Anvend ændringer",
"AddDownloadClientImplementation": "Tilføj downloadklient - {implementationName}"
"AddDownloadClientImplementation": "Tilføj downloadklient - {implementationName}",
"Album": "album",
"Theme": "Tema",
"Categories": "Kategorier",
"Application": "Applikationer",
"EditIndexerProxyImplementation": "Tilføj betingelse - {implementationName}",
"Publisher": "Udgiver",
"IndexerHDBitsSettingsCodecs": "codec",
"Applications": "Applikationer",
"AddIndexerProxyImplementation": "Tilføj betingelse - {implementationName}",
"EditIndexerImplementation": "Tilføj betingelse - {implementationName}",
"Directory": "Mappe",
"EditApplicationImplementation": "Tilføj forbindelse - {implementationName}",
"EditDownloadClientImplementation": "Tilføj downloadklient - {implementationName}",
"IndexerHDBitsSettingsMediums": "Medium",
"CustomFilter": "Bruger Tilpassede Filtere"
}

View File

@@ -20,7 +20,7 @@
"Analytics": "Analysen",
"AnalyticsEnabledHelpText": "Senden Sie anonyme Nutzungs- und Fehlerinformationen an die Server von {appName}. Dazu gehören Informationen zu Ihrem Browser, welche {appName}-WebUI-Seiten Sie verwenden, Fehlerberichte sowie Betriebssystem- und Laufzeitversion. Wir werden diese Informationen verwenden, um Funktionen und Fehlerbehebungen zu priorisieren.",
"ApiKey": "API-Schlüssel",
"ApiKeyValidationHealthCheckMessage": "Bitte den API Schlüssel korrigieren, dieser muss mindestens {0} Zeichen lang sein. Die Änderung kann über die Einstellungen oder die Konfigurationsdatei erfolgen",
"ApiKeyValidationHealthCheckMessage": "Bitte den API Schlüssel korrigieren, dieser muss mindestens {length} Zeichen lang sein. Die Änderung kann über die Einstellungen oder die Konfigurationsdatei erfolgen",
"AppDataDirectory": "AppData-Verzeichnis",
"AppDataLocationHealthCheckMessage": "Ein Update ist nicht möglich, um das Löschen von AppData beim Update zu verhindern",
"AppProfileInUse": "App-Profil im Einsatz",
@@ -107,8 +107,8 @@
"Donations": "Spenden",
"DownloadClient": "Download Client",
"DownloadClientSettings": "Downloader Einstellungen",
"DownloadClientStatusCheckAllClientMessage": "Alle Download Clients sind aufgrund von Fehlern nicht verfügbar",
"DownloadClientStatusCheckSingleClientMessage": "Download Clients aufgrund von Fehlern nicht verfügbar: {0}",
"DownloadClientStatusAllClientHealthCheckMessage": "Alle Download Clients sind aufgrund von Fehlern nicht verfügbar",
"DownloadClientStatusSingleClientHealthCheckMessage": "Download Clients aufgrund von Fehlern nicht verfügbar: {downloadClientNames}",
"DownloadClients": "Downloader",
"DownloadClientsSettingsSummary": "Download der Client-Konfigurationen für die Integration in die {appName} UI-Suche",
"Duration": "Dauer",
@@ -176,8 +176,8 @@
"IndexerFlags": "Indexer-Flags",
"IndexerHealthCheckNoIndexers": "Keine Indexer aktiviert, {appName} wird keine Suchergebnisse zurückgeben",
"IndexerInfo": "Indexer-Info",
"IndexerLongTermStatusCheckAllClientMessage": "Alle Indexer sind wegen über 6 Stunden langen bestehender Fehler nicht verfügbar",
"IndexerLongTermStatusCheckSingleClientMessage": "Indexer wegen über 6 Stunden langen bestehenden Fehlern nicht verfügbar: {0}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Alle Indexer sind wegen über 6 Stunden langen bestehender Fehler nicht verfügbar",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexer wegen über 6 Stunden langen bestehenden Fehlern nicht verfügbar: {indexerNames}",
"IndexerName": "Indexer-Name",
"IndexerNoDefCheckMessage": "Indexer haben keine Definition und werden nicht funktionieren: {0}. Bitte entferne und (oder) füge diese neu zu {appName} hinzu",
"IndexerObsoleteCheckMessage": "Indexer sind nicht mehr verfügbar oder wurden aktualiiert: {0}. Bitte enfernen und (oder) neu zu {appName} hinzufügen",
@@ -185,17 +185,17 @@
"IndexerPriorityHelpText": "Indexer Priorität von 1 (höchste) bis 50 (niedrigste). Standard: 25.",
"IndexerProxies": "Indexer-Proxies",
"IndexerProxy": "Indexer-Proxy",
"IndexerProxyStatusCheckAllClientMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar",
"IndexerProxyStatusCheckSingleClientMessage": "Listen aufgrund von Fehlern nicht verfügbar: {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Listen aufgrund von Fehlern nicht verfügbar: {indexerProxyNames}",
"IndexerQuery": "Indexer Anfrage",
"IndexerRss": "Indexer RSS",
"IndexerSettingsSummary": "Konfiguration verschiedener globaler Indexer Einstellungen, einschließlich Proxies.",
"IndexerSite": "Indexer-Seite",
"IndexerStatusCheckAllClientMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar",
"IndexerStatusCheckSingleClientMessage": "Indexer aufgrund von Fehlern nicht verfügbar: {0}",
"IndexerStatusAllUnavailableHealthCheckMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar",
"IndexerStatusUnavailableHealthCheckMessage": "Indexer aufgrund von Fehlern nicht verfügbar: {indexerNames}",
"IndexerTagsHelpText": "Benutze Tags, um Indexer-Proxies zu spezifizieren, mit welchen Apps der Indexer synchronisiert oder um Indexer zu organisieren.",
"IndexerVipCheckExpiredClientMessage": "Die VIP Indexer Vorteile sind abgelaufen: {0}",
"IndexerVipCheckExpiringClientMessage": "Die Indexer VIP Vorteile verfallen bald: {0}",
"IndexerVipExpiredHealthCheckMessage": "Die VIP Indexer Vorteile sind abgelaufen: {indexerNames}",
"IndexerVipExpiringHealthCheckMessage": "Die Indexer VIP Vorteile verfallen bald: {indexerNames}",
"Indexers": "Indexer",
"Info": "Info",
"InstanceName": "Instanzname",
@@ -281,9 +281,9 @@
"Proxies": "Proxies",
"Proxy": "Proxy",
"ProxyBypassFilterHelpText": "Verwenden Sie ',' als Trennzeichen und '*.' als Wildcard für Subdomains",
"ProxyCheckBadRequestMessage": "Proxy konnte nicht getestet werden. StatusCode: {0}",
"ProxyCheckFailedToTestMessage": "Proxy konnte nicht getestet werden: {0}",
"ProxyCheckResolveIpMessage": "Fehler beim Auflösen der IP-Adresse für den konfigurierten Proxy-Host {0}",
"ProxyBadRequestHealthCheckMessage": "Proxy konnte nicht getestet werden. StatusCode: {statusCode}",
"ProxyFailedToTestHealthCheckMessage": "Proxy konnte nicht getestet werden: {url}",
"ProxyResolveIpHealthCheckMessage": "Fehler beim Auflösen der IP-Adresse für den konfigurierten Proxy-Host {proxyHostName}",
"ProxyPasswordHelpText": "Sie müssen nur einen Benutzernamen und ein Passwort eingeben, wenn dies erforderlich ist. Andernfalls lassen Sie sie leer.",
"ProxyType": "Proxy-Typ",
"ProxyUsernameHelpText": "Sie müssen nur einen Benutzernamen und ein Passwort eingeben, wenn dies erforderlich ist. Andernfalls lassen Sie sie leer.",
@@ -432,9 +432,9 @@
"UnsavedChanges": "Nicht gespeicherte Änderungen",
"UnselectAll": "Alle abwählen",
"UpdateAutomaticallyHelpText": "Updates automatisch herunterladen und installieren. Sie können weiterhin über System: Updates installieren",
"UpdateCheckStartupNotWritableMessage": "Update kann nicht installiert werden, da der Startordner '{0}' vom Benutzer '{1}' nicht beschreibbar ist.",
"UpdateCheckStartupTranslocationMessage": "Update kann nicht installiert werden, da sich der Startordner '{0}' in einem App Translocation-Ordner befindet.",
"UpdateCheckUINotWritableMessage": "Update kann nicht installiert werden, da der Benutzeroberflächenordner '{0}' vom Benutzer '{1}' nicht beschreibbar ist.",
"UpdateStartupNotWritableHealthCheckMessage": "Update kann nicht installiert werden, da der Startordner '{startupFolder}' vom Benutzer '{userName}' nicht beschreibbar ist.",
"UpdateStartupTranslocationHealthCheckMessage": "Update kann nicht installiert werden, da sich der Startordner '{startupFolder}' in einem App Translocation-Ordner befindet.",
"UpdateUiNotWritableHealthCheckMessage": "Update kann nicht installiert werden, da der Benutzeroberflächenordner '{uiFolder}' vom Benutzer '{userName}' nicht beschreibbar ist.",
"UpdateMechanismHelpText": "Verwenden Sie den integrierten Updater von {appName} oder ein Skript",
"UpdateScriptPathHelpText": "Pfad zu einem benutzerdefinierten Skript, das ein extrahiertes Update-Paket übernimmt und den Rest des Update-Prozesses abwickelt",
"Updates": "Aktualisierung",
@@ -485,7 +485,7 @@
"More": "Mehr",
"Publisher": "Herausgeber",
"Track": "Trace",
"UpdateAvailable": "Neue Version verfügbar",
"UpdateAvailableHealthCheckMessage": "Neue Version verfügbar",
"Year": "Jahr",
"Album": "Album",
"Artist": "Künstler",
@@ -499,7 +499,7 @@
"DeleteAppProfileMessageText": "Qualitätsprofil '{0}' wirklich löschen?",
"AddConnection": "Verbindung hinzufügen",
"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: {notificationNames}",
"AuthBasic": "Basis (Browser-Popup)",
"AuthForm": "Formulare (Anmeldeseite)",
"DisabledForLocalAddresses": "Für lokale Adressen deaktiviert",

View File

@@ -28,8 +28,8 @@
"EventType": "Είδος Γεγονότος",
"Events": "Γεγονότα",
"Edit": "Επεξεργασία",
"DownloadClientStatusCheckSingleClientMessage": "Προγράμματα λήψης που είναι μη διαθέσιμα λόγων αποτυχιών: {0}",
"DownloadClientStatusCheckAllClientMessage": "Όλα τα προγράμματα λήψης είναι μη διαθέσιμα λόγων αποτυχιών",
"DownloadClientStatusSingleClientHealthCheckMessage": "Προγράμματα λήψης που είναι μη διαθέσιμα λόγων αποτυχιών: {downloadClientNames}",
"DownloadClientStatusAllClientHealthCheckMessage": "Όλα τα προγράμματα λήψης είναι μη διαθέσιμα λόγων αποτυχιών",
"DownloadClientsSettingsSummary": "Κάντε λήψη της διαμόρφωσης πελατών για ενσωμάτωση στην αναζήτηση διεπαφής χρήστη {appName}",
"CustomFilters": "Custom Φιλτρα",
"ConnectSettingsSummary": "Ειδοποιήσεις και προσαρμοσμένα σενάρια",
@@ -45,7 +45,7 @@
"Indexer": "Ευρετήριο",
"PendingChangesDiscardChanges": "Απορρίψτε τις αλλαγές και φύγετε",
"ShowSearchHelpText": "Εμφάνιση κουμπιού αναζήτησης στο δείκτη",
"UpdateCheckStartupNotWritableMessage": "Δεν είναι δυνατή η εγκατάσταση της ενημέρωσης επειδή ο φάκελος εκκίνησης \"{0}\" δεν είναι εγγράψιμος από τον χρήστη \"{1}\".",
"UpdateStartupNotWritableHealthCheckMessage": "Δεν είναι δυνατή η εγκατάσταση της ενημέρωσης επειδή ο φάκελος εκκίνησης \"{startupFolder}\" δεν είναι εγγράψιμος από τον χρήστη \"{userName}\".",
"BranchUpdateMechanism": "Υποκατάστημα που χρησιμοποιείται από εξωτερικό μηχανισμό ενημέρωσης",
"Mode": "Τρόπος",
"SettingsEnableColorImpairedMode": "Ενεργοποίηση λειτουργίας με προβλήματα χρώματος",
@@ -73,8 +73,8 @@
"NoChange": "Καμία αλλαγή",
"Port": "Λιμάνι",
"PortNumber": "Αριθμός θύρας",
"IndexerStatusCheckAllClientMessage": "Όλοι οι δείκτες δεν είναι διαθέσιμοι λόγω αστοχιών",
"IndexerStatusCheckSingleClientMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών: {0}",
"IndexerStatusAllUnavailableHealthCheckMessage": "Όλοι οι δείκτες δεν είναι διαθέσιμοι λόγω αστοχιών",
"IndexerStatusUnavailableHealthCheckMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών: {indexerNames}",
"KeyboardShortcuts": "Συντομεύσεις πληκτρολογίου",
"Language": "Γλώσσα",
"Reset": "Επαναφορά",
@@ -113,7 +113,7 @@
"ProxyBypassFilterHelpText": "Χρησιμοποιήστε το \",\" ως διαχωριστικό και \"*.\" ως μπαλαντέρ για υποτομείς",
"UnableToAddANewAppProfilePleaseTryAgain": "Δεν είναι δυνατή η προσθήκη ενός νέου προφίλ ποιότητας. Δοκιμάστε ξανά.",
"UnableToLoadHistory": "Δεν είναι δυνατή η φόρτωση του ιστορικού",
"UpdateCheckUINotWritableMessage": "Δεν είναι δυνατή η εγκατάσταση της ενημέρωσης επειδή ο φάκελος διεπαφής χρήστη \"{0}\" δεν είναι εγγράψιμος από τον χρήστη \"{1}\".",
"UpdateUiNotWritableHealthCheckMessage": "Δεν είναι δυνατή η εγκατάσταση της ενημέρωσης επειδή ο φάκελος διεπαφής χρήστη \"{uiFolder}\" δεν είναι εγγράψιμος από τον χρήστη \"{userName}\".",
"AuthenticationMethodHelpText": "Απαιτήστε όνομα χρήστη και κωδικό πρόσβασης για πρόσβαση στο {appName}",
"Automatic": "Αυτόματο",
"BeforeUpdate": "Πριν από την ενημέρωση",
@@ -139,10 +139,10 @@
"HomePage": "Αρχική σελίδα",
"Host": "Πλήθος",
"Hostname": "Όνομα κεντρικού υπολογιστή",
"IndexerLongTermStatusCheckSingleClientMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών για περισσότερο από 6 ώρες: {0}",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών για περισσότερο από 6 ώρες: {indexerNames}",
"IndexerPriorityHelpText": "Προτεραιότητα ευρετηρίου από 1 (Υψηλότερη) έως 50 (Χαμηλότερη). Προεπιλογή: 25.",
"IndexerProxyStatusCheckAllClientMessage": "Όλες οι λίστες δεν είναι διαθέσιμες λόγω αστοχιών",
"IndexerProxyStatusCheckSingleClientMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών: {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Όλες οι λίστες δεν είναι διαθέσιμες λόγω αστοχιών",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Τα ευρετήρια δεν είναι διαθέσιμα λόγω αστοχιών: {indexerProxyNames}",
"LaunchBrowserHelpText": " Ανοίξτε ένα πρόγραμμα περιήγησης ιστού και μεταβείτε στην αρχική σελίδα του {appName} κατά την έναρξη της εφαρμογής.",
"LogFiles": "Αρχεία καταγραφής",
"Logging": "Ξύλευση",
@@ -166,8 +166,8 @@
"PendingChangesStayReview": "Παραμείνετε και ελέγξτε τις αλλαγές",
"Presets": "Προεπιλογές",
"Priority": "Προτεραιότητα",
"ProxyCheckFailedToTestMessage": "Αποτυχία δοκιμής διακομιστή μεσολάβησης: {0}",
"ProxyCheckResolveIpMessage": "Αποτυχία επίλυσης της διεύθυνσης IP για τον Διαμορφωμένο διακομιστή μεσολάβησης {0}",
"ProxyFailedToTestHealthCheckMessage": "Αποτυχία δοκιμής διακομιστή μεσολάβησης: {url}",
"ProxyResolveIpHealthCheckMessage": "Αποτυχία επίλυσης της διεύθυνσης IP για τον Διαμορφωμένο διακομιστή μεσολάβησης {proxyHostName}",
"Queue": "Ουρά",
"ReadTheWikiForMoreInformation": "Διαβάστε το Wiki για περισσότερες πληροφορίες",
"Refresh": "Φρεσκάρω",
@@ -219,7 +219,7 @@
"UnableToLoadNotifications": "Δεν είναι δυνατή η φόρτωση ειδοποιήσεων",
"UnableToLoadUISettings": "Δεν είναι δυνατή η φόρτωση των ρυθμίσεων διεπαφής χρήστη",
"UnsavedChanges": "Μη αποθηκευμένες αλλαγές",
"UpdateCheckStartupTranslocationMessage": "Δεν είναι δυνατή η εγκατάσταση της ενημέρωσης επειδή ο φάκελος εκκίνησης \"{0}\" βρίσκεται σε ένα φάκελο \"Μετατόπιση εφαρμογών\".",
"UpdateStartupTranslocationHealthCheckMessage": "Δεν είναι δυνατή η εγκατάσταση της ενημέρωσης επειδή ο φάκελος εκκίνησης \"{startupFolder}\" βρίσκεται σε ένα φάκελο \"Μετατόπιση εφαρμογών\".",
"UpdateScriptPathHelpText": "Διαδρομή σε ένα προσαρμοσμένο σενάριο που λαμβάνει ένα εξαγόμενο πακέτο ενημέρωσης και χειρίζεται το υπόλοιπο της διαδικασίας ενημέρωσης",
"URLBase": "Βάση διεύθυνσης URL",
"UrlBaseHelpText": "Για αντίστροφη υποστήριξη διακομιστή μεσολάβησης, η προεπιλογή είναι άδεια",
@@ -242,10 +242,10 @@
"BindAddress": "Δεσμευμένη διεύθυνση",
"EnableRss": "Ενεργοποίηση RSS",
"IndexerFlags": "Σημαίες ευρετηρίου",
"IndexerLongTermStatusCheckAllClientMessage": "Όλοι οι δείκτες δεν είναι διαθέσιμοι λόγω αστοχιών για περισσότερο από 6 ώρες",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Όλοι οι δείκτες δεν είναι διαθέσιμοι λόγω αστοχιών για περισσότερο από 6 ώρες",
"InteractiveSearch": "Διαδραστική αναζήτηση",
"Interval": "Διάστημα",
"ProxyCheckBadRequestMessage": "Αποτυχία δοκιμής διακομιστή μεσολάβησης. StatusCode: {0}",
"ProxyBadRequestHealthCheckMessage": "Αποτυχία δοκιμής διακομιστή μεσολάβησης. StatusCode: {statusCode}",
"ProxyPasswordHelpText": "Πρέπει να εισαγάγετε ένα όνομα χρήστη και έναν κωδικό πρόσβασης μόνο εάν απαιτείται. Αφήστε τα κενά διαφορετικά.",
"ProxyType": "Τύπος διακομιστή μεσολάβησης",
"ProxyUsernameHelpText": "Πρέπει να εισαγάγετε ένα όνομα χρήστη και έναν κωδικό πρόσβασης μόνο εάν απαιτείται. Αφήστε τα κενά διαφορετικά.",
@@ -356,7 +356,7 @@
"Auth": "Auth",
"BookSearch": "Αναζήτηση βιβλίου",
"FullSync": "Πλήρης συγχρονισμός",
"IndexerVipCheckExpiringClientMessage": "Τα οφέλη VIP του ευρετηρίου λήγουν σύντομα: {0}",
"IndexerVipExpiringHealthCheckMessage": "Τα οφέλη VIP του ευρετηρίου λήγουν σύντομα: {indexerNames}",
"NotSupported": "Δεν υποστηρίζεται",
"Parameters": "Παράμετροι",
"Public": "Δημόσιο",
@@ -394,7 +394,7 @@
"IndexerQuery": "Ερώτημα ευρετηρίου",
"IndexerSettingsSummary": "Διαμορφώστε διάφορες καθολικές ρυθμίσεις ευρετηρίου, συμπεριλαμβανομένων των διακομιστών μεσολάβησης.",
"IndexerSite": "Ιστότοπος ευρετηρίου",
"IndexerVipCheckExpiredClientMessage": "Τα προνόμια VIP του ευρετηρίου έχουν λήξει: {0}",
"IndexerVipExpiredHealthCheckMessage": "Τα προνόμια VIP του ευρετηρίου έχουν λήξει: {indexerNames}",
"MappedCategories": "Χαρτογραφημένες κατηγορίες",
"MovieSearch": "Αναζήτηση ταινίας",
"MovieSearchTypes": "Τύποι αναζήτησης ταινιών",
@@ -459,7 +459,7 @@
"Remove": "Αφαιρώ",
"Replace": "Αντικαθιστώ",
"TheLatestVersionIsAlreadyInstalled": "Η τελευταία έκδοση του {appName} είναι ήδη εγκατεστημένη",
"ApiKeyValidationHealthCheckMessage": "Παρακαλούμε ενημερώστε το κλείδι API ώστε να έχει τουλάχιστον {0} χαρακτήρες. Μπορείτε να το κάνετε αυτό μέσα από τις ρυθμίσεις ή το αρχείο ρυθμίσεων",
"ApiKeyValidationHealthCheckMessage": "Παρακαλούμε ενημερώστε το κλείδι API ώστε να έχει τουλάχιστον {length} χαρακτήρες. Μπορείτε να το κάνετε αυτό μέσα από τις ρυθμίσεις ή το αρχείο ρυθμίσεων",
"StopSelecting": "Διακοπή Επιλογής",
"OnHealthRestored": "Στην Αποκατάσταση Υγείας",
"ApplicationURL": "Διεύθυνση URL εφαρμογής",
@@ -485,7 +485,7 @@
"Theme": "Θέμα",
"Track": "Ιχνος",
"Year": "Ετος",
"UpdateAvailable": "Νέα ενημέρωση είναι διαθέσιμη",
"UpdateAvailableHealthCheckMessage": "Νέα ενημέρωση είναι διαθέσιμη",
"Artist": "Καλλιτέχνης",
"Author": "Συγγραφέας",
"Book": "Βιβλίο",
@@ -501,7 +501,7 @@
"DeleteAppProfileMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το προφίλ ποιότητας '{0}'?",
"AddConnection": "Προσθήκη Σύνδεσης",
"NotificationStatusAllClientHealthCheckMessage": "Όλες οι λίστες δεν είναι διαθέσιμες λόγω αστοχιών",
"NotificationStatusSingleClientHealthCheckMessage": "Μη διαθέσιμες λίστες λόγω αποτυχιών: {0}",
"NotificationStatusSingleClientHealthCheckMessage": "Μη διαθέσιμες λίστες λόγω αποτυχιών: {notificationNames}",
"AuthBasic": "Βασικό (Αναδυόμενο παράθυρο προγράμματος περιήγησης)",
"AuthForm": "Φόρμες (σελίδα σύνδεσης)",
"Clone": "Κλωνοποίηση",
@@ -518,5 +518,9 @@
"AddConnectionImplementation": "Προσθήκη - {implementationName}",
"AddIndexerImplementation": "Προσθήκη",
"EditIndexerProxyImplementation": "Προσθήκη",
"CountApplicationsSelected": "Επιλέχθηκαν {0} συλλογές"
"CountApplicationsSelected": "Επιλέχθηκαν {0} συλλογές",
"IndexerBeyondHDSettingsSearchTypes": "Τύποι αναζήτησης",
"IndexerHDBitsSettingsMediums": "Μεσαίο",
"UseSsl": "Χρησιμοποιήστε SSL",
"CustomFilter": "Custom Φιλτρα"
}

View File

@@ -34,7 +34,7 @@
"Analytics": "Analytics",
"AnalyticsEnabledHelpText": "Send anonymous usage and error information to {appName}'s servers. This includes information on your browser, which {appName} WebUI pages you use, error reporting as well as OS and runtime version. We will use this information to prioritize features and bug fixes.",
"ApiKey": "API Key",
"ApiKeyValidationHealthCheckMessage": "Please update your API key to be at least {0} characters long. You can do this via settings or the config file",
"ApiKeyValidationHealthCheckMessage": "Please update your API key to be at least {length} characters long. You can do this via settings or the config file",
"AppDataDirectory": "AppData Directory",
"AppDataLocationHealthCheckMessage": "Updating will not be possible to prevent deleting AppData on Update",
"AppProfileInUse": "App Profile in Use",
@@ -45,6 +45,8 @@
"Application": "Application",
"ApplicationLongTermStatusCheckAllClientMessage": "All applications are unavailable due to failures for more than 6 hours",
"ApplicationLongTermStatusCheckSingleClientMessage": "Applications unavailable due to failures for more than 6 hours: {0}",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashes": "Sync Reject Blocklisted Torrent Hashes While Grabbing",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText": "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.",
"ApplicationStatusCheckAllClientMessage": "All applications are unavailable due to failures",
"ApplicationStatusCheckSingleClientMessage": "Applications unavailable due to failures: {0}",
"ApplicationTagsHelpText": "Sync Indexers to this application that have one or more matching tags. If no tags are listed here, then no indexers will be prevented from syncing due to their tags.",
@@ -114,6 +116,7 @@
"Clear": "Clear",
"ClearHistory": "Clear History",
"ClearHistoryMessageText": "Are you sure you want to clear all {appName} history?",
"ClickToChangeQueryOptions": "Click to change query options",
"ClientPriority": "Client Priority",
"Clone": "Clone",
"CloneProfile": "Clone Profile",
@@ -223,8 +226,8 @@
"DownloadClientSettingsPriorityItemHelpText": "Priority to use when grabbing items",
"DownloadClientSettingsUrlBaseHelpText": "Adds a prefix to the {clientName} url, such as {url}",
"DownloadClientSettingsUseSslHelpText": "Use secure connection when connection to {clientName}",
"DownloadClientStatusCheckAllClientMessage": "All download clients are unavailable due to failures",
"DownloadClientStatusCheckSingleClientMessage": "Download clients unavailable due to failures: {0}",
"DownloadClientStatusAllClientHealthCheckMessage": "All download clients are unavailable due to failures",
"DownloadClientStatusSingleClientHealthCheckMessage": "Download clients unavailable due to failures: {downloadClientNames}",
"DownloadClientTransmissionSettingsDirectoryHelpText": "Optional location to put downloads in, leave blank to use the default Transmission location",
"DownloadClientTransmissionSettingsUrlBaseHelpText": "Adds a prefix to the {clientName} rpc url, eg {url}, defaults to '{defaultUrl}'",
"DownloadClients": "Download Clients",
@@ -324,7 +327,7 @@
"IndexerCategories": "Indexer Categories",
"IndexerDetails": "Indexer Details",
"IndexerDisabled": "Indexer Disabled",
"IndexerDownloadClientHealthCheckMessage": "Indexers with invalid download clients: {0}.",
"IndexerDownloadClientHealthCheckMessage": "Indexers with invalid download clients: {indexerNames}.",
"IndexerDownloadClientHelpText": "Specify which download client is used for grabs made within {appName} from this indexer",
"IndexerFailureRate": "Indexer Failure Rate",
"IndexerFileListSettingsFreeleechOnlyHelpText": "Search freeleech releases only",
@@ -353,8 +356,10 @@
"IndexerIPTorrentsSettingsFreeleechOnlyHelpText": "Search freeleech releases only",
"IndexerId": "Indexer ID",
"IndexerInfo": "Indexer Info",
"IndexerLongTermStatusCheckAllClientMessage": "All indexers are unavailable due to failures for more than 6 hours",
"IndexerLongTermStatusCheckSingleClientMessage": "Indexers unavailable due to failures for more than 6 hours: {0}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "All indexers are unavailable due to failures for more than 6 hours",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexers unavailable due to failures for more than 6 hours: {indexerNames}",
"IndexerMTeamTpSettingsApiKeyHelpText": "API Key from the Site (Found in User Control Panel => Security => Laboratory)",
"IndexerMTeamTpSettingsFreeleechOnlyHelpText": "Search freeleech releases only",
"IndexerName": "Indexer Name",
"IndexerNebulanceSettingsApiKeyHelpText": "API Key from User Settings > Api Keys. Key must have List and Download permissions",
"IndexerNewznabSettingsAdditionalParametersHelpText": "Additional Newznab parameters",
@@ -371,8 +376,8 @@
"IndexerPriorityHelpText": "Indexer Priority from 1 (Highest) to 50 (Lowest). Default: 25.",
"IndexerProxies": "Indexer Proxies",
"IndexerProxy": "Indexer Proxy",
"IndexerProxyStatusCheckAllClientMessage": "All proxies are unavailable due to failures",
"IndexerProxyStatusCheckSingleClientMessage": "Proxies unavailable due to failures: {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "All indexer proxies are unavailable due to failures",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Indexer proxies unavailable due to failures: {indexerProxyNames}",
"IndexerQuery": "Indexer Query",
"IndexerRedactedSettingsApiKeyHelpText": "API Key from the Site (Found in Settings => Access Settings)",
"IndexerRss": "Indexer RSS",
@@ -396,8 +401,6 @@
"IndexerSettingsPasskey": "Pass Key",
"IndexerSettingsQueryLimit": "Query Limit",
"IndexerSettingsQueryLimitHelpText": "The number of max queries as specified by the respective unit that {appName} will allow to the site",
"IndexerSettingsRejectBlocklistedTorrentHashes": "Reject Blocklisted Torrent Hashes While Grabbing",
"IndexerSettingsRejectBlocklistedTorrentHashesHelpText": "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.",
"IndexerSettingsRssKey": "RSS Key",
"IndexerSettingsSeedRatio": "Seed Ratio",
"IndexerSettingsSeedRatioHelpText": "The ratio a torrent should reach before stopping, empty uses the download client's default. Ratio should be at least 1.0 and follow the indexers rules",
@@ -407,13 +410,13 @@
"IndexerSettingsVipExpiration": "VIP Expiration",
"IndexerSite": "Indexer Site",
"IndexerStatus": "Indexer Status",
"IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures",
"IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}",
"IndexerStatusAllUnavailableHealthCheckMessage": "All indexers are unavailable due to failures",
"IndexerStatusUnavailableHealthCheckMessage": "Indexers unavailable due to failures: {indexerNames}",
"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.",
"IndexerTorrentSyndikatSettingsApiKeyHelpText": "Site API Key",
"IndexerVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}",
"IndexerVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}",
"IndexerVipExpiredHealthCheckMessage": "Indexer VIP benefits have expired: {indexerNames}",
"IndexerVipExpiringHealthCheckMessage": "Indexer VIP benefits expiring soon: {indexerNames}",
"Indexers": "Indexers",
"Info": "Info",
"InitialFailure": "Initial Failure",
@@ -486,12 +489,14 @@
"NotSupported": "Not Supported",
"Notification": "Notification",
"NotificationStatusAllClientHealthCheckMessage": "All notifications are unavailable due to failures",
"NotificationStatusSingleClientHealthCheckMessage": "Notifications unavailable due to failures: {0}",
"NotificationStatusSingleClientHealthCheckMessage": "Notifications unavailable due to failures: {notificationNames}",
"NotificationTriggers": "Notification Triggers",
"NotificationTriggersHelpText": "Select which events should trigger this notification",
"Notifications": "Notifications",
"NotificationsEmailSettingsUseEncryption": "Use Encryption",
"NotificationsEmailSettingsUseEncryptionHelpText": "Whether to prefer using encryption if configured on the server, to always use encryption via SSL (Port 465 only) or StartTLS (any other port) or to never use encryption",
"NotificationsTelegramSettingsIncludeAppName": "Include {appName} in Title",
"NotificationsTelegramSettingsIncludeAppNameHelpText": "Optionally prefix message title with {appName} to differentiate notifications from different applications",
"OAuthPopupMessage": "Pop-ups are being blocked by your browser",
"Ok": "Ok",
"OnApplicationUpdate": "On Application Update",
@@ -530,11 +535,11 @@
"ProwlarrSupportsAnyIndexer": "{appName} supports many indexers in addition to any indexer that uses the Newznab/Torznab standard using 'Generic Newznab' (for usenet) or 'Generic Torznab' (for torrents). Search & Select your indexer from below.",
"Proxies": "Proxies",
"Proxy": "Proxy",
"ProxyBadRequestHealthCheckMessage": "Failed to test proxy. Status code: {statusCode}",
"ProxyBypassFilterHelpText": "Use ',' as a separator, and '*.' as a wildcard for subdomains",
"ProxyCheckBadRequestMessage": "Failed to test proxy. Status code: {0}",
"ProxyCheckFailedToTestMessage": "Failed to test proxy: {0}",
"ProxyCheckResolveIpMessage": "Failed to resolve the IP Address for the Configured Proxy Host {0}",
"ProxyFailedToTestHealthCheckMessage": "Failed to test proxy: {url}",
"ProxyPasswordHelpText": "You only need to enter a username and password if one is required. Leave them blank otherwise.",
"ProxyResolveIpHealthCheckMessage": "Failed to resolve the IP Address for the Configured Proxy Host {proxyHostName}",
"ProxyType": "Proxy Type",
"ProxyUsernameHelpText": "You only need to enter a username and password if one is required. Leave them blank otherwise.",
"Public": "Public",
@@ -715,12 +720,12 @@
"UnsavedChanges": "Unsaved Changes",
"UnselectAll": "Unselect All",
"UpdateAutomaticallyHelpText": "Automatically download and install updates. You will still be able to install from System: Updates",
"UpdateAvailable": "New update is available",
"UpdateCheckStartupNotWritableMessage": "Cannot install update because startup folder '{0}' is not writable by the user '{1}'.",
"UpdateCheckStartupTranslocationMessage": "Cannot install update because startup folder '{0}' is in an App Translocation folder.",
"UpdateCheckUINotWritableMessage": "Cannot install update because UI folder '{0}' is not writable by the user '{1}'.",
"UpdateAvailableHealthCheckMessage": "New update is available",
"UpdateMechanismHelpText": "Use {appName}'s built-in updater or a script",
"UpdateScriptPathHelpText": "Path to a custom script that takes an extracted update package and handle the remainder of the update process",
"UpdateStartupNotWritableHealthCheckMessage": "Cannot install update because startup folder '{startupFolder}' is not writable by the user '{userName}'.",
"UpdateStartupTranslocationHealthCheckMessage": "Cannot install update because startup folder '{startupFolder}' is in an App Translocation folder.",
"UpdateUiNotWritableHealthCheckMessage": "Cannot install update because UI folder '{uiFolder}' is not writable by the user '{userName}'.",
"Updates": "Updates",
"Uptime": "Uptime",
"Url": "Url",

View File

@@ -10,8 +10,8 @@
"Files": "Archivos",
"Events": "Eventos",
"Edit": "Editar",
"DownloadClientStatusCheckSingleClientMessage": "Gestores de descargas no disponibles debido a errores: {0}",
"DownloadClientStatusCheckAllClientMessage": "Los gestores de descargas no están disponibles debido a errores",
"DownloadClientStatusSingleClientHealthCheckMessage": "Gestores de descargas no disponibles debido a errores: {downloadClientNames}",
"DownloadClientStatusAllClientHealthCheckMessage": "Los gestores de descargas no están disponibles debido a errores",
"DownloadClients": "Clientes de descarga",
"Delete": "Eliminar",
"Dates": "Fechas",
@@ -28,9 +28,9 @@
"About": "Acerca de",
"View": "Vista",
"Updates": "Actualizaciones",
"UpdateCheckUINotWritableMessage": "No se puede instalar la actualización porque la carpeta UI '{0}' no tiene permisos de escritura para el usuario '{1}'.",
"UpdateCheckStartupTranslocationMessage": "No se puede instalar la actualización porque la carpeta de arranque '{0}' está en una carpeta de \"App Translocation\".",
"UpdateCheckStartupNotWritableMessage": "No se puede instalar la actualización porque la carpeta de arranque '{0}' no tiene permisos de escritura para el usuario '{1}'.",
"UpdateUiNotWritableHealthCheckMessage": "No se puede instalar la actualización porque la carpeta UI '{uiFolder}' no tiene permisos de escritura para el usuario '{userName}'.",
"UpdateStartupTranslocationHealthCheckMessage": "No se puede instalar la actualización porque la carpeta de arranque '{startupFolder}' está en una carpeta de \"App Translocation\".",
"UpdateStartupNotWritableHealthCheckMessage": "No se puede instalar la actualización porque la carpeta de arranque '{startupFolder}' no tiene permisos de escritura para el usuario '{userName}'.",
"UnselectAll": "Desmarcar todo",
"UI": "UI",
"Tasks": "Tareas",
@@ -51,9 +51,9 @@
"ReleaseBranchCheckOfficialBranchMessage": "Las versión {0} no es una versión válida de {appName}, no recibirás actualizaciones",
"Refresh": "Actualizar",
"Queue": "Cola",
"ProxyCheckResolveIpMessage": "No se pudo resolver la dirección IP del Host Proxy configurado {0}",
"ProxyCheckFailedToTestMessage": "Fallo al comprobar el proxy: {0}",
"ProxyCheckBadRequestMessage": "Fallo al comprobar el proxy. Status code: {0}",
"ProxyResolveIpHealthCheckMessage": "No se pudo resolver la dirección IP del Host Proxy configurado {proxyHostName}",
"ProxyFailedToTestHealthCheckMessage": "Fallo al comprobar el proxy: {url}",
"ProxyBadRequestHealthCheckMessage": "Fallo al comprobar el proxy. Status code: {statusCode}",
"Proxy": "Proxy",
"Options": "Opciones",
"NoChange": "Sin cambio",
@@ -62,7 +62,7 @@
"Logging": "Registro de eventos",
"LogFiles": "Archivos de Registro",
"Language": "Idioma",
"IndexerStatusCheckAllClientMessage": "Todos los indexadores no están disponibles debido a errores",
"IndexerStatusAllUnavailableHealthCheckMessage": "Todos los indexadores no están disponibles debido a errores",
"Added": "Añadido",
"Actions": "Acciones",
"UISettingsSummary": "Fecha, idioma, y opciones de color deteriorado",
@@ -71,7 +71,7 @@
"ReleaseStatus": "Estado del Estreno",
"Protocol": "Protocolo",
"LastWriteTime": "Última Fecha de Escritura",
"IndexerStatusCheckSingleClientMessage": "Indexadores no disponibles debido a errores: {indexerNames}",
"IndexerStatusUnavailableHealthCheckMessage": "Indexadores no disponibles debido a errores: {indexerNames}",
"Indexer": "Indexador",
"Grabbed": "Añadido",
"GeneralSettingsSummary": "Puerto, SSL, nombre de usuario/contraseña , proxy, analíticas, y actualizaciones",
@@ -284,8 +284,8 @@
"MovieIndexScrollBottom": "Indice de Películas: Desplazar hacia abajo",
"CloseCurrentModal": "Cerrar esta Ventana Modal",
"AcceptConfirmationModal": "Aceptar Confirmación de esta Ventana Modal",
"IndexerLongTermStatusCheckSingleClientMessage": "Indexers no disponible por errores durando más de 6 horas: {0}",
"IndexerLongTermStatusCheckAllClientMessage": "Ningún indexer está disponible por errores durando más de 6 horas",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexers no disponible por errores durando más de 6 horas: {indexerNames}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Ningún indexer está disponible por errores durando más de 6 horas",
"Reddit": "Reddit",
"UnableToAddANewAppProfilePleaseTryAgain": "No se ha podido añadir un nuevo perfil de calidad, prueba otra vez.",
"DeleteIndexerProxyMessageText": "¿Seguro que quieres eliminar el proxy indexador '{name}'?",
@@ -308,8 +308,8 @@
"ApplicationStatusCheckSingleClientMessage": "Listas no disponibles debido a errores: {0}",
"AllIndexersHiddenDueToFilter": "Todos los indexadores están ocultas debido al filtro aplicado.",
"DeleteApplicationMessageText": "Seguro que quieres eliminar la notificación '{name}'?",
"IndexerProxyStatusCheckAllClientMessage": "Los indexers no están disponibles debido a errores",
"IndexerProxyStatusCheckSingleClientMessage": "Indexers no disponibles debido a errores: {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Los indexers no están disponibles debido a errores",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Indexers no disponibles debido a errores: {indexerProxyNames}",
"NoLinks": "Sin enlaces",
"AddDownloadClient": "Añadir Cliente de Descarga",
"CouldNotConnectSignalR": "No se pudo conectar a SignalR, la interfaz de usuario no se actualiza",
@@ -388,7 +388,7 @@
"More": "Más",
"Track": "Rastro",
"Year": "Año",
"UpdateAvailable": "La nueva actualización está disponible",
"UpdateAvailableHealthCheckMessage": "La nueva actualización está disponible",
"Genre": "Género",
"Publisher": "Editor",
"AuthenticationRequired": "Autenticación requerida",
@@ -399,8 +399,8 @@
"EditSelectedIndexers": "Editar Indexadores Seleccionados",
"Implementation": "Implementación",
"ManageDownloadClients": "Gestionar Clientes de Descarga",
"ApiKeyValidationHealthCheckMessage": "Actualice su clave de API para que tenga al menos {0} carácteres. Puede hacerlo en los ajustes o en el archivo de configuración",
"IndexerDownloadClientHealthCheckMessage": "Indexadores con clientes de descarga inválidos: {0}.",
"ApiKeyValidationHealthCheckMessage": "Actualice su clave de API para que tenga al menos {length} carácteres. Puede hacerlo en los ajustes o en el archivo de configuración",
"IndexerDownloadClientHealthCheckMessage": "Indexadores con clientes de descarga inválidos: {indexerNames}.",
"Episode": "Episodio",
"ConnectionLostReconnect": "{appName} intentará conectarse automáticamente, o puede hacer clic en recargar abajo.",
"ConnectionLostToBackend": "{appName} ha perdido su conexión con el backend y tendrá que ser recargado para recuperar su funcionalidad.",
@@ -412,7 +412,7 @@
"DeleteAppProfileMessageText": "¿Estás seguro de que quieres eliminar el perfil de la aplicación '{name}'?",
"AddConnection": "Añadir Conexión",
"NotificationStatusAllClientHealthCheckMessage": "Las notificaciones no están disponibles debido a fallos",
"NotificationStatusSingleClientHealthCheckMessage": "Listas no disponibles debido a errores: {0}",
"NotificationStatusSingleClientHealthCheckMessage": "Listas no disponibles debido a errores: {notificationNames}",
"EditIndexerImplementation": "Editar Indexador - {implementationName}",
"AuthBasic": "Básico (ventana emergente del navegador)",
"AuthForm": "Formularios (Página de inicio de sesión)",
@@ -423,14 +423,14 @@
"External": "Externo",
"None": "Ninguno",
"ResetAPIKeyMessageText": "¿Estás seguro que quieres restablecer tu clave API?",
"EditIndexerProxyImplementation": "Editar Proxy de Indexador - { implementationName}",
"EditIndexerProxyImplementation": "Editar proxy de indexador - {implementationName}",
"AppUpdated": "{appName} Actualizado",
"AppUpdatedVersion": "{appName} ha sido actualizado a la versión `{version}`, para obtener los cambios más recientes, necesitará recargar {appName}",
"AddApplicationImplementation": "Agregar aplicación - { implementationName}",
"AddApplicationImplementation": "Agregar aplicación - {implementationName}",
"AddConnectionImplementation": "Añadir Conexión - {implementationName}",
"AddIndexerImplementation": "Agregar Indexador - {implementationName}",
"AddIndexerProxyImplementation": "Agregar Proxy de Indexador - { implementationName}",
"EditApplicationImplementation": "Editar Aplicación - { implementationName}",
"EditApplicationImplementation": "Editar aplicación - {implementationName}",
"EditConnectionImplementation": "Editar Conexión - {implementationName}",
"AddDownloadClientImplementation": "Añadir Cliente de Descarga - {implementationName}",
"AuthenticationMethod": "Método de autenticación",
@@ -524,10 +524,10 @@
"IndexerRss": "RSS del Indexador",
"IndexerSettingsSummary": "Configurar varios ajustes globales del Indexador, incluyendo Proxies.",
"IndexerName": "Nombre del Indexador",
"IndexerVipCheckExpiringClientMessage": "Las ventajas VIP de los indexadores expiran pronto: {0}",
"IndexerVipExpiringHealthCheckMessage": "Las ventajas VIP de los indexadores expiran pronto: {indexerNames}",
"IndexerProxies": "Proxies del Indexador",
"IndexerHistoryLoadError": "Error al cargar el historial del Indexador",
"IndexerVipCheckExpiredClientMessage": "Las ventajas VIP del Indexador han caducado: {0}",
"IndexerVipExpiredHealthCheckMessage": "Las ventajas VIP del Indexador han caducado: {indexerNames}",
"IndexerQuery": "Consulta dedl Indexador",
"IndexerSite": "Sitio del Indexador",
"IndexerStatus": "Estado del indexador",
@@ -621,5 +621,131 @@
"UsenetBlackholeNzbFolder": "Carpeta Nzb",
"TorrentBlackholeSaveMagnetFilesHelpText": "Guarda el enlace magnet si no hay ningún archivo .torrent disponible (útil solo si el cliente de descarga soporta magnets guardados en un archivo)",
"SecretToken": "Token secreto",
"TorrentBlackholeSaveMagnetFilesExtension": "Guardar extensión de archivos magnet"
"TorrentBlackholeSaveMagnetFilesExtension": "Guardar extensión de archivos magnet",
"Donate": "Donar",
"ClickToChangeQueryOptions": "Haz clic para cambiar las opciones de petición",
"DefaultCategory": "Categoría predeterminada",
"Destination": "Destino",
"Directory": "Directorio",
"DownloadClientDelugeSettingsUrlBaseHelpText": "Añade un prefijo al url del json de deluge, vea {url}",
"DownloadClientDownloadStationSettingsDirectoryHelpText": "Carpeta compartida opcional en la que poner las descargas, dejar en blanco para usar la ubicación de la Estación de Descarga predeterminada",
"DownloadClientFloodSettingsAdditionalTags": "Etiquetas adicionales",
"DownloadClientFloodSettingsAdditionalTagsHelpText": "Añade propiedades de medios como etiquetas. Los consejos son ejemplos.",
"DownloadClientFreeboxSettingsAppId": "ID de la app",
"DownloadClientFreeboxSettingsAppToken": "Token de la app",
"DownloadClientFreeboxSettingsApiUrl": "URL de API",
"DownloadClientFreeboxSettingsApiUrlHelpText": "Define la URL base de la API Freebox con la versión de la API, p. ej. '{url}', por defecto a '{defaultApiUrl}'",
"DownloadClientFreeboxSettingsAppIdHelpText": "ID de la app dada cuando se crea acceso a la API de Freebox (esto es 'app_id')",
"DownloadClientFloodSettingsTagsHelpText": "Etiquetas iniciales de una descarga. Para ser reconocida, una descarga debe tener todas las etiquetas iniciales. Esto evita conflictos con descargas no relacionadas.",
"DownloadClientFloodSettingsUrlBaseHelpText": "Añade un prefijo a la API de Flood, como {url}",
"DownloadClientFreeboxSettingsAppTokenHelpText": "Token de la app recuperado cuando se crea acceso a la API de Freebox (esto es 'app_token')",
"ProwlarrDownloadClientsAlert": "Si intentas hacer búsquedas directamente dentro de {appName}, necesitas añadir clientes de descarga. De otro modo, no necesitas añadirlos aquí. Para búsquedas desde tus aplicaciones, los clientes de descarga configurados serán usados en su lugar.",
"ProwlarrDownloadClientsInAppOnlyAlert": "Los clientes de descarga son solo para búsquedas internas en {appName} y no sincronizan a las aplicaciones. No hay planes para añadir cualquier funcionalidad.",
"TorrentBlackholeSaveMagnetFilesExtensionHelpText": "Extensión a usar para enlaces magnet, predeterminado a '.magnet'",
"DownloadClientRTorrentSettingsUrlPath": "Ruta de url",
"IndexerHDBitsSettingsOrigins": "Orígenes",
"IndexerIPTorrentsSettingsCookieUserAgentHelpText": "User-Agent asociado con la cookie usada desde el navegador",
"IndexerSettingsSeedRatioHelpText": "El ratio que un torrent debería alcanzar antes de detenerse, vacío usa el predeterminado del cliente de descarga. El ratio debería ser al menos 1.0 y seguir las reglas de los indexadores",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashes": "Sincronizar rechazo de hashes de torrents en la lista de bloqueo mientras se captura",
"IndexerGazelleGamesSettingsApiKeyHelpTextWarning": "Debes tener permisos de usuario y de torrents",
"IndexerGazelleGamesSettingsSearchGroupNamesHelpText": "Busca lanzamientos por nombres de grupo",
"IndexerHDBitsSettingsOriginsHelpText": "Si no se especifica, se usarán todas las opciones.",
"IndexerIPTorrentsSettingsCookieUserAgent": "Cookie de User-Agent",
"IndexerAlphaRatioSettingsExcludeSceneHelpText": "Excluye lanzamientos de ESCENA de los resultados",
"IndexerAlphaRatioSettingsExcludeScene": "Excluir ESCENA",
"IndexerAlphaRatioSettingsFreeleechOnlyHelpText": "Buscar solo lanzamientos freeleech",
"IndexerBeyondHDSettingsLimitedOnly": "Solo limitados",
"IndexerBeyondHDSettingsRewindOnlyHelpText": "Buscar solo rebobinados",
"IndexerBeyondHDSettingsRssKeyHelpText": "Clave RSS del sitio (encontrada en Mi seguridad => Clave RSS)",
"IndexerBeyondHDSettingsSearchTypes": "Tipos de búsqueda",
"IndexerGazelleGamesSettingsSearchGroupNames": "Buscar nombres de grupo",
"IndexerHDBitsSettingsCodecsHelpText": "Si no se especifica, se usarán todas las opciones.",
"IndexerHDBitsSettingsMediumsHelpText": "Si no se especifica, se usarán todas las opciones.",
"IndexerHDBitsSettingsUseFilenames": "Usar nombres de archivo",
"IndexerHDBitsSettingsUseFilenamesHelpText": "Señala esta opción si quieres usar nombres de archivo como títulos de lanzamiento",
"IndexerHDBitsSettingsUsernameHelpText": "Usuario del sitio",
"IndexerIPTorrentsSettingsFreeleechOnlyHelpText": "Buscar solo lanzamientos freeleech",
"IndexerNewznabSettingsAdditionalParametersHelpText": "Parámetros adicionales de Newznab",
"IndexerNewznabSettingsApiKeyHelpText": "Clave API del sitio",
"IndexerNzbIndexSettingsApiKeyHelpText": "Clave API del sitio",
"IndexerPassThePopcornSettingsApiUserHelpText": "Estas opciones se encuentran en tus opciones de seguridad de PassThePopcorn (Editar perfil > Seguridad).",
"IndexerPassThePopcornSettingsApiKeyHelpText": "Clave API del sitio",
"IndexerRedactedSettingsApiKeyHelpText": "Clave API del sitio (encontrada en Opciones => Opciones de acceso)",
"IndexerSettingsAdditionalParameters": "Parámetros adicionales",
"IndexerSettingsApiPathHelpText": "Ruta a la API, usualmente {url}",
"IndexerSettingsApiUser": "Usuario de API",
"IndexerSettingsAppsMinimumSeeders": "Semillas mínimas de las aplicaciones",
"IndexerSettingsBaseUrlHelpText": "Selecciona qué url base usará {appName} para las peticiones al sitio",
"IndexerSettingsCookie": "Cookie",
"IndexerSettingsRssKey": "Clave RSS",
"IndexerSettingsSeedRatio": "Ratio de sembrado",
"IndexerSettingsSeedTimeHelpText": "El tiempo que un torrent debería ser compartido antes de detenerse, vació usa el predeterminado del cliente de descarga",
"IndexerMTeamTpSettingsApiKeyHelpText": "Clave API del sitio (encontrada en Panel de control de usuario => Seguridad => Laboratorio)",
"IndexerMTeamTpSettingsFreeleechOnlyHelpText": "Buscar solo lanzamientos freeleech",
"Menu": "Menú",
"Mixed": "Mezclado",
"DownloadClientQbittorrentSettingsFirstAndLastFirstHelpText": "Descarga primero las primeras y últimas piezas (qBittorrent 4.1.0+)",
"DownloadClientQbittorrentSettingsFirstAndLastFirst": "Primeras y últimas primero",
"DownloadClientQbittorrentSettingsInitialStateHelpText": "Estado inicial para los torrents añadidos a qBittorrent. Ten en cuenta que Forzar torrents no cumple las restricciones de semilla",
"DownloadClientRTorrentSettingsAddStopped": "Añadir detenido",
"DownloadClientRTorrentSettingsAddStoppedHelpText": "Permite añadir torrents y magnets a rTorrent en estado detenido. Esto puede romper los archivos magnet.",
"DownloadClientQbittorrentSettingsUseSslHelpText": "Usa una conexión segura. Ver en Opciones -> Interfaz web -> 'Usar HTTPS en lugar de HTTP' en qbittorrent.",
"DownloadClientRTorrentSettingsDirectoryHelpText": "Ubicación opcional en la que poner las descargas, dejar en blanco para usar la ubicación predeterminada de rTorrent",
"DownloadClientSettingsDefaultCategorySubFolderHelpText": "Categoría devuelta por defecto si no existe ninguna categoría mapeada para un lanzamiento. Añadir una categoría específica a {appName} evita conflictos con descargas no relacionadas con {appName}. Usar una categoría es opcional, pero bastante recomendado. Crea un subdirectorio [categoría] en el directorio de salida.",
"DownloadClientSettingsAddPaused": "Añadir pausado",
"DownloadClientSettingsPriorityItemHelpText": "Prioridad a usar cuando se capturen elementos",
"DownloadClientSettingsInitialStateHelpText": "Estado inicial para torrents añadidos a {clientName}",
"DownloadClientSettingsUseSslHelpText": "Usa una conexión segura cuando haya una conexión a {clientName}",
"DownloadClientTransmissionSettingsDirectoryHelpText": "Ubicación opcional en la que poner las descargas, dejar en blanco para usar la ubicación predeterminada de Transmission",
"DownloadClientSettingsUrlBaseHelpText": "Añade un prefijo a la url {clientName}, como {url}",
"IndexerBeyondHDSettingsApiKeyHelpText": "Clave API del sitio (encontrada en Mi seguridad => Clave API)",
"IndexerBeyondHDSettingsFreeleechOnlyHelpText": "Buscar solo lanzamientos freeleech",
"IndexerBeyondHDSettingsLimitedOnlyHelpText": "Buscar solo freeleech (UL limitada)",
"IndexerFileListSettingsFreeleechOnlyHelpText": "Buscar solo lanzamientos freeleech",
"IndexerFileListSettingsPasskeyHelpText": "Clave de acceso del sitio (esto es la cadena alfanumérica en la url del tracket mostrada en tu cliente de descarga)",
"IndexerFileListSettingsUsernameHelpText": "Usuario del sitio",
"IndexerHDBitsSettingsMediums": "Medios",
"IndexerHDBitsSettingsCodecs": "Códecs",
"IndexerHDBitsSettingsFreeleechOnlyHelpText": "Mostrar solo lanzamientos freeleech",
"IndexerNebulanceSettingsApiKeyHelpText": "Clave API de Opciones de usuario > Claves API. La clave debe tener permisos de lista y descarga",
"IndexerNewznabSettingsVipExpirationHelpText": "Introduce la fecha (yyyy-mm-dd) para Expiración VIP o en blanco, {appName} notificará a una semana de la expiración del VIP",
"IndexerOrpheusSettingsApiKeyHelpText": "Clave API del sitio (encontrada en Opciones => Opciones de acceso)",
"IndexerPassThePopcornSettingsFreeleechOnlyHelpText": "Buscar solo lanzamientos freeleech",
"IndexerSettingsApiPath": "Ruta de API",
"IndexerSettingsBaseUrl": "Url base",
"IndexerSettingsPackSeedTime": "Tiempo de sembrado de pack",
"IndexerSettingsLimitsUnit": "Unidad de límites",
"IndexerSettingsQueryLimit": "Límite de petición",
"IndexerTorrentSyndikatSettingsApiKeyHelpText": "Clave API del sitio",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText": "Si un torrent es bloqueado por un hash puede no ser rechazado apropiadamente durante Buscar/RSS para algunos indexadores, habilitar esto permitirá que sea rechazado después de que el torrent sea capturado, pero antes es enviado al cliente.",
"IndexerSettingsAppsMinimumSeedersHelpText": "Semillas mínimas requeridas por las aplicaciones para que el indexador capture, dejar vacío usa el predeterminado de Sincronización de perfil",
"DownloadClientSettingsDefaultCategoryHelpText": "Categoría devuelta por defecto si no existe ninguna categoría mapeada para un lanzamiento. Añadir una categoría específica a {appName} evita conflictos con descargas no relacionadas con {appName}. Usar una categoría es opcional, pero bastante recomendado.",
"IndexerSettingsGrabLimitHelpText": "El número de capturas máximas especificadas por la unidad respectiva que {appName} permitirá al sitio",
"IndexerSettingsLimitsUnitHelpText": "La unidad o tiempo para límites de recuento por indexador",
"IndexerSettingsPackSeedTimeIndexerHelpText": "El tiempo en que un pack de torrent (temporada o discografía) debería ser compartido antes de detenerse, vacío usa el predeterminado de la aplicación",
"DownloadClientPneumaticSettingsNzbFolder": "Carpeta de Nzb",
"DownloadClientTransmissionSettingsUrlBaseHelpText": "Añade un prefijo a la url rpc de {clientName}, p. ej. {url}, predeterminado a '{defaultUrl}'",
"DownloadClientPneumaticSettingsNzbFolderHelpText": "Esta carpeta necesitará ser alcanzable desde XBMC",
"DownloadClientPneumaticSettingsStrmFolder": "Carpeta de Strm",
"DownloadClientPneumaticSettingsStrmFolderHelpText": "Los archivos .strm en esta carpeta será importados por drone",
"DownloadClientQbittorrentSettingsSequentialOrder": "Orden secuencial",
"DownloadClientFreeboxSettingsHostHelpText": "Nombre de host o dirección IP de host del Freebox, predeterminado a '{url}' (solo funcionará en la misma red)",
"DownloadClientFreeboxSettingsPortHelpText": "Puerto usado para acceder a la interfaz de Freebox, predeterminado a '{port}'",
"DownloadClientNzbgetSettingsAddPausedHelpText": "Esta opción requiere al menos NzbGet versión 16.0",
"DownloadClientQbittorrentSettingsSequentialOrderHelpText": "Descarga en orden secuencial (qBittorrent 4.1.0+)",
"DownloadClientRTorrentSettingsUrlPathHelpText": "Ruta al endpoint de XMLRPC, ver {url}. Esto es usualmente RPC2 o [ruta a ruTorrent]{url2} cuando se usa ruTorrent.",
"DownloadClientSettingsDestinationHelpText": "Especifica manualmente el destino de descarga, dejar en blanco para usar el predeterminado",
"DownloadClientSettingsInitialState": "Estado inicial",
"IndexerBeyondHDSettingsRefundOnly": "Solo devueltos",
"IndexerBeyondHDSettingsRefundOnlyHelpText": "Buscar solo devueltos",
"IndexerBeyondHDSettingsRewindOnly": "Solo rebobinados",
"IndexerBeyondHDSettingsSearchTypesHelpText": "Selecciona los tipos de lanzamientos en los que estás interesado. Si no se selecciona ninguno, se usarán todas las opciones.",
"IndexerGazelleGamesSettingsApiKeyHelpText": "Clave API del sitio (encontrada en Opciones => Opciones de acceso)",
"IndexerSettingsGrabLimit": "Límite de captura",
"IndexerSettingsQueryLimitHelpText": "El número de peticiones máximas especificadas por la unidad respectiva que {appName} permitirá al sitio",
"IndexerSettingsSeedTime": "Tiempo de sembrado",
"IndexerSettingsCookieHelpText": "Cookie del sitio",
"IndexerSettingsFreeleechOnly": "Solo freeleech",
"IndexerSettingsVipExpiration": "Expiración del VIP",
"XmlRpcPath": "Ruta RPC de XML"
}

View File

@@ -1,5 +1,5 @@
{
"IndexerProxyStatusCheckSingleClientMessage": "Välityspalvelimet eivät ole käytettävissä virheiden vuoksi: {0}",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Välityspalvelimet eivät ole käytettävissä virheiden vuoksi: {indexerProxyNames}",
"Logging": "Lokikirjaus",
"LogLevel": "Lokikirjauksen laajuus",
"MovieIndexScrollTop": "Elokuvakirjasto: vieritä ylös",
@@ -51,15 +51,15 @@
"SettingsLongDateFormat": "Pitkän päiväyksen esitys",
"SettingsShortDateFormat": "Lyhyen päiväyksen esitys",
"UnselectAll": "Tyhjennä valinnat",
"UpdateCheckStartupTranslocationMessage": "Päivitystä ei voida asentaa, koska käynnistyskansio \"{0}\" sijaitsee \"App Translocation\" -kansiossa.",
"UpdateCheckUINotWritableMessage": "Päivityksen asennus ei onnistu, koska käyttäjällä \"{1}\" ei ole kirjoitusoikeutta käyttöliittymäkansioon \"{0}\".",
"UpdateStartupTranslocationHealthCheckMessage": "Päivitystä ei voida asentaa, koska käynnistyskansio \"{startupFolder}\" sijaitsee \"App Translocation\" -kansiossa.",
"UpdateUiNotWritableHealthCheckMessage": "Päivityksen asennus ei onnistu, koska käyttäjällä \"{userName}\" ei ole kirjoitusoikeutta käyttöliittymäkansioon \"{uiFolder}\".",
"UpdateMechanismHelpText": "Käytä {appName}in sisäänrakennettua päivitystoimintoa tai komentosarjaa.",
"Enable": "Käytä",
"UI": "Käyttöliittymä",
"Usenet": "Usenet",
"BackupNow": "Varmuuskopioi nyt",
"NoBackupsAreAvailable": "Varmuuskopioita ei ole käytettävissä",
"UpdateCheckStartupNotWritableMessage": "Päivitystä ei voida asentaa, koska käyttäjällä \"{1}\" ei ole kirjoitusoikeutta käynnistyskansioon \"{0}\".",
"UpdateStartupNotWritableHealthCheckMessage": "Päivitystä ei voida asentaa, koska käyttäjällä \"{userName}\" ei ole kirjoitusoikeutta käynnistyskansioon \"{startupFolder}\".",
"Updates": "Päivitykset",
"UpdateScriptPathHelpText": "Polku komentosarjaan, joka käsittelee puretun päivitystiedoston ja hoitaa asennuksen loppuosuuden.",
"Uptime": "Käyttöaika",
@@ -93,9 +93,9 @@
"Presets": "Esiasetukset",
"Priority": "Painotus",
"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.",
"ProxyBadRequestHealthCheckMessage": "Välityspalvelintesti epäonnistui. Tilakoodi: {statusCode}.",
"ProxyFailedToTestHealthCheckMessage": "Välityspalvelintesti epäonnistui: {url}",
"ProxyResolveIpHealthCheckMessage": "Määritetyn välityspalvelimen \"{0}\" IP-osoitteen selvitys epäonnistui.",
"ProxyPasswordHelpText": "Käyttäjätunnus ja salasana tulee täyttää vain tarvittaessa. Mikäli näitä ei ole, tulee kentät jättää tyhjiksi.",
"ProxyType": "Välityspalvelimen tyyppi",
"ProxyUsernameHelpText": "Käyttäjätunnus ja salasana tulee täyttää vain tarvittaessa. Mikäli näitä ei ole, tulee kentät jättää tyhjiksi.",
@@ -154,7 +154,7 @@
"Disabled": "Ei käytössä",
"DownloadClients": "Lataustyökalut",
"DownloadClientSettings": "Lataustyökalujen asetukset",
"DownloadClientStatusCheckAllClientMessage": "Lataustyökaluja ei ole ongelmien vuoksi käytettävissä",
"DownloadClientStatusAllClientHealthCheckMessage": "Lataustyökaluja ei ole ongelmien vuoksi käytettävissä",
"Mode": "Tila",
"MoreInfo": "Lisätietoja",
"SelectAll": "Valitse kaikki",
@@ -247,7 +247,7 @@
"DeleteBackup": "Poista varmuuskopio",
"DeleteBackupMessageText": "Haluatko varmasti poistaa varmuuskopion \"{name}\"?",
"DeleteDownloadClient": "Poista lataustyökalu",
"DownloadClientStatusCheckSingleClientMessage": "Lataustyökaluja ei ole ongelmien vuoksi käytettävissä: {0}",
"DownloadClientStatusSingleClientHealthCheckMessage": "Lataustyökaluja ei ole ongelmien vuoksi käytettävissä: {downloadClientNames}",
"EditIndexer": "Muokkaa tietolähdettä",
"EnableAutomaticSearch": "Käytä automaattihakua",
"EnableInteractiveSearch": "Käytä manuaalihakuun",
@@ -275,12 +275,12 @@
"IncludeHealthWarningsHelpText": "Sisällytä kuntovaroitukset",
"Indexer": "Tietolähde",
"IndexerFlags": "Tietolähteen liput",
"IndexerLongTermStatusCheckAllClientMessage": "Mikään tietolähde ei ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi.",
"IndexerLongTermStatusCheckSingleClientMessage": "Tietolähteet eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {0}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Mikään tietolähde ei ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi.",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Tietolähteet eivät ole käytettävissä yli 6 tuntia kestäneiden virheiden vuoksi: {indexerNames}",
"IndexerPriority": "Tietolähteiden painotus",
"IndexerProxyStatusCheckAllClientMessage": "Välityspalvelimet eivät ole käytettävissä virheiden vuoksi",
"IndexerStatusCheckAllClientMessage": "Tietolähteet eivät ole käytettävissä virheiden vuoksi",
"IndexerStatusCheckSingleClientMessage": "Tietolähteet eivät ole käytettävissä virheiden vuoksi: {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Välityspalvelimet eivät ole käytettävissä virheiden vuoksi",
"IndexerStatusAllUnavailableHealthCheckMessage": "Tietolähteet eivät ole käytettävissä virheiden vuoksi",
"IndexerStatusUnavailableHealthCheckMessage": "Tietolähteet eivät ole käytettävissä virheiden vuoksi: {indexerNames}",
"NoChange": "Ei muutosta",
"NoLogFiles": "Lokitiedostoja ei ole",
"SSLCertPasswordHelpText": "PFX-tiedoston salasana",
@@ -317,7 +317,7 @@
"IndexerObsoleteCheckMessage": "Tietolähteet ovat poistuneet tai ne ovat muuttuneet: {0}. Poista ja/tai lisää ne {appName}iin uudelleen.",
"IndexerProxy": "Tiedonhaun välityspalvelin",
"IndexerSettingsSummary": "Määritä useita globaaleita tietolähdeasetuksia, kuten välityspalvelimia.",
"IndexerVipCheckExpiringClientMessage": "Tietolähteen VIP-edut erääntyvät pian: {0}",
"IndexerVipExpiringHealthCheckMessage": "Tietolähteen VIP-edut erääntyvät pian: {indexerNames}",
"ProwlarrSupportsAnyIndexer": "{appName} tukee Newznab- ja Torznab-yhteensopivien tietolähteiden ohella myös useita muita lähteitä vaihtoehdoilla \"Yleinen Newznab\" (Usenetille) ja 'Yleinen Torznab' (torrenteille).",
"SettingsIndexerLogging": "Tehostettu tietolähteiden valvonta",
"AddIndexerProxy": "Lisää tiedonhaun välityspalvelin",
@@ -330,7 +330,7 @@
"IndexerRss": "Tietolähteen RSS",
"SearchIndexers": "Etsi tietolähteistä",
"AddRemoveOnly": "Ainoastaan lisää/poista",
"IndexerVipCheckExpiredClientMessage": "Tietolähteen VIP-edut ovat erääntyneet: {0}",
"IndexerVipExpiredHealthCheckMessage": "Tietolähteen VIP-edut ovat erääntyneet: {indexerNames}",
"MaintenanceRelease": "Huoltojulkaisu: korjauksia ja muita parannuksia. Lue lisää Githubin muutoshistoriasta.",
"Query": "Kysely",
"Redirect": "Uudelleenohjaus",
@@ -480,7 +480,7 @@
"Artist": "Esittäjä",
"Author": "Kirjailija",
"Book": "Kirja",
"UpdateAvailable": "Uusi päivitys on saatavilla",
"UpdateAvailableHealthCheckMessage": "Uusi päivitys on saatavilla",
"Episode": "Jakso",
"Label": "Nimi",
"Theme": "Teema",
@@ -492,7 +492,7 @@
"minutes": "minuuttia",
"AddConnection": "Lisää yhteys",
"NotificationStatusAllClientHealthCheckMessage": "Mikään ilmoituspavelu ei ole ongelmien vuoksi käytettävissä.",
"NotificationStatusSingleClientHealthCheckMessage": "Ilmoitukset eivät ole ongelmien vuoksi käytettävissä: {0}",
"NotificationStatusSingleClientHealthCheckMessage": "Ilmoitukset eivät ole ongelmien vuoksi käytettävissä: {notificationNames}",
"AuthBasic": "Perus (ponnahdusikkuna)",
"AuthForm": "Lomake (kirjautumissivu)",
"DisabledForLocalAddresses": "Ei käytössä paikallisille osoitteille",
@@ -511,7 +511,7 @@
"NoDownloadClientsFound": "Lataustyökaluja ei löytynyt",
"CountDownloadClientsSelected": "{count} lataustyökalu(a) on valittu",
"EditSelectedDownloadClients": "Muokkaa valittuja lataustyökaluja",
"IndexerDownloadClientHealthCheckMessage": "Tietolähteet virheellisillä lataustyökaluilla: {0}.",
"IndexerDownloadClientHealthCheckMessage": "Tietolähteet virheellisillä lataustyökaluilla: {indexerNames}.",
"AddIndexerProxyImplementation": "Lisää tiedonhaun välityspalvelin - {implementationName}",
"EditIndexerProxyImplementation": "Muokkaa tiedonhaun välityspalvelinta - {implementationName}",
"EditDownloadClientImplementation": "Muokataan lataustyökalua - {implementationName}",
@@ -564,7 +564,7 @@
"SearchAllIndexers": "Etsi kaikista tietolähteistä",
"SeedRatioHelpText": "Jakosuhde, joka torrentin tulee saavuttaa ennen sen pysäytystä. Käytä sovelluksen oletusta jättämällä tyhjäksi.",
"TorznabUrl": "Torznab URL",
"ApiKeyValidationHealthCheckMessage": "Muuta rajapinnan (API) avain ainakin {0} merkin pituiseksi. Voit tehdä tämän asetuksista tai muokkaamalla asetustiedostoa.",
"ApiKeyValidationHealthCheckMessage": "Muuta rajapinnan (API) avain ainakin {length} merkin pituiseksi. Voit tehdä tämän asetuksista tai muokkaamalla asetustiedostoa.",
"OnHealthRestored": "Terveystilan vakautuessa",
"OnHealthRestoredHelpText": "Terveystilan vakautuessa",
"TotalHostQueries": "Isännän kyselyiden kokonaismäärä",
@@ -608,5 +608,77 @@
"NotificationsEmailSettingsUseEncryptionHelpText": "Määrittää suositaanko salausta, jos se on määritetty palvelimelle, käytetäänkö aina SSL- (vain portti 465) tai StartTLS-salausta (kaikki muut portit), voi käytetäänkö salausta lainkaan.",
"ManageClients": "Hallitse työkaluja",
"NoApplicationsFound": "Sovelluksia ei löytynyt",
"DownloadClientAriaSettingsDirectoryHelpText": "Valinnainen latuasten tallennussijainti. Käytä Aria2-oletusta jättämällä tyhjäksi."
"DownloadClientAriaSettingsDirectoryHelpText": "Valinnainen latuasten tallennussijainti. Käytä Aria2-oletusta jättämällä tyhjäksi.",
"UrlBaseHelpText": "Lisää {appName}in URL-osoitteeseen jälkiliitteen, esim. \"http://[osoite]:[portti]/[URL-perusta]\". Oletusarvo on tyhjä.",
"Donate": "Lahjoita",
"DownloadClientFloodSettingsAdditionalTagsHelpText": "Lisää median ominaisuuksia tunnisteina. Vihjeet ovat esimerkkejä.",
"DownloadClientRTorrentSettingsDirectoryHelpText": "Valinnainen latuasten tallennussijainti. Käytä Aria2-oletusta jättämällä tyhjäksi.",
"DownloadClientSettingsUseSslHelpText": "Muodosta {clientName} -yhteys käyttäen salattua yhteyttä.",
"DownloadClientTransmissionSettingsDirectoryHelpText": "Vaihtoehtoinen latauskansio. Käytä Transmissionin oletusta jättämällä tyhjäksi.",
"DownloadClientTransmissionSettingsUrlBaseHelpText": "Lisää etuliite lataustyökalun {clientName} RPC-URL-osoitteeseen. Esimerkiksi {url}. Oletus on \"{defaultUrl}\".",
"IndexerSettingsAppsMinimumSeedersHelpText": "Sovellusten edellyttämä tietolähteestä kaapattavien kohteiden jakajien (seed) vähimmäismäärä. Jos tyhjä, käytetään synkronointiprofiilin oletusta.",
"Menu": "Valikko",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashes": "Hylkää estetyt torrent-hajautusarvot kaapattaessa",
"IndexerBeyondHDSettingsSearchTypes": "Mitä etsitään",
"IndexerSettingsSeedRatio": "Jakosuhde",
"IndexerSettingsSeedTime": "Jakoaika",
"IndexerSettingsSeedTimeHelpText": "Aika, joka torrentia tulee jakaa ennen sen pysäytystä. Käytä lataustyökalun oletusta jättämällä tyhjäksi.",
"IndexerSettingsVipExpiration": "VIP-erääntyy",
"Destination": "Kohde",
"Directory": "Kansio",
"DownloadClientFloodSettingsTagsHelpText": "Latauksen alkuperäiset tunnisteet. Jotta se voidaa tunnistaa, on latauksella oltava sen alkuperäiset tunnisteet. Tämä välttää ristiriidat muiden latausten kanssa.",
"DownloadClientFreeboxSettingsApiUrl": "Rajapinnan URL-osoite",
"DownloadClientFreeboxSettingsAppTokenHelpText": "Freebox-rajapinnan käyttöoikeutta määritettäessä saatu app_token-tietue.",
"DownloadClientFreeboxSettingsHostHelpText": "Freeboxin isäntänimi tai IP-osoite. Oletus on \"{url}\" (toimii vain samassa verkossa).",
"DownloadClientPneumaticSettingsStrmFolder": "Strm-kansio",
"DownloadClientQbittorrentSettingsInitialStateHelpText": "Tila, jossa torrentit lisätään qBittorrentiin. Huomioi, että pakotetut torrentit eivät noudata nopeusrajoituksia.",
"DownloadClientSettingsAddPaused": "Lisää pysäytettynä",
"DownloadClientSettingsDestinationHelpText": "Määrittää manuaalisen tallennuskohteen. Käytä oletusta jättämällä tyhjäksi.",
"DownloadClientSettingsInitialState": "Virheellinen tila",
"DownloadClientSettingsInitialStateHelpText": "Lataustyökaluun {clientName} lisättyjen torrentien aloitustila.",
"IndexerHDBitsSettingsCodecs": "Koodekit",
"IndexerHDBitsSettingsCodecsHelpText": "Jos ei määritetty, käytetään kaikkia vaihtoehtoja.",
"IndexerHDBitsSettingsMediums": "Mediatyypit",
"IndexerHDBitsSettingsMediumsHelpText": "Jos ei määritetty, käytetään kaikkia vaihtoehtoja.",
"IndexerHDBitsSettingsOriginsHelpText": "Jos ei määritetty, käytetään kaikkia vaihtoehtoja.",
"IndexerSettingsAdditionalParameters": "Muut parametrit",
"IndexerSettingsApiPath": "API:n polku",
"IndexerSettingsApiPathHelpText": "Polku API:in (yleensä {url}).",
"IndexerSettingsCookie": "Eväste",
"IndexerSettingsPackSeedTime": "Koosteen jakoaika",
"IndexerSettingsPackSeedTimeIndexerHelpText": "Aika, joka koostepaketin (kuten sarjan tuotantokauden tai esittäjän diskografian) sisältävää torrentia tulee jakaa. Käytä sovelluksen oletusta jättämällä tyhjäksi.",
"IndexerSettingsSeedRatioHelpText": "Suhde, joka torrentin tulee saavuttaa ennen sen pysäytystä. Käytä lataustyökalun oletusta jättämällä tyhjäksi. Suhteen tulisi olla ainakin 1.0 ja noudattaa tietolähteen sääntöjä.",
"SecretToken": "Salainen tunniste",
"TorrentBlackholeSaveMagnetFiles": "Tallenna magnet-tiedostot",
"UseSsl": "Käytä SSL-salausta",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText": "Jos torrent on estetty hajautusarvon perusteella sitä ei välttämättä hylätä oikein etsittäessä joiltakin tietolähteiltä RSS-syötteen tai haun välityksellä. Tämä mahdollistaa tällaisten torrentien hylkäämisen kaappauksen jälkeen, mutta ennen välitystä lataustyökalulle.",
"BlackholeFolderHelpText": "Kansio, jonne {appName} tallentaa {extension}-tiedoston.",
"DownloadClientDelugeSettingsUrlBaseHelpText": "Lisää etuliitteen Delugen JSON-URL-osoitteeseen (ks. {url}).",
"DownloadClientFloodSettingsAdditionalTags": "Lisätunnisteet",
"DownloadClientPneumaticSettingsStrmFolderHelpText": "Tämän kansion .strm-tiedostot tuodaan droonilla.",
"DownloadClientQbittorrentSettingsSequentialOrderHelpText": "Lataa tiedostot järjestyksessä (qBittorrent 4.1.0+).",
"UsenetBlackholeNzbFolder": "NZB-kansio",
"XmlRpcPath": "XML RPC -sijainti",
"DownloadClientSettingsUrlBaseHelpText": "Lisää etuliite lataustuökalun {clientName} URL-osoitteeseen, kuten {url}.",
"DownloadClientFloodSettingsUrlBaseHelpText": "Lisää etuliitteen Flood-rajapintaan (esim. {url}).",
"DownloadClientDownloadStationSettingsDirectoryHelpText": "Valinnainen jaettu kansio latauksille. Download Stationin oletussijaintia jättämällä tyhjäksi.",
"DownloadClientFreeboxSettingsApiUrlHelpText": "Määritä Freebox-rajapinnan perus-URL rajapinnan versiolla. Esimerkiksi \"{url}\". Oletus on \"{defaultApiUrl}\".",
"DownloadClientQbittorrentSettingsFirstAndLastFirst": "Ensimmäinen ja viimeinen ensin",
"DownloadClientFreeboxSettingsAppId": "Sovellustunniste",
"DownloadClientFreeboxSettingsPortHelpText": "Freebox-liittymän portti. Oletus on \"{port}\".",
"DownloadClientPneumaticSettingsNzbFolder": "NZB-kansio",
"DownloadClientQbittorrentSettingsSequentialOrder": "Peräkkäinen järjestys",
"CustomFilter": "Omat suodattimet",
"DownloadClientFreeboxSettingsAppIdHelpText": "Freebox-rajapinnan käyttöoikeutta määritettäessä käytettävä App ID -sovellustunniste.",
"DownloadClientFreeboxSettingsAppToken": "Sovellustietue",
"DownloadClientNzbgetSettingsAddPausedHelpText": "Tämä vaatii vähintään NzbGet-version 16.0.",
"DownloadClientPneumaticSettingsNzbFolderHelpText": "Tämän kansion on oltava tavoitettavissa XBMC:stä.",
"DownloadClientQbittorrentSettingsFirstAndLastFirstHelpText": "Aloita lataamalla ensimmäinen ja viimeinen osa (qBittorrent 4.1.0+).",
"DownloadClientQbittorrentSettingsUseSslHelpText": "Käytä suojattua yhteyttä. Katso qBittorentin asetusten \"Selainkäyttö\"-osion \"Käytä HTTPS:ää HTTP:n sijaan\" -asetus.",
"DownloadClientRTorrentSettingsAddStopped": "Lisää pysäytettynä",
"DownloadClientRTorrentSettingsUrlPath": "URL-sijainti",
"TorrentBlackholeSaveMagnetFilesHelpText": "Tallenna magnet-linkki, jos .torrent-tiedostoa ei ole käytettävissä (hyödyllinen vain lataustyökalun tukiessa tiedostoon tallennettuja magnet-linkkejä).",
"TorrentBlackholeTorrentFolder": "Torrent-kansio",
"TorrentBlackholeSaveMagnetFilesExtension": "Tallennettujen magnet-tiedostojen pääte",
"TorrentBlackholeSaveMagnetFilesExtensionHelpText": "Magnet-linkeille käytettävä tiedostopääte. Oletus on \".magnet\"."
}

View File

@@ -1,5 +1,5 @@
{
"IndexerStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs",
"IndexerStatusAllUnavailableHealthCheckMessage": "Tous les indexeurs sont indisponibles en raison d'échecs",
"Indexers": "Indexeurs",
"Host": "Hôte",
"History": "Historique",
@@ -11,7 +11,7 @@
"Files": "Fichiers",
"Events": "Événements",
"Edit": "Modifier",
"DownloadClientStatusCheckAllClientMessage": "Aucun client de téléchargement n'est disponible en raison d'échecs",
"DownloadClientStatusAllClientHealthCheckMessage": "Aucun client de téléchargement n'est disponible en raison d'échecs",
"DownloadClients": "Clients de télécharg.",
"Dates": "Dates",
"Date": "Date",
@@ -25,14 +25,14 @@
"AppDataLocationHealthCheckMessage": "La mise à jour ne sera pas possible afin empêcher la suppression de AppData lors de la mise à jour",
"Analytics": "Statistiques",
"All": "Tout",
"About": "Tagalog",
"IndexerStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison d'échecs : {0}",
"DownloadClientStatusCheckSingleClientMessage": "Clients de Téléchargement indisponibles en raison d'échecs: {0}",
"About": "À propos",
"IndexerStatusUnavailableHealthCheckMessage": "Indexeurs indisponibles en raison d'échecs : {indexerNames}",
"DownloadClientStatusSingleClientHealthCheckMessage": "Clients de Téléchargement indisponibles en raison d'échecs: {downloadClientNames}",
"SetTags": "Définir des é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}'.",
"UpdateUiNotWritableHealthCheckMessage": "Impossible d'installer la mise à jour car le dossier d'interface utilisateur '{uiFolder}' n'est pas accessible en écriture par l'utilisateur '{userName}'.",
"UpdateStartupTranslocationHealthCheckMessage": "Impossible d'installer la mise à jour car le dossier de démarrage '{startupFolder}' se trouve dans un dossier App Translocation.",
"UpdateStartupNotWritableHealthCheckMessage": "Impossible d'installer la mise à jour car le dossier de démarrage '{startupFolder}' n'est pas accessible en écriture par l'utilisateur '{userName}'.",
"UnselectAll": "Tout désélectionner",
"UISettingsSummary": "Date, langue, et perceptions des couleurs",
"TagsSettingsSummary": "Voir toutes les étiquettes et comment elles sont utilisées. Les étiquettes inutilisées peuvent être supprimées",
@@ -51,9 +51,9 @@
"ReleaseBranchCheckOfficialBranchMessage": "La branche {0} n'est pas une branche de version {appName} valide, vous ne recevrez pas de mises à jour",
"Refresh": "Rafraîchir",
"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. Code d'état : {0}",
"ProxyResolveIpHealthCheckMessage": "Impossible de résoudre l'adresse IP de l'hôte proxy configuré {proxyHostName}",
"ProxyFailedToTestHealthCheckMessage": "Échec du test du proxy : {url}",
"ProxyBadRequestHealthCheckMessage": "Échec du test du proxy. Code d'état : {statusCode}",
"Proxy": "Proxy",
"Protocol": "Protocole",
"Options": "Options",
@@ -284,8 +284,8 @@
"OnHealthIssueHelpText": "Sur un problème de santé",
"AcceptConfirmationModal": "Accepter les modalités d'utilisation",
"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",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexeurs indisponibles en raison de pannes pendant plus de 6 heures : {indexerNames}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Tous les indexeurs sont indisponibles en raison d'échecs de plus de 6 heures",
"Yesterday": "Hier",
"Tomorrow": "Demain",
"Today": "Aujourd'hui",
@@ -368,13 +368,13 @@
"AppSettingsSummary": "Applications et paramètres pour configurer comment {appName} interagit avec vos programmes PVR",
"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}",
"IndexerVipExpiredHealthCheckMessage": "Les avantages VIP de l'indexeur ont expiré : {indexerNames}",
"IndexerProxy": "Proxy d'indexation",
"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}",
"IndexerVipCheckExpiringClientMessage": "Les avantages VIP de l'indexeur arrivent bientôt à expiration : {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Tous les proxys sont indisponibles en raison d'échecs",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Proxys indisponibles en raison d'échecs : {indexerProxyNames}",
"IndexerVipExpiringHealthCheckMessage": "Les avantages VIP de l'indexeur arrivent bientôt à expiration : {indexerNames}",
"NoLinks": "Aucun liens",
"Notification": "Notification",
"UnableToAddANewIndexerProxyPleaseTryAgain": "Impossible d'ajouter un nouveau proxy d'indexation, veuillez réessayer.",
@@ -493,7 +493,7 @@
"Track": "Piste",
"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",
"ApiKeyValidationHealthCheckMessage": "Veuillez mettre à jour votre clé API pour qu'elle contienne au moins {length} caractères. Vous pouvez le faire via les paramètres ou le fichier de configuration",
"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 : ajoute les étiquettes à la liste de étiquettes existantes",
@@ -509,7 +509,7 @@
"DeleteSelectedDownloadClients": "Supprimer le(s) client(s) de téléchargement",
"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",
"UpdateAvailableHealthCheckMessage": "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",
@@ -537,7 +537,7 @@
"AddIndexerImplementation": "Ajouter un indexeur - {implementationName}",
"EditConnectionImplementation": "Modifier la connexion - {implementationName}",
"NotificationStatusAllClientHealthCheckMessage": "Toutes les notifications ne sont pas disponibles en raison d'échecs",
"NotificationStatusSingleClientHealthCheckMessage": "Notifications indisponibles en raison d'échecs : {0}",
"NotificationStatusSingleClientHealthCheckMessage": "Notifications indisponibles en raison d'échecs : {notificationNames}",
"EditApplicationImplementation": "Ajouter une condition - {implementationName}",
"EditIndexerImplementation": "Modifier l'indexeur - {implementationName}",
"EditIndexerProxyImplementation": "Modifier un proxy d'indexeur - {implementationName}",
@@ -587,7 +587,7 @@
"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].",
"IndexerDownloadClientHealthCheckMessage": "Indexeurs avec des clients de téléchargement invalides : {indexerNames}.",
"AuthenticationMethod": "Méthode d'authentification",
"AuthenticationMethodHelpTextWarning": "Veuillez choisir une méthode d'authentification valide",
"ActiveIndexers": "Indexeurs actifs",
@@ -733,11 +733,19 @@
"DownloadClientFreeboxSettingsAppIdHelpText": "L'ID de l'application donné lors de la création de l'accès à l'API Freebox (c'est-à-dire 'app_id')",
"DownloadClientQbittorrentSettingsFirstAndLastFirstHelpText": "Télécharger d'abord le premier et le dernier morceau (qBittorrent 4.1.0+)",
"DownloadClientQbittorrentSettingsUseSslHelpText": "Utilisez une connexion sécurisée. Voir Options -> UI Web -> 'Utiliser HTTPS au lieu de HTTP' dans qBittorrent.",
"IndexerSettingsRejectBlocklistedTorrentHashesHelpText": "Si un torrent est bloqué par le hachage, il peut ne pas être correctement rejeté pendant le RSS/recherche pour certains indexeurs. L'activation de cette fonction permet de le rejeter après que le torrent a été saisi, mais avant qu'il ne soit envoyé au client.",
"TorrentBlackholeSaveMagnetFilesExtensionHelpText": "Extension à utiliser pour les liens magnétiques, la valeur par défaut est '.magnet'",
"TorrentBlackholeTorrentFolder": "Dossier Torrent",
"UseSsl": "Utiliser SSL",
"IndexerSettingsRejectBlocklistedTorrentHashes": "Rejeter les hachages de torrents bloqués lors de la saisie",
"DownloadClientRTorrentSettingsDirectoryHelpText": "Emplacement facultatif dans lequel placer les téléchargements. Laisser vide pour utiliser l'emplacement par défaut de rTorrent",
"DownloadClientSettingsDefaultCategorySubFolderHelpText": "Catégorie de secours par défaut si aucune catégorie mappée n'existe pour une version. L'ajout d'une catégorie spécifique à {appName} permet d'éviter les conflits avec des téléchargements sans rapport avec {appName}. L'utilisation d'une catégorie est facultative, mais fortement recommandée. Crée un sous-répertoire [catégorie] dans le répertoire de sortie."
"DownloadClientSettingsDefaultCategorySubFolderHelpText": "Catégorie de secours par défaut si aucune catégorie mappée n'existe pour une version. L'ajout d'une catégorie spécifique à {appName} permet d'éviter les conflits avec des téléchargements sans rapport avec {appName}. L'utilisation d'une catégorie est facultative, mais fortement recommandée. Crée un sous-répertoire [catégorie] dans le répertoire de sortie.",
"ProwlarrDownloadClientsInAppOnlyAlert": "Les clients de téléchargement servent uniquement à effectuer des recherches dans l'application {appName} et ne se synchronisent pas avec les applications. Il n'est pas prévu d'ajouter une telle fonctionnalité.",
"Donate": "Donation",
"Menu": "Menu",
"Mixed": "Mixte",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashes": "Synchroniser le rejet des hachages torrent sur liste bloquée lors de la saisie",
"ClickToChangeQueryOptions": "Cliquez pour modifier les options de la requête",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText": "Si un torrent est bloqué par le hachage, il peut ne pas être correctement rejeté pendant le RSS/recherche pour certains indexeurs. L'activation de cette fonction permet de le rejeter après que le torrent a été saisi, mais avant qu'il ne soit envoyé au client.",
"ProwlarrDownloadClientsAlert": "Si vous avez l'intention d'effectuer des recherches directement dans {appName}, vous devez ajouter les clients de téléchargement. Sinon, vous n'avez pas besoin de les ajouter ici. Pour les recherches à partir de vos applications, les clients de téléchargement qui y sont configurés sont utilisés à la place.",
"IndexerMTeamTpSettingsApiKeyHelpText": "Clé API du site (trouvée dans le panneau de configuration utilisateur => Sécurité => Laboratoire)",
"IndexerMTeamTpSettingsFreeleechOnlyHelpText": "Rechercher uniquement les versions freeleech"
}

View File

@@ -20,7 +20,7 @@
"NoLinks": "אין קישורים",
"PendingChangesDiscardChanges": "מחק שינויים ועזוב",
"ProxyBypassFilterHelpText": "השתמש ב- ',' כמפריד וב- '*.' כתו כללי לתת-דומיינים",
"ProxyCheckBadRequestMessage": "נכשל בדיקת ה- proxy. קוד קוד: {0}",
"ProxyBadRequestHealthCheckMessage": "נכשל בדיקת ה- proxy. קוד קוד: {statusCode}",
"ReleaseStatus": "שחרור סטטוס",
"Reload": "לִטעוֹן מִחָדָשׁ",
"RemovedFromTaskQueue": "הוסר מתור המשימות",
@@ -39,8 +39,8 @@
"Added": "נוסף",
"Component": "רְכִיב",
"Info": "מידע",
"IndexerLongTermStatusCheckAllClientMessage": "כל האינדקסים אינם זמינים עקב כשלים במשך יותר מ -6 שעות",
"IndexerLongTermStatusCheckSingleClientMessage": "אינדקסים לא זמינים עקב כשלים במשך יותר משש שעות: {0}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "כל האינדקסים אינם זמינים עקב כשלים במשך יותר מ -6 שעות",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "אינדקסים לא זמינים עקב כשלים במשך יותר משש שעות: {indexerNames}",
"Manual": "מדריך ל",
"PageSize": "גודל עמוד",
"PageSizeHelpText": "מספר הפריטים להצגה בכל עמוד",
@@ -80,8 +80,8 @@
"Custom": "המותאם אישית",
"CustomFilters": "מסננים מותאמים אישית",
"Date": "תַאֲרִיך",
"DownloadClientStatusCheckAllClientMessage": "כל לקוחות ההורדה אינם זמינים עקב כשלים",
"DownloadClientStatusCheckSingleClientMessage": "הורדת לקוחות לא זמינה עקב כשלים: {0}",
"DownloadClientStatusAllClientHealthCheckMessage": "כל לקוחות ההורדה אינם זמינים עקב כשלים",
"DownloadClientStatusSingleClientHealthCheckMessage": "הורדת לקוחות לא זמינה עקב כשלים: {downloadClientNames}",
"Fixed": "תוקן",
"FocusSearchBox": "תיבת חיפוש פוקוס",
"Folder": "תיקיה",
@@ -141,7 +141,7 @@
"Time": "זְמַן",
"Title": "כותרת",
"UnableToLoadHistory": "לא ניתן לטעון את ההיסטוריה",
"UpdateCheckStartupNotWritableMessage": "לא ניתן להתקין את העדכון מכיוון שתיקיית ההפעלה '{0}' אינה ניתנת לכתיבה על ידי המשתמש '{1}'.",
"UpdateStartupNotWritableHealthCheckMessage": "לא ניתן להתקין את העדכון מכיוון שתיקיית ההפעלה '{startupFolder}' אינה ניתנת לכתיבה על ידי המשתמש '{userName}'.",
"AddDownloadClient": "הוסף לקוח הורדות",
"Filename": "שם קובץ",
"Files": "קבצים",
@@ -160,15 +160,15 @@
"Hostname": "שם מארח",
"IndexerPriority": "עדיפות אינדקס",
"IndexerPriorityHelpText": "עדיפות אינדקס מ -1 (הגבוה ביותר) ל -50 (הנמוך ביותר). ברירת מחדל: 25.",
"IndexerProxyStatusCheckAllClientMessage": "כל הרשימות אינן זמינות בגלל כשלים",
"IndexerProxyStatusCheckSingleClientMessage": "אינדקסים לא זמינים בגלל כשלים: {0}",
"IndexerStatusCheckAllClientMessage": "כל האינדקסים אינם זמינים עקב כשלים",
"IndexerStatusCheckSingleClientMessage": "אינדקסים לא זמינים בגלל כשלים: {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "כל הרשימות אינן זמינות בגלל כשלים",
"IndexerProxyStatusUnavailableHealthCheckMessage": "אינדקסים לא זמינים בגלל כשלים: {indexerProxyNames}",
"IndexerStatusAllUnavailableHealthCheckMessage": "כל האינדקסים אינם זמינים עקב כשלים",
"IndexerStatusUnavailableHealthCheckMessage": "אינדקסים לא זמינים בגלל כשלים: {indexerNames}",
"NoBackupsAreAvailable": "אין גיבויים",
"PackageVersion": "גרסת חבילה",
"Peers": "עמיתים",
"ProxyCheckFailedToTestMessage": "נכשל בדיקת ה- proxy: {0}",
"ProxyCheckResolveIpMessage": "פתרון כתובת ה- IP עבור מארח ה- Proxy המוגדר {0} נכשל",
"ProxyFailedToTestHealthCheckMessage": "נכשל בדיקת ה- proxy: {url}",
"ProxyResolveIpHealthCheckMessage": "פתרון כתובת ה- IP עבור מארח ה- Proxy המוגדר {proxyHostName} נכשל",
"ProxyPasswordHelpText": "עליך להזין שם משתמש וסיסמה רק אם נדרשים שם. השאר אותם ריקים אחרת.",
"ProxyUsernameHelpText": "עליך להזין שם משתמש וסיסמה רק אם נדרשים שם. השאר אותם ריקים אחרת.",
"Reddit": "רדיט",
@@ -197,8 +197,8 @@
"Tomorrow": "מָחָר",
"Torrent": "טורנטים",
"UnableToAddANewIndexerProxyPleaseTryAgain": "לא ניתן להוסיף אינדקס חדש, נסה שוב.",
"UpdateCheckStartupTranslocationMessage": "לא ניתן להתקין את העדכון מכיוון שתיקיית ההפעלה '{0}' נמצאת בתיקיית טרנסלוקציה של אפליקציות.",
"UpdateCheckUINotWritableMessage": "לא ניתן להתקין את העדכון מכיוון שתיקיית ממשק המשתמש '{0}' אינה ניתנת לכתיבה על ידי המשתמש '{1}'.",
"UpdateStartupTranslocationHealthCheckMessage": "לא ניתן להתקין את העדכון מכיוון שתיקיית ההפעלה '{startupFolder}' נמצאת בתיקיית טרנסלוקציה של אפליקציות.",
"UpdateUiNotWritableHealthCheckMessage": "לא ניתן להתקין את העדכון מכיוון שתיקיית ממשק המשתמש '{uiFolder}' אינה ניתנת לכתיבה על ידי המשתמש '{userName}'.",
"Updates": "עדכונים",
"UpdateScriptPathHelpText": "נתיב לסקריפט מותאם אישית שלוקח חבילת עדכון שחולצה ומטפל בשארית תהליך העדכון",
"Uptime": "זמן עבודה",
@@ -386,7 +386,7 @@
"DeleteSelectedDownloadClients": "מחק את לקוח ההורדות",
"DeleteSelectedIndexersMessageText": "האם אתה בטוח שברצונך למחוק את האינדקס '{0}'?",
"DownloadClientPriorityHelpText": "העדיפו עדיפות למספר לקוחות הורדה. Round-Robin משמש ללקוחות עם אותה עדיפות.",
"ApiKeyValidationHealthCheckMessage": "עדכן בבקשה את מפתח ה־API שלך כדי שיהיה באורך של לפחות {0} תווים. תוכל לעשות זאת בהגדרות או דרך קובץ הקונפיגורציה.",
"ApiKeyValidationHealthCheckMessage": "עדכן בבקשה את מפתח ה־API שלך כדי שיהיה באורך של לפחות {length} תווים. תוכל לעשות זאת בהגדרות או דרך קובץ הקונפיגורציה.",
"More": "יותר",
"Track": "זֵכֶר",
"ApplyTagsHelpTextHowToApplyApplications": "כיצד להחיל תגים על הסרטים שנבחרו",
@@ -401,7 +401,7 @@
"Album": "אלבום",
"Artist": "אמן",
"NotificationStatusAllClientHealthCheckMessage": "כל הרשימות אינן זמינות בגלל כשלים",
"NotificationStatusSingleClientHealthCheckMessage": "רשימות לא זמינות בגלל כשלים: {0}",
"NotificationStatusSingleClientHealthCheckMessage": "רשימות לא זמינות בגלל כשלים: {notificationNames}",
"ResetAPIKeyMessageText": "האם אתה בטוח שברצונך לאפס את מפתח ה- API שלך?",
"DisabledForLocalAddresses": "מושבת לכתובות מקומיות",
"Publisher": "מוציא לאור",

View File

@@ -54,7 +54,7 @@
"Authentication": "प्रमाणीकरण",
"ClientPriority": "ग्राहक प्राथमिकता",
"Connections": "सम्बन्ध",
"DownloadClientStatusCheckSingleClientMessage": "विफलताओं के कारण अनुपलब्ध ग्राहक डाउनलोड करें: {0}",
"DownloadClientStatusSingleClientHealthCheckMessage": "विफलताओं के कारण अनुपलब्ध ग्राहक डाउनलोड करें: {downloadClientNames}",
"NoChanges": "कोई बदलाव नहीं",
"Yesterday": "बिता कल",
"DeleteIndexerProxyMessageText": "क्या आप वाकई '{0}' टैग हटाना चाहते हैं?",
@@ -104,8 +104,8 @@
"DownloadClientSettings": "क्लाइंट सेटिंग्स डाउनलोड करें",
"EventType": "घटना प्रकार",
"Exception": "अपवाद",
"IndexerStatusCheckAllClientMessage": "विफलताओं के कारण सभी अनुक्रमणिका अनुपलब्ध हैं",
"IndexerStatusCheckSingleClientMessage": "अनुक्रमणिका विफलताओं के कारण अनुपलब्ध: {0}",
"IndexerStatusAllUnavailableHealthCheckMessage": "विफलताओं के कारण सभी अनुक्रमणिका अनुपलब्ध हैं",
"IndexerStatusUnavailableHealthCheckMessage": "अनुक्रमणिका विफलताओं के कारण अनुपलब्ध: {indexerNames}",
"Info": "जानकारी",
"Language": "भाषा: हिन्दी",
"UnableToAddANewDownloadClientPleaseTryAgain": "नया डाउनलोड क्लाइंट जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।",
@@ -133,9 +133,9 @@
"NoLinks": "कोई लिंक नहीं",
"BindAddress": "बाँध का पता",
"Branch": "डाली",
"ProxyCheckBadRequestMessage": "प्रॉक्सी का परीक्षण करने में विफल। स्थिति कोड: {0}",
"ProxyCheckFailedToTestMessage": "प्रॉक्सी का परीक्षण करने में विफल: {0}",
"ProxyCheckResolveIpMessage": "कॉन्फ़िगर प्रॉक्सी होस्ट {0} के लिए आईपी एड्रेस को हल करने में विफल",
"ProxyBadRequestHealthCheckMessage": "प्रॉक्सी का परीक्षण करने में विफल। स्थिति कोड: {statusCode}",
"ProxyFailedToTestHealthCheckMessage": "प्रॉक्सी का परीक्षण करने में विफल: {url}",
"ProxyResolveIpHealthCheckMessage": "कॉन्फ़िगर प्रॉक्सी होस्ट {proxyHostName} के लिए आईपी एड्रेस को हल करने में विफल",
"ProxyPasswordHelpText": "यदि आवश्यक हो तो आपको केवल एक उपयोगकर्ता नाम और पासवर्ड दर्ज करना होगा। उन्हें खाली छोड़ दें अन्यथा।",
"ProxyType": "प्रॉक्सी प्रकार",
"ProxyUsernameHelpText": "यदि आवश्यक हो तो आपको केवल एक उपयोगकर्ता नाम और पासवर्ड दर्ज करना होगा। उन्हें खाली छोड़ दें अन्यथा।",
@@ -170,7 +170,7 @@
"UnsavedChanges": "बिना बदलाव किए",
"UnselectAll": "सभी का चयन रद्द",
"UpdateAutomaticallyHelpText": "अपडेट को स्वचालित रूप से डाउनलोड और इंस्टॉल करें। आप अभी भी सिस्टम से अपडेट कर पाएंगे: अपडेट",
"UpdateCheckUINotWritableMessage": "अद्यतन स्थापित नहीं कर सकता क्योंकि UI फ़ोल्डर '{0}' उपयोगकर्ता '{1}' द्वारा लिखने योग्य नहीं है।",
"UpdateUiNotWritableHealthCheckMessage": "अद्यतन स्थापित नहीं कर सकता क्योंकि UI फ़ोल्डर '{uiFolder}' उपयोगकर्ता '{userName}' द्वारा लिखने योग्य नहीं है।",
"Uptime": "अपटाइम",
"URLBase": "URL बेस",
"YesCancel": "हाँ, रद्द करें",
@@ -234,7 +234,7 @@
"CloneProfile": "क्लोन प्रोफ़ाइल",
"Close": "बंद करे",
"CloseCurrentModal": "वर्तमान मोडल को बंद करें",
"DownloadClientStatusCheckAllClientMessage": "सभी डाउनलोड क्लाइंट विफलताओं के कारण अनुपलब्ध हैं",
"DownloadClientStatusAllClientHealthCheckMessage": "सभी डाउनलोड क्लाइंट विफलताओं के कारण अनुपलब्ध हैं",
"Edit": "संपादित करें",
"EnableAutomaticSearch": "स्वचालित खोज सक्षम करें",
"EnableAutomaticSearchHelpText": "यूआई के माध्यम से या रेडर द्वारा स्वचालित खोज किए जाने पर उपयोग किया जाएगा",
@@ -268,12 +268,12 @@
"Hostname": "होस्ट का नाम",
"IncludeHealthWarningsHelpText": "स्वास्थ्य चेतावनी शामिल करें",
"IndexerFlags": "इंडेक्स फ्लैग",
"IndexerLongTermStatusCheckAllClientMessage": "6 घंटे से अधिक समय तक विफलताओं के कारण सभी सूचकांक अनुपलब्ध हैं",
"IndexerLongTermStatusCheckSingleClientMessage": "6 घंटे से अधिक समय तक विफलताओं के कारण सूचकांक उपलब्ध नहीं: {0}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "6 घंटे से अधिक समय तक विफलताओं के कारण सभी सूचकांक अनुपलब्ध हैं",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "6 घंटे से अधिक समय तक विफलताओं के कारण सूचकांक उपलब्ध नहीं: {indexerNames}",
"IndexerPriority": "सूचकांक प्राथमिकता",
"IndexerPriorityHelpText": "इंडेक्सर प्राथमिकता 1 (उच्चतम) से 50 (सबसे कम)। डिफ़ॉल्ट: 25",
"IndexerProxyStatusCheckAllClientMessage": "सभी सूचियाँ विफल होने के कारण अनुपलब्ध हैं",
"IndexerProxyStatusCheckSingleClientMessage": "अनुक्रमणिका विफलताओं के कारण अनुपलब्ध: {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "सभी सूचियाँ विफल होने के कारण अनुपलब्ध हैं",
"IndexerProxyStatusUnavailableHealthCheckMessage": "अनुक्रमणिका विफलताओं के कारण अनुपलब्ध: {indexerProxyNames}",
"InteractiveSearch": "इंटरएक्टिव खोज",
"Interval": "मध्यान्तर",
"KeyboardShortcuts": "कुंजीपटल अल्प मार्ग",
@@ -297,8 +297,8 @@
"DownloadClientsLoadError": "डाउनलोड क्लाइंट लोड करने में असमर्थ",
"UnableToLoadGeneralSettings": "सामान्य सेटिंग्स लोड करने में असमर्थ",
"UnableToLoadNotifications": "सूचनाएं लोड करने में असमर्थ",
"UpdateCheckStartupNotWritableMessage": "अपडेट स्थापित नहीं किया जा सकता क्योंकि स्टार्टअप फ़ोल्डर '{0}' उपयोगकर्ता '{1}' द्वारा लिखने योग्य नहीं है।",
"UpdateCheckStartupTranslocationMessage": "अपडेट स्थापित नहीं किया जा सकता क्योंकि स्टार्टअप फ़ोल्डर '{0}' ऐप ट्रांसलेशन फ़ोल्डर में है।",
"UpdateStartupNotWritableHealthCheckMessage": "अपडेट स्थापित नहीं किया जा सकता क्योंकि स्टार्टअप फ़ोल्डर '{startupFolder}' उपयोगकर्ता '{userName}' द्वारा लिखने योग्य नहीं है।",
"UpdateStartupTranslocationHealthCheckMessage": "अपडेट स्थापित नहीं किया जा सकता क्योंकि स्टार्टअप फ़ोल्डर '{startupFolder}' ऐप ट्रांसलेशन फ़ोल्डर में है।",
"NoUpdatesAreAvailable": "कोई अद्यतन उपलब्ध नहीं हैं",
"OAuthPopupMessage": "आपके ब्राउज़र द्वारा पॉप-अप्स को ब्लॉक किया जा रहा है",
"OnHealthIssueHelpText": "स्वास्थ्य के मुद्दे पर",
@@ -347,10 +347,12 @@
"minutes": "मिनट",
"DeleteAppProfileMessageText": "क्या आप वाकई गुणवत्ता प्रोफ़ाइल {0} को हटाना चाहते हैं",
"NotificationStatusAllClientHealthCheckMessage": "सभी सूचियाँ विफल होने के कारण अनुपलब्ध हैं",
"NotificationStatusSingleClientHealthCheckMessage": "विफलताओं के कारण अनुपलब्ध सूची: {0}",
"NotificationStatusSingleClientHealthCheckMessage": "विफलताओं के कारण अनुपलब्ध सूची: {notificationNames}",
"AuthBasic": "बेसिक (ब्राउज़र पॉपअप)",
"AuthForm": "प्रपत्र (लॉग इन पेज)",
"DisabledForLocalAddresses": "स्थानीय पते के लिए अक्षम",
"None": "कोई नहीं",
"ResetAPIKeyMessageText": "क्या आप वाकई अपनी API कुंजी को रीसेट करना चाहते हैं?"
"ResetAPIKeyMessageText": "क्या आप वाकई अपनी API कुंजी को रीसेट करना चाहते हैं?",
"IndexerHDBitsSettingsMediums": "मध्यम",
"CustomFilter": "कस्टम फ़िल्टर"
}

View File

@@ -10,8 +10,8 @@
"Enable": "Aktiválás",
"EditIndexer": "Indexer Szerkesztése",
"Edit": "Szerkeszt",
"DownloadClientStatusCheckSingleClientMessage": "Letöltőkliens hiba miatt nem elérhető: {0}",
"DownloadClientStatusCheckAllClientMessage": "Az összes letöltőkliens elérhetetlen, hiba miatt",
"DownloadClientStatusSingleClientHealthCheckMessage": "Letöltőkliens hiba miatt nem elérhető: {downloadClientNames}",
"DownloadClientStatusAllClientHealthCheckMessage": "Az összes letöltőkliens elérhetetlen, hiba miatt",
"DownloadClientsSettingsSummary": "Letöltőkliens konfigurációja a {appName} felhasználói felület keresésbe történő integráláshoz",
"DownloadClientSettings": "Letöltőkliens Beállítások",
"DownloadClients": "Letöltő kliensek",
@@ -160,9 +160,9 @@
"ProxyUsernameHelpText": "Csak akkor kell megadnia egy felhasználónevet és jelszót, ha szükséges. Ellenkező esetben hagyja üresen.",
"ProxyType": "Proxy típus",
"ProxyPasswordHelpText": "Csak akkor kell megadnia egy felhasználónevet és jelszót, ha szükséges. Ellenkező esetben hagyja üresen.",
"ProxyCheckResolveIpMessage": "Nem sikerült megoldani a konfigurált proxykiszolgáló IP-címét {0}",
"ProxyCheckFailedToTestMessage": "Proxy tesztelése sikertelen: {0}",
"ProxyCheckBadRequestMessage": "Proxy tesztelése sikertelen. Állapotkód: {0}",
"ProxyResolveIpHealthCheckMessage": "Nem sikerült megoldani a konfigurált proxykiszolgáló IP-címét {proxyHostName}",
"ProxyFailedToTestHealthCheckMessage": "Proxy tesztelése sikertelen: {url}",
"ProxyBadRequestHealthCheckMessage": "Proxy tesztelése sikertelen. Állapotkód: {statusCode}",
"ProxyBypassFilterHelpText": "Használja a ',' jelet elválasztóként és a '*' jelet. helyettesítő karakterként az aldomainekhez",
"Proxy": "Proxy",
"Protocol": "Protokoll",
@@ -215,7 +215,7 @@
"Interval": "Intervallum",
"InteractiveSearch": "Interaktív Keresés",
"Info": "Infó",
"IndexerStatusCheckSingleClientMessage": "Indexerek elérhetetlenek a következő hiba miatt: {0}",
"IndexerStatusUnavailableHealthCheckMessage": "Indexerek elérhetetlenek a következő hiba miatt: {indexerNames}",
"Hostname": "Hosztnév",
"Host": "Hoszt",
"Grabbed": "Megragadta",
@@ -249,7 +249,7 @@
"TagCannotBeDeletedWhileInUse": "Használat közben nem törölhető",
"TableOptionsColumnsMessage": "Válasszd ki, mely oszlopok legyenek láthatóak, és milyen sorrendben jelenjenek meg",
"SystemTimeCheckMessage": "A rendszeridő több mint 1 napja nem frissült. Előfordulhat, hogy az ütemezett feladatok az idő kijavításáig nem futnak megfelelően",
"IndexerStatusCheckAllClientMessage": "Az összes indexer elérhetetlen hiba miatt",
"IndexerStatusAllUnavailableHealthCheckMessage": "Az összes indexer elérhetetlen hiba miatt",
"Indexers": "Indexerek",
"IndexerPriorityHelpText": "Indexelő prioritás 1-től (legmagasabb) 50-ig (legalacsonyabb). Alapértelmezés: 25.",
"IndexerPriority": "Indexer Prioritása",
@@ -271,9 +271,9 @@
"UpdateScriptPathHelpText": "Keresse meg az egyéni parancsfájl elérési útját, amely kibontott frissítési csomagot vesz fel, és kezeli a frissítési folyamat fennmaradó részét",
"Updates": "Frissítések",
"UpdateMechanismHelpText": "Használja a {appName} beépített frissítőjét vagy szkriptjét",
"UpdateCheckUINotWritableMessage": "Nem lehet telepíteni a frissítést, mert a(z) „{0}” felhasználói felület mappát nem írhatja a „{1}” felhasználó.",
"UpdateCheckStartupTranslocationMessage": "Nem lehet telepíteni a frissítést, mert a (z) „{0}” indítási mappa az Alkalmazások Transzlokációs mappájában található.",
"UpdateCheckStartupNotWritableMessage": "A frissítés nem telepíthető, mert a (z) „{0}” indítási mappát a „{1}” felhasználó nem írhatja.",
"UpdateUiNotWritableHealthCheckMessage": "Nem lehet telepíteni a frissítést, mert a(z) „{uiFolder}” felhasználói felület mappát nem írhatja a „{userName}” felhasználó.",
"UpdateStartupTranslocationHealthCheckMessage": "Nem lehet telepíteni a frissítést, mert a (z) „{startupFolder}” indítási mappa az Alkalmazások Transzlokációs mappájában található.",
"UpdateStartupNotWritableHealthCheckMessage": "A frissítés nem telepíthető, mert a (z) „{startupFolder}” indítási mappát a „{userName}” felhasználó nem írhatja.",
"UpdateAutomaticallyHelpText": "A frissítések automatikus letöltése és telepítése. A Rendszer: Frissítések alkalmazásból továbbra is telepíteni tudja",
"UnselectAll": "Minden kijelölés megszüntetése",
"UnsavedChanges": "Nem mentett változások",
@@ -284,8 +284,8 @@
"ShowSearch": "Keresés mutatása",
"SetTags": "Címkék beállítása",
"NotificationTriggers": "Értesítési triggerek",
"IndexerLongTermStatusCheckSingleClientMessage": "Az összes indexer elérhetetlen több mint 6 órája, meghibásodás miatt: {0}",
"IndexerLongTermStatusCheckAllClientMessage": "Az összes indexer elérhetetlen több mint 6 órája, meghibásodás miatt",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Az összes indexer elérhetetlen több mint 6 órája, meghibásodás miatt: {indexerNames}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Az összes indexer elérhetetlen több mint 6 órája, meghibásodás miatt",
"SettingsLogSql": "SQL naplózás",
"IndexerRss": "Indexer Rss",
"IndexerAuth": "Indexelő auth",
@@ -366,16 +366,16 @@
"DeleteIndexerProxy": "Indexer Proxy törlése",
"DeleteIndexerProxyMessageText": "Biztosan törlöd a(z) „{0}” proxyt?",
"IndexerProxies": "Indexer Proxy(k)",
"IndexerProxyStatusCheckAllClientMessage": "Az összes Proxy elérhetetlen, hiba miatt",
"IndexerProxyStatusCheckSingleClientMessage": "Proxyk elérhetetlenek az alábbi hibák miatt: {0}",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Az összes Proxy elérhetetlen, hiba miatt",
"IndexerProxyStatusUnavailableHealthCheckMessage": "Proxyk elérhetetlenek az alábbi hibák miatt: {indexerProxyNames}",
"IndexerTagsHelpText": "Címkék segítségével megadhatod az indexer proxykat amelyekkel az indexer szinkronizálva van, vagy egyszerűen az indexelők rendszerezéséhez.",
"UnableToLoadIndexerProxies": "Nem lehet betölteni az Indexer Proxyt",
"AddIndexerProxy": "Indexer Proxy hozzáadása",
"IndexerSettingsSummary": "Konfigurálja a különböző globális indexer beállításokat, beleértve a proxykat is.",
"Notifications": "Értesítések",
"UnableToAddANewIndexerProxyPleaseTryAgain": "Nem lehet új Indexer Proxyt hozzáadni, próbálja újra.",
"IndexerVipCheckExpiredClientMessage": "Az Indexer VIP előnyei lejártak: {0}",
"IndexerVipCheckExpiringClientMessage": "Az Indexer VIP előnyei hamarosan lejárnak: {0}",
"IndexerVipExpiredHealthCheckMessage": "Az Indexer VIP előnyei lejártak: {indexerNames}",
"IndexerVipExpiringHealthCheckMessage": "Az Indexer VIP előnyei hamarosan lejárnak: {indexerNames}",
"IndexerProxy": "Indexelő Proxy",
"NoLinks": "Nincsenek Linkek",
"Notification": "Értesítés",
@@ -476,12 +476,12 @@
"EditSelectedDownloadClients": "Kijelölt letöltési kliensek szerkesztése",
"Label": "Címke",
"SelectIndexers": "Indexelők keresése",
"ApiKeyValidationHealthCheckMessage": "Kérlek frissítsd az API kulcsot, ami legalább {0} karakter hosszú. Ezt megteheted a Beállításokban, vagy a config file-ban",
"ApiKeyValidationHealthCheckMessage": "Kérlek frissítsd az API kulcsot, ami legalább {length} karakter hosszú. Ezt megteheted a Beállításokban, vagy a config file-ban",
"Episode": "Epizód",
"Genre": "Műfajok",
"Theme": "Téma",
"Track": "Dal",
"UpdateAvailable": "Új frissítés elérhető",
"UpdateAvailableHealthCheckMessage": "Új frissítés elérhető",
"Year": "Év",
"Book": "Könyv",
"Season": "Évad",
@@ -496,7 +496,7 @@
"minutes": "percek",
"AddConnection": "Csatlakozás hozzáadása",
"NotificationStatusAllClientHealthCheckMessage": "Az összes értesítés nem érhető el hibák 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: {notificationNames}",
"AuthBasic": "Alap (böngésző előugró ablak)",
"AuthForm": "Űrlapok (bejelentkezési oldal)",
"DisabledForLocalAddresses": "Helyi címeknél letiltva",
@@ -546,7 +546,29 @@
"DeleteSelectedApplicationsMessageText": "Biztosan törölni szeretne {count} kiválasztott importlistát?",
"CountApplicationsSelected": "{count} Gyűjtemény(ek) kiválasztva",
"ManageClients": "Ügyfelek kezelése",
"IndexerDownloadClientHealthCheckMessage": "Indexelők érvénytelen letöltési kliensekkel: {0}.",
"IndexerDownloadClientHealthCheckMessage": "Indexelők érvénytelen letöltési kliensekkel: {indexerNames}.",
"PasswordConfirmation": "Jelszó megerősítése",
"SecretToken": "Titkos token"
"SecretToken": "Titkos token",
"UseSsl": "SSL használata",
"Donate": "Adományoz",
"IndexerBeyondHDSettingsSearchTypes": "Keresés típusa",
"Mixed": "Mixed",
"TorrentBlackholeSaveMagnetFiles": "Magnet fájlok mentése",
"DownloadClientSettingsInitialState": "Kezdeti állapot",
"DownloadClientSettingsInitialStateHelpText": "A torrentek kezdeti állapota hozzáadva a következőhöz {clientName}",
"DownloadClientTransmissionSettingsDirectoryHelpText": "Választható hely a letöltések elhelyezéséhez, hagyja üresen az alapértelmezett Aria2 hely használatához",
"IndexerHDBitsSettingsCodecs": "Kodek",
"IndexerHDBitsSettingsMediums": "Közepes",
"BlackholeFolderHelpText": "Mappa, amelyben az {appName} tárolja az {extension} fájlt",
"Destination": "Rendeltetési hely",
"Directory": "Könyvtár",
"DownloadClientFloodSettingsAdditionalTags": "További címkék",
"DownloadClientFloodSettingsAdditionalTagsHelpText": "Hozzáadja a média tulajdonságait címkékként. A tippek példák.",
"TorrentBlackholeSaveMagnetFilesExtension": "Magnet Files kiterjesztés mentése",
"TorrentBlackholeTorrentFolder": "Torrent mappa",
"DownloadClientDelugeSettingsUrlBaseHelpText": "Előtagot ad a deluge json URL-hez, lásd: {url}",
"CustomFilter": "Egyedi Szűrők",
"DownloadClientDownloadStationSettingsDirectoryHelpText": "Opcionális megosztott mappa a letöltések elhelyezéséhez, hagyja üresen az alapértelmezett Download Station hely használatához",
"DownloadClientRTorrentSettingsDirectoryHelpText": "Választható hely a letöltések elhelyezéséhez, hagyja üresen az alapértelmezett Aria2 hely használatához",
"DownloadClientSettingsUseSslHelpText": "Biztonságos kapcsolat használata, amikor a(z) {clientName} szolgáltatással csatlakozik"
}

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