mirror of
https://github.com/Radarr/Radarr.git
synced 2026-03-30 18:25:57 -04:00
Compare commits
39 Commits
v4.6.0.743
...
v4.6.3.751
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fd267580a | ||
|
|
8974aa823b | ||
|
|
41492efd2e | ||
|
|
d008768fff | ||
|
|
cb21fe535d | ||
|
|
4cce2727e2 | ||
|
|
b1ff82da37 | ||
|
|
c5266152c5 | ||
|
|
783878be1e | ||
|
|
0cbfb4ca65 | ||
|
|
c22c9400c2 | ||
|
|
0288c4b704 | ||
|
|
e4429d2919 | ||
|
|
7052a7a5ec | ||
|
|
b38912851b | ||
|
|
1354c2c337 | ||
|
|
e259235df6 | ||
|
|
0cc1fe8308 | ||
|
|
f4fe18a440 | ||
|
|
eeed935e3a | ||
|
|
1b3701371a | ||
|
|
d56f3ec2e7 | ||
|
|
e7e3aac971 | ||
|
|
d2cb36c88a | ||
|
|
2fe28cb1dc | ||
|
|
5d65b4cae4 | ||
|
|
b0f56e2840 | ||
|
|
5593837482 | ||
|
|
8231290c7b | ||
|
|
0c1b88c60a | ||
|
|
0b8478e4a1 | ||
|
|
69e09c8687 | ||
|
|
3f2ea49023 | ||
|
|
32f09633e9 | ||
|
|
3542b263c7 | ||
|
|
d5cc84d8c8 | ||
|
|
c0790060fb | ||
|
|
5ec7e86488 | ||
|
|
b8abafd72f |
@@ -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)'
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -92,9 +92,9 @@ class ImportMovieSelectFolder extends Component {
|
||||
|
||||
{
|
||||
!isFetching && error ?
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadRootFolders')}
|
||||
</div> :
|
||||
</Alert> :
|
||||
null
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -9,6 +9,8 @@ const fuseOptions = {
|
||||
keys: [
|
||||
'title',
|
||||
'alternateTitles.title',
|
||||
'tmdbId',
|
||||
'imdbId',
|
||||
'tags.label'
|
||||
]
|
||||
};
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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 ? (
|
||||
|
||||
@@ -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 ? (
|
||||
|
||||
@@ -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 ? (
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -29,9 +29,9 @@ function DownloadClientOptions(props) {
|
||||
|
||||
{
|
||||
!isFetching && error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadDownloadClientOptions')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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 || '';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ***")]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
43
src/NzbDrone.Core.Test/ParserTests/UrlFixture.cs
Normal file
43
src/NzbDrone.Core.Test/ParserTests/UrlFixture.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -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 '/%'
|
||||
)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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": "هل أنت متأكد أنك تريد حذف تعيين المسار البعيد هذا؟"
|
||||
}
|
||||
|
||||
@@ -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": "Наистина ли искате да изтриете това отдалечено картографиране на пътя?"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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?"
|
||||
}
|
||||
|
||||
@@ -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?"
|
||||
}
|
||||
|
||||
@@ -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?"
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user