1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-17 16:14:46 -04:00

Compare commits

..

60 Commits

Author SHA1 Message Date
nitsua
12ae4fba88 Move edit icon to the left on remote path mappings
Fixes: #6686
2021-12-26 22:19:43 -06:00
bakerboy448
194e0f3d7f Fixed: Various Translations 2021-12-26 21:49:44 -06:00
Qstick
d1fa92bc6c Fixed: Manual Import language handling 2021-12-26 19:41:37 -06:00
Qstick
974e44ce48 New: Link indexer to specific download client 2021-12-26 19:07:22 -06:00
Taloth Saldono
de05be62d7 Added BDLight to quality parser
(cherry picked from commit 5c8f2518baa1b2d4a8b0507f9fafe12b2ecff1e5)
2021-12-26 19:05:11 -06:00
Qstick
cae5badee0 New: Support server notifications
(cherry picked from commit f5f0dd6fae5bc9f308506d56be42ac9a4be908e7)

Closes Radarr #5393

[common]
2021-12-26 15:48:28 -06:00
Qstick
45d8227654 Fixed: Handle MS variant MPEG4 files in video formatter 2021-12-25 18:24:30 -06:00
ta264
7bbd2246c4 Fix secondary ffprobe scan 2021-12-24 17:47:17 +00:00
ta264
59fed13442 MediaInfoModel initializer -> assignment for NRE tracking 2021-12-23 21:41:38 +00:00
Qstick
50b273acae Fixed: Ignore permissions issues on recycle bin files 2021-12-24 11:05:22 -06:00
Qstick
4278415fd7 Fixed: Default MinAvail to Released if not passed on add
Fixes #2117
2021-12-24 11:05:22 -06:00
Qstick
124b50288d Fix invalid PropType for sizeOnDisk in DeleteMovieModal 2021-12-24 11:05:22 -06:00
bakerboy448
3fcc395964 Fixed: Escape Characters as needed for *znab queries
Fixes #6799

