1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-13 20:44:52 -04:00

Compare commits

..

55 Commits

Author SHA1 Message Date
Weblate
f77e27bace Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Altair <villagermd@outlook.com>
Co-authored-by: Ano10 <arnaudthommeray+github@ik.me>
Co-authored-by: Fonkio <maxime.fabre10@gmail.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Jacopo Luca Maria Latrofa <jacopo.latrofa@gmail.com>
Co-authored-by: Mailme Dashite <mailmedashite@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: YSLG <1451164040@qq.com>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: myrad2267 <myrad2267@gmail.com>
Co-authored-by: toeiazarothis <patrickdealmeida89000@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2024-04-19 17:25:34 +03:00
Servarr
8ea6d59d59 Automated API Docs update 2024-04-19 17:24:01 +03:00
Bogdan
98668d0d25 Bump SixLabors.ImageSharp to 3.1.4 2024-04-19 07:59:50 +03:00
Gauthier
649d57a234 Improve Multi Language Regex and field translations
(cherry picked from commit 6c232b062c5c11b76a2f205fcd949619e4346d16)

Closes #9931
2024-04-16 12:53:04 +03:00
Josh McKinney
dc7c8bf800 Add dev container workspace
Allows the linting and style settings for the frontend to be applied even when you load the main repo as a workspace

(cherry picked from commit d6278fced49b26be975c3a6039b38a94f700864b)

Closes #9929
2024-04-16 11:41:14 +03:00
Bogdan
8d90c7678f Fixed: Re-testing edited providers will forcibly test them
(cherry picked from commit e9662544621b2d1fb133ff9d96d0eb20b8198725)

Closes #9933
2024-04-16 11:39:43 +03:00
Bogdan
02518e2116 Fixed: Validate provider's settings in Test All endpoint 2024-04-16 11:39:35 +03:00
Mark McDowall
3191a883dc New: Improve multi-language negate Custom Format
(cherry picked from commit 42b11528b4699b8343887185c93a02b139192d83)

Closes #9720
2024-04-13 11:03:37 +03:00
Bogdan
31a714e6b3 Bump version to 5.5.0 2024-04-13 08:46:17 +03:00
Mark McDowall
f7ca0b8b06 New: Auto tag movies based on tags present/absent on movies
(cherry picked from commit f4c19a384bd9bb4e35c9fa0ca5d9a448c04e409e)

Closes #9916
2024-04-10 23:40:26 +03:00
Josh McKinney
56be9502af Add DevContainer, VSCode config and extensions.json
(cherry picked from commit 5061dc4b5e5ea9925740496a5939a1762788b793)

Closes #9914
2024-04-10 22:59:13 +03:00
Mark McDowall
77381d3f72 New: Option to prefix app name on Telegram notification titles
(cherry picked from commit 37863a8deb339ef730b2dd5be61e1da1311fdd23)

Closes #9913
2024-04-10 22:34:52 +03:00
Bogdan
198e6324e0 Truncate long names for import lists 2024-04-09 18:19:26 +03:00
Alan Collins
81c9537e5a New: 'Custom Format:Format Name' rename token
cherry picked from commit 48cb5d227187a06930aad5ee1b4e7b76422d8421)

New: Update Custom Format renaming token to allow excluding specific formats

(cherry picked from commit 6584d95331d0e0763e1688a397a3ccaf5fa6ca38)

Closes #9835
Closes #9826
2024-04-09 08:04:57 +03:00
Bogdan
d3cbb9be8d New: Detect shfs mounts 2024-04-08 22:25:42 +03:00
Bogdan
2e043c0cf7 Bump version to 5.4.6 2024-04-07 07:58:52 +03:00
Weblate
ada33dc065 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Michael5564445 <michaelvelosk@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2024-04-06 16:34:41 +03:00
Till Krüss
badb68b817 Improve text for file deleted through UI/API (#9882) 2024-04-06 16:32:25 +03:00
Mark McDowall
3bd1b3e972 Fixed: Sending ntfy.sh notifications with unicode characters
(cherry picked from commit a169ebff2adda5c8585c6aae6249b1c1f7c12264)
2024-04-06 16:27:30 +03:00
Stevie Robinson
6851de42a7 New: Informational text on Custom Formats modal
(cherry picked from commit 238ba85f0a2639608d9890292dfe0b96c0212f10)
2024-04-06 16:27:19 +03:00
Cuki
dd0b7c91f9 Fixed: Use widely supported display mode for PWA
(cherry picked from commit 1562d3bae3002947f9e428321d2b162ad69c3309)
2024-04-06 16:27:08 +03:00
Mark McDowall
45ac69e2d9 Fixed: Cleanse BHD RSS key in log files
(cherry picked from commit 60ee7cc716d344fc904fa6fb28f7be0386ae710d)
2024-04-06 16:26:49 +03:00
Bogdan
9ccf0ecdb1 Fix translation token for Include Health Warnings 2024-04-06 03:31:36 +03:00
Servarr
48a3467572 Automated API Docs update 2024-03-29 14:53:19 +02:00
Mark McDowall
d0a10379f9 Fixed: Use custom formats from import during rename
(cherry picked from commit d338425951af50a710c6c4411a72f05d14737ddd)

Closes #9867
2024-03-28 12:42:21 +02:00
Bogdan
caab5e3614 Add missing import after 4e4769 2024-03-28 12:38:28 +02:00
Alex Cortelyou
4e47695f89 New: Add additional fields to Webhook Manual Interaction Required events
(cherry picked from commit 1ec1ce58e9f095222e7fe4a8c74a0720fed71558)

Closes #9874
2024-03-28 11:15:56 +02:00
Bogdan
83bd4d0686 New: Advanced settings toggle in import list, notification and download client modals
(cherry picked from commit 13c925b3418d1d48ec041e3d97ab51aaf2b8977a)

Closes #9869
2024-03-28 11:14:26 +02:00
Mark McDowall
a75619c8ef Fixed: Task with removed movie causing error
(cherry picked from commit fc6494c569324c839debdb1d08dde23b8f1b8d76)

Closes #9866
2024-03-28 11:08:32 +02:00
Louis R
28689006fb Fixed: Exceptions when checking for routable IPv4 addresses
(cherry picked from commit 060b789bc6f10f667795697eb536d4bd3851da49)
2024-03-28 10:29:30 +02:00
Carlos Gustavo Sarmiento
43b0589bea Fixed: qBittorrent not correctly handling retention during testing
(cherry picked from commit 588372fd950fc85f5e9a4275fbcb423b247ed0ee)
2024-03-28 10:29:17 +02:00
Stevie Robinson
c4aad5800c Fixed: Handling torrents with relative path in rTorrent
(cherry picked from commit 35d0e6a6f806c68756450a7d199600d7fb49d6c5)
2024-03-28 10:28:53 +02:00
Bogdan
0c998dac5c New: Allow HEAD requests to ping endpoint
(cherry picked from commit 7353fe479dbb8d0dab76993ebed92d48e1b05524)
2024-03-28 10:28:41 +02:00
Bogdan
d41c0f0ab7 Fixed: Movie search label on overflow views
Fixed #9865
2024-03-27 15:16:56 +02:00
Weblate
85b13b7e41 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Altair <villagermd@outlook.com>
Co-authored-by: Casselluu <jack10193@163.com>
Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Jason54 <jason54700.jg@gmail.com>
Co-authored-by: Stanislav <prekop3@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: shimmyx <shimmygodx@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2024-03-27 13:16:17 +02:00
Bogdan
2a545a84b4 Bump version to 5.4.5 2024-03-24 17:45:46 +02:00
Mark McDowall
280083f4d7 Fixed: Task progress messages in the UI
(cherry picked from commit c6417337812f3578a27f9dc1e44fdad80f557271)

Closes #9855
2024-03-22 11:15:16 +02:00
Mark McDowall
d6dcae3d6a Fixed: Plex Watchlist import list
(cherry picked from commit 88de9274358d7005fa9c677bb8c86f046a2a23a9)
2024-03-22 11:06:39 +02:00
Bogdan
ebde4d3bc8 New: Critic Rating for Kodi/Emby metadata 2024-03-21 19:22:51 +02:00
Yurii
1ee30290ef Use branded message title for Telegram nitifications 2024-03-17 13:20:57 +00:00
Bogdan
d303eae7c6 New: Company filters for TMDb Popular List 2024-03-17 13:50:41 +02:00
Bogdan
584910514a Bump version to 5.4.4 2024-03-17 13:50:03 +02:00
Weblate
a253181d7d Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dennis Langthjem <dennis@langthjem.dk>
Co-authored-by: DimitriDR <dimitridroeck@gmail.com>
Co-authored-by: Gianmarco Novelli <rinogaetano94@live.it>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Ihor Mudryi <mudryy33@gmail.com>
Co-authored-by: MadaxDeLuXe <madaxdeluxe@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: infoaitek24 <info@aitekph.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: vfaergestad <vgf@hotmail.no>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/uk/
Translation: Servarr/Radarr
2024-03-16 18:15:57 +02:00
Bogdan
7ea6918327 Remove leftover QueuedTasks.js 2024-03-14 15:40:13 +02:00
Bogdan
953d3ad3fb Ensure not allowed cursor is shown for disabled select inputs 2024-03-14 14:31:09 +02:00
Mark McDowall
b9f4073514 Fixed: Disabled select option still selectable
(cherry picked from commit 063dba22a803295adee4fdcbe42718af3e85ca78)

Closes #9838
2024-03-14 13:20:33 +02:00
Stevie Robinson
86a17e7984 Fixed: Wrapping of naming tokens with alternate separators
(cherry picked from commit 80630bf97f5bb3b49d4824dc039d2edfc74e4797)

Closes #9743
Closes #9836
2024-03-14 11:33:54 +02:00
Bogdan
f38545f852 Ensure movies are populated in PageConnector 2024-03-14 11:21:56 +02:00
Mark McDowall
a7720e829d New: Show movie titles after task name when applicable
(cherry picked from commit 6d552f2a60f44052079b5e8944f5e1bbabac56e0)

Closes #9837
2024-03-14 11:15:39 +02:00
Mark McDowall
3a4eac4d59 Fixed: Release push with only Magnet URL
(cherry picked from commit 9f705e4161af3f4dd55b399d56b0b9c5a36e181b)
2024-03-14 07:12:12 +02:00
Bogdan
04f792c55a Fixed: Map covers to local for Movie Editor 2024-03-12 22:48:27 +02:00
Stevie Robinson
ada326e4dd Update release profile download client warning
(cherry picked from commit 2ec071a5ecab8f5056d179feaaef0147abb944ca)

Closes #9828
2024-03-10 20:16:09 +02:00
Bogdan
cae58d620b New: Collection Refresh Complete Event to trigger root folder check for collections 2024-03-10 20:13:35 +02:00
Bogdan
e84df18e8d Bump ImageSharp, Polly 2024-03-10 13:06:26 +02:00
Bogdan
a51ae70938 Bump version to 5.4.3 2024-03-10 09:08:55 +02:00
147 changed files with 2351 additions and 1046 deletions

View File

@@ -0,0 +1,13 @@
// This file is used to open the backend and frontend in the same workspace, which is necessary as
// the frontend has vscode settings that are distinct from the backend
{
"folders": [
{
"path": ".."
},
{
"path": "../frontend"
}
],
"settings": {}
}

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": "Radarr",
"image": "mcr.microsoft.com/devcontainers/dotnet:1-6.0",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"nodeGypDependencies": true,
"version": "16",
"nvmVersion": "latest"
}
},
"forwardPorts": [7878],
"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

@@ -126,6 +126,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 Radarr",
"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/Radarr",
"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/Radarr.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/Radarr.sln",
"-property:GenerateFullPaths=true",
"-consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/src/Radarr.sln"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '5.4.2'
majorVersion: '5.5.0'
minorVersion: $[counter('minorVersion', 2000)]
radarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(radarrVersion)'

View File

