1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-30 18:25:57 -04:00

Compare commits

...

39 Commits

Author SHA1 Message Date
Servarr
8fd267580a Automated API Docs update 2023-06-21 06:45:42 +03:00
Bogdan
8974aa823b Remove not implemented endpoints from API docs
Closes #8724
2023-06-21 06:34:07 +03:00
Bogdan
41492efd2e Convert to 'using' declaration in Housekeeping Tasks
Closes #8723
2023-06-21 06:25:44 +03:00
Bogdan
d008768fff Prevent NullRef when deleting missing backups
(cherry picked from commit 0ff0fe2e68f3abf7b8e4d6bf0c1e9dee4eb68227)

Closes #8721
2023-06-21 06:19:30 +03:00
Bogdan
cb21fe535d Fix translation for Unreleased 2023-06-20 19:39:16 +03:00
Bogdan
4cce2727e2 Update translations
(cherry picked from commit 26031389757f6b5270bbe5591101b08e58debb73)
2023-06-20 02:38:55 +03:00
Stevie Robinson
b1ff82da37 Fixed: Parsing Vyndros as release group
(cherry picked from commit f2ddd4757c897c522b553de8bafb5340746253c9)

Closes #8569
2023-06-19 07:09:04 +03:00
Mark McDowall
c5266152c5 Fixed: Strip additional domains from release names
(cherry picked from commit e273f16c3905e0c2451f43cf98b9b7ad1cbdc777)

Closes #8603
2023-06-19 07:00:22 +03:00
Bogdan
783878be1e Minor improvements in health checks
(cherry picked from commit a22f598b0c129110f2a3b663e9b40c84f3a1f02b)