[common]
2021-12-23 15:12:05 -06:00
Weblate
0ee9981cba Translated using Weblate (Arabic) [skip ci]
Currently translated at 95.7% (1069 of 1116 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 98.5% (1100 of 1116 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 99.7% (1113 of 1116 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 99.5% (1111 of 1116 strings)

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

Currently translated at 100.0% (1116 of 1116 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 10.1% (113 of 1114 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 10.0% (112 of 1113 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 98.0% (1091 of 1113 strings)

Added translation using Weblate (Ukrainian) [skip ci]

Added translation using Weblate (Persian) [skip ci]

Added translation using Weblate (Bengali) [skip ci]

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Qstick <qstick@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: htrex <hantarex@gmail.com>
Co-authored-by: rakan <rakaz30@hotmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sk/
Translation: Servarr/Radarr
2021-12-23 15:10:42 -06:00
Qstick
2848899206 Fixed: Calendar can show incorrect Release Types 2021-12-23 14:34:48 -06:00
Qstick
f1a00764cd New: Additional logging for InvalidModel BadRequest API calls
[common]
2021-12-23 14:22:09 -06:00
Qstick
346236764c Drop all Commands rows before running migration 204 2021-12-23 11:50:13 -06:00
Qstick
eecd4e4b7d New: Allow Import to update existing Custom Formats
Fixes #6178
2021-12-21 19:18:36 -06:00
Qstick
2838d8ca29 Add Ratings to Movie Index sort menu
Fixes #6741
2021-12-21 19:01:11 -06:00
bakerboy448
4ebcbc28aa fix applicationupdate filename typo
fix onapplicationupdate translate typo
2021-12-21 18:23:42 -06:00
Qstick
2c24f7ca04 Ensure Identity on Tables that have been modified 2021-12-21 18:09:05 -06:00
Qstick
ec86de78d2 Maintain PrimaryKey and AutoIncrement on some schemas
[common]
2021-12-21 17:45:00 -06:00
Qstick
4f5f9ff77e Update NotificationResource.cs 2021-12-21 16:07:25 -06:00
erikp9
465bb403a9 fixed hardsub detection 2021-12-21 07:58:13 -06:00
Qstick
9e175e28ef New: OnApplicationUpdate Notifications (#6854)
Fixes #4681
[common]
2021-12-20 23:12:12 -06:00
Qstick
4d2a311e40 Remove PreDB from MovieStatusType
Fixes #5002
2021-12-20 21:25:07 -06:00
Qstick
b2195148a2 Fixed: NullRef in SchemaBuilder when sending payload without optional Provider.Settings fields 2021-12-20 20:38:16 -06:00
Qstick
2ae7371d73 Update Deluge log statements 2021-12-20 20:35:38 -06:00
Mark McDowall
7b03a856c9 Fixed: Increase width and truncate long titles on Import List Exclusions
Closes #6779

(cherry picked from commit 2d0541c03b761a0ec5e10711d6bd577e07141517)
2021-12-20 20:16:22 -06:00
Qstick
48d1d47b67 Rename ImportExclusions to ImportListExclusions 2021-12-20 20:16:22 -06:00
Qstick
906b9bb92a Fixed: Use unmodified titles when searching Nyaa
Fixes #6642

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2021-12-20 20:16:22 -06:00
Mark McDowall
6fc14278e6 Fixed: Parsing of quality when release group contains Remux
Closes #6607
2021-12-20 19:58:47 -06:00
Mark McDowall
34b269086d Fixed: Get full path for download station instead of shared folder
Closes #6751
Fixes #6818

(cherry picked from commit b184e62fa7dd7ecd089619f176e6388c1c3be25d)
2021-12-20 19:55:09 -06:00
Qstick
6c40a27f2e Restore Parse API compatibility
Fixes #6852
2021-12-20 19:54:01 -06:00
Qstick
be158a09b4 Ensure new languages are in All collection 2021-12-20 19:44:35 -06:00
Robin Dadswell
eecd746f51 New: Health check for Discord notifications setup as Slack 2021-12-21 00:59:53 +00:00
Robin Dadswell
5ed034320e New: Migrate Discord from Slack to Discord notifications 2021-12-21 00:59:53 +00:00
bakerboy448
41dd678dfd Better wording of MissingFromDisk
closes #6834
2021-12-20 18:56:52 -06:00
Qstick
716eadc551 Add Multiple Languages
Closes #6385
Closes #6564
Closes #6694
Closes #6463

Co-Authored-By: siankatabg <siankatabg@users.noreply.github.com>
Co-Authored-By: tandy1000 <24867509+tandy-1000@users.noreply.github.com>
Co-Authored-By: Kristof Mattei <864376+kristof-mattei@users.noreply.github.com>
Co-Authored-By: Oleksandr Hulyi <4095184+pamidur@users.noreply.github.com>
2021-12-20 18:01:00 -06:00
bakerboy448
1cb31aa95c Fixed: Support movies with French in their title
Regression: Dropped Support for poorly named French Releases

Add language test case

Fixes #6821
2021-12-20 17:32:53 -06:00
Weblate
568dd2fbb2 Translated using Weblate (German) [skip ci]
Currently translated at 100.0% (1113 of 1113 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 99.9% (1112 of 1113 strings)

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

Currently translated at 100.0% (1113 of 1113 strings)

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: reloxx <reloxx@interia.pl>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translation: Servarr/Radarr
2021-12-20 17:21:44 -06:00
Qstick
5d091e519e More Bluray UHD test cases
Fixes #6839
2021-12-19 22:57:06 -06:00
Qstick
faab78c00a Fixed: Improve WEBDL detection of Netflix Rips
Co-Authored-By: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2021-12-19 22:53:51 -06:00
Qstick
f1461056ce Fixed: Parsing of Ger.Dub releases as German
Fixes #6778

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2021-12-19 22:50:42 -06:00
ta264
2042ffce62 Fixed: Don't buffer update package to memory when downloading
[common]
2021-12-19 22:32:37 -06:00
ta264
c6ae6f7b1c Reinstate update tests on BSD
[common]
2021-12-19 22:32:37 -06:00
Weblate
8d7affae68 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 100.0% (1113 of 1113 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2021-12-19 22:29:56 -06:00
Qstick
a418111245 remove removeHandler net6 serialization frontend hack 2021-12-19 20:39:45 -06:00
Qstick
6359ed5757 Bump RestSharp in test package to 106.15.0 2021-12-18 10:04:26 -06:00
Weblate
9a8c1d7d1b Translated using Weblate (Hungarian) [skip ci]
Currently translated at 100.0% (1113 of 1113 strings)

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

Currently translated at 100.0% (1113 of 1113 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 97.2% (1082 of 1113 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Jessie <1355239678@qq.com>
Co-authored-by: Nuno Filipe de Vilhena Santos <nunovilhenasantos@msn.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2021-12-15 22:04:26 -06:00
bakerboy448
e89c2ee9f7 Fixed: Better wording of MissingFromDisk
[common]
2021-12-14 21:08:23 +00:00
Servarr
3d36f88939 Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci] (#6810)
Currently translated at 100.0% (1113 of 1113 strings)

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

Currently translated at 99.9% (1112 of 1113 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (1113 of 1113 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 99.7% (1110 of 1113 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1113 of 1113 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: 西行寺鬼鬼子 <zhang.yaowei@live.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: 西行寺鬼鬼子 <zhang.yaowei@live.com>
2021-12-13 22:37:07 -05:00
Jacob Roeland
8e4320a93b Fix FAQ Link on Add New Movie page 2021-12-13 07:36:23 -06:00
Servarr
b095676010 Translations using Weblate [skip ci] 2021-12-12 11:28:24 -06:00
bakerboy448
41d69d8484 fix erroneous logging for windows service on non-windows
[common]
2021-12-11 22:20:16 -06:00
ta264
073e59e3db Fixed: Windows installer and adding/removing services
(cherry picked from commit 27e3b5e630f04b0774bd6693ffb1c79e7cab95d6)
2021-12-08 21:58:50 +00:00
ta264
588a0843a4 Fixed: Support older glibc in libMonoPosixHelper
(cherry picked from commit 9e7af8369e165c19a2f181071e63bef6961cd64e)
2021-12-08 16:04:51 -06:00
ta264
26cedfd47d Fixed: ffprobe on macOS 10.13 2021-12-07 21:11:35 +00:00
bakerboy448
16789e5b6b New: Display Unknown Items in Activity Queue by Default 2021-12-07 17:34:04 -06:00
Weblate
159edcde94 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 99.9% (1112 of 1113 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 98.6% (1098 of 1113 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 99.7% (1110 of 1113 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 96.8% (1078 of 1113 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: hidaba <nag@hidaba.com>
Co-authored-by: x-nemesis <fsedgy@outlook.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2021-12-07 17:33:52 -06:00
161 changed files with 1879 additions and 441 deletions

View File

@@ -120,7 +120,7 @@ class Blocklist extends Component {
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label="Remove Selected"
label={translate('RemoveSelected')}
iconName={icons.REMOVE}
isDisabled={!selectedIds.length}
isSpinning={isRemoving}

View File

@@ -161,7 +161,7 @@ class AddNewMovie extends Component {
{translate('YouCanAlsoSearch')}
</div>
<div>
<Link to="https://wiki.servarr.com/radarr/faq#why-cant-i-add-a-new-movie-to-radarr">
<Link to="https://wiki.servarr.com/radarr/faq#why-can-i-not-add-a-new-movie-to-radarr">
{translate('CantFindMovie')}
</Link>
</div>

View File

@@ -43,15 +43,15 @@ class CalendarEvent extends Component {
const link = `/movie/${titleSlug}`;
const eventType = [];
if (moment(date).isSame(moment(inCinemas), 'day')) {
if (inCinemas && moment(date).isSame(moment(inCinemas), 'day')) {
eventType.push('Cinemas');
}
if (moment(date).isSame(moment(physicalRelease), 'day')) {
if (physicalRelease && moment(date).isSame(moment(physicalRelease), 'day')) {
eventType.push('Physical');
}
if (moment(date).isSame(moment(digitalRelease), 'day')) {
if (digitalRelease && moment(date).isSame(moment(digitalRelease), 'day')) {
eventType.push('Digital');
}

View File

@@ -166,7 +166,9 @@ class FilterBuilderModalContent extends Component {
</div>
</div>
<div className={styles.label}>Filters</div>
<div className={styles.label}>
{translate('Filters')}
</div>
<div className={styles.rows}>
{

View File

@@ -6,8 +6,7 @@ import SelectInput from './SelectInput';
const availabilityOptions = [
{ key: 'announced', value: translate('Announced') },
{ key: 'inCinemas', value: translate('InCinemas') },
{ key: 'released', value: translate('Released') },
{ key: 'preDB', value: translate('PreDB') }
{ key: 'released', value: translate('Released') }
];
function AvailabilitySelectInput(props) {

View File

@@ -0,0 +1,100 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchDownloadClients } from 'Store/Actions/settingsActions';
import sortByName from 'Utilities/Array/sortByName';
import EnhancedSelectInput from './EnhancedSelectInput';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.downloadClients,
(state, { includeAny }) => includeAny,
(state, { protocol }) => protocol,
(downloadClients, includeAny, protocolFilter) => {
const {
isFetching,
isPopulated,
error,
items
} = downloadClients;
const filteredItems = items.filter((item) => item.protocol === protocolFilter);
const values = _.map(filteredItems.sort(sortByName), (downloadClient) => {
return {
key: downloadClient.id,
value: downloadClient.name
};
});
if (includeAny) {
values.unshift({
key: 0,
value: '(Any)'
});
}
return {
isFetching,
isPopulated,
error,
values
};
}
);
}
const mapDispatchToProps = {
dispatchFetchDownloadClients: fetchDownloadClients
};
class DownloadClientSelectInputConnector extends Component {
//
// Lifecycle
componentDidMount() {
if (!this.props.isPopulated) {
this.props.dispatchFetchDownloadClients();
}
}
//
// Listeners
onChange = ({ name, value }) => {
this.props.onChange({ name, value: parseInt(value) });
}
//
// Render
render() {
return (
<EnhancedSelectInput
{...this.props}
onChange={this.onChange}
/>
);
}
}
DownloadClientSelectInputConnector.propTypes = {
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
values: PropTypes.arrayOf(PropTypes.object).isRequired,
includeAny: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
dispatchFetchDownloadClients: PropTypes.func.isRequired
};
DownloadClientSelectInputConnector.defaultProps = {
includeAny: false,
protocol: 'torrent'
};
export default connect(createMapStateToProps, mapDispatchToProps)(DownloadClientSelectInputConnector);

View File

@@ -8,6 +8,7 @@ import AvailabilitySelectInput from './AvailabilitySelectInput';
import CaptchaInputConnector from './CaptchaInputConnector';
import CheckInput from './CheckInput';
import DeviceInputConnector from './DeviceInputConnector';
import DownloadClientSelectInputConnector from './DownloadClientSelectInputConnector';
import EnhancedSelectInput from './EnhancedSelectInput';
import EnhancedSelectInputConnector from './EnhancedSelectInputConnector';
import FormInputHelpText from './FormInputHelpText';
@@ -73,6 +74,9 @@ function getComponent(type) {
case inputTypes.INDEXER_FLAGS_SELECT:
return IndexerFlagsSelectInputConnector;
case inputTypes.DOWNLOAD_CLIENT_SELECT:
return DownloadClientSelectInputConnector;
case inputTypes.LANGUAGE_SELECT:
return LanguageSelectInputConnector;

View File

@@ -13,6 +13,7 @@ export const QUALITY_PROFILE_SELECT = 'qualityProfileSelect';
export const ROOT_FOLDER_SELECT = 'rootFolderSelect';
export const INDEXER_FLAGS_SELECT = 'indexerFlagsSelect';
export const LANGUAGE_SELECT = 'languageSelect';
export const DOWNLOAD_CLIENT_SELECT = 'downloadClientSelect';
export const SELECT = 'select';
export const DYNAMIC_SELECT = 'dynamicSelect';
export const TAG = 'tag';
@@ -35,6 +36,7 @@ export const all = [
PASSWORD,
PATH,
QUALITY_PROFILE_SELECT,
DOWNLOAD_CLIENT_SELECT,
ROOT_FOLDER_SELECT,
INDEXER_FLAGS_SELECT,
LANGUAGE_SELECT,

View File

@@ -19,6 +19,7 @@ import { align, icons, kinds, scrollDirections } from 'Helpers/Props';
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
@@ -40,6 +41,11 @@ const columns = [
isSortable: true,
isVisible: true
},
{
name: 'releaseGroup',
label: translate('ReleaseGroup'),
isVisible: true
},
{
name: 'quality',
label: translate('Quality'),
@@ -83,6 +89,7 @@ const SELECT = 'select';
const MOVIE = 'movie';
const LANGUAGE = 'language';
const QUALITY = 'quality';
const RELEASE_GROUP = 'releaseGroup';
class InteractiveImportModalContent extends Component {
@@ -202,10 +209,11 @@ class InteractiveImportModalContent extends Component {
const errorMessage = getErrorMessage(error, translate('UnableToLoadManualImportItems'));
const bulkSelectOptions = [
{
key: SELECT, value: translate('SelectDotDot'), disabled: true },
{ key: SELECT, value: translate('SelectDotDot'), disabled: true },
{ key: LANGUAGE, value: translate('SelectLanguage') },
{ key: QUALITY, value: translate('SelectQuality') }];
{ key: QUALITY, value: translate('SelectQuality') },
{ key: RELEASE_GROUP, value: translate('SelectReleaseGroup') }
];
if (allowMovieChange) {
bulkSelectOptions.splice(1, 0, {
@@ -372,6 +380,13 @@ class InteractiveImportModalContent extends Component {
real={false}
onModalClose={this.onSelectModalClose}
/>
<SelectReleaseGroupModal
isOpen={selectModalOpen === RELEASE_GROUP}
ids={selectedIds}
releaseGroup=""
onModalClose={this.onSelectModalClose}
/>
</ModalContent>
);
}

View File

@@ -110,7 +110,8 @@ class InteractiveImportModalContentConnector extends Component {
const {
movie,
quality,
languages
languages,
releaseGroup
} = item;
if (!movie) {
@@ -132,6 +133,7 @@ class InteractiveImportModalContentConnector extends Component {
path: item.path,
folderName: item.folderName,
movieId: movie.id,
releaseGroup,
quality,
languages,
downloadId: this.props.downloadId

View File

@@ -11,6 +11,7 @@ import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
import MovieLanguage from 'Movie/MovieLanguage';
import MovieQuality from 'Movie/MovieQuality';
import formatBytes from 'Utilities/Number/formatBytes';
@@ -28,6 +29,7 @@ class InteractiveImportRow extends Component {
this.state = {
isSelectMovieModalOpen: false,
isSelectReleaseGroupModalOpen: false,
isSelectQualityModalOpen: false,
isSelectLanguageModalOpen: false
};
@@ -103,6 +105,10 @@ class InteractiveImportRow extends Component {
this.setState({ isSelectMovieModalOpen: true });
}
onSelectReleaseGroupPress = () => {
this.setState({ isSelectReleaseGroupModalOpen: true });
}
onSelectQualityPress = () => {
this.setState({ isSelectQualityModalOpen: true });
}
@@ -116,6 +122,11 @@ class InteractiveImportRow extends Component {
this.selectRowAfterChange(changed);
}
onSelectReleaseGroupModalClose = (changed) => {
this.setState({ isSelectReleaseGroupModalOpen: false });
this.selectRowAfterChange(changed);
}
onSelectQualityModalClose = (changed) => {
this.setState({ isSelectQualityModalOpen: false });
this.selectRowAfterChange(changed);
@@ -137,6 +148,7 @@ class InteractiveImportRow extends Component {
movie,
quality,
languages,
releaseGroup,
size,
rejections,
isReprocessing,
@@ -147,7 +159,8 @@ class InteractiveImportRow extends Component {
const {
isSelectMovieModalOpen,
isSelectQualityModalOpen,
isSelectLanguageModalOpen
isSelectLanguageModalOpen,
isSelectReleaseGroupModalOpen
} = this.state;
const movieTitle = movie ? movie.title + ( movie.year > 0 ? ` (${movie.year})` : '') : '';
@@ -155,6 +168,7 @@ class InteractiveImportRow extends Component {
const showMoviePlaceholder = isSelected && !movie;
const showQualityPlaceholder = isSelected && !quality;
const showLanguagePlaceholder = isSelected && !languages && !isReprocessing;
const showReleaseGroupPlaceholder = isSelected && !releaseGroup;
return (
<TableRow>
@@ -181,6 +195,17 @@ class InteractiveImportRow extends Component {
}
</TableRowCellButton>
<TableRowCellButton
title={translate('ClickToChangeReleaseGroup')}
onPress={this.onSelectReleaseGroupPress}
>
{
showReleaseGroupPlaceholder ?
<InteractiveImportRowCellPlaceholder /> :
releaseGroup
}
</TableRowCellButton>
<TableRowCellButton
className={styles.quality}
title={translate('ClickToChangeQuality')}
@@ -268,6 +293,13 @@ class InteractiveImportRow extends Component {
onModalClose={this.onSelectMovieModalClose}
/>
<SelectReleaseGroupModal
isOpen={isSelectReleaseGroupModalOpen}
ids={[id]}
releaseGroup={releaseGroup ?? ''}
onModalClose={this.onSelectReleaseGroupModalClose}
/>
<SelectQualityModal
isOpen={isSelectQualityModalOpen}
ids={[id]}
@@ -296,6 +328,7 @@ InteractiveImportRow.propTypes = {
movie: PropTypes.object,
quality: PropTypes.object,
languages: PropTypes.arrayOf(PropTypes.object),
releaseGroup: PropTypes.string,
size: PropTypes.number.isRequired,
rejections: PropTypes.arrayOf(PropTypes.object).isRequired,
isReprocessing: PropTypes.bool,

View File

@@ -128,7 +128,7 @@ class SelectLanguageModalContent extends Component {
kind={kinds.SUCCESS}
onPress={this.onLanguageSelect}
>
{translate('SelectLanguges')}
{translate('SelectLanguages')}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -0,0 +1,37 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Modal from 'Components/Modal/Modal';
import SelectReleaseGroupModalContentConnector from './SelectReleaseGroupModalContentConnector';
class SelectReleaseGroupModal extends Component {
//
// Render
render() {
const {
isOpen,
onModalClose,
...otherProps
} = this.props;
return (
<Modal
isOpen={isOpen}
onModalClose={onModalClose}
>
<SelectReleaseGroupModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
</Modal>
);
}
}
SelectReleaseGroupModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default SelectReleaseGroupModal;

View File

@@ -0,0 +1,99 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
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 Button from 'Components/Link/Button';
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, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class SelectReleaseGroupModalContent extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
const {
releaseGroup
} = props;
this.state = {
releaseGroup
};
}
//
// Listeners
onReleaseGroupChange = ({ value }) => {
this.setState({ releaseGroup: value });
}
onReleaseGroupSelect = () => {
this.props.onReleaseGroupSelect(this.state);
}
//
// Render
render() {
const {
onModalClose
} = this.props;
const {
releaseGroup
} = this.state;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{translate('ManualImportSetReleaseGroup')}
</ModalHeader>
<ModalBody>
<Form>
<FormGroup>
<FormLabel>{translate('ReleaseGroup')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="releaseGroup"
value={releaseGroup}
onChange={this.onReleaseGroupChange}
/>
</FormGroup>
</Form>
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>
{translate('Cancel')}
</Button>
<Button
kind={kinds.SUCCESS}
onPress={this.onReleaseGroupSelect}
>
{translate('SetReleaseGroup')}
</Button>
</ModalFooter>
</ModalContent>
);
}
}
SelectReleaseGroupModalContent.propTypes = {
releaseGroup: PropTypes.string.isRequired,
onReleaseGroupSelect: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default SelectReleaseGroupModalContent;

View File

@@ -0,0 +1,54 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { reprocessInteractiveImportItems, updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
import SelectReleaseGroupModalContent from './SelectReleaseGroupModalContent';
const mapDispatchToProps = {
dispatchUpdateInteractiveImportItems: updateInteractiveImportItems,
dispatchReprocessInteractiveImportItems: reprocessInteractiveImportItems
};
class SelectReleaseGroupModalContentConnector extends Component {
//
// Listeners
onReleaseGroupSelect = ({ releaseGroup }) => {
const {
ids,
dispatchUpdateInteractiveImportItems,
dispatchReprocessInteractiveImportItems
} = this.props;
dispatchUpdateInteractiveImportItems({
ids,
releaseGroup
});
dispatchReprocessInteractiveImportItems({ ids });
this.props.onModalClose(true);
}
//
// Render
render() {
return (
<SelectReleaseGroupModalContent
{...this.props}
onReleaseGroupSelect={this.onReleaseGroupSelect}
/>
);
}
}
SelectReleaseGroupModalContentConnector.propTypes = {
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired,
dispatchReprocessInteractiveImportItems: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default connect(null, mapDispatchToProps)(SelectReleaseGroupModalContentConnector);

View File

@@ -155,7 +155,7 @@ DeleteMovieModalContent.propTypes = {
title: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
hasFile: PropTypes.bool.isRequired,
sizeOnDisk: PropTypes.string.isRequired,
sizeOnDisk: PropTypes.number.isRequired,
onDeletePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};

View File

@@ -101,6 +101,15 @@ function MovieIndexSortMenu(props) {
{translate('DigitalRelease')}
</SortMenuItem>
<SortMenuItem
name="ratings"
sortKey={sortKey}
sortDirection={sortDirection}
onPress={onSortSelect}
>
{translate('Ratings')}
</SortMenuItem>
<SortMenuItem
name="path"
sortKey={sortKey}

View File

@@ -6,7 +6,7 @@ export function getMovieStatusDetails(status) {
let statusDetails = {
icon: icons.ANNOUNCED,
title: translate('Announced'),
message: translate('AnnoucedMsg')
message: translate('AnnouncedMsg')
};
if (status === 'deleted') {

View File

@@ -4,6 +4,11 @@
margin-right: auto;
}
.rightButtons {
justify-content: flex-end;
margin-right: auto;
}
.addSpecification {
composes: customFormat from '~./CustomFormat.css';

View File

@@ -198,26 +198,25 @@ class EditCustomFormatModalContent extends Component {
</div>
</ModalBody>
<ModalFooter>
{
id &&
<Button
className={styles.deleteButton}
kind={kinds.DANGER}
onPress={onDeleteCustomFormatPress}
>
{translate('Delete')}
</Button>
}
<div className={styles.rightButtons}>
{
id &&
<Button
className={styles.deleteButton}
kind={kinds.DANGER}
onPress={onDeleteCustomFormatPress}
>
{translate('Delete')}
</Button>
}
{
!id &&
<Button
className={styles.deleteButton}
onPress={this.onImportPress}
>
{translate('Import')}
</Button>
}
<Button
className={styles.deleteButton}
onPress={this.onImportPress}
>
{translate('Import')}
</Button>
</div>
<Button
onPress={onModalClose}

View File

@@ -1,23 +1,20 @@
.remotePathMapping {
display: flex;
align-items: stretch;
align-items: left;
margin-bottom: 10px;
height: 30px;
border-bottom: 1px solid $borderColor;
line-height: 30px;
}
.actions {
flex: 0 0 25px;
}
.host {
flex: 0 0 300px;
flex: 1 0 300px;
}
.path {
flex: 0 0 400px;
}
.actions {
display: flex;
justify-content: flex-end;
flex: 1 0 auto;
padding-right: 10px;
flex: 1 0 400px;
}

View File

@@ -66,9 +66,6 @@ class RemotePathMapping extends Component {
styles.remotePathMapping
)}
>
<div className={styles.host}>{host}</div>
<div className={styles.path}>{remotePath}</div>
<div className={styles.path}>{localPath}</div>
<div className={styles.actions}>
<Link
@@ -78,6 +75,10 @@ class RemotePathMapping extends Component {
</Link>
</div>
<div className={styles.host}>{host}</div>
<div className={styles.path}>{remotePath}</div>
<div className={styles.path}>{localPath}</div>
<EditRemotePathMappingModalConnector
id={id}
isOpen={this.state.isEditRemotePathMappingModalOpen}

View File

@@ -4,17 +4,19 @@
font-weight: bold;
}
.actions {
flex: 0 0 25px;
}
.host {
flex: 0 0 300px;
flex: 1 0 300px;
}
.path {
flex: 0 0 400px;
flex: 1 0 400px;
}
.addRemotePathMapping {
display: flex;
justify-content: flex-end;
padding-right: 10px;
}

View File

@@ -51,9 +51,15 @@ class RemotePathMappings extends Component {
{...otherProps}
>
<div className={styles.remotePathMappingsHeader}>
<div className={styles.host}>Host</div>
<div className={styles.path}>Remote Path</div>
<div className={styles.path}>Local Path</div>
<div className={styles.host}>
{translate('Host')}
</div>
<div className={styles.path}>
{translate('RemotePath')}
</div>
<div className={styles.path}>
{translate('LocalPath')}
</div>
</div>
<div>

View File

@@ -2,16 +2,16 @@ import PropTypes from 'prop-types';
import React from 'react';
import Modal from 'Components/Modal/Modal';
import { sizes } from 'Helpers/Props';
import EditImportExclusionModalContentConnector from './EditImportExclusionModalContentConnector';
import EditImportListExclusionModalContentConnector from './EditImportListExclusionModalContentConnector';
function EditImportExclusionModal({ isOpen, onModalClose, ...otherProps }) {
function EditImportListExclusionModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>
<EditImportExclusionModalContentConnector
<EditImportListExclusionModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
@@ -19,9 +19,9 @@ function EditImportExclusionModal({ isOpen, onModalClose, ...otherProps }) {
);
}
EditImportExclusionModal.propTypes = {
EditImportListExclusionModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default EditImportExclusionModal;
export default EditImportListExclusionModal;

View File

@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import EditImportExclusionModal from './EditImportExclusionModal';
import EditImportListExclusionModal from './EditImportListExclusionModal';
function mapStateToProps() {
return {};
@@ -12,7 +12,7 @@ const mapDispatchToProps = {
clearPendingChanges
};
class EditImportExclusionModalConnector extends Component {
class EditImportListExclusionModalConnector extends Component {
//
// Listeners
@@ -27,7 +27,7 @@ class EditImportExclusionModalConnector extends Component {
render() {
return (
<EditImportExclusionModal
<EditImportListExclusionModal
{...this.props}
onModalClose={this.onModalClose}
/>
@@ -35,9 +35,9 @@ class EditImportExclusionModalConnector extends Component {
}
}
EditImportExclusionModalConnector.propTypes = {
EditImportListExclusionModalConnector.propTypes = {
onModalClose: PropTypes.func.isRequired,
clearPendingChanges: PropTypes.func.isRequired
};
export default connect(mapStateToProps, mapDispatchToProps)(EditImportExclusionModalConnector);
export default connect(mapStateToProps, mapDispatchToProps)(EditImportListExclusionModalConnector);

View File

@@ -13,9 +13,9 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './EditImportExclusionModalContent.css';
import styles from './EditImportListExclusionModalContent.css';
function EditImportExclusionModalContent(props) {
function EditImportListExclusionModalContent(props) {
const {
id,
isFetching,
@@ -130,7 +130,7 @@ function EditImportExclusionModalContent(props) {
);
}
EditImportExclusionModalContent.propTypes = {
EditImportListExclusionModalContent.propTypes = {
id: PropTypes.number,
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
@@ -143,4 +143,4 @@ EditImportExclusionModalContent.propTypes = {
onDeleteImportExclusionPress: PropTypes.func
};
export default EditImportExclusionModalContent;
export default EditImportListExclusionModalContent;

View File

@@ -5,7 +5,7 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { saveImportExclusion, setImportExclusionValue } from 'Store/Actions/settingsActions';
import selectSettings from 'Store/Selectors/selectSettings';
import EditImportExclusionModalContent from './EditImportExclusionModalContent';
import EditImportListExclusionModalContent from './EditImportListExclusionModalContent';
const newImportExclusion = {
movieTitle: '',
@@ -97,7 +97,7 @@ class EditImportExclusionModalContentConnector extends Component {
render() {
return (
<EditImportExclusionModalContent
<EditImportListExclusionModalContent
{...this.props}
onSavePress={this.onSavePress}
onInputChange={this.onInputChange}

View File

@@ -8,12 +8,14 @@
}
.movieTitle {
flex: 0 0 400px;
@add-mixin truncate;
flex: 0 0 600px;
}
.tmdbId,
.movieYear {
flex: 0 0 200px;
flex: 0 0 70px;
}
.actions {

View File

@@ -6,10 +6,10 @@ import Link from 'Components/Link/Link';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditImportExclusionModalConnector from './EditImportExclusionModalConnector';
import styles from './ImportExclusion.css';
import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector';
import styles from './ImportListExclusion.css';
class ImportExclusion extends Component {
class ImportListExclusion extends Component {
//
// Lifecycle
@@ -78,7 +78,7 @@ class ImportExclusion extends Component {
</Link>
</div>
<EditImportExclusionModalConnector
<EditImportListExclusionModalConnector
id={id}
isOpen={this.state.isEditImportExclusionModalOpen}
onModalClose={this.onEditImportExclusionModalClose}
@@ -99,7 +99,7 @@ class ImportExclusion extends Component {
}
}
ImportExclusion.propTypes = {
ImportListExclusion.propTypes = {
id: PropTypes.number.isRequired,
movieTitle: PropTypes.string.isRequired,
tmdbId: PropTypes.number.isRequired,
@@ -107,9 +107,9 @@ ImportExclusion.propTypes = {
onConfirmDeleteImportExclusion: PropTypes.func.isRequired
};
ImportExclusion.defaultProps = {
ImportListExclusion.defaultProps = {
// The drag preview will not connect the drag handle.
connectDragSource: (node) => node
};
export default ImportExclusion;
export default ImportListExclusion;

View File

@@ -1,16 +1,16 @@
.importExclusionsHeader {
.importListExclusionsHeader {
display: flex;
margin-bottom: 10px;
font-weight: bold;
}
.title {
flex: 0 0 400px;
flex: 0 0 600px;
}
.tmdbId,
.movieYear {
flex: 0 0 200px;
flex: 0 0 70px;
}
.addImportExclusion {

View File

@@ -6,11 +6,11 @@ import Link from 'Components/Link/Link';
import PageSectionContent from 'Components/Page/PageSectionContent';
import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditImportExclusionModalConnector from './EditImportExclusionModalConnector';
import ImportExclusion from './ImportExclusion';
import styles from './ImportExclusions.css';
import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector';
import ImportListExclusion from './ImportListExclusion';
import styles from './ImportListExclusions.css';
class ImportExclusions extends Component {
class ImportListExclusions extends Component {
//
// Lifecycle
@@ -51,16 +51,22 @@ class ImportExclusions extends Component {
{...otherProps}
>
<div className={styles.importExclusionsHeader}>
<div className={styles.tmdbId}>TMDB Id</div>
<div className={styles.title}>Title</div>
<div className={styles.movieYear}>Year</div>
<div className={styles.tmdbId}>
TMDb Id
</div>
<div className={styles.title}>
{translate('Title')}
</div>
<div className={styles.movieYear}>
{translate('Year')}
</div>
</div>
<div>
{
items.map((item, index) => {
return (
<ImportExclusion
<ImportListExclusion
key={item.id}
{...item}
{...otherProps}
@@ -81,7 +87,7 @@ class ImportExclusions extends Component {
</Link>
</div>
<EditImportExclusionModalConnector
<EditImportListExclusionModalConnector
isOpen={this.state.isAddImportExclusionModalOpen}
onModalClose={this.onModalClose}
/>
@@ -92,11 +98,11 @@ class ImportExclusions extends Component {
}
}
ImportExclusions.propTypes = {
ImportListExclusions.propTypes = {
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
onConfirmDeleteImportExclusion: PropTypes.func.isRequired
};
export default ImportExclusions;
export default ImportListExclusions;

View File

@@ -3,7 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { deleteImportExclusion, fetchImportExclusions } from 'Store/Actions/settingsActions';
import ImportExclusions from './ImportExclusions';
import ImportListExclusions from './ImportListExclusions';
function createMapStateToProps() {
return createSelector(
@@ -42,7 +42,7 @@ class ImportExclusionsConnector extends Component {
render() {
return (
<ImportExclusions
<ImportListExclusions
{...this.state}
{...this.props}
onConfirmDeleteImportExclusion={this.onConfirmDeleteImportExclusion}

View File

@@ -7,7 +7,7 @@ import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { icons } from 'Helpers/Props';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
import ImportExclusionsConnector from './ImportExclusions/ImportExclusionsConnector';
import ImportListExclusionsConnector from './ImportListExclusions/ImportListExclusionsConnector';
import ImportListsConnector from './ImportLists/ImportListsConnector';
import ImportListOptionsConnector from './Options/ImportListOptionsConnector';
@@ -86,7 +86,7 @@ class ImportListSettings extends Component {
onChildStateChange={this.onChildStateChange}
/>
<ImportExclusionsConnector />
<ImportListExclusionsConnector />
</PageContentBody>
</PageContent>

View File

@@ -45,7 +45,9 @@ function EditIndexerModalContent(props) {
supportsSearch,
tags,
fields,
priority
priority,
protocol,
downloadClientId
} = item;
return (
@@ -154,8 +156,25 @@ function EditIndexerModalContent(props) {
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('DownloadClient')}</FormLabel>
<FormInputGroup
type={inputTypes.DOWNLOAD_CLIENT_SELECT}
name="downloadClientId"
helpText={translate('IndexerDownloadClientHelpText')}
{...downloadClientId}
includeAny={true}
protocol={protocol.value}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>Tags</FormLabel>
<FormLabel>{translate('Tags')}</FormLabel>
<FormInputGroup
type={inputTypes.TAG}

View File

@@ -63,6 +63,7 @@ class Notification extends Component {
onMovieFileDelete,
onMovieFileDeleteForUpgrade,
onHealthIssue,
onApplicationUpdate,
supportsOnGrab,
supportsOnDownload,
supportsOnUpgrade,
@@ -70,7 +71,8 @@ class Notification extends Component {
supportsOnMovieDelete,
supportsOnMovieFileDelete,
supportsOnMovieFileDeleteForUpgrade,
supportsOnHealthIssue
supportsOnHealthIssue,
supportsOnApplicationUpdate
} = this.props;
return (
@@ -123,6 +125,14 @@ class Notification extends Component {
null
}
{
supportsOnApplicationUpdate && onApplicationUpdate ?
<Label kind={kinds.SUCCESS}>
{translate('OnApplicationUpdate')}
</Label> :
null
}
{
supportsOnMovieDelete && onMovieDelete ?
<Label kind={kinds.SUCCESS}>
@@ -148,7 +158,7 @@ class Notification extends Component {
}
{
!onGrab && !onDownload && !onRename && !onHealthIssue && !onMovieDelete && !onMovieFileDelete ?
!onGrab && !onDownload && !onRename && !onHealthIssue && !onApplicationUpdate && !onMovieDelete && !onMovieFileDelete ?
<Label
kind={kinds.DISABLED}
outline={true}
@@ -190,6 +200,7 @@ Notification.propTypes = {
onMovieFileDelete: PropTypes.bool.isRequired,
onMovieFileDeleteForUpgrade: PropTypes.bool.isRequired,
onHealthIssue: PropTypes.bool.isRequired,
onApplicationUpdate: PropTypes.bool.isRequired,
supportsOnGrab: PropTypes.bool.isRequired,
supportsOnDownload: PropTypes.bool.isRequired,
supportsOnMovieDelete: PropTypes.bool.isRequired,
@@ -198,6 +209,7 @@ Notification.propTypes = {
supportsOnUpgrade: PropTypes.bool.isRequired,
supportsOnRename: PropTypes.bool.isRequired,
supportsOnHealthIssue: PropTypes.bool.isRequired,
supportsOnApplicationUpdate: PropTypes.bool.isRequired,
onConfirmDeleteNotification: PropTypes.func.isRequired
};

View File

@@ -23,6 +23,7 @@ function NotificationEventItems(props) {
onMovieFileDelete,
onMovieFileDeleteForUpgrade,
onHealthIssue,
onApplicationUpdate,
supportsOnGrab,
supportsOnDownload,
supportsOnUpgrade,
@@ -30,6 +31,7 @@ function NotificationEventItems(props) {
supportsOnMovieDelete,
supportsOnMovieFileDelete,
supportsOnMovieFileDeleteForUpgrade,
supportsOnApplicationUpdate,
supportsOnHealthIssue,
includeHealthWarnings
} = item;
@@ -150,6 +152,17 @@ function NotificationEventItems(props) {
/>
</div>
}
<div>
<FormInputGroup
type={inputTypes.CHECK}
name="onApplicationUpdate"
helpText={translate('OnApplicationUpdateHelpText')}
isDisabled={!supportsOnApplicationUpdate.value}
{...onApplicationUpdate}
onChange={onInputChange}
/>
</div>
</div>
</div>
</FormGroup>

View File

@@ -82,10 +82,18 @@ class DelayProfiles extends Component {
>
<div>
<div className={styles.delayProfilesHeader}>
<div className={styles.column}>Protocol</div>
<div className={styles.column}>Usenet Delay</div>
<div className={styles.column}>Torrent Delay</div>
<div className={styles.tags}>Tags</div>
<div className={styles.column}>
{translate('Protocol')}
</div>
<div className={styles.column}>
{translate('UsenetDelay')}
</div>
<div className={styles.column}>
{translate('TorrentDelay')}
</div>
<div className={styles.tags}>
{translate('Tags')}
</div>
</div>
<div className={styles.delayProfiles}>

View File

@@ -25,9 +25,15 @@ class QualityDefinitions extends Component {
{...otherProps}
>
<div className={styles.header}>
<div className={styles.quality}>Quality</div>
<div className={styles.title}>Title</div>
<div className={styles.sizeLimit}>Size Limit</div>
<div className={styles.quality}>
{translate('Quality')}
</div>
<div className={styles.title}>
{translate('Title')}
</div>
<div className={styles.sizeLimit}>
{translate('SizeLimit')}
</div>
{
advancedSettings ?

View File

@@ -152,7 +152,7 @@ function TagDetailsModalContent(props) {
{
indexers.length ?
<FieldSet legend="Indexers">
<FieldSet legend={translate('Indexers')}>
{
indexers.map((item) => {
return (

View File

@@ -14,7 +14,6 @@ function createRemoveItemHandler(section, url) {
const ajaxOptions = {
url: `${url}/${id}?${$.param(queryParams, true)}`,
dataType: 'text',
method: 'DELETE'
};

View File

@@ -109,6 +109,7 @@ export default {
selectedSchema.onMovieDelete = selectedSchema.supportsOnMovieDelete;
selectedSchema.onMovieFileDelete = selectedSchema.supportsOnMovieFileDelete;
selectedSchema.onMovieFileDeleteForUpgrade = selectedSchema.supportsOnMovieFileDeleteForUpgrade;
selectedSchema.onApplicationUpdate = selectedSchema.supportsOnApplicationUpdate;
return selectedSchema;
});

View File

@@ -148,9 +148,10 @@ export const actionHandlers = handleThunks({
return {
id,
path: item.path,
movieId: item.movie.id,
movieId: item.movie ? item.movie.id : undefined,
quality: item.quality,
languages: item.languages,
releaseGroup: item.releaseGroup,
downloadId: item.downloadId
};
});

View File

@@ -27,7 +27,7 @@ const paged = `${section}.paged`;
export const defaultState = {
options: {
includeUnknownMovieItems: false
includeUnknownMovieItems: true
},
status: {

View File

@@ -146,7 +146,7 @@ namespace NzbDrone.Common.Test.Http
var request = new HttpRequest($"https://expired.badssl.com");
Assert.Throws<HttpRequestException>(() => Subject.Execute(request));
ExceptionVerification.ExpectedErrors(2);
ExceptionVerification.ExpectedErrors(1);
}
[Test]

View File

@@ -14,7 +14,7 @@ namespace NzbDrone.Common.EnvironmentInfo
private readonly Logger _logger;
private readonly DateTime _startTime = DateTime.UtcNow;
public RuntimeInfo(IHostLifetime hostLifetime, Logger logger)
public RuntimeInfo(Logger logger, IHostLifetime hostLifetime = null)
{
_logger = logger;

View File

@@ -26,20 +26,17 @@ namespace NzbDrone.Common.Http.Dispatchers
private readonly ICertificateValidationService _certificateValidationService;
private readonly IUserAgentBuilder _userAgentBuilder;
private readonly ICached<System.Net.Http.HttpClient> _httpClientCache;
private readonly Logger _logger;
public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider,
ICreateManagedWebProxy createManagedWebProxy,
ICertificateValidationService certificateValidationService,
IUserAgentBuilder userAgentBuilder,
ICacheManager cacheManager,
Logger logger)
ICacheManager cacheManager)
{
_proxySettingsProvider = proxySettingsProvider;
_createManagedWebProxy = createManagedWebProxy;
_certificateValidationService = certificateValidationService;
_userAgentBuilder = userAgentBuilder;
_logger = logger;
_httpClientCache = cacheManager.GetCache<System.Net.Http.HttpClient>(typeof(ManagedHttpDispatcher));
}
@@ -79,49 +76,32 @@ namespace NzbDrone.Common.Http.Dispatchers
var httpClient = GetClient(request.Url);
HttpResponseMessage responseMessage;
try
using var responseMessage = httpClient.Send(requestMessage, HttpCompletionOption.ResponseHeadersRead, cts.Token);
{
responseMessage = httpClient.Send(requestMessage, cts.Token);
}
catch (HttpRequestException e)
{
_logger.Error(e, "HttpClient error");
throw;
}
byte[] data = null;
byte[] data = null;
using (var responseStream = responseMessage.Content.ReadAsStream())
{
if (responseStream != null && responseStream != Stream.Null)
try
{
try
if (request.ResponseStream != null && responseMessage.StatusCode == HttpStatusCode.OK)
{
if (request.ResponseStream != null && responseMessage.StatusCode == HttpStatusCode.OK)
{
// A target ResponseStream was specified, write to that instead.
// But only on the OK status code, since we don't want to write failures and redirects.
responseStream.CopyTo(request.ResponseStream);
}
else
{
data = responseStream.ToBytes();
}
responseMessage.Content.CopyTo(request.ResponseStream, null, cts.Token);
}
catch (Exception ex)
else
{
throw new WebException("Failed to read complete http response", ex, WebExceptionStatus.ReceiveFailure, null);
data = responseMessage.Content.ReadAsByteArrayAsync(cts.Token).GetAwaiter().GetResult();
}
}
catch (Exception ex)
{
throw new WebException("Failed to read complete http response", ex, WebExceptionStatus.ReceiveFailure, null);
}
var headers = responseMessage.Headers.ToNameValueCollection();
headers.Add(responseMessage.Content.Headers.ToNameValueCollection());
return new HttpResponse(request, new HttpHeader(headers), data, responseMessage.StatusCode);
}
var headers = responseMessage.Headers.ToNameValueCollection();
headers.Add(responseMessage.Content.Headers.ToNameValueCollection());
return new HttpResponse(request, new HttpHeader(headers), data, responseMessage.StatusCode);
}
protected virtual System.Net.Http.HttpClient GetClient(HttpUri uri)

View File

@@ -0,0 +1,71 @@
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class migrate_discord_from_slackFixture : MigrationTest<migrate_discord_from_slack>
{
private readonly JsonSerializerOptions _serializerSettings;
public migrate_discord_from_slackFixture()
{
_serializerSettings = new JsonSerializerOptions
{
AllowTrailingCommas = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
PropertyNameCaseInsensitive = true,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
_serializerSettings.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase, true));
}
[Test]
public void should_replace_old_url()
{
var webhookUrl = "https://discord.com/api/webhooks/922499153416847361/f9CAcD5i_E_-0AoPfMVa8igVK8h271HpJDbd6euUrPh9KonWlMCziLOSMmD-2SQ4CHmX/slack";
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Notifications").Row(new
{
Name = "SlackDiscord",
Implementation = "Slack",
Settings = new SlackNotificationSettings201
{
Icon = "TestURL",
Username = "TestUsername",
WebHookUrl = webhookUrl
}.ToJson(),
ConfigContract = "SlackSettings",
OnGrab = true,
OnDownload = true,
OnUpgrade = true,
OnRename = true,
OnHealthIssue = true,
OnMovieDelete = true,
OnMovieFileDelete = true,
OnMovieFileDeleteForUpgrade = true,
IncludeHealthWarnings = true
});
});
var items = db.Query<NotificationEntity201>("SELECT Id,ConfigContract,Implementation,Name,Settings FROM Notifications");
items.Should().HaveCount(1);
items.First().ConfigContract.Should().Be("DiscordSettings");
var settings = JsonSerializer.Deserialize<DiscordNotificationSettings201>(items.First().Settings, _serializerSettings);
settings.Avatar.Should().Be("TestURL");
settings.Username.Should().Be("TestUsername");
settings.WebHookUrl.Should().Be(webhookUrl.Replace("/slack", ""));
}
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class remove_predbFixture : MigrationTest<remove_predb>
{
[Test]
public void should_change_min_avail_from_predb_on_list()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("ImportLists").Row(new
{
Enabled = 1,
EnableAuto = 1,
RootFolderPath = "D:\\Movies",
ProfileId = 1,
MinimumAvailability = 4,
ShouldMonitor = 1,
Name = "IMDB List",
Implementation = "RadarrLists",
Settings = new RadarrListSettings169
{
APIURL = "https://api.radarr.video/v2",
Path = "/imdb/list?listId=ls000199717",
}.ToJson(),
ConfigContract = "RadarrSettings"
});
});
var items = db.Query<ListDefinition201>("SELECT Id, MinimumAvailability FROM ImportLists");
items.Should().HaveCount(1);
items.First().MinimumAvailability.Should().Be(3);
}
[Test]
public void should_change_min_avail_from_predb_on_movie()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Movies").Row(new
{
Monitored = true,
Title = "Title",
CleanTitle = "CleanTitle",
Status = 3,
MinimumAvailability = 4,
Images = new[] { new { CoverType = "Poster" } }.ToJson(),
Recommendations = new[] { 1 }.ToJson(),
HasPreDBEntry = false,
Runtime = 90,
OriginalLanguage = 1,
ProfileId = 1,
MovieFileId = 0,
Path = string.Format("/Movies/{0}", "Title"),
TitleSlug = 123456,
TmdbId = 132456,
Added = DateTime.UtcNow,
LastInfoSync = DateTime.UtcNow,
});
});
var items = db.Query<Movie201>("SELECT Id, MinimumAvailability FROM Movies");
items.Should().HaveCount(1);
items.First().MinimumAvailability.Should().Be(3);
}
}
public class ListDefinition201
{
public int Id { get; set; }
public int MinimumAvailability { get; set; }
}
public class Movie201
{
public int Id { get; set; }
public int MinimumAvailability { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
using System.Data;
using System.Data;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
@@ -38,6 +38,7 @@ namespace NzbDrone.Core.Test.Datastore.SqliteSchemaDumperTests
result.Name.Should().Be(tableName);
result.Columns.Count.Should().Be(1);
result.Columns.First().Name.Should().Be(columnName);
result.Columns.First().IsIdentity.Should().BeTrue();
}
[TestCase(@"CREATE INDEX TestIndex ON TestTable (MyId)", "TestIndex", "TestTable", "MyId")]

View File

@@ -1,10 +1,11 @@
using System;
using System;
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Test.Framework;
@@ -67,6 +68,17 @@ namespace NzbDrone.Core.Test.Download
return mock;
}
private void WithTorrentIndexer(int downloadClientId)
{
Mocker.GetMock<IIndexerFactory>()
.Setup(v => v.Find(It.IsAny<int>()))
.Returns(Builder<IndexerDefinition>
.CreateNew()
.With(v => v.Id = _nextId++)
.With(v => v.DownloadClientId = downloadClientId)
.Build());
}
private void GivenBlockedClient(int id)
{
_blockedProviders.Add(new DownloadClientStatus
@@ -223,5 +235,39 @@ namespace NzbDrone.Core.Test.Download
client3.Definition.Id.Should().Be(2);
client4.Definition.Id.Should().Be(3);
}
[Test]
public void should_always_choose_indexer_client()
{
WithUsenetClient();
WithTorrentClient();
WithTorrentClient();
WithTorrentClient();
WithTorrentIndexer(3);
var client1 = Subject.GetDownloadClient(DownloadProtocol.Torrent, 1);
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent, 1);
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent, 1);
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent, 1);
var client5 = Subject.GetDownloadClient(DownloadProtocol.Torrent, 1);
client1.Definition.Id.Should().Be(3);
client2.Definition.Id.Should().Be(3);
client3.Definition.Id.Should().Be(3);
client4.Definition.Id.Should().Be(3);
client5.Definition.Id.Should().Be(3);
}
[Test]
public void should_fail_to_choose_client_when_indexer_reference_does_not_exist()
{
WithUsenetClient();
WithTorrentClient();
WithTorrentClient();
WithTorrentClient();
WithTorrentIndexer(5);
Assert.Throws<DownloadClientUnavailableException>(() => Subject.GetDownloadClient(DownloadProtocol.Torrent, 1));
}
}
}

View File

@@ -31,8 +31,8 @@ namespace NzbDrone.Core.Test.Download
.Returns(_downloadClients);
Mocker.GetMock<IProvideDownloadClient>()
.Setup(v => v.GetDownloadClient(It.IsAny<DownloadProtocol>()))
.Returns<DownloadProtocol>(v => _downloadClients.FirstOrDefault(d => d.Protocol == v));
.Setup(v => v.GetDownloadClient(It.IsAny<DownloadProtocol>(), It.IsAny<int>()))
.Returns<DownloadProtocol, int>((v, i) => _downloadClients.FirstOrDefault(d => d.Protocol == v));
var releaseInfo = Builder<ReleaseInfo>.CreateNew()
.With(v => v.DownloadProtocol = DownloadProtocol.Usenet)

View File

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

View File

@@ -19,6 +19,10 @@ namespace NzbDrone.Core.Test.HealthCheck
Mocker.SetConstant<IEnumerable<IProvideHealthCheck>>(new[] { _healthCheck });
Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>());
Mocker.GetMock<IServerSideNotificationService>()
.Setup(v => v.GetServerChecks())
.Returns(new List<Core.HealthCheck.HealthCheck>());
}
[Test]

View File

@@ -204,5 +204,48 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
pageTier2.Url.Query.Should().NotContain("imdbid=0076759");
pageTier2.Url.Query.Should().Contain("q=");
}
[Test]
public void should_encode_raw_title()
{
_capabilities.SupportedMovieSearchParameters = new[] { "q" };
_capabilities.TextSearchEngine = "raw";
MovieSearchCriteria movieRawSearchCriteria = new MovieSearchCriteria
{
Movie = new Movies.Movie { Title = "Some Movie & Title: Words", Year = 2021, TmdbId = 123 },
SceneTitles = new List<string> { "Some Movie & Title: Words" }
};
var results = Subject.GetSearchRequests(movieRawSearchCriteria);
var page = results.GetTier(0).First().First();
page.Url.Query.Should().Contain("q=Some%20Movie%20%26%20Title%3A%20Words");
page.Url.Query.Should().NotContain(" & ");
page.Url.Query.Should().Contain("%26");
}
[Test]
public void should_use_clean_title_and_encode()
{
_capabilities.SupportedMovieSearchParameters = new[] { "q" };
_capabilities.TextSearchEngine = "sphinx";
MovieSearchCriteria movieRawSearchCriteria = new MovieSearchCriteria
{
Movie = new Movies.Movie { Title = "Some Movie & Title: Words", Year = 2021, TmdbId = 123 },
SceneTitles = new List<string> { "Some Movie & Title: Words" }
};
var results = Subject.GetSearchRequests(movieRawSearchCriteria);
var page = results.GetTier(0).First().First();
page.Url.Query.Should().Contain("q=Some%20Movie%20and%20Title%20Words%202021");
page.Url.Query.Should().Contain("and");
page.Url.Query.Should().NotContain(" & ");
page.Url.Query.Should().NotContain("%26");
}
}
}

View File

@@ -43,7 +43,10 @@ namespace NzbDrone.Core.Test.Languages
new object[] { 28, Language.Thai },
new object[] { 29, Language.Bulgarian },
new object[] { 30, Language.PortugueseBR },
new object[] { 31, Language.Arabic }
new object[] { 31, Language.Arabic },
new object[] { 32, Language.Ukrainian },
new object[] { 33, Language.Persian },
new object[] { 34, Language.Bengali },
};
public static object[] ToIntCases =
@@ -81,7 +84,10 @@ namespace NzbDrone.Core.Test.Languages
new object[] { Language.Thai, 28 },
new object[] { Language.Bulgarian, 29 },
new object[] { Language.PortugueseBR, 30 },
new object[] { Language.Arabic, 31 }
new object[] { Language.Arabic, 31 },
new object[] { Language.Ukrainian, 32 },
new object[] { Language.Persian, 33 },
new object[] { Language.Bengali, 34 },
};
[Test]

View File

@@ -20,6 +20,9 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo.MediaInfoFormatterTests
[TestCase("wmv2, WMV2", "Droned.wmv", "WMV")]
[TestCase("mpeg4, XVID", "", "XviD")]
[TestCase("mpeg4, DIV3", "spsm.dvdrip.divx.avi'.", "DivX")]
[TestCase("msmpeg4, DIV3", "Exit the Dragon, Enter the Tiger (1976) 360p MPEG Audio.avi", "DivX")]
[TestCase("msmpeg4v2, DIV3", "Exit the Dragon, Enter the Tiger (1976) 360p MPEG Audio.avi", "DivX")]
[TestCase("msmpeg4v3, DIV3", "Exit the Dragon, Enter the Tiger (1976) 360p MPEG Audio.avi", "DivX")]
[TestCase("vp6, 4", "Top Gear - S12E01 - Lorries - SD TV.flv", "VP6")]
[TestCase("vp7, VP70", "Sweet Seymour.avi", "VP7")]
[TestCase("vp8, V_VP8", "Dick.mkv", "VP8")]

View File

@@ -78,6 +78,11 @@ namespace NzbDrone.Core.Test.NotificationTests
{
TestLogger.Info("OnHealthIssue was called");
}
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
{
TestLogger.Info("OnApplicationUpdate was called");
}
}
private class TestNotificationWithNoEvents : NotificationBase<TestSetting>
@@ -116,6 +121,7 @@ namespace NzbDrone.Core.Test.NotificationTests
notification.SupportsOnMovieFileDelete.Should().BeTrue();
notification.SupportsOnMovieFileDeleteForUpgrade.Should().BeTrue();
notification.SupportsOnHealthIssue.Should().BeTrue();
notification.SupportsOnApplicationUpdate.Should().BeTrue();
}
[Test]
@@ -131,6 +137,7 @@ namespace NzbDrone.Core.Test.NotificationTests
notification.SupportsOnMovieFileDelete.Should().BeFalse();
notification.SupportsOnMovieFileDeleteForUpgrade.Should().BeFalse();
notification.SupportsOnHealthIssue.Should().BeFalse();
notification.SupportsOnApplicationUpdate.Should().BeFalse();
}
}
}

View File

@@ -51,15 +51,6 @@ namespace NzbDrone.Core.Test.ParserTests
result.Languages.Should().Contain(Language.English);
}
[TestCase("Movie.Title.1982.Ger.Eng.AC3.DL.BDRip.x264-iNCEPTiON")]
public void should_parse_language_english_german(string postTitle)
{
var result = Parser.Parser.ParseMovieTitle(postTitle, true);
result.Languages.Should().Contain(Language.German);
result.Languages.Should().Contain(Language.English);
}
[TestCase("Movie.Title.1994.Spanish.1080p.XviD-LOL")]
[TestCase("Movie Title (2020)[BDRemux AVC 1080p][E-AC3 DD Plus 5.1 Castellano-Inglés Subs]")]
[TestCase("Movie Title (2020) [UHDRemux2160p HDR][DTS-HD MA 5.1 AC3 5.1 Castellano - True-HD 7.1 Atmos Inglés Subs]")]
@@ -72,6 +63,7 @@ namespace NzbDrone.Core.Test.ParserTests
}
[TestCase("Movie.Title.1994.German.1080p.XviD-LOL")]
[TestCase("Movie.Title.2016.Ger.Dub.AAC.1080p.WebDL.x264-TKP21")]
public void should_parse_language_german(string postTitle)
{
var result = Parser.Parser.ParseMovieTitle(postTitle, true);
@@ -161,6 +153,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Movie.Title.1994.Bulgarian.1080p.XviD-LOL")]
[TestCase("Movie.Title.1994.BGAUDIO.1080p.XviD-LOL")]
[TestCase("Movie.Title.1994.BG.AUDIO.1080p.XviD-LOL")]
public void should_parse_language_bulgarian(string postTitle)
{
var result = Parser.Parser.ParseMovieTitle(postTitle, true);
@@ -314,6 +307,40 @@ namespace NzbDrone.Core.Test.ParserTests
result.Languages.Should().BeEquivalentTo(Language.Arabic);
}
[TestCase("Movie.Title [1989, BDRip] MVO + DVO + UKR (MVO) + Sub")]
[TestCase("Movie.Title (2006) BDRemux 1080p 2xUkr | Sub Ukr")]
[TestCase("Movie.Title [1984, BDRip 720p] MVO + MVO + Dub + AVO + 3xUkr")]
[TestCase("Movie.Title.2019.UKRAINIAN.WEBRip.x264-VXT")]
public void should_parse_language_ukrainian(string postTitle)
{
var result = Parser.Parser.ParseMovieTitle(postTitle, true);
result.Languages.Should().BeEquivalentTo(Language.Ukrainian);
}
[TestCase("Movie.Title [1937, BDRip 1080p] Dub UKR/Eng + Sub rus")]
[TestCase("Movie.Title.[2003.BDRemux.1080p].Dub.MVO.(2xUkr/Fra).Sub.(Rus/Fra)")]
public void should_parse_language_ukrainian_multi(string postTitle)
{
var result = Parser.Parser.ParseMovieTitle(postTitle, true);
result.Languages.Should().Contain(Language.Ukrainian);
}
[TestCase("Movie.Title.2019.PERSIAN.WEBRip.x264-VXT")]
public void should_parse_language_persian(string postTitle)
{
var result = Parser.Parser.ParseMovieTitle(postTitle);
result.Languages.Should().BeEquivalentTo(Language.Persian);
}
[TestCase("Movie.Title.2019.BENGALI.WEBRip.x264-VXT")]
public void should_parse_language_bengali(string postTitle)
{
var result = Parser.Parser.ParseMovieTitle(postTitle);
result.Languages.Should().BeEquivalentTo(Language.Bengali);
}
[TestCase("Movie.Title.en.sub")]
[TestCase("Movie Title.eng.sub")]
[TestCase("Movie.Title.eng.forced.sub")]

View File

@@ -23,6 +23,7 @@ namespace NzbDrone.Core.Test.ParserTests
* Superman.-.The.Man.of.Steel.1994-06.34.hybrid.DreamGirl-Novus-HD
* Superman.-.The.Man.of.Steel.1994-05.33.hybrid.DreamGirl-Novus-HD
* Constantine S1-E1-WEB-DL-1080p-NZBgeek
* [TestCase("Valana la Movie FRENCH BluRay 720p 2016 kjhlj", "Valana la Movie")] Removed 2021-12-19 as this / the regex for this was breaking all movies w/ french in title
*/
[Test]
@@ -49,7 +50,6 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Movie.The.Final.Chapter.2016", "Movie The Final Chapter")]
[TestCase("Der.Movie.James.German.Bluray.FuckYou.Pso.Why.cant.you.follow.scene.rules.1998", "Der Movie James")]
[TestCase("Movie.German.DL.AC3.Dubbed..BluRay.x264-PsO", "Movie")]
[TestCase("Valana la Movie FRENCH BluRay 720p 2016 kjhlj", "Valana la Movie")]
[TestCase("Valana la Movie TRUEFRENCH BluRay 720p 2016 kjhlj", "Valana la Movie")]
[TestCase("Mission Movie: Rogue Movie (2015)<29>[XviD - Ita Ac3 - SoftSub Ita]azione, spionaggio, thriller *Prima Visione* Team mulnic Tom Cruise", "Mission Movie Rogue Movie")]
[TestCase("Movie.Movie.2000.FRENCH..BluRay.-AiRLiNE", "Movie Movie")]
@@ -61,6 +61,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("World.Movie.Z.2.EXTENDED.2013.German.DL.1080p.BluRay.AVC-XANOR", "World Movie Z 2")]
[TestCase("G.I.Movie.Movie.2013.THEATRiCAL.COMPLETE.BLURAY-GLiMMER", "G.I. Movie Movie")]
[TestCase("www.Torrenting.org - Movie.2008.720p.X264-DIMENSION", "Movie")]
[TestCase("The.French.Movie.2013.720p.BluRay.x264 - ROUGH[PublicHD]", "The French Movie")]
public void should_parse_movie_title(string postTitle, string title)
{
Parser.Parser.ParseMovieTitle(postTitle).PrimaryMovieTitle.Should().Be(title);
@@ -199,6 +200,7 @@ namespace NzbDrone.Core.Test.ParserTests
}
[TestCase("The.Italian.Movie.2025.720p.BluRay.X264-AMIABLE")]
[TestCase("The.French.Movie.2013.720p.BluRay.x264 - ROUGH[PublicHD]")]
public void should_not_parse_wrong_language_in_title(string postTitle)
{
var parsed = Parser.Parser.ParseMovieTitle(postTitle, true);

View File

@@ -119,6 +119,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Movie.Name.S01E08.Tourmaline.Nepal.720p.HDTV.x264-DHD", false)]
[TestCase("Movie.Name.US.S12E17.HR.WS.PDTV.X264-DIMENSION", false)]
[TestCase("Movie.Name.The.Lost.Pilots.Movie.HR.WS.PDTV.x264-DHD", false)]
[TestCase("Movie.Name.The.Lost.Pilots.Movie.HR.WS.PDTV.x264-DHD-Remux.mkv", false)]
public void should_parse_hdtv720p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.TV, proper, Resolution.R720p);
@@ -186,6 +187,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("[HorribleSubs] Movie Title! 2018 [Web][MKV][h264][1080p][AAC 2.0][Softsubs (HorribleSubs)]", false)]
[TestCase("Movie.Title.2020.MULTi.1080p.WEB.H264-ALLDAYiN (S:285/L:11)", false)]
[TestCase("Movie Title (2020) MULTi WEB 1080p x264-JiHEFF (S:317/L:28)", false)]
[TestCase("Movie.Titles.2020.1080p.NF.WEB.DD2.0.x264-SNEAkY", false)]
public void should_parse_webdl1080p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.WEBDL, proper, Resolution.R1080p);
@@ -256,6 +258,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Movie Name 2005 1080p UHD BluRay DD+7.1 x264-LoRD.mkv", false)]
[TestCase("Movie.Name.2011.1080p.UHD.BluRay.DD5.1.HDR.x265-CtrlHD.mkv", false)]
[TestCase("Movie.Name.2016.German.DTS.DL.1080p.UHDBD.x265-TDO.mkv", false)]
[TestCase("Movie.Name.2021.1080p.BDLight.x265-AVCDVD", false)]
public void should_parse_bluray1080p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.BLURAY, proper, Resolution.R1080p);
@@ -272,6 +275,8 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Movie.Title.2019.2160p.MBLURAY.x264-MBLURAYFANS.mkv", false)]
[TestCase("Movie.Title.2017.2160p.MBluRay.x264-TREBLE.mkv", false)]
[TestCase("Movie.Name.2020.German.UHDBD.2160p.HDR10.HEVC.EAC3.DL-pmHD.mkv", false)]
[TestCase("Movie.Title.2014.2160p.UHD.BluRay.X265-IAMABLE.mkv", false)]
[TestCase("Movie.Title.2014.2160p.BDRip.AAC.7.1.HDR10.x265.10bit-Markll", false)]
public void should_parse_bluray2160p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.BLURAY, proper, Resolution.R2160p);
@@ -425,6 +430,8 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Movie.Title.2016.1080p.KORSUBS.WEBRip.x264.AAC2.0-RADARR", "KORSUBS")]
[TestCase("Movie Title 2017 HC 720p HDRiP DD5 1 x264-LEGi0N", "Generic Hardcoded Subs")]
[TestCase("Movie.Title.2017.720p.SUBBED.HDRip.V2.XViD-26k.avi", "Generic Hardcoded Subs")]
[TestCase("Movie Title! 2018 [Web][MKV][h264][480p][AAC 2.0][Softsubs]", null)]
[TestCase("Movie Title! 2019 [HorribleSubs][Web][MKV][h264][848x480][AAC 2.0][Softsubs(HorribleSubs)]", null)]
public void should_parse_hardcoded_subs(string postTitle, string sub)
{
QualityParser.ParseQuality(postTitle).HardcodedSubs.Should().Be(sub);

View File

@@ -27,7 +27,6 @@ namespace NzbDrone.Core.Test.UpdateTests
[Test]
public void finds_update_when_version_lower()
{
NotBsd();
UseRealHttp();
Subject.GetLatestUpdate("develop", new Version(3, 0)).Should().NotBeNull();
}
@@ -43,8 +42,6 @@ namespace NzbDrone.Core.Test.UpdateTests
[Test]
public void should_get_recent_updates()
{
NotBsd();
const string branch = "nightly";
UseRealHttp();
var recent = Subject.GetRecentUpdates(branch, new Version(3, 0), null);

View File

@@ -17,6 +17,7 @@ namespace NzbDrone.Core.Datastore
IEnumerable<TModel> All();
int Count();
TModel Get(int id);
TModel Find(int id);
TModel Insert(TModel model);
TModel Update(TModel model);
TModel Upsert(TModel model);
@@ -99,6 +100,13 @@ namespace NzbDrone.Core.Datastore
return model;
}
public TModel Find(int id)
{
var model = Query(c => c.Id == id).SingleOrDefault();
return model;
}
public IEnumerable<TModel> Get(IEnumerable<int> ids)
{
if (!ids.Any())

View File

@@ -1,4 +1,4 @@
using FluentMigrator;
using FluentMigrator;
//using FluentMigrator.Expressions;
using NzbDrone.Core.Datastore.Migration.Framework;
@@ -13,12 +13,12 @@ namespace NzbDrone.Core.Datastore.Migration
{
if (!Schema.Schema("dbo").Table("NetImport").Column("MinimumAvailability").Exists())
{
Alter.Table("NetImport").AddColumn("MinimumAvailability").AsInt32().WithDefaultValue(MovieStatusType.PreDB);
Alter.Table("NetImport").AddColumn("MinimumAvailability").AsInt32().WithDefaultValue(MovieStatusType.Released);
}
if (!Schema.Schema("dbo").Table("Movies").Column("MinimumAvailability").Exists())
{
Alter.Table("Movies").AddColumn("MinimumAvailability").AsInt32().WithDefaultValue(MovieStatusType.PreDB);
Alter.Table("Movies").AddColumn("MinimumAvailability").AsInt32().WithDefaultValue(MovieStatusType.Released);
}
}
}

View File

@@ -47,7 +47,7 @@ namespace NzbDrone.Core.Datastore.Migration
//Manual SQL, Fluent Migrator doesn't support multi-column unique contraint on table creation, SQLite doesn't support adding it after creation
Execute.Sql("CREATE TABLE MovieTranslations(" +
"Id INTEGER PRIMARY KEY, " +
"Id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +
"MovieId INTEGER NOT NULL, " +
"Title TEXT, " +
"CleanTitle TEXT, " +

View File

@@ -0,0 +1,101 @@
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Dapper;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(201)]
public class migrate_discord_from_slack : NzbDroneMigrationBase
{
private readonly JsonSerializerOptions _serializerSettings;
public migrate_discord_from_slack()
{
_serializerSettings = new JsonSerializerOptions
{
AllowTrailingCommas = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
PropertyNameCaseInsensitive = true,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
_serializerSettings.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase, true));
}
protected override void MainDbUpgrade()
{
Execute.WithConnection(MigrateDiscordFromSlack);
}
private void MigrateDiscordFromSlack(IDbConnection conn, IDbTransaction tran)
{
var notificationRows = conn.Query<NotificationEntity201>($"SELECT Id,ConfigContract,Implementation,Name,Settings FROM Notifications WHERE Implementation = 'Slack'");
var discordSlackNotifications = notificationRows.Where(n => JsonSerializer.Deserialize<SlackNotificationSettings201>(n.Settings, _serializerSettings).WebHookUrl.Contains("discord"));
if (!discordSlackNotifications.Any())
{
return;
}
foreach (NotificationEntity201 notification in discordSlackNotifications)
{
SlackNotificationSettings201 settings = JsonSerializer.Deserialize<SlackNotificationSettings201>(notification.Settings, _serializerSettings);
DiscordNotificationSettings201 discordSettings = new DiscordNotificationSettings201
{
Avatar = settings.Icon,
GrabFields = new List<int> { 0, 1, 2, 3, 5, 6, 7, 8, 9 },
ImportFields = new List<int> { 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12 },
Username = settings.Username,
WebHookUrl = settings.WebHookUrl.Replace("/slack", "")
};
notification.ConfigContract = "DiscordSettings";
notification.Implementation = "Discord";
notification.Name = $"{notification.Name}-Slack_Migrated";
notification.Settings = JsonSerializer.Serialize(discordSettings, _serializerSettings);
}
var updateSql = "UPDATE Notifications SET ConfigContract = @ConfigContract, " +
"Implementation = @Implementation, " +
"Name = @Name, " +
"Settings = @Settings " +
"WHERE Id = @Id";
conn.Execute(updateSql, discordSlackNotifications, transaction: tran);
}
}
public class NotificationEntity201
{
public int Id { get; set; }
public string ConfigContract { get; set; }
public string Implementation { get; set; }
public string Name { get; set; }
public string Settings { get; set; }
}
public class SlackNotificationSettings201
{
public string Channel { get; set; }
public string Icon { get; set; }
public string Username { get; set; }
public string WebHookUrl { get; set; }
}
public class DiscordNotificationSettings201
{
public string Avatar { get; set; }
public string Username { get; set; }
public string WebHookUrl { get; set; }
public IEnumerable<int> GrabFields { get; set; }
public IEnumerable<int> ImportFields { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(202)]
public class remove_predb : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
//Set PreDb entries to Released
Update.Table("Movies").Set(new { MinimumAvailability = 3 }).Where(new { MinimumAvailability = 4 });
Update.Table("ImportLists").Set(new { MinimumAvailability = 3 }).Where(new { MinimumAvailability = 4 });
//Should never be set, but just in case
Update.Table("Movies").Set(new { Status = 3 }).Where(new { Status = 4 });
Update.Table("ImportListMovies").Set(new { Status = 3 }).Where(new { Status = 4 });
//Remove unused column
Delete.Column("HasPreDBEntry").FromTable("Movies");
}
}
}

View File

@@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(203)]
public class add_on_update_to_notifications : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Notifications").AddColumn("OnApplicationUpdate").AsBoolean().WithDefaultValue(0);
}
}
}

View File

@@ -0,0 +1,27 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(204)]
public class ensure_identity_on_id_columns : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
//Purge Commands before reworking tables
Delete.FromTable("Commands").AllRows();
Alter.Column("Id").OnTable("Movies").AsInt32().PrimaryKey().Identity();
Alter.Column("Id").OnTable("MovieTranslations").AsInt32().PrimaryKey().Identity();
Alter.Column("Id").OnTable("Commands").AsInt32().PrimaryKey().Identity();
Alter.Column("Id").OnTable("Credits").AsInt32().PrimaryKey().Identity();
Alter.Column("Id").OnTable("Profiles").AsInt32().PrimaryKey().Identity();
Alter.Column("Id").OnTable("PendingReleases").AsInt32().PrimaryKey().Identity();
Alter.Column("Id").OnTable("NamingConfig").AsInt32().PrimaryKey().Identity();
Alter.Column("Id").OnTable("History").AsInt32().PrimaryKey().Identity();
Alter.Column("Id").OnTable("Blocklist").AsInt32().PrimaryKey().Identity();
Alter.Column("Id").OnTable("MovieFiles").AsInt32().PrimaryKey().Identity();
Alter.Column("Id").OnTable("CustomFormats").AsInt32().PrimaryKey().Identity();
}
}
}

View File

@@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(205)]
public class download_client_per_indexer : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Indexers").AddColumn("DownloadClientId").AsInt32().WithDefaultValue(0);
}
}
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using FluentMigrator.Model;
using FluentMigrator.Runner.Processors.SQLite;
@@ -66,6 +67,24 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
if (columnReader.Read() == SqliteSyntaxReader.TokenType.StringToken)
{
if (columnReader.ValueToUpper == "PRIMARY")
{
columnReader.SkipTillToken(SqliteSyntaxReader.TokenType.ListStart);
if (columnReader.Read() == SqliteSyntaxReader.TokenType.Identifier)
{
var pk = table.Columns.First(v => v.Name == columnReader.Value);
pk.IsPrimaryKey = true;
pk.IsNullable = true;
pk.IsUnique = true;
if (columnReader.Buffer.ToUpperInvariant().Contains("AUTOINCREMENT"))
{
pk.IsIdentity = true;
}
continue;
}
}
if (columnReader.ValueToUpper == "CONSTRAINT" ||
columnReader.ValueToUpper == "PRIMARY" || columnReader.ValueToUpper == "UNIQUE" ||
columnReader.ValueToUpper == "CHECK" || columnReader.ValueToUpper == "FOREIGN")

View File

@@ -89,7 +89,8 @@ namespace NzbDrone.Core.Datastore
.Ignore(i => i.SupportsOnMovieDelete)
.Ignore(i => i.SupportsOnMovieFileDelete)
.Ignore(i => i.SupportsOnMovieFileDeleteForUpgrade)
.Ignore(i => i.SupportsOnHealthIssue);
.Ignore(i => i.SupportsOnHealthIssue)
.Ignore(i => i.SupportsOnApplicationUpdate);
Mapper.Entity<MetadataDefinition>("Metadata").RegisterModel()
.Ignore(x => x.ImplementationName)

View File

@@ -265,12 +265,12 @@ namespace NzbDrone.Core.Download.Clients.Deluge
case WebExceptionStatus.ConnectionClosed:
return new NzbDroneValidationFailure("UseSsl", "Verify SSL settings")
{
DetailedDescription = "Please verify your SSL configuration on both Deluge and NzbDrone."
DetailedDescription = "Please verify your SSL configuration on both Deluge and Radarr."
};
case WebExceptionStatus.SecureChannelFailure:
return new NzbDroneValidationFailure("UseSsl", "Unable to connect through SSL")
{
DetailedDescription = "Drone is unable to connect to Deluge using SSL. This problem could be computer related. Please try to configure both drone and Deluge to not use SSL."
DetailedDescription = "Drone is unable to connect to Deluge using SSL. This problem could be computer related. Please try to configure both Radarr and Deluge to not use SSL."
};
default:
return new NzbDroneValidationFailure(string.Empty, "Unknown exception: " + ex.Message);

View File

@@ -118,14 +118,17 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
try
{
var serialNumber = _serialNumberProvider.GetSerialNumber(Settings);
var sharedFolder = GetDownloadDirectory() ?? GetDefaultDir();
var outputPath = new OsPath($"/{sharedFolder.TrimStart('/')}");
var path = _sharedFolderResolver.RemapToFullPath(outputPath, Settings, serialNumber);
// Download station returns the path without the leading `/`, but the leading
// slash is required to get the full path back from download station.
var path = new OsPath($"/{GetDownloadDirectory()}");
var fullPath = _sharedFolderResolver.RemapToFullPath(path, Settings, serialNumber);
return new DownloadClientInfo
{
IsLocalhost = Settings.Host == "127.0.0.1" || Settings.Host == "localhost",
OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, path) }
OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, fullPath) }
};
}
catch (DownloadClientException e)

View File

@@ -142,14 +142,17 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
try
{
var serialNumber = _serialNumberProvider.GetSerialNumber(Settings);
var sharedFolder = GetDownloadDirectory() ?? GetDefaultDir();
var outputPath = new OsPath($"/{sharedFolder.TrimStart('/')}");
var path = _sharedFolderResolver.RemapToFullPath(outputPath, Settings, serialNumber);
// Download station returns the path without the leading `/`, but the leading
// slash is required to get the full path back from download station.
var path = new OsPath($"/{GetDownloadDirectory()}");
var fullPath = _sharedFolderResolver.RemapToFullPath(path, Settings, serialNumber);
return new DownloadClientInfo
{
IsLocalhost = Settings.Host == "127.0.0.1" || Settings.Host == "localhost",
OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, path) }
OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, fullPath) }
};
}
catch (DownloadClientException e)

View File

@@ -1,14 +1,15 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.Indexers;
namespace NzbDrone.Core.Download
{
public interface IProvideDownloadClient
{
IDownloadClient GetDownloadClient(DownloadProtocol downloadProtocol);
IDownloadClient GetDownloadClient(DownloadProtocol downloadProtocol, int indexerId = 0);
IEnumerable<IDownloadClient> GetDownloadClients();
IDownloadClient Get(int id);
}
@@ -18,17 +19,23 @@ namespace NzbDrone.Core.Download
private readonly Logger _logger;
private readonly IDownloadClientFactory _downloadClientFactory;
private readonly IDownloadClientStatusService _downloadClientStatusService;
private readonly IIndexerFactory _indexerFactory;
private readonly ICached<int> _lastUsedDownloadClient;
public DownloadClientProvider(IDownloadClientStatusService downloadClientStatusService, IDownloadClientFactory downloadClientFactory, ICacheManager cacheManager, Logger logger)
public DownloadClientProvider(IDownloadClientStatusService downloadClientStatusService,
IDownloadClientFactory downloadClientFactory,
IIndexerFactory indexerFactory,
ICacheManager cacheManager,
Logger logger)
{
_logger = logger;
_downloadClientFactory = downloadClientFactory;
_downloadClientStatusService = downloadClientStatusService;
_indexerFactory = indexerFactory;
_lastUsedDownloadClient = cacheManager.GetCache<int>(GetType(), "lastDownloadClientId");
}
public IDownloadClient GetDownloadClient(DownloadProtocol downloadProtocol)
public IDownloadClient GetDownloadClient(DownloadProtocol downloadProtocol, int indexerId = 0)
{
var availableProviders = _downloadClientFactory.GetAvailableProviders().Where(v => v.Protocol == downloadProtocol).ToList();
@@ -37,6 +44,18 @@ namespace NzbDrone.Core.Download
return null;
}
if (indexerId > 0)
{
var indexer = _indexerFactory.Find(indexerId);
if (indexer != null && indexer.DownloadClientId > 0)
{
var client = availableProviders.SingleOrDefault(d => d.Definition.Id == indexer.DownloadClientId);
return client ?? throw new DownloadClientUnavailableException($"Indexer specified download client is not available");
}
}
var blockedProviders = new HashSet<int>(_downloadClientStatusService.GetBlockedProviders().Select(v => v.ProviderId));
if (blockedProviders.Any())

View File

@@ -50,7 +50,7 @@ namespace NzbDrone.Core.Download
Ensure.That(remoteMovie.Movie, () => remoteMovie.Movie).IsNotNull();
var downloadTitle = remoteMovie.Release.Title;
var downloadClient = _downloadClientProvider.GetDownloadClient(remoteMovie.Release.DownloadProtocol);
var downloadClient = _downloadClientProvider.GetDownloadClient(remoteMovie.Release.DownloadProtocol, remoteMovie.Release.IndexerId);
if (downloadClient == null)
{

View File

@@ -0,0 +1,39 @@
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Notifications;
using NzbDrone.Core.Notifications.Slack;
using NzbDrone.Core.ThingiProvider.Events;
namespace NzbDrone.Core.HealthCheck.Checks
{
[CheckOn(typeof(ProviderUpdatedEvent<INotificationFactory>))]
[CheckOn(typeof(ProviderDeletedEvent<INotificationFactory>))]
[CheckOn(typeof(ProviderStatusChangedEvent<INotificationFactory>))]
public class SlackUrlCheck : HealthCheckBase
{
private readonly INotificationFactory _notificationFactory;
public SlackUrlCheck(INotificationFactory notificationFactory, ILocalizationService localizationService)
: base(localizationService)
{
_notificationFactory = notificationFactory;
}
public override HealthCheck Check()
{
var discordSlackNotifications = _notificationFactory.GetAvailableProviders().Where(n => n.ConfigContract.Equals("SlackSettings") && (n.Definition.Settings as SlackSettings).WebHookUrl.Contains("discord"));
if (discordSlackNotifications.Empty())
{
return new HealthCheck(GetType());
}
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("DiscordUrlInSlackNotification"),
string.Join(", ", discordSlackNotifications.Select(n => n.Name))),
"#discord-as-slack-notification");
}
}
}

View File

@@ -25,6 +25,7 @@ namespace NzbDrone.Core.HealthCheck
private readonly IProvideHealthCheck[] _startupHealthChecks;
private readonly IProvideHealthCheck[] _scheduledHealthChecks;
private readonly Dictionary<Type, IEventDrivenHealthCheck[]> _eventDrivenHealthChecks;
private readonly IServerSideNotificationService _serverSideNotificationService;
private readonly IEventAggregator _eventAggregator;
private readonly ICacheManager _cacheManager;
private readonly Logger _logger;
@@ -32,11 +33,13 @@ namespace NzbDrone.Core.HealthCheck
private readonly ICached<HealthCheck> _healthCheckResults;
public HealthCheckService(IEnumerable<IProvideHealthCheck> healthChecks,
IServerSideNotificationService serverSideNotificationService,
IEventAggregator eventAggregator,
ICacheManager cacheManager,
Logger logger)
{
_healthChecks = healthChecks.ToArray();
_serverSideNotificationService = serverSideNotificationService;
_eventAggregator = eventAggregator;
_cacheManager = cacheManager;
_logger = logger;
@@ -72,6 +75,8 @@ namespace NzbDrone.Core.HealthCheck
var results = healthChecks.Select(c => c.Check())
.ToList();
results.AddRange(_serverSideNotificationService.GetServerChecks());
foreach (var result in results)
{
if (result.Type == HealthCheckResult.Ok)

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using NLog;
using NzbDrone.Common.Cloud;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Core.HealthCheck
{
public interface IServerSideNotificationService
{
public List<HealthCheck> GetServerChecks();
}
public class ServerSideNotificationService : IServerSideNotificationService
{
private readonly IHttpClient _client;
private readonly IConfigFileProvider _configFileProvider;
private readonly IHttpRequestBuilderFactory _cloudRequestBuilder;
private readonly Logger _logger;
public ServerSideNotificationService(IHttpClient client, IConfigFileProvider configFileProvider, IRadarrCloudRequestBuilder cloudRequestBuilder, Logger logger)
{
_client = client;
_configFileProvider = configFileProvider;
_cloudRequestBuilder = cloudRequestBuilder.Services;
_logger = logger;
}
public List<HealthCheck> GetServerChecks()
{
var request = _cloudRequestBuilder.Create()
.Resource("/notification")
.AddQueryParam("version", BuildInfo.Version)
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
.AddQueryParam("arch", RuntimeInformation.OSArchitecture)
.AddQueryParam("runtime", PlatformInfo.Platform.ToString().ToLowerInvariant())
.AddQueryParam("branch", _configFileProvider.Branch)
.Build();
try
{
_logger.Trace("Getting server side health notifications");
var response = _client.Execute(request);
var result = Json.Deserialize<List<ServerNotificationResponse>>(response.Content);
return result.Select(x => new HealthCheck(GetType(), x.Type, x.Message, x.WikiUrl)).ToList();
}
catch (Exception ex)
{
_logger.Error(ex, "Failed to retrieve server notifications");
return new List<HealthCheck>();
}
}
}
public class ServerNotificationResponse
{
public HealthCheckResult Type { get; set; }
public string Message { get; set; }
public string WikiUrl { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Indexers
{
@@ -7,6 +7,7 @@ namespace NzbDrone.Core.Indexers
public bool EnableRss { get; set; }
public bool EnableAutomaticSearch { get; set; }
public bool EnableInteractiveSearch { get; set; }
public int DownloadClientId { get; set; }
public DownloadProtocol Protocol { get; set; }
public bool SupportsRss { get; set; }
public bool SupportsSearch { get; set; }

View File

@@ -204,7 +204,8 @@ namespace NzbDrone.Core.Indexers.Newznab
private static string NewsnabifyTitle(string title)
{
return title.Replace("+", "%20");
var newtitle = title.Replace("+", " ");
return Uri.EscapeDataString(newtitle);
}
public Func<IDictionary<string, string>> GetCookies { get; set; }

View File

@@ -60,7 +60,7 @@ namespace NzbDrone.Core.Indexers.Nyaa
{
var pageableRequests = new IndexerPageableRequestChain();
foreach (var queryTitle in searchCriteria.CleanSceneTitles)
foreach (var queryTitle in searchCriteria.SceneTitles)
{
pageableRequests.Add(GetPagedRequests(MaxPages, PrepareQuery(string.Format("{0} {1}", queryTitle, searchCriteria.Movie.Year))));
}

View File

@@ -102,6 +102,9 @@ namespace NzbDrone.Core.Languages
public static Language Bulgarian => new Language(29, "Bulgarian");
public static Language PortugueseBR => new Language(30, "Portuguese (Brazil)");
public static Language Arabic => new Language(31, "Arabic");
public static Language Ukrainian => new Language(32, "Unkrainian");
public static Language Persian => new Language(33, "Persian");
public static Language Bengali => new Language(34, "Bengali");
public static Language Any => new Language(-1, "Any");
public static Language Original => new Language(-2, "Original");
@@ -143,6 +146,9 @@ namespace NzbDrone.Core.Languages
Bulgarian,
PortugueseBR,
Arabic,
Ukrainian,
Persian,
Bengali,
Any,
Original
};

View File

@@ -1017,7 +1017,7 @@
"Agenda": "جدول أعمال",
"Age": "عمر",
"AfterManualRefresh": "بعد التحديث اليدوي",
"AddToDownloadQueue": "تمت الإضافة إلى قائمة انتظار التنزيل",
"AddToDownloadQueue": "إضافة إلى قائمة انتظار التنزيل",
"AddRootFolder": "إضافة مجلد جذر",
"AddRestriction": "إضافة القيد",
"AddRemotePathMapping": "إضافة تعيين المسار البعيد",
@@ -1047,7 +1047,7 @@
"AddIndexer": "أضف مفهرس",
"AddImportExclusionHelpText": "منع إضافة الفيلم إلى Radarr بواسطة القوائم",
"AddExclusion": "أضف استثناء",
"AddedToDownloadQueue": "تمت الإضافة إلى قائمة الانتظار التي تم تنزيلها",
"AddedToDownloadQueue": "تمت الإضافة إلى قائمة انتظار التنزيلات",
"Added": "مضاف",
"AddDownloadClient": "إضافة وكيل التحميل",
"AddDelayProfile": "إضافة ملف تعريف تأخير",

View File

@@ -0,0 +1 @@
{}

View File

@@ -529,7 +529,7 @@
"ShowTitleHelpText": "Filmtitel unter dem Plakat anzeigen",
"ShowUnknownMovieItems": "Unzugeordente Filmeinträge anzeigen",
"SkipFreeSpaceCheck": "Pürfung des freien Speichers überspringen",
"SkipFreeSpaceCheckWhenImportingHelpText": "Aktiviere dies wenn es nicht möglich ist, den freien Speicherplatz vom Stammverzeichnis zu ermitteln",
"SkipFreeSpaceCheckWhenImportingHelpText": "Aktiviere dies, wenn es nicht möglich ist, den freien Speicherplatz vom Stammverzeichnis zu ermitteln",
"SorryThatMovieCannotBeFound": "Schade, dieser Film kann nicht gefunden werden.",
"SourcePath": "Quellpfad",
"SourceRelativePath": "Relativer Quellpfad",
@@ -544,7 +544,7 @@
"TestAllIndexers": "Alle testen",
"TestAllLists": "Alle testen",
"TimeFormat": "Zeitformat",
"UpdateMechanismHelpText": "Benutze den Built-In Updater oder ein Script",
"UpdateMechanismHelpText": "Benutze den Build-In Updater oder ein Script",
"UpdateScriptPathHelpText": "Pfad zu einem benutzerdefinierten Skript, das ein extrahiertes Update-Paket übernimmt und den Rest des Update-Prozesses abwickelt",
"UpgradeAllowedHelpText": "Wenn deaktiviert wird die Qualität nicht verbessert",
"Uptime": "Laufzeit",
@@ -954,7 +954,7 @@
"Months": "Monate",
"MonitoredStatus": "Beobachtet/Status",
"Monday": "Montag",
"MissingFromDisk": "Radarr konnte die Datei nicht auf der Festplatte finden, deshalb wurde es gelöscht",
"MissingFromDisk": "Radarr konnte die Datei nicht auf der Festplatte finden, daher wurde die Datei aus der Datenbank entfernt",
"Minutes": "Minuten",
"MinimumCustomFormatScore": "Minimum der eigenen Formate Bewertungspunkte",
"Min": "Min.",
@@ -1037,7 +1037,7 @@
"AllMoviesInPathHaveBeenImported": "Alle Filme in {0} wurden importiert",
"AllFiles": "Alle Dateien",
"AfterManualRefresh": "Nach manuellen aktualisieren",
"AddToDownloadQueue": "Zur Downloadwarteschlange hinzugefügt",
"AddToDownloadQueue": "Zur Downloadwarteschlange hinzufügen",
"AddRootFolder": "Stammordner hinzufügen",
"AddQualityProfile": "Qualitätsprofil hinzufügen",
"AddNotification": "Benachrichtigung hinzufügen",

View File

@@ -38,7 +38,6 @@
"AllMoviesInPathHaveBeenImported": "All movies in {0} have been imported",
"AllowHardcodedSubs": "Allow Hardcoded Subs",
"AllowHardcodedSubsHelpText": "Detected hardcoded subs will be automatically downloaded",
"AllowMovieChangeClickToChangeMovie": "Click to change movie",
"AllResultsHiddenFilter": "All results are hidden by the applied filter",
"AlreadyInYourLibrary": "Already in your library",
"AlternativeTitle": "Alternative Title",
@@ -46,8 +45,8 @@
"AnalyseVideoFiles": "Analyze video files",
"Analytics": "Analytics",
"AnalyticsEnabledHelpText": "Send anonymous usage and error information to Radarr's servers. This includes information on your browser, which Radarr WebUI pages you use, error reporting as well as OS and runtime version. We will use this information to prioritize features and bug fixes.",
"AnnoucedMsg": "Movie is announced",
"Announced": "Announced",
"AnnouncedMsg": "Movie is announced",
"ApiKey": "API Key",
"AppDataDirectory": "AppData directory",
"AppDataLocationHealthCheckMessage": "Updating will not be possible to prevent deleting AppData on Update",
@@ -128,6 +127,7 @@
"ClickToChangeLanguage": "Click to change language",
"ClickToChangeMovie": "Click to change movie",
"ClickToChangeQuality": "Click to change quality",
"ClickToChangeReleaseGroup": "Click to change release group",
"ClientPriority": "Client Priority",
"CloneCustomFormat": "Clone Custom Format",
"CloneFormatTag": "Clone Format Tag",
@@ -226,10 +226,10 @@
"DetailedProgressBar": "Detailed Progress Bar",
"DetailedProgressBarHelpText": "Show text on progress bar",
"Details": "Details",
"Digital": "Digital",
"DigitalRelease": "Digital Release",
"Disabled": "Disabled",
"Discord": "Discord",
"DiscordUrlInSlackNotification": "You have a Discord notification setup as a Slack notification. Set this up as a Discord notification for better functionality. The effected notifications are: {0}",
"Discover": "Discover",
"DiskSpace": "Disk Space",
"Docker": "Docker",
@@ -238,8 +238,6 @@
"DoneEditingGroups": "Done Editing Groups",
"DoNotPrefer": "Do Not Prefer",
"DoNotUpgradeAutomatically": "Do not Upgrade Automatically",
"DotNetVersionCheckNotRecommendedMessage": "Currently installed .Net Framework {0} is supported but we recommend upgrading to at least {1}.",
"DotNetVersionCheckOldUnsupportedMessage": "Currently installed .Net Framework {0} is old and unsupported. Please upgrade the .Net Framework to at least {1}.",
"Download": "Download",
"DownloadClient": "Download Client",
"DownloadClientCheckDownloadingToRoot": "Download client {0} places downloads in the root folder {1}. You should not download to a root folder.",
@@ -303,7 +301,6 @@
"ErrorRestoringBackup": "Error restoring backup",
"Events": "Events",
"EventType": "Event Type",
"Example": "Example",
"Exception": "Exception",
"Excluded": "Excluded",
"ExcludeMovie": "Exclude Movie",
@@ -328,11 +325,11 @@
"FileNames": "File Names",
"FileNameTokens": "File Name Tokens",
"Files": "Files",
"Filesize": "Filesize",
"FileWasDeletedByUpgrade": "File was deleted to import an upgrade",
"FileWasDeletedByViaUI": "File was deleted via the UI",
"Filter": "Filter",
"FilterPlaceHolder": "Search movies",
"Filters": "Filters",
"FirstDayOfWeek": "First Day of Week",
"Fixed": "Fixed",
"FocusSearchBox": "Focus Search Box",
@@ -420,6 +417,7 @@
"IncludeUnknownMovieItemsHelpText": "Show items without a movie in the queue. This could include removed movies or anything else in Radarr's category",
"IncludeUnmonitored": "Include Unmonitored",
"Indexer": "Indexer",
"IndexerDownloadClientHelpText": "Specify which download client is used for grabs from this indexer",
"IndexerFlags": "Indexer Flags",
"IndexerLongTermStatusCheckAllClientMessage": "All indexers are unavailable due to failures for more than 6 hours",
"IndexerLongTermStatusCheckSingleClientMessage": "Indexers unavailable due to failures for more than 6 hours: {0}",
@@ -472,9 +470,9 @@
"LoadingMovieExtraFilesFailed": "Loading movie extra files failed",
"LoadingMovieFilesFailed": "Loading movie files failed",
"Local": "Local",
"LocalPath": "Local Path",
"Location": "Location",
"LogFiles": "Log Files",
"LogFilesLocationMessage": "Log files are located in:",
"Logging": "Logging",
"LogLevel": "Log Level",
"LogLevelTraceHelpTextWarning": "Trace logging should only be enabled temporarily",
@@ -489,6 +487,7 @@
"ManualImportSelectLanguage": "Manual Import - Select Language",
"ManualImportSelectMovie": "Manual Import - Select Movie",
"ManualImportSelectQuality": " Manual Import - Select Quality",
"ManualImportSetReleaseGroup": "Manual Import - Set Release Group",
"MappedDrivesRunningAsService": "Mapped network drives are not available when running as a Windows Service. Please see the FAQ for more information",
"MarkAsFailed": "Mark as Failed",
"MarkAsFailedMessageText": "Are you sure you want to mark '{0}' as failed?",
@@ -499,7 +498,6 @@
"MaximumSizeHelpText": "Maximum size for a release to be grabbed in MB. Set to zero to set to unlimited",
"Mechanism": "Mechanism",
"MediaInfo": "Media Info",
"MediaInfoDllCheckMessage": "MediaInfo Library could not be loaded {0}",
"MediaManagement": "Media Management",
"MediaManagementSettings": "Media Management Settings",
"MediaManagementSettingsSummary": "Naming and file management settings",
@@ -525,7 +523,7 @@
"MinutesNinety": "90 Minutes: {0}",
"MinutesSixty": "60 Minutes: {0}",
"Missing": "Missing",
"MissingFromDisk": "Radarr was unable to find the file on disk so it was removed",
"MissingFromDisk": "Radarr was unable to find the file on disk so the file was unlinked from the movie in the database",
"MissingMonitoredAndConsideredAvailable": "Missing (Monitored)",
"MissingNotMonitored": "Missing (Unmonitored)",
"Mode": "Mode",
@@ -536,14 +534,6 @@
"MonitoredOnly": "Monitored Only",
"MonitoredStatus": "Monitored/Status",
"MonitorMovie": "Monitor Movie",
"MonoBSDSupportCheckMessage": "The operating system {0} will not be supported in the next release of Radarr.",
"MonoNotNetCoreCheckMessage": "Please upgrade to the .NET Core version of Radarr, Mono versions will not be supported in the next release.",
"MonoTlsCheckMessage": "Radarr Mono 4.x tls workaround still enabled, consider removing MONO_TLS_PROVIDER=legacy environment option",
"MonoVersion": "Mono Version",
"MonoVersionCheckNotSupportedMessage": "Currently installed Mono version {0} is no longer supported. Please upgrade Mono to version {1}.",
"MonoVersionCheckOldNotSupportedMessage": "Currently installed Mono version {0} is old and unsupported. Please upgrade Mono to version {1}.",
"MonoVersionCheckUpgradeRecommendedMessage": "Currently installed Mono version {0} is supported but upgrading to {1} is recommended.",
"Monox86SupportCheckMessage": "The current operating system is 32 bit, this will not be supported in the next release of Radarr.",
"Month": "Month",
"Months": "Months",
"More": "More",
@@ -556,7 +546,6 @@
"MoveFolders2": "Would you like to move the movie files from '{0}' to '{1}' ?",
"Movie": "Movie",
"MovieAlreadyExcluded": "Movie already Excluded",
"MovieAvailableButMissing": "Movie Available, but Missing",
"MovieChat": "Movie Chat",
"MovieDetailsNextMovie": "Movie Details: Next Movie",
"MovieDetailsPreviousMovie": "Movie Details: Previous Movie",
@@ -565,7 +554,6 @@
"MovieFiles": "Movie Files",
"MovieFilesTotaling": "Movie Files Totaling",
"MovieFolderFormat": "Movie Folder Format",
"MovieHasntReleasedYet": "Movie hasn't released yet",
"MovieID": "Movie ID",
"MovieIndex": "Movie Index",
"MovieIndexScrollBottom": "Movie Index: Scroll Bottom",
@@ -585,7 +573,6 @@
"MoviesSelectedInterp": "{0} Movie(s) Selected",
"MovieTitle": "Movie Title",
"MovieTitleHelpText": "The title of the movie to exclude (can be anything meaningful)",
"MovieWasDownloadedAndSorted": "Movie was downloaded and sorted",
"MovieYear": "Movie Year",
"MovieYearHelpText": "The year of the movie to exclude",
"MultiLanguage": "Multi-Language",
@@ -604,7 +591,6 @@
"NoBackupsAreAvailable": "No backups are available",
"NoChange": "No Change",
"NoChanges": "No Changes",
"NoCinemaRelease": "No Cinema Release",
"NoEventsFound": "No events found",
"NoHistory": "No history",
"NoLeaveIt": "No, Leave It",
@@ -627,6 +613,8 @@
"NoVideoFilesFoundSelectedFolder": "No video files were found in the selected folder",
"OAuthPopupMessage": "Pop-ups are being blocked by your browser",
"Ok": "Ok",
"OnApplicationUpdate": "On Application Update",
"OnApplicationUpdateHelpText": "On Application Update",
"OnDownloadHelpText": "On Import",
"OnGrab": "On Grab",
"OnGrabHelpText": "On Grab",
@@ -727,7 +715,6 @@
"Queued": "Queued",
"QueueIsEmpty": "Queue is empty",
"QuickImport": "Move Automatically",
"Radarr": "Radarr",
"RadarrCalendarFeed": "Radarr Calendar Feed",
"RadarrSupportsAnyDownloadClient": "Radarr supports many popular torrent and usenet download clients.",
"RadarrSupportsAnyIndexer": "Radarr supports any indexer that uses the Newznab standard, as well as other indexers listed below.",
@@ -758,7 +745,6 @@
"RelativePath": "Relative Path",
"ReleaseBranchCheckOfficialBranchMessage": "Branch {0} is not a valid Radarr release branch, you will not receive updates",
"Released": "Released",
"ReleaseDate": "Release Date",
"ReleaseDates": "Release Dates",
"ReleasedMsg": "Movie is released",
"ReleaseGroup": "Release Group",
@@ -767,8 +753,8 @@
"ReleaseTitle": "Release Title",
"ReleaseWillBeProcessedInterp": "Release will be processed {0}",
"Reload": "Reload",
"RemotePath": "Remote Path",
"RemotePathMappingCheckBadDockerPath": "You are using docker; download client {0} places downloads in {1} but this is not a valid {2} path. Review your remote path mappings and download client settings.",
"RemotePathMappingCheckDockerFilesMissing": "You are using docker; download client {0} reported files in {1} but this directory does not appear to exist inside the container. Review your remote path mappings and container volume settings.",
"RemotePathMappingCheckDockerFolderMissing": "You are using docker; download client {0} places downloads in {1} but this directory does not appear to exist inside the container. Review your remote path mappings and container volume settings.",
"RemotePathMappingCheckDownloadPermissions": "Radarr can see but not access downloaded movie {0}. Likely permissions error.",
"RemotePathMappingCheckFileRemoved": "File {0} was removed part way through processing.",
@@ -874,13 +860,15 @@
"SelectDotDot": "Select...",
"SelectFolder": "Select Folder",
"SelectLanguage": "Select Language",
"SelectLanguges": "Select Languages",
"SelectLanguages": "Select Languages",
"SelectMovie": "Select Movie",
"SelectQuality": "Select Quality",
"SelectReleaseGroup": "Select Release Group",
"SendAnonymousUsageData": "Send Anonymous Usage Data",
"SetPermissions": "Set Permissions",
"SetPermissionsLinuxHelpText": "Should chmod be run when files are imported/renamed?",
"SetPermissionsLinuxHelpTextWarning": "If you're unsure what these settings do, do not alter them.",
"SetReleaseGroup": "Set Release Group",
"SetTags": "Set Tags",
"Settings": "Settings",
"SettingsEnableColorImpairedMode": "Enable Color-Impaired Mode",
@@ -929,6 +917,7 @@
"ShowYear": "Show Year",
"Shutdown": "Shutdown",
"Size": "Size",
"SizeLimit": "Size Limit",
"SizeOnDisk": "Size on Disk",
"SkipFreeSpaceCheck": "Skip Free Space Check",
"SkipFreeSpaceCheckWhenImportingHelpText": "Use when Radarr is unable to detect free space from your movie root folder",
@@ -1112,4 +1101,4 @@
"YesMoveFiles": "Yes, Move the Files",
"Yesterday": "Yesterday",
"YouCanAlsoSearch": "You can also search using TMDb ID or IMDb ID of a movie. e.g. `tmdb:71663`"
}
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -163,7 +163,7 @@
"AddNotification": "Lisää ilmoitus",
"AddQualityProfile": "Lisää laatuprofiili",
"AddRootFolder": "Lisää juurikansio",
"AddToDownloadQueue": "Lisätty latausjonoon",
"AddToDownloadQueue": "Lisää latausjonoon",
"AfterManualRefresh": "Manuaalisen päivityksen jälkeen",
"AllFiles": "Kaikki tiedostot",
"AllMoviesInPathHaveBeenImported": "Kaikki kansion '{0}' elokuvat on tuotu",
@@ -222,7 +222,7 @@
"MinimumFreeSpace": "Vapaan tallennustilan vähimmäismäärä",
"MinimumLimits": "Vähimmäismäärät",
"Minutes": "Minuuttia",
"MissingFromDisk": "Radarr ei löytänyt tiedostoa levyltä, joten se poistettiin",
"MissingFromDisk": "Radarr ei löytänyt tiedostoa levyltä, joten sen kytkös kirjaston elokuvaan poistettiin",
"Monday": "maanantai",
"MonoVersion": "Mono-versio",
"MonoVersionCheckNotSupportedMessage": "Tällä hetkellä asennettua mono-versiota {0} ei enää tueta. Päivitä Mono versioon {1}.",
@@ -883,12 +883,12 @@
"ShowDateAdded": "Näytä lisäyspäivä",
"ShowMonitored": "Näytä valvonta",
"ShowPath": "Näytä sijainti",
"ShowMonitoredHelpText": "Näytä elokuvan valvontatila julisteen alla.",
"ShowMonitoredHelpText": "Näytä valvontatila julisteen alla.",
"ShowMovieInformation": "Näytä elokuvan tiedot",
"ShowMovieInformationHelpText": "Näytä elokuvien lajutyypit ja ikäluokitukset.",
"ShownClickToHide": "Näkyvissä, piilota painamalla",
"ShowQualityProfile": "Näytä laatuprofiili",
"ShowQualityProfileHelpText": "Näytä elokuvan laatuprofiili julisteen alla.",
"ShowQualityProfileHelpText": "Näytä laatuprofiili julisteen alla.",
"ShowRatings": "Näytä arviot",
"ShowSearch": "Näytä haku",
"ShowSearchHelpText": "Näytä hakupainike osoitettaessa.",
@@ -1111,5 +1111,8 @@
"BypassDelayIfHighestQuality": "Ohita, jos korkein laatu",
"RemoveFailed": "Poisto epäonnistui",
"RemoveCompleted": "Poista valmistuneet",
"RemoveDownloadsAlert": "Poistoasetukset on siirretty yllä olevassa taulukossa yksittäisten lataustyökalujen alle."
"RemoveDownloadsAlert": "Poistoasetukset on siirretty yllä olevassa taulukossa yksittäisten lataustyökalujen alle.",
"OnApplicationUpdate": "Kun sovellus päivittyy",
"OnApplicationUpdateHelpText": "Kun sovellus päivittyy",
"DiscordUrlInSlackNotification": "Olet määrittänyt Discord-ilmoituksen Slack-ilmoitukseksi. Määritä se Discord-ilmoitukseksi parempaa toiminnallisuutta varten. Koskee seuraavia ilmoituksia: {0}"
}

View File

@@ -1094,5 +1094,7 @@
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Êtes-vous sûr de vouloir désinstaller {0} objet{1} de la file d'attente ?",
"BlocklistReleases": "Mettre cette release sur la liste noire",
"RemotePathMappingCheckGenericPermissions": "Le client de téléchargement {0} met les téléchargements dans {1} mais Radarr ne peut voir ce répertoire. Il est possible que vous ayez besoin d'ajuster les permissions de ce dossier.",
"RemotePathMappingCheckLocalWrongOSPath": "Le client de téléchargement {0} met les téléchargements dans {1} mais il ne s'agit pas d'un chemin {2} valide. Vérifiez les paramètres de votre client de téléchargement."
"RemotePathMappingCheckLocalWrongOSPath": "Le client de téléchargement {0} met les téléchargements dans {1} mais il ne s'agit pas d'un chemin {2} valide. Vérifiez les paramètres de votre client de téléchargement.",
"RemotePathMappingCheckFilesGenericPermissions": "Le client de téléchargement {0} met les téléchargements dans {1} mais Radarr ne peut voir ce répertoire. Il est possible que vous ayez besoin d'ajuster les permissions de ce dossier.",
"RemotePathMappingCheckFilesLocalWrongOSPath": "Le client de téléchargement {0} met les téléchargements dans {1} mais il ne s'agit pas d'un chemin {2} valide. Vérifiez les paramètres de votre client de téléchargement."
}

View File

@@ -893,11 +893,11 @@
"AllMoviesInPathHaveBeenImported": "Az összes film a(z) {0} -ból importálva lett",
"AllFiles": "Összes fájl",
"AfterManualRefresh": "A kézi frissítés után",
"AddToDownloadQueue": "Hozzáadva a letöltési sorhoz",
"AddToDownloadQueue": "Hozzáadás a letöltési sorhoz",
"AddRootFolder": "Gyökérmappa hozzáadása",
"AddQualityProfile": "Minőségi profil hozzáadása",
"AddNotification": "Értesítés hozzáadása",
"AddedToDownloadQueue": "Hozzáadva a letöltött elemekhez",
"AddedToDownloadQueue": "Hozzáadva a letöltési sorhoz",
"AddDownloadClient": "Letöltőkliens hozzáadása",
"AddDelayProfile": "Késleltetési profil hozzáadása",
"AddCustomFormat": "Egyéni formátum hozzáadása",
@@ -1028,7 +1028,7 @@
"Months": "Hónapok",
"MonitoredStatus": "Megfigyelt/Státusz",
"Monday": "Hétfő",
"MissingFromDisk": "A Radarr nem találta a megadott fájlt a lemezen, így eltávolitotta azt",
"MissingFromDisk": "A Radarr nem találta a fájlt a lemezen, ezért a fájlt eltávolítottuk az adatbázisból",
"Minutes": "percek",
"MinimumCustomFormatScore": "Minimum Egyéni Formátum száma",
"Min": "minimum",

View File

@@ -1,7 +1,7 @@
{
"RootFolderCheckSingleMessage": "Cartella radice mancante: {0}",
"Wanted": "Ricercato",
"View": "Guarda",
"View": "Vista",
"UpdateSelected": "Aggiorna i Film Selezionati",
"UnselectAll": "Deseleziona Tutto",
"Unmonitored": "Non Seguito",
@@ -59,7 +59,7 @@
"Clear": "Cancella",
"Certification": "Certificazione",
"AppDataLocationHealthCheckMessage": "Non è possibile effettuare l'aggiornamento per evitare di cancellare AppData",
"Analytics": "Statistiche",
"Analytics": "Analisi",
"Added": "Aggiunto",
"About": "Versione",
"Year": "Anno",
@@ -259,7 +259,7 @@
"AnalyticsEnabledHelpText": "Inviare informazioni anonime sull'utilizzo e sugli errori ai server di Radarr. Ciò include informazioni del tuo browser, come le pagine di Radarr che utilizzi, la segnalazione di errori e la versione del sistema operativo e del runtime. Utilizzeremo queste informazioni per dare priorità alle funzioni e alle correzioni di bug.",
"AnalyseVideoFiles": "Analizza i file video",
"AlternativeTitle": "Titolo Alternativo",
"AlreadyInYourLibrary": "Già presente nella libreria",
"AlreadyInYourLibrary": "Già presente nella tua libreria",
"AllowHardcodedSubsHelpText": "Se verranno rilevati sottotitoli impressi il film verrà comunque scaricato",
"AllowHardcodedSubs": "Permetti i sottotitoli hardcoded (impressi direttamente nel file)",
"Warn": "Attenzione",
@@ -602,7 +602,7 @@
"GeneralSettings": "Impostazioni Generali",
"ForMoreInformationOnTheIndividualIndexers": "Per maggiori informazioni sui singoli Indexer clicca sul pulsante info.",
"ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Per maggiori informazioni sulle singole liste di importazione clicca sul pulsante info.",
"ForMoreInformationOnTheIndividualDownloadClients": "Per maggiori informazioni sui singoli client di download clicca sul pulsante info.",
"ForMoreInformationOnTheIndividualDownloadClients": "Per maggiori informazioni sui singoli download del client clicca sul pulsante info.",
"FollowPerson": "Segui Persona",
"Folders": "Cartelle",
"Fixed": "Fissato",
@@ -734,7 +734,7 @@
"TagsHelpText": "Si applica ai film con almeno un tag corrispondente",
"TagIsNotUsedAndCanBeDeleted": "Il tag non è usato e può essere eliminato",
"TagCannotBeDeletedWhileInUse": "Non può essere cancellato mentre è in uso",
"Table": "Tavola",
"Table": "Tabella",
"SuggestTranslationChange": "Richiedi cambio di traduzione",
"SubfolderWillBeCreatedAutomaticallyInterp": "La sottocartella '{0}' verrà creata automaticamente",
"StartupDirectory": "Cartella di avvio",
@@ -857,11 +857,11 @@
"AllMoviesInPathHaveBeenImported": "Tutti i Film in {0} sono stati importati",
"AllFiles": "Tutti i file",
"AfterManualRefresh": "Dopo il refresh manuale",
"AddToDownloadQueue": "Aggiunto alla coda di download",
"AddToDownloadQueue": "Aggiungi alla coda di download",
"AddRootFolder": "Aggiungi cartella Root",
"AddQualityProfile": "Aggiungi profilo qualità",
"AddNotification": "Aggiungi notifica",
"AddedToDownloadQueue": "Aggiungi alla coda di download",
"AddedToDownloadQueue": "Aggiunto alla coda di download",
"AddDownloadClient": "Aggiungi client di download",
"AddCustomFormat": "Aggiungi formato personalizzato",
"Add": "Aggiungi",
@@ -1079,5 +1079,31 @@
"Blocklisted": "Lista Nera",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Sei sicuro di voler cancellare {0} elemento{1} dalla coda?",
"BlocklistReleases": "Release in blacklist",
"BypassDelayIfHighestQuality": "Non considerare se la qualità è massima"
"BypassDelayIfHighestQuality": "Non considerare se la qualità è massima",
"ImportListMissingRoot": "Persa la cartella principale per limportazione delle liste : {0}",
"ImportListMultipleMissingRoots": "Diverse cartelle principale sono perse per limportazione: {0}",
"From": "Da",
"MonoBSDSupportCheckMessage": "Il sistema operativo {0} non sarà supportato nella prossima release di Radarr.",
"RemotePathMappingCheckDockerFilesMissing": "Stai utilizzando docker; il download client {0} riporta files in {1} ma questa directory non sembra esistere nel contenitore. Controlla la mappa dei percorsi remoti e le impostazioni dei volumi del container.",
"IndexerTagHelpText": "Usa questo indicizzatore per i film con almeno un tag corrispondente. Lascia in bianco per usarlo con tutti i film.",
"RemotePathMappingCheckFilesBadDockerPath": "Stai utilizzando docker; Il client di download {0} riporta files in {1} ma questo non è un percorso valido {2}. Controlla la mappa dei percorsi remoti e le impostazioni del client di download.",
"RemotePathMappingCheckFilesGenericPermissions": "Il download client {0} riporta files in {1} ma Radarr non può vedere questa directory. Potrebbe essere necessario aggiustare i permessi della cartella.",
"OnApplicationUpdate": "All'aggiornamento dell'applicazione",
"OnApplicationUpdateHelpText": "All'aggiornamento dell'applicazione",
"RemotePathMappingCheckBadDockerPath": "Stai utilizzando docker; Il client di download {0} mette i download in {1} ma questo non è un percorso valido {2}. Controlla la mappa dei percorsi remoti e le impostazioni del client di download.",
"RemotePathMappingCheckDockerFolderMissing": "Stai utilizzando docker; il download client {0} riporta files in {1} ma questa directory non sembra esistere nel contenitore. Controlla la mappa dei percorsi remoti e le impostazioni dei volumi del container.",
"RemotePathMappingCheckDownloadPermissions": "Radarr può vedere ma non accedere al film scaricato {0}. Probabilmente per un errore nei permessi.",
"RemotePathMappingCheckFolderPermissions": "Radarr può vedere ma non accedere alla directory {0}. Probabilmente per un errore nei permessi.",
"RemoveCompleted": "Rimuovi completati",
"RemoveDownloadsAlert": "Le impostazioni per la rimozione sono stati spostati nelle impostazioni individuali dei Client di Download nella tabella sopra.",
"RemoveFailed": "Rimozione fallita",
"RemotePathMappingCheckGenericPermissions": "Il download client {0} mette i files in {1} ma Radarr non può vedere questa directory. Potrebbe essere necessario aggiustare i permessi della cartella.",
"RemotePathMappingCheckImportFailed": "Radarr ha fallito nell'importare un film. Controlla i logs per dettagli.",
"RemoveSelectedItem": "Rimuovi elemento selezionato",
"RemoveSelectedItems": "Rimuovi elementi selezionati",
"TaskUserAgentTooltip": "User-Agent esposto dalla app che ha chiamato la API",
"UpdateAvailable": "É disponibile un nuovo aggiornamento",
"BypassDelayIfHighestQualityHelpText": "Salta il ritardo quando la release ha la più alta qualità abilitata nel profilo qualità con il protocollo preferito",
"Monox86SupportCheckMessage": "Il sistema operativo attuale è a 32bit, questo non sarà supportato nella prossima release di Radarr.",
"NotificationTriggersHelpText": "Selezionare quali eventi attiveranno questa notifica"
}

View File

@@ -484,7 +484,7 @@
"Links": "Koppelingen",
"IconForCutoffUnmet": "Icoon voor Onbereikte Drempel",
"EnableMediaInfoHelpText": "Video informatie extraheren zoals resolutie, speelduur en codec informatie van bestanden. Dit maakt het noodzakelijk dat Radarr delen van een bestand moet inlezen dewelke hoge schijf- of netwerkactiviteit kan veroorzaken tijdens het scannen.",
"BindAddress": "Aanhaak Adres",
"BindAddress": "Gebonden Adres",
"PreferIndexerFlagsHelpText": "Verkies uitgaves met speciale flags",
"MinimumAgeHelpText": "Enkel Usenet: Minimale leeftijd in minuten voor NZB bestanden alvorens ze worden opgehaald. Gebruik dit om nieuwe uitgaves de tijd te geven om tot bij uw Usenet provider toe te komen.",
"LanguageHelpText": "Taal voor Uitgaves",
@@ -1096,12 +1096,12 @@
"RemotePathMappingCheckLocalWrongOSPath": "Lokale downloadclient {0} plaatst downloads in {1}, maar dit is geen geldig {2}-pad. Controleer de instellingen van uw downloadclient.",
"TaskUserAgentTooltip": "User-Agent geleverd door de app die de API heeft aangeroepen",
"AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist": "Ben je zeker dat je de geselecteerde items wil verwijderen van de uitzonderingslijst?",
"Blocklist": "Zwarte lijst",
"Blocklist": "Blokkeerlijst",
"BlocklistHelpText": "Voorkom dat Radarr deze release nogmaals automatisch ophaalt",
"BlocklistRelease": "Uitgave op Zwarte lijst zetten",
"BlocklistRelease": "Uitgave op blokkeerlijst zetten",
"RemoveFromBlocklist": "Verwijder van zwarte lijst",
"UnableToLoadBlocklist": "Kon zwarte lijst niet laden",
"Blocklisted": "Zwarte lijst",
"Blocklisted": "Blokkeerlijst",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Ben je zeker dat je {1} item{2} uit de wachtrij wilt verwijderen?",
"BlocklistReleases": "Uitgave op Zwarte lijst zetten"
"BlocklistReleases": "Uitgave op blokkeerlijst zetten"
}

View File

@@ -415,7 +415,7 @@
"IgnoredHelpText": "A versão será rejeitada caso contenha um ou mais destes termos (sem distinção de maiúsculas ou minúsculas)",
"IgnoreDeletedMovies": "Deixar de monitorar filmes eliminados",
"IgnoredAddresses": "Endereços ignorados",
"IconForCutoffUnmet": "Ícone para Limite não-correspondido",
"IconForCutoffUnmet": "Ícone para Limite não correspondido",
"ICalHttpUrlHelpText": "Copie este URL para seu(s) cliente(s) ou clique para subscrever-se caso seu browser suporte webcal",
"ICalFeed": "Feed do iCal",
"Hostname": "Nome do anfitrião",
@@ -440,8 +440,8 @@
"EnableInteractiveSearch": "Ativar pesquisa interativa",
"EnableHelpText": "Ativar criação do ficheiro de metadados para este tipo de metadados",
"EnabledHelpText": "Ativar esta lista para uso no Radarr",
"EnableCompletedDownloadHandlingHelpText": "Automaticamente importar transferências concluídas do cliente de transferências",
"EnableColorImpairedModeHelpText": "Estilo alterado para permitir que utilizadores com daltonismo possam melhor distinguir informações de cores",
"EnableCompletedDownloadHandlingHelpText": "Importar automaticamente as transferências concluídas do cliente de transferências",
"EnableColorImpairedModeHelpText": "Estilo alterado para permitir que utilizadores com daltonismo possam distinguir melhor os códigos de cores",
"EnableColorImpairedMode": "Ativar modo de daltonismo",
"EnableAutomaticSearch": "Ativar pesquisa automática",
"EnableAutomaticAdd": "Ativar adição automática",
@@ -480,7 +480,7 @@
"CreateEmptyMovieFoldersHelpText": "Criar pastas ausentes para filmes durante a análise do disco",
"CreateEmptyMovieFolders": "Criar pastas vazias para filmes",
"CopyUsingHardlinksHelpTextWarning": "Ocasionalmente, bloqueios de ficheiros podem impedir a renomeação de ficheiros que ainda estão sendo provisionados. Você pode temporariamente desativar o provisionamento e utilizar a função de renomeação do Radarr como uma solução alternativa.",
"CopyUsingHardlinksHelpText": "Usar ligações fixas ao tentar copiar ficheiros de torrents que ainda estão em modo de provisionamento",
"CopyUsingHardlinksHelpText": "Usar ligações fixas (Hardlinks) ao tentar copiar ficheiros de torrents que ainda estão em modo de semeio",
"ConnectSettings": "Definições de ligação",
"Conditions": "Condições",
"ColonReplacementFormatHelpText": "Mude a forma como o Radarr lida com a substituição de dois-pontos",
@@ -605,7 +605,7 @@
"LoadingMovieExtraFilesFailed": "Falha no carregamento dos ficheiros adicionais do filme",
"LoadingMovieCreditsFailed": "Falha no carregamento dos créditos do filme",
"LinkHere": "aqui",
"LastDuration": "Duração mais recente",
"LastDuration": "Última Duração",
"InteractiveSearch": "Pesquisa interativa",
"IncludeRadarrRecommendations": "Incluir recomendações do Radarr",
"ImportListSyncIntervalHelpText": "Frequência com que o Radarr sincroniza suas listas. Valor mínimo de 6 horas",
@@ -619,7 +619,7 @@
"GrabReleaseMessageText": "O Radarr não pode determinar a que filme pertence esta versão. O Radarr pode ser incapaz de importar automaticamente esta versão. Deseja capturar \"{0}\"?",
"GoToInterp": "Ir para {0}",
"ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Para obter mais informações sobre cada lista de importação, clique nos botões de informação.",
"ForMoreInformationOnTheIndividualDownloadClients": "Para obter mais informações sobre cada cliente de transferências, clique nos botões de informação.",
"ForMoreInformationOnTheIndividualDownloadClients": "Para obter mais informações sobre cada cliente de transferências, clique nos botões de mais informação.",
"FilterPlaceHolder": "Pesquisar filmes",
"FailedLoadingSearchResults": "Erro ao carregar resultados da pesquisa. Tenta novamente.",
"ExtraFileExtensionsHelpTexts2": "Exemplos: \".sub, .nfo\" ou \"sub,nfo\"",
@@ -831,8 +831,8 @@
"Tomorrow": "Amanhã",
"Today": "Hoje",
"ListTagsHelpText": "Os itens na lista de etiquetas serão adicionados com",
"IndexerLongTermStatusCheckSingleClientMessage": "Indexadores indisponíveis devido a erros por mais de 6 horas: {0}",
"IndexerLongTermStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a erros por mais de 6 horas",
"IndexerLongTermStatusCheckSingleClientMessage": "Indexadores indisponíveis devido a erros à mais de 6 horas: {0}",
"IndexerLongTermStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a erros á mais de 6 horas",
"EditMovieFile": "Editar ficheiro do filme",
"Yes": "Sim",
"No": "Não",
@@ -858,7 +858,7 @@
"AddNotification": "Adicionar notificação",
"AddQualityProfile": "Adicionar perfil de qualidade",
"AddRootFolder": "Adicionar pasta raiz",
"AddToDownloadQueue": "Adicionado à fila de transferências",
"AddToDownloadQueue": "Adicionar à fila de transferências",
"AfterManualRefresh": "Após a atualização manual",
"AllFiles": "Todos os ficheiros",
"Add": "Adicionar",
@@ -1090,11 +1090,11 @@
"Monox86SupportCheckMessage": "O sistema operativo atual é de 32 bits e não será suportado na próxima versão do Radarr.",
"MonoBSDSupportCheckMessage": "O sistema operativo {0} não será compatível com a próxima versão do Radarr.",
"Letterboxd": "Letterboxd",
"ImportListMultipleMissingRoots": "Faltam várias pastas raiz para listas de importação: {0}",
"ImportListMissingRoot": "Pasta raiz ausente para lista(s) de importação: {0}",
"ImportListMultipleMissingRoots": "Faltam várias pastas de raiz para a(s) lista(s) de importação: {0}",
"ImportListMissingRoot": "Pasta de raiz ausente para a(s) lista(s) de importação: {0}",
"From": "De",
"BypassDelayIfHighestQualityHelpText": "Ignorar o atraso quando a versão tiver a qualidade mais alta ativada no perfil de qualidade com o protocolo preferido",
"BypassDelayIfHighestQuality": "Ignorar se for a qualidade mais alta",
"BypassDelayIfHighestQuality": "Ignorar se a qualidade for mais alta",
"NotificationTriggersHelpText": "Seleciona quais eventos acionam esta notificação",
"UnableToAddRootFolder": "Não foi possível carregar as pastas raiz",
"AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist": "Tem a certeza que quer remover os itens selecionados da lista de bloqueio?",
@@ -1105,5 +1105,6 @@
"UnableToLoadBlocklist": "Não foi possível carregar a lista de bloqueio",
"Blocklisted": "Lista de bloqueio",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Tem a certeza que quer remover {0} item{1} da fila?",
"BlocklistReleases": "Bloquear versão"
"BlocklistReleases": "Bloquear versão",
"IndexerTagHelpText": "Só use este indexador para filmes com pelo menos uma etiqueta correspondente. Deixe em branco para usar com todos os filmes."
}

View File

@@ -244,7 +244,7 @@
"DeleteFilesLabel": "Excluir {0} arquivos do filme",
"DeleteFilesHelpText": "Excluir os arquivos e a pasta do filme",
"DeleteFile": "Excluir arquivo",
"DeleteEmptyFoldersHelpText": "Excluir pastas de filmes vazias durante a verificação do disco e quando os arquivos de filmes forem excluídos",
"DeleteEmptyFoldersHelpText": "Excluir pastas de filmes vazias durante a verificação do disco e quando os arquivos do filme forem excluídos",
"DeleteEmptyFolders": "Excluir pastas vazias",
"DeleteDownloadClientMessageText": "Tem certeza que deseja excluir o cliente de download \"{0}\"?",
"DeleteDownloadClient": "Excluir cliente de download",
@@ -326,14 +326,14 @@
"ChmodFolder": "Pasta chmod",
"CheckForFinishedDownloadsInterval": "Verifique o intervalo de downloads concluídos",
"CheckDownloadClientForDetails": "verifique o cliente de download para saber mais",
"ChangeHasNotBeenSavedYet": "A alteração ainda não foi salva",
"ChangeFileDate": "Alterar data do arquivo",
"ChangeHasNotBeenSavedYet": "Mudar o que não foi salvo ainda",
"ChangeFileDate": "Mudar Data do Arquivo",
"CertValidationNoLocal": "Desabilitado para endereços locais",
"CertificationCountryHelpText": "Selecione o país para as certificações de filmes",
"CertificationCountry": "País da certificação",
"Certification": "Certificação",
"CertificateValidationHelpText": "Alterar o quão estrita é a validação da certificação HTTPS",
"CertificateValidation": "Validação de certificado",
"CertificateValidationHelpText": "Mudar o quão estrito a validação da certificação HTTPS é",
"CertificateValidation": "Validação do Certificado",
"Cast": "Elenco",
"CantFindMovie": "Por que não consigo encontrar meu filme?",
"CancelProcessing": "Cancelar processamento",
@@ -345,9 +345,9 @@
"BuiltIn": "Embutido",
"BranchUpdateMechanism": "Ramificação usada pelo mecanismo de atualização externo",
"BranchUpdate": "Ramificação para atualização do Radarr",
"Branch": "Ramificação",
"BindAddressHelpText": "Endereço IP4 válido ou \"*\" para todas as interfaces",
"BindAddress": "Endereço de vínculo",
"Branch": "Ramo",
"BindAddressHelpText": "Endereço IPv4 Válido ou '*' para todas as interfaces",
"BindAddress": "Fixar Endereço",
"BeforeUpdate": "Antes da atualização",
"Backups": "Backups",
"BackupRetentionHelpText": "Backups automáticos anteriores ao período de retenção serão limpos automaticamente",
@@ -401,7 +401,7 @@
"Mode": "Modo",
"MissingNotMonitored": "Ausente (não monitorado)",
"MissingMonitoredAndConsideredAvailable": "Ausente (monitorado)",
"MissingFromDisk": "O Radarr não conseguiu encontrar o arquivo no disco, então ele foi removido",
"MissingFromDisk": "Radarr não conseguiu encontrar o arquivo no disco, então o arquivo foi desvinculado do filme no banco de dados",
"Missing": "Ausente",
"MinutesSixty": "60 minutos: {0}",
"MinutesNinety": "90 minutos: {0}",
@@ -482,7 +482,7 @@
"Agenda": "Programação",
"Age": "Tempo de vida",
"AfterManualRefresh": "Após atualização manual",
"AddToDownloadQueue": "Adicionado à fila de download",
"AddToDownloadQueue": "Adicionar à fila de download",
"AddRootFolder": "Adicionar pasta raiz",
"AddRestriction": "Adicionar restrição",
"AddRemotePathMapping": "Adicionar mapeamento de caminho remoto",
@@ -1101,7 +1101,7 @@
"AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist": "Tem certeza de que deseja remover os itens selecionados da lista de bloqueio?",
"Blocklist": "Lista de bloqueio",
"BlocklistHelpText": "Impede que o Readarr obtenha este lançamento novamente de forma automática",
"BlocklistRelease": "Adicionar versão à lista de bloqueio",
"BlocklistRelease": "Lista de Bloqueio de Lançamentos",
"RemoveFromBlocklist": "Remover da lista de bloqueio",
"UnableToLoadBlocklist": "Não foi possível carregar a lista de bloqueio",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Você tem certeza de que deseja remover {0} item{1} da fila?",
@@ -1111,5 +1111,8 @@
"RemoveSelectedItem": "Remover Item Selecionado",
"RemoveFailed": "Falha na remoção",
"RemoveCompleted": "Remoção Completa",
"RemoveDownloadsAlert": "As configurações de remoção foram movidas para as configurações do Cliente de Download na tabela acima."
"RemoveDownloadsAlert": "As configurações de remoção foram movidas para as configurações do Cliente de Download na tabela acima.",
"OnApplicationUpdate": "Na Atualização do Aplicativo",
"OnApplicationUpdateHelpText": "Na Atualização do Aplicativo",
"DiscordUrlInSlackNotification": "Você tem uma notificação do Discord configurado como uma notificação do Slack. Definir isso como uma notificação do Discord para melhor funcionalidade. Com efeito, notificações são: {0}"
}

View File

@@ -126,7 +126,7 @@
"ImportHeader": "Импортировать фильмы, которые у вас уже есть",
"ImportIncludeQuality": "Убедитесь, что имена файлов включают в себя их качество. Например {0}",
"IncludeCustomFormatWhenRenaming": "Учесть пользовательский формат при переименовании",
"ImportRootPath": "Указать Radarr папку со всеми фильмами, а не конкретным фильмом. Например {0}, а не {1}",
"ImportRootPath": "Укажите Radarr на папку, содержащую все ваши фильмы, а не конкретный фильм. Например, {0}, а не {1}. Кроме того, каждый фильм должен находиться в своей отдельной папке в корневой папке/библиотеке.",
"ImportTipsMessage": "Некоторые советы чтобы импорт прошел без проблем:",
"InCinemas": "В кинотеатрах",
"IncludeCustomFormatWhenRenamingHelpText": "Включить в {Custom Formats} формат переименования",
@@ -231,18 +231,18 @@
"ListTagsHelpText": "Тэги листа будут добавлены с",
"LoadingMovieCreditsFailed": "Неудачная загрузка информации о фильме",
"UnableToLoadCustomFormats": "Невозможно загрузить пользовательские форматы",
"UpdateMechanismHelpText": "Используйте встроенную в Radarr функцию обновления или скрипт",
"UpdateMechanismHelpText": "Используйте встроенное средство обновления Radarr или скрипт",
"UpdateScriptPathHelpText": "Путь к пользовательскому скрипту, который обрабатывает остатки после процесса обновления",
"CustomFormatJSON": "Настраиваемый формат JSON",
"Add": "Добавить",
"AddCustomFormat": "Добавить свой формат",
"AddDelayProfile": "Добавить профиль задержки",
"AddedToDownloadQueue": "Добавлено в очередь скачанных",
"AddedToDownloadQueue": "Добавлено в очередь на скачивание",
"AddNotification": "Добавить оповещение",
"AddRootFolder": "Добавить корневой каталог",
"AllFiles": "Все файлы",
"AllMoviesInPathHaveBeenImported": "Все фильмы из {0} были внесены",
"AddToDownloadQueue": "Добавлено в очередь скачивания",
"AddToDownloadQueue": "Добавить в очередь загрузки",
"AfterManualRefresh": "После обновления в ручную",
"AllResultsHiddenFilter": "Все результаты скрыты фильтром",
"AddDownloadClient": "Добавить программу для скачивания",
@@ -251,7 +251,7 @@
"ApplyTagsHelpTexts2": "Добавить: добавить ярлыки к существующему списку",
"AptUpdater": "Используйте apt для установки обновления",
"AuthForm": "Формы (Страница авторизации)",
"AreYouSureYouWantToRemoveSelectedItemsFromQueue": "Вы уверены, что хотите удалить {1} номер{2} из очереди?",
"AreYouSureYouWantToRemoveSelectedItemsFromQueue": "Вы уверены, что хотите удалить {0} элемент{1} из очереди?",
"BeforeUpdate": "До обновления",
"BuiltIn": "Встроено",
"CalendarOptions": "Настройки календаря",
@@ -335,7 +335,7 @@
"Agenda": "План",
"MinFormatScoreHelpText": "Минимальная оценка пользовательского формата для скачивания",
"Cast": "Состав",
"Certification": "Сертификация",
"Certification": "Возрастной рейтинг",
"Connect": "Подключить",
"Connections": "Соединения",
"CompletedDownloadHandling": "Обработка завершенных скачиваний",
@@ -356,7 +356,7 @@
"Automatic": "Автоматически",
"AuthenticationMethodHelpText": "Необходим логин и пароль для доступа в Radarr",
"ConnectionLostAutomaticMessage": "Radarr попытается соединиться автоматически или нажмите кнопку внизу.",
"ConnectionLostMessage": "Radarr отключился от сервера и должен быть перезапущен.",
"ConnectionLostMessage": "Radarr потерял связь с сервером и его необходимо перезагрузить, чтобы восстановить работоспособность.",
"Crew": "Команда",
"Health": "Здоровье",
"EnableMediaInfoHelpText": "Извлекать из файлов видео разрешение, длительность и информацию о кодеках. Это может привести к высокой активности диска и сети во время сканирования.",
@@ -421,10 +421,10 @@
"RadarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Radarr поддерживает настраиваемые условия в соответствии со свойствами выпуска, указанными ниже.",
"RadarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Radarr поддерживает любые списки фильмов RSS, а также приведенный ниже.",
"RadarrSupportsAnyIndexer": "Radarr поддерживает любой индексатор, использующий стандарт Newznab, а также другие индексаторы, перечисленные ниже.",
"RadarrSupportsAnyDownloadClient": "Radarr поддерживает любой клиент загрузки использующий стандарт Newznab, а также другие клиенты загрузки перечисленные ниже.",
"RadarrSupportsAnyDownloadClient": "Radarr поддерживает многие популярные торрент и usenet-клиенты для скачивания.",
"RadarrCalendarFeed": "Лента календаря Radarr",
"Radarr": "Radarr",
"QuickImport": "Быстрый импорт",
"QuickImport": "Автоматическое перемещение",
"QueueIsEmpty": "Очередь пуста",
"Queued": "В очереди",
"Queue": "Очередь",
@@ -438,7 +438,7 @@
"QualityLimitsHelpText": "Пределы автоматически регулируются для времени воспроизведения фильма.",
"QualityDefinitions": "Определения качества",
"QualityCutoffHasNotBeenMet": "Порог качества не соблюден",
"Quality": "Количество",
"Quality": "Качество",
"QualitiesHelpText": "Качества, расположенные выше в списке, более предпочтительны. Качества внутри одной группы равны. Требуются только отмеченные качества",
"Qualities": "Качества",
"PublishedDate": "Дата публикации",
@@ -498,7 +498,7 @@
"OrganizeModalDisabled": "Переименование отключено, переименовывать нечего",
"OrganizeModalAllPathsRelative": "Все пути указаны относительно:",
"OrganizeConfirm": "Вы действительно хотите организовать все файлы в {0} выбранных фильм(ах)?",
"OrganizeAndRename": "Организовать & переименовать",
"OrganizeAndRename": "Организовать и переименовать",
"Organize": "Организовать",
"Options": "Опции",
"OpenThisModal": "Открыть это модальное окно",
@@ -542,7 +542,7 @@
"No": "Нет",
"NextExecution": "Следующее выполнение",
"New": "Новый",
"NetCore": ".NET Core",
"NetCore": ".NET",
"Negated": "Отрицательный",
"Negate": "Отрицать",
"NamingSettings": "Настройки именования",
@@ -597,7 +597,7 @@
"MonoVersionCheckNotSupportedMessage": "Установленная Mono версия {0} больше не поддерживается. Обновите до версии {1}.",
"MonoVersion": "Моно версия",
"MonoTlsCheckMessage": "Radarr Mono 4.x tls включён, удалите настройку MONO_TLS_PROVIDER=legacy",
"MonoNotNetCoreCheckMessage": "Пожалуйста обновите Radarr до .NET Core версии",
"MonoNotNetCoreCheckMessage": "Пожалуйста обновите .NET Core версию Radarr, версии Mono не будут поддерживаться в следующем выпуске.",
"MonitorMovie": "Отслеживать фильм",
"MonitoredStatus": "Отслеживаемые/Статус",
"MonitoredOnly": "Только отслеживаемые",
@@ -608,7 +608,7 @@
"Mode": "Режим",
"MissingNotMonitored": "Не найден (не отслеживался)",
"MissingMonitoredAndConsideredAvailable": "Не найден (отслеживался)",
"MissingFromDisk": "Radarr не нашел файл на диске и он был удалён",
"MissingFromDisk": "Radarr не смог найти файл на диске, поэтому файл был откреплён от фильма в базе данных",
"Missing": "Не найдено",
"MinutesSixty": "60 минут: {0}",
"MinutesNinety": "90 минут: {0}",
@@ -659,7 +659,7 @@
"FreeSpace": "Свободное место",
"ForMoreInformationOnTheIndividualIndexers": "Для дополнительной информации по индексаторам нажмите кнопку с информацией.",
"ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Для дополнительной информации по спискам импорта нажмите эту кнопку.",
"ForMoreInformationOnTheIndividualDownloadClients": "Для дополнительной информации пл программам скачивания нажмите эту кнопку.",
"ForMoreInformationOnTheIndividualDownloadClients": "Для получения дополнительной информации о каждом из клиентов загрузки нажмите на кнопки с дополнительной информацией.",
"Formats": "Форматы",
"Forecast": "Прогноз",
"FollowPerson": "Отслеживать человека",
@@ -678,7 +678,7 @@
"FileNames": "Имена файлов",
"Filename": "Имя файла",
"FileManagement": "Управление файлами",
"FileDateHelpText": "Заменить лату файла при импорте/сканировании",
"FileDateHelpText": "Заменить дату файла при импорте/сканировании",
"FeatureRequests": "Будущие запросы",
"FailedToLoadQueue": "Не удалось загрузить очередность",
"FailedToLoadMovieFromAPI": "Не удалось загрузить фильмы из API",
@@ -875,7 +875,7 @@
"SaveSettings": "Сохранить настройки",
"SaveChanges": "Сохранить изменения",
"Save": "Сохранить",
"Runtime": "Время выполнения",
"Runtime": "Продолжительность",
"RSSSyncIntervalHelpTextWarning": "Это будет применяться ко всем индексаторам, пожалуйста, следуйте установленным ими правилам",
"RSSSyncInterval": "Интервал синхронизации RSS",
"RSSSync": "Синхронизация RSS",
@@ -977,7 +977,7 @@
"Socks5": "Socks5 (Поддержка TOR)",
"Socks4": "Socks4",
"Small": "Маленький",
"SkipFreeSpaceCheckWhenImportingHelpText": "Используйте, когда Radarr не может обнаружить свободное место в корневой папке вашего фильма",
"SkipFreeSpaceCheckWhenImportingHelpText": "Используется, когда Radarr не может найти свободное место в корневой папке фильма",
"SkipFreeSpaceCheck": "Пропустить проверку свободного места",
"SizeOnDisk": "Объём на диске",
"Size": "Размер",
@@ -1033,7 +1033,7 @@
"SelectLanguges": "Выбрать языки",
"SelectLanguage": "Выбрать язык",
"SelectFolder": "Выбрать папку",
"SelectDotDot": "'Выбрать...",
"SelectDotDot": "Выбрать...",
"SelectAll": "Выбрать все",
"Seeders": "Сиды",
"Security": "Безопасность",
@@ -1094,5 +1094,22 @@
"UnableToLoadBlocklist": "Не удалось загрузить черный список",
"Blocklisted": "Черный список",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Вы действительно хотите удалить {0} из очереди?",
"BlocklistReleases": "Релиз из черного списка"
"BlocklistReleases": "Релиз из черного списка",
"RemoveFailed": "Удаление не удалось",
"RemoveSelectedItem": "Удалить выбранный элемент",
"RemoveSelectedItems": "Удалить выбранные элементы",
"BypassDelayIfHighestQuality": "Игнорировать при максимальном качестве",
"BypassDelayIfHighestQualityHelpText": "Игнорирование задержки, когда выпуск имеет максимальное качество в выбранном профиле качества с предпочитаемым протоколом",
"ImportListMissingRoot": "Отсутствует корневая папка для импортирования списка(ов): {0}",
"ImportListMultipleMissingRoots": "Для импортируемых списков отсутствуют несколько корневых папок: {0}",
"NotificationTriggersHelpText": "Выберите, какие события должны вызвать это уведомление",
"RemotePathMappingCheckFileRemoved": "Файл {0} был удален в процессе обработки.",
"RemotePathMappingCheckDockerFilesMissing": "Вы используете docker; клиент загрузки {0} сообщил о файлах в {1}, но этот каталог, похоже, не существует внутри контейнера. Проверьте соответствие путей к файлам и настройки тома контейнера.",
"RemotePathMappingCheckDockerFolderMissing": "Вы используете docker; клиент загрузки {0} размещает загрузки в {1}, но этот каталог, похоже, не существует внутри контейнера. Проверьте соответствие путей к файлам и настройки тома контейнера.",
"BlocklistHelpText": "Запрещает Radarr автоматически получать этот релиз повторно",
"RemoveCompleted": "Удаление завершено",
"RemoveDownloadsAlert": "Настройки удаления были перенесены в отдельные настройки клиента загрузки выше.",
"TaskUserAgentTooltip": "User-Agent, представленный приложением, который вызывает API",
"IndexerTagHelpText": "Используйте этот индексатор только для фильмов с хотя бы одним совпадающим тегом. Оставьте пустым, чтобы использовать для всех фильмов.",
"DiscordUrlInSlackNotification": "У вас уведомление Discord настроено как уведомление Slack. Настройте это как уведомление Discord для лучшей функциональности. Затронуты следующие уведомления: {0}"
}

View File

@@ -110,5 +110,8 @@
"DeleteDownloadClientMessageText": "Naozaj chcete zmazať značku formátu {0} ?",
"DeleteIndexerMessageText": "Naozaj chcete zmazať značku formátu {0} ?",
"DeleteListMessageText": "Naozaj chcete zmazať značku formátu {0} ?",
"DeleteNotificationMessageText": "Naozaj chcete zmazať značku formátu {0} ?"
"DeleteNotificationMessageText": "Naozaj chcete zmazať značku formátu {0} ?",
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Naozaj chcete odobrať {0} položku {1} z fronty?",
"ImportCustomFormat": "Pridať vlastný formát",
"DeleteRestrictionHelpText": "Naozaj chcete zmazať tento profil oneskorenia?"
}

View File

@@ -0,0 +1 @@
{}

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