@@ -20,7 +20,7 @@ const monitoredOptions = [
get value() {
return translate('NoChange');
},
disabled: true
isDisabled: true
},
{
key: 'monitored',
@@ -42,7 +42,7 @@ const searchOnAddOptions = [
get value() {
return translate('NoChange');
},
disabled: true
isDisabled: true
},
{
key: 'yes',

View File

@@ -13,6 +13,7 @@ export interface CommandBody {
trigger: string;
suppressMessages: boolean;
movieId?: number;
movieIds?: number[];
}
interface Command extends ModelBase {

View File

@@ -36,7 +36,7 @@ function AvailabilitySelectInput(props) {
values.unshift({
key: 'noChange',
value: translate('NoChange'),
disabled: true
isDisabled: true
});
}
@@ -44,7 +44,7 @@ function AvailabilitySelectInput(props) {
values.unshift({
key: 'mixed',
value: '(Mixed)',
disabled: true
isDisabled: true
});
}

View File

@@ -19,7 +19,7 @@
.isDisabled {
opacity: 0.7;
cursor: not-allowed;
cursor: not-allowed !important;
}
.dropdownArrowContainer {

View File

@@ -17,6 +17,7 @@ import IndexerSelectInputConnector from './IndexerSelectInputConnector';
import KeyValueListInput from './KeyValueListInput';
import LanguageSelectInputConnector from './LanguageSelectInputConnector';
import MovieMonitoredSelectInput from './MovieMonitoredSelectInput';
import MovieTagInput from './MovieTagInput';
import NumberInput from './NumberInput';
import OAuthInputConnector from './OAuthInputConnector';
import PasswordInput from './PasswordInput';
@@ -89,6 +90,10 @@ function getComponent(type) {
case inputTypes.DYNAMIC_SELECT:
return EnhancedSelectInputConnector;
case inputTypes.MOVIE_TAG:
return MovieTagInput;
case inputTypes.TAG:
return TagInputConnector;

View File

@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import monitorOptions from 'Utilities/Movie/monitorOptions';
import translate from 'Utilities/String/translate';
import SelectInput from './SelectInput';
import EnhancedSelectInput from './EnhancedSelectInput';
function MovieMonitoredSelectInput(props) {
const values = [...monitorOptions];
@@ -16,7 +16,7 @@ function MovieMonitoredSelectInput(props) {
values.unshift({
key: 'noChange',
value: translate('NoChange'),
disabled: true
isDisabled: true
});
}
@@ -24,12 +24,12 @@ function MovieMonitoredSelectInput(props) {
values.unshift({
key: 'mixed',
value: '(Mixed)',
disabled: true
isDisabled: true
});
}
return (
<SelectInput
<EnhancedSelectInput
{...props}
values={values}
/>

View File

@@ -0,0 +1,53 @@
import React, { useCallback } from 'react';
import TagInputConnector from './TagInputConnector';
interface MovieTagInputProps {
name: string;
value: number | number[];
onChange: ({
name,
value,
}: {
name: string;
value: number | number[];
}) => void;
}
export default function MovieTagInput(props: MovieTagInputProps) {
const { value, onChange, ...otherProps } = props;
const isArray = Array.isArray(value);
const handleChange = useCallback(
({ name, value: newValue }: { name: string; value: number[] }) => {
if (isArray) {
onChange({ name, value: newValue });
} else {
onChange({
name,
value: newValue.length ? newValue[newValue.length - 1] : 0,
});
}
},
[isArray, onChange]
);
let finalValue: number[] = [];
if (isArray) {
finalValue = value;
} else if (value === 0) {
finalValue = [];
} else {
finalValue = [value];
}
return (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore 2786 'TagInputConnector' isn't typed yet
<TagInputConnector
{...otherProps}
value={finalValue}
onChange={handleChange}
/>
);
}

View File

@@ -27,6 +27,8 @@ function getType({ type, selectOptionsProviderAction }) {
return inputTypes.DYNAMIC_SELECT;
}
return inputTypes.SELECT;
case 'movieTag':
return inputTypes.MOVIE_TAG;
case 'tag':
return inputTypes.TEXT_TAG;
case 'tagSelect':

View File

@@ -26,7 +26,7 @@ function createMapStateToProps() {
values.unshift({
key: 'noChange',
value: translate('NoChange'),
disabled: includeNoChangeDisabled
isDisabled: includeNoChangeDisabled
});
}
@@ -34,7 +34,7 @@ function createMapStateToProps() {
values.unshift({
key: 'mixed',
value: '(Mixed)',
disabled: true
isDisabled: true
});
}

View File

@@ -45,6 +45,7 @@ const selectAppProps = createSelector(
);
const selectIsPopulated = createSelector(
(state) => state.movies.isPopulated,
(state) => state.customFilters.isPopulated,
(state) => state.tags.isPopulated,
(state) => state.settings.ui.isPopulated,
@@ -56,6 +57,7 @@ const selectIsPopulated = createSelector(
(state) => state.movieCollections.isPopulated,
(state) => state.app.translations.isPopulated,
(
moviesIsPopulated,
customFiltersIsPopulated,
tagsIsPopulated,
uiSettingsIsPopulated,
@@ -68,6 +70,7 @@ const selectIsPopulated = createSelector(
translationsIsPopulated
) => {
return (
moviesIsPopulated &&
customFiltersIsPopulated &&
tagsIsPopulated &&
uiSettingsIsPopulated &&
@@ -83,6 +86,7 @@ const selectIsPopulated = createSelector(
);
const selectErrors = createSelector(
(state) => state.movies.error,
(state) => state.customFilters.error,
(state) => state.tags.error,
(state) => state.settings.ui.error,
@@ -94,6 +98,7 @@ const selectErrors = createSelector(
(state) => state.movieCollections.error,
(state) => state.app.translations.error,
(
moviesError,
customFiltersError,
tagsError,
uiSettingsError,
@@ -106,6 +111,7 @@ const selectErrors = createSelector(
translationsError
) => {
const hasError = !!(
moviesError ||
customFiltersError ||
tagsError ||
uiSettingsError ||

View File

@@ -15,5 +15,5 @@
"start_url": "../../../../",
"theme_color": "#3a3f51",
"background_color": "#3a3f51",
"display": "minimal-ui"
"display": "standalone"
}

View File

@@ -0,0 +1,17 @@
import { useCallback, useState } from 'react';
export default function useModalOpenState(
initialState: boolean
): [boolean, () => void, () => void] {
const [isOpen, setOpen] = useState(initialState);
const setModalOpen = useCallback(() => {
setOpen(true);
}, [setOpen]);
const setModalClosed = useCallback(() => {
setOpen(false);
}, [setOpen]);
return [isOpen, setModalOpen, setModalClosed];
}

View File

@@ -17,6 +17,7 @@ export const INDEXER_FLAGS_SELECT = 'indexerFlagsSelect';
export const LANGUAGE_SELECT = 'languageSelect';
export const DOWNLOAD_CLIENT_SELECT = 'downloadClientSelect';
export const SELECT = 'select';
export const MOVIE_TAG = 'movieTag';
export const DYNAMIC_SELECT = 'dynamicSelect';
export const TAG = 'tag';
export const TEXT = 'text';
@@ -45,6 +46,7 @@ export const all = [
INDEXER_FLAGS_SELECT,
LANGUAGE_SELECT,
SELECT,
MOVIE_TAG,
DYNAMIC_SELECT,
TAG,
TEXT,

View File

@@ -44,6 +44,7 @@ import MovieIndexViewMenu from './Menus/MovieIndexViewMenu';
import MovieIndexFooter from './MovieIndexFooter';
import MovieIndexRefreshMovieButton from './MovieIndexRefreshMovieButton';
import MovieIndexSearchButton from './MovieIndexSearchButton';
import MovieIndexSearchMenuItem from './MovieIndexSearchMenuItem';
import MovieIndexOverviews from './Overview/MovieIndexOverviews';
import MovieIndexOverviewOptionsModal from './Overview/Options/MovieIndexOverviewOptionsModal';
import MovieIndexPosters from './Posters/MovieIndexPosters';
@@ -247,6 +248,7 @@ const MovieIndex = withScrollPosition((props: MovieIndexProps) => {
<MovieIndexSearchButton
isSelectMode={isSelectMode}
selectedFilterKey={selectedFilterKey}
overflowComponent={MovieIndexSearchMenuItem}
/>
<PageToolbarButton

View File

@@ -16,6 +16,7 @@ import getSelectedIds from 'Utilities/Table/getSelectedIds';
interface MovieIndexSearchButtonProps {
isSelectMode: boolean;
selectedFilterKey: string;
overflowComponent: React.FunctionComponent<never>;
}
function MovieIndexSearchButton(props: MovieIndexSearchButtonProps) {

View File

@@ -0,0 +1,72 @@
import React, { useCallback, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useSelect } from 'App/SelectContext';
import ClientSideCollectionAppState from 'App/State/ClientSideCollectionAppState';
import MoviesAppState, { MovieIndexAppState } from 'App/State/MoviesAppState';
import { MOVIE_SEARCH } from 'Commands/commandNames';
import PageToolbarOverflowMenuItem from 'Components/Page/Toolbar/PageToolbarOverflowMenuItem';
import { icons } from 'Helpers/Props';
import { executeCommand } from 'Store/Actions/commandActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import createMovieClientSideCollectionItemsSelector from 'Store/Selectors/createMovieClientSideCollectionItemsSelector';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
interface MovieIndexSearchMenuItemProps {
isSelectMode: boolean;
selectedFilterKey: string;
}
function MovieIndexSearchMenuItem(props: MovieIndexSearchMenuItemProps) {
const isSearching = useSelector(createCommandExecutingSelector(MOVIE_SEARCH));
const {
items,
}: MoviesAppState & MovieIndexAppState & ClientSideCollectionAppState =
useSelector(createMovieClientSideCollectionItemsSelector('movieIndex'));
const dispatch = useDispatch();
const { isSelectMode, selectedFilterKey } = props;
const [selectState] = useSelect();
const { selectedState } = selectState;
const selectedMovieIds = useMemo(() => {
return getSelectedIds(selectedState);
}, [selectedState]);
const moviesToSearch =
isSelectMode && selectedMovieIds.length > 0
? selectedMovieIds
: items.map((m) => m.id);
const searchIndexLabel =
selectedFilterKey === 'all'
? translate('SearchAll')
: translate('SearchFiltered');
const searchSelectLabel =
selectedMovieIds.length > 0
? translate('SearchSelected')
: translate('SearchAll');
const onPress = useCallback(() => {
dispatch(
executeCommand({
name: MOVIE_SEARCH,
movieIds: moviesToSearch,
})
);
}, [dispatch, moviesToSearch]);
return (
<PageToolbarOverflowMenuItem
label={isSelectMode ? searchSelectLabel : searchIndexLabel}
isSpinning={isSearching}
isDisabled={!items.length}
iconName={icons.SEARCH}
onPress={onPress}
/>
);
}
export default MovieIndexSearchMenuItem;

View File

@@ -34,7 +34,7 @@ const monitoredOptions = [
get value() {
return translate('NoChange');
},
disabled: true,
isDisabled: true,
},
{
key: 'monitored',

View File

@@ -151,6 +151,11 @@ class EditCustomFormatModalContent extends Component {
</Form>
<FieldSet legend={translate('Conditions')}>
<Alert kind={kinds.INFO}>
<div>
{translate('CustomFormatsSettingsTriggerInfo')}
</div>
</Alert>
<div className={styles.customFormats}>
{
specifications.map((tag) => {

View File

@@ -15,6 +15,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import AdvancedSettingsButton from 'Settings/AdvancedSettingsButton';
import translate from 'Utilities/String/translate';
import styles from './EditDownloadClientModalContent.css';
@@ -37,6 +38,7 @@ class EditDownloadClientModalContent extends Component {
onModalClose,
onSavePress,
onTestPress,
onAdvancedSettingsPress,
onDeleteDownloadClientPress,
...otherProps
} = this.props;
@@ -199,6 +201,12 @@ class EditDownloadClientModalContent extends Component {
</Button>
}
<AdvancedSettingsButton
advancedSettings={advancedSettings}
onAdvancedSettingsPress={onAdvancedSettingsPress}
showLabel={false}
/>
<SpinnerErrorButton
isSpinning={isTesting}
error={saveError}
@@ -239,6 +247,7 @@ EditDownloadClientModalContent.propTypes = {
onModalClose: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onTestPress: PropTypes.func.isRequired,
onAdvancedSettingsPress: PropTypes.func.isRequired,
onDeleteDownloadClientPress: 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 { saveDownloadClient, setDownloadClientFieldValue, setDownloadClientValue, testDownloadClient } from 'Store/Actions/settingsActions';
import {
saveDownloadClient,
setDownloadClientFieldValue,
setDownloadClientValue,
testDownloadClient,
toggleAdvancedSettings
} from 'Store/Actions/settingsActions';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import EditDownloadClientModalContent from './EditDownloadClientModalContent';
@@ -23,7 +29,8 @@ const mapDispatchToProps = {
setDownloadClientValue,
setDownloadClientFieldValue,
saveDownloadClient,
testDownloadClient
testDownloadClient,
toggleAdvancedSettings
};
class EditDownloadClientModalContentConnector extends Component {
@@ -56,6 +63,10 @@ class EditDownloadClientModalContentConnector extends Component {
this.props.testDownloadClient({ id: this.props.id });
};
onAdvancedSettingsPress = () => {
this.props.toggleAdvancedSettings();
};
//
// Render
@@ -65,6 +76,7 @@ class EditDownloadClientModalContentConnector extends Component {
{...this.props}
onSavePress={this.onSavePress}
onTestPress={this.onTestPress}
onAdvancedSettingsPress={this.onAdvancedSettingsPress}
onInputChange={this.onInputChange}
onFieldChange={this.onFieldChange}
/>
@@ -82,6 +94,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

@@ -32,7 +32,7 @@ const enableOptions = [
get value() {
return translate('NoChange');
},
disabled: true,
isDisabled: true,
},
{
key: 'enabled',

View File

@@ -17,6 +17,8 @@
}
.name {
@add-mixin truncate;
text-align: center;
font-weight: lighter;
font-size: 24px;

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 formatShortTimeSpan from 'Utilities/Date/formatShortTimeSpan';
import translate from 'Utilities/String/translate';
import styles from './EditImportListModalContent.css';
@@ -33,6 +34,7 @@ function EditImportListModalContent(props) {
onModalClose,
onSavePress,
onTestPress,
onAdvancedSettingsPress,
onDeleteImportListPress,
...otherProps
} = props;
@@ -234,6 +236,12 @@ function EditImportListModalContent(props) {
</Button>
}
<AdvancedSettingsButton
advancedSettings={advancedSettings}
onAdvancedSettingsPress={onAdvancedSettingsPress}
showLabel={false}
/>
<SpinnerErrorButton
isSpinning={isTesting}
error={saveError}
@@ -274,6 +282,7 @@ EditImportListModalContent.propTypes = {
onModalClose: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onTestPress: PropTypes.func.isRequired,
onAdvancedSettingsPress: PropTypes.func.isRequired,
onDeleteImportListPress: 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 { saveImportList, setImportListFieldValue, setImportListValue, testImportList } from 'Store/Actions/settingsActions';
import {
saveImportList,
setImportListFieldValue,
setImportListValue,
testImportList,
toggleAdvancedSettings
} from 'Store/Actions/settingsActions';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import EditImportListModalContent from './EditImportListModalContent';
@@ -33,7 +39,8 @@ const mapDispatchToProps = {
setImportListValue,
setImportListFieldValue,
saveImportList,
testImportList
testImportList,
toggleAdvancedSettings
};
class EditImportListModalContentConnector extends Component {
@@ -66,6 +73,10 @@ class EditImportListModalContentConnector extends Component {
this.props.testImportList({ id: this.props.id });
};
onAdvancedSettingsPress = () => {
this.props.toggleAdvancedSettings();
};
//
// Render
@@ -75,6 +86,7 @@ class EditImportListModalContentConnector extends Component {
{...this.props}
onSavePress={this.onSavePress}
onTestPress={this.onTestPress}
onAdvancedSettingsPress={this.onAdvancedSettingsPress}
onInputChange={this.onInputChange}
onFieldChange={this.onFieldChange}
/>
@@ -92,6 +104,7 @@ EditImportListModalContentConnector.propTypes = {
setImportListFieldValue: PropTypes.func.isRequired,
saveImportList: PropTypes.func.isRequired,
testImportList: PropTypes.func.isRequired,
toggleAdvancedSettings: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};

View File

@@ -33,7 +33,7 @@ const enableOptions = [
get value() {
return translate('NoChange');
},
disabled: true,
isDisabled: true,
},
{
key: 'enabled',

View File

@@ -32,7 +32,7 @@ const enableOptions = [
get value() {
return translate('NoChange');
},
disabled: true,
isDisabled: true,
},
{
key: 'enabled',

View File

@@ -120,7 +120,8 @@ const editionTokens = [
];
const customFormatTokens = [
{ token: '{Custom Formats}', example: 'Surround Sound x264' }
{ token: '{Custom Formats}', example: 'Surround Sound x264' },
{ token: '{Custom Format:FormatName}', example: 'AMZN' }
];
const originalTokens = [

View File

@@ -17,7 +17,7 @@
}
.small {
width: 480px;
width: 490px;
}
.large {
@@ -26,8 +26,8 @@
.token {
flex: 0 0 50%;
padding: 6px 16px;
background-color: var(--popoverTitleBorderColor);
padding: 6px;
background-color: var(--popoverTitleBackgroundColor);
font-family: $monoSpaceFontFamily;
}
@@ -37,8 +37,8 @@
align-self: stretch;
justify-content: space-between;
flex: 0 0 50%;
padding: 6px 16px;
background-color: var(--popoverTitleBackgroundColor);
padding: 6px;
background-color: var(--popoverBodyBackgroundColor);
.footNote {
padding: 2px;

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

@@ -12,7 +12,7 @@ export default function TagInUse(props) {
return null;
}
if (count > 1 && labelPlural ) {
if (count > 1 && labelPlural) {
return (
<div>
{count} {labelPlural.toLowerCase()}

View File

@@ -1,8 +1,11 @@
import $ from 'jquery';
import _ from 'lodash';
import createAjaxRequest from 'Utilities/createAjaxRequest';
import getProviderState from 'Utilities/State/getProviderState';
import { set } from '../baseActions';
const abortCurrentRequests = {};
let lastTestData = null;
export function createCancelTestProviderHandler(section) {
return function(getState, payload, dispatch) {
@@ -17,10 +20,25 @@ function createTestProviderHandler(section, url) {
return function(getState, payload, dispatch) {
dispatch(set({ section, isTesting: true }));
const testData = getProviderState(payload, getState, section);
const {
queryParams = {},
...otherPayload
} = payload;
const testData = getProviderState({ ...otherPayload }, getState, section);
const params = { ...queryParams };
// If the user is re-testing the same provider without changes
// force it to be tested.
if (_.isEqual(testData, lastTestData)) {
params.forceTest = true;
}
lastTestData = testData;
const ajaxOptions = {
url: `${url}/test`,
url: `${url}/test?${$.param(params, true)}`,
method: 'POST',
contentType: 'application/json',
dataType: 'json',
@@ -32,6 +50,8 @@ function createTestProviderHandler(section, url) {
abortCurrentRequests[section] = abortRequest;
request.done((data) => {
lastTestData = null;
dispatch(set({
section,
isTesting: false,

View File

@@ -0,0 +1,23 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import Movie from 'Movie/Movie';
function createMultiMoviesSelector(movieIds: number[]) {
return createSelector(
(state: AppState) => state.movies.itemMap,
(state: AppState) => state.movies.items,
(itemMap, allMovies) => {
return movieIds.reduce((acc: Movie[], movieId) => {
const movie = allMovies[itemMap[movieId]];
if (movie) {
acc.push(movie);
}
return acc;
}, []);
}
);
}
export default createMultiMoviesSelector;

View File

@@ -10,15 +10,6 @@
width: 100%;
}
.commandName {
display: inline-block;
min-width: 220px;
}
.userAgent {
color: #b0b0b0;
}
.queued,
.started,
.ended {

View File

@@ -2,14 +2,12 @@
// Please do not change this file!
interface CssExports {
'actions': string;
'commandName': string;
'duration': string;
'ended': string;
'queued': string;
'started': string;
'trigger': string;
'triggerContent': string;
'userAgent': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,279 +0,0 @@
import moment from 'moment';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Icon from 'Components/Icon';
import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow';
import { icons, kinds } from 'Helpers/Props';
import formatDate from 'Utilities/Date/formatDate';
import formatDateTime from 'Utilities/Date/formatDateTime';
import formatTimeSpan from 'Utilities/Date/formatTimeSpan';
import titleCase from 'Utilities/String/titleCase';
import translate from 'Utilities/String/translate';
import styles from './QueuedTaskRow.css';
function getStatusIconProps(status, message) {
const title = titleCase(status);
switch (status) {
case 'queued':
return {
name: icons.PENDING,
title
};
case 'started':
return {
name: icons.REFRESH,
isSpinning: true,
title
};
case 'completed':
return {
name: icons.CHECK,
kind: kinds.SUCCESS,
title: message === 'Completed' ? title : `${title}: ${message}`
};
case 'failed':
return {
name: icons.FATAL,
kind: kinds.DANGER,
title: `${title}: ${message}`
};
default:
return {
name: icons.UNKNOWN,
title
};
}
}
function getFormattedDates(props) {
const {
queued,
started,
ended,
showRelativeDates,
shortDateFormat
} = props;
if (showRelativeDates) {
return {
queuedAt: moment(queued).fromNow(),
startedAt: started ? moment(started).fromNow() : '-',
endedAt: ended ? moment(ended).fromNow() : '-'
};
}
return {
queuedAt: formatDate(queued, shortDateFormat),
startedAt: started ? formatDate(started, shortDateFormat) : '-',
endedAt: ended ? formatDate(ended, shortDateFormat) : '-'
};
}
class QueuedTaskRow extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
...getFormattedDates(props),
isCancelConfirmModalOpen: false
};
this._updateTimeoutId = null;
}
componentDidMount() {
this.setUpdateTimer();
}
componentDidUpdate(prevProps) {
const {
queued,
started,
ended
} = this.props;
if (
queued !== prevProps.queued ||
started !== prevProps.started ||
ended !== prevProps.ended
) {
this.setState(getFormattedDates(this.props));
}
}
componentWillUnmount() {
if (this._updateTimeoutId) {
this._updateTimeoutId = clearTimeout(this._updateTimeoutId);
}
}
//
// Control
setUpdateTimer() {
this._updateTimeoutId = setTimeout(() => {
this.setState(getFormattedDates(this.props));
this.setUpdateTimer();
}, 30000);
}
//
// Listeners
onCancelPress = () => {
this.setState({
isCancelConfirmModalOpen: true
});
};
onAbortCancel = () => {
this.setState({
isCancelConfirmModalOpen: false
});
};
//
// Render
render() {
const {
trigger,
commandName,
queued,
started,
ended,
status,
duration,
message,
clientUserAgent,
longDateFormat,
timeFormat,
onCancelPress
} = this.props;
const {
queuedAt,
startedAt,
endedAt,
isCancelConfirmModalOpen
} = this.state;
let triggerIcon = icons.QUICK;
if (trigger === 'manual') {
triggerIcon = icons.INTERACTIVE;
} else if (trigger === 'scheduled') {
triggerIcon = icons.SCHEDULED;
}
return (
<TableRow>
<TableRowCell className={styles.trigger}>
<span className={styles.triggerContent}>
<Icon
name={triggerIcon}
title={titleCase(trigger)}
/>
<Icon
{...getStatusIconProps(status, message)}
/>
</span>
</TableRowCell>
<TableRowCell>
<span className={styles.commandName}>
{commandName}
</span>
{
clientUserAgent ?
<span className={styles.userAgent} title={translate('TaskUserAgentTooltip')}>
{translate('From')}: {clientUserAgent}
</span> :
null
}
</TableRowCell>
<TableRowCell
className={styles.queued}
title={formatDateTime(queued, longDateFormat, timeFormat)}
>
{queuedAt}
</TableRowCell>
<TableRowCell
className={styles.started}
title={formatDateTime(started, longDateFormat, timeFormat)}
>
{startedAt}
</TableRowCell>
<TableRowCell
className={styles.ended}
title={formatDateTime(ended, longDateFormat, timeFormat)}
>
{endedAt}
</TableRowCell>
<TableRowCell className={styles.duration}>
{formatTimeSpan(duration)}
</TableRowCell>
<TableRowCell
className={styles.actions}
>
{
status === 'queued' &&
<IconButton
title={translate('RemovedFromTaskQueue')}
name={icons.REMOVE}
onPress={this.onCancelPress}
/>
}
</TableRowCell>
<ConfirmModal
isOpen={isCancelConfirmModalOpen}
kind={kinds.DANGER}
title={translate('Cancel')}
message={translate('CancelPendingTask')}
confirmLabel={translate('YesCancel')}
cancelLabel={translate('NoLeaveIt')}
onConfirm={onCancelPress}
onCancel={this.onAbortCancel}
/>
</TableRow>
);
}
}
QueuedTaskRow.propTypes = {
trigger: PropTypes.string.isRequired,
commandName: PropTypes.string.isRequired,
queued: PropTypes.string.isRequired,
started: PropTypes.string,
ended: PropTypes.string,
status: PropTypes.string.isRequired,
duration: PropTypes.string,
message: PropTypes.string,
clientUserAgent: PropTypes.string,
showRelativeDates: PropTypes.bool.isRequired,
shortDateFormat: PropTypes.string.isRequired,
longDateFormat: PropTypes.string.isRequired,
timeFormat: PropTypes.string.isRequired,
onCancelPress: PropTypes.func.isRequired
};
export default QueuedTaskRow;

View File

@@ -0,0 +1,238 @@
import moment from 'moment';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { CommandBody } from 'Commands/Command';
import Icon from 'Components/Icon';
import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow';
import useModalOpenState from 'Helpers/Hooks/useModalOpenState';
import { icons, kinds } from 'Helpers/Props';
import { cancelCommand } from 'Store/Actions/commandActions';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import formatDate from 'Utilities/Date/formatDate';
import formatDateTime from 'Utilities/Date/formatDateTime';
import formatTimeSpan from 'Utilities/Date/formatTimeSpan';
import titleCase from 'Utilities/String/titleCase';
import translate from 'Utilities/String/translate';
import QueuedTaskRowNameCell from './QueuedTaskRowNameCell';
import styles from './QueuedTaskRow.css';
function getStatusIconProps(status: string, message: string | undefined) {
const title = titleCase(status);
switch (status) {
case 'queued':
return {
name: icons.PENDING,
title,
};
case 'started':
return {
name: icons.REFRESH,
isSpinning: true,
title,
};
case 'completed':
return {
name: icons.CHECK,
kind: kinds.SUCCESS,
title: message === 'Completed' ? title : `${title}: ${message}`,
};
case 'failed':
return {
name: icons.FATAL,
kind: kinds.DANGER,
title: `${title}: ${message}`,
};
default:
return {
name: icons.UNKNOWN,
title,
};
}
}
function getFormattedDates(
queued: string,
started: string | undefined,
ended: string | undefined,
showRelativeDates: boolean,
shortDateFormat: string
) {
if (showRelativeDates) {
return {
queuedAt: moment(queued).fromNow(),
startedAt: started ? moment(started).fromNow() : '-',
endedAt: ended ? moment(ended).fromNow() : '-',
};
}
return {
queuedAt: formatDate(queued, shortDateFormat),
startedAt: started ? formatDate(started, shortDateFormat) : '-',
endedAt: ended ? formatDate(ended, shortDateFormat) : '-',
};
}
interface QueuedTimes {
queuedAt: string;
startedAt: string;
endedAt: string;
}
export interface QueuedTaskRowProps {
id: number;
trigger: string;
commandName: string;
queued: string;
started?: string;
ended?: string;
status: string;
duration?: string;
message?: string;
body: CommandBody;
clientUserAgent?: string;
}
export default function QueuedTaskRow(props: QueuedTaskRowProps) {
const {
id,
trigger,
commandName,
queued,
started,
ended,
status,
duration,
message,
body,
clientUserAgent,
} = props;
const dispatch = useDispatch();
const { longDateFormat, shortDateFormat, showRelativeDates, timeFormat } =
useSelector(createUISettingsSelector());
const updateTimeTimeoutId = useRef<ReturnType<typeof setTimeout> | null>(
null
);
const [times, setTimes] = useState<QueuedTimes>(
getFormattedDates(
queued,
started,
ended,
showRelativeDates,
shortDateFormat
)
);
const [
isCancelConfirmModalOpen,
openCancelConfirmModal,
closeCancelConfirmModal,
] = useModalOpenState(false);
const handleCancelPress = useCallback(() => {
dispatch(cancelCommand({ id }));
}, [id, dispatch]);
useEffect(() => {
updateTimeTimeoutId.current = setTimeout(() => {
setTimes(
getFormattedDates(
queued,
started,
ended,
showRelativeDates,
shortDateFormat
)
);
}, 30000);
return () => {
if (updateTimeTimeoutId.current) {
clearTimeout(updateTimeTimeoutId.current);
}
};
}, [queued, started, ended, showRelativeDates, shortDateFormat, setTimes]);
const { queuedAt, startedAt, endedAt } = times;
let triggerIcon = icons.QUICK;
if (trigger === 'manual') {
triggerIcon = icons.INTERACTIVE;
} else if (trigger === 'scheduled') {
triggerIcon = icons.SCHEDULED;
}
return (
<TableRow>
<TableRowCell className={styles.trigger}>
<span className={styles.triggerContent}>
<Icon name={triggerIcon} title={titleCase(trigger)} />
<Icon {...getStatusIconProps(status, message)} />
</span>
</TableRowCell>
<QueuedTaskRowNameCell
commandName={commandName}
body={body}
clientUserAgent={clientUserAgent}
/>
<TableRowCell
className={styles.queued}
title={formatDateTime(queued, longDateFormat, timeFormat)}
>
{queuedAt}
</TableRowCell>
<TableRowCell
className={styles.started}
title={formatDateTime(started, longDateFormat, timeFormat)}
>
{startedAt}
</TableRowCell>
<TableRowCell
className={styles.ended}
title={formatDateTime(ended, longDateFormat, timeFormat)}
>
{endedAt}
</TableRowCell>
<TableRowCell className={styles.duration}>
{formatTimeSpan(duration)}
</TableRowCell>
<TableRowCell className={styles.actions}>
{status === 'queued' && (
<IconButton
title={translate('RemovedFromTaskQueue')}
name={icons.REMOVE}
onPress={openCancelConfirmModal}
/>
)}
</TableRowCell>
<ConfirmModal
isOpen={isCancelConfirmModalOpen}
kind={kinds.DANGER}
title={translate('Cancel')}
message={translate('CancelPendingTask')}
confirmLabel={translate('YesCancel')}
cancelLabel={translate('NoLeaveIt')}
onConfirm={handleCancelPress}
onCancel={closeCancelConfirmModal}
/>
</TableRow>
);
}

View File

@@ -1,31 +0,0 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { cancelCommand } from 'Store/Actions/commandActions';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import QueuedTaskRow from './QueuedTaskRow';
function createMapStateToProps() {
return createSelector(
createUISettingsSelector(),
(uiSettings) => {
return {
showRelativeDates: uiSettings.showRelativeDates,
shortDateFormat: uiSettings.shortDateFormat,
longDateFormat: uiSettings.longDateFormat,
timeFormat: uiSettings.timeFormat
};
}
);
}
function createMapDispatchToProps(dispatch, props) {
return {
onCancelPress() {
dispatch(cancelCommand({
id: props.id
}));
}
};
}
export default connect(createMapStateToProps, createMapDispatchToProps)(QueuedTaskRow);

View File

@@ -0,0 +1,8 @@
.commandName {
display: inline-block;
min-width: 220px;
}
.userAgent {
color: #b0b0b0;
}

View File

@@ -0,0 +1,8 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'commandName': string;
'userAgent': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -0,0 +1,49 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { CommandBody } from 'Commands/Command';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import createMultiMoviesSelector from 'Store/Selectors/createMultiMoviesSelector';
import translate from 'Utilities/String/translate';
import styles from './QueuedTaskRowNameCell.css';
export interface QueuedTaskRowNameCellProps {
commandName: string;
body: CommandBody;
clientUserAgent?: string;
}
export default function QueuedTaskRowNameCell(
props: QueuedTaskRowNameCellProps
) {
const { commandName, body, clientUserAgent } = props;
const movieIds = [...(body.movieIds ?? [])];
if (body.movieId) {
movieIds.push(body.movieId);
}
const movies = useSelector(createMultiMoviesSelector(movieIds));
const sortedMovies = movies.sort((a, b) =>
a.sortTitle.localeCompare(b.sortTitle)
);
return (
<TableRowCell>
<span className={styles.commandName}>
{commandName}
{sortedMovies.length ? (
<span> - {sortedMovies.map((m) => m.title).join(', ')}</span>
) : null}
</span>
{clientUserAgent ? (
<span
className={styles.userAgent}
title={translate('TaskUserAgentTooltip')}
>
{translate('From')}: {clientUserAgent}
</span>
) : null}
</TableRowCell>
);
}

View File

@@ -1,90 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import FieldSet from 'Components/FieldSet';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import translate from 'Utilities/String/translate';
import QueuedTaskRowConnector from './QueuedTaskRowConnector';
const columns = [
{
name: 'trigger',
label: () => translate('Trigger'),
isVisible: true
},
{
name: 'commandName',
label: () => translate('Name'),
isVisible: true
},
{
name: 'queued',
label: () => translate('Queued'),
isVisible: true
},
{
name: 'started',
label: () => translate('Started'),
isVisible: true
},
{
name: 'ended',
label: () => translate('Ended'),
isVisible: true
},
{
name: 'duration',
label: () => translate('Duration'),
isVisible: true
},
{
name: 'actions',
isVisible: true
}
];
function QueuedTasks(props) {
const {
isFetching,
isPopulated,
items
} = props;
return (
<FieldSet legend={translate('Queue')}>
{
isFetching && !isPopulated &&
<LoadingIndicator />
}
{
isPopulated &&
<Table
columns={columns}
>
<TableBody>
{
items.map((item) => {
return (
<QueuedTaskRowConnector
key={item.id}
{...item}
/>
);
})
}
</TableBody>
</Table>
}
</FieldSet>
);
}
QueuedTasks.propTypes = {
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
items: PropTypes.array.isRequired
};
export default QueuedTasks;

View File

@@ -0,0 +1,74 @@
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import AppState from 'App/State/AppState';
import FieldSet from 'Components/FieldSet';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { fetchCommands } from 'Store/Actions/commandActions';
import translate from 'Utilities/String/translate';
import QueuedTaskRow from './QueuedTaskRow';
const columns = [
{
name: 'trigger',
label: '',
isVisible: true,
},
{
name: 'commandName',
label: () => translate('Name'),
isVisible: true,
},
{
name: 'queued',
label: () => translate('Queued'),
isVisible: true,
},
{
name: 'started',
label: () => translate('Started'),
isVisible: true,
},
{
name: 'ended',
label: () => translate('Ended'),
isVisible: true,
},
{
name: 'duration',
label: () => translate('Duration'),
isVisible: true,
},
{
name: 'actions',
isVisible: true,
},
];
export default function QueuedTasks() {
const dispatch = useDispatch();
const { isFetching, isPopulated, items } = useSelector(
(state: AppState) => state.commands
);
useEffect(() => {
dispatch(fetchCommands());
}, [dispatch]);
return (
<FieldSet legend={translate('Queue')}>
{isFetching && !isPopulated && <LoadingIndicator />}
{isPopulated && (
<Table columns={columns}>
<TableBody>
{items.map((item) => {
return <QueuedTaskRow key={item.id} {...item} />;
})}
</TableBody>
</Table>
)}
</FieldSet>
);
}

View File

@@ -1,46 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchCommands } from 'Store/Actions/commandActions';
import QueuedTasks from './QueuedTasks';
function createMapStateToProps() {
return createSelector(
(state) => state.commands,
(commands) => {
return commands;
}
);
}
const mapDispatchToProps = {
dispatchFetchCommands: fetchCommands
};
class QueuedTasksConnector extends Component {
//
// Lifecycle
componentDidMount() {
this.props.dispatchFetchCommands();
}
//
// Render
render() {
return (
<QueuedTasks
{...this.props}
/>
);
}
}
QueuedTasksConnector.propTypes = {
dispatchFetchCommands: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(QueuedTasksConnector);

View File

@@ -2,7 +2,7 @@ import React from 'react';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import translate from 'Utilities/String/translate';
import QueuedTasksConnector from './Queued/QueuedTasksConnector';
import QueuedTasks from './Queued/QueuedTasks';
import ScheduledTasksConnector from './Scheduled/ScheduledTasksConnector';
function Tasks() {
@@ -10,7 +10,7 @@ function Tasks() {
<PageContent title={translate('Tasks')}>
<PageContentBody>
<ScheduledTasksConnector />
<QueuedTasksConnector />
<QueuedTasks />
</PageContentBody>
</PageContent>
);

View File

@@ -11,7 +11,7 @@
"lint": "eslint --config frontend/.eslintrc.js --ignore-path frontend/.eslintignore frontend/",
"lint-fix": "yarn lint --fix",
"stylelint-linux": "stylelint $(find frontend -name '*.css') --config frontend/.stylelintrc",
"stylelint-windows": "stylelint frontend/**/*.css --config frontend/.stylelintrc"
"stylelint-windows": "stylelint \"frontend/**/*.css\" --config frontend/.stylelintrc"
},
"repository": "https://github.com/Radarr/Radarr",
"author": "Team Radarr",

View File

@@ -147,16 +147,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

@@ -19,6 +19,8 @@ namespace NzbDrone.Common.Test.InstrumentationTests
[TestCase(@"https://baconbits.org/feeds.php?feed=torrents_tv&user=12345&auth=2b51db35e1910123321025a12b9933d2&passkey=mySecret&authkey=2b51db35e1910123321025a12b9933d2")]
[TestCase(@"http://127.0.0.1:9117/dl/indexername?jackett_apikey=flwjiefewklfjacketmySecretsdfldskjfsdlk&path=we0re9f0sdfbase64sfdkfjsdlfjk&file=The+Torrent+File+Name.torrent")]
[TestCase(@"http://nzb.su/getnzb/2b51db35e1912ffc138825a12b9933d2.nzb&i=37292&r=2b51db35e1910123321025a12b9933d2")]
[TestCase(@"https://b-hd.me/torrent/download/auto.343756.is1t1pl127p1sfwur8h4kgyhg1wcsn05")]
[TestCase(@"https://b-hd.me/torrent/download/a-slug-in-the-url.343756.is1t1pl127p1sfwur8h4kgyhg1wcsn05")]
// NzbGet
[TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")]

View File

@@ -9,6 +9,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;
@@ -30,11 +31,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;
@@ -43,6 +47,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)
@@ -248,19 +254,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.
@@ -284,7 +298,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

@@ -18,6 +18,7 @@ namespace NzbDrone.Common.Instrumentation
new (@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled),
new (@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"\b(\w*)?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"-hd.me/torrent/[a-z0-9-]\.[0-9]+\.(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Trackers Announce Keys; Designed for Qbit Json; should work for all in theory
new (@"announce(\.php)?(/|%2f|%3fpasskey%3d)(?<secret>[a-z0-9]{16,})|(?<secret>[a-z0-9]{16,})(/|%2f)announce", RegexOptions.Compiled | RegexOptions.IgnoreCase),

View File

@@ -0,0 +1,71 @@
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.CustomFormats.Specifications.LanguageSpecification
{
[TestFixture]
public class MultiLanguageFixture : CoreTest<Core.CustomFormats.LanguageSpecification>
{
private CustomFormatInput _input;
[SetUp]
public void Setup()
{
_input = new CustomFormatInput
{
MovieInfo = Builder<ParsedMovieInfo>.CreateNew().Build(),
Movie = Builder<Movie>.CreateNew().With(m => m.MovieMetadata.Value.OriginalLanguage = Language.English).Build(),
Size = 100.Megabytes(),
Languages = new List<Language>
{
Language.English,
Language.French
},
Filename = "Movie.Title.2024"
};
}
[Test]
public void should_match_one_language()
{
Subject.Value = Language.French.Id;
Subject.Negate = false;
Subject.IsSatisfiedBy(_input).Should().BeTrue();
}
[Test]
public void should_not_match_different_language()
{
Subject.Value = Language.Spanish.Id;
Subject.Negate = false;
Subject.IsSatisfiedBy(_input).Should().BeFalse();
}
[Test]
public void should_not_match_negated_when_one_language_matches()
{
Subject.Value = Language.French.Id;
Subject.Negate = true;
Subject.IsSatisfiedBy(_input).Should().BeFalse();
}
[Test]
public void should_not_match_negated_when_all_languages_do_not_match()
{
Subject.Value = Language.Spanish.Id;
Subject.Negate = true;
Subject.IsSatisfiedBy(_input).Should().BeTrue();
}
}
}

View File

@@ -0,0 +1,80 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.CustomFormats.Specifications.LanguageSpecification
{
[TestFixture]
public class OriginalLanguageFixture : CoreTest<Core.CustomFormats.LanguageSpecification>
{
private CustomFormatInput _input;
[SetUp]
public void Setup()
{
_input = new CustomFormatInput
{
MovieInfo = Builder<ParsedMovieInfo>.CreateNew().Build(),
Movie = Builder<Movie>.CreateNew().With(m => m.MovieMetadata.Value.OriginalLanguage = Language.English).Build(),
Size = 100.Megabytes(),
Languages = new List<Language>
{
Language.French
},
Filename = "Movie.Title.2024"
};
}
public void GivenLanguages(params Language[] languages)
{
_input.Languages = languages.ToList();
}
[Test]
public void should_match_same_single_language()
{
GivenLanguages(Language.English);
Subject.Value = Language.Original.Id;
Subject.Negate = false;
Subject.IsSatisfiedBy(_input).Should().BeTrue();
}
[Test]
public void should_not_match_different_single_language()
{
Subject.Value = Language.Original.Id;
Subject.Negate = false;
Subject.IsSatisfiedBy(_input).Should().BeFalse();
}
[Test]
public void should_not_match_negated_same_single_language()
{
GivenLanguages(Language.English);
Subject.Value = Language.Original.Id;
Subject.Negate = true;
Subject.IsSatisfiedBy(_input).Should().BeFalse();
}
[Test]
public void should_match_negated_different_single_language()
{
Subject.Value = Language.Original.Id;
Subject.Negate = true;
Subject.IsSatisfiedBy(_input).Should().BeTrue();
}
}
}

View File

@@ -0,0 +1,70 @@
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.CustomFormats.Specifications.LanguageSpecification
{
[TestFixture]
public class SingleLanguageFixture : CoreTest<Core.CustomFormats.LanguageSpecification>
{
private CustomFormatInput _input;
[SetUp]
public void Setup()
{
_input = new CustomFormatInput
{
MovieInfo = Builder<ParsedMovieInfo>.CreateNew().Build(),
Movie = Builder<Movie>.CreateNew().With(m => m.MovieMetadata.Value.OriginalLanguage = Language.English).Build(),
Size = 100.Megabytes(),
Languages = new List<Language>
{
Language.French
},
Filename = "Movie.Title.2024"
};
}
[Test]
public void should_match_same_language()
{
Subject.Value = Language.French.Id;
Subject.Negate = false;
Subject.IsSatisfiedBy(_input).Should().BeTrue();
}
[Test]
public void should_not_match_different_language()
{
Subject.Value = Language.Spanish.Id;
Subject.Negate = false;
Subject.IsSatisfiedBy(_input).Should().BeFalse();
}
[Test]
public void should_not_match_negated_same_language()
{
Subject.Value = Language.French.Id;
Subject.Negate = true;
Subject.IsSatisfiedBy(_input).Should().BeFalse();
}
[Test]
public void should_match_negated_different_language()
{
Subject.Value = Language.Spanish.Id;
Subject.Negate = true;
Subject.IsSatisfiedBy(_input).Should().BeTrue();
}
}
}

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<IRadarrCloudRequestBuilder>(new RadarrCloudRequestBuilder());
}

View File

@@ -1,6 +1,9 @@
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.AutoTagging;
using NzbDrone.Core.AutoTagging.Specifications;
using NzbDrone.Core.Housekeeping.Housekeepers;
using NzbDrone.Core.Profiles.Releases;
using NzbDrone.Core.Tags;
@@ -43,5 +46,35 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
Subject.Clean();
AllStoredModels.Should().HaveCount(1);
}
[Test]
public void should_not_delete_used_auto_tagging_tag_specification_tags()
{
var tags = Builder<Tag>
.CreateListOfSize(2)
.All()
.With(x => x.Id = 0)
.BuildList();
Db.InsertMany(tags);
var autoTags = Builder<AutoTag>.CreateListOfSize(1)
.All()
.With(x => x.Id = 0)
.With(x => x.Specifications = new List<IAutoTaggingSpecification>
{
new TagSpecification
{
Name = "Test",
Value = tags[0].Id
}
})
.BuildList();
Mocker.GetMock<IAutoTaggingRepository>().Setup(s => s.All())
.Returns(autoTags);
Subject.Clean();
AllStoredModels.Should().HaveCount(1);
}
}
}

View File

@@ -0,0 +1,138 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
{
[TestFixture]
public class CustomFormatsFixture : CoreTest<FileNameBuilder>
{
private Movie _movie;
private MovieFile _movieFile;
private NamingConfig _namingConfig;
private List<CustomFormat> _customFormats;
[SetUp]
public void Setup()
{
_movie = Builder<Movie>
.CreateNew()
.With(s => s.Title = "South Park")
.Build();
_namingConfig = NamingConfig.Default;
_namingConfig.RenameMovies = true;
Mocker.GetMock<INamingConfigService>()
.Setup(c => c.GetConfig()).Returns(_namingConfig);
_movieFile = new MovieFile { Quality = new QualityModel(Quality.HDTV720p), ReleaseGroup = "RadarrTest" };
_customFormats = new List<CustomFormat>()
{
new CustomFormat()
{
Name = "INTERNAL",
IncludeCustomFormatWhenRenaming = true
},
new CustomFormat()
{
Name = "AMZN",
IncludeCustomFormatWhenRenaming = true
},
new CustomFormat()
{
Name = "NAME WITH SPACES",
IncludeCustomFormatWhenRenaming = true
},
new CustomFormat()
{
Name = "NotIncludedFormat",
IncludeCustomFormatWhenRenaming = false
}
};
Mocker.GetMock<IQualityDefinitionService>()
.Setup(v => v.Get(Moq.It.IsAny<Quality>()))
.Returns<Quality>(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v));
}
[TestCase("{Custom Formats}", "INTERNAL AMZN NAME WITH SPACES")]
public void should_replace_custom_formats(string format, string expected)
{
_namingConfig.StandardMovieFormat = format;
Subject.BuildFileName(_movie, _movieFile, customFormats: _customFormats)
.Should().Be(expected);
}
[TestCase("{Custom Formats}", "")]
public void should_replace_custom_formats_with_no_custom_formats(string format, string expected)
{
_namingConfig.StandardMovieFormat = format;
Subject.BuildFileName(_movie, _movieFile, customFormats: new List<CustomFormat>())
.Should().Be(expected);
}
[TestCase("{Custom Formats:-INTERNAL}", "AMZN NAME WITH SPACES")]
[TestCase("{Custom Formats:-NAME WITH SPACES}", "INTERNAL AMZN")]
[TestCase("{Custom Formats:-INTERNAL,NAME WITH SPACES}", "AMZN")]
[TestCase("{Custom Formats:INTERNAL}", "INTERNAL")]
[TestCase("{Custom Formats:NAME WITH SPACES}", "NAME WITH SPACES")]
[TestCase("{Custom Formats:INTERNAL,NAME WITH SPACES}", "INTERNAL NAME WITH SPACES")]
public void should_replace_custom_formats_with_filtered_names(string format, string expected)
{
_namingConfig.StandardMovieFormat = format;
Subject.BuildFileName(_movie, _movieFile, customFormats: _customFormats)
.Should().Be(expected);
}
[TestCase("{Custom Formats:-}", "{Custom Formats:-}")]
[TestCase("{Custom Formats:}", "{Custom Formats:}")]
public void should_not_replace_custom_formats_due_to_invalid_token(string format, string expected)
{
_namingConfig.StandardMovieFormat = format;
Subject.BuildFileName(_movie, _movieFile, customFormats: _customFormats)
.Should().Be(expected);
}
[TestCase("{Custom Format}", "")]
[TestCase("{Custom Format:INTERNAL}", "INTERNAL")]
[TestCase("{Custom Format:AMZN}", "AMZN")]
[TestCase("{Custom Format:NAME WITH SPACES}", "NAME WITH SPACES")]
[TestCase("{Custom Format:DOESNOTEXIST}", "")]
[TestCase("{Custom Format:INTERNAL} - {Custom Format:AMZN}", "INTERNAL - AMZN")]
[TestCase("{Custom Format:AMZN} - {Custom Format:INTERNAL}", "AMZN - INTERNAL")]
public void should_replace_custom_format(string format, string expected)
{
_namingConfig.StandardMovieFormat = format;
Subject.BuildFileName(_movie, _movieFile, customFormats: _customFormats)
.Should().Be(expected);
}
[TestCase("{Custom Format}", "")]
[TestCase("{Custom Format:INTERNAL}", "")]
[TestCase("{Custom Format:AMZN}", "")]
public void should_replace_custom_format_with_no_custom_formats(string format, string expected)
{
_namingConfig.StandardMovieFormat = format;
Subject.BuildFileName(_movie, _movieFile, customFormats: new List<CustomFormat>())
.Should().Be(expected);
}
}
}

View File

@@ -84,7 +84,8 @@ namespace NzbDrone.Core.Annotations
Device,
TagSelect,
RootFolder,
QualityProfile
QualityProfile,
MovieTag
}
public enum HiddenType

View File

@@ -0,0 +1,36 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.AutoTagging.Specifications
{
public class TagSpecificationValidator : AbstractValidator<TagSpecification>
{
public TagSpecificationValidator()
{
RuleFor(c => c.Value).GreaterThan(0);
}
}
public class TagSpecification : AutoTaggingSpecificationBase
{
private static readonly TagSpecificationValidator Validator = new ();
public override int Order => 1;
public override string ImplementationName => "Tag";
[FieldDefinition(1, Label = "AutoTaggingSpecificationTag", Type = FieldType.MovieTag)]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(Movie movie)
{
return movie.Tags.Contains(Value);
}
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;

View File

@@ -20,7 +20,7 @@ namespace NzbDrone.Core.CustomFormats
public abstract NzbDroneValidationResult Validate();
public bool IsSatisfiedBy(CustomFormatInput input)
public virtual bool IsSatisfiedBy(CustomFormatInput input)
{
var match = IsSatisfiedByWithoutNegate(input);

View File

@@ -30,6 +30,16 @@ namespace NzbDrone.Core.CustomFormats
[FieldDefinition(1, Label = "Language", Type = FieldType.Select, SelectOptions = typeof(LanguageFieldConverter))]
public int Value { get; set; }
public override bool IsSatisfiedBy(CustomFormatInput input)
{
if (Negate)
{
return IsSatisfiedByWithNegate(input);
}
return IsSatisfiedByWithoutNegate(input);
}
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
{
var comparedLanguage = input.MovieInfo != null && input.Movie != null && Value == Language.Original.Id && input.Movie.MovieMetadata.Value.OriginalLanguage != Language.Unknown
@@ -39,6 +49,15 @@ namespace NzbDrone.Core.CustomFormats
return input?.Languages?.Contains(comparedLanguage) ?? false;
}
private bool IsSatisfiedByWithNegate(CustomFormatInput input)
{
var comparedLanguage = input.MovieInfo != null && input.Movie != null && Value == Language.Original.Id && input.Movie.MovieMetadata.Value.OriginalLanguage != Language.Unknown
? input.Movie.MovieMetadata.Value.OriginalLanguage
: (Language)Value;
return !input.Languages?.Contains(comparedLanguage) ?? false;
}
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -388,16 +388,20 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
}
}
var minimumRetention = 60 * 24 * 14;
return new DownloadClientInfo
{
IsLocalhost = Settings.Host == "127.0.0.1" || Settings.Host == "localhost",
OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, destDir) },
RemovesCompletedDownloads = (config.MaxRatioEnabled || (config.MaxSeedingTimeEnabled && config.MaxSeedingTime < minimumRetention)) && (config.MaxRatioAction == QBittorrentMaxRatioAction.Remove || config.MaxRatioAction == QBittorrentMaxRatioAction.DeleteFiles)
RemovesCompletedDownloads = RemovesCompletedDownloads(config)
};
}
private bool RemovesCompletedDownloads(QBittorrentPreferences config)
{
var minimumRetention = 60 * 24 * 14; // 14 days in minutes
return (config.MaxRatioEnabled || (config.MaxSeedingTimeEnabled && config.MaxSeedingTime < minimumRetention)) && (config.MaxRatioAction == QBittorrentMaxRatioAction.Remove || config.MaxRatioAction == QBittorrentMaxRatioAction.DeleteFiles);
}
protected override void Test(List<ValidationFailure> failures)
{
failures.AddIfNotNull(TestConnection());
@@ -448,7 +452,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
// Complain if qBittorrent is configured to remove torrents on max ratio
var config = Proxy.GetConfig(Settings);
if ((config.MaxRatioEnabled || config.MaxSeedingTimeEnabled) && (config.MaxRatioAction == QBittorrentMaxRatioAction.Remove || config.MaxRatioAction == QBittorrentMaxRatioAction.DeleteFiles))
if (RemovesCompletedDownloads(config))
{
return new NzbDroneValidationFailure(string.Empty, _localizationService.GetLocalizedString("DownloadClientQbittorrentValidationRemovesAtRatioLimit"))
{

View File

@@ -139,12 +139,14 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
// Ignore torrents with an empty path
if (torrent.Path.IsNullOrWhiteSpace())
{
_logger.Warn("Torrent '{0}' has an empty download path and will not be processed. Adjust this to an absolute path in rTorrent", torrent.Name);
continue;
}
if (torrent.Path.StartsWith("."))
{
throw new DownloadClientException("Download paths must be absolute. Please specify variable \"directory\" in rTorrent.");
_logger.Warn("Torrent '{0}' has a download path starting with '.' and will not be processed. Adjust this to an absolute path in rTorrent", torrent.Name);
continue;
}
var item = new DownloadClientItem();

View File

@@ -156,13 +156,13 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
details.Add(new XElement("sorttitle", Parser.Parser.NormalizeTitle(metadataTitle)));
if (movie.MovieMetadata.Value.Ratings.Tmdb?.Votes > 0 || movie.MovieMetadata.Value.Ratings.Imdb?.Votes > 0)
if (movie.MovieMetadata.Value.Ratings?.Tmdb?.Votes > 0 || movie.MovieMetadata.Value.Ratings?.Imdb?.Votes > 0 || movie.MovieMetadata.Value.Ratings?.RottenTomatoes?.Value > 0)
{
var setRating = new XElement("ratings");
var defaultRatingSet = false;
if (movie.MovieMetadata.Value.Ratings.Imdb?.Votes > 0)
if (movie.MovieMetadata.Value.Ratings?.Imdb?.Votes > 0)
{
var setRateImdb = new XElement("rating", new XAttribute("name", "imdb"), new XAttribute("max", "10"), new XAttribute("default", "true"));
setRateImdb.Add(new XElement("value", movie.MovieMetadata.Value.Ratings.Imdb.Value));
@@ -172,18 +172,32 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
setRating.Add(setRateImdb);
}
if (movie.MovieMetadata.Value.Ratings.Tmdb?.Votes > 0)
if (movie.MovieMetadata.Value.Ratings?.Tmdb?.Votes > 0)
{
var setRatethemoviedb = new XElement("rating", new XAttribute("name", "themoviedb"), new XAttribute("max", "10"));
setRatethemoviedb.Add(new XElement("value", movie.MovieMetadata.Value.Ratings.Tmdb.Value));
setRatethemoviedb.Add(new XElement("votes", movie.MovieMetadata.Value.Ratings.Tmdb.Votes));
var setRateTheMovieDb = new XElement("rating", new XAttribute("name", "themoviedb"), new XAttribute("max", "10"));
setRateTheMovieDb.Add(new XElement("value", movie.MovieMetadata.Value.Ratings.Tmdb.Value));
setRateTheMovieDb.Add(new XElement("votes", movie.MovieMetadata.Value.Ratings.Tmdb.Votes));
if (!defaultRatingSet)
{
setRatethemoviedb.SetAttributeValue("default", "true");
defaultRatingSet = true;
setRateTheMovieDb.SetAttributeValue("default", "true");
}
setRating.Add(setRatethemoviedb);
setRating.Add(setRateTheMovieDb);
}
if (movie.MovieMetadata.Value.Ratings?.RottenTomatoes?.Value > 0)
{
var setRateRottenTomatoes = new XElement("rating", new XAttribute("name", "tomatometerallcritics"), new XAttribute("max", "100"));
setRateRottenTomatoes.Add(new XElement("value", movie.MovieMetadata.Value.Ratings.RottenTomatoes.Value));
if (!defaultRatingSet)
{
setRateRottenTomatoes.SetAttributeValue("default", "true");
}
setRating.Add(setRateRottenTomatoes);
}
details.Add(setRating);
@@ -194,6 +208,11 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
details.Add(new XElement("rating", movie.MovieMetadata.Value.Ratings.Tmdb.Value));
}
if (movie.MovieMetadata.Value.Ratings?.RottenTomatoes?.Value > 0)
{
details.Add(new XElement("criticrating", movie.MovieMetadata.Value.Ratings.RottenTomatoes.Value));
}
details.Add(new XElement("userrating"));
details.Add(new XElement("top250"));

View File

@@ -19,7 +19,6 @@ namespace NzbDrone.Core.HealthCheck.Checks
[CheckOn(typeof(ProviderDeletedEvent<IDownloadClient>))]
[CheckOn(typeof(ModelEvent<RootFolder>))]
[CheckOn(typeof(ModelEvent<RemotePathMapping>))]
public class DownloadClientRootFolderCheck : HealthCheckBase, IProvideHealthCheck
{
private readonly IProvideDownloadClient _downloadClientProvider;
@@ -58,7 +57,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
_localizationService.GetLocalizedString("DownloadClientCheckDownloadingToRoot", new Dictionary<string, object>
{
{ "downloadClientName", client.Definition.Name },
{ "path", folder.FullPath }
{ "rootFolderPath", folder.FullPath }
}),
"#downloads-in-root-folder");
}

View File

@@ -5,10 +5,12 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Movies.Collections;
using NzbDrone.Core.Movies.Events;
using NzbDrone.Core.RootFolders;
namespace NzbDrone.Core.HealthCheck.Checks
{
[CheckOn(typeof(CollectionRefreshCompleteEvent))]
[CheckOn(typeof(ModelEvent<RootFolder>))]
public class MovieCollectionRootFolderCheck : HealthCheckBase
{

View File

@@ -3,6 +3,8 @@ using System.Data;
using System.Linq;
using Dapper;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.AutoTagging;
using NzbDrone.Core.AutoTagging.Specifications;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Housekeeping.Housekeepers
@@ -10,17 +12,24 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public class CleanupUnusedTags : IHousekeepingTask
{
private readonly IMainDatabase _database;
private readonly IAutoTaggingRepository _autoTaggingRepository;
public CleanupUnusedTags(IMainDatabase database)
public CleanupUnusedTags(IMainDatabase database, IAutoTaggingRepository autoTaggingRepository)
{
_database = database;
_autoTaggingRepository = autoTaggingRepository;
}
public void Clean()
{
using var mapper = _database.OpenConnection();
var usedTags = new[] { "Movies", "Notifications", "DelayProfiles", "ReleaseProfiles", "ImportLists", "Indexers", "AutoTagging", "DownloadClients" }
var usedTags = new[]
{
"Movies", "Notifications", "DelayProfiles", "ReleaseProfiles", "ImportLists", "Indexers",
"AutoTagging", "DownloadClients"
}
.SelectMany(v => GetUsedTags(v, mapper))
.Concat(GetAutoTaggingTagSpecificationTags(mapper))
.Distinct()
.ToList();
@@ -45,10 +54,31 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
private int[] GetUsedTags(string table, IDbConnection mapper)
{
return mapper.Query<List<int>>($"SELECT DISTINCT \"Tags\" FROM \"{table}\" WHERE NOT \"Tags\" = '[]' AND NOT \"Tags\" IS NULL")
return mapper
.Query<List<int>>(
$"SELECT DISTINCT \"Tags\" FROM \"{table}\" WHERE NOT \"Tags\" = '[]' AND NOT \"Tags\" IS NULL")
.SelectMany(x => x)
.Distinct()
.ToArray();
}
private List<int> GetAutoTaggingTagSpecificationTags(IDbConnection mapper)
{
var tags = new List<int>();
var autoTags = _autoTaggingRepository.All();
foreach (var autoTag in autoTags)
{
foreach (var specification in autoTag.Specifications)
{
if (specification is TagSpecification tagSpec)
{
tags.Add(tagSpec.Value);
}
}
}
return tags;
}
}
}

View File

@@ -36,6 +36,8 @@ namespace NzbDrone.Core.ImportLists.TMDb.Popular
var certification = Settings.FilterCriteria.Certification;
var includeGenreIds = Settings.FilterCriteria.IncludeGenreIds;
var excludeGenreIds = Settings.FilterCriteria.ExcludeGenreIds;
var includeCompanyIds = Settings.FilterCriteria.IncludeCompanyIds;
var excludeCompanyIds = Settings.FilterCriteria.ExcludeCompanyIds;
var languageCode = (TMDbLanguageCodes)Settings.FilterCriteria.LanguageCode;
var todaysDate = DateTime.Now.ToString("yyyy-MM-dd");
@@ -92,6 +94,16 @@ namespace NzbDrone.Core.ImportLists.TMDb.Popular
requestBuilder.AddQueryParam("without_genres", excludeGenreIds);
}
if (includeCompanyIds.IsNotNullOrWhiteSpace())
{
requestBuilder.AddQueryParam("with_companies", includeCompanyIds);
}
if (excludeCompanyIds.IsNotNullOrWhiteSpace())
{
requestBuilder.AddQueryParam("without_companies", excludeCompanyIds);
}
requestBuilder
.AddQueryParam("with_original_language", languageCode)
.Accept(HttpAccept.Json);

View File

@@ -38,6 +38,18 @@ namespace NzbDrone.Core.ImportLists.TMDb
.Matches(@"^\d+([,|]\d+)*$", RegexOptions.IgnoreCase)
.When(c => c.ExcludeGenreIds.IsNotNullOrWhiteSpace())
.WithMessage("Genre Ids must be comma (,) or pipe (|) separated number ids");
// CSV of numbers
RuleFor(c => c.IncludeCompanyIds)
.Matches(@"^\d+([,|]\d+)*$", RegexOptions.IgnoreCase)
.When(c => c.IncludeCompanyIds.IsNotNullOrWhiteSpace())
.WithMessage("Company Ids must be comma (,) or pipe (|) separated number ids");
// CSV of numbers
RuleFor(c => c.ExcludeCompanyIds)
.Matches(@"^\d+([,|]\d+)*$", RegexOptions.IgnoreCase)
.When(c => c.ExcludeCompanyIds.IsNotNullOrWhiteSpace())
.WithMessage("Company Ids must be comma (,) or pipe (|) separated number ids");
}
}
@@ -48,8 +60,10 @@ namespace NzbDrone.Core.ImportLists.TMDb
MinVoteAverage = "5";
MinVotes = "1";
LanguageCode = (int)TMDbLanguageCodes.en;
ExcludeGenreIds = "";
IncludeGenreIds = "";
ExcludeGenreIds = "";
IncludeCompanyIds = "";
ExcludeCompanyIds = "";
}
[FieldDefinition(1, Label = "Minimum Vote Average", HelpText = "Filter movies by votes (0.0-10.0)")]
@@ -67,7 +81,13 @@ namespace NzbDrone.Core.ImportLists.TMDb
[FieldDefinition(5, Label = "Exclude Genre Ids", HelpText = "Filter movies by TMDb Genre Ids (Comma Separated)")]
public string ExcludeGenreIds { get; set; }
[FieldDefinition(6, Label = "Original Language", Type = FieldType.Select, SelectOptions = typeof(TMDbLanguageCodes), HelpText = "Filter by Language")]
[FieldDefinition(6, Label = "Include Company Ids", HelpText = "Filter movies by TMDb Company Ids (Comma Separated)")]
public string IncludeCompanyIds { get; set; }
[FieldDefinition(7, Label = "Exclude Company Ids", HelpText = "Filter movies by TMDb Company Ids (Comma Separated)")]
public string ExcludeCompanyIds { get; set; }
[FieldDefinition(8, Label = "Original Language", Type = FieldType.Select, SelectOptions = typeof(TMDbLanguageCodes), HelpText = "Filter by Language")]
public int LanguageCode { get; set; }
}
}

View File

@@ -112,7 +112,7 @@ namespace NzbDrone.Core.IndexerSearch
var reports = batch.SelectMany(x => x).ToList();
_logger.Debug("Total of {0} reports were found for {1} from {2} indexers", reports.Count, criteriaBase, indexers.Count);
_logger.ProgressDebug("Total of {0} reports were found for {1} from {2} indexers", reports.Count, criteriaBase, indexers.Count);
// Update the last search time for movie if at least 1 indexer was searched.
if (indexers.Any())

View File

@@ -46,27 +46,27 @@ namespace NzbDrone.Core.Indexers.FileList
[FieldDefinition(1, Label = "Passkey", Privacy = PrivacyLevel.ApiKey)]
public string Passkey { get; set; }
[FieldDefinition(2, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "Multi Languages", HelpText = "What languages are normally in a multi release on this indexer?", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(3, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")]
[FieldDefinition(2, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")]
public string BaseUrl { get; set; }
[FieldDefinition(4, Label = "Categories", Type = FieldType.Select, SelectOptions = typeof(FileListCategories), HelpText = "Categories for use in search and feeds. If unspecified, all options are used.")]
[FieldDefinition(3, Label = "Categories", Type = FieldType.Select, SelectOptions = typeof(FileListCategories), HelpText = "Categories for use in search and feeds. If unspecified, all options are used.")]
public IEnumerable<int> Categories { get; set; }
[FieldDefinition(5, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(4, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
[FieldDefinition(7)]
[FieldDefinition(5)]
public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings();
[FieldDefinition(8, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
[FieldDefinition(6, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(7, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(8, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -53,21 +53,21 @@ namespace NzbDrone.Core.Indexers.HDBits
[FieldDefinition(5, Label = "Mediums", Type = FieldType.Select, SelectOptions = typeof(HdBitsMedium), Advanced = true, HelpText = "If unspecified, all options are used.")]
public IEnumerable<int> Mediums { get; set; }
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "Multi Languages", HelpText = "What languages are normally in a multi release on this indexer?", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(7, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(6, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(8, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
[FieldDefinition(9)]
[FieldDefinition(7)]
public SeedCriteriaSettings SeedCriteria { get; set; } = new ();
[FieldDefinition(10, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
[FieldDefinition(8, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(9, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(10, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -41,21 +41,21 @@ namespace NzbDrone.Core.Indexers.IPTorrents
[FieldDefinition(0, Label = "Feed URL", HelpText = "The full RSS feed url generated by IPTorrents, using only the categories you selected (HD, SD, x264, etc ...)")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "Multi Languages", HelpText = "What languages are normally in a multi release on this indexer?", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(2, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(1, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(3, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
[FieldDefinition(4)]
[FieldDefinition(2)]
public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings();
[FieldDefinition(5, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
[FieldDefinition(3, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(4, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -19,7 +19,7 @@ namespace NzbDrone.Core.Indexers
public abstract class IndexerBase<TSettings> : IIndexer
where TSettings : IIndexerSettings, new()
{
private static readonly Regex MultiRegex = new (@"\b(?<multi>multi)\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex MultiRegex = new (@"[_. ](?<multi>multi)[_. ]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
protected readonly IIndexerStatusService _indexerStatusService;
protected readonly IConfigService _configService;

View File

@@ -65,23 +65,19 @@ namespace NzbDrone.Core.Indexers.Newznab
[FieldDefinition(1, Label = "API Path", HelpText = "Path to the api, usually /api", Advanced = true)]
public string ApiPath { get; set; }
[FieldDefinition(1, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "Multi Languages", HelpText = "What languages are normally in a multi release on this indexer?", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey)]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Categories", Type = FieldType.Select, SelectOptionsProviderAction = "newznabCategories", HelpText = "Drop down list; at least one category must be selected.")]
public IEnumerable<int> Categories { get; set; }
[FieldDefinition(5, Label = "Additional Parameters", HelpText = "Additional Newznab parameters", Advanced = true)]
[FieldDefinition(4, Label = "Additional Parameters", HelpText = "Additional Newznab parameters", Advanced = true)]
public string AdditionalParameters { get; set; }
[FieldDefinition(6,
Label = "Remove year from search string",
HelpText = "Should Radarr remove the year after the title when searching this indexer?",
Advanced = true,
Type = FieldType.Checkbox)]
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(6, Label = "Remove year from search string", HelpText = "Should Radarr remove the year after the title when searching this indexer?", Type = FieldType.Checkbox, Advanced = true)]
public bool RemoveYear { get; set; }
// Field 8 is used by TorznabSettings MinimumSeeders

View File

@@ -36,24 +36,24 @@ namespace NzbDrone.Core.Indexers.Nyaa
[FieldDefinition(0, Label = "Website URL")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "Multi Languages", HelpText = "What languages are normally in a multi release on this indexer?", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(2, Label = "Additional Parameters", Advanced = true, HelpText = "Please note if you change the category you will have to add required/restricted rules about the subgroups to avoid foreign language releases.")]
[FieldDefinition(1, Label = "Additional Parameters", Advanced = true, HelpText = "Please note if you change the category you will have to add required/restricted rules about the subgroups to avoid foreign language releases.")]
public string AdditionalParameters { get; set; }
[FieldDefinition(3, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(2, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(4, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
[FieldDefinition(5)]
[FieldDefinition(3)]
public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings();
[FieldDefinition(6, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -35,27 +35,27 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
[FieldDefinition(0, Label = "URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your cookie will be sent to that host.")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "APIUser", HelpText = "These settings are found in your PassThePopcorn security settings (Edit Profile > Security).", Privacy = PrivacyLevel.UserName)]
[FieldDefinition(1, Label = "API User", HelpText = "These settings are found in your PassThePopcorn security settings (Edit Profile > Security).", Privacy = PrivacyLevel.UserName)]
public string APIUser { get; set; }
[FieldDefinition(2, Label = "APIKey", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
[FieldDefinition(2, Label = "API Key", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
public string APIKey { get; set; }
[FieldDefinition(3, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "Multi Languages", HelpText = "What languages are normally in a multi release on this indexer?", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(4, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
[FieldDefinition(6)]
[FieldDefinition(4)]
public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings();
[FieldDefinition(7, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
[FieldDefinition(5, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(7, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -5,7 +5,6 @@ namespace NzbDrone.Core.Indexers
public class RssSyncCommand : Command
{
public override bool SendUpdatesToClient => true;
public override bool IsLongRunning => true;
}
}

View File

@@ -39,21 +39,21 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
[FieldDefinition(2, Label = "Passkey", HelpText = "The password you use at your Indexer.", Privacy = PrivacyLevel.Password)]
public string Passkey { get; set; }
[FieldDefinition(3, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "Multi Languages", HelpText = "What languages are normally in a multi release on this indexer?", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(4, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(3, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
[FieldDefinition(6)]
[FieldDefinition(4)]
public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings();
[FieldDefinition(7, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
[FieldDefinition(5, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(7, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -40,21 +40,21 @@ namespace NzbDrone.Core.Indexers.TorrentRss
[FieldDefinition(2, Type = FieldType.Checkbox, Label = "Allow Zero Size", HelpText = "Enabling this will allow you to use feeds that don't specify release size, but be careful, size related checks will not be performed.")]
public bool AllowZeroSize { get; set; }
[FieldDefinition(3, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "Multi Languages", HelpText = "What languages are normally in a multi release on this indexer?", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(4, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
[FieldDefinition(3, Type = FieldType.Number, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
[FieldDefinition(6)]
[FieldDefinition(4)]
public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings();
[FieldDefinition(7, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
[FieldDefinition(5, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(7, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -58,12 +58,12 @@ namespace NzbDrone.Core.Indexers.Torznab
[FieldDefinition(9)]
public SeedCriteriaSettings SeedCriteria { get; set; } = new ();
[FieldDefinition(10, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
[FieldDefinition(11, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
[FieldDefinition(10, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(11, Type = FieldType.Select, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", HelpLink = "https://wiki.servarr.com/radarr/settings#indexer-flags", Advanced = true)]
public IEnumerable<int> RequiredFlags { get; set; }
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -353,7 +353,6 @@
"IncludeUnmonitored": "تضمين غير مراقب",
"IncludeRecommendationsHelpText": "قم بتضمين أفلام {appName} الموصى بها في عرض الاكتشاف",
"IncludeRadarrRecommendations": "تضمين توصيات الرادار",
"IncludeHealthWarningsHelpText": "قم بتضمين التحذيرات الصحية",
"IncludeCustomFormatWhenRenamingHelpText": "تضمين في تنسيق إعادة تسمية {تنسيقات مخصصة}",
"IncludeCustomFormatWhenRenaming": "قم بتضمين تنسيق مخصص عند إعادة التسمية",
"InCinemasMsg": "الفيلم في دور السينما",

View File

@@ -813,7 +813,6 @@
"ICalFeedHelpText": "Копирайте този URL адрес на вашите клиенти или кликнете, за да се абонирате, ако браузърът ви поддържа webcal",
"Imported": "Внос",
"IllRestartLater": "Ще рестартирам по-късно",
"IncludeHealthWarningsHelpText": "Включете здравни предупреждения",
"Medium": "Среден",
"MinAvailability": "Минимална наличност",
"MinimumAge": "Минимална възраст",

View File

@@ -25,7 +25,7 @@
"LastWriteTime": "La darrera hora d'escriptura",
"LocalPath": "Camí local",
"Logs": "Registres",
"MinutesNinety": "90 minuts: {0}",
"MinutesNinety": "90 minuts: {ninety}",
"NoListRecommendations": "No s'han trobat elements de llista ni recomanacions; per a començar, podeu afegir una pel·lícula nova, importar-ne algunes existents o afegir una llista.",
"NotAvailable": "No disponible",
"PreferAndUpgrade": "Marca preferit i actualitza",
@@ -287,7 +287,7 @@
"MovieChat": "Xat de pel·lícula",
"MovieDetailsNextMovie": "Detalls de la pel·lícula: propera pel·lícula",
"MovieInvalidFormat": "Pel·lícula: Format no vàlid",
"NegateHelpText": "Si està marcat, el format personalitzat no s'aplicarà si la condició {0} coincideix.",
"NegateHelpText": "Si està marcat, el format personalitzat no s'aplicarà si la condició {implementationName} coincideix.",
"NetCore": ".NET",
"NoLeaveIt": "No, deixa-ho",
"TotalMovies": "Total de pel·lícules",
@@ -410,8 +410,8 @@
"Custom": "Personalitzat",
"CustomFilters": "Filtres personalitzats",
"CustomFormats": "Formats personalitzats",
"CustomFormatUnknownCondition": "Condició de format personalitzada desconeguda '{0}'",
"CustomFormatUnknownConditionOption": "Opció desconeguda '{0}' per a la condició '{1}'",
"CustomFormatUnknownCondition": "Condició de format personalitzada desconeguda '{implementation}'",
"CustomFormatUnknownConditionOption": "Opció desconeguda '{key}' per a la condició '{implementation}'",
"UpgradeUntilCustomFormatScoreMovieHelpText": "Un cop s'arribi a aquesta puntuació de format personalitzat, {appName} ja no baixarà pel·lícules",
"UpgradeUntilMovieHelpText": "Un cop s'assoleixi aquesta qualitat, {appName} ja no baixarà pel·lícules",
"Database": "Base de dades",
@@ -448,7 +448,7 @@
"DoNotPrefer": "No ho prefereixo",
"DoNotUpgradeAutomatically": "No actualitzeu automàticament",
"DownloadClientCheckDownloadingToRoot": "El client de baixada {downloadClientName} col·loca les baixades a la carpeta arrel {path}. No s'hauria de baixar a una carpeta arrel.",
"DownloadClientCheckUnableToCommunicateMessage": "No es pot comunicar amb {downloadClientName}.",
"DownloadClientCheckUnableToCommunicateMessage": "No es pot comunicar amb {downloadClientName}. {errorMessage}",
"DownloadClientsSettingsSummary": "Descàrrega de clients, gestió de descàrregues i mapes de camins remots",
"DownloadClientUnavailable": "El client de descàrrega no està disponible",
"Downloaded": "S'ha baixat",
@@ -531,7 +531,6 @@
"InCinemasMsg": "Estrena de pel·lícula",
"IncludeCustomFormatWhenRenaming": "Inclou el format personalitzat en canviar el nom",
"IncludeCustomFormatWhenRenamingHelpText": "Inclou en {Custom Formats} el format de canvi de nom",
"IncludeHealthWarningsHelpText": "Inclou advertències de salut",
"IncludeRecommendationsHelpText": "Inclou les pel·lícules recomanades per {appName} a la vista de descobriment",
"IndexerJackettAll": "Indexadors que utilitzen el punt final \"tot\" no compatible amb Jackett: {indexerNames}",
"IndexerLongTermStatusCheckAllClientMessage": "Tots els indexadors no estan disponibles a causa d'errors durant més de 6 hores",
@@ -559,7 +558,7 @@
"Links": "Enllaços",
"ImportListExclusions": "Llista d'exclusions",
"ImportLists": "Llistes",
"ImportListsSettingsSummary": "Importa llistes, exclusions de llista",
"ImportListsSettingsSummary": "Importa des d'una altra instància {appName} o llistes de Trakt i gestiona les exclusions de llistes",
"ListSyncLevelHelpText": "Les pel·lícules de la biblioteca es gestionaran en funció de la vostra selecció si cauen o no apareixen a les vostres llistes",
"ListSyncLevelHelpTextWarning": "Els fitxers de pel·lícules se suprimiran permanentment; això pot provocar que esborraràs la teva biblioteca si les teves llistes estan buides",
"ListTagsHelpText": "Els elements de la llista d'etiquetes s'afegiran amb",
@@ -598,8 +597,8 @@
"MinimumFreeSpace": "Espai lliure mínim",
"MinimumFreeSpaceHelpText": "Eviteu la importació si quedara menys d'aquesta quantitat d'espai disponible en disc",
"Minutes": "Minuts",
"MinutesHundredTwenty": "120 minuts: {0}",
"MinutesSixty": "60 minuts: {0}",
"MinutesHundredTwenty": "120 minuts: {hundredTwenty}",
"MinutesSixty": "60 minuts: {sixty}",
"Missing": "Absents",
"MonitorCollection": "Monitora col·leccions",
"MonitoredCollectionHelpText": "Monitora per a afegir automàticament pel·lícules d'aquesta col·lecció a la biblioteca",
@@ -716,7 +715,7 @@
"RefreshLists": "Actualitza llistes",
"RefreshMonitoredIntervalHelpText": "Amb quina freqüència s'actualitzen les baixades monitorades dels clients de descàrrega, mínim 1 minut",
"RefreshMovie": "Actualitza pel·lícula",
"RegularExpressionsCanBeTested": "Es poden provar expressions regulars ",
"RegularExpressionsCanBeTested": "Les expressions regulars es poden provar [aquí](http://regexstorm.net/tester).",
"RejectionCount": "Recompte de rebuigs",
"RelativePath": "Camí relatiu",
"ReleaseBranchCheckOfficialBranchMessage": "La branca {0} no és una branca de llançament de {appName} vàlida, no rebreu actualitzacions",
@@ -877,7 +876,7 @@
"Tomorrow": "Demà",
"TorrentDelay": "Retard del torrent",
"TorrentDelayHelpText": "Retard en minuts per a esperar abans de capturar un torrent",
"TorrentDelayTime": "Retard del torrent: {0}",
"TorrentDelayTime": "Retard del torrent: {torrentDelay}",
"Torrents": "Torrents",
"TorrentsDisabled": "Torrents desactivats",
"TotalFileSize": "Mida total del fitxer",
@@ -917,7 +916,7 @@
"UpdateCheckStartupNotWritableMessage": "L'actualització no es pot instal·lar perquè la carpeta d'inici '{startupFolder}' no té permisos d'escriptura per a l'usuari '{userName}'.",
"UpdateSelected": "Actualització seleccionada",
"UpdateCheckStartupTranslocationMessage": "No es pot instal·lar l'actualització perquè la carpeta d'inici \"{startupFolder}\" es troba en una carpeta de translocació d'aplicacions.",
"UpdateCheckUINotWritableMessage": "L'actualització no es pot instal·lar perquè la carpeta UI '{startupFolder}' no té permisos d'escriptura per a l'usuari '{userName}'.",
"UpdateCheckUINotWritableMessage": "L'actualització no es pot instal·lar perquè la carpeta UI '{uiFolder}' no té permisos d'escriptura per a l'usuari '{userName}'.",
"UpdateMechanismHelpText": "Utilitzeu l'actualitzador integrat de {appName} o un script",
"UpdateScriptPathHelpText": "Camí a un script personalitzat que pren un paquet d'actualització i gestiona la resta del procés d'actualització",
"UpgradesAllowedHelpText": "Si les qualitats estan desactivades no s'actualitzaran",
@@ -929,7 +928,7 @@
"UseHardlinksInsteadOfCopy": "Utilitzeu enllaços durs en lloc de copiar",
"Usenet": "Usenet",
"UsenetDelayHelpText": "Retard en minuts per esperar abans de capturar una versió d'Usenet",
"UsenetDelayTime": "Retard d'Usenet: {0}",
"UsenetDelayTime": "Retard d'Usenet: {usenetDelay}",
"UsenetDisabled": "Usenet desactivat",
"UseProxy": "Utilitzeu el servidor intermediari",
"Username": "Nom d'usuari",
@@ -994,7 +993,7 @@
"NoIssuesWithYourConfiguration": "No hi ha cap problema amb la configuració",
"HiddenClickToShow": "Amagat, feu clic per a mostrar",
"Max": "Màx",
"RequiredHelpText": "La condició {0} ha de coincidir perquè s'apliqui el format personalitzat. En cas contrari, n'hi ha prou amb una única coincidència de {1}.",
"RequiredHelpText": "La condició {implementationName} ha de coincidir perquè s'apliqui el format personalitzat. En cas contrari, n'hi ha prou amb una única coincidència de {implementationName}.",
"ShowTitle": "Mostra el títol",
"Ignored": "Ignorat",
"IgnoredAddresses": "Adreces ignorades",
@@ -1094,8 +1093,8 @@
"ApplyTagsHelpTextHowToApplyDownloadClients": "Com aplicar etiquetes als clients de baixada seleccionats",
"ApplyTagsHelpTextHowToApplyImportLists": "Com aplicar etiquetes a les llistes d'importació seleccionades",
"MoveAutomatically": "Mou automàticament",
"AutoTaggingNegateHelpText": "Si està marcat, el format personalitzat no s'aplicarà si la condició {0} coincideix.",
"AutoTaggingRequiredHelpText": "La condició {0} ha de coincidir perquè s'apliqui el format personalitzat. En cas contrari, n'hi ha prou amb una única coincidència de {0}.",
"AutoTaggingNegateHelpText": "Si està marcat, el format personalitzat no s'aplicarà si la condició {implementationName} coincideix.",
"AutoTaggingRequiredHelpText": "La condició {implementationName} ha de coincidir perquè s'apliqui el format personalitzat. En cas contrari, n'hi ha prou amb una única coincidència de {implementationName}.",
"DeleteAutoTagHelpText": "Esteu segur que voleu suprimir l'etiqueta '{name}'?",
"DeleteRootFolderMessageText": "Esteu segur que voleu suprimir la carpeta arrel '{path}'?",
"AddConnection": "Afegeix una connexió",
@@ -1113,7 +1112,7 @@
"GrabId": "Captura ID",
"OrganizeNothingToRename": "Èxit! La feina està acabada, no hi ha fitxers per a canviar el nom.",
"OrganizeLoadError": "S'ha produït un error en carregar les previsualitzacions",
"BlocklistReleaseHelpText": "Impedeix que {appName} torni a capturar aquesta versió automàticament",
"BlocklistReleaseHelpText": "Impedeix que {appName} baixi aquesta versió mitjançant RSS o cerca automàtica",
"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.",
"DelayingDownloadUntil": "S'està retardant la baixada fins al {date} a les {time}",
@@ -1127,7 +1126,7 @@
"TablePageSize": "Mida de la pàgina",
"TablePageSizeHelpText": "Nombre d'elements per mostrar a cada pàgina",
"MovieFileDeletedTooltip": "S'ha suprimit el fitxer de pel·lícula",
"RetryingDownloadOn": "S'està retardant la baixada fins a les {0} a les {1}",
"RetryingDownloadOn": "S'està retardant la baixada fins al {date} a les {time}",
"FormatAgeHours": "hores",
"FormatAgeMinute": "minut",
"FormatAgeMinutes": "minuts",
@@ -1202,7 +1201,7 @@
"FailedToUpdateSettings": "No s'ha pogut actualitzar la configuració",
"InteractiveImportNoImportMode": "S'ha de seleccionar un mode d'importació",
"InteractiveImportNoMovie": "S'ha de triar una pel·lícula triar per a cada fitxer seleccionat",
"InteractiveSearchResultsFailedErrorMessage": "La cerca ha fallat per {missatge}. Actualitza la informació de la pel·lícula i verifica que hi hagi la informació necessària abans de tornar a cercar.",
"InteractiveSearchResultsFailedErrorMessage": "La cerca ha fallat per {message}. Actualitza la informació de la pel·lícula i verifica que hi hagi la informació necessària abans de tornar a cercar.",
"LogFilesLocation": "Els fitxers de registre es troben a: {location}",
"ManageDownloadClients": "Gestiona els clients de descàrrega",
"MovieGrabbedHistoryTooltip": "Pel·lícula captura de {indexer} i enviada a {downloadClient}",
@@ -1211,7 +1210,7 @@
"FullColorEventsHelpText": "Estil alterat per a pintar tot l'esdeveniment amb el color d'estat, en lloc de només la vora esquerra. No s'aplica a l'Agenda",
"InteractiveImportNoFilesFound": "No s'ha trobat cap fitxer de vídeo a la carpeta seleccionada",
"InteractiveImportNoLanguage": "S'ha de triar l'idioma per a cada fitxer seleccionat",
"ListWillRefreshEveryInterval": "La llista s'actualitzarà cada {0}",
"ListWillRefreshEveryInterval": "La llista s'actualitzarà cada {refreshInterval}",
"MovieMatchType": "Tipus de concordança de pel·lícula",
"NoDownloadClientsFound": "No s'han trobat clients de baixada",
"NoIndexersFound": "No s'han trobat indexadors",
@@ -1289,5 +1288,54 @@
"Rejections": "Rebutjats",
"NotificationsPushoverSettingsExpire": "Venciment",
"NotificationsEmailSettingsServer": "Servidor",
"NotificationsSettingsWebhookMethod": "Mètode"
"NotificationsSettingsWebhookMethod": "Mètode",
"BlocklistAndSearch": "Llista de bloqueig i cerca",
"BlocklistAndSearchHint": "Comença una cerca per reemplaçar després d'haver bloquejat",
"AddDelayProfileError": "No s'ha pogut afegir un perfil realentit, torna-ho a probar",
"DoNotBlocklistHint": "Elimina sense afegir a la llista de bloqueig",
"DoNotBlocklist": "No afegiu a la llista de bloqueig",
"BlackholeWatchFolder": "Monitora la carpeta",
"BlackholeFolderHelpText": "Carpeta on {appName} emmagatzemarà els fitxers {extension}",
"BlocklistAndSearchMultipleHint": "Comença una cerca per reemplaçar després d'haver bloquejat",
"BlackholeWatchFolderHelpText": "Carpeta des de la qual {appName} hauria d'importar les baixades finalitzades",
"BlocklistMultipleOnlyHint": "Afegeix a la llista de bloqueig sense cercar substituts",
"BlocklistOnly": "Sols afegir a la llista de bloqueig",
"Category": "Categoria",
"ChangeCategoryHint": "Canvia la baixada a la \"Categoria post-importació\" des del client de descàrrega",
"Directory": "Directori",
"Destination": "Destinació",
"DownloadClientDelugeTorrentStateError": "Deluge està informant d'un error",
"ClickToChangeIndexerFlags": "Feu clic per canviar els indicadors de l'indexador",
"ConditionUsingRegularExpressions": "Aquesta condició coincideix amb expressions regulars. Tingueu en compte que els caràcters `\\^$.|?*+()[{` tenen significats especials i cal escapar amb un `\\`",
"Umask": "UMask",
"DownloadClientAriaSettingsDirectoryHelpText": "Ubicació opcional per a les baixades, deixeu-lo en blanc per utilitzar la ubicació predeterminada d'Aria2",
"AddAutoTagError": "No es pot afegir una etiqueta automàtica nova, torneu-ho a provar.",
"AddReleaseProfile": "Afegeix un perfil de llançament",
"ConnectionSettingsUrlBaseHelpText": "Afegeix un prefix a l'URL {connectionName}, com ara {url}",
"CustomFormatsSpecificationRegularExpression": "Expressió regular",
"CustomFormatsSpecificationRegularExpressionHelpText": "El format personalitzat RegEx no distingeix entre majúscules i minúscules",
"AddListExclusion": "Afegeix una llista d'exclusió",
"ChangeCategory": "Canvia categoria",
"AutoTaggingLoadError": "No es pot carregar l'etiquetatge automàtic",
"BlocklistOnlyHint": "Afegir a la llista de bloqueig sense cercar substituts",
"ChangeCategoryMultipleHint": "Canvia les baixades a la \"Categoria post-importació\" des del client de descàrrega",
"ChownGroup": "Canvia el grup propietari",
"Clone": "Clona",
"DelayMinutes": "{delay} Minuts",
"DelayProfileMovieTagsHelpText": "S'aplica a pel·lícules amb almenys una etiqueta coincident",
"DelayProfileProtocol": "Protocol: {preferredProtocol}",
"DeleteReleaseProfileMessageText": "Esteu segur que voleu suprimir el perfil de llançament '{name}'?",
"DeleteSpecification": "Esborra especificació",
"CutoffNotMet": "Tall no assolit",
"CustomFilter": "Filtres personalitzats",
"CustomFormatsSpecificationFlag": "Bandera",
"Dash": "Guió",
"DeleteSpecificationHelpText": "Esteu segur que voleu suprimir l'especificació '{name}'?",
"DownloadClientDelugeSettingsDirectory": "Directori de baixada",
"DownloadClientDelugeSettingsDirectoryCompleted": "Directori al qual es mou quan s'hagi completat",
"DownloadClientDelugeSettingsDirectoryCompletedHelpText": "Ubicació opcional de les baixades completades, deixeu-lo en blanc per utilitzar la ubicació predeterminada de Deluge",
"DownloadClientDelugeSettingsDirectoryHelpText": "Ubicació opcional de les baixades completades, deixeu-lo en blanc per utilitzar la ubicació predeterminada de Deluge",
"DeleteReleaseProfile": "Suprimeix el perfil de llançament",
"Donate": "Dona",
"DownloadClientDelugeSettingsUrlBaseHelpText": "Afegeix un prefix a l'url json del Deluge, vegeu {url}"
}

View File

@@ -212,7 +212,6 @@
"AddNewMessage": "Přidání nového filmu je snadné, stačí začít psát název filmu, který chcete přidat",
"AddNewMovie": "Přidat nový film",
"AddNewTmdbIdMessage": "Můžete také vyhledávat pomocí ID TMDb filmu. např. 'tmdb: 71663'",
"IncludeHealthWarningsHelpText": "Zahrnout zdravotní varování",
"AddListExclusionMovieHelpText": "Zabraňte přidávání filmů do {appName}u pomocí seznamů",
"ImportHeader": "Chcete-li přidat filmy do {appName}u, importujte existující organizovanou knihovnu",
"ImportListStatusCheckSingleClientMessage": "Seznamy nejsou k dispozici z důvodu selhání: {importListNames}",

View File

@@ -94,11 +94,11 @@
"Agenda": "Dagsorden",
"Age": "Alder",
"AddNewTmdbIdMessage": "Du kan også søge ved at bruge TMDB Id'et af en film. f.eks 'tmdb:71663'",
"AddNewMovie": "Tilføj Ny Film",
"AddNewMovie": "Tilføj ny film",
"AddNewMessage": "Det er nemt at tilføje en ny film, bare start ved at skrive navnet på filmen du vil tilføje",
"AddNew": "Tilføj Ny",
"AddMovies": "Tilføj Film",
"AddExclusion": "Tilføj Undtagelse",
"AddExclusion": "Tilføj undtagelse",
"Added": "Tilføjet",
"Activity": "Aktivitet",
"Actions": "Handlinger",
@@ -106,7 +106,7 @@
"AnalyseVideoFiles": "Analyser videofiler",
"System": "System",
"AutoRedownloadFailedHelpText": "Søg automatisk efter og forsøg at downloade en anden udgivelse",
"TestAllClients": "Test alle klienter",
"TestAllClients": "Afprøv alle klienter",
"UnableToLoadAltTitle": "Kan ikke indlæse alternative titler.",
"WhatsNew": "Hvad er nyt?",
"ProtocolHelpText": "Vælg hvilke protokol (r) du vil bruge, og hvilken der foretrækkes, når du vælger mellem ellers lige udgivelser",
@@ -198,7 +198,7 @@
"ChangeHasNotBeenSavedYet": "Ændring er endnu ikke gemt",
"CheckDownloadClientForDetails": "tjek download klient for flere detaljer",
"CheckForFinishedDownloadsInterval": "Kontroller for færdige downloadsinterval",
"AddIndexer": "Tilføj indeksør",
"AddIndexer": "Tilføj indekser",
"ChmodFolder": "chmod mappe",
"ChmodFolderHelpText": "Oktal, anvendt under import / omdøbning til mediemapper og filer (uden udførelse af bits)",
"ChmodFolderHelpTextWarning": "Dette fungerer kun, hvis den bruger, der kører {appName}, er ejeren af filen. Det er bedre at sikre, at downloadklienten indstiller tilladelserne korrekt.",
@@ -281,7 +281,6 @@
"CancelPendingTask": "Er du sikker på, at du vil annullere denne afventende opgave?",
"DeleteDownloadClient": "Slet Download Client",
"ImportIncludeQuality": "Sørg for, at dine filer inkluderer kvaliteten i deres filnavne. f.eks. {0}",
"IncludeHealthWarningsHelpText": "Inkluder sundhedsadvarsler",
"Max": "Maks.",
"Medium": "Medium",
"MovieFilesTotaling": "Totale filmfiler",
@@ -327,8 +326,8 @@
"ShowGenres": "Vis genrer",
"Size": "Størrelse",
"SuggestTranslationChange": "Foreslå ændring af oversættelsen",
"TestAllIndexers": "Test alle indeksører",
"TestAllLists": "Test alle lister",
"TestAllIndexers": "Afprøv alle indeks",
"TestAllLists": "Afprøv alle lister",
"Queued": "I kø",
"TMDb": "TMDb",
"Tomorrow": "I morgen",
@@ -392,7 +391,7 @@
"PortNumber": "Portnummer",
"UpgradesAllowedHelpText": "Hvis deaktiveret, vil kvalitet ikke vil blive opgraderet",
"PackageVersion": "Pakkeversion",
"AddMovie": "Tilføj Film",
"AddMovie": "Tilføj film",
"AddRestriction": "Tilføj begrænsning",
"Password": "Adgangskode",
"Path": "Sti",
@@ -831,7 +830,7 @@
"Style": "Stil",
"SubfolderWillBeCreatedAutomaticallyInterp": "Undermappen '{0}' oprettes automatisk",
"Sunday": "Søndag",
"Table": "Bord",
"Table": "Tabel",
"TableOptions": "Tabelindstillinger",
"TableOptionsColumnsMessage": "Vælg hvilke kolonner der er synlige og hvilken rækkefølge de vises i",
"TagDetails": "Tagdetaljer - {0}",
@@ -839,8 +838,8 @@
"Tags": "Mærker",
"ICalTagsMoviesHelpText": "Gælder film med mindst et matchende tag",
"Tasks": "Opgaver",
"Test": "Prøve",
"TestAll": "Test alle",
"Test": "Afprøv",
"TestAll": "Afprøv alle",
"TheLogLevelDefault": "Logniveauet er som standard 'Info' og kan ændres i",
"ThisCannotBeCancelled": "Dette kan ikke annulleres en gang startet uden genstart af {appName}.",
"Title": "Titel",
@@ -901,13 +900,13 @@
"UnmappedFolders": "Ikke-kortlagte mapper",
"Unmonitored": "Uovervåget",
"ICalIncludeUnmonitoredMoviesHelpText": "Inkluder ikke-overvågede film i iCal-feedet",
"Unreleased": "Ikke tilgængelig",
"Unreleased": "Ikke udgivet",
"UnsavedChanges": "Ugemte ændringer",
"UnselectAll": "Fravælg alle",
"UpdateAll": "Opdater alle",
"UpdateAutomaticallyHelpText": "Download og installer opdateringer automatisk. Du kan stadig installere fra System: Updates",
"UpdateCheckStartupTranslocationMessage": "Kan ikke installere opdatering, fordi startmappen '{startupFolder}' er i en App Translocation-mappe.",
"UpdateCheckUINotWritableMessage": "Kan ikke installere opdatering, fordi brugergrænsefladen \"{startupFolder}\" ikke kan skrives af brugeren \"{userName}\".",
"UpdateCheckUINotWritableMessage": "Kan ikke installere opdatering, fordi '{userName}' ikke kan skrive til mappen for brugergrænseflade '{uiFolder}'.",
"UpdateMechanismHelpText": "Brug {appName}s indbyggede opdatering eller et script",
"UpdateScriptPathHelpText": "Sti til et brugerdefineret script, der tager en udpakket opdateringspakke og håndterer resten af opdateringsprocessen",
"UpdateSelected": "Opdatering valgt",
@@ -993,5 +992,18 @@
"ApplyTagsHelpTextAdd": "Tilføj: Føj tags til den eksisterende liste over tags",
"ApplyTagsHelpTextHowToApplyIndexers": "Sådan anvendes tags på de valgte film",
"DeleteSelectedDownloadClients": "Slet Download Client",
"DeleteSelectedIndexers": "Slet Indexer"
"DeleteSelectedIndexers": "Slet Indexer",
"AnnouncedMsg": "Film er annonceret",
"AddConditionImplementation": "Tilføj betingelse - {implementationName}",
"AddConnection": "Tilføj forbindelse",
"AddConnectionImplementation": "Tilføj forbindelse - {implementationName}",
"AddImportList": "Tilføj importliste",
"AddDownloadClientImplementation": "Tilføj downloadklient - {implementationName}",
"AddImportListImplementation": "Tilføj importliste - {implementationName}",
"ApplyChanges": "Anvend ændringer",
"AddCondition": "Tilføj betingelse",
"AllTitles": "All titler",
"TablePageSize": "Sidestørrelse",
"AddRootFolderError": "Kunne ikke tilføje rodmappe",
"Unknown": "Ukendt"
}

View File

@@ -19,7 +19,7 @@
"CompletedDownloadHandling": "Download-Handhabung abgeschlossen",
"Connect": "Verbinden",
"Connections": "Verbindungen",
"Crew": "Besatzung",
"Crew": "Besetzung",
"CustomFilters": "Benutzerdefinierte Filter",
"CustomFormats": "Eigene Formate",
"Date": "Datum",
@@ -149,7 +149,7 @@
"Language": "Sprache",
"MediaManagementSettingsSummary": "Einstellungen für Bennenung und Dateiverwaltung",
"Year": "Jahr",
"Wanted": " Gesucht",
"Wanted": "Gesucht",
"UpdateSelected": "Auswahl aktualisieren",
"UiSettingsSummary": "Einstellungen für Kalender, Datumsformat und Farbbeeinträchtigung",
"Timeleft": "Restzeit",
@@ -386,7 +386,6 @@
"ImportMovies": "Filme importieren",
"IncludeCustomFormatWhenRenaming": "Eigenes Format beim umbennen einfügen",
"IncludeCustomFormatWhenRenamingHelpText": "In {Custom Formats} umbennenungs Format",
"IncludeHealthWarningsHelpText": "Zustandswarnung",
"IncludeUnmonitored": "Nicht beobachtete einbeziehen",
"IndexerFlags": "Indexer-Flags",
"Interval": "Intervall",
@@ -624,16 +623,16 @@
"DownloadClientUnavailable": "Downloader ist nicht verfügbar",
"DeleteTagMessageText": "Sind Sie sicher, dass Sie das Tag „{label}“ löschen möchten?",
"DeleteRestrictionHelpText": "Beschränkung '{0}' wirklich löschen?",
"DeleteNotificationMessageText": "Sind Sie sicher, dass Sie die Benachrichtigung {name}“ löschen möchten?",
"DeleteIndexerMessageText": "Sind Sie sicher, dass Sie den Indexer {name}“ löschen möchten?",
"DeleteDownloadClientMessageText": "Sind Sie sicher, dass Sie den Download-Client {name} löschen möchten?",
"DeleteBackupMessageText": "Sind Sie sicher, dass Sie die Sicherung „{name}“ löschen möchten?",
"DeleteNotificationMessageText": "Bist du sicher, dass du die Benachrichtigung '{name}' wirklich löschen willst?",
"DeleteIndexerMessageText": "Bist du sicher, dass du den Indexer '{name}' wirklich löschen willst?",
"DeleteDownloadClientMessageText": "Bist du sicher, dass du den Download Client '{name}' wirklich löschen willst?",
"DeleteBackupMessageText": "Soll das Backup '{name}' wirklich gelöscht werden?",
"Cutoff": "Schwelle",
"ClickToChangeMovie": "Klicken um den Film zu bearbeiten",
"CheckDownloadClientForDetails": "Weitere Informationen finden Sie im Download-Client",
"CancelPendingTask": "Möchten Sie diese ausstehende Aufgabe wirklich abbrechen?",
"BranchUpdateMechanism": "Git-Branch für den externen Updateablauf",
"BranchUpdate": "Verwendeter Git-Branch für Aktualisierungen",
"BranchUpdate": "Branch, der verwendet werden soll, um {appName} zu updaten",
"BeforeUpdate": "Vor dem Update",
"AddingTag": "Tag hinzufügen",
"YouCanAlsoSearch": "Es kann auch nach der TMDb oder IMDb ID eines Filmes gesucht werden. Z.B.: 'tmdb:71663'",
@@ -926,10 +925,10 @@
"AllMoviesInPathHaveBeenImported": "Alle Filme in {path} wurden importiert",
"AllFiles": "Alle Dateien",
"AfterManualRefresh": "Nach manueller Aktualisierung",
"AddToDownloadQueue": "Zur Download-Warteschlange hinzufügen",
"AddToDownloadQueue": "Zur Download Warteschlange hinzufügen",
"AddRootFolder": "Stammverzeichnis hinzufügen",
"AddQualityProfile": "Qualitäts Profil hinzufügen",
"AddedToDownloadQueue": "Zur Download-Warteschlange hinzugefügt",
"AddedToDownloadQueue": "Zur Download Warteschlange hinzugefügt",
"AddDownloadClient": "Downloadmanager hinzufügen",
"AddCustomFormat": "Eigenes Format hinzufügen",
"AddDelayProfile": "Verzögerungsprofil hinzufügen",
@@ -1080,7 +1079,7 @@
"RemoveSelectedItemsQueueMessageText": "Bist du sicher, dass du {selectedCount} Einträge aus der Warteschlange entfernen willst?",
"ResetDefinitionTitlesHelpText": "Definitionstitel und -werte zurücksetzen",
"DeleteConditionMessageText": "Bist du sicher, dass du die Bedingung '{0}' löschen willst?",
"DeleteCustomFormatMessageText": "Bist du sicher, dass du das eigene Format '{name}' löschen willst?",
"DeleteCustomFormatMessageText": "Bist du sicher, dass du das benutzerdefinierte Format '{name}' wirklich löschen willst?",
"DeleteDelayProfileMessageText": "Sind Sie sicher, dass Sie dieses Verzögerungsprofil löschen möchten?",
"DeleteFormatMessageText": "Bist du sicher, dass du das Formatierungstag {0} löschen willst?",
"ResetAPIKeyMessageText": "Sind Sie sicher, dass Sie Ihren API-Schlüssel zurücksetzen möchten?",
@@ -1110,24 +1109,24 @@
"NoImportListsFound": "Keine Einspiel-Listen gefunden",
"NoIndexersFound": "Keine Indexer gefunden",
"CountIndexersSelected": "{count} Indexer ausgewählt",
"ApplyTagsHelpTextAdd": "Hinzufügen: Fügen Sie die Tags der vorhandenen Tag-Liste hinzu",
"ApplyTagsHelpTextRemove": "Entfernen: Die eingegebenen Tags entfernen",
"ApplyTagsHelpTextHowToApplyIndexers": "So wenden Sie Tags auf die ausgewählten Indexer an",
"ApplyTagsHelpTextReplace": "Ersetzen: Ersetzen Sie die Tags durch die eingegebenen Tags (geben Sie keine Tags ein, um alle Tags zu löschen).",
"ApplyTagsHelpTextAdd": "Hinzufügen: Füge Tags zu den bestehenden Tags hinzu",
"ApplyTagsHelpTextRemove": "Entfernen: Entferne die hinterlegten Tags",
"ApplyTagsHelpTextHowToApplyIndexers": "Wie Tags zu den selektierten Indexern hinzugefügt werden können",
"ApplyTagsHelpTextReplace": "Ersetzen: Ersetze die Tags mit den eingegebenen Tags (keine Tags eingeben um alle Tags zu löschen)",
"DeleteImportList": "Importliste löschen",
"DeleteImportListMessageText": "Sind Sie sicher, dass Sie die Liste {name}“ löschen möchten?",
"DeleteQualityProfileMessageText": "Sind Sie sicher, dass Sie das Qualitätsprofil {name}“ löschen möchten?",
"DeleteImportListMessageText": "Bist du sicher, dass du die Liste '{name}' wirklich löschen willst?",
"DeleteQualityProfileMessageText": "Bist du sicher, dass du das Qualitätsprofil '{name}' wirklich löschen willst?",
"RemoveQueueItemConfirmation": "Bist du sicher, dass du {0} Einträge aus der Warteschlange entfernen willst?",
"SkipRedownload": "Überspringe erneuten Download",
"MoveAutomatically": "Automatisch verschieben",
"AutoTaggingNegateHelpText": "Wenn aktiviert wird das eigene Format nicht angewendet solange diese {0} Bedingung zutrifft.",
"AutoTaggingRequiredHelpText": "Diese {0} Bedingungen müsen zutreffen damit das eigene Format zutrifft. Ansonsten reicht ein einzelner {1} Treffer.",
"AutoTaggingNegateHelpText": "Falls aktiviert wird die Auto Tagging Regel nicht angewendet, solange diese Bedingung {implementationName} zutrifft.",
"AutoTaggingRequiredHelpText": "Diese {0} Bedingungen müssen erfüllt sein, damit das eigene Format zutrifft. Ansonsten reicht ein einzelner {1} Treffer.",
"DeleteAutoTagHelpText": "Sind Sie sicher, dass Sie das automatische Tag „{name}“ löschen möchten?",
"DeleteSelectedDownloadClientsMessageText": "Sind Sie sicher, dass Sie {count} ausgewählte Download-Clients löschen möchten?",
"DeleteSelectedImportListsMessageText": "Sind Sie sicher, dass Sie {count} ausgewählte Importliste(n) löschen möchten?",
"DeleteSelectedIndexersMessageText": "Sind Sie sicher, dass Sie {count} ausgewählte(n) Indexer löschen möchten?",
"ApplyTagsHelpTextHowToApplyDownloadClients": "So wenden Sie Tags auf die ausgewählten Download-Clients an",
"ApplyTagsHelpTextHowToApplyImportLists": "So wenden Sie Tags auf die ausgewählten Importlisten an",
"ApplyTagsHelpTextHowToApplyDownloadClients": "Wie Tags zu den selektierten Downloadclients hinzugefügt werden können",
"ApplyTagsHelpTextHowToApplyImportLists": "Wie Tags den selektierten Importlisten hinzugefügt werden können",
"DeleteRootFolderMessageText": "Sind Sie sicher, dass Sie den Stammordner „{path}“ löschen möchten?",
"DeleteRootFolder": "Stammordner löschen",
"AddConnection": "Verbindung hinzufügen",
@@ -1203,5 +1202,23 @@
"Unmonitored": "Nicht beobachtet",
"DownloadClientFreeboxUnableToReachFreebox": "Die Freebox-API kann nicht erreicht werden. Überprüfen Sie die Einstellungen „Host“, „Port“ oder „SSL verwenden“. (Fehler: {exceptionMessage})",
"DownloadClientDownloadStationValidationNoDefaultDestinationDetail": "Sie müssen sich bei Ihrer Diskstation als {username} anmelden und sie manuell in den DownloadStation-Einstellungen unter BT/HTTP/FTP/NZB -> Standort einrichten.",
"UsenetBlackhole": "Usenet Blackhole"
"UsenetBlackhole": "Usenet Blackhole",
"BlocklistAndSearch": "Sperrliste und Suche",
"BlocklistAndSearchHint": "Starte Suche nach einer Alternative, falls es der Sperrliste hinzugefügt wurde",
"BlocklistMultipleOnlyHint": "Der Sperrliste hinzufügen, ohne nach Alternativen zu suchen",
"ChangeCategory": "Kategorie wechseln",
"BlackholeFolderHelpText": "Ordner, in dem {appName} die Datei {extension} speichert",
"BlackholeWatchFolderHelpText": "Der Ordner, aus dem {appName} fertige Downloads importieren soll",
"BlocklistAndSearchMultipleHint": "Starte Suchen nach einer Alternative, falls es der Sperrliste hinzugefügt wurde",
"BlocklistOnly": "Nur der Sperrliste hinzufügen",
"Category": "Kategorie",
"ClickToChangeIndexerFlags": "Klicken, um Indexer-Flags zu ändern",
"AddReleaseProfile": "Release Profil hinzufügen",
"BlocklistReleaseHelpText": "Dieses Release für erneuten Download durch {appName} via RSS oder automatische Suche sperren",
"AddListExclusion": "Listenausschluss hinzufügen",
"ChownGroup": "chown Gruppe",
"Clone": "Klonen",
"BlocklistOnlyHint": "Der Sperrliste hinzufügen, ohne nach Alternative zu suchen",
"AddAutoTagError": "Auto-Tag konnte nicht hinzugefügt werden. Bitte erneut versuchen.",
"AddDelayProfileError": "Verzögerungsprofil konnte nicht hinzugefügt werden. Bitte erneut versuchen."
}

View File

@@ -240,7 +240,6 @@
"ExcludeTitle": "Εξαίρεση {0}; Αυτό θα αποτρέψει την αυτόματη προσθήκη του {appName} μέσω συγχρονισμού λίστας.",
"FileNameTokens": "Διακριτικά ονόματος αρχείου",
"ImportMechanismHealthCheckMessage": "Ενεργοποίηση ολοκληρωμένου χειρισμού λήψεων",
"IncludeHealthWarningsHelpText": "Συμπεριλάβετε προειδοποιήσεις για την υγεία",
"InvalidFormat": "Ακυρη μορφή",
"LastDuration": "Τελευταία Διάρκεια",
"LastExecution": "Τελευταία εκτέλεση",

View File

@@ -113,6 +113,7 @@
"AutoTaggingLoadError": "Unable to load auto tagging",
"AutoTaggingNegateHelpText": "If checked, the auto tagging rule will not apply if this {implementationName} condition matches.",
"AutoTaggingRequiredHelpText": "This {implementationName} condition must match for the auto tagging rule to apply. Otherwise a single {implementationName} match is sufficient.",
"AutoTaggingSpecificationTag": "Tag",
"AutoUnmonitorPreviouslyDownloadedMoviesHelpText": "Movies deleted from the disk are automatically unmonitored in {appName}",
"Automatic": "Automatic",
"AutomaticAdd": "Automatic Add",
@@ -258,6 +259,7 @@
"CustomFormatsLoadError": "Unable to load Custom Formats",
"CustomFormatsSettings": "Custom Formats Settings",
"CustomFormatsSettingsSummary": "Custom Formats and Settings",
"CustomFormatsSettingsTriggerInfo": "A Custom Format will be applied to a release or file when it matches at least one of each of the different condition types chosen.",
"CustomFormatsSpecificationFlag": "Flag",
"CustomFormatsSpecificationRegularExpression": "Regular Expression",
"CustomFormatsSpecificationRegularExpressionHelpText": "Custom Format RegEx is Case Insensitive",
@@ -341,7 +343,7 @@
"DeleteTheMovieFolder": "The movie folder '{path}' and all its content will be deleted.",
"Deleted": "Deleted",
"DeletedMsg": "Movie was deleted from TMDb",
"DeletedReasonManual": "File was deleted by via UI",
"DeletedReasonManual": "File was deleted using {appName}, either manually or by another tool through the API",
"DeletedReasonMissingFromDisk": "{appName} was unable to find the file on disk so the file was unlinked from the movie in the database",
"DeletedReasonUpgrade": "File was deleted to import an upgrade",
"Destination": "Destination",
@@ -725,7 +727,7 @@
"InCinemasMsg": "Movie is in Cinemas",
"IncludeCustomFormatWhenRenaming": "Include Custom Format when Renaming",
"IncludeCustomFormatWhenRenamingHelpText": "Include in {Custom Formats} renaming format",
"IncludeHealthWarningsHelpText": "Include Health Warnings",
"IncludeHealthWarnings": "Include Health Warnings",
"IncludeRadarrRecommendations": "Include {appName} Recommendations",
"IncludeRecommendationsHelpText": "Include {appName} recommended movies in discovery view",
"IncludeUnmonitored": "Include Unmonitored",
@@ -745,6 +747,8 @@
"IndexerSearchCheckNoAvailableIndexersMessage": "All search-capable indexers are temporarily unavailable due to recent indexer errors",
"IndexerSearchCheckNoInteractiveMessage": "No indexers available with Interactive Search enabled, {appName} will not provide any interactive search results",
"IndexerSettings": "Indexer Settings",
"IndexerSettingsMultiLanguageRelease": "Multi Languages",
"IndexerSettingsMultiLanguageReleaseHelpText": "What languages are normally in a multi release on this indexer?",
"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.",
"IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures",
@@ -1139,6 +1143,8 @@
"NotificationsTelegramSettingsBotToken": "Bot Token",
"NotificationsTelegramSettingsChatId": "Chat ID",
"NotificationsTelegramSettingsChatIdHelpText": "You must start a conversation with the bot or add it to your group to receive messages",
"NotificationsTelegramSettingsIncludeAppName": "Include {appName} in Title",
"NotificationsTelegramSettingsIncludeAppNameHelpText": "Optionally prefix message title with {appName} to differentiate notifications from different applications",
"NotificationsTelegramSettingsSendSilently": "Send Silently",
"NotificationsTelegramSettingsSendSilentlyHelpText": "Sends the message silently. Users will receive a notification with no sound",
"NotificationsTelegramSettingsTopicId": "Topic ID",
@@ -1334,7 +1340,7 @@
"ReleaseGroups": "Release Groups",
"ReleaseHash": "Release Hash",
"ReleaseProfileIndexerHelpText": "Specify what indexer the profile applies to",
"ReleaseProfileIndexerHelpTextWarning": "Using a specific indexer with release profiles can lead to duplicate releases being grabbed",
"ReleaseProfileIndexerHelpTextWarning": "Setting a specific indexer on a release profile will cause this profile to only apply to releases from that indexer.",
"ReleaseProfileTagMovieHelpText": "Release profiles will apply to movies with at least one matching tag. Leave blank to apply to all movies",
"ReleaseProfiles": "Release Profiles",
"ReleaseProfilesLoadError": "Unable to load Release Profiles",

View File

@@ -164,7 +164,7 @@
"QualitySettingsSummary": "Tamaños de calidad y nombrado",
"Protocol": "Protocolo",
"Progress": "Progreso",
"ProfilesSettingsSummary": "Calidad, Idioma y Perfiles de retraso",
"ProfilesSettingsSummary": "Calidad, idioma, retraso y perfiles de lanzamiento",
"PhysicalRelease": "Estreno Físico",
"OutputPath": "Ruta de salida",
"MovieTitle": "Título de la Película",
@@ -320,7 +320,7 @@
"DeleteRestriction": "Borrar Restricción",
"DeleteQualityProfile": "Borrar perfil de calidad",
"DeleteNotification": "Borrar Notificacion",
"DeleteIndexer": "Borrar Indexer",
"DeleteIndexer": "Borrar indexador",
"DeleteImportListExclusion": "Eliminar exclusión de listas de importación",
"DeleteFile": "Borrar archivo",
"DeleteEmptyFoldersHelpText": "Borrar carpetas vacías durante la exploración del disco y cuando se eliminen archivos",
@@ -452,7 +452,7 @@
"RescanMovieFolderAfterRefresh": "Reescanear la Carpeta de Películas después de Actualizar",
"RescanAfterRefreshHelpTextWarning": "{appName} no detectará automáticamente cambios en los archivos si no se elige 'Siempre'",
"RescanAfterRefreshMovieHelpText": "Reescanear la carpeta de películas después de actualizar la película",
"RequiredHelpText": "Esta condición {0} ha de igualar al formato propio para aplicarse. Si no, una sóla {1} es suficiente.",
"RequiredHelpText": "Esta condición {implementationName} debe coincidir con el formato personalizado para aplicarse. De otro modo, una simple coincidencia {implementationName} es suficiente.",
"ReplaceIllegalCharactersHelpText": "Reemplaza los caracteres ilegales. Si no está marcado, {appName} los eliminará en su lugar",
"ReplaceIllegalCharacters": "Reemplazar caracteres ilegales",
"Reorder": "Reordenar",
@@ -544,7 +544,6 @@
"IndexerSettings": "Ajustes de Indexer",
"IndexerFlags": "Banderas del indexador",
"IncludeUnmonitored": "Incluir sin monitorizar",
"IncludeHealthWarningsHelpText": "Incluir Alertas de Salud",
"IncludeCustomFormatWhenRenamingHelpText": "Incluir en formato de renombrado {Custom Formats}",
"IncludeCustomFormatWhenRenaming": "Incluir formato personalizado cuando se renombra",
"ImportMovies": "Importar Películas",
@@ -558,7 +557,7 @@
"IgnoredAddresses": "Direcciones Ignoradas",
"IconForCutoffUnmet": "Icono de Corte no alcanzado",
"ICalFeedHelpText": "Copia esta URL a tu gestor(es) o haz click en subscribir si tu navegador soporta webcal",
"ICalFeed": "iCal Feed",
"ICalFeed": "Feed de iCal",
"Hostname": "Nombre del Host",
"EnableSsl": "Habilitar SSL",
"EnableRss": "Habilitar RSS",
@@ -599,7 +598,7 @@
"Pending": "Pendiente",
"Paused": "Pausado",
"NegateHelpText": "Si se marca, el formato personalizado no se aplica si coincide la condición {implementationName}.",
"MoviesSelectedInterp": "{0} Película(s) Seleccionada(s)",
"MoviesSelectedInterp": "{count} película(s) seleccionada(s)",
"MovieIsUnmonitored": "La película no está monitoreada",
"MovieIsMonitored": "La película está monitoreada",
"MovieExcludedFromAutomaticAdd": "Película Excluida de Adición Automática",
@@ -628,7 +627,7 @@
"DeleteNotificationMessageText": "¿Seguro que quieres eliminar la notificación '{name}'?",
"DeleteBackupMessageText": "Seguro que quieres eliminar la copia de seguridad '{name}'?",
"DeleteDownloadClientMessageText": "Seguro que quieres eliminar el gestor de descargas '{name}'?",
"DeleteIndexerMessageText": "Seguro que quieres eliminar el indexer '{name}'?",
"DeleteIndexerMessageText": "¿Estás seguro que quieres eliminar el indexador '{name}'?",
"Cutoff": "Umbral",
"ClickToChangeMovie": "Clic para cambiar película",
"CheckDownloadClientForDetails": "Revisar el cliente de descarga para más detalles",
@@ -640,7 +639,7 @@
"SupportedCustomConditions": "{appName} soporta condiciones personalizadas para las siguientes propiedades de lanzamiento.",
"YouCanAlsoSearch": "También puedes buscar usando la ID de TMDb o la ID de IMDb de una película. ej. `tmdb:71663`",
"VisitTheWikiForMoreDetails": "Visita la wiki para más detalles: ",
"Unreleased": "Inédito",
"Unreleased": "Sin estrenar",
"UiSettingsLoadError": "No se pudo cargar las opciones de interfaz",
"CalendarLoadError": "No se ha podido cargar el calendario",
"UnableToLoadRootFolders": "No se han podido cargar las carpetas raiz",
@@ -664,7 +663,7 @@
"TagIsNotUsedAndCanBeDeleted": "La etiqueta no se usa y puede ser borrada",
"StartTypingOrSelectAPathBelow": "Comienza a escribir o selecciona una ruta debajo",
"Restore": "Restaurar",
"RegularExpressionsCanBeTested": "Las expresiones regulares se pueden testear ",
"RegularExpressionsCanBeTested": "Las expresiones regulares pueden ser probadas [aquí](http://regexstorm.net/tester).",
"SupportedListsMovie": "{appName} soporta cualquier lista RSS de películas, como también la listada debajo.",
"SupportedIndexers": "{appName} soporta cualquier indexador que use el estándar Newznab, así como otros indexadores listados a continuación.",
"SupportedDownloadClients": "{appName} soporta muchos torrent populares y clientes de descarga de usenet.",
@@ -677,8 +676,8 @@
"MissingNotMonitored": "No encontrada (No Monitoreada)",
"MissingMonitoredAndConsideredAvailable": "No encontrada (Monitoreada)",
"MinutesSixty": "60 minutos: {sixty}",
"MinutesNinety": "90 Minutos: {0}",
"MinutesHundredTwenty": "120 Minutos: {0}",
"MinutesNinety": "90 Minutos: {ninety}",
"MinutesHundredTwenty": "120 Minutos: {hundredTwenty}",
"MaintenanceRelease": "Lanzamiento de mantenimiento: Corrección de errores y otras mejoras. Ver historial de commits de Github para mas detalle",
"LoadingMovieFilesFailed": "La carga de los archivos ha fallado",
"LoadingMovieExtraFilesFailed": "La carga de los extras de la película ha fallado",
@@ -712,8 +711,8 @@
"DownloadPropersAndRepacksHelpTextCustomFormat": "Usar \"No Preferir\" para ordenar por puntuación de palabras preferidas en vez de proper/repacks",
"DownloadPropersAndRepacksHelpText": "Decidir si automaticamente actualizar a Propers/Repacks",
"DownloadPropersAndRepacks": "Propers y repacks",
"CustomFormatUnknownConditionOption": "Opción Desconocida '{0}' para condición '{1}'",
"CustomFormatUnknownCondition": "Condición de Formato Personalizado Desconocida '{0}'",
"CustomFormatUnknownConditionOption": "Opción Desconocida '{key}' para condición '{implementation}'",
"CustomFormatUnknownCondition": "Condición de Formato Personalizado Desconocida '{implementation}'",
"Priority": "Prioridad",
"InteractiveSearch": "Búsqueda Interactiva",
"IndexerPriorityHelpText": "Prioridad del Indexador de 1 (la más alta) a 50 (la más baja). Por defecto: 25. Usada para desempatar lanzamientos iguales cuando se capturan, {appName} seguirá usando todos los indexadores habilitados para Sincronización de RSS y Búsqueda",
@@ -885,7 +884,7 @@
"Negate": "Negar",
"Negated": "Anulado",
"NoListRecommendations": "No se encontraron elementos de lista ni recomendaciones; para comenzar, querrá agregar una nueva película, importar algunas existentes o agregar una lista.",
"OrganizeConfirm": "¿Está seguro de que desea organizar todos los archivos de las {0} películas seleccionadas?",
"OrganizeConfirm": "¿Estás seguro que quieres organizar todos los archivos en las {count} película(s) seleccionada(s)?",
"OrganizeSelectedMovies": "Organizar películas seleccionadas",
"PhysicalReleaseDate": "Fecha de lanzamiento físico",
"PreferAndUpgrade": "Preferir y actualizar",
@@ -1075,7 +1074,7 @@
"ApplyTagsHelpTextRemove": "Eliminar: Elimina las etiquetas introducidas",
"ApplyTagsHelpTextReplace": "Reemplazar: Sustituye las etiquetas por las introducidas (introduce \"no tags\" para borrar todas las etiquetas)",
"DeleteSelectedDownloadClients": "Borrar Cliente de Descarga(s)",
"DeleteSelectedIndexers": "Borrar indexer(s)",
"DeleteSelectedIndexers": "Borrar indexador(es)",
"ApplyChanges": "Aplicar Cambios",
"AddAutoTag": "Añadir Etiqueta Automática",
"AddCondition": "Añadir Condición",
@@ -1161,7 +1160,7 @@
"AppUpdatedVersion": "{appName} ha sido actualizado a la versión `{version}`, para obtener los cambios más recientes, necesitará recargar {appName}",
"DeleteSelectedIndexersMessageText": "¿Está seguro de querer eliminar {count} indexador(es) seleccionado(s)?",
"DisabledForLocalAddresses": "Deshabilitado para Direcciones Locales",
"DeletedReasonManual": "El archivo fue borrado por vía UI",
"DeletedReasonManual": "El archivo fue eliminado usando {appName}, o bien manualmente o por otra herramienta a través de la API",
"DeletedReasonMissingFromDisk": "{appName} no ha podido encontrar el archivo en el disco, por lo que se ha desvinculado de la película en la base de datos",
"DeletedReasonUpgrade": "Se ha borrado el archivo para importar una versión mejorada",
"DeleteSelectedMovieFilesHelpText": "¿Está seguro de que desea eliminar los archivos de película seleccionados?",
@@ -1173,7 +1172,7 @@
"ClearBlocklistMessageText": "¿Estás seguro de que quieres borrar todos los elementos de la lista de bloqueos?",
"ClientPriority": "Prioridad del Cliente",
"ColonReplacement": "Reemplazar dos puntos",
"CloneIndexer": "Clonar Indexer",
"CloneIndexer": "Clonar indexador",
"CompletedDownloadHandling": "Manipulación de descargas completas",
"CopyToClipboard": "Copiar al portapapeles",
"CloneCustomFormat": "Clonar formato personalizado",
@@ -1484,7 +1483,6 @@
"PendingDownloadClientUnavailable": "Pendiente - El cliente de descarga no está disponible",
"PreviouslyInstalled": "Previamente instalado",
"Rejections": "Rechazos",
"ReleaseProfileIndexerHelpTextWarning": "Usar un indexador específico con perfiles de lanzamientos puede conllevar que lanzamientos duplicados sean capturados",
"RestartRequiredToApplyChanges": "{appName} requiere reiniciar para aplicar cambios. ¿Quieres reiniciar ahora?",
"RestartLater": "Reiniciaré más tarde",
"OptionalName": "Nombre opcional",
@@ -1552,5 +1550,206 @@
"ConnectionSettingsUrlBaseHelpText": "Añade un prefijo a la url {connectionName}, como {url}",
"NotificationsSignalSettingsPasswordHelpText": "Contraseña usada para autenticar solicitudes hacia signal-api",
"NotificationsValidationUnableToSendTestMessage": "No se pudo enviar un mensaje de prueba: {exceptionMessage}",
"NotificationsJoinSettingsDeviceIdsHelpText": "En desuso, usar Nombres de dispositivo en su lugar. Lista separada por coma de los IDs de dispositivo a los que te gustaría enviar notificaciones. Si no se establece, todos los dispositivos recibirán notificaciones."
"NotificationsJoinSettingsDeviceIdsHelpText": "En desuso, usar Nombres de dispositivo en su lugar. Lista separada por coma de los IDs de dispositivo a los que te gustaría enviar notificaciones. Si no se establece, todos los dispositivos recibirán notificaciones.",
"Destination": "Destino",
"DownloadClientFloodSettingsAdditionalTags": "Etiquetas adicionales",
"DownloadClientFreeboxSettingsApiUrlHelpText": "Define la URL base de la API Freebox con la versión de la API, p. ej. '{url}', por defecto a '{defaultApiUrl}'",
"DownloadClientFreeboxSettingsAppToken": "Token de la app",
"DownloadClientFloodSettingsAdditionalTagsHelpText": "Añade propiedades de medios como etiquetas. Los consejos son ejemplos.",
"DownloadClientFloodSettingsUrlBaseHelpText": "Añade un prefijo a la API de Flood, como {url}",
"DownloadClientFreeboxSettingsApiUrl": "URL de API",
"DownloadClientFreeboxSettingsAppId": "ID de la app",
"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.",
"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",
"DownloadClientFreeboxSettingsAppTokenHelpText": "Token de la app recuperado cuando se crea acceso a la API de Freebox (esto es 'app_token')",
"Directory": "Directorio",
"Donate": "Donar",
"DownloadClientDelugeSettingsUrlBaseHelpText": "Añade un prefijo al url del json de deluge, vea {url}",
"DownloadClientFreeboxSettingsPortHelpText": "Puerto usado para acceder a la interfaz de Freebox, predeterminado a '{port}'",
"DownloadClientPneumaticSettingsStrmFolder": "Carpeta de Strm",
"DownloadClientPneumaticSettingsNzbFolderHelpText": "Esta carpeta necesitará ser alcanzable desde XBMC",
"DownloadClientPneumaticSettingsStrmFolderHelpText": "Los archivos .strm en esta carpeta será importados por drone",
"DownloadClientQbittorrentSettingsFirstAndLastFirst": "Primeras y últimas primero",
"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.",
"DownloadClientRTorrentSettingsUrlPath": "Ruta de url",
"DownloadClientTransmissionSettingsDirectoryHelpText": "Ubicación opcional en la que poner las descargas, dejar en blanco para usar la ubicación predeterminada de Transmission",
"DownloadClientFreeboxSettingsHostHelpText": "Nombre de host o dirección IP de host del Freebox, predeterminado a '{url}' (solo funcionará en la misma red)",
"DownloadClientQbittorrentSettingsFirstAndLastFirstHelpText": "Descarga primero las primeras y últimas piezas (qBittorrent 4.1.0+)",
"DownloadClientPneumaticSettingsNzbFolder": "Carpeta de Nzb",
"DownloadClientQbittorrentSettingsSequentialOrder": "Orden secuencial",
"DownloadClientRTorrentSettingsAddStopped": "Añadir detenido",
"DownloadClientRTorrentSettingsAddStoppedHelpText": "Permite añadir torrents y magnets a rTorrent en estado detenido. Esto puede romper los archivos magnet.",
"DownloadClientSettingsAddPaused": "Añadir pausado",
"DownloadClientSettingsInitialStateHelpText": "Estado inicial para torrents añadidos a {clientName}",
"DownloadClientTransmissionSettingsUrlBaseHelpText": "Añade un prefijo a la url rpc de {clientName}, p. ej. {url}, predeterminado a '{defaultUrl}'",
"Menu": "Menú",
"TorrentBlackholeSaveMagnetFilesExtensionHelpText": "Extensión a usar para enlaces magnet, predeterminado a '.magnet'",
"XmlRpcPath": "Ruta RPC de XML",
"DownloadClientQbittorrentSettingsUseSslHelpText": "Usa una conexión segura. Ver en Opciones -> Interfaz web -> 'Usar HTTPS en lugar de HTTP' en qbittorrent.",
"DownloadClientSettingsUrlBaseHelpText": "Añade un prefijo a la url {clientName}, como {url}",
"DownloadClientSettingsUseSslHelpText": "Usa una conexión segura cuando haya una conexión a {clientName}",
"DownloadClientNzbgetSettingsAddPausedHelpText": "Esta opción requiere al menos NzbGet versión 16.0",
"DownloadClientQbittorrentSettingsInitialStateHelpText": "Estado inicial para los torrents añadidos a qBittorrent. Ten en cuenta que Forzar torrents no cumple las restricciones de semilla",
"DownloadClientRTorrentSettingsDirectoryHelpText": "Ubicación opcional en la que poner las descargas, dejar en blanco para usar la ubicación predeterminada de rTorrent",
"DownloadClientSettingsDestinationHelpText": "Especifica manualmente el destino de descarga, dejar en blanco para usar el predeterminado",
"DownloadClientSettingsInitialState": "Estado inicial",
"CustomFormatsSettingsTriggerInfo": "Un formato personalizado será aplicado al lanzamiento o archivo cuando coincida con al menos uno de los diferentes tipos de condición elegidos.",
"IndexerSettingsMultiLanguageRelease": "Múltiples idiomas",
"IndexerSettingsMultiLanguageReleaseHelpText": "¿Qué idiomas están normalmente en un lanzamiento múltiple en este indexador?",
"PopularityIndex": "Índice de popularidad actual",
"AutoTaggingSpecificationTag": "Etiqueta",
"BlackholeWatchFolderHelpText": "Carpeta desde la que {appName} debería importar las descargas completadas",
"DeleteSpecificationHelpText": "¿Estás seguro que quieres eliminar la especificación '{name}'?",
"DownloadClientDelugeTorrentStateError": "Deluge está reportando un error",
"DownloadClientDelugeValidationLabelPluginInactive": "Plugin de etiqueta no activado",
"DownloadClientDownloadStationValidationNoDefaultDestination": "Sin destino predeterminado",
"DownloadClientDownloadStationValidationSharedFolderMissingDetail": "El Diskstation no tiene una carpeta compartida con el nombre '{sharedFolder}'. ¿Estás seguro que lo has especificado correctamente?",
"DownloadClientFloodSettingsRemovalInfo": "{appName} manejará la eliminación automática de torrents basados en los criterios de sembrado actuales en Opciones -> Indexadores",
"DownloadClientNzbgetValidationKeepHistoryOverMax": "La configuración KeepHistory de NzbGet debería ser menor de 25000",
"DownloadClientSabnzbdValidationEnableDisableDateSorting": "Deshabilitar ordenamiento de fecha",
"DownloadClientSabnzbdValidationEnableDisableMovieSorting": "Deshabilitar ordenamiento de película",
"DownloadClientSabnzbdValidationEnableDisableMovieSortingDetail": "Debes deshabilitar el ordenamiento de película para la categoría que {appName} usa para evitar problemas al importar. Ve a Sabnzbd para corregirlo.",
"DownloadClientSabnzbdValidationEnableDisableTvSorting": "Deshabilitar ordenamiento de TV",
"DownloadClientSabnzbdValidationEnableJobFolders": "Habilitar carpetas de trabajo",
"DownloadClientSabnzbdValidationEnableJobFoldersDetail": "{appName} prefiere que cada descarga tenga una carpeta separada. Con * añadido a la carpeta/ruta, Sabnzbd no creará esas carpetas de trabajo. Ve a Sabnzbd para corregirlo.",
"DownloadClientSettingsOlderPriority": "Priorizar más antiguos",
"DownloadClientSettingsOlderPriorityMovieHelpText": "Prioridad a usar cuando se capturan películas que empezaron su emisión hace más de 21 días",
"DownloadClientSettingsRecentPriority": "Priorizar recientes",
"DownloadClientValidationApiKeyRequired": "Clave API requerida",
"DownloadClientValidationApiKeyIncorrect": "Clave API incorrecta",
"DownloadClientValidationAuthenticationFailure": "Fallo de autenticación",
"DownloadClientValidationSslConnectFailureDetail": "{appName} no se pudo conectar a {clientName} usando SSL. Este problema puede estar relacionado con el ordenador. Por favor intenta configurar tanto {appName} como {clientName} para no usar SSL.",
"NotificationsTelegramSettingsIncludeAppNameHelpText": "Opcionalmente prefija el título del mensaje con {appName} para diferenciar las notificaciones de las diferentes aplicaciones",
"NotificationsTelegramSettingsIncludeAppName": "Incluir {appName} en el título",
"Recommended": "Recomendado",
"ShowTmdbRating": "Mostrar valoraciones de TMDb",
"MovieMatchType": "Tipo de coincidencia de película",
"BlackholeWatchFolder": "Monitorizar carpeta",
"Category": "Categoría",
"DownloadClientDownloadStationValidationSharedFolderMissing": "La carpeta compartida no existe",
"DownloadClientFloodSettingsAddPaused": "Añadir pausados",
"DownloadClientFreeboxNotLoggedIn": "Sin sesión iniciada",
"DownloadClientFreeboxUnableToReachFreebox": "No se pudo alcanzar la API de Freebox. Verifica las opciones 'Host', 'Puerto' o 'Usar SSL'. (Error: {exceptionMessage})",
"DownloadClientNzbVortexMultipleFilesMessage": "La descarga contiene múltiples archivos y no está en una carpeta de trabajo: {outputPath}",
"DownloadClientNzbgetValidationKeepHistoryOverMaxDetail": "La configuración KeepHistory de NzbGet está establecida demasiado alta.",
"DownloadClientQbittorrentTorrentStateDhtDisabled": "qBittorrent no puede resolver el enlace magnet con DHT deshabilitado",
"DownloadClientQbittorrentTorrentStateMetadata": "qBittorrent está descargando metadatos",
"DownloadClientSettingsPostImportCategoryHelpText": "Categoría para que {appName} establezca una vez se haya importado la descarga. {appName} no eliminará torrents en esa categoría incluso si finalizó el sembrado. Dejar en blanco para mantener la misma categoría.",
"DownloadClientUTorrentTorrentStateError": "uTorrent está reportando un error",
"DownloadClientValidationCategoryMissing": "La categoría no existe",
"DownloadClientValidationCategoryMissingDetail": "La categoría que has introducido no existe en {clientName}. Créala en {clientName} primero.",
"DownloadClientValidationGroupMissing": "El grupo no existe",
"DownloadClientValidationErrorVersion": "La versión de {clientName} debería ser al menos {requiredVersion}. La versión reportada es {reportedVersion}",
"DownloadClientValidationGroupMissingDetail": "El grupo que introdujiste no existe en {clientName}. Créalo en {clientName} primero.",
"DownloadClientValidationSslConnectFailure": "No se pudo conectar a través de SSL",
"DownloadClientValidationTestTorrents": "Fallo al obtener la lista de torrents: {exceptionMessage}",
"DownloadClientValidationTestNzbs": "Fallo al obtener la lista de NZBs: {exceptionMessage}",
"DownloadClientValidationUnableToConnectDetail": "Por favor verifica el nombre de host y el puerto.",
"OrganizeNamingPattern": "Patrón de nombrado: `{standardMovieFormat}`",
"WhySearchesCouldBeFailing": "Pulsa aquí para descubrir por qué las búsquedas podrían estar fallando",
"MovieSearchResultsLoadError": "No se pudo cargar los resultados para esta búsqueda de película. Intentar de nuevo más tarde",
"DelayMinutes": "{delay} minutos",
"DelayProfileProtocol": "Protocolo: {preferredProtocol}",
"DeleteReleaseProfile": "Eliminar perfil de lanzamiento",
"DeleteReleaseProfileMessageText": "¿Estás seguro que quieres eliminar este perfil de lanzamiento '{name}'?",
"DeleteSpecification": "Eliminar especificación",
"DownloadClientDelugeValidationLabelPluginFailure": "La configuración de etiqueta falló",
"DownloadClientDelugeValidationLabelPluginFailureDetail": "{appName} no pudo añadir la etiqueta a {clientName}.",
"DownloadClientDelugeValidationLabelPluginInactiveDetail": "Debes tener el plugir de etiqueta habilitado en {clientName} para usar categorías.",
"DownloadClientDownloadStationValidationApiVersion": "Versión API de estación de descarga no soportada, debería ser al menos {requiredVersion}. Soporta desde {minVersion} hasta {maxVersion}",
"DownloadClientDownloadStationValidationNoDefaultDestinationDetail": "Debes iniciar sesión en tu Diskstation como {username} y configurarlo manualmente en las opciones de DownloadStation en BT/HTTP/FTP/NZB -> Ubicación.",
"DownloadClientFloodSettingsPostImportTags": "Etiquetas post-importación",
"DownloadClientFloodSettingsStartOnAdd": "Iniciar al añadir",
"DownloadClientNzbgetValidationKeepHistoryZero": "La configuración KeepHistory de NzbGet debería ser mayor de 0",
"DownloadClientQbittorrentTorrentStateError": "qBittorrent está reportando un error",
"DownloadClientQbittorrentValidationCategoryAddFailure": "La configuración de categoría falló",
"DownloadClientQbittorrentTorrentStateStalled": "La descarga está parada sin conexiones",
"DownloadClientQbittorrentTorrentStateUnknown": "Estado de descarga desconocido: {state}",
"DownloadClientQbittorrentValidationCategoryRecommended": "Una categoría es recomendada",
"DownloadClientQbittorrentValidationCategoryAddFailureDetail": "{appName} no pudo añadir la etiqueta a qBittorrent.",
"DownloadClientQbittorrentValidationCategoryUnsupportedDetail": "Las categorías no están soportadas por debajo de la versión 3.3.0 de qBittorrent. Por favor actualiza o inténtalo de nuevo con una categoría vacía.",
"DownloadClientQbittorrentValidationCategoryUnsupported": "La categoría no está soportada",
"DownloadClientQbittorrentValidationQueueingNotEnabledDetail": "El encolado de torrent no está habilitado en las opciones de tu qBittorrent. Habilítalo en qBittorrent o selecciona 'Último' como prioridad.",
"DownloadClientQbittorrentValidationRemovesAtRatioLimit": "qBittorrent está configurado para eliminar torrents cuando alcanzan su Límite de ratio de compartición",
"DownloadClientSabnzbdValidationDevelopVersion": "Versión de desarrollo de Sabnzbd, asumiendo versión 3.0.0 o superior.",
"DownloadClientSabnzbdValidationEnableDisableDateSortingDetail": "Debes deshabilitar el ordenamiento de fecha para la categoría que {appName} usa para evitar problemas al importar. Ve a Sabnzbd para corregirlo.",
"DownloadClientSabnzbdValidationEnableDisableTvSortingDetail": "Debes deshabilitar el ordenamiento de TV para la categoría que {appName} usa para evitar problemas al importar. Ve a Sabnzbd para corregirlo.",
"DownloadClientSabnzbdValidationUnknownVersion": "Versión desconocida: {rawVersion}",
"DownloadClientSettingsCategoryHelpText": "Añade una categoría específica para que {appName} evite conflictos con descargas no relacionadas con {appName}. Usar una categoría es opcional, pero altamente recomendado.",
"DownloadClientSettingsCategorySubFolderHelpText": "Añade una categoría específica para que {appName} evite conflictos con descargas no relacionadas con {appName}. Usar una categoría es opcional, pero altamente recomendado. Crea un subdirectorio [categoría] en el directorio de salida.",
"DownloadClientSettingsRecentPriorityMovieHelpText": "Prioridad a usar cuando se capturan películas que empezaron la emisión dentro de los últimos 21 días",
"DownloadClientValidationUnableToConnect": "No se pudo conectar a {clientName}",
"DownloadClientValidationVerifySslDetail": "Por favor verifica tu configuración SSL tanto en {clientName} como en {appName}",
"DownloadStationStatusExtracting": "Extrayendo: {progress}%",
"EditReleaseProfile": "Editar perfil de lanzamiento",
"NewNonExcluded": "Nuevos no excluidos",
"NoExtraFilesToManage": "Ningún archivo adicional para gestionar.",
"OnManualInteractionRequiredHelpText": "En interacción manual requerida",
"Recommendation": "Recomendación",
"ShowRottenTomatoesRating": "Mostrar valoraciones de Tomato",
"Popularity": "Popularidad",
"OverrideGrabNoMovie": "La película debe ser seleccionada",
"RecycleBinUnableToWriteHealthCheck": "No se pudo escribir a la carpeta de papelera de reciclaje configurada: {path}. Asegúrate de que existe esta ruta y es modificable por el usuario que ejecuta {appName}",
"ThereWasAnErrorLoadingThisItem": "Hubo un error cargando este elemento",
"DownloadClientSabnzbdValidationCheckBeforeDownloadDetail": "Usar 'Verificar antes de descargar' afecta a la habilidad de {appName} para rastrear nuevas descargas. Sabnzbd recomienda 'Abortar trabajos que no pueden ser completados' en su lugar ya que es más efectivo.",
"AddListExclusion": "Añadir lista de exclusión",
"AddReleaseProfile": "Añadir perfil de lanzamiento",
"SearchMoviesConfirmationMessageText": "¿Estás seguro que quieres realizar una búsqueda para {count} película(s)?",
"ShowUnknownMovieItemsHelpText": "Mostrar elementos sin una película en la cola. Esto podría incluir películas eliminadas o cualquier otra cosa en la categoría de {appName}",
"AutoTaggingLoadError": "No se pudo cargar el etiquetado automático",
"DownloadClientRTorrentProviderMessage": "rTorrent no pausará torrents cuando cumplan el criterio de sembrado. {appName} manejará la eliminación automática de torrents basados en el criterio de sembrado actual en Opciones -> Indexadores solo cuando Eliminar completados esté habilitado. Después de importarlo también se establecerá {importedView} como una vista de rTorrent, lo que puede ser usado en los scripts de rTorrent para personalizar su comportamiento.",
"DownloadClientValidationAuthenticationFailureDetail": "Por favor verifica tu usuario y contraseña. Verifica también si al host que ejecuta {appName} no se le ha bloqueado el acceso a {clientName} por limitaciones en la lista blanca en la configuración de {clientName}.",
"ThereWasAnErrorLoadingThisPage": "Hubo un error cargando esta página",
"MovieIsTrending": "La película es tendencia en TMDb",
"MovieIsPopular": "La película es popular en TMDb",
"RemotePathMappingsInfo": "El mapeo de rutas remotas es muy raramente requerido, si {appName} y tu cliente de descarga están en el mismo sistema es mejor para coincidir tus rutas. Para más información consulta la [wiki]({wikiLink}).",
"NotificationsPlexValidationNoMovieLibraryFound": "Se requiere al menos una biblioteca de películas",
"IncludeHealthWarnings": "Incluir avisos de salud",
"Trending": "Tendencia",
"EditMetadata": "Editar metadatos {metadataType}",
"Example": "Ejemplo",
"HourShorthand": "h",
"ReleaseProfileIndexerHelpTextWarning": "Establecer un indexador específico en un perfil de lanzamiento causará que este perfil solo se aplique a lanzamientos desde ese indexador.",
"ReleaseProfileTagMovieHelpText": "Los perfiles de lanzamiento se aplicarán a películas con al menos una etiqueta coincidente. Dejar en blanco para aplicar a todas las películas",
"ShowImdbRatingHelpText": "Mostrar valoraciones de IMDb debajo del póster",
"ShowImdbRating": "Mostrar valoraciones de IMDb",
"MovieFileMissingTooltip": "Archivo de película perdido",
"CutoffNotMet": "Umbrales no alcanzados",
"Dash": "Guion",
"ImportScriptPathHelpText": "La ruta al script a usar para importar",
"MovieFolderFormatHelpText": "Usado cuando se añade una nueva película o se mueven películas a través del editor de películas",
"Popular": "Popular",
"ShowTmdbRatingHelpText": "Mostrar valoraciones de TMDb debajo del póster",
"SearchMoviesOnAdd": "Buscar películas al añadir",
"ShowRottenTomatoesRatingHelpText": "Mostrar valoraciones de Tomato debajo del póster",
"ConditionUsingRegularExpressions": "Esta condición coincide usando expresiones regulares. Ten en cuenta que los caracteres `\\^$.|?*+()[{` tienen significados especiales y necesitan ser escapados con un `\\`",
"DelayProfileMovieTagsHelpText": "Se aplica a películas con al menos una etiqueta coincidente",
"ExistsInLibrary": "Existe en la biblioteca",
"Lists": "Listas",
"NotificationsTagsMovieHelpText": "Enviar notificaciones solo para películas con al menos una etiqueta coincidente",
"OnExcludedList": "En lista de excluidos",
"DownloadClientDownloadStationValidationFolderMissing": "La carpeta no existe",
"DownloadClientDownloadStationValidationFolderMissingDetail": "La carpeta '{downloadDir}' no existe, debe ser creada manualmente dentro de la carpeta compartida '{sharedFolder}'.",
"DownloadClientFloodSettingsPostImportTagsHelpText": "Añadir etiquetas una vez una descarga sea importada.",
"DownloadClientFreeboxAuthenticationError": "La autenticación a la API de Freebox falló. Motivo: {errorDescription}",
"DownloadClientFreeboxUnableToReachFreeboxApi": "No se pudo alcanzar la API de Freebox. Verifica la opción 'URL de la API' para la URL base y la versión.",
"DownloadClientNzbgetValidationKeepHistoryZeroDetail": "La configuración KeepHistory de NzbGet está establecida a 0. Esto evita que {appName} vea las descargas completadas.",
"Yes": "Sí",
"NotificationsGotifySettingIncludeMoviePoster": "Incluir póster de la película",
"NotificationsGotifySettingIncludeMoviePosterHelpText": "Incluye el póster de la película en el mensaje",
"DownloadClientFreeboxApiError": "La API de Freebox devolvió el error: {errorDescription}",
"DownloadClientQbittorrentValidationCategoryRecommendedDetail": "{appName} no intentará importar las descargas completadas sin una categoría.",
"DownloadClientQbittorrentValidationQueueingNotEnabled": "Encolado no habilitado",
"DownloadClientSabnzbdValidationCheckBeforeDownload": "Deshabilita la opción 'Verificar antes de descargar' en Sabnbzd",
"DownloadClientQbittorrentTorrentStatePathError": "No se pudo importar. La ruta coincide con el directorio de descarga base del cliente. ¿Es posible que 'Mantener carpeta de nivel superior' esté deshabilitado para este torrent o que 'Distribución de contenido de torrent' NO esté configurado a 'Original' o 'Crear subcarpeta'?",
"DownloadClientValidationUnknownException": "Excepción desconocida: {exception}",
"DownloadClientValidationVerifySsl": "Verificar opciones de SSL",
"DownloadClientVuzeValidationErrorVersion": "Versión de protocolo no soportada, usa Vuze 5.0.0.0 o superior con el plugin de web remota de Vuze.",
"NoMovieFilesToManage": "Ningún archivo de película para gestionar.",
"Underscore": "Guion bajo",
"AddDelayProfileError": "No se pudo añadir un nuevo perfil de retraso, por favor inténtalo de nuevo.",
"ChownGroup": "chown grupo",
"RegularExpressionsTutorialLink": "Más detalles de las expresiones regulares pueden ser encontrados [aquí](https://www.regular-expressions.info/tutorial.html)."
}

View File

@@ -131,7 +131,6 @@
"ICalFeed": "iCal-syöte",
"ICalFeedHelpText": "Kopioi URL-osoite kalenteripalveluusi/-sovellukseesi tai tilaa se painamalla tästä, jos selaimesi tukee Webcal-osoitteita.",
"IllRestartLater": "Käynnistän uudelleen myöhemmin",
"IncludeHealthWarningsHelpText": "Sisällytä kuntovaroitukset",
"IndexersSettingsSummary": "Tietolähteet ja julkaisurajoitukset",
"Info": "Informatiivinen",
"Add": "Lisää",
@@ -1705,6 +1704,5 @@
"RegularExpressionsTutorialLink": "Lisätietoja säännöllisistä lausekkeista löytyy [täältä](https://www.regular-expressions.info/tutorial.html).",
"ReleaseProfileIndexerHelpText": "Määritä mitä tietolähdettä profiili koskee.",
"ReleaseProfileTagMovieHelpText": "Julkaisuprofiileja sovelletaan elokuviin, jotka on merkitty ainakin yhdellä vastaavalla tunnisteella. Käytä kaikille elokuville jättämällä tyhjäksi.",
"ReleaseProfileIndexerHelpTextWarning": "Tietyn tietolähteen käyttö julkaisuprofiileilla saattaa aiheuttaa julkaisujen kaksoiskappaleiden kaappauksia.",
"SearchMoviesOnAdd": "Etsi elokuvia kun ne lisätään"
}

View File

@@ -1,6 +1,6 @@
{
"IndexerStatusCheckAllClientMessage": "Tous les indexeurs sont indisponibles en raison d'échecs",
"IndexerSearchCheckNoInteractiveMessage": "Aucun indexeur n'est disponible avec la recherche interactive activée. {appName} ne fournira aucun résultat de recherche interactif.",
"IndexerSearchCheckNoInteractiveMessage": "Aucun indexeur n'est disponible avec la recherche interactive activée, {appName} ne fournira aucun résultat de recherche interactif",
"IndexerSearchCheckNoAvailableIndexersMessage": "Tous les indexeurs compatibles avec la recherche sont temporairement indisponibles en raison d'erreurs d'indexation récentes",
"IndexerSearchCheckNoAutomaticMessage": "Aucun indexeur disponible avec la recherche automatique activée, {appName} ne fournira aucun résultat de recherche automatique",
"Indexers": "Indexeurs",
@@ -26,7 +26,7 @@
"Edit": "Modifier",
"Downloaded": "Téléchargé",
"DownloadClientStatusCheckAllClientMessage": "Aucun client de téléchargement n'est disponible en raison d'échecs",
"DownloadClients": "Clients de télécharg.",
"DownloadClients": "Clients de téléchargement",
"DownloadClientCheckNoneAvailableMessage": "Aucun client de téléchargement n'est disponible",
"Dates": "Dates",
"Date": "Date",
@@ -58,7 +58,7 @@
"AddNew": "Ajouter",
"Activity": "Activité",
"About": "À propos",
"CustomFormatsSettingsSummary": "Paramètres de formats personnalisés",
"CustomFormatsSettingsSummary": "Formats et paramètres personnalisés",
"IndexerStatusCheckSingleClientMessage": "Indexeurs indisponibles en raison d'échecs : {indexerNames}",
"DownloadClientStatusCheckSingleClientMessage": "Clients de Téléchargement indisponibles en raison d'échecs: {downloadClientNames}",
"SetTags": "Définir des étiquettes",
@@ -141,13 +141,13 @@
"MountCheckMessage": "Le montage contenant un chemin de film est monté en lecture seule: ",
"MoreInfo": "Plus d'informations",
"Month": "Mois",
"ImportListsSettingsSummary": "Importer des Listes, exclure des listes",
"ImportListsSettingsSummary": "Importer depuis une autre instance {appName} ou des listes Trakt et gérer les exclusions de listes",
"ImportListExclusions": "Liste des exclusions",
"IndexersSettingsSummary": "Indexeurs et restrictions de version",
"Grabbed": "Saisie",
"Genres": "Genres",
"Forecast": "Prévision",
"DownloadClientsSettingsSummary": "Clients de téléchargement, gestion des téléchargements et mappages de chemins distants",
"DownloadClientsSettingsSummary": "Clients de téléchargement, gestion des téléchargements et mappages de chemins d'accès à distance",
"DownloadClientCheckUnableToCommunicateMessage": "Impossible de communiquer avec {downloadClientName}. {errorMessage}",
"DownloadClient": "Client de téléchargement",
"CutoffUnmet": "Limite non satisfaite",
@@ -188,7 +188,7 @@
"InCinemas": "Dans les cinémas",
"Imported": "Importé",
"Ignored": "Ignoré",
"GeneralSettingsSummary": "Port, SSL/TLS, nom d'utilisateur/mot de passe, proxy, analyses et mises à jour",
"GeneralSettingsSummary": "Port, SSL, nom d'utilisateur/mot de passe, proxy, analyses et mises à jour",
"Filename": "Nom de fichier",
"Failed": "Échoué",
"EventType": "Type d'événement",
@@ -386,7 +386,7 @@
"DatabaseMigration": "Migration des bases de données",
"UpgradeUntilMovieHelpText": "Quand cette qualité est atteinte, {appName} ne téléchargera plus de films",
"UpgradeUntilCustomFormatScoreMovieHelpText": "Quand ce score de format personnalisé est atteint, {appName} ne téléchargera plus de films",
"CustomFormatsSettings": "Paramètres de formats personnalisés",
"CustomFormatsSettings": "Paramètre des formats personnalisés",
"CreateGroup": "Créer un groupe",
"CreateEmptyMovieFoldersHelpText": "Créer les dossiers films manquants pendant le scan du disque",
"CreateEmptyMovieFolders": "Créer des dossiers films vides",
@@ -527,7 +527,6 @@
"LoadingMovieCreditsFailed": "Échec du chargement des crédits du film",
"ImportListSettings": "Paramètres liste",
"HiddenClickToShow": "Masqué, cliquez pour afficher",
"IncludeHealthWarningsHelpText": "Inclure avertissements santé",
"FocusSearchBox": "Placer le curseur sur la barre de recherche",
"RequiredHelpText": "Cette condition {implementationName} doit être remplie pour que le format personnalisé s'applique. Dans le cas contraire, une seule correspondance avec {implementationName} suffit.",
"ProxyBypassFilterHelpText": "Utilisez ',' comme séparateur et '*.' comme caractère générique pour les sous-domaines",
@@ -799,7 +798,7 @@
"CustomFormatHelpText": "{appName} attribue un score pour chaque release en additionnant les scores des formats personnalisés correspondants. Si une nouvelle release permet d'améliorer le score, pour une qualité identique ou supérieure, alors {appName} la téléchargera.",
"Days": "Jours",
"Debug": "Déboguer",
"DefaultCase": "Casse par défaut",
"DefaultCase": "Case par défaut",
"DeletedMsg": "Le film a été supprimé de TMDb",
"DeleteFilesHelpText": "Supprimer les fichiers du film et dossier du film",
"DeleteFilesLabel": "Supprimer {0} fichiers",
@@ -820,14 +819,14 @@
"ExcludeTitle": "Exclure {0} ? {appName} n'importera plus automatiquement ce film des listes de synchronisation.",
"FailedToLoadMovieFromAPI": "Erreur lors du chargement du film via l'API",
"FeatureRequests": "Requêtes de nouvelles fonctionnalités",
"FileNameTokens": "Tokens des noms de fichier",
"FileNameTokens": "Jetons de nom de fichier",
"FolderMoveRenameWarning": "Ceci va également renommer le dossier du film par le format de dossier défini dans les paramètres.",
"Images": "Images",
"IMDb": "IMDb",
"Hours": "Heures",
"HomePage": "Page d'accueil",
"HttpHttps": "HTTP(S)",
"ImportLibrary": "Importer biblio.",
"ImportLibrary": "Importation de bibliothèque",
"MovieIsRecommend": "Le film est recommandé en fonction de l'ajout récent",
"NoAltTitle": "Pas de titres alternatifs.",
"NoLinks": "Aucun liens",
@@ -839,7 +838,7 @@
"UpgradesAllowed": "Mises à niveau autorisées",
"WhatsNew": "Quoi de neuf ?",
"InCinemasMsg": "Le film est dans les cinémas",
"Lowercase": "Minuscules",
"Lowercase": "Minuscule",
"ManualImportSelectMovie": "Importation manuelle - Sélectionnez un film",
"MappedDrivesRunningAsService": "Les lecteurs réseau mappés ne sont pas disponibles en fonctionnement en tant que service Windows. Veuillez consulter la FAQ pour plus d'informations",
"RequiredRestrictionHelpText": "La version doit contenir au moins un de ces termes (insensible à la casse)",
@@ -857,7 +856,7 @@
"NoMoveFilesSelf": " Non, je vais déplacer les fichiers moi-même",
"None": "Aucun",
"NoResultsFound": "Aucun résultat trouvé",
"OnGrab": "À saisir",
"OnGrab": "Lors de la saisie",
"OnHealthIssue": "Sur la question de la santé",
"OnImport": "À l'importation",
"OnLatestVersion": "La dernière version de {appName} est déjà installée",
@@ -873,7 +872,7 @@
"PreferUsenet": "Préférer Usenet",
"ReplaceWithDash": "Remplacer par un tiret",
"InCinemasDate": "Dans les cinémas Date",
"InstallLatest": "Installer le dernier",
"InstallLatest": "Installer la dernière",
"KeepAndUnmonitorMovie": "Conserver et annuler la surveillance du film",
"Large": "Grand",
"LastUsed": "Dernière utilisation",
@@ -1111,7 +1110,7 @@
"DeleteImportListMessageText": "Êtes-vous sûr de vouloir supprimer la liste « {name} » ?",
"DeleteQualityProfileMessageText": "Êtes-vous sûr de vouloir supprimer le profil de qualité \"{name}\" ?",
"RemoveQueueItemConfirmation": "Êtes-vous sûr de vouloir retirer '{sourceTitle}' de la file d'attente ?",
"MoveAutomatically": "Se déplacer automatiquement",
"MoveAutomatically": "Importation automatique",
"AutoTaggingNegateHelpText": "Si cette case est cochée, la règle de marquage automatique ne s'appliquera pas si cette condition {implementationName} correspond.",
"AutoTaggingRequiredHelpText": "Cette condition {implementationName} doit correspondre pour que la règle de marquage automatique s'applique. Sinon, une seule correspondance {implementationName} suffit.",
"DeleteAutoTagHelpText": "Voulez-vous vraiment supprimer la balise automatique « {name} » ?",
@@ -1183,7 +1182,7 @@
"Or": "ou",
"FormatAgeHours": "heures",
"Implementation": "Mise en œuvre",
"FormatTimeSpanDays": "{days}j {time}",
"FormatTimeSpanDays": "{days} j {time}",
"FormatAgeMinute": "minute",
"FormatAgeMinutes": "minutes",
"FormatDateTimeRelative": "{relativeDay}, {formattedDate} {formattedTime}",
@@ -1200,7 +1199,7 @@
"OrganizeNothingToRename": "C'est fait ! Mon travail est terminé, plus aucun fichier à renommer.",
"False": "Faux",
"DefaultNameCopiedProfile": "{name} - Copier",
"IndexerDownloadClientHealthCheckMessage": "Indexeurs avec des clients de téléchargement invalides : {0].",
"IndexerDownloadClientHealthCheckMessage": "Indexeurs avec des clients de téléchargement invalides : {0}.",
"DeleteRootFolder": "Supprimer le dossier racine",
"SelectDownloadClientModalTitle": "{modalTitle} Sélectionnez le client de téléchargement",
"HistoryLoadError": "Impossible de charger l'historique",
@@ -1284,7 +1283,7 @@
"CustomFormatJson": "Format personnalisé JSON",
"DeleteAutoTag": "Supprimer la balise automatique",
"MovieImportedTooltip": "Film téléchargé avec succès et récupéré à partir du client de téléchargement",
"DeletedReasonManual": "Le fichier a été supprimé via l'interface utilisateur",
"DeletedReasonManual": "Le fichier a été supprimé à l'aide de {appName}, soit manuellement, soit par un autre outil via l'API.",
"DownloadIgnored": "Téléchargement ignoré",
"EditAutoTag": "Modifier la balise automatique",
"OrganizeNamingPattern": "Modèle de nommage : `{standardMovieFormat}`",
@@ -1469,7 +1468,7 @@
"NotificationsValidationUnableToSendTestMessage": "Impossible d'envoyer un message d'essai : {exceptionMessage}",
"NotificationsNtfySettingsAccessTokenHelpText": "Autorisation basée sur jeton facultative. A la priorité sur le couple nom d'utilisateur / mot de passe",
"NotificationsValidationInvalidUsernamePassword": "Nom d'utilisateur ou mot de passe invalides",
"NotificationsKodiSettingsUpdateLibraryHelpText": "Mettre à jour la bibliothèque dans Importer & Renommer ?",
"NotificationsKodiSettingsUpdateLibraryHelpText": "Mettre à jour la bibliothèque lors de l'importation et du renommage ?",
"NotificationsAppriseSettingsTagsHelpText": "Notifier facultativement uniquement ceux mentionnés.",
"NotificationsAppriseSettingsStatelessUrlsHelpText": "Une ou plusieurs URL séparées par des virgules identifiant où la notification doit être envoyée. Laisser vide si le stockage persistant est utilisé.",
"NotificationsValidationInvalidApiKey": "La clé d'API est invalide",
@@ -1506,7 +1505,7 @@
"DoNotBlocklist": "Ne pas mettre sur liste noire",
"DoNotBlocklistHint": "Supprimer sans mettre sur liste noire",
"IgnoreDownload": "Ignorer le téléchargement",
"IndexerSettingsRejectBlocklistedTorrentHashes": "Rejeter les hachages de torrents bloqués lors de la saisie",
"IndexerSettingsRejectBlocklistedTorrentHashes": "Rejeter les hachages de torrent sur liste noir lors de la saisie",
"RemoveQueueItemRemovalMethod": "Méthode de suppression",
"RemoveMultipleFromDownloadClientHint": "Supprime les téléchargements et les fichiers du client de téléchargement",
"RemoveQueueItemRemovalMethodHelpTextWarning": "\"Supprimer du client de téléchargement\" supprimera le téléchargement et le(s) fichier(s) du client de téléchargement.",
@@ -1525,11 +1524,11 @@
"DownloadClientDelugeSettingsUrlBaseHelpText": "Ajoute un préfixe à l'URL json du déluge, voir {url}",
"DownloadClientDelugeTorrentStateError": "Deluge signale une erreur",
"DownloadClientDelugeValidationLabelPluginInactiveDetail": "Vous devez avoir activé le plug-in Label dans {clientName} pour utiliser les catégories.",
"ClickToChangeIndexerFlags": "Cliquer pour changer les attributs de l'indexer",
"CustomFormatsSpecificationFlag": "Attribut",
"ClickToChangeIndexerFlags": "Cliquez pour changer les drapeaux de l'indexeur",
"CustomFormatsSpecificationFlag": "Drapeau",
"DelayMinutes": "{delay} minutes",
"DelayProfileProtocol": "Protocole: {preferredProtocol}",
"Donate": "Faire un don",
"DelayProfileProtocol": "Protocole : {preferredProtocol}",
"Donate": "Donation",
"AddListExclusion": "Ajouter une liste d'exclusion",
"AddReleaseProfile": "Ajouter un profil de version",
"Category": "Catégorie",
@@ -1602,7 +1601,6 @@
"TorrentBlackholeSaveMagnetFilesExtensionHelpText": "Extension à utiliser pour les liens magnétiques, la valeur par défaut est '.magnet'",
"DownloadClientTransmissionSettingsDirectoryHelpText": "Emplacement facultatif pour les téléchargements, laisser vide pour utiliser l'emplacement de transmission par défaut",
"ReleaseProfileIndexerHelpText": "Spécifier l'indexeur auquel le profil s'applique",
"ReleaseProfileIndexerHelpTextWarning": "L'utilisation d'un indexeur spécifique avec des profils de version peut entraîner la saisie de publications en double.",
"ReleaseProfileTagMovieHelpText": "Les profils de version s'appliquent aux films ayant au moins une étiquette correspondante. Laisser vide pour appliquer à tous les films",
"Repack": "Repack",
"RestartRequiredWindowsService": "En fonction de l'utilisateur qui exécute le service {appName}, vous devrez peut-être redémarrer {appName} en tant qu'administrateur une fois avant que le service ne démarre automatiquement.",
@@ -1745,5 +1743,13 @@
"ListRootFolderHelpText": "Les éléments de la liste du dossier racine seront ajoutés à la liste des dossiers racine",
"Lists": "Listes",
"DownloadClientRTorrentProviderMessage": "rTorrent ne mettra pas les torrents en pause lorsqu'ils répondent aux critères d'ensemencement. {appName} traitera la suppression automatique des torrents en fonction des critères d'ensemencement actuels dans Paramètres->Indexeurs uniquement lorsque l'option Supprimer terminé est activée. Après l'importation, il définira également {importedView} comme une vue rTorrent, qui peut être utilisée dans les scripts rTorrent pour personnaliser le comportement.",
"MediaInfoFootNote": "MediaInfo Full/AudioLanguages/SubtitleLanguages supporte un suffixe `:EN+DE` vous permettant de filtrer les langues incluses dans le nom de fichier. Utilisez `-DE` pour exclure des langues spécifiques. En ajoutant `+` (par exemple `:EN+`), vous obtiendrez `[EN]`/`[EN+--]`/`[--]` en fonction des langues exclues. Par exemple `{MediaInfo Full:EN+DE}`."
"MediaInfoFootNote": "MediaInfo Full/AudioLanguages/SubtitleLanguages supporte un suffixe `:EN+DE` vous permettant de filtrer les langues incluses dans le nom de fichier. Utilisez `-DE` pour exclure des langues spécifiques. En ajoutant `+` (par exemple `:EN+`), vous obtiendrez `[EN]`/`[EN+--]`/`[--]` en fonction des langues exclues. Par exemple `{MediaInfo Full:EN+DE}`.",
"ReleaseProfileIndexerHelpTextWarning": "L'utilisation d'un indexeur spécifique avec des profils de version peut entraîner la saisie de publications en double.",
"IncludeHealthWarnings": "Inclure les avertissements de santé",
"CustomFormatsSettingsTriggerInfo": "Un format personnalisé sera appliqué à une version ou à un fichier lorsqu'il correspond à au moins un de chacun des différents types de conditions choisis.",
"AutoTaggingSpecificationTag": "Étiquette",
"NotificationsTelegramSettingsIncludeAppName": "Inclure {appName} dans le Titre",
"NotificationsTelegramSettingsIncludeAppNameHelpText": "Préfixer éventuellement le titre du message par {appName} pour différencier les notifications des différentes applications",
"IndexerSettingsMultiLanguageReleaseHelpText": "Quelles langues sont normalement présentes dans une version multiple de l'indexeur ?",
"IndexerSettingsMultiLanguageRelease": "Multilingue"
}

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