Closes #8615
2023-06-19 06:38:51 +03:00
Bogdan
0cbfb4ca65 New: (UI) Search library by imdbId and tmdbId 2023-06-19 04:19:12 +03:00
bakerboy448
c22c9400c2 New: Indexer Messaging and Error Improvements
(cherry picked from commit 3b505d8734dcbe3fa53acba7f94f1361151e6a44)
2023-06-18 12:06:55 +03:00
Bogdan
0288c4b704 Bump version to 4.6.3 2023-06-18 12:05:11 +03:00
Márki-Zay Ferenc
e4429d2919 Fixed: Close database connection in housekeeping tasks 2023-06-17 03:52:12 +03:00
Bogdan
7052a7a5ec New: Improved page loading errors
Closes #8706
2023-06-16 23:45:26 +03:00
Weblate
b38912851b Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 100.0% (1184 of 1184 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2023-06-16 02:21:40 +03:00
Bogdan
1354c2c337 Fix sorting history items by movie titles 2023-06-15 23:21:16 +03:00
Servarr
e259235df6 Automated API Docs update 2023-06-14 09:17:16 +03:00
Bogdan
0cc1fe8308 Add HelpTextWarning support in FieldDefinition
(cherry picked from commit 0e07d54ee77d5f83716e17b6757e23f38ff73694)

Closes #8687
2023-06-14 07:55:44 +03:00
Bogdan
f4fe18a440 Require ApiKey for all actions in RadarrImport
(cherry picked from commit 19b8fbe13bf584b915a05fe9fc87622adbaee0b7)

Closes #8692
2023-06-14 07:50:53 +03:00
Bogdan
eeed935e3a Update cleansing rules for RSS TL feed and homedir for Mac
(cherry picked from commit e5ff4aafa3f0b855fec332788e9fc490a03dfce3)

Closes #8684
2023-06-14 07:48:26 +03:00
Bogdan
1b3701371a Fixed: Treat redirects as errors in Radarr Import List
(cherry picked from commit 059a156f4a34c6b9cbe139fa1973b814e8a534ae)
2023-06-14 07:40:06 +03:00
Qstick
d56f3ec2e7 Fixed: Correctly handle 302 and 303 redirects in HttpClient
(cherry picked from commit ed7c5a937f4b50fcdf819e8fe347c8c0bc6bd2e7)

(cherry picked from commit 11bd764a75d3b97117098738d3489c4b3329738f)
2023-06-14 07:37:37 +03:00
Weblate
e7e3aac971 Update translation files [skip ci]
Updated by "Cleanup translation files" hook in Weblate.

Update translation files  [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Translated using Weblate (Ukrainian) [skip ci]

Currently translated at 97.5% (1155 of 1184 strings)

Translated using Weblate (Norwegian Bokmål) [skip ci]

Currently translated at 22.1% (262 of 1184 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 97.8% (1158 of 1184 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1184 of 1184 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 99.5% (1179 of 1184 strings)

Update translation files  [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Translated using Weblate (Indonesian) [skip ci]

Currently translated at 7.5% (89 of 1180 strings)

Translated using Weblate (Croatian) [skip ci]

Currently translated at 21.8% (258 of 1180 strings)

Translated using Weblate (Ukrainian) [skip ci]

Currently translated at 97.9% (1156 of 1180 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 21.1% (249 of 1180 strings)

Translated using Weblate (Norwegian Bokmål) [skip ci]

Currently translated at 22.2% (263 of 1180 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 98.2% (1159 of 1180 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 88.8% (1048 of 1180 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 98.8% (1166 of 1180 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 99.9% (1179 of 1180 strings)

Translated using Weblate (Thai) [skip ci]

Currently translated at 88.2% (1041 of 1180 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 86.2% (1018 of 1180 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 88.2% (1041 of 1180 strings)

Translated using Weblate (Romanian) [skip ci]

Currently translated at 85.9% (1014 of 1180 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 88.2% (1041 of 1180 strings)

Translated using Weblate (Turkish) [skip ci]

Currently translated at 88.1% (1040 of 1180 strings)

Translated using Weblate (Swedish) [skip ci]

Currently translated at 89.0% (1051 of 1180 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 98.2% (1159 of 1180 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 98.3% (1160 of 1180 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 97.1% (1146 of 1180 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 98.4% (1162 of 1180 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 21.3% (252 of 1180 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 88.2% (1041 of 1180 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 88.3% (1042 of 1180 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 98.1% (1158 of 1180 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 91.2% (1077 of 1180 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 97.9% (1156 of 1180 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 99.6% (1176 of 1180 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 88.3% (1042 of 1180 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 89.1% (1052 of 1180 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 93.8% (1107 of 1180 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 98.2% (1159 of 1180 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 99.4% (1173 of 1180 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 99.9% (1179 of 1180 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/cs/
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/el/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt/
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/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2023-06-14 07:37:13 +03:00
Bogdan
d2cb36c88a Check only clients not in failure status in DownloadClientSortingCheck
(cherry picked from commit 0b872803358bac1297cc7618ea3c13a32a92b5a4)
2023-06-14 07:34:21 +03:00
bakerboy448
2fe28cb1dc Fixed: Handle checkingResumeData state form qBittorrent
(cherry picked from commit 8d8a16225ff7772ccb57784f272ca31e28bb8455)
2023-06-14 07:33:55 +03:00
Bogdan
5d65b4cae4 Fix sorting queue items by size 2023-06-14 04:46:19 +03:00
Bogdan
b0f56e2840 Update translations 2023-06-13 02:03:51 +03:00
Weblate
5593837482 Update translation files [skip ci]
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translation: Servarr/Radarr
2023-06-13 01:40:09 +03:00
Qstick
8231290c7b Update Remote Path Mapping delete modal title
(cherry picked from commit 18716a00516a971f7f2eb369b920266bea24fe08)

Closes #8675
2023-06-12 22:52:50 +03:00
Weblate
0c1b88c60a Translated using Weblate (Indonesian) [skip ci]
Currently translated at 7.3% (87 of 1179 strings)

Co-authored-by: liimee <git.taaa@fedora.email>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/id/
Translation: Servarr/Radarr
2023-06-12 11:49:17 +03:00
Qstick
0b8478e4a1 Bump version to 4.6.2 2023-06-11 09:39:17 -05:00
Weblate
69e09c8687 Translated using Weblate (Russian) [skip ci]
Currently translated at 98.3% (1159 of 1179 strings)

Co-authored-by: Андрей <andryfly7@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translation: Servarr/Radarr
2023-06-10 22:43:53 +03:00
Bogdan
3f2ea49023 Add style for default kind in ProgressBar 2023-06-10 03:13:47 +03:00
Bogdan
32f09633e9 Use more specific styling for kinds in ProgressBar
(cherry picked from commit dd31c913d2a974d95f3be251714ce749cfd99a72)

Fixes #8669
2023-06-10 01:45:40 +03:00
Qstick
3542b263c7 Fixed: Don't die on movie refresh when collection has been deleted from TMDB
Fixes #8664
2023-06-07 20:12:59 -05:00
Weblate
d5cc84d8c8 Translated using Weblate (Greek) [skip ci]
Currently translated at 99.5% (1174 of 1179 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 99.4% (1172 of 1179 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 98.3% (1159 of 1179 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1179 of 1179 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1179 of 1179 strings)

Co-authored-by: MoowGlax <matthieu.derouet.pro@gmail.com>
Co-authored-by: Thodoris Kalatzis <teo.kal@hotmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: emacsdias <emacs.dias@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: splifter <a.strahlke@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt/
Translation: Servarr/Radarr
2023-06-07 17:57:09 +03:00
Bogdan
c0790060fb Fixed: (UI) Sort last movies with no release dates
Towards #8662
2023-06-07 06:52:12 +03:00
Bogdan
5ec7e86488 Add language names as hints in TMDbSettings
Add Romanian in TMDb Language Codes
Move DateTime.TryParse to if condition in TMDbParser
2023-06-05 22:17:32 +03:00
Qstick
b8abafd72f Bump version to 4.6.1 2023-06-04 11:43:43 -05:00
144 changed files with 1055 additions and 1299 deletions

View File

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

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import PageContent from 'Components/Page/PageContent';
@@ -156,16 +157,16 @@ class Blocklist extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadBlocklist')}
</div>
</Alert>
}
{
isPopulated && !error && !items.length &&
<div>
{translate('NoHistory')}
</div>
<Alert kind={kinds.INFO}>
{translate('NoHistoryBlocklist')}
</Alert>
}
{
@@ -209,7 +210,7 @@ class Blocklist extends Component {
isOpen={isConfirmRemoveModalOpen}
kind={kinds.DANGER}
title={translate('RemoveSelected')}
message={translate('AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist')}
message={translate('RemoveSelectedItemBlocklistMessageText')}
confirmLabel={translate('RemoveSelected')}
onConfirm={this.onRemoveSelectedConfirmed}
onCancel={this.onConfirmRemoveModalClose}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu';
import PageContent from 'Components/Page/PageContent';
@@ -11,7 +12,7 @@ import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import { align, icons } from 'Helpers/Props';
import { align, icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import HistoryRowConnector from './HistoryRowConnector';
@@ -83,9 +84,9 @@ class History extends Component {
{
!isFetchingAny && hasError &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadHistory')}
</div>
</Alert>
}
{
@@ -93,9 +94,9 @@ class History extends Component {
// wait for the episodes to populate because they are never coming.
isPopulated && !hasError && !items.length &&
<div>
<Alert kind={kinds.INFO}>
{translate('NoHistory')}
</div>
</Alert>
}
{

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -12,7 +13,7 @@ import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import { align, icons } from 'Helpers/Props';
import { align, icons, kinds } from 'Helpers/Props';
import getRemovedItems from 'Utilities/Object/getRemovedItems';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
@@ -231,17 +232,17 @@ class Queue extends Component {
{
!isRefreshing && hasError ?
<div>
<Alert kind={kinds.DANGER}>
{translate('FailedToLoadQueue')}
</div> :
</Alert> :
null
}
{
isAllPopulated && !hasError && !items.length ?
<div>
<Alert kind={kinds.INFO}>
{translate('QueueIsEmpty')}
</div> :
</Alert> :
null
}

View File

@@ -88,7 +88,7 @@ class RemoveQueueItemsModal extends Component {
<ModalBody>
<div className={styles.message}>
{selectedCount > 1 ? translate('AreYouSureYouWantToRemoveSelectedItemsFromQueue', selectedCount) : translate('AreYouSureYouWantToRemoveSelectedItemFromQueue')}
{selectedCount > 1 ? translate('RemoveSelectedItemsQueueMessageText', selectedCount) : translate('RemoveSelectedItemQueueMessageText')}
</div>
{
@@ -133,7 +133,7 @@ class RemoveQueueItemsModal extends Component {
kind={kinds.DANGER}
onPress={this.onRemoveConfirmed}
>
Remove
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -1,9 +1,11 @@
import { reduce } from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected';
@@ -105,9 +107,9 @@ class ImportMovie extends Component {
{
!rootFoldersFetching && !!rootFoldersError ?
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadRootFolders')}
</div> :
</Alert> :
null
}
@@ -116,9 +118,9 @@ class ImportMovie extends Component {
!rootFoldersFetching &&
rootFoldersPopulated &&
!unmappedFolders.length ?
<div>
<Alert kind={kinds.INFO}>
{translate('AllMoviesInPathHaveBeenImported', [path])}
</div> :
</Alert> :
null
}

View File

@@ -92,9 +92,9 @@ class ImportMovieSelectFolder extends Component {
{
!isFetching && error ?
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadRootFolders')}
</div> :
</Alert> :
null
}

View File

@@ -1,6 +1,8 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import AgendaConnector from './Agenda/AgendaConnector';
import * as calendarViews from './calendarViews';
@@ -31,9 +33,9 @@ class Calendar extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadTheCalendar')}
</div>
</Alert>
}
{

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -9,7 +10,7 @@ import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { align, icons, sortDirections } from 'Helpers/Props';
import { align, icons, kinds, sortDirections } from 'Helpers/Props';
import styles from 'Movie/Index/MovieIndex.css';
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
import translate from 'Utilities/String/translate';
@@ -313,9 +314,9 @@ class Collection extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadCollections')}
</div>
</Alert>
}
{

View File

@@ -63,6 +63,7 @@ function ProviderFieldFormGroup(props) {
name,
label,
helpText,
helpTextWarning,
helpLink,
placeholder,
value,
@@ -96,6 +97,7 @@ function ProviderFieldFormGroup(props) {
name={name}
label={label}
helpText={helpText}
helpTextWarning={helpTextWarning}
helpLink={helpLink}
placeholder={placeholder}
value={value}
@@ -122,6 +124,7 @@ ProviderFieldFormGroup.propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
helpText: PropTypes.string,
helpTextWarning: PropTypes.string,
helpLink: PropTypes.string,
placeholder: PropTypes.string,
value: PropTypes.any,

View File

@@ -19,6 +19,8 @@ function createCleanMovieSelector() {
year,
images,
alternateTitles = [],
tmdbId,
imdbId,
tags = []
} = movie;
@@ -29,6 +31,8 @@ function createCleanMovieSelector() {
year,
images,
alternateTitles,
tmdbId,
imdbId,
firstCharacter: title.charAt(0).toLowerCase(),
tags: tags.reduce((acc, id) => {
const matchingTag = allTags.find((tag) => tag.id === id);

View File

@@ -12,6 +12,8 @@ function MovieSearchResult(props) {
year,
images,
alternateTitles,
tmdbId,
imdbId,
tags
} = props;
@@ -47,6 +49,22 @@ function MovieSearchResult(props) {
null
}
{
match.key === 'tmdbId' && tmdbId ?
<div className={styles.alternateTitle}>
TmdbId: {tmdbId}
</div> :
null
}
{
match.key === 'imdbId' && imdbId ?
<div className={styles.alternateTitle}>
ImdbId: {imdbId}
</div> :
null
}
{
tag ?
<div className={styles.tagContainer}>
@@ -69,6 +87,8 @@ MovieSearchResult.propTypes = {
year: PropTypes.number.isRequired,
images: PropTypes.arrayOf(PropTypes.object).isRequired,
alternateTitles: PropTypes.arrayOf(PropTypes.object).isRequired,
tmdbId: PropTypes.number,
imdbId: PropTypes.string,
tags: PropTypes.arrayOf(PropTypes.object).isRequired,
match: PropTypes.object.isRequired
};

View File

@@ -9,6 +9,8 @@ const fuseOptions = {
keys: [
'title',
'alternateTitles.title',
'tmdbId',
'imdbId',
'tags.label'
]
};

View File

@@ -1,6 +1,8 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { kinds } from 'Helpers/Props';
function PageSectionContent(props) {
const {
@@ -17,7 +19,7 @@ function PageSectionContent(props) {
);
} else if (!isFetching && !!error) {
return (
<div>{errorMessage}</div>
<Alert kind={kinds.DANGER}>{errorMessage}</Alert>
);
} else if (isPopulated && !error) {
return (

View File

@@ -16,6 +16,46 @@
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
color: var(--white);
transition: width 0.6s ease;
&.default {
background-color: var(--darkGray);
}
&.primary {
background-color: var(--primaryColor);
}
&.danger {
background-color: var(--dangerColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, color(#f05050 shade(5%)), color(#f05050 shade(5%)) 5px, color(#f05050 shade(15%)) 5px, color(#f05050 shade(15%)) 10px);
}
}
&.success {
background-color: var(--successColor);
}
&.purple {
background-color: var(--purple);
}
&.warning {
background-color: var(--warningColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, #ffa500, #ffa500 5px, color(#ffa500 tint(15%)) 5px, color(#ffa500 tint(15%)) 10px);
}
}
&.info {
background-color: var(--infoColor);
}
&.queue {
background-color: var(--queueColor);
}
}
.frontTextContainer {
@@ -45,46 +85,6 @@
cursor: default;
}
.default {
background-color: var(--darkGray);
}
.primary {
background-color: var(--primaryColor);
}
.danger {
background-color: var(--dangerColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, color(#f05050 shade(5%)), color(#f05050 shade(5%)) 5px, color(#f05050 shade(15%)) 5px, color(#f05050 shade(15%)) 10px);
}
}
.success {
background-color: var(--successColor);
}
.purple {
background-color: var(--purple);
}
.warning {
background-color: var(--warningColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, #ffa500, #ffa500 5px, color(#ffa500 tint(15%)) 5px, color(#ffa500 tint(15%)) 10px);
}
}
.info {
background-color: var(--infoColor);
}
.queue {
background-color: var(--queueColor);
}
.small {
height: $progressBarSmallHeight;

View File

@@ -38,7 +38,7 @@ function ProgressBar(props) {
{
showText && width ?
<div
className={styles.backTextContainer}
className={classNames(styles.backTextContainer, styles[kind])}
style={{ width: actualWidth }}
>
<div className={styles.backText}>
@@ -67,7 +67,7 @@ function ProgressBar(props) {
{
showText ?
<div
className={styles.frontTextContainer}
className={classNames(styles.frontTextContainer, styles[kind])}
style={{ width: progressPercent }}
>
<div

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -10,7 +11,7 @@ import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import { align, icons, sortDirections } from 'Helpers/Props';
import { align, icons, kinds, sortDirections } from 'Helpers/Props';
import styles from 'Movie/Index/MovieIndex.css';
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
import translate from 'Utilities/String/translate';
@@ -369,9 +370,9 @@ class DiscoverMovie extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadMovies')}
</div>
</Alert>
}
{

View File

@@ -2,6 +2,7 @@ import React, { useCallback, useState } from 'react';
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import { LanguageSettingsAppState } from 'App/State/SettingsAppState';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -86,7 +87,9 @@ function SelectLanguageModalContent(props: SelectLanguageModalContentProps) {
{isFetching ? <LoadingIndicator /> : null}
{!isFetching && error ? (
<div>{translate('UnableToLoadLanguages')}</div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadLanguages')}
</Alert>
) : null}
{isPopulated && !error ? (

View File

@@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import { Error } from 'App/State/AppSectionState';
import AppState from 'App/State/AppState';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -130,7 +131,9 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) {
{isFetching && <LoadingIndicator />}
{!isFetching && error ? (
<div>{translate('UnableToLoadQualities')}</div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadQualities')}
</Alert>
) : null}
{isPopulated && !error ? (

View File

@@ -10,6 +10,7 @@ import { SelectProvider } from 'App/SelectContext';
import ClientSideCollectionAppState from 'App/State/ClientSideCollectionAppState';
import MoviesAppState, { MovieIndexAppState } from 'App/State/MoviesAppState';
import { RSS_SYNC } from 'Commands/commandNames';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -20,7 +21,7 @@ import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import withScrollPosition from 'Components/withScrollPosition';
import { align, icons } from 'Helpers/Props';
import { align, icons, kinds } from 'Helpers/Props';
import SortDirection from 'Helpers/Props/SortDirection';
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
import NoMovie from 'Movie/NoMovie';
@@ -337,7 +338,9 @@ const MovieIndex = withScrollPosition((props: MovieIndexProps) => {
{isFetching && !isPopulated ? <LoadingIndicator /> : null}
{!isFetching && !!error ? (
<div>{translate('UnableToLoadMovies')}</div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadMovies')}
</Alert>
) : null}
{isLoaded ? (

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -109,9 +110,9 @@ class FileEditModalContent extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadQualities')}
</div>
</Alert>
}
{

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -92,9 +93,9 @@ class SelectQualityModalContent extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadQualities')}
</div>
</Alert>
}
{

View File

@@ -1,8 +1,10 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import RootFolderRowConnector from './RootFolderRowConnector';
@@ -44,9 +46,9 @@ function RootFolders(props) {
if (!isFetching && !!error) {
return (
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadRootFolders')}
</div>
</Alert>
);
}

View File

@@ -152,13 +152,7 @@ class CustomFormat extends Component {
isOpen={this.state.isDeleteCustomFormatModalOpen}
kind={kinds.DANGER}
title={translate('DeleteCustomFormat')}
message={
<div>
<div>
{translate('AreYouSureYouWantToDeleteFormat', [name])}
</div>
</div>
}
message={translate('DeleteCustomFormatMessageText', [name])}
confirmLabel={translate('Delete')}
isSpinning={isDeleting}
onConfirm={this.onConfirmDeleteCustomFormat}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Button from 'Components/Link/Button';
import ClipboardButton from 'Components/Link/ClipboardButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
@@ -41,9 +42,9 @@ class ExportCustomFormatModalContent extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadCustomFormats')}
</div>
</Alert>
}
{

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -11,7 +12,7 @@ import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, sizes } from 'Helpers/Props';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './ImportCustomFormatModalContent.css';
@@ -95,9 +96,9 @@ class ImportCustomFormatModalContent extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadCustomFormats')}
</div>
</Alert>
}
{

View File

@@ -78,7 +78,7 @@ class Specification extends Component {
<IconButton
className={styles.cloneButton}
title={translate('CloneFormatTag')}
title={translate('CloneCondition')}
name={icons.CLONE}
onPress={this.onCloneSpecificationPress}
/>
@@ -114,14 +114,8 @@ class Specification extends Component {
<ConfirmModal
isOpen={this.state.isDeleteSpecificationModalOpen}
kind={kinds.DANGER}
title={translate('DeleteCustomFormat')}
message={
<div>
<div>
{translate('AreYouSureYouWantToDeleteFormat', [name])}
</div>
</div>
}
title={translate('DeleteCondition')}
message={translate('DeleteConditionMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteSpecification}
onCancel={this.onDeleteSpecificationModalClose}

View File

@@ -29,9 +29,9 @@ function DownloadClientOptions(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadDownloadClientOptions')}
</div>
</Alert>
}
{

View File

@@ -88,8 +88,8 @@ class RemotePathMapping extends Component {
<ConfirmModal
isOpen={this.state.isDeleteRemotePathMappingModalOpen}
kind={kinds.DANGER}
title={translate('DeleteDelayProfile')}
message={translate('AreYouSureYouWantToDeleteThisRemotePathMapping')}
title={translate('DeleteRemotePathMapping')}
message={translate('DeleteRemotePathMappingMessageText')}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteRemotePathMapping}
onCancel={this.onDeleteRemotePathMappingModalClose}

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ConfirmModal from 'Components/Modal/ConfirmModal';
@@ -123,9 +124,9 @@ class GeneralSettings extends Component {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadGeneralSettings')}
</div>
</Alert>
}
{

View File

@@ -168,7 +168,7 @@ class SecuritySettings extends Component {
isOpen={this.state.isConfirmApiKeyResetModalOpen}
kind={kinds.DANGER}
title={translate('ResetAPIKey')}
message={translate('AreYouSureYouWantToResetYourAPIKey')}
message={translate('ResetAPIKeyMessageText')}
confirmLabel={translate('Reset')}
onConfirm={this.onConfirmResetApiKey}
onCancel={this.onCloseResetApiKeyModal}

View File

@@ -89,7 +89,7 @@ class ImportListExclusion extends Component {
isOpen={this.state.isDeleteImportExclusionModalOpen}
kind={kinds.DANGER}
title={translate('DeleteImportListExclusion')}
message={translate('AreYouSureYouWantToDeleteThisImportListExclusion')}
message={translate('DeleteImportListExclusionMessageText')}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteImportExclusion}
onCancel={this.onDeleteImportExclusionModalClose}

View File

@@ -1,12 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes } from 'Helpers/Props';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function ImportListOptions(props) {
@@ -37,9 +38,9 @@ function ImportListOptions(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadListOptions')}
</div>
</Alert>
}
{

View File

@@ -1,12 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes } from 'Helpers/Props';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function IndexerOptions(props) {
@@ -28,9 +29,9 @@ function IndexerOptions(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadIndexerOptions')}
</div>
</Alert>
}
{

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
@@ -8,7 +9,7 @@ import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { inputTypes, sizes } from 'Helpers/Props';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import RootFoldersConnector from 'RootFolder/RootFoldersConnector';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
@@ -72,9 +73,9 @@ class MediaManagement extends Component {
{
!isFetching && error ?
<FieldSet legend={translate('NamingSettings')}>
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadMediaManagementSettings')}
</div>
</Alert>
</FieldSet> : null
}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
@@ -7,7 +8,7 @@ import FormInputButton from 'Components/Form/FormInputButton';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes, sizes } from 'Helpers/Props';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import NamingModal from './NamingModal';
import styles from './Naming.css';
@@ -110,9 +111,9 @@ class Naming extends Component {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadNamingSettings')}
</div>
</Alert>
}
{

View File

@@ -6,8 +6,9 @@ import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes } from 'Helpers/Props';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import Alert from '../../../Components/Alert';
// Note: Do Not Translate Certification Countries
@@ -43,9 +44,9 @@ function MetadataOptions(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadIndexerOptions')}
</div>
</Alert>
}
{

View File

@@ -141,7 +141,7 @@ class DelayProfile extends Component {
isOpen={this.state.isDeleteDelayProfileModalOpen}
kind={kinds.DANGER}
title={translate('DeleteDelayProfile')}
message={translate('AreYouSureYouWantToDeleteThisDelayProfile')}
message={translate('DeleteDelayProfileMessageText')}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteDelayProfile}
onCancel={this.onDeleteDelayProfileModalClose}

View File

@@ -60,17 +60,19 @@ class ResetQualityDefinitionsModalContent extends Component {
<ModalBody>
<div className={styles.messageContainer}>
{translate('AreYouSureYouWantToResetQualityDefinitions')}
{translate('ResetQualityDefinitionsMessageText')}
</div>
<FormGroup>
<FormLabel>{translate('ResetTitles')}</FormLabel>
<FormLabel>
{translate('ResetTitles')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="resetDefinitionTitles"
value={resetDefinitionTitles}
helpText={translate('ResetTitlesHelpText')}
helpText={translate('ResetDefinitionTitlesHelpText')}
onChange={this.onResetDefinitionTitlesChange}
/>
</FormGroup>

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
@@ -8,7 +9,7 @@ import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { inputTypes } from 'Helpers/Props';
import { inputTypes, kinds } from 'Helpers/Props';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import themes from 'Styles/Themes';
import titleCase from 'Utilities/String/titleCase';
@@ -87,9 +88,9 @@ class UISettings extends Component {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadUISettings')}
</div>
</Alert>
}
{

View File

@@ -234,6 +234,18 @@ export const sortPredicates = {
}
return padNumber(result.toString(), 2) + qualityName;
},
inCinemas: function(item) {
return item.inCinemas || '';
},
physicalRelease: function(item) {
return item.physicalRelease || '';
},
digitalRelease: function(item) {
return item.digitalRelease || '';
}
};

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -8,7 +9,7 @@ import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { icons } from 'Helpers/Props';
import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import BackupRow from './BackupRow';
import RestoreBackupModalConnector from './RestoreBackupModalConnector';
@@ -107,16 +108,16 @@ class Backups extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadBackups')}
</div>
</Alert>
}
{
noBackups &&
<div>
<Alert kind={kinds.INFO}>
{translate('NoBackupsAreAvailable')}
</div>
</Alert>
}
{

View File

@@ -27,19 +27,47 @@ namespace NzbDrone.Api.Test.ClientSchemaTests
var schema = SchemaBuilder.ToSchema(model);
schema.Should().Contain(c => c.Order == 1 && c.Name == "lastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && (string)c.Value == "Poop");
schema.Should().Contain(c => c.Order == 0 && c.Name == "firstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && (string)c.Value == "Bob");
schema.Should().Contain(c => c.Order == 1 && c.Name == "lastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && c.HelpTextWarning == "Mandatory Last Name" && (string)c.Value == "Poop");
schema.Should().Contain(c => c.Order == 0 && c.Name == "firstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && c.HelpTextWarning == "Mandatory First Name" && (string)c.Value == "Bob");
}
[Test]
public void schema_should_have_nested_fields()
{
var model = new NestedTestModel
{
Name =
{
FirstName = "Bob",
LastName = "Poop"
}
};
var schema = SchemaBuilder.ToSchema(model);
schema.Should().Contain(c => c.Order == 0 && c.Name == "name.firstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && c.HelpTextWarning == "Mandatory First Name" && (string)c.Value == "Bob");
schema.Should().Contain(c => c.Order == 1 && c.Name == "name.lastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && c.HelpTextWarning == "Mandatory Last Name" && (string)c.Value == "Poop");
schema.Should().Contain(c => c.Order == 2 && c.Name == "quote" && c.Label == "Quote" && c.HelpText == "Your Favorite Quote");
}
}
public class TestModel
{
[FieldDefinition(0, Label = "First Name", HelpText = "Your First Name")]
[FieldDefinition(0, Label = "First Name", HelpText = "Your First Name", HelpTextWarning = "Mandatory First Name")]
public string FirstName { get; set; }
[FieldDefinition(1, Label = "Last Name", HelpText = "Your Last Name")]
[FieldDefinition(1, Label = "Last Name", HelpText = "Your Last Name", HelpTextWarning = "Mandatory Last Name")]
public string LastName { get; set; }
public string Other { get; set; }
}
public class NestedTestModel
{
[FieldDefinition(0)]
public TestModel Name { get; set; } = new TestModel();
[FieldDefinition(1, Label = "Quote", HelpText = "Your Favorite Quote")]
public string Quote { get; set; }
}
}

View File

@@ -10,7 +10,9 @@ namespace NzbDrone.Common.Test.InstrumentationTests
// Indexer Urls
[TestCase(@"https://iptorrents.com/torrents/rss?u=mySecret;tp=mySecret;l5;download")]
[TestCase(@"http://rss.torrentleech.org/mySecret")]
[TestCase(@"http://rss.torrentleech.org/rss/download/12345/01233210/filename.torrent")]
[TestCase(@"https://rss24h.torrentleech.org/mySecret")]
[TestCase(@"http://rss.torrentleech.org/rss/download/12345/01233210/file.name-RLSGRP.torrent")]
[TestCase(@"https://www.torrentleech.org/rss/download/12345/01233210/file.name-RLSGRP.torrent")]
[TestCase(@"http://www.bitmetv.org/rss.php?uid=mySecret&passkey=mySecret")]
[TestCase(@"https://rss.omgwtfnzbs.org/rss-search.php?catid=19,20&user=sonarr&api=mySecret&eng=1")]
[TestCase(@"https://dognzb.cr/fetch/2b51db35e1912ffc138825a12b9933d2/2b51db35e1910123321025a12b9933d2")]
@@ -44,6 +46,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests
// Deluge
[TestCase(@",{""download_location"": ""C:\Users\\mySecret mySecret\\Downloads""}")]
[TestCase(@",{""download_location"": ""/home/mySecret/Downloads""}")]
[TestCase(@",{""download_location"": ""/Users/mySecret/Downloads""}")]
[TestCase(@"auth.login(""mySecret"")")]
// Download Station
@@ -59,8 +62,11 @@ namespace NzbDrone.Common.Test.InstrumentationTests
// Internal
[TestCase(@"OutputPath=/home/mySecret/Downloads")]
[TestCase(@"OutputPath=/Users/mySecret/Downloads")]
[TestCase("Hardlinking episode file: /home/mySecret/Downloads to /media/abc.mkv")]
[TestCase("Hardlinking episode file: /Users/mySecret/Downloads to /media/abc.mkv")]
[TestCase("Hardlink '/home/mySecret/Downloads/abs.mkv' to '/media/abc.mkv' failed.")]
[TestCase("Hardlink '/Users/mySecret/Downloads/abs.mkv' to '/media/abc.mkv' failed.")]
[TestCase("https://notifiarr.com/notifier.php: api=1234530f-422f-4aac-b6b3-01233210aaaa&radarr_health_issue_message=Download")]
[TestCase("/readarr/signalr/messages/negotiate?access_token=1234530f422f4aacb6b301233210aaaa&negotiateVersion=1")]
[TestCase(@"[Info] MigrationController: *** Migrating Database=radarr-main;Host=postgres14;Username=mySecret;Password=mySecret;Port=5432;Enlist=False ***")]

View File

@@ -60,8 +60,7 @@ namespace NzbDrone.Common.Http
if (request.AllowAutoRedirect && response.HasHttpRedirect)
{
var autoRedirectChain = new List<string>();
autoRedirectChain.Add(request.Url.ToString());
var autoRedirectChain = new List<string> { request.Url.ToString() };
do
{
@@ -75,6 +74,14 @@ namespace NzbDrone.Common.Http
throw new WebException($"Too many automatic redirections were attempted for {autoRedirectChain.Join(" -> ")}", WebExceptionStatus.ProtocolError);
}
// 302 or 303 should default to GET on redirect even if POST on original
if (RequestRequiresForceGet(response.StatusCode, response.Request.Method))
{
request.Method = HttpMethod.Get;
request.ContentData = null;
request.ContentSummary = null;
}
response = ExecuteRequest(request, cookieContainer);
}
while (response.HasHttpRedirect);
@@ -105,6 +112,16 @@ namespace NzbDrone.Common.Http
return response;
}
private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod)
{
return statusCode switch
{
HttpStatusCode.Moved or HttpStatusCode.Found or HttpStatusCode.MultipleChoices => requestMethod == HttpMethod.Post,
HttpStatusCode.SeeOther => requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head,
_ => false,
};
}
private HttpResponse ExecuteRequest(HttpRequest request, CookieContainer cookieContainer)
{
foreach (var interceptor in _requestInterceptors)

View File

@@ -50,6 +50,8 @@ namespace NzbDrone.Common.Http
public bool HasHttpError => (int)StatusCode >= 400;
public bool HasHttpServerError => (int)StatusCode >= 500;
public bool HasHttpRedirect => StatusCode == HttpStatusCode.Moved ||
StatusCode == HttpStatusCode.MovedPermanently ||
StatusCode == HttpStatusCode.Found ||

View File

@@ -7,55 +7,55 @@ namespace NzbDrone.Common.Instrumentation
{
public class CleanseLogMessage
{
private static readonly Regex[] CleansingRules = new[]
{
// Url
new Regex(@"(?<=\?|&|: )(apikey|(?:access[-_]?)?token|passkey|auth|authkey|user|uid|api|[a-z_]*apikey|account|passwd)=(?<secret>[^&=]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled),
new Regex(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"\b(\w*)?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
private static readonly Regex[] CleansingRules =
{
// Url
new (@"(?<=\?|&|: )(apikey|(?:access[-_]?)?token|passkey|auth|authkey|user|uid|api|[a-z_]*apikey|account|passwd)=(?<secret>[^&=]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"rss(24h)?\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
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),
// Trackers Announce Keys; Designed for Qbit Json; should work for all in theory
new Regex(@"announce(\.php)?(/|%2f|%3fpasskey%3d)(?<secret>[a-z0-9]{16,})|(?<secret>[a-z0-9]{16,})(/|%2f)announce"),
// 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"),
// Path
new Regex(@"C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"/home/(?<secret>[^/""]+?)(/|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Path
new (@"C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"/(home|Users)/(?<secret>[^/""]+?)(/|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// NzbGet
new Regex(@"""Name""\s*:\s*""[^""]*(username|password)""\s*,\s*""Value""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// NzbGet
new (@"""Name""\s*:\s*""[^""]*(username|password)""\s*,\s*""Value""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Sabnzbd
new Regex(@"""[^""]*(username|password|api_?key|nzb_key)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"""email_(account|to|from|pwd)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Sabnzbd
new (@"""[^""]*(username|password|api_?key|nzb_key)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"""email_(account|to|from|pwd)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// uTorrent
new Regex(@"\[""[a-z._]*(username|password)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"\[""(boss_key|boss_key_salt|proxy\.proxy)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// uTorrent
new (@"\[""[a-z._]*(username|password)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"\[""(boss_key|boss_key_salt|proxy\.proxy)"",\d,""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Deluge
new Regex(@"auth.login\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Deluge
new (@"auth.login\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// BroadcastheNet
new Regex(@"""?method""?\s*:\s*""(getTorrents)"",\s*""?params""?\s*:\s*\[\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"getTorrents\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=\?|&)(authkey|torrent_pass)=(?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// BroadcastheNet
new (@"""?method""?\s*:\s*""(getTorrents)"",\s*""?params""?\s*:\s*\[\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"getTorrents\(""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=\?|&)(authkey|torrent_pass)=(?<secret>[^&=]+?)(?=""|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Plex
new Regex(@"(?<=\?|&)(X-Plex-Client-Identifier|X-Plex-Token)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Plex
new (@"(?<=\?|&)(X-Plex-Client-Identifier|X-Plex-Token)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Notifiarr
new Regex(@"api/v[0-9]/notification/radarr/(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Notifiarr
new (@"api/v[0-9]/notification/radarr/(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Discord
new Regex(@"discord.com/api/webhooks/((?<secret>[\w-]+)/)?(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase)
};
// Discord
new (@"discord.com/api/webhooks/((?<secret>[\w-]+)/)?(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase)
};
private static readonly Regex CleanseRemoteIPRegex = new Regex(@"(?:Auth-\w+(?<!Failure|Unauthorized) ip|from) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Compiled);
private static readonly Regex CleanseRemoteIPRegex = new (@"(?:Auth-\w+(?<!Failure|Unauthorized) ip|from) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Compiled);
public static string Cleanse(string message)
{
@@ -67,15 +67,15 @@ namespace NzbDrone.Common.Instrumentation
foreach (var regex in CleansingRules)
{
message = regex.Replace(message, m =>
{
var value = m.Value;
foreach (var capture in m.Groups["secret"].Captures.OfType<Capture>().Reverse())
{
var value = m.Value;
foreach (var capture in m.Groups["secret"].Captures.OfType<Capture>().Reverse())
{
value = value.Replace(capture.Index - m.Index, capture.Length, "(removed)");
}
value = value.Replace(capture.Index - m.Index, capture.Length, "(removed)");
}
return value;
});
return value;
});
}
message = CleanseRemoteIPRegex.Replace(message, CleanseRemoteIP);
@@ -86,7 +86,6 @@ namespace NzbDrone.Common.Instrumentation
private static string CleanseRemoteIP(Match match)
{
var group = match.Groups[1];
var valueAll = match.Value;
var valueIP = group.Value;
if (IPAddress.TryParse(valueIP, out var address) && !address.IsLocalAddress())

View File

@@ -225,6 +225,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
[TestCase("checkingDL")]
[TestCase("checkingUP")]
[TestCase("metaDL")]
[TestCase("checkingResumeData")]
public void queued_item_should_have_required_properties(string state)
{
var torrent = new QBittorrentTorrent

View File

@@ -109,6 +109,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Movie.Should.Not.Use.Dots.2022.1080p.BluRay.x265.10bit.Tigole", "Tigole")]
[TestCase("Movie.Title.2005.2160p.UHD.BluRay.TrueHD 7.1.Atmos.x265 - HQMUX", "HQMUX")]
[TestCase("Movie.Name.2022.1080p.BluRay.x264-VARYG (Blue Lock, Multi-Subs)", "VARYG")]
[TestCase("Movie Title (2023) (1080p BluRay x265 SDR AAC 2.0 English Vyndros)", "Vyndros")]
public void should_parse_exception_release_group(string title, string expected)
{
Parser.Parser.ParseReleaseGroup(title).Should().Be(expected);

View File

@@ -0,0 +1,43 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class UrlFixture : CoreTest
{
[TestCase("[www.test.com] - Movie.Title.2023.720p.HDTV.X264-DIMENSION", "Movie Title")]
[TestCase("test.net - Movie.Title.2023.720p.HDTV.X264-DIMENSION", "Movie Title")]
[TestCase("[www.test-hyphen.com] - Movie.Title.2023.720p.HDTV.X264-DIMENSION", "Movie Title")]
[TestCase("www.test123.org - Movie.Title.2023.720p.HDTV.X264-DIMENSION", "Movie Title")]
[TestCase("[test.co.uk] - Movie.Title.2023.720p.HDTV.X264-DIMENSION", "Movie Title")]
[TestCase("www.test-hyphen.net.au - Movie.Title.2023.720p.HDTV.X264-DIMENSION", "Movie Title")]
[TestCase("[www.test123.co.nz] - Movie.Title.2023.720p.HDTV.X264-DIMENSION", "Movie Title")]
[TestCase("test-hyphen123.org.au - Movie.Title.2023.720p.HDTV.X264-DIMENSION", "Movie Title")]
[TestCase("[www.test123.de] - Mad Movie Title 2023 [Bluray720p]", "Mad Movie Title")]
[TestCase("www.test-hyphen.de - Mad Movie Title 2023 [Bluray1080p]", "Mad Movie Title")]
[TestCase("www.test123.co.za - The Movie Title Bros. (2023)", "The Movie Title Bros.")]
[TestCase("[www.test-hyphen.ca] - Movie Title (2023)", "Movie Title")]
[TestCase("test123.ca - Movie Time 2023 720p HDTV x264 CRON", "Movie Time")]
[TestCase("[www.test-hyphen123.co.za] - Movie Title 2023", "Movie Title")]
public void should_not_parse_url_in_name(string postTitle, string title)
{
var result = Parser.Parser.ParseMovieTitle(postTitle).MovieTitle.CleanMovieTitle();
result.Should().Be(title.CleanMovieTitle());
}
[TestCase("Movie.2023.English.HDTV.XviD-LOL[www.abb.com]", "LOL")]
[TestCase("Movie Title 2023 English HDTV XviD LOL[www.academy.org]", null)]
[TestCase("Movie Title Now 2023 DVDRip XviD RUNNER[www.aetna.net]", null)]
[TestCase("Movie.Title.2023.DVDRip.XviD-RUNNER[www.alfaromeo.io]", "RUNNER")]
[TestCase("Movie.Title.2023.English.HDTV.XviD-LOL[www.abbott.gov]", "LOL")]
[TestCase("Movie Title 2023 English HDTV XviD LOL[www.actor.org]", null)]
[TestCase("Movie Title Future 2023 DVDRip XviD RUNNER[www.allstate.net]", null)]
public void should_not_parse_url_in_group(string title, string expected)
{
Parser.Parser.ParseReleaseGroup(title).Should().Be(expected);
}
}
}

View File

@@ -15,6 +15,7 @@ namespace NzbDrone.Core.Annotations
public string Label { get; set; }
public string Unit { get; set; }
public string HelpText { get; set; }
public string HelpTextWarning { get; set; }
public string HelpLink { get; set; }
public FieldType Type { get; set; }
public bool Advanced { get; set; }

View File

@@ -251,6 +251,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
case "queuedDL": // queuing is enabled and torrent is queued for download
case "checkingDL": // same as checkingUP, but torrent has NOT finished downloading
case "checkingUP": // torrent has finished downloading and is being checked. Set when `recheck torrent on completion` is enabled. In the event the check fails we shouldn't treat it as completed.
case "checkingResumeData": // torrent is checking resume data on load
item.Status = DownloadItemStatus.Queued;
break;

View File

@@ -48,13 +48,11 @@ namespace NzbDrone.Core.HealthCheck.Checks
try
{
var status = client.GetStatus();
var folders = status.OutputRootFolders;
var folders = status.OutputRootFolders.Where(folder => rootFolders.Any(r => r.Path.PathEquals(folder.FullPath)));
foreach (var folder in folders)
{
if (rootFolders.Any(r => r.Path.PathEquals(folder.FullPath)))
{
return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("DownloadClientCheckDownloadingToRoot"), client.Definition.Name, folder.FullPath), "#downloads-in-root-folder");
}
return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("DownloadClientCheckDownloadingToRoot"), client.Definition.Name, folder.FullPath), "#downloads-in-root-folder");
}
}
catch (DownloadClientException ex)

View File

@@ -32,7 +32,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check()
{
var clients = _downloadClientProvider.GetDownloadClients();
var clients = _downloadClientProvider.GetDownloadClients(true);
foreach (var client in clients)
{

View File

@@ -23,12 +23,14 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check()
{
var jackettAllProviders = _providerFactory.All().Where(
i => i.ConfigContract.Equals("TorznabSettings") &&
((i.Settings as TorznabSettings).BaseUrl.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) ||
(i.Settings as TorznabSettings).BaseUrl.Contains("/api/v2.0/indexers/all/results/torznab", StringComparison.InvariantCultureIgnoreCase) ||
(i.Settings as TorznabSettings).ApiPath.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) ||
(i.Settings as TorznabSettings).ApiPath.Contains("/api/v2.0/indexers/all/results/torznab", StringComparison.InvariantCultureIgnoreCase)));
var jackettAllProviders = _providerFactory.All()
.Where(
i => i.ConfigContract.Equals("TorznabSettings") &&
(((TorznabSettings)i.Settings).BaseUrl.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) ||
((TorznabSettings)i.Settings).BaseUrl.Contains("/api/v2.0/indexers/all/results/torznab", StringComparison.InvariantCultureIgnoreCase) ||
((TorznabSettings)i.Settings).ApiPath.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) ||
((TorznabSettings)i.Settings).ApiPath.Contains("/api/v2.0/indexers/all/results/torznab", StringComparison.InvariantCultureIgnoreCase)))
.ToArray();
if (jackettAllProviders.Empty())
{

View File

@@ -28,13 +28,12 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
var enabledProviders = _providerFactory.GetAvailableProviders();
var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(),
i => i.Definition.Id,
s => s.ProviderId,
(i, s) => new { Provider = i, Status = s })
.Where(p => p.Status.InitialFailure.HasValue &&
p.Status.InitialFailure.Value.Before(
DateTime.UtcNow.AddHours(-6)))
.ToList();
i => i.Definition.Id,
s => s.ProviderId,
(i, s) => new { Provider = i, Status = s })
.Where(p => p.Status.InitialFailure.HasValue &&
p.Status.InitialFailure.Value.Before(DateTime.UtcNow.AddHours(-6)))
.ToList();
if (backOffProviders.Empty())
{

View File

@@ -26,13 +26,12 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
var enabledProviders = _providerFactory.GetAvailableProviders();
var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(),
i => i.Definition.Id,
s => s.ProviderId,
(i, s) => new { Provider = i, Status = s })
.Where(p => p.Status.InitialFailure.HasValue &&
p.Status.InitialFailure.Value.After(
DateTime.UtcNow.AddHours(-6)))
.ToList();
i => i.Definition.Id,
s => s.ProviderId,
(i, s) => new { Provider = i, Status = s })
.Where(p => p.Status.InitialFailure.HasValue &&
p.Status.InitialFailure.Value.After(DateTime.UtcNow.AddHours(-6)))
.ToList();
if (backOffProviders.Empty())
{

View File

@@ -21,10 +21,10 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
// Not best for optimization but due to possible symlinks and junctions, we get mounts based on series path so internals can handle mount resolution.
var mounts = _movieService.AllMoviePaths()
.Select(p => _diskProvider.GetMount(p.Value))
.Where(m => m != null && m.MountOptions != null && m.MountOptions.IsReadOnly)
.DistinctBy(m => m.RootDirectory)
.ToList();
.Select(p => _diskProvider.GetMount(p.Value))
.Where(m => m is { MountOptions.IsReadOnly: true })
.DistinctBy(m => m.RootDirectory)
.ToList();
if (mounts.Any())
{

View File

@@ -18,10 +18,12 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check()
{
var ptpIndexers = _indexerFactory.All().Where(i => i.Settings.GetType() == typeof(PassThePopcornSettings));
var ptpIndexers = _indexerFactory.All()
.Where(i => i.Settings.GetType() == typeof(PassThePopcornSettings));
var ptpIndexerOldSettings = ptpIndexers
.Where(i => (i.Settings as PassThePopcornSettings).APIUser.IsNullOrWhiteSpace()).Select(i => i.Name);
.Where(i => ((PassThePopcornSettings)i.Settings).APIUser.IsNullOrWhiteSpace()).Select(i => i.Name)
.ToList();
if (ptpIndexerOldSettings.Any())
{

View File

@@ -31,35 +31,38 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check()
{
if (_configService.ProxyEnabled)
if (!_configService.ProxyEnabled)
{
var addresses = Dns.GetHostAddresses(_configService.ProxyHostname);
if (!addresses.Any())
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("ProxyCheckResolveIpMessage"), _configService.ProxyHostname), "#proxy-failed-resolve-ip");
}
return new HealthCheck(GetType());
}
var request = _cloudRequestBuilder.Create()
.Resource("/ping")
.Build();
var addresses = Dns.GetHostAddresses(_configService.ProxyHostname);
try
{
var response = _client.Execute(request);
if (!addresses.Any())
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("ProxyCheckResolveIpMessage"), _configService.ProxyHostname), "#proxy-failed-resolve-ip");
}
// We only care about 400 responses, other error codes can be ignored
if (response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error("Proxy Health Check failed: {0}", response.StatusCode);
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("ProxyCheckBadRequestMessage"), response.StatusCode), "#proxy-failed-test");
}
}
catch (Exception ex)
var request = _cloudRequestBuilder.Create()
.Resource("/ping")
.Build();
try
{
var response = _client.Execute(request);
// We only care about 400 responses, other error codes can be ignored
if (response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Proxy Health Check failed");
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("ProxyCheckFailedToTestMessage"), request.Url), "#proxy-failed-test");
_logger.Error("Proxy Health Check failed: {0}", response.StatusCode);
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("ProxyCheckBadRequestMessage"), response.StatusCode), "#proxy-failed-test");
}
}
catch (Exception ex)
{
_logger.Error(ex, "Proxy Health Check failed");
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("ProxyCheckFailedToTestMessage"), request.Url), "#proxy-failed-test");
}
return new HealthCheck(GetType());
}

View File

@@ -62,6 +62,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
var status = client.GetStatus();
var folders = status.OutputRootFolders;
foreach (var folder in folders)
{
if (!folder.IsValid)
@@ -70,14 +71,13 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckWrongOSPath"), client.Definition.Name, folder.FullPath, _osInfo.Name), "#bad-remote-path-mapping");
}
else if (_osInfo.IsDocker)
if (_osInfo.IsDocker)
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckBadDockerPath"), client.Definition.Name, folder.FullPath, _osInfo.Name), "#docker-bad-remote-path-mapping");
}
else
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckLocalWrongOSPath"), client.Definition.Name, folder.FullPath, _osInfo.Name), "#bad-download-client-settings");
}
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckLocalWrongOSPath"), client.Definition.Name, folder.FullPath, _osInfo.Name), "#bad-download-client-settings");
}
if (!_diskProvider.FolderExists(folder.FullPath))
@@ -86,14 +86,13 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckDockerFolderMissing"), client.Definition.Name, folder.FullPath), "#docker-bad-remote-path-mapping");
}
else if (!status.IsLocalhost)
if (!status.IsLocalhost)
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckLocalFolderMissing"), client.Definition.Name, folder.FullPath), "#bad-remote-path-mapping");
}
else
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckGenericPermissions"), client.Definition.Name, folder.FullPath), "#permissions-error");
}
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckGenericPermissions"), client.Definition.Name, folder.FullPath), "#permissions-error");
}
}
}
@@ -122,24 +121,21 @@ namespace NzbDrone.Core.HealthCheck.Checks
return new HealthCheck(GetType());
}
if (typeof(MovieImportFailedEvent).IsAssignableFrom(message.GetType()))
if (message is MovieImportFailedEvent failureMessage)
{
var failureMessage = (MovieImportFailedEvent)message;
// if we can see the file exists but the import failed then likely a permissions issue
if (failureMessage.MovieInfo != null)
{
var moviePath = failureMessage.MovieInfo.Path;
if (_diskProvider.FileExists(moviePath))
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckDownloadPermissions"), moviePath), "#permissions-error");
}
else
{
// If the file doesn't exist but MovieInfo is not null then the message is coming from
// ImportApprovedMovies and the file must have been removed part way through processing
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckFileRemoved"), moviePath), "#remote-path-file-removed");
}
// If the file doesn't exist but MovieInfo is not null then the message is coming from
// ImportApprovedMovies and the file must have been removed part way through processing
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckFileRemoved"), moviePath), "#remote-path-file-removed");
}
// If the previous case did not match then the failure occured in DownloadedMovieImportService,
@@ -170,14 +166,13 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckFilesWrongOSPath"), client.Definition.Name, dlpath, _osInfo.Name), "#bad-remote-path-mapping");
}
else if (_osInfo.IsDocker)
if (_osInfo.IsDocker)
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckFilesBadDockerPath"), client.Definition.Name, dlpath, _osInfo.Name), "#docker-bad-remote-path-mapping");
}
else
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckFilesLocalWrongOSPath"), client.Definition.Name, dlpath, _osInfo.Name), "#bad-download-client-settings");
}
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckFilesLocalWrongOSPath"), client.Definition.Name, dlpath, _osInfo.Name), "#bad-download-client-settings");
}
if (_diskProvider.FolderExists(dlpath))
@@ -190,15 +185,14 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckFolderPermissions"), client.Definition.Name, dlpath), "#docker-bad-remote-path-mapping");
}
else if (!status.IsLocalhost)
if (!status.IsLocalhost)
{
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckRemoteDownloadClient"), client.Definition.Name, dlpath), "#bad-remote-path-mapping");
}
else
{
// path mappings shouldn't be needed locally so probably a permissions issue
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckFilesGenericPermissions"), client.Definition.Name, dlpath), "#permissions-error");
}
// path mappings shouldn't be needed locally so probably a permissions issue
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckFilesGenericPermissions"), client.Definition.Name, dlpath), "#permissions-error");
}
catch (DownloadClientException ex)
{
@@ -215,10 +209,8 @@ namespace NzbDrone.Core.HealthCheck.Checks
return new HealthCheck(GetType());
}
else
{
return Check();
}
return Check();
}
}
}

View File

@@ -29,11 +29,11 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check()
{
var rootFolders = _movieService.AllMoviePaths()
.Select(s => _rootFolderService.GetBestRootFolderPath(s.Value))
.Distinct();
.Select(s => _rootFolderService.GetBestRootFolderPath(s.Value))
.Distinct();
var missingRootFolders = rootFolders.Where(s => !_diskProvider.FolderExists(s))
.ToList();
.ToList();
if (missingRootFolders.Any())
{

View File

@@ -22,7 +22,9 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check()
{
var discordSlackNotifications = _notificationFactory.GetAvailableProviders().Where(n => n.ConfigContract.Equals("SlackSettings") && (n.Definition.Settings as SlackSettings).WebHookUrl.Contains("discord"));
var discordSlackNotifications = _notificationFactory.GetAvailableProviders()
.Where(n => n.ConfigContract.Equals("SlackSettings") && ((SlackSettings)n.Definition.Settings).WebHookUrl.Contains("discord"))
.ToList();
if (discordSlackNotifications.Empty())
{
@@ -31,8 +33,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("DiscordUrlInSlackNotification"),
string.Join(", ", discordSlackNotifications.Select(n => n.Name))),
string.Format(_localizationService.GetLocalizedString("DiscordUrlInSlackNotification"), string.Join(", ", discordSlackNotifications.Select(n => n.Name))),
"#discord-as-slack-notification");
}
}

View File

@@ -24,8 +24,8 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check()
{
var request = _cloudRequestBuilder.Create()
.Resource("/time")
.Build();
.Resource("/time")
.Build();
var response = _client.Execute(request);
var result = Json.Deserialize<ServiceTimeResponse>(response.Content);

View File

@@ -76,7 +76,8 @@ namespace NzbDrone.Core.History
protected override SqlBuilder PagedBuilder() => new SqlBuilder(_database.DatabaseType)
.Join<MovieHistory, Movie>((h, m) => h.MovieId == m.Id)
.Join<Movie, Profile>((m, p) => m.ProfileId == p.Id);
.Join<Movie, Profile>((m, p) => m.ProfileId == p.Id)
.LeftJoin<Movie, MovieMetadata>((m, mm) => m.MovieMetadataId == mm.Id);
protected override IEnumerable<MovieHistory> PagedQuery(SqlBuilder sql) =>
_database.QueryJoined<MovieHistory, Movie, Profile>(sql, (hist, movie, profile) =>

View File

@@ -14,34 +14,32 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
using var mapper = _database.OpenConnection();
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" = ANY (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""RelativePath""
LIKE '_:\\%'
OR ""RelativePath""
LIKE '\\%'
OR ""RelativePath""
LIKE '/%'
)");
}
else
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""RelativePath""
LIKE '_:\%'
OR ""RelativePath""
LIKE '\%'
OR ""RelativePath""
LIKE '/%'
)");
}
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" = ANY (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""RelativePath""
LIKE '_:\\%'
OR ""RelativePath""
LIKE '\\%'
OR ""RelativePath""
LIKE '/%'
)");
}
else
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""RelativePath""
LIKE '_:\%'
OR ""RelativePath""
LIKE '\%'
OR ""RelativePath""
LIKE '/%'
)");
}
}
}

View File

@@ -14,13 +14,11 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""NamingConfig""
WHERE ""Id"" NOT IN (
SELECT ""Id"" FROM ""NamingConfig""
LIMIT 1)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""NamingConfig""
WHERE ""Id"" NOT IN (
SELECT ""Id"" FROM ""NamingConfig""
LIMIT 1)");
}
}
}

View File

@@ -14,13 +14,11 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""Users""
WHERE ""Id"" NOT IN (
SELECT ""Id"" FROM ""Users""
LIMIT 1)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""Users""
WHERE ""Id"" NOT IN (
SELECT ""Id"" FROM ""Users""
LIMIT 1)");
}
}
}

View File

@@ -16,29 +16,28 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
var mapper = _database.OpenConnection();
using var mapper = _database.OpenConnection();
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
mapper.Execute(@"DELETE FROM ""PendingReleases""
WHERE ""Added"" < @TwoWeeksAgo
AND ""Reason"" = ANY (@Reasons)",
new
{
TwoWeeksAgo = DateTime.UtcNow.AddDays(-14),
Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback }
});
WHERE ""Added"" < @TwoWeeksAgo
AND ""Reason"" = ANY (@Reasons)",
new
{
TwoWeeksAgo = DateTime.UtcNow.AddDays(-14),
Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback }
});
}
else
{
mapper.Execute(@"DELETE FROM ""PendingReleases""
WHERE ""Added"" < @TwoWeeksAgo
AND ""REASON"" IN @Reasons",
new
{
TwoWeeksAgo = DateTime.UtcNow.AddDays(-14),
Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback }
});
mapper.Execute(@"DELETE FROM ""PendingReleases""
WHERE ""Added"" < @TwoWeeksAgo
AND ""REASON"" IN @Reasons",
new
{
TwoWeeksAgo = DateTime.UtcNow.AddDays(-14),
Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback }
});
}
}
}

View File

@@ -20,30 +20,26 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
private void DeleteDuplicateMovieMetadata()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT MIN(""Id"") FROM ""MetadataFiles""
WHERE ""Type"" = 1
GROUP BY ""MovieId"", ""Consumer""
HAVING COUNT(""MovieId"") > 1
)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT MIN(""Id"") FROM ""MetadataFiles""
WHERE ""Type"" = 1
GROUP BY ""MovieId"", ""Consumer""
HAVING COUNT(""MovieId"") > 1
)");
}
private void DeleteDuplicateMovieFileMetadata()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT MIN(""Id"") FROM ""MetadataFiles""
WHERE ""Type"" = 1
GROUP BY ""MovieFileId"", ""Consumer""
HAVING COUNT(""MovieFileId"") > 1
)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT MIN(""Id"") FROM ""MetadataFiles""
WHERE ""Type"" = 1
GROUP BY ""MovieFileId"", ""Consumer""
HAVING COUNT(""MovieFileId"") > 1
)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""AlternativeTitles""
WHERE ""Id"" IN (
SELECT ""AlternativeTitles"".""Id"" FROM ""AlternativeTitles""
LEFT OUTER JOIN ""MovieMetadata""
ON ""AlternativeTitles"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""MovieMetadata"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""AlternativeTitles""
WHERE ""Id"" IN (
SELECT ""AlternativeTitles"".""Id"" FROM ""AlternativeTitles""
LEFT OUTER JOIN ""MovieMetadata""
ON ""AlternativeTitles"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""MovieMetadata"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""Blocklist""
WHERE ""Id"" IN (
SELECT ""Blocklist"".""Id"" FROM ""Blocklist""
LEFT OUTER JOIN ""Movies""
ON ""Blocklist"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""Blocklist""
WHERE ""Id"" IN (
SELECT ""Blocklist"".""Id"" FROM ""Blocklist""
LEFT OUTER JOIN ""Movies""
ON ""Blocklist"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,13 +14,11 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""Collections"" WHERE ""TmdbId"" IN (SELECT ""X"".""TmdbId"" FROM (SELECT ""Collections"".""TmdbId"", COUNT(""Movies"".""Id"") as ""MovieCount"" FROM ""Collections""
LEFT OUTER JOIN ""MovieMetadata"" ON ""Collections"".""TmdbId"" = ""MovieMetadata"".""CollectionTmdbId""
LEFT OUTER JOIN ""Movies"" ON ""Movies"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
GROUP BY ""Collections"".""Id"") AS ""X"" WHERE ""X"".""MovieCount"" = 0)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""Collections"" WHERE ""TmdbId"" IN (SELECT ""X"".""TmdbId"" FROM (SELECT ""Collections"".""TmdbId"", COUNT(""Movies"".""Id"") as ""MovieCount"" FROM ""Collections""
LEFT OUTER JOIN ""MovieMetadata"" ON ""Collections"".""TmdbId"" = ""MovieMetadata"".""CollectionTmdbId""
LEFT OUTER JOIN ""Movies"" ON ""Movies"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
GROUP BY ""Collections"".""Id"") AS ""X"" WHERE ""X"".""MovieCount"" = 0)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""Credits""
WHERE ""Id"" IN (
SELECT ""Credits"".""Id"" FROM ""Credits""
LEFT OUTER JOIN ""MovieMetadata""
ON ""Credits"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""MovieMetadata"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""Credits""
WHERE ""Id"" IN (
SELECT ""Credits"".""Id"" FROM ""Credits""
LEFT OUTER JOIN ""MovieMetadata""
ON ""Credits"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""MovieMetadata"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,14 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
var mapper = _database.OpenConnection();
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""DownloadClientStatus""
WHERE ""Id"" IN (
SELECT ""DownloadClientStatus"".""Id"" FROM ""DownloadClientStatus""
LEFT OUTER JOIN ""DownloadClients""
ON ""DownloadClientStatus"".""ProviderId"" = ""DownloadClients"".""Id""
WHERE ""DownloadClients"".""Id"" IS NULL)");
WHERE ""Id"" IN (
SELECT ""DownloadClientStatus"".""Id"" FROM ""DownloadClientStatus""
LEFT OUTER JOIN ""DownloadClients""
ON ""DownloadClientStatus"".""ProviderId"" = ""DownloadClients"".""Id""
WHERE ""DownloadClients"".""Id"" IS NULL)");
}
}
}

View File

@@ -20,29 +20,25 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
private void DeleteOrphanedByMovie()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""ExtraFiles""
WHERE ""Id"" IN (
SELECT ""ExtraFiles"".""Id"" FROM ""ExtraFiles""
LEFT OUTER JOIN ""Movies""
ON ""ExtraFiles"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""ExtraFiles""
WHERE ""Id"" IN (
SELECT ""ExtraFiles"".""Id"" FROM ""ExtraFiles""
LEFT OUTER JOIN ""Movies""
ON ""ExtraFiles"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
private void DeleteOrphanedByMovieFile()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""ExtraFiles""
WHERE ""Id"" IN (
SELECT ""ExtraFiles"".""Id"" FROM ""ExtraFiles""
LEFT OUTER JOIN ""MovieFiles""
ON ""ExtraFiles"".""MovieFileId"" = ""MovieFiles"".""Id""
WHERE ""ExtraFiles"".""MovieFileId"" > 0
AND ""MovieFiles"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""ExtraFiles""
WHERE ""Id"" IN (
SELECT ""ExtraFiles"".""Id"" FROM ""ExtraFiles""
LEFT OUTER JOIN ""MovieFiles""
ON ""ExtraFiles"".""MovieFileId"" = ""MovieFiles"".""Id""
WHERE ""ExtraFiles"".""MovieFileId"" > 0
AND ""MovieFiles"".""Id"" IS NULL)");
}
}
}

View File

@@ -19,15 +19,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
private void CleanupOrphanedByMovie()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""History""
WHERE ""Id"" IN (
SELECT ""History"".""Id"" FROM ""History""
LEFT OUTER JOIN ""Movies""
ON ""History"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""History""
WHERE ""Id"" IN (
SELECT ""History"".""Id"" FROM ""History""
LEFT OUTER JOIN ""Movies""
ON ""History"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""IndexerStatus""
WHERE ""Id"" IN (
SELECT ""IndexerStatus"".""Id"" FROM ""IndexerStatus""
LEFT OUTER JOIN ""Indexers""
ON ""IndexerStatus"".""ProviderId"" = ""Indexers"".""Id""
WHERE ""Indexers"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""IndexerStatus""
WHERE ""Id"" IN (
SELECT ""IndexerStatus"".""Id"" FROM ""IndexerStatus""
LEFT OUTER JOIN ""Indexers""
ON ""IndexerStatus"".""ProviderId"" = ""Indexers"".""Id""
WHERE ""Indexers"".""Id"" IS NULL)");
}
}
}

View File

@@ -21,41 +21,35 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
private void DeleteOrphanedByMovie()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles""
LEFT OUTER JOIN ""Movies""
ON ""MetadataFiles"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles""
LEFT OUTER JOIN ""Movies""
ON ""MetadataFiles"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
private void DeleteOrphanedByMovieFile()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles""
LEFT OUTER JOIN ""MovieFiles""
ON ""MetadataFiles"".""MovieFileId"" = ""MovieFiles"".""Id""
WHERE ""MetadataFiles"".""MovieFileId"" > 0
AND ""MovieFiles"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles""
LEFT OUTER JOIN ""MovieFiles""
ON ""MetadataFiles"".""MovieFileId"" = ""MovieFiles"".""Id""
WHERE ""MetadataFiles"".""MovieFileId"" > 0
AND ""MovieFiles"".""Id"" IS NULL)");
}
private void DeleteWhereMovieFileIsZero()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""Type"" IN (1, 2)
AND ""MovieFileId"" = 0)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""Type"" IN (1, 2)
AND ""MovieFileId"" = 0)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MovieFiles""
WHERE ""Id"" IN (
SELECT ""MovieFiles"".""Id"" FROM ""MovieFiles""
LEFT OUTER JOIN ""Movies""
ON ""MovieFiles"".""Id"" = ""Movies"".""MovieFileId""
WHERE ""Movies"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MovieFiles""
WHERE ""Id"" IN (
SELECT ""MovieFiles"".""Id"" FROM ""MovieFiles""
LEFT OUTER JOIN ""Movies""
ON ""MovieFiles"".""Id"" = ""Movies"".""MovieFileId""
WHERE ""Movies"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,16 +14,14 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MovieMetadata""
WHERE ""Id"" IN (
SELECT ""MovieMetadata"".""Id"" FROM ""MovieMetadata""
LEFT OUTER JOIN ""Movies"" ON ""Movies"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
LEFT OUTER JOIN ""Collections"" ON ""Collections"".""TmdbId"" = ""MovieMetadata"".""CollectionTmdbId""
LEFT OUTER JOIN ""ImportListMovies"" ON ""ImportListMovies"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""Movies"".""Id"" IS NULL AND ""ImportListMovies"".""Id"" IS NULL AND ""Collections"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MovieMetadata""
WHERE ""Id"" IN (
SELECT ""MovieMetadata"".""Id"" FROM ""MovieMetadata""
LEFT OUTER JOIN ""Movies"" ON ""Movies"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
LEFT OUTER JOIN ""Collections"" ON ""Collections"".""TmdbId"" = ""MovieMetadata"".""CollectionTmdbId""
LEFT OUTER JOIN ""ImportListMovies"" ON ""ImportListMovies"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""Movies"".""Id"" IS NULL AND ""ImportListMovies"".""Id"" IS NULL AND ""Collections"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,16 +14,14 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"UPDATE ""Movies""
SET ""MovieFileId"" = 0
WHERE ""Id"" IN (
SELECT ""Movies"".""Id"" FROM ""Movies""
LEFT OUTER JOIN ""MovieFiles""
ON ""Movies"".""MovieFileId"" = ""MovieFiles"".""Id""
WHERE ""MovieFiles"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"UPDATE ""Movies""
SET ""MovieFileId"" = 0
WHERE ""Id"" IN (
SELECT ""Movies"".""Id"" FROM ""Movies""
LEFT OUTER JOIN ""MovieFiles""
ON ""Movies"".""MovieFileId"" = ""MovieFiles"".""Id""
WHERE ""MovieFiles"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MovieTranslations""
WHERE ""Id"" IN (
SELECT ""MovieTranslations"".""Id"" FROM ""MovieTranslations""
LEFT OUTER JOIN ""MovieMetadata""
ON ""MovieTranslations"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""MovieMetadata"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MovieTranslations""
WHERE ""Id"" IN (
SELECT ""MovieTranslations"".""Id"" FROM ""MovieTranslations""
LEFT OUTER JOIN ""MovieMetadata""
ON ""MovieTranslations"".""MovieMetadataId"" = ""MovieMetadata"".""Id""
WHERE ""MovieMetadata"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""PendingReleases""
WHERE ""Id"" IN (
SELECT ""PendingReleases"".""Id"" FROM ""PendingReleases""
LEFT OUTER JOIN ""Movies""
ON ""PendingReleases"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""PendingReleases""
WHERE ""Id"" IN (
SELECT ""PendingReleases"".""Id"" FROM ""PendingReleases""
LEFT OUTER JOIN ""Movies""
ON ""PendingReleases"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
}
}

View File

@@ -20,29 +20,25 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
private void DeleteOrphanedByMovie()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""SubtitleFiles""
WHERE ""Id"" IN (
SELECT ""SubtitleFiles"".""Id"" FROM ""SubtitleFiles""
LEFT OUTER JOIN ""Movies""
ON ""SubtitleFiles"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""SubtitleFiles""
WHERE ""Id"" IN (
SELECT ""SubtitleFiles"".""Id"" FROM ""SubtitleFiles""
LEFT OUTER JOIN ""Movies""
ON ""SubtitleFiles"".""MovieId"" = ""Movies"".""Id""
WHERE ""Movies"".""Id"" IS NULL)");
}
private void DeleteOrphanedByMovieFile()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""SubtitleFiles""
WHERE ""Id"" IN (
SELECT ""SubtitleFiles"".""Id"" FROM ""SubtitleFiles""
LEFT OUTER JOIN ""MovieFiles""
ON ""SubtitleFiles"".""MovieFileId"" = ""MovieFiles"".""Id""
WHERE ""SubtitleFiles"".""MovieFileId"" > 0
AND ""MovieFiles"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""SubtitleFiles""
WHERE ""Id"" IN (
SELECT ""SubtitleFiles"".""Id"" FROM ""SubtitleFiles""
LEFT OUTER JOIN ""MovieFiles""
ON ""SubtitleFiles"".""MovieFileId"" = ""MovieFiles"".""Id""
WHERE ""SubtitleFiles"".""MovieFileId"" > 0
AND ""MovieFiles"".""Id"" IS NULL)");
}
}
}

View File

@@ -18,8 +18,7 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
var mapper = _database.OpenConnection();
using var mapper = _database.OpenConnection();
var usedTags = new[] { "Movies", "Notifications", "DelayProfiles", "Restrictions", "ImportLists", "Indexers" }
.SelectMany(v => GetUsedTags(v, mapper))
.Distinct()

View File

@@ -24,13 +24,11 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
_logger.Debug("Not running scheduled task last execution cleanup during debug");
}
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"UPDATE ""ScheduledTasks""
SET ""LastExecution"" = @time
WHERE ""LastExecution"" > @time",
new { time = DateTime.UtcNow });
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"UPDATE ""ScheduledTasks""
SET ""LastExecution"" = @time
WHERE ""LastExecution"" > @time",
new { time = DateTime.UtcNow });
}
}
}

View File

@@ -95,11 +95,11 @@ namespace NzbDrone.Core.ImportLists.Radarr
return new
{
options = devices.OrderBy(d => d.Name, StringComparer.InvariantCultureIgnoreCase)
.Select(d => new
{
Value = d.Id,
Name = d.Name
})
.Select(d => new
{
Value = d.Id,
Name = d.Name
})
};
}
@@ -110,23 +110,21 @@ namespace NzbDrone.Core.ImportLists.Radarr
return new
{
options = devices.OrderBy(d => d.Label, StringComparer.InvariantCultureIgnoreCase)
.Select(d => new
{
Value = d.Id,
Name = d.Label
})
.Select(d => new
{
Value = d.Id,
Name = d.Label
})
};
}
if (action == "getRootFolders")
{
Settings.Validate().Filter("ApiKey").ThrowOnError();
var remoteRootfolders = _radarrV3Proxy.GetRootFolders(Settings);
var remoteRootFolders = _radarrV3Proxy.GetRootFolders(Settings);
return new
{
options = remoteRootfolders.OrderBy(d => d.Path, StringComparer.InvariantCultureIgnoreCase)
options = remoteRootFolders.OrderBy(d => d.Path, StringComparer.InvariantCultureIgnoreCase)
.Select(d => new
{
Value = d.Path,

View File

@@ -63,6 +63,12 @@ namespace NzbDrone.Core.ImportLists.Radarr
return new ValidationFailure("ApiKey", "API Key is invalid");
}
if (ex.Response.HasHttpRedirect)
{
_logger.Error(ex, "Radarr returned redirect and is invalid");
return new ValidationFailure("BaseUrl", "Radarr URL is invalid, are you missing a URL base?");
}
_logger.Error(ex, "Unable to connect to import list.");
return new ValidationFailure(string.Empty, $"Unable to connect to import list: {ex.Message}. Check the log surrounding this error for details.");
}
@@ -84,11 +90,18 @@ namespace NzbDrone.Core.ImportLists.Radarr
var baseUrl = settings.BaseUrl.TrimEnd('/');
var request = new HttpRequestBuilder(baseUrl).Resource(resource).Accept(HttpAccept.Json)
.SetHeader("X-Api-Key", settings.ApiKey).Build();
var request = new HttpRequestBuilder(baseUrl).Resource(resource)
.Accept(HttpAccept.Json)
.SetHeader("X-Api-Key", settings.ApiKey)
.Build();
var response = _httpClient.Get(request);
if ((int)response.StatusCode >= 300)
{
throw new HttpException(response);
}
var results = JsonConvert.DeserializeObject<List<TResource>>(response.Content);
return results;

View File

@@ -1,30 +1,58 @@
using NzbDrone.Core.Annotations;
namespace NzbDrone.Core.ImportLists.TMDb
{
public enum TMDbLanguageCodes
{
[FieldOption(Hint = "Danish")]
da,
[FieldOption(Hint = "Dutch")]
nl,
[FieldOption(Hint = "English")]
en,
[FieldOption(Hint = "Finnish")]
fi,
[FieldOption(Hint = "French")]
fr,
[FieldOption(Hint = "German")]
de,
[FieldOption(Hint = "Greek")]
el,
[FieldOption(Hint = "Hungarian")]
hu,
[FieldOption(Hint = "Italian")]
it,
[FieldOption(Hint = "Japanese")]
ja,
[FieldOption(Hint = "Korean")]
ko,
[FieldOption(Hint = "Norwegian")]
no,
[FieldOption(Hint = "Polish")]
pl,
[FieldOption(Hint = "Portuguese")]
pt,
[FieldOption(Hint = "Russian")]
ru,
[FieldOption(Hint = "Spanish")]
es,
[FieldOption(Hint = "Swedish")]
sv,
[FieldOption(Hint = "Turkish")]
tr,
[FieldOption(Hint = "Vietnamese")]
vi,
[FieldOption(Hint = "Chinese")]
zh,
[FieldOption(Hint = "Tamil")]
ta,
[FieldOption(Hint = "Telugu")]
te,
[FieldOption(Hint = "Hindi")]
hi,
bn
[FieldOption(Hint = "Bengali")]
bn,
[FieldOption(Hint = "Romanian")]
ro
}
}

View File

@@ -39,9 +39,8 @@ namespace NzbDrone.Core.ImportLists.TMDb
Title = movieResult.Title,
};
if (movieResult.ReleaseDate.IsNotNullOrWhiteSpace())
if (movieResult.ReleaseDate.IsNotNullOrWhiteSpace() && DateTime.TryParse(movieResult.ReleaseDate, out var releaseDate))
{
DateTime.TryParse(movieResult.ReleaseDate, out var releaseDate);
movie.Year = releaseDate.Year;
}

View File

@@ -2,6 +2,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Extensions;
@@ -94,6 +96,7 @@ namespace NzbDrone.Core.Indexers
{
var releases = new List<ReleaseInfo>();
var url = string.Empty;
var minimumBackoff = TimeSpan.FromHours(1);
try
{
@@ -190,8 +193,7 @@ namespace NzbDrone.Core.Indexers
}
catch (WebException webException)
{
if (webException.Status == WebExceptionStatus.NameResolutionFailure ||
webException.Status == WebExceptionStatus.ConnectFailure)
if (webException.Status is WebExceptionStatus.NameResolutionFailure or WebExceptionStatus.ConnectFailure)
{
_indexerStatusService.RecordConnectionFailure(Definition.Id);
}
@@ -201,7 +203,7 @@ namespace NzbDrone.Core.Indexers
}
if (webException.Message.Contains("502") || webException.Message.Contains("503") ||
webException.Message.Contains("timed out"))
webException.Message.Contains("504") || webException.Message.Contains("timed out"))
{
_logger.Warn("{0} server is currently unavailable. {1} {2}", this, url, webException.Message);
}
@@ -212,34 +214,29 @@ namespace NzbDrone.Core.Indexers
}
catch (TooManyRequestsException ex)
{
if (ex.RetryAfter != TimeSpan.Zero)
{
_indexerStatusService.RecordFailure(Definition.Id, ex.RetryAfter);
}
else
{
_indexerStatusService.RecordFailure(Definition.Id, TimeSpan.FromHours(1));
}
var retryTime = ex.RetryAfter != TimeSpan.Zero ? ex.RetryAfter : minimumBackoff;
_indexerStatusService.RecordFailure(Definition.Id, retryTime);
_logger.Warn("API Request Limit reached for {0}", this);
_logger.Warn("API Request Limit reached for {0}. Disabled for {1}", this, retryTime);
}
catch (HttpException ex)
{
_indexerStatusService.RecordFailure(Definition.Id);
_logger.Warn("{0} {1}", this, ex.Message);
}
catch (RequestLimitReachedException ex)
{
if (ex.RetryAfter != TimeSpan.Zero)
if (ex.Response.HasHttpServerError)
{
_indexerStatusService.RecordFailure(Definition.Id, ex.RetryAfter);
_logger.Warn("Unable to connect to {0} at [{1}]. Indexer's server is unavailable. Try again later. {2}", this, url, ex.Message);
}
else
{
_indexerStatusService.RecordFailure(Definition.Id, TimeSpan.FromHours(1));
_logger.Warn("{0} {1}", this, ex.Message);
}
}
catch (RequestLimitReachedException ex)
{
var retryTime = ex.RetryAfter != TimeSpan.Zero ? ex.RetryAfter : minimumBackoff;
_indexerStatusService.RecordFailure(Definition.Id, retryTime);
_logger.Warn("API Request Limit reached for {0}", this);
_logger.Warn("API Request Limit reached for {0}. Disabled for {1}", this, retryTime);
}
catch (ApiKeyException)
{
@@ -259,6 +256,11 @@ namespace NzbDrone.Core.Indexers
_logger.Error(ex, "CAPTCHA token required for {0}, check indexer settings.", this);
}
}
catch (TaskCanceledException ex)
{
_indexerStatusService.RecordFailure(Definition.Id);
_logger.Warn(ex, "Unable to connect to indexer, possibly due to a timeout. {0}", url);
}
catch (IndexerException ex)
{
_indexerStatusService.RecordFailure(Definition.Id);
@@ -360,6 +362,8 @@ namespace NzbDrone.Core.Indexers
catch (RequestLimitReachedException ex)
{
_logger.Warn("Request limit reached: " + ex.Message);
return new ValidationFailure(string.Empty, "Request limit reached: " + ex.Message);
}
catch (CloudFlareCaptchaException ex)
{
@@ -392,11 +396,45 @@ namespace NzbDrone.Core.Indexers
_logger.Warn(ex, "Indexer does not support the query");
return new ValidationFailure(string.Empty, "Indexer does not support the current query. Check if the categories and or searching for movies are supported. Check the log for more details.");
}
else
{
_logger.Warn(ex, "Unable to connect to indexer");
return new ValidationFailure(string.Empty, "Unable to connect to indexer. " + ex.Message);
_logger.Warn(ex, "Unable to connect to indexer");
if (ex.Response.HasHttpServerError)
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer, indexer's server is unavailable. Try again later. " + ex.Message);
}
if (ex.Response.StatusCode is HttpStatusCode.Forbidden or HttpStatusCode.Unauthorized)
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer, invalid credentials. " + ex.Message);
}
return new ValidationFailure(string.Empty, "Unable to connect to indexer, check the log above the ValidationFailure for more details. " + ex.Message);
}
catch (HttpRequestException ex)
{
_logger.Warn(ex, "Unable to connect to indexer");
return new ValidationFailure(string.Empty, "Unable to connect to indexer, please check your DNS settings and ensure IPv6 is working or disabled. " + ex.Message);
}
catch (TaskCanceledException ex)
{
_logger.Warn(ex, "Unable to connect to indexer");
return new ValidationFailure(string.Empty, "Unable to connect to indexer, possibly due to a timeout. Try again or check your network settings. " + ex.Message);
}
catch (WebException webException)
{
_logger.Warn("Unable to connect to indexer.");
if (webException.Status is WebExceptionStatus.NameResolutionFailure or WebExceptionStatus.ConnectFailure)
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer connection failure. Check your connection to the indexer's server and DNS." + webException.Message);
}
if (webException.Message.Contains("502") || webException.Message.Contains("503") ||
webException.Message.Contains("504") || webException.Message.Contains("timed out"))
{
return new ValidationFailure(string.Empty, "Unable to connect to indexer, indexer's server is unavailable. Try again later. " + webException.Message);
}
}
catch (Exception ex)

View File

@@ -123,7 +123,8 @@ namespace NzbDrone.Core.Indexers
protected virtual bool PreProcess(IndexerResponse indexerResponse)
{
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
// Server Down HTTP Errors are handled in HTTPIndexerBase so ignore them here
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK && !indexerResponse.HttpResponse.HasHttpServerError)
{
throw new IndexerException(indexerResponse, "Indexer API call resulted in an unexpected StatusCode [{0}]", indexerResponse.HttpResponse.StatusCode);
}
@@ -268,11 +269,11 @@ namespace NzbDrone.Core.Indexers
try
{
return new RssEnclosure
{
Url = v.Attribute("url")?.Value,
Type = v.Attribute("type")?.Value,
Length = v.Attribute("length")?.Value?.ParseInt64() ?? 0
};
{
Url = v.Attribute("url")?.Value,
Type = v.Attribute("type")?.Value,
Length = v.Attribute("length")?.Value?.ParseInt64() ?? 0
};
}
catch (Exception e)
{

View File

@@ -825,7 +825,6 @@
"Close": "قريب",
"CloneProfile": "الملف الشخصي استنساخ",
"CloneIndexer": "مفهرس استنساخ",
"CloneFormatTag": "علامة تنسيق استنساخ",
"CloneCustomFormat": "استنساخ تنسيق مخصص",
"ClientPriority": "أولوية العميل",
"ClickToChangeQuality": "انقر لتغيير الجودة",
@@ -883,12 +882,6 @@
"AuthBasic": "أساسي (المتصفح المنبثق)",
"AudioInfo": "معلومات الصوت",
"AsAllDayHelpText": "ستظهر الأحداث كأحداث طوال اليوم في التقويم الخاص بك",
"AreYouSureYouWantToResetYourAPIKey": "هل أنت متأكد أنك تريد إعادة تعيين مفتاح API الخاص بك؟",
"AreYouSureYouWantToRemoveSelectedItemsFromQueue": "هل تريد بالتأكيد إزالة {0} عنصر {1} من قائمة الانتظار؟",
"AreYouSureYouWantToDeleteThisRemotePathMapping": "هل أنت متأكد أنك تريد حذف تعيين المسار البعيد هذا؟",
"AreYouSureYouWantToDeleteThisImportListExclusion": "هل أنت متأكد أنك تريد حذف استثناء قائمة الاستيراد؟",
"AreYouSureYouWantToDeleteThisDelayProfile": "هل أنت متأكد أنك تريد حذف ملف تعريف التأخير هذا؟",
"AreYouSureYouWantToDeleteFormat": "هل تريد بالتأكيد حذف علامة التنسيق {0}؟",
"AptUpdater": "استخدم apt لتثبيت التحديث",
"ApplyTagsHelpTexts4": "استبدال: استبدل العلامات بالعلامات التي تم إدخالها (لا تدخل أي علامات لمسح جميع العلامات)",
"ApplyTagsHelpTexts3": "إزالة: قم بإزالة العلامات التي تم إدخالها",
@@ -1043,14 +1036,12 @@
"DownloadClientCheckDownloadingToRoot": "يقوم برنامج التنزيل {0} بوضع التنزيلات في المجلد الجذر {1}. يجب ألا تقوم بالتنزيل إلى مجلد جذر.",
"DeleteFileLabel": "احذف {0} ملفات الأفلام",
"UnableToAddRootFolder": "تعذر تحميل مجلدات الجذر",
"AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist": "هل أنت متأكد أنك تريد إزالة العناصر المحددة من القائمة السوداء؟",
"Blocklist": "القائمة السوداء",
"BlocklistHelpText": "يمنع Radarr من الاستيلاء على هذا الإصدار تلقائيًا مرة أخرى",
"BlocklistRelease": "إصدار القائمة السوداء",
"RemoveFromBlocklist": "إزالة من القائمة السوداء",
"UnableToLoadBlocklist": "تعذر تحميل القائمة السوداء",
"Blocklisted": "القائمة السوداء",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "هل تريد بالتأكيد إزالة {0} عنصر {1} من قائمة الانتظار؟",
"BlocklistReleases": "إصدار القائمة السوداء",
"SelectLanguages": "اختار اللغة",
"List": "القوائم",
@@ -1066,5 +1057,7 @@
"File": "الملفات",
"AnnouncedMsg": "تم اعلان الفيلم",
"ShowCinemaReleaseHelpText": "عرض تاريخ الإصدار تحت الملصق",
"EditMovies": "تحرير الفيلم"
"EditMovies": "تحرير الفيلم",
"DeleteRemotePathMapping": "تحرير تعيين المسار البعيد",
"DeleteRemotePathMappingMessageText": "هل أنت متأكد أنك تريد حذف تعيين المسار البعيد هذا؟"
}

View File

@@ -91,7 +91,6 @@
"UpdateCheckStartupNotWritableMessage": "Не може да се инсталира актуализация, тъй като стартовата папка „{0}“ не може да се записва от потребителя „{1}“.",
"UpgradeAllowedHelpText": "Ако инвалидните качества няма да бъдат надградени",
"ApplyTagsHelpTexts4": "Замяна: Заменете маркерите с въведените маркери (не въвеждайте маркери, за да изчистите всички маркери)",
"AreYouSureYouWantToDeleteThisDelayProfile": "Наистина ли искате да изтриете този профил за забавяне?",
"Username": "Потребителско име",
"WaitingToImport": "Изчаква се импортиране",
"BackupFolderHelpText": "Относителните пътища ще бъдат в директорията AppData на Radarr",
@@ -746,11 +745,7 @@
"AppDataDirectory": "Директория на AppData",
"Apply": "Приложи",
"AptUpdater": "Използвайте apt, за да инсталирате актуализацията",
"AreYouSureYouWantToDeleteFormat": "Наистина ли искате да изтриете маркер за формат {0}?",
"AreYouSureYouWantToDeleteThisImportListExclusion": "Наистина ли искате да изтриете това изключване от списъка за импортиране?",
"AreYouSureYouWantToDeleteThisRemotePathMapping": "Наистина ли искате да изтриете това отдалечено картографиране на пътя?",
"AudioInfo": "Аудио информация",
"AreYouSureYouWantToRemoveSelectedItemsFromQueue": "Наистина ли искате да премахнете {0} елемент {1} от опашката?",
"AsAllDayHelpText": "Събитията ще се показват като събития през целия ден във вашия календар",
"AutoRedownloadFailedHelpText": "Автоматично търсете и се опитвайте да изтеглите различна версия",
"AvailabilityDelay": "Забавяне на наличността",
@@ -789,7 +784,6 @@
"ChmodFolderHelpTextWarning": "Това работи само ако потребителят, работещ с Radarr, е собственик на файла. По-добре е да се уверите, че клиентът за изтегляне правилно задава разрешенията.",
"ChmodGroup": "chmod група",
"ChmodGroupHelpText": "Име на група или gid. Използвайте gid за отдалечени файлови системи.",
"AreYouSureYouWantToResetYourAPIKey": "Наистина ли искате да нулирате своя API ключ?",
"AuthBasic": "Основно (изскачащ прозорец на браузъра)",
"Authentication": "Удостоверяване",
"Announced": "Обявен",
@@ -1009,7 +1003,6 @@
"Backup": "Архивиране",
"View": "Изглед",
"Real": "Истински",
"CloneFormatTag": "Клониране на етикет за форматиране",
"Close": "Близо",
"CloseCurrentModal": "Затворете текущия режим",
"Connection": "Връзка",
@@ -1043,13 +1036,11 @@
"DownloadClientCheckDownloadingToRoot": "Клиентът за изтегляне {0} поставя изтеглянията в основната папка {1}. Не трябва да изтегляте в основна папка.",
"DeleteFileLabel": "Изтрийте {0} филмови файлове",
"UnableToAddRootFolder": "Не може да се заредят коренови папки",
"AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist": "Наистина ли искате да премахнете избраните елементи от черния списък?",
"Blocklist": "Черен списък",
"BlocklistRelease": "Освобождаване на черния списък",
"RemoveFromBlocklist": "Премахване от черния списък",
"UnableToLoadBlocklist": "Черният списък не може да се зареди",
"Blocklisted": "Черен списък",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Наистина ли искате да премахнете {0} елемент {1} от опашката?",
"BlocklistReleases": "Освобождаване на черния списък",
"Filters": "Филтър",
"Rating": "Оценки",
@@ -1064,5 +1055,7 @@
"RssSyncHelpText": "Интервал за минути. Задайте на нула, за да деактивирате (това ще спре всички автоматично хващане на освобождаване)",
"File": "Файлове",
"ShowCinemaReleaseHelpText": "Показване на датата на пускане под постер",
"EditMovies": "Редактиране на филм"
"EditMovies": "Редактиране на филм",
"DeleteRemotePathMapping": "Редактиране на отдалечено картографиране на пътя",
"DeleteRemotePathMappingMessageText": "Наистина ли искате да изтриете това отдалечено картографиране на пътя?"
}

View File

@@ -14,7 +14,6 @@
"RecyclingBin": "Paperera de reciclatge",
"Refresh": "Actualitza",
"Reload": "Torna a carregar",
"AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist": "Esteu segur que voleu suprimir els elements seleccionats de la llista de blocs?",
"Blocklist": "Llista de bloquejats",
"Blocklisted": "Bloquejats",
"BlocklistRelease": "Publicació de la llista de bloqueig",
@@ -59,7 +58,6 @@
"ClickToChangeQuality": "Feu clic per canviar la qualitat",
"ClickToChangeReleaseGroup": "Feu clic per canviar el grup de llançaments",
"CloneCustomFormat": "Clona el format personalitzat",
"CloneFormatTag": "Clona l'etiqueta de format",
"CloneProfile": "Clona el perfil",
"ConnectSettings": "Configuració de connexió",
"ConnectSettingsSummary": "Notificacions, connexions a servidors/reproductors multimèdia i scripts personalitzats",
@@ -369,14 +367,7 @@
"ApplyTagsHelpTexts2": "Afegeix: afegeix les etiquetes a la llista d'etiquetes existent",
"ApplyTagsHelpTexts3": "Eliminar: elimina les etiquetes introduïdes",
"AptUpdater": "Utilitzeu apt per instal·lar l'actualització",
"AreYouSureYouWantToDeleteFormat": "Esteu segur que voleu suprimir l'etiqueta de format {0} ?",
"AreYouSureYouWantToDeleteThisDelayProfile": "Esteu segur que voleu suprimir aquest perfil de retard?",
"AreYouSureYouWantToDeleteThisImportListExclusion": "Esteu segur que voleu suprimir aquesta exclusió de la llista d'importació?",
"AreYouSureYouWantToDeleteThisRemotePathMapping": "Esteu segur que voleu suprimir aquesta assignació remota de camins?",
"ApplyTagsHelpTexts4": "Substituïu: substituïu les etiquetes per les etiquetes introduïdes (no introduïu cap etiqueta per esborrar totes les etiquetes)",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Esteu segur que voleu suprimir 1 element de la cua?",
"AreYouSureYouWantToRemoveSelectedItemsFromQueue": "Esteu segur que voleu suprimir elements de {0} de la cua?",
"AreYouSureYouWantToResetYourAPIKey": "Esteu segur que voleu restablir la clau de l'API?",
"AsAllDayHelpText": "Els esdeveniments es mostraran com a esdeveniments durant tot el dia al calendari",
"AuthBasic": "Basic (finestra emergent del navegador)",
"Authentication": "Autenticació",
@@ -1152,11 +1143,20 @@
"ResetDefinitions": "Restableix definicions",
"ResetQualityDefinitions": "Restableix les definicions de qualitat",
"ResetTitles": "Restableix els títols",
"ResetTitlesHelpText": "Restableix els títols de definició i els valors",
"SettingsTheme": "Tema",
"UMask": "Umask",
"RSSHelpText": "S'utilitzarà quan Radarr cerqui publicacions periòdicament mitjançant RSS Sync",
"AreYouSureYouWantToResetQualityDefinitions": "Esteu segur que voleu restablir les definicions de qualitat?",
"EditMovies": "Edita pel·lícula",
"ShowCinemaReleaseHelpText": "Mostra la data de llançament sota el cartell"
"ShowCinemaReleaseHelpText": "Mostra la data de llançament sota el cartell",
"DeleteRemotePathMapping": "Editeu el mapa de camins remots",
"DeleteRemotePathMappingMessageText": "Esteu segur que voleu suprimir aquesta assignació remota de camins?",
"DeleteImportListExclusionMessageText": "Esteu segur que voleu suprimir aquesta exclusió de la llista d'importació?",
"DeleteConditionMessageText": "Esteu segur que voleu suprimir la notificació '{0}'?",
"DeleteCustomFormatMessageText": "Esteu segur que voleu suprimir l'indexador '{0}'?",
"DeleteDelayProfileMessageText": "Esteu segur que voleu suprimir aquest perfil de retard?",
"DeleteFormatMessageText": "Esteu segur que voleu suprimir l'etiqueta de format {0} ?",
"RemoveSelectedItemQueueMessageText": "Esteu segur que voleu eliminar {0} de la cua?",
"RemoveSelectedItemsQueueMessageText": "Esteu segur que voleu eliminar {0} de la cua?",
"ResetAPIKeyMessageText": "Esteu segur que voleu restablir la clau de l'API?",
"ResetDefinitionTitlesHelpText": "Restableix els títols de definició i els valors"
}

View File

@@ -167,12 +167,8 @@
"Always": "Vždy",
"AnalyticsEnabledHelpText": "Odesílejte anonymní informace o použití a chybách na servery Radarru. To zahrnuje informace o vašem prohlížeči, které stránky Radarr WebUI používáte, hlášení chyb a také verzi operačního systému a běhového prostředí. Tyto informace použijeme k upřednostnění funkcí a oprav chyb.",
"AptUpdater": "Nainstalujte aktualizaci pomocí apt",
"AreYouSureYouWantToDeleteFormat": "Opravdu chcete smazat značku formátu {0}?",
"AreYouSureYouWantToDeleteThisRemotePathMapping": "Opravdu chcete toto vzdálené mapování cesty odstranit?",
"AreYouSureYouWantToRemoveSelectedItemsFromQueue": "Opravdu chcete odebrat {0} položku {1} z fronty?",
"ApplyTagsHelpTexts2": "Přidat: Přidejte značky do existujícího seznamu značek",
"AudioInfo": "Zvukové informace",
"AreYouSureYouWantToResetYourAPIKey": "Opravdu chcete resetovat klíč API?",
"AsAllDayHelpText": "Události se ve vašem kalendáři zobrazí jako celodenní události",
"AuthBasic": "Základní (vyskakovací okno prohlížeče)",
"Authentication": "Ověření",
@@ -239,7 +235,6 @@
"ImportListStatusCheckSingleClientMessage": "Seznamy nejsou k dispozici z důvodu selhání: {0}",
"ChmodFolderHelpText": "Octal, aplikováno během importu / přejmenování na mediální složky a soubory (bez provádění bitů)",
"AgeWhenGrabbed": "Stáří (při zachycení)",
"AreYouSureYouWantToDeleteThisImportListExclusion": "Opravdu chcete toto vyloučení importního seznamu smazat?",
"ChmodFolderHelpTextWarning": "Funguje to pouze v případě, že je uživatel souboru Radarr vlastníkem souboru. Je lepší zajistit, aby stahovací klient správně nastavil oprávnění.",
"ChmodGroup": "chmod Group",
"Updates": "Aktualizace",
@@ -496,7 +491,6 @@
"TotalSpace": "Celkový prostor",
"UpdateCheckStartupNotWritableMessage": "Aktualizaci nelze nainstalovat, protože spouštěcí složku „{0}“ nelze zapisovat uživatelem „{1}“.",
"UpgradeAllowedHelpText": "Pokud budou deaktivovány vlastnosti, nebudou upgradovány",
"AreYouSureYouWantToDeleteThisDelayProfile": "Opravdu chcete smazat tento profil zpoždění?",
"WaitingToImport": "Čekání na import",
"DigitalRelease": "Digitální vydání",
"Disabled": "Zakázáno",
@@ -513,7 +507,6 @@
"ChooseAnotherFolder": "Vyberte jinou složku",
"ClickToChangeLanguage": "Klepnutím změníte jazyk",
"CloneCustomFormat": "Klonovat vlastní formát",
"CloneFormatTag": "Značka formátu klonování",
"CloneIndexer": "Klonovat indexátor",
"CloneProfile": "Klonovat profil",
"Close": "Zavřít",
@@ -1043,13 +1036,11 @@
"DownloadClientCheckDownloadingToRoot": "Stahovací klient {0} umístí stažené soubory do kořenové složky {1}. Neměli byste stahovat do kořenové složky.",
"DeleteFileLabel": "Smažte {0} filmové soubory",
"UnableToAddRootFolder": "Nelze načíst kořenové složky",
"AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist": "Opravdu chcete odebrat vybrané položky z černé listiny?",
"Blocklist": "Černá listina",
"BlocklistRelease": "Vydání černé listiny",
"RemoveFromBlocklist": "Odebrat z černé listiny",
"UnableToLoadBlocklist": "Nelze načíst černou listinu",
"Blocklisted": "Černá listina",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Opravdu chcete odebrat {0} položku {1} z fronty?",
"BlocklistReleases": "Vydání černé listiny",
"Filters": "Filtr",
"LocalPath": "Místní cesta",
@@ -1064,5 +1055,7 @@
"RssSyncHelpText": "Interval v minutách. Nastavením na nulu deaktivujete (tím se zastaví veškeré automatické uvolnění uvolnění)",
"File": "Soubory",
"EditMovies": "Upravit film",
"ShowCinemaReleaseHelpText": "Zobrazit datum vydání pod plakátem"
"ShowCinemaReleaseHelpText": "Zobrazit datum vydání pod plakátem",
"DeleteRemotePathMapping": "Upravit vzdálené mapování cesty",
"DeleteRemotePathMappingMessageText": "Opravdu chcete toto vzdálené mapování cesty odstranit?"
}

View File

@@ -190,7 +190,6 @@
"Always": "Altid",
"AnalyticsEnabledHelpText": "Send anonym brugs- og fejlinformation til Radarrs servere. Dette inkluderer information i din browser, hvilke Radarr WebUI-sider du bruger, fejlrapportering samt OS og runtime-version. Vi bruger disse oplysninger til at prioritere funktioner og fejlrettelser.",
"AppDataDirectory": "AppData-bibliotek",
"AreYouSureYouWantToDeleteThisRemotePathMapping": "Er du sikker på, at du vil slette denne kortlægning af fjernstien?",
"AuthBasic": "Grundlæggende (pop op-browser)",
"Authentication": "Godkendelse",
"ApplyTags": "Anvend tags",
@@ -225,11 +224,7 @@
"AfterManualRefresh": "Efter manuel opdatering",
"ApiKey": "API-nøgle",
"AptUpdater": "Brug apt til at installere opdateringen",
"AreYouSureYouWantToDeleteFormat": "Er du sikker på, at du vil slette formattag {0}?",
"ApplyTagsHelpTexts1": "Sådan anvendes tags på de valgte film",
"AreYouSureYouWantToDeleteThisImportListExclusion": "Er du sikker på, at du vil slette denne undtagelse fra importlisten?",
"AreYouSureYouWantToRemoveSelectedItemsFromQueue": "Er du sikker på, at du vil fjerne {0} element {1} fra køen?",
"AreYouSureYouWantToResetYourAPIKey": "Er du sikker på, at du vil nulstille din API-nøgle?",
"AsAllDayHelpText": "Begivenheder vises som begivenheder hele dagen i din kalender",
"AuthenticationMethodHelpText": "Kræv brugernavn og adgangskode for at få adgang til Radarr",
"AvailabilityDelay": "Tilgængelighed forsinkelse",
@@ -488,7 +483,6 @@
"TotalSpace": "Samlet plads",
"UpdateCheckStartupNotWritableMessage": "Kan ikke installere opdatering, fordi startmappen '{0}' ikke kan skrives af brugeren '{1}'.",
"ApplyTagsHelpTexts4": "Erstat: Udskift tags med de indtastede tags (indtast ingen tags for at rydde alle tags)",
"AreYouSureYouWantToDeleteThisDelayProfile": "Er du sikker på, at du vil slette denne forsinkelsesprofil?",
"Username": "Brugernavn",
"WaitingToImport": "Venter på at importere",
"BackupFolderHelpText": "Relative stier vil være under Radarrs AppData-bibliotek",
@@ -508,7 +502,6 @@
"ClickToChangeMovie": "Klik for at skifte film",
"ClickToChangeQuality": "Klik for at ændre kvalitet",
"CloneCustomFormat": "Klon brugerdefineret format",
"CloneFormatTag": "Klonformat-tag",
"CloneIndexer": "Klonindekser",
"CloneProfile": "Klonprofil",
"CloseCurrentModal": "Luk Nuværende Modal",
@@ -1043,13 +1036,11 @@
"DownloadClientCheckDownloadingToRoot": "Download klient {0} placerer downloads i rodmappen {1}. Du skal ikke downloade til en rodmappe.",
"DeleteFileLabel": "Slet {0} filmfiler",
"UnableToAddRootFolder": "Kan ikke indlæse rodmapper",
"AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist": "Er du sikker på, at du vil fjerne de valgte emner fra sortlisten?",
"Blocklist": "Blacklist",
"BlocklistRelease": "Udgivelse af sortliste",
"RemoveFromBlocklist": "Fjern fra sortlisten",
"UnableToLoadBlocklist": "Kunne ikke indlæse sortliste",
"Blocklisted": "Blacklist",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Er du sikker på, at du vil fjerne {0} element {1} fra køen?",
"BlocklistReleases": "Udgivelse af sortliste",
"Filters": "Filter",
"LocalPath": "Lokal sti",
@@ -1064,5 +1055,7 @@
"Collections": "Samling",
"File": "Filer",
"EditMovies": "Rediger film",
"ShowCinemaReleaseHelpText": "Vis udgivelsesdato under plakat"
"ShowCinemaReleaseHelpText": "Vis udgivelsesdato under plakat",
"DeleteRemotePathMapping": "Rediger kortlægning af fjernsti",
"DeleteRemotePathMappingMessageText": "Er du sikker på, at du vil slette denne kortlægning af fjernstien?"
}

View File

@@ -20,7 +20,7 @@
"Connect": "Verbinden",
"Connections": "Verbindungen",
"Crew": "Besatzung",
"CustomFilters": "Filter anpassen",
"CustomFilters": "Eigene Filter",
"CustomFormats": "Eigene Formate",
"Date": "Datum",
"Dates": "Termine",
@@ -317,8 +317,6 @@
"AnalyseVideoFiles": "Video Dateien analysieren",
"AppDataDirectory": "AppData Ordner",
"ApplyTags": "Tags setzen",
"AreYouSureYouWantToDeleteThisImportListExclusion": "Bist du sicher, dass du diesen Importlisten Ausschluss löschen willst?",
"AreYouSureYouWantToDeleteThisRemotePathMapping": "Bist du sicher, dass du diese entfernte Pfadzuordnung löschen willst?",
"AsAllDayHelpText": "Events werden als ganztags Event in deinem Kalender angezeigt",
"Authentication": "Authentifizierung",
"Automatic": "Automatisch",
@@ -342,7 +340,6 @@
"ClickToChangeLanguage": "Sprache ändern",
"ClickToChangeQuality": "Hier klicken um die Qualität zu ändern",
"ClientPriority": "Priorität",
"CloneFormatTag": "Format Tag kopieren",
"CloneProfile": "Profil kopieren",
"ColonReplacement": "Doppelpunkt-Ersatz",
"ColonReplacementFormatHelpText": "Ändere wie Radarr Doppelpunkte ersetzt",
@@ -375,12 +372,12 @@
"EditPerson": "Schausteller bearbeiten",
"Enable": "Aktivieren",
"EnableAutomaticAdd": "Automatisch hinzufügen",
"EnableAutomaticSearch": "Automatisch suchen",
"EnableAutomaticSearch": "Automatische Suche einschalten",
"EnableColorImpairedMode": "Farbbeeinträchtigter Modus aktivieren",
"EnableCompletedDownloadHandlingHelpText": "Importiere fertige Downloads vom Downloader automatisch",
"EnabledHelpText": "Aktiviere diese Liste",
"EnableHelpText": "Metadaten Dateien erstellen für diesen Metadata Typ",
"EnableInteractiveSearch": "Interaktive Suche",
"EnableInteractiveSearch": "Interaktive Suche einschalten",
"EnableRSS": "RSS aktivieren",
"EnableSSL": "SSL",
"EnableSslHelpText": " Erfordert einen Neustart als Administrator",
@@ -415,7 +412,7 @@
"LanguageHelpText": "Sprache für Releases",
"Links": "Links",
"ListSettings": "Listen Einstellungen",
"ListSyncLevelHelpText": "Die Filme in der Bibliothek werden auf der Grundlage Ihrer Auswahl behandelt, wenn sie nicht auf Ihrer Liste auftauchen",
"ListSyncLevelHelpText": "Die Filme in der Bibliothek werden auf der Grundlage dieser Auswahl behandelt, wenn sie nicht auf einer Liste auftauchen",
"ListUpdateInterval": "Aktualisierungs Intervall der Listen",
"Local": "Lokal",
"LogLevel": "Log Level",
@@ -583,10 +580,8 @@
"ApiKey": "API-Schlüssel",
"ImportedTo": "Importiert nach",
"Permissions": "Rechte",
"AreYouSureYouWantToDeleteThisDelayProfile": "Bist du sicher, dass du dieses Verzögerungs-Profil löschen willst?",
"ImportExtraFilesHelpText": "Importiere zutreffende Extra Dateien (Untertitel, nfo, etc.) nach dem Importieren einer Filmdatei",
"PreferIndexerFlags": "Bevorzugte Indexer Flags",
"AreYouSureYouWantToResetYourAPIKey": "Bist du sicher, dass du den API-Schlüssel zurücksetzen willst?",
"CopyUsingHardlinksHelpText": "Hardlinks erlauben es Radarr, Torrents zu importieren die derzeit geseeded werden, ohne dabei weiteren Speicherplatz zu belegen oder die Datei vollständig zu kopieren. Hardlinks funktionieren nur, wenn sich die Quelle und das Ziel auf dem selben Volume befinden",
"IncludeUnknownMovieItemsHelpText": "Einträge ohne eine Zuordnung in der Warteschlange anzeigen. Dies könnten gelöschte Filme oder alles andere mit Radarrs Downloadkategorie sein",
"PriorityHelpText": "Priorisiere mehrere Downloader. Rundlauf-Verfahren wird für Downloader mit der gleichen Priorität verwendet.",
@@ -1005,8 +1000,6 @@
"BuiltIn": "Integriert",
"AuthForm": "Formular (Login Seite)",
"AuthBasic": "Einfach (Browser Popup)",
"AreYouSureYouWantToRemoveSelectedItemsFromQueue": "Bist du sicher, dass du {0} Einträge aus der Warteschlange löschen willst?",
"AreYouSureYouWantToDeleteFormat": "Bist du sicher, dass du das Formatierungstag {0} löschen willst ?",
"AptUpdater": "Benutze 'apt' um das Update zu installieren",
"Always": "Immer",
"AllResultsHiddenFilter": "Keine Ergebnisse mit den ausgewählten Filtern",
@@ -1067,14 +1060,12 @@
"From": "von",
"NotificationTriggersHelpText": "Auslöser für diese Benachrichtigung auswählen",
"UnableToAddRootFolder": "Stammverzeichnis konnte nicht hinzugefügt werden",
"AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist": "Bist du icher, dass du die ausgewählten Einträge aus der Sperrliste entfernen willst?",
"Blocklist": "Sperrliste",
"BlocklistHelpText": "Dieses Release nicht automatisch erneut erfassen",
"BlocklistRelease": "Release sperren",
"RemoveFromBlocklist": "Aus der Sperrliste entfernen",
"UnableToLoadBlocklist": "Sperrliste konnte nicht geladen werden",
"Blocklisted": "Gesperrt",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Bist du sicher, dass du {0} Einträge aus der Warteschlange löschen willst?",
"BlocklistReleases": "Release sperren",
"IndexerTagHelpText": "Benutze den Indexer nur für Filme mit mindesens einen zutreffenden Tag. Leer lassen für alle Filme.",
"RemoveSelectedItem": "Entferne ausgewählten Eintrag",
@@ -1146,12 +1137,10 @@
"ApplicationURL": "Anwendungs-URL",
"ApplicationUrlHelpText": "Die externe URL der Anwendung inklusive http(s)://, Port und URL-Basis",
"PreferredProtocol": "Bevorzugtes Protokoll",
"AreYouSureYouWantToResetQualityDefinitions": "Sicher, dass die Qualitätsdefinitionen zurückgesetzt werden sollen?",
"ResetDefinitions": "Definitionen zurücksetzen",
"ResetQualityDefinitions": "Qualitätsdefinitionen zurücksetzen",
"SettingsThemeHelpText": "Anwendungsdesign ändern, das 'Auto' Design passt sich an den Light/Dark-Mode deines Systems an. Inspiriert von Theme.Park",
"ResetTitles": "Titel zurücksetzen",
"ResetTitlesHelpText": "Definitionstitel und Werte zurücksetzen",
"SettingsTheme": "Design",
"RSSHelpText": "Wird benutzt, wenn Radarr mittels RSS-Sync regelmäßig nach Releases schaut",
"DownloadClientSortingCheckMessage": "Downloader {0} hat die {1} Sortierung für Radarrs Kategorie aktiviert. Dies sollte deaktiviert werden, um Import-Probleme zu vermeiden.",
@@ -1161,6 +1150,32 @@
"EditSelectedMovies": "Bearbeite ausgewählte Filme",
"EditMovies": "Filme bearbeiten",
"RecycleBinUnableToWriteHealthCheck": "Schreiben in konfigurierten Papierkorbordner nicht möglich: {0}. Stelle sicher, dass dieser Pfad existiert und von dem Benutzer, der Radarr ausführt, beschreibbar ist",
"ShowCinemaReleaseHelpText": "Erscheinungsdatum unter Poster anzeigen",
"ApiKeyValidationHealthCheckMessage": "Bitte den API Schlüssel korrigieren, dieser muss mindestens {0} Zeichen lang sein. Die Änderung kann über die Einstellungen oder die Konfigurationsdatei erfolgen"
"ShowCinemaReleaseHelpText": "Kino-Erscheinungsdatum unter Poster anzeigen",
"ApiKeyValidationHealthCheckMessage": "Bitte den API Schlüssel korrigieren, dieser muss mindestens {0} Zeichen lang sein. Die Änderung kann über die Einstellungen oder die Konfigurationsdatei erfolgen",
"StopSelecting": "Auswahl stoppen",
"ImportScriptPath": "Pfad zum Importscript",
"ImportUsingScript": "Import per Script",
"OnManualInteractionRequired": "Wenn manuelles Eingreifen erforderlich ist",
"OnManualInteractionRequiredHelpText": "Wenn manuelles Eingreifen erforderlich ist",
"RemoveCompletedDownloads": "Entferne abgeschlossene Downloads",
"RemoveFailedDownloads": "Entferne fehlgeschlagene Downloads",
"ScriptImportPathHelpText": "Pfad zum Script für den Import",
"UseScriptImportHelpText": "Kopiere Dateien zum Import mithilfe eines Scripts (z.B.: für Transkodierungen)",
"OnHealthRestoredHelpText": "Bei Wiederherstellung des Zustands",
"OnHealthRestored": "Bei Wiederherstellung des Zustands",
"Loading": "Lade",
"UpdateFiltered": "Gefilterte updaten",
"ThereWasAnErrorLoadingThisItem": "Beim Laden des Eintrags ist ein Fehler aufgetreten",
"ThereWasAnErrorLoadingThisPage": "Beim Laden der Seite ist ein Fehler aufgetreten",
"DeleteRemotePathMapping": "Entfernte Pfadzuordnung bearbeiten",
"NoHistoryBlocklist": "Keine History Blockliste",
"RemoveSelectedItemQueueMessageText": "Bist du sicher, dass du {0} aus der Warteschlange entfernen willst?",
"RemoveSelectedItemsQueueMessageText": "Bist du sicher, dass du {0} aus der Warteschlange entfernen willst?",
"ResetDefinitionTitlesHelpText": "Definitionstitel und Werte zurücksetzen",
"DeleteConditionMessageText": "Benachrichtigung '{0}' wirklich löschen?",
"DeleteCustomFormatMessageText": "Indexer '{0}' wirklich löschen?",
"DeleteDelayProfileMessageText": "Bist du sicher, dass du dieses Verzögerungs-Profil löschen willst?",
"DeleteFormatMessageText": "Bist du sicher, dass du das Formatierungstag {0} löschen willst ?",
"DeleteImportListExclusionMessageText": "Bist du sicher, dass du diesen Importlisten Ausschluss löschen willst?",
"ResetAPIKeyMessageText": "Bist du sicher, dass du den API-Schlüssel zurücksetzen willst?"
}

View File

@@ -62,7 +62,7 @@
"CustomFilters": "Custom Φιλτρα",
"Crew": "Ομάδα",
"ConnectSettingsSummary": "Ειδοποιήσεις, συνδέσεις με διακομιστές πολυμέσων/προγράμματα αναπαραγωγής και προσαρμοσμένα σενάρια",
"AppDataLocationHealthCheckMessage": "Η αναβάθμιση δεν είναι πιθανό να αποτρέψει την διαγραφή των AppData κατά την αναβάθμιση",
"AppDataLocationHealthCheckMessage": "Η ενημέρωση δεν θα είναι δυνατή για να αποτραπεί η διαγραφή των δεδομένων εφαρμογής κατά την ενημέρωση",
"AddNewTmdbIdMessage": "Μπορείτε επίσης να ψάξετε μέσω του TMDB Id της ταινίας. π.χ. tmdb:71663",
"AddNewMessage": "Είναι εύκολο να προσθέσετε μια καινούρια ταινία, απλά πληκτρολογήστε το όνομα της ταινίας",
"ConnectionLostAutomaticMessage": "Το Radarr θα προσπαθήσει να συνδεθεί αυτόματα, αλλιώς μπορείτε να κάνετε reload απο κάτω.",
@@ -91,7 +91,7 @@
"NoLimitForAnyRuntime": "Δεν υπάρχει όριο για οποιοδήποτε χρόνο εκτέλεσης",
"NotificationTriggers": "Ενεργοποιήσεις ειδοποίησης",
"ColonReplacementFormatHelpText": "Αλλάξτε τον τρόπο με τον οποίο το Radarr χειρίζεται την αντικατάσταση του παχέος εντέρου",
"CopyUsingHardlinksHelpText": "Χρησιμοποιήστε σκληρούς συνδέσμους όταν προσπαθείτε να αντιγράψετε αρχεία από torrents που εξακολουθούν να σπέρνονται",
"CopyUsingHardlinksHelpText": "Οι σκληροί σύνδεσμοι επιτρέπουν στο Radarr να εισαγάγει τα torrents που έχουν κατέβει, στον φάκελο της ταινίας χωρίς να καταλαμβάνει περισσότερο χώρο στον δίσκο ή να αντιγράφει ολόκληρο το περιεχόμενο του αρχείου. Οι σκληροί σύνδεσμοι θα λειτουργήσουν μόνο αν η πηγή και ο προορισμός βρίσκονται στον ίδιο τόμο δίσκου",
"CopyUsingHardlinksHelpTextWarning": "Περιστασιακά, τα κλειδώματα αρχείων ενδέχεται να αποτρέψουν τη μετονομασία αρχείων που έχουν σπαρθεί. Μπορείτε προσωρινά να απενεργοποιήσετε τη σπορά και να χρησιμοποιήσετε τη λειτουργία μετονομασίας Radarr ως εργασία.",
"CustomFormatsSettings": "Ρυθμίσεις προσαρμοσμένων μορφών",
"CutoffFormatScoreHelpText": "Μόλις επιτευχθεί αυτό το σκορ προσαρμοσμένης μορφής, το Radarr δεν θα κατεβάζει πλέον ταινίες",
@@ -170,13 +170,8 @@
"AnalyticsEnabledHelpText": "Στείλτε ανώνυμες πληροφορίες χρήσης και σφάλματος στους διακομιστές του Radarr. Αυτό περιλαμβάνει πληροφορίες στο πρόγραμμα περιήγησής σας, ποιες σελίδες Radarr WebUI χρησιμοποιείτε, αναφορά σφαλμάτων καθώς και έκδοση λειτουργικού συστήματος και χρόνου εκτέλεσης. Θα χρησιμοποιήσουμε αυτές τις πληροφορίες για να δώσουμε προτεραιότητα σε λειτουργίες και διορθώσεις σφαλμάτων.",
"AppDataDirectory": "Κατάλογος AppData",
"AptUpdater": "Χρησιμοποιήστε το apt για να εγκαταστήσετε την ενημέρωση",
"AreYouSureYouWantToDeleteFormat": "Είστε βέβαιοι ότι θέλετε να διαγράψετε την ετικέτα μορφής {0};",
"AreYouSureYouWantToDeleteThisImportListExclusion": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την εξαίρεση λίστας εισαγωγής;",
"AreYouSureYouWantToDeleteThisRemotePathMapping": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την αντιστοίχιση απομακρυσμένης διαδρομής;",
"AreYouSureYouWantToRemoveSelectedItemsFromQueue": "Είστε βέβαιοι ότι θέλετε να καταργήσετε το {0} στοιχείο {1} από την ουρά;",
"CustomFormatUnknownCondition": "Άγνωστη συνθήκη προσαρμοσμένης μορφής \"{0}\"",
"AddRemotePathMapping": "Προσθήκη απομακρυσμένης αντιστοίχισης διαδρομής",
"AreYouSureYouWantToResetYourAPIKey": "Είστε βέβαιοι ότι θέλετε να επαναφέρετε το κλειδί API σας;",
"AsAllDayHelpText": "Οι εκδηλώσεις θα εμφανίζονται ως ολοήμερα συμβάντα στο ημερολόγιό σας",
"AuthBasic": "Βασικό (Αναδυόμενο παράθυρο προγράμματος περιήγησης)",
"Authentication": "Αυθεντικοποίηση",
@@ -484,7 +479,6 @@
"TotalSpace": "Συνολικός χώρος",
"UpgradeAllowedHelpText": "Εάν οι ιδιότητες με ειδικές ανάγκες δεν θα αναβαθμιστούν",
"ApplyTagsHelpTexts4": "Αντικατάσταση: Αντικαταστήστε τις ετικέτες με τις εισαγόμενες ετικέτες (μην εισάγετε ετικέτες για να διαγράψετε όλες τις ετικέτες)",
"AreYouSureYouWantToDeleteThisDelayProfile": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το προφίλ καθυστέρησης;",
"Username": "Όνομα χρήστη",
"WaitingToImport": "Αναμονή για εισαγωγή",
"Disabled": "άτομα με ειδικές ανάγκες",
@@ -502,7 +496,6 @@
"ClickToChangeMovie": "Κάντε κλικ για να αλλάξετε ταινία",
"ClickToChangeQuality": "Κάντε κλικ για να αλλάξετε την ποιότητα",
"CloneCustomFormat": "Προσαρμοσμένη μορφή κλώνου",
"CloneFormatTag": "Ετικέτα μορφής κλώνου",
"CloneIndexer": "Δείκτης κλώνου",
"CloneProfile": "Προφίλ κλώνου",
"CloseCurrentModal": "Κλείσιμο τρέχοντος modal",
@@ -520,7 +513,7 @@
"CurrentlyInstalled": "Εγκατεστημένο αυτήν τη στιγμή",
"Custom": "Εθιμο",
"CustomFormat": "Προσαρμοσμένη μορφή",
"CustomFormatHelpText": "Ο Radarr βαθμολογεί κάθε κυκλοφορία χρησιμοποιώντας το άθροισμα των βαθμολογιών για προσαρμοσμένες προσαρμοσμένες μορφές. Εάν μια νέα κυκλοφορία βελτιώσει το σκορ, στην ίδια ή καλύτερη ποιότητα, τότε ο Radarr θα το πιάσει.",
"CustomFormatHelpText": "Το Radarr βαθμολογεί κάθε κυκλοφορία χρησιμοποιώντας το άθροισμα των βαθμολογιών για προσαρμοσμένες μορφές. Εάν μια νέα κυκλοφορία βελτιώσει το σκορ, στην ίδια ή καλύτερη ποιότητα, τότε το Radarr θα το πιάσει.",
"CustomFormatJSON": "Προσαρμοσμένη μορφή JSON",
"CustomFormatScore": "Βαθμολογία προσαρμοσμένης μορφής",
"CustomFormatUnknownConditionOption": "Άγνωστη επιλογή \"{0}\" για συνθήκη \"{1}\"",
@@ -665,7 +658,7 @@
"Links": "Συνδέσεις",
"Lists": "Τόπος αγώνων",
"ListSettings": "Ρυθμίσεις λίστας",
"ListSyncLevelHelpText": "Οι ταινίες στη βιβλιοθήκη θα καταργηθούν ή θα παρακολουθούνται, εάν δεν βρίσκονται στη λίστα σας",
"ListSyncLevelHelpText": "Οι ταινίες στη βιβλιοθήκη θα χειριστούνε ανάλογα με την επιλογή σας, εάν θα απομακρυνθούν ή δεν θα εμφανιστούν στη λίστα ή τις λίστες σας",
"LogFiles": "Αρχεία καταγραφής",
"Logging": "Ξύλευση",
"LogLevel": "Επίπεδο καταγραφής",
@@ -1043,13 +1036,11 @@
"DownloadClientCheckDownloadingToRoot": "Λήψη προγράμματος-πελάτη {0} τοποθετεί λήψεις στον ριζικό φάκελο {1}. Δεν πρέπει να κάνετε λήψη σε έναν ριζικό φάκελο.",
"DeleteFileLabel": "Διαγραφή {0} Αρχείων ταινιών",
"UnableToAddRootFolder": "Δεν είναι δυνατή η φόρτωση ριζικών φακέλων",
"AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist": "Είστε βέβαιοι ότι θέλετε να καταργήσετε τα επιλεγμένα στοιχεία από τη μαύρη λίστα;",
"Blocklist": "Αποριφθέντα",
"BlocklistRelease": "Έκδοση μαύρης λίστας",
"RemoveFromBlocklist": "Κατάργηση από μαύρη λίστα",
"UnableToLoadBlocklist": "Δεν είναι δυνατή η φόρτωση της μαύρης λίστας",
"Blocklisted": "Αποριφθέντα",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Είστε βέβαιοι ότι θέλετε να καταργήσετε το {0} στοιχείο {1} από την ουρά;",
"BlocklistReleases": "Έκδοση μαύρης λίστας",
"LocalPath": "Τοπικό μονοπάτι",
"RemotePath": "Απομακρυσμένη διαδρομή",
@@ -1094,7 +1085,6 @@
"ManualImportSetReleaseGroup": "Μη αυτόματη εισαγωγή - Ορισμός ομάδας απελευθέρωσης",
"OriginalLanguage": "Γλώσσα Πρωτότυπου",
"OriginalTitle": "Πρωτότυπος τίτλος",
"AreYouSureYouWantToResetQualityDefinitions": "Είστε βέβαιοι ότι θέλετε να επαναφέρετε τους ορισμούς ποιότητας;",
"CollectionOptions": "Επιλογές συλλογής",
"CollectionShowDetailsHelpText": "Εμφάνιση κατάστασης και ιδιοτήτων συλλογής",
"CollectionShowOverviewsHelpText": "Εμφάνιση επισκοπήσεων συλλογής",
@@ -1140,7 +1130,6 @@
"RemotePathMappingCheckWrongOSPath": "Το πρόγραμμα-πελάτης απομακρυσμένης λήψης {0} τοποθετεί λήψεις στο {1} αλλά αυτή δεν είναι έγκυρη διαδρομή {2}. Ελέγξτε τις απομακρυσμένες αντιστοιχίσεις διαδρομής και κατεβάστε τις ρυθμίσεις πελάτη.",
"RemoveDownloadsAlert": "Οι ρυθμίσεις κατάργησης μετακινήθηκαν στις μεμονωμένες ρυθμίσεις Download Client στον παραπάνω πίνακα.",
"RemoveSelectedItem": "Αφαίρεση επιλεγμένου αντικειμένου",
"ResetTitlesHelpText": "Επαναφέρετε τίτλους ορισμού καθώς και τιμές",
"RSSHelpText": "Θα χρησιμοποιηθεί όταν το Radarr αναζητά περιοδικά εκδόσεις μέσω RSS Sync",
"SearchOnAddCollectionHelpText": "Αναζητήστε ταινίες σε αυτήν τη συλλογή όταν προστεθούν στη βιβλιοθήκη",
"SelectReleaseGroup": "Επιλέξτε Ομάδα έκδοσης",
@@ -1158,5 +1147,22 @@
"File": "Αρχεία",
"UMask": "UMask",
"EditMovies": "Επεξεργασία ταινίας",
"ShowCinemaReleaseHelpText": "Εμφάνιση ημερομηνίας κυκλοφορίας στην αφίσα"
"ShowCinemaReleaseHelpText": "Εμφάνιση ημερομηνίας κυκλοφορίας στην αφίσα",
"RecycleBinUnableToWriteHealthCheck": "Δεν είναι δυνατή η εγγραφή στον επιλεγμένο φάκελο ανακύκλωσης: {0}. Ελέγξτε ότι ο φάκελος υπάρχει και είναι εγγράψιμος από τον χρήστη που τρέχει το Radarr",
"UpdateFiltered": "Ενημέρωση Φιλτραρισμένων",
"OnHealthRestored": "Στην Αποκατάσταση Υγείας",
"RemoveCompletedDownloads": "Αφαίρεση Ολοκληρωμένων Λήψεων",
"RemoveFailedDownloads": "Αφαίρεση Αποτυχημένων Λήψεων",
"ImportScriptPath": "Εισαγωγή Μονοπατιού Script",
"ImportUsingScript": "Εισαγωγή με χρήση Script",
"ScriptImportPathHelpText": "Μονοπάτι για το script που θα χρησιμοποιηθεί για την εισαγωγή",
"ThereWasAnErrorLoadingThisItem": "Υπήρξε ένα σφάλμα κατά τη φόρτωση του αρχείου",
"Loading": "Φόρτωση",
"EditSelectedMovies": "Επεξεργασία Επιλεγμένων Ταινιών",
"ApiKeyValidationHealthCheckMessage": "Παρακαλούμε ενημερώστε το κλείδι API ώστε να έχει τουλάχιστον {0} χαρακτήρες. Μπορείτε να το κάνετε αυτό μέσα από τις ρυθμίσεις ή το αρχείο ρυθμίσεων",
"StopSelecting": "Διακοπή Επιλογής",
"ThereWasAnErrorLoadingThisPage": "Υπήρξε ένα σφάλμα κατά τη φόρτωση της σελίδας",
"DeleteRemotePathMapping": "Επεξεργασία αντιστοίχισης απομακρυσμένης διαδρομής",
"DeleteRemotePathMappingMessageText": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την αντιστοίχιση απομακρυσμένης διαδρομής;",
"OnHealthRestoredHelpText": "Στην Αποκατάσταση Υγείας"
}

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