mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-18 21:35:51 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dec77f63e7 |
@@ -76,15 +76,6 @@ Thank you to [<img src="/Logo/jetbrains.svg" alt="JetBrains" width="32"> JetBrai
|
|||||||
* [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
|
* [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
|
||||||
* [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
|
* [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
|
||||||
|
|
||||||
## DigitalOcean
|
|
||||||
|
|
||||||
This project is also supported by DigitalOcean
|
|
||||||
<p>
|
|
||||||
<a href="https://www.digitalocean.com/">
|
|
||||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
### License
|
### License
|
||||||
|
|
||||||
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ variables:
|
|||||||
testsFolder: './_tests'
|
testsFolder: './_tests'
|
||||||
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
||||||
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
|
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
|
||||||
majorVersion: '4.4.0'
|
majorVersion: '4.3.1'
|
||||||
minorVersion: $[counter('minorVersion', 2000)]
|
minorVersion: $[counter('minorVersion', 2000)]
|
||||||
radarrVersion: '$(majorVersion).$(minorVersion)'
|
radarrVersion: '$(majorVersion).$(minorVersion)'
|
||||||
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
|
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
|
||||||
|
|||||||
@@ -75,23 +75,13 @@ class Queue extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextState = {};
|
|
||||||
|
|
||||||
if (prevProps.items !== items) {
|
|
||||||
nextState.items = items;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedIds = this.getSelectedIds();
|
const selectedIds = this.getSelectedIds();
|
||||||
const isPendingSelected = _.some(this.props.items, (item) => {
|
const isPendingSelected = _.some(this.props.items, (item) => {
|
||||||
return selectedIds.indexOf(item.id) > -1 && item.status === 'delay';
|
return selectedIds.indexOf(item.id) > -1 && item.status === 'delay';
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isPendingSelected !== this.state.isPendingSelected) {
|
if (isPendingSelected !== this.state.isPendingSelected) {
|
||||||
nextState.isPendingSelected = isPendingSelected;
|
this.setState({ isPendingSelected });
|
||||||
}
|
|
||||||
|
|
||||||
if (!_.isEmpty(nextState)) {
|
|
||||||
this.setState(nextState);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,29 +214,26 @@ class Queue extends Component {
|
|||||||
|
|
||||||
<PageContentBody>
|
<PageContentBody>
|
||||||
{
|
{
|
||||||
isRefreshing && !isAllPopulated ?
|
isRefreshing && !isAllPopulated &&
|
||||||
<LoadingIndicator /> :
|
<LoadingIndicator />
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
!isRefreshing && hasError ?
|
!isRefreshing && hasError &&
|
||||||
<div>
|
<div>
|
||||||
{translate('FailedToLoadQueue')}
|
{translate('FailedToLoadQueue')}
|
||||||
</div> :
|
</div>
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isAllPopulated && !hasError && !items.length ?
|
isAllPopulated && !hasError && !items.length &&
|
||||||
<div>
|
<div>
|
||||||
{translate('QueueIsEmpty')}
|
{translate('QueueIsEmpty')}
|
||||||
</div> :
|
</div>
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isAllPopulated && !hasError && !!items.length ?
|
isAllPopulated && !hasError && !!items.length &&
|
||||||
<div>
|
<div>
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
@@ -281,8 +268,7 @@ class Queue extends Component {
|
|||||||
isFetching={isRefreshing}
|
isFetching={isRefreshing}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
/>
|
/>
|
||||||
</div> :
|
</div>
|
||||||
null
|
|
||||||
}
|
}
|
||||||
</PageContentBody>
|
</PageContentBody>
|
||||||
|
|
||||||
|
|||||||
@@ -225,19 +225,13 @@ class ImportMovieFooter extends Component {
|
|||||||
body={
|
body={
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
Array.isArray(importError.responseJSON) ?
|
importError.responseJSON.map((error, index) => {
|
||||||
importError.responseJSON.map((error, index) => {
|
return (
|
||||||
return (
|
<li key={index}>
|
||||||
<li key={index}>
|
{error.errorMessage}
|
||||||
{error.errorMessage}
|
</li>
|
||||||
</li>
|
);
|
||||||
);
|
})
|
||||||
}) :
|
|
||||||
<li>
|
|
||||||
{
|
|
||||||
JSON.stringify(importError.responseJSON)
|
|
||||||
}
|
|
||||||
</li>
|
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,19 +152,13 @@ class ImportMovieSelectFolder extends Component {
|
|||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
Array.isArray(saveError.responseJSON) ?
|
saveError.responseJSON.map((e, index) => {
|
||||||
saveError.responseJSON.map((e, index) => {
|
return (
|
||||||
return (
|
<li key={index}>
|
||||||
<li key={index}>
|
{e.errorMessage}
|
||||||
{e.errorMessage}
|
</li>
|
||||||
</li>
|
);
|
||||||
);
|
})
|
||||||
}) :
|
|
||||||
<li>
|
|
||||||
{
|
|
||||||
JSON.stringify(saveError.responseJSON)
|
|
||||||
}
|
|
||||||
</li>
|
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</Alert> :
|
</Alert> :
|
||||||
|
|||||||
@@ -113,12 +113,10 @@ class EnhancedSelectInput extends Component {
|
|||||||
this._scheduleUpdate();
|
this._scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(this.props.value)) {
|
if (!Array.isArray(this.props.value) && prevProps.value !== this.props.value) {
|
||||||
if (prevProps.value !== this.props.value || prevProps.values !== this.props.values) {
|
this.setState({
|
||||||
this.setState({
|
selectedIndex: getSelectedIndex(this.props)
|
||||||
selectedIndex: getSelectedIndex(this.props)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,11 +332,6 @@ class EnhancedSelectInput extends Component {
|
|||||||
|
|
||||||
const isMultiSelect = Array.isArray(value);
|
const isMultiSelect = Array.isArray(value);
|
||||||
const selectedOption = getSelectedOption(selectedIndex, values);
|
const selectedOption = getSelectedOption(selectedIndex, values);
|
||||||
let selectedValue = value;
|
|
||||||
|
|
||||||
if (!values.length) {
|
|
||||||
selectedValue = isMultiSelect ? [] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -379,17 +372,15 @@ class EnhancedSelectInput extends Component {
|
|||||||
onPress={this.onPress}
|
onPress={this.onPress}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
isFetching ?
|
isFetching &&
|
||||||
<LoadingIndicator
|
<LoadingIndicator
|
||||||
className={styles.loading}
|
className={styles.loading}
|
||||||
size={20}
|
size={20}
|
||||||
/> :
|
/>
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isFetching ?
|
!isFetching &&
|
||||||
null :
|
|
||||||
<Icon
|
<Icon
|
||||||
name={icons.CARET_DOWN}
|
name={icons.CARET_DOWN}
|
||||||
/>
|
/>
|
||||||
@@ -409,7 +400,7 @@ class EnhancedSelectInput extends Component {
|
|||||||
onPress={this.onPress}
|
onPress={this.onPress}
|
||||||
>
|
>
|
||||||
<SelectedValueComponent
|
<SelectedValueComponent
|
||||||
value={selectedValue}
|
value={value}
|
||||||
values={values}
|
values={values}
|
||||||
{...selectedValueOptions}
|
{...selectedValueOptions}
|
||||||
{...selectedOption}
|
{...selectedOption}
|
||||||
@@ -427,17 +418,15 @@ class EnhancedSelectInput extends Component {
|
|||||||
>
|
>
|
||||||
|
|
||||||
{
|
{
|
||||||
isFetching ?
|
isFetching &&
|
||||||
<LoadingIndicator
|
<LoadingIndicator
|
||||||
className={styles.loading}
|
className={styles.loading}
|
||||||
size={20}
|
size={20}
|
||||||
/> :
|
/>
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isFetching ?
|
!isFetching &&
|
||||||
null :
|
|
||||||
<Icon
|
<Icon
|
||||||
name={icons.CARET_DOWN}
|
name={icons.CARET_DOWN}
|
||||||
/>
|
/>
|
||||||
@@ -517,7 +506,7 @@ class EnhancedSelectInput extends Component {
|
|||||||
</Manager>
|
</Manager>
|
||||||
|
|
||||||
{
|
{
|
||||||
isMobile ?
|
isMobile &&
|
||||||
<Modal
|
<Modal
|
||||||
className={styles.optionsModal}
|
className={styles.optionsModal}
|
||||||
size={sizes.EXTRA_SMALL}
|
size={sizes.EXTRA_SMALL}
|
||||||
@@ -568,8 +557,7 @@ class EnhancedSelectInput extends Component {
|
|||||||
}
|
}
|
||||||
</Scroller>
|
</Scroller>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
</Modal> :
|
</Modal>
|
||||||
null
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function HintedSelectInputSelectedValue(props) {
|
|||||||
>
|
>
|
||||||
<div className={styles.valueText}>
|
<div className={styles.valueText}>
|
||||||
{
|
{
|
||||||
isMultiSelect ?
|
isMultiSelect &&
|
||||||
value.map((key, index) => {
|
value.map((key, index) => {
|
||||||
const v = valuesMap[key];
|
const v = valuesMap[key];
|
||||||
return (
|
return (
|
||||||
@@ -32,28 +32,26 @@ function HintedSelectInputSelectedValue(props) {
|
|||||||
{v ? v.value : key}
|
{v ? v.value : key}
|
||||||
</Label>
|
</Label>
|
||||||
);
|
);
|
||||||
}) :
|
})
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isMultiSelect ? null : value
|
!isMultiSelect && value
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
hint != null && includeHint ?
|
hint != null && includeHint &&
|
||||||
<div className={styles.hintText}>
|
<div className={styles.hintText}>
|
||||||
{hint}
|
{hint}
|
||||||
</div> :
|
</div>
|
||||||
null
|
|
||||||
}
|
}
|
||||||
</EnhancedSelectInputSelectedValue>
|
</EnhancedSelectInputSelectedValue>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
HintedSelectInputSelectedValue.propTypes = {
|
HintedSelectInputSelectedValue.propTypes = {
|
||||||
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))]).isRequired,
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))]).isRequired,
|
||||||
values: PropTypes.arrayOf(PropTypes.object).isRequired,
|
values: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
hint: PropTypes.string,
|
hint: PropTypes.string,
|
||||||
isMultiSelect: PropTypes.bool.isRequired,
|
isMultiSelect: PropTypes.bool.isRequired,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ RootFolderSelectInputOption.propTypes = {
|
|||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
freeSpace: PropTypes.number,
|
freeSpace: PropTypes.number,
|
||||||
movieFolder: PropTypes.string,
|
movieFolder: PropTypes.string,
|
||||||
isMissing: PropTypes.bool,
|
isMissing: PropTypes.boolean,
|
||||||
isMobile: PropTypes.bool.isRequired,
|
isMobile: PropTypes.bool.isRequired,
|
||||||
isWindows: PropTypes.bool
|
isWindows: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,10 +17,6 @@
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cloneButton {
|
.cloneButton {
|
||||||
composes: button from '~Components/Link/IconButton.css';
|
composes: button from '~Components/Link/IconButton.css';
|
||||||
|
|
||||||
@@ -40,10 +36,3 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
|
||||||
@add-mixin truncate;
|
|
||||||
composes: label from '~Components/Label.css';
|
|
||||||
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class CustomFormat extends Component {
|
|||||||
{name}
|
{name}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.buttons}>
|
<div>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={styles.cloneButton}
|
className={styles.cloneButton}
|
||||||
title={translate('CloneCustomFormat')}
|
title={translate('CloneCustomFormat')}
|
||||||
@@ -124,7 +124,6 @@ class CustomFormat extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Label
|
<Label
|
||||||
className={styles.label}
|
|
||||||
key={index}
|
key={index}
|
||||||
kind={kind}
|
kind={kind}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ function EditIndexerModalContent(props) {
|
|||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.CHECK}
|
type={inputTypes.CHECK}
|
||||||
name="enableRss"
|
name="enableRss"
|
||||||
helpText={supportsRss.value ? translate('RSSHelpText') : undefined}
|
|
||||||
helpTextWarning={supportsRss.value ? undefined : translate('RSSIsNotSupportedWithThisIndexer')}
|
helpTextWarning={supportsRss.value ? undefined : translate('RSSIsNotSupportedWithThisIndexer')}
|
||||||
isDisabled={!supportsRss.value}
|
isDisabled={!supportsRss.value}
|
||||||
{...enableRss}
|
{...enableRss}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
import * as dark from './dark';
|
import * as dark from './dark';
|
||||||
import * as light from './light';
|
import * as light from './light';
|
||||||
|
|
||||||
const defaultDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
||||||
const auto = defaultDark ? { ...dark } : { ...light };
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
auto,
|
|
||||||
light,
|
light,
|
||||||
dark
|
dark
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -134,9 +134,5 @@
|
|||||||
"webpack-cli": "4.9.1",
|
"webpack-cli": "4.9.1",
|
||||||
"webpack-livereload-plugin": "3.0.2",
|
"webpack-livereload-plugin": "3.0.2",
|
||||||
"worker-loader": "3.0.8"
|
"worker-loader": "3.0.8"
|
||||||
},
|
|
||||||
"volta": {
|
|
||||||
"node": "16.17.0",
|
|
||||||
"yarn": "1.22.19"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-25
@@ -1,25 +0,0 @@
|
|||||||
using System.Globalization;
|
|
||||||
using FluentAssertions;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
|
|
||||||
namespace NzbDrone.Common.Test.ExtensionTests.StringExtensionTests
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class IsValidIPAddressFixture
|
|
||||||
{
|
|
||||||
[TestCase("192.168.0.1")]
|
|
||||||
[TestCase("::1")]
|
|
||||||
[TestCase("2001:db8:4006:812::200e")]
|
|
||||||
public void should_validate_ip_address(string input)
|
|
||||||
{
|
|
||||||
input.IsValidIpAddress().Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase("sonarr.tv")]
|
|
||||||
public void should_not_parse_non_ip_address(string input)
|
|
||||||
{
|
|
||||||
input.IsValidIpAddress().Should().BeFalse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Test.Common;
|
using NzbDrone.Test.Common;
|
||||||
@@ -10,7 +10,6 @@ namespace NzbDrone.Common.Test.Http
|
|||||||
[TestCase("abc://my_host.com:8080/root/api/")]
|
[TestCase("abc://my_host.com:8080/root/api/")]
|
||||||
[TestCase("abc://my_host.com:8080//root/api/")]
|
[TestCase("abc://my_host.com:8080//root/api/")]
|
||||||
[TestCase("abc://my_host.com:8080/root//api/")]
|
[TestCase("abc://my_host.com:8080/root//api/")]
|
||||||
[TestCase("abc://[::1]:8080/root//api/")]
|
|
||||||
public void should_parse(string uri)
|
public void should_parse(string uri)
|
||||||
{
|
{
|
||||||
var newUri = new HttpUri(uri);
|
var newUri = new HttpUri(uri);
|
||||||
|
|||||||
@@ -7,50 +7,34 @@ namespace NzbDrone.Common.Extensions
|
|||||||
{
|
{
|
||||||
public static bool IsLocalAddress(this IPAddress ipAddress)
|
public static bool IsLocalAddress(this IPAddress ipAddress)
|
||||||
{
|
{
|
||||||
// Map back to IPv4 if mapped to IPv6, for example "::ffff:1.2.3.4" to "1.2.3.4".
|
if (ipAddress.IsIPv6LinkLocal)
|
||||||
if (ipAddress.IsIPv4MappedToIPv6)
|
|
||||||
{
|
{
|
||||||
ipAddress = ipAddress.MapToIPv4();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks loopback ranges for both IPv4 and IPv6.
|
|
||||||
if (IPAddress.IsLoopback(ipAddress))
|
if (IPAddress.IsLoopback(ipAddress))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPv4
|
|
||||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
|
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
|
||||||
{
|
{
|
||||||
return IsLocalIPv4(ipAddress.GetAddressBytes());
|
byte[] bytes = ipAddress.GetAddressBytes();
|
||||||
}
|
switch (bytes[0])
|
||||||
|
{
|
||||||
// IPv6
|
case 10:
|
||||||
if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
case 127:
|
||||||
{
|
return true;
|
||||||
return ipAddress.IsIPv6LinkLocal ||
|
case 172:
|
||||||
ipAddress.IsIPv6UniqueLocal ||
|
return bytes[1] < 32 && bytes[1] >= 16;
|
||||||
ipAddress.IsIPv6SiteLocal;
|
case 192:
|
||||||
|
return bytes[1] == 168;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsLocalIPv4(byte[] ipv4Bytes)
|
|
||||||
{
|
|
||||||
// Link local (no IP assigned by DHCP): 169.254.0.0 to 169.254.255.255 (169.254.0.0/16)
|
|
||||||
bool IsLinkLocal() => ipv4Bytes[0] == 169 && ipv4Bytes[1] == 254;
|
|
||||||
|
|
||||||
// Class A private range: 10.0.0.0 – 10.255.255.255 (10.0.0.0/8)
|
|
||||||
bool IsClassA() => ipv4Bytes[0] == 10;
|
|
||||||
|
|
||||||
// Class B private range: 172.16.0.0 – 172.31.255.255 (172.16.0.0/12)
|
|
||||||
bool IsClassB() => ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31;
|
|
||||||
|
|
||||||
// Class C private range: 192.168.0.0 – 192.168.255.255 (192.168.0.0/16)
|
|
||||||
bool IsClassC() => ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168;
|
|
||||||
|
|
||||||
return IsLinkLocal() || IsClassA() || IsClassC() || IsClassB();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
@@ -194,30 +192,5 @@ namespace NzbDrone.Common.Extensions
|
|||||||
.Replace("'", "%27")
|
.Replace("'", "%27")
|
||||||
.Replace("%7E", "~");
|
.Replace("%7E", "~");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsValidIpAddress(this string value)
|
|
||||||
{
|
|
||||||
if (!IPAddress.TryParse(value, out var parsedAddress))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsedAddress.Equals(IPAddress.Parse("255.255.255.255")))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsedAddress.IsIPv6Multicast)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedAddress.AddressFamily == AddressFamily.InterNetwork || parsedAddress.AddressFamily == AddressFamily.InterNetworkV6;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ToUrlHost(this string input)
|
|
||||||
{
|
|
||||||
return input.Contains(":") ? $"[{input}]" : input;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace NzbDrone.Common.Http
|
|||||||
{
|
{
|
||||||
public class HttpUri : IEquatable<HttpUri>
|
public class HttpUri : IEquatable<HttpUri>
|
||||||
{
|
{
|
||||||
private static readonly Regex RegexUri = new Regex(@"^(?:(?<scheme>[a-z]+):)?(?://(?<host>[-_A-Z0-9.]+|\[[[A-F0-9:]+\])(?::(?<port>[0-9]{1,5}))?)?(?<path>(?:(?:(?<=^)|/+)[^/?#\r\n]+)+/*|/+)?(?:\?(?<query>[^#\r\n]*))?(?:\#(?<fragment>.*))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
private static readonly Regex RegexUri = new Regex(@"^(?:(?<scheme>[a-z]+):)?(?://(?<host>[-_A-Z0-9.]+)(?::(?<port>[0-9]{1,5}))?)?(?<path>(?:(?:(?<=^)|/+)[^/?#\r\n]+)+/*|/+)?(?:\?(?<query>[^#\r\n]*))?(?:\#(?<fragment>.*))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
private readonly string _uri;
|
private readonly string _uri;
|
||||||
public string FullUri => _uri;
|
public string FullUri => _uri;
|
||||||
@@ -70,8 +70,6 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
private void Parse()
|
private void Parse()
|
||||||
{
|
{
|
||||||
var parseSuccess = Uri.TryCreate(_uri, UriKind.RelativeOrAbsolute, out var uri);
|
|
||||||
|
|
||||||
var match = RegexUri.Match(_uri);
|
var match = RegexUri.Match(_uri);
|
||||||
|
|
||||||
var scheme = match.Groups["scheme"];
|
var scheme = match.Groups["scheme"];
|
||||||
@@ -81,7 +79,7 @@ namespace NzbDrone.Common.Http
|
|||||||
var query = match.Groups["query"];
|
var query = match.Groups["query"];
|
||||||
var fragment = match.Groups["fragment"];
|
var fragment = match.Groups["fragment"];
|
||||||
|
|
||||||
if (!parseSuccess || (scheme.Success && !host.Success && path.Success))
|
if (!match.Success || (scheme.Success && !host.Success && path.Success))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Uri didn't match expected pattern: " + _uri);
|
throw new ArgumentException("Uri didn't match expected pattern: " + _uri);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,41 +11,26 @@ namespace NzbDrone.Common.Instrumentation.Sentry
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (sentryEvent.Message is not null)
|
sentryEvent.Message.Message = CleanseLogMessage.Cleanse(sentryEvent.Message.Message);
|
||||||
{
|
|
||||||
sentryEvent.Message.Formatted = CleanseLogMessage.Cleanse(sentryEvent.Message.Formatted);
|
|
||||||
sentryEvent.Message.Message = CleanseLogMessage.Cleanse(sentryEvent.Message.Message);
|
|
||||||
sentryEvent.Message.Params = sentryEvent.Message.Params?.Select(x => CleanseLogMessage.Cleanse(x switch
|
|
||||||
{
|
|
||||||
string str => str,
|
|
||||||
_ => x.ToString()
|
|
||||||
})).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sentryEvent.Fingerprint.Any())
|
if (sentryEvent.Fingerprint != null)
|
||||||
{
|
{
|
||||||
var fingerprint = sentryEvent.Fingerprint.Select(x => CleanseLogMessage.Cleanse(x)).ToList();
|
var fingerprint = sentryEvent.Fingerprint.Select(x => CleanseLogMessage.Cleanse(x)).ToList();
|
||||||
sentryEvent.SetFingerprint(fingerprint);
|
sentryEvent.SetFingerprint(fingerprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sentryEvent.Extra.Any())
|
if (sentryEvent.Extra != null)
|
||||||
{
|
{
|
||||||
var extras = sentryEvent.Extra.ToDictionary(x => x.Key, y => (object)CleanseLogMessage.Cleanse(y.Value as string));
|
var extras = sentryEvent.Extra.ToDictionary(x => x.Key, y => (object)CleanseLogMessage.Cleanse((string)y.Value));
|
||||||
sentryEvent.SetExtras(extras);
|
sentryEvent.SetExtras(extras);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sentryEvent.SentryExceptions is not null)
|
foreach (var exception in sentryEvent.SentryExceptions)
|
||||||
{
|
{
|
||||||
foreach (var exception in sentryEvent.SentryExceptions)
|
exception.Value = CleanseLogMessage.Cleanse(exception.Value);
|
||||||
|
foreach (var frame in exception.Stacktrace.Frames)
|
||||||
{
|
{
|
||||||
exception.Value = CleanseLogMessage.Cleanse(exception.Value);
|
frame.FileName = ShortenPath(frame.FileName);
|
||||||
if (exception.Stacktrace is not null)
|
|
||||||
{
|
|
||||||
foreach (var frame in exception.Stacktrace.Frames)
|
|
||||||
{
|
|
||||||
frame.FileName = ShortenPath(frame.FileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,6 +99,9 @@ namespace NzbDrone.Common.Instrumentation.Sentry
|
|||||||
o.Dsn = dsn;
|
o.Dsn = dsn;
|
||||||
o.AttachStacktrace = true;
|
o.AttachStacktrace = true;
|
||||||
o.MaxBreadcrumbs = 200;
|
o.MaxBreadcrumbs = 200;
|
||||||
|
o.SendDefaultPii = false;
|
||||||
|
o.Debug = false;
|
||||||
|
o.DiagnosticLevel = SentryLevel.Debug;
|
||||||
o.Release = BuildInfo.Release;
|
o.Release = BuildInfo.Release;
|
||||||
o.BeforeSend = x => SentryCleanser.CleanseEvent(x);
|
o.BeforeSend = x => SentryCleanser.CleanseEvent(x);
|
||||||
o.BeforeBreadcrumb = x => SentryCleanser.CleanseBreadcrumb(x);
|
o.BeforeBreadcrumb = x => SentryCleanser.CleanseBreadcrumb(x);
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
<PackageReference Include="DryIoc.dll" Version="5.3.0" />
|
<PackageReference Include="DryIoc.dll" Version="5.3.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="NLog" Version="5.0.1" />
|
<PackageReference Include="NLog" Version="5.0.1" />
|
||||||
<PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" />
|
<PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.23.1" />
|
<PackageReference Include="Sentry" Version="3.20.1" />
|
||||||
<PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" />
|
<PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||||
<PackageReference Include="System.Text.Json" Version="6.0.5" />
|
<PackageReference Include="System.Text.Json" Version="6.0.5" />
|
||||||
|
|||||||
@@ -1,211 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using FluentAssertions;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Core.CustomFormats;
|
|
||||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
|
||||||
using NzbDrone.Core.Profiles;
|
|
||||||
using NzbDrone.Core.Qualities;
|
|
||||||
using NzbDrone.Core.Test.Framework;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class UpgradeAllowedSpecificationFixture : CoreTest<UpgradableSpecification>
|
|
||||||
{
|
|
||||||
private CustomFormat _customFormatOne;
|
|
||||||
private CustomFormat _customFormatTwo;
|
|
||||||
private Profile _qualityProfile;
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
_customFormatOne = new CustomFormat
|
|
||||||
{
|
|
||||||
Id = 1,
|
|
||||||
Name = "One"
|
|
||||||
};
|
|
||||||
_customFormatTwo = new CustomFormat
|
|
||||||
{
|
|
||||||
Id = 2,
|
|
||||||
Name = "Two"
|
|
||||||
};
|
|
||||||
|
|
||||||
_qualityProfile = new Profile
|
|
||||||
{
|
|
||||||
Cutoff = Quality.Bluray1080p.Id,
|
|
||||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
|
||||||
UpgradeAllowed = false,
|
|
||||||
CutoffFormatScore = 100,
|
|
||||||
FormatItems = new List<ProfileFormatItem>
|
|
||||||
{
|
|
||||||
new ProfileFormatItem
|
|
||||||
{
|
|
||||||
Id = 1,
|
|
||||||
Format = _customFormatOne,
|
|
||||||
Score = 50
|
|
||||||
},
|
|
||||||
new ProfileFormatItem
|
|
||||||
{
|
|
||||||
Id = 1,
|
|
||||||
Format = _customFormatTwo,
|
|
||||||
Score = 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_false_when_quality_is_better_custom_formats_are_the_same_and_upgrading_is_not_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = false;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat>(),
|
|
||||||
new QualityModel(Quality.Bluray1080p),
|
|
||||||
new List<CustomFormat>())
|
|
||||||
.Should().BeFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_false_when_quality_is_same_and_custom_format_is_upgrade_and_upgrading_is_not_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = false;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat> { _customFormatOne },
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat> { _customFormatTwo })
|
|
||||||
.Should().BeFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_true_for_custom_format_upgrade_when_upgrading_is_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = true;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat> { _customFormatOne },
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat> { _customFormatTwo })
|
|
||||||
.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_true_for_same_custom_format_score_when_upgrading_is_not_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = false;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat> { _customFormatOne },
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat> { _customFormatOne })
|
|
||||||
.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_true_for_lower_custom_format_score_when_upgrading_is_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = true;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat> { _customFormatTwo },
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat> { _customFormatOne })
|
|
||||||
.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_true_for_lower_language_when_upgrading_is_not_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = false;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat> { _customFormatTwo },
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat> { _customFormatOne })
|
|
||||||
.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_true_for_quality_upgrade_when_upgrading_is_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = true;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat>(),
|
|
||||||
new QualityModel(Quality.Bluray1080p),
|
|
||||||
new List<CustomFormat>())
|
|
||||||
.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_true_for_same_quality_when_upgrading_is_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = true;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat>(),
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat>())
|
|
||||||
.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_true_for_same_quality_when_upgrading_is_not_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = false;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat>(),
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat>())
|
|
||||||
.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_true_for_lower_quality_when_upgrading_is_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = true;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat>(),
|
|
||||||
new QualityModel(Quality.SDTV),
|
|
||||||
new List<CustomFormat>())
|
|
||||||
.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_true_for_lower_quality_when_upgrading_is_not_allowed()
|
|
||||||
{
|
|
||||||
_qualityProfile.UpgradeAllowed = false;
|
|
||||||
|
|
||||||
Subject.IsUpgradeAllowed(
|
|
||||||
_qualityProfile,
|
|
||||||
new QualityModel(Quality.DVD),
|
|
||||||
new List<CustomFormat>(),
|
|
||||||
new QualityModel(Quality.SDTV),
|
|
||||||
new List<CustomFormat>())
|
|
||||||
.Should().BeTrue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-367
@@ -1,367 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using FluentAssertions;
|
|
||||||
using Moq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Common.Disk;
|
|
||||||
using NzbDrone.Common.Http;
|
|
||||||
using NzbDrone.Core.Download;
|
|
||||||
using NzbDrone.Core.Download.Clients;
|
|
||||||
using NzbDrone.Core.Download.Clients.FreeboxDownload;
|
|
||||||
using NzbDrone.Core.Download.Clients.FreeboxDownload.Responses;
|
|
||||||
using NzbDrone.Core.Movies;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.FreeboxDownloadTests
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class TorrentFreeboxDownloadFixture : DownloadClientFixtureBase<TorrentFreeboxDownload>
|
|
||||||
{
|
|
||||||
protected FreeboxDownloadSettings _settings;
|
|
||||||
|
|
||||||
protected FreeboxDownloadConfiguration _downloadConfiguration;
|
|
||||||
|
|
||||||
protected FreeboxDownloadTask _task;
|
|
||||||
|
|
||||||
protected string _defaultDestination = @"/some/path";
|
|
||||||
protected string _encodedDefaultDestination = "L3NvbWUvcGF0aA==";
|
|
||||||
protected string _category = "somecat";
|
|
||||||
protected string _encodedDefaultDestinationAndCategory = "L3NvbWUvcGF0aC9zb21lY2F0";
|
|
||||||
protected string _destinationDirectory = @"/path/to/media";
|
|
||||||
protected string _encodedDestinationDirectory = "L3BhdGgvdG8vbWVkaWE=";
|
|
||||||
protected OsPath _physicalPath = new OsPath("/mnt/sdb1/mydata");
|
|
||||||
protected string _downloadURL => "magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcad53426&dn=download";
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
Subject.Definition = new DownloadClientDefinition();
|
|
||||||
|
|
||||||
_settings = new FreeboxDownloadSettings()
|
|
||||||
{
|
|
||||||
Host = "127.0.0.1",
|
|
||||||
Port = 443,
|
|
||||||
ApiUrl = "/api/v1/",
|
|
||||||
AppId = "someid",
|
|
||||||
AppToken = "S0mEv3RY1oN9T0k3n"
|
|
||||||
};
|
|
||||||
|
|
||||||
Subject.Definition.Settings = _settings;
|
|
||||||
|
|
||||||
_downloadConfiguration = new FreeboxDownloadConfiguration()
|
|
||||||
{
|
|
||||||
DownloadDirectory = _encodedDefaultDestination
|
|
||||||
};
|
|
||||||
|
|
||||||
_task = new FreeboxDownloadTask()
|
|
||||||
{
|
|
||||||
Id = "id0",
|
|
||||||
Name = "name",
|
|
||||||
DownloadDirectory = "L3NvbWUvcGF0aA==",
|
|
||||||
InfoHash = "HASH",
|
|
||||||
QueuePosition = 1,
|
|
||||||
Status = FreeboxDownloadTaskStatus.Unknown,
|
|
||||||
Eta = 0,
|
|
||||||
Error = "none",
|
|
||||||
Type = FreeboxDownloadTaskType.Bt.ToString(),
|
|
||||||
IoPriority = FreeboxDownloadTaskIoPriority.Normal.ToString(),
|
|
||||||
StopRatio = 150,
|
|
||||||
PieceLength = 125,
|
|
||||||
CreatedTimestamp = 1665261599,
|
|
||||||
Size = 1000,
|
|
||||||
ReceivedPrct = 0,
|
|
||||||
ReceivedBytes = 0,
|
|
||||||
ReceivedRate = 0,
|
|
||||||
TransmittedPrct = 0,
|
|
||||||
TransmittedBytes = 0,
|
|
||||||
TransmittedRate = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
Mocker.GetMock<IHttpClient>()
|
|
||||||
.Setup(s => s.Get(It.IsAny<HttpRequest>()))
|
|
||||||
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void GivenCategory()
|
|
||||||
{
|
|
||||||
_settings.Category = _category;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void GivenDestinationDirectory()
|
|
||||||
{
|
|
||||||
_settings.DestinationDirectory = _destinationDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void GivenDownloadConfiguration()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
|
||||||
.Setup(s => s.GetDownloadConfiguration(It.IsAny<FreeboxDownloadSettings>()))
|
|
||||||
.Returns(_downloadConfiguration);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void GivenTasks(List<FreeboxDownloadTask> torrents)
|
|
||||||
{
|
|
||||||
if (torrents == null)
|
|
||||||
{
|
|
||||||
torrents = new List<FreeboxDownloadTask>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
|
||||||
.Setup(s => s.GetTasks(It.IsAny<FreeboxDownloadSettings>()))
|
|
||||||
.Returns(torrents);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void PrepareClientToReturnQueuedItem()
|
|
||||||
{
|
|
||||||
_task.Status = FreeboxDownloadTaskStatus.Queued;
|
|
||||||
|
|
||||||
GivenTasks(new List<FreeboxDownloadTask>
|
|
||||||
{
|
|
||||||
_task
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void GivenSuccessfulDownload()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IHttpClient>()
|
|
||||||
.Setup(s => s.Get(It.IsAny<HttpRequest>()))
|
|
||||||
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[1000]));
|
|
||||||
|
|
||||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
|
||||||
.Setup(s => s.AddTaskFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()))
|
|
||||||
.Callback(PrepareClientToReturnQueuedItem);
|
|
||||||
|
|
||||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
|
||||||
.Setup(s => s.AddTaskFromFile(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()))
|
|
||||||
.Callback(PrepareClientToReturnQueuedItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override RemoteMovie CreateRemoteMovie()
|
|
||||||
{
|
|
||||||
var movie = base.CreateRemoteMovie();
|
|
||||||
|
|
||||||
movie.Release.DownloadUrl = _downloadURL;
|
|
||||||
|
|
||||||
return movie;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Download_with_DestinationDirectory_should_force_directory()
|
|
||||||
{
|
|
||||||
GivenDestinationDirectory();
|
|
||||||
GivenSuccessfulDownload();
|
|
||||||
|
|
||||||
var remoteMovie = CreateRemoteMovie();
|
|
||||||
|
|
||||||
Subject.Download(remoteMovie);
|
|
||||||
|
|
||||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
|
||||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _encodedDestinationDirectory, It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Download_with_Category_should_force_directory()
|
|
||||||
{
|
|
||||||
GivenDownloadConfiguration();
|
|
||||||
GivenCategory();
|
|
||||||
GivenSuccessfulDownload();
|
|
||||||
|
|
||||||
var remoteMovie = CreateRemoteMovie();
|
|
||||||
|
|
||||||
Subject.Download(remoteMovie);
|
|
||||||
|
|
||||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
|
||||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _encodedDefaultDestinationAndCategory, It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Download_without_DestinationDirectory_and_Category_should_use_default()
|
|
||||||
{
|
|
||||||
GivenDownloadConfiguration();
|
|
||||||
GivenSuccessfulDownload();
|
|
||||||
|
|
||||||
var remoteMovie = CreateRemoteMovie();
|
|
||||||
|
|
||||||
Subject.Download(remoteMovie);
|
|
||||||
|
|
||||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
|
||||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _encodedDefaultDestination, It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase(false, false)]
|
|
||||||
[TestCase(true, true)]
|
|
||||||
public void Download_should_pause_torrent_as_expected(bool addPausedSetting, bool toBePausedFlag)
|
|
||||||
{
|
|
||||||
_settings.AddPaused = addPausedSetting;
|
|
||||||
|
|
||||||
GivenDownloadConfiguration();
|
|
||||||
GivenSuccessfulDownload();
|
|
||||||
|
|
||||||
var remoteMovie = CreateRemoteMovie();
|
|
||||||
|
|
||||||
Subject.Download(remoteMovie);
|
|
||||||
|
|
||||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
|
||||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), It.IsAny<string>(), toBePausedFlag, It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase(0, (int)FreeboxDownloadPriority.First, (int)FreeboxDownloadPriority.First, true)]
|
|
||||||
[TestCase(0, (int)FreeboxDownloadPriority.Last, (int)FreeboxDownloadPriority.First, true)]
|
|
||||||
[TestCase(0, (int)FreeboxDownloadPriority.First, (int)FreeboxDownloadPriority.Last, false)]
|
|
||||||
[TestCase(0, (int)FreeboxDownloadPriority.Last, (int)FreeboxDownloadPriority.Last, false)]
|
|
||||||
[TestCase(22, (int)FreeboxDownloadPriority.First, (int)FreeboxDownloadPriority.First, true)]
|
|
||||||
[TestCase(22, (int)FreeboxDownloadPriority.Last, (int)FreeboxDownloadPriority.First, false)]
|
|
||||||
[TestCase(22, (int)FreeboxDownloadPriority.First, (int)FreeboxDownloadPriority.Last, true)]
|
|
||||||
[TestCase(22, (int)FreeboxDownloadPriority.Last, (int)FreeboxDownloadPriority.Last, false)]
|
|
||||||
public void Download_should_queue_torrent_first_as_expected(int ageDay, int olderPriority, int recentPriority, bool toBeQueuedFirstFlag)
|
|
||||||
{
|
|
||||||
_settings.OlderPriority = olderPriority;
|
|
||||||
_settings.RecentPriority = recentPriority;
|
|
||||||
|
|
||||||
GivenDownloadConfiguration();
|
|
||||||
GivenSuccessfulDownload();
|
|
||||||
|
|
||||||
var remoteMovie = CreateRemoteMovie();
|
|
||||||
|
|
||||||
remoteMovie.Movie.MovieMetadata.Value.PhysicalRelease = DateTime.UtcNow.AddDays(-ageDay);
|
|
||||||
|
|
||||||
Subject.Download(remoteMovie);
|
|
||||||
|
|
||||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
|
||||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), toBeQueuedFirstFlag, It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase(0, 0)]
|
|
||||||
[TestCase(1.5, 150)]
|
|
||||||
public void Download_should_define_seed_ratio_as_expected(double? providerSeedRatio, double? expectedSeedRatio)
|
|
||||||
{
|
|
||||||
GivenDownloadConfiguration();
|
|
||||||
GivenSuccessfulDownload();
|
|
||||||
|
|
||||||
var remoteMovie = CreateRemoteMovie();
|
|
||||||
|
|
||||||
remoteMovie.SeedConfiguration = new TorrentSeedConfiguration();
|
|
||||||
remoteMovie.SeedConfiguration.Ratio = providerSeedRatio;
|
|
||||||
|
|
||||||
Subject.Download(remoteMovie);
|
|
||||||
|
|
||||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
|
||||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), expectedSeedRatio, It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetItems_should_return_empty_list_if_no_tasks_available()
|
|
||||||
{
|
|
||||||
GivenTasks(new List<FreeboxDownloadTask>());
|
|
||||||
|
|
||||||
Subject.GetItems().Should().BeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetItems_should_return_ignore_tasks_of_unknown_type()
|
|
||||||
{
|
|
||||||
_task.Status = FreeboxDownloadTaskStatus.Done;
|
|
||||||
_task.Type = "toto";
|
|
||||||
|
|
||||||
GivenTasks(new List<FreeboxDownloadTask> { _task });
|
|
||||||
|
|
||||||
Subject.GetItems().Should().BeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetItems_when_destinationdirectory_is_set_should_ignore_downloads_in_wrong_folder()
|
|
||||||
{
|
|
||||||
_settings.DestinationDirectory = @"/some/path/that/will/not/match";
|
|
||||||
|
|
||||||
_task.Status = FreeboxDownloadTaskStatus.Done;
|
|
||||||
|
|
||||||
GivenTasks(new List<FreeboxDownloadTask> { _task });
|
|
||||||
|
|
||||||
Subject.GetItems().Should().BeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetItems_when_category_is_set_should_ignore_downloads_in_wrong_folder()
|
|
||||||
{
|
|
||||||
_settings.Category = "somecategory";
|
|
||||||
|
|
||||||
_task.Status = FreeboxDownloadTaskStatus.Done;
|
|
||||||
|
|
||||||
GivenTasks(new List<FreeboxDownloadTask> { _task });
|
|
||||||
|
|
||||||
Subject.GetItems().Should().BeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Downloading, false, false)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Done, true, true)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Seeding, false, false)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Stopped, false, false)]
|
|
||||||
public void GetItems_should_return_canBeMoved_and_canBeDeleted_as_expected(FreeboxDownloadTaskStatus apiStatus, bool canMoveFilesExpected, bool canBeRemovedExpected)
|
|
||||||
{
|
|
||||||
_task.Status = apiStatus;
|
|
||||||
|
|
||||||
GivenTasks(new List<FreeboxDownloadTask>() { _task });
|
|
||||||
|
|
||||||
var items = Subject.GetItems();
|
|
||||||
|
|
||||||
items.Should().HaveCount(1);
|
|
||||||
items.First().CanBeRemoved.Should().Be(canBeRemovedExpected);
|
|
||||||
items.First().CanMoveFiles.Should().Be(canMoveFilesExpected);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Stopped, DownloadItemStatus.Paused)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Stopping, DownloadItemStatus.Paused)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Queued, DownloadItemStatus.Queued)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Starting, DownloadItemStatus.Downloading)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Downloading, DownloadItemStatus.Downloading)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Retry, DownloadItemStatus.Downloading)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Checking, DownloadItemStatus.Downloading)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Error, DownloadItemStatus.Warning)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Seeding, DownloadItemStatus.Completed)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Done, DownloadItemStatus.Completed)]
|
|
||||||
[TestCase(FreeboxDownloadTaskStatus.Unknown, DownloadItemStatus.Downloading)]
|
|
||||||
public void GetItems_should_return_item_as_downloadItemStatus(FreeboxDownloadTaskStatus apiStatus, DownloadItemStatus expectedItemStatus)
|
|
||||||
{
|
|
||||||
_task.Status = apiStatus;
|
|
||||||
|
|
||||||
GivenTasks(new List<FreeboxDownloadTask>() { _task });
|
|
||||||
|
|
||||||
var items = Subject.GetItems();
|
|
||||||
|
|
||||||
items.Should().HaveCount(1);
|
|
||||||
items.First().Status.Should().Be(expectedItemStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetItems_should_return_decoded_destination_directory()
|
|
||||||
{
|
|
||||||
var decodedDownloadDirectory = "/that/the/path";
|
|
||||||
|
|
||||||
_task.Status = FreeboxDownloadTaskStatus.Done;
|
|
||||||
_task.DownloadDirectory = "L3RoYXQvdGhlL3BhdGg=";
|
|
||||||
|
|
||||||
GivenTasks(new List<FreeboxDownloadTask> { _task });
|
|
||||||
|
|
||||||
var items = Subject.GetItems();
|
|
||||||
|
|
||||||
items.Should().HaveCount(1);
|
|
||||||
items.First().OutputPath.Should().Be(decodedDownloadDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetItems_should_return_message_if_tasks_in_error()
|
|
||||||
{
|
|
||||||
_task.Status = FreeboxDownloadTaskStatus.Error;
|
|
||||||
_task.Error = "internal";
|
|
||||||
|
|
||||||
GivenTasks(new List<FreeboxDownloadTask> { _task });
|
|
||||||
|
|
||||||
var items = Subject.GetItems();
|
|
||||||
|
|
||||||
items.Should().HaveCount(1);
|
|
||||||
items.First().Message.Should().Be("Internal error.");
|
|
||||||
items.First().Status.Should().Be(DownloadItemStatus.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
_downloadClients = new List<IDownloadClient>();
|
_downloadClients = new List<IDownloadClient>();
|
||||||
|
|
||||||
Mocker.GetMock<IProvideDownloadClient>()
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
.Setup(v => v.GetDownloadClients(It.IsAny<bool>()))
|
.Setup(v => v.GetDownloadClients())
|
||||||
.Returns(_downloadClients);
|
.Returns(_downloadClients);
|
||||||
|
|
||||||
Mocker.GetMock<IProvideDownloadClient>()
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
.With(h => h.Title = title)
|
.With(h => h.Title = title)
|
||||||
.With(h => h.Release = release)
|
.With(h => h.Release = release)
|
||||||
.With(h => h.Reason = reason)
|
.With(h => h.Reason = reason)
|
||||||
.With(h => h.ParsedMovieInfo = _parsedMovieInfo)
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_heldReleases.AddRange(heldReleases);
|
_heldReleases.AddRange(heldReleases);
|
||||||
|
|||||||
-1
@@ -52,7 +52,6 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
_pending.Add(new PendingRelease
|
_pending.Add(new PendingRelease
|
||||||
{
|
{
|
||||||
Id = id,
|
Id = id,
|
||||||
Title = "Movie.Title.2020.720p-Radarr",
|
|
||||||
ParsedMovieInfo = new ParsedMovieInfo { MovieTitles = new List<string> { title }, Year = year },
|
ParsedMovieInfo = new ParsedMovieInfo { MovieTitles = new List<string> { title }, Year = year },
|
||||||
MovieId = _movie.Id
|
MovieId = _movie.Id
|
||||||
});
|
});
|
||||||
|
|||||||
-1
@@ -93,7 +93,6 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
.With(h => h.MovieId = _movie.Id)
|
.With(h => h.MovieId = _movie.Id)
|
||||||
.With(h => h.Title = title)
|
.With(h => h.Title = title)
|
||||||
.With(h => h.Release = release)
|
.With(h => h.Release = release)
|
||||||
.With(h => h.ParsedMovieInfo = _parsedMovieInfo)
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
Mocker.GetMock<IPendingReleaseRepository>()
|
Mocker.GetMock<IPendingReleaseRepository>()
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||||||
public void should_return_warning_when_download_client_has_not_been_configured()
|
public void should_return_warning_when_download_client_has_not_been_configured()
|
||||||
{
|
{
|
||||||
Mocker.GetMock<IProvideDownloadClient>()
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
.Setup(s => s.GetDownloadClients())
|
||||||
.Returns(Array.Empty<IDownloadClient>());
|
.Returns(Array.Empty<IDownloadClient>());
|
||||||
|
|
||||||
Subject.Check().ShouldBeWarning();
|
Subject.Check().ShouldBeWarning();
|
||||||
@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||||||
.Throws<Exception>();
|
.Throws<Exception>();
|
||||||
|
|
||||||
Mocker.GetMock<IProvideDownloadClient>()
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
.Setup(s => s.GetDownloadClients())
|
||||||
.Returns(new IDownloadClient[] { downloadClient.Object });
|
.Returns(new IDownloadClient[] { downloadClient.Object });
|
||||||
|
|
||||||
Subject.Check().ShouldBeError();
|
Subject.Check().ShouldBeError();
|
||||||
@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||||||
.Returns(new List<DownloadClientItem>());
|
.Returns(new List<DownloadClientItem>());
|
||||||
|
|
||||||
Mocker.GetMock<IProvideDownloadClient>()
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
.Setup(s => s.GetDownloadClients())
|
||||||
.Returns(new IDownloadClient[] { downloadClient.Object });
|
.Returns(new IDownloadClient[] { downloadClient.Object });
|
||||||
|
|
||||||
Subject.Check().ShouldBeOk();
|
Subject.Check().ShouldBeOk();
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||||||
.Returns(_clientStatus);
|
.Returns(_clientStatus);
|
||||||
|
|
||||||
Mocker.GetMock<IProvideDownloadClient>()
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
.Setup(s => s.GetDownloadClients())
|
||||||
.Returns(new IDownloadClient[] { _downloadClient.Object });
|
.Returns(new IDownloadClient[] { _downloadClient.Object });
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Moq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Common.Disk;
|
|
||||||
using NzbDrone.Core.Download;
|
|
||||||
using NzbDrone.Core.Download.Clients;
|
|
||||||
using NzbDrone.Core.HealthCheck.Checks;
|
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.RootFolders;
|
|
||||||
using NzbDrone.Core.Test.Framework;
|
|
||||||
using NzbDrone.Test.Common;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class DownloadClientFolderCheckFixture : CoreTest<DownloadClientSortingCheck>
|
|
||||||
{
|
|
||||||
private DownloadClientInfo _clientStatus;
|
|
||||||
private Mock<IDownloadClient> _downloadClient;
|
|
||||||
|
|
||||||
private static Exception[] DownloadClientExceptions =
|
|
||||||
{
|
|
||||||
new DownloadClientUnavailableException("error"),
|
|
||||||
new DownloadClientAuthenticationException("error"),
|
|
||||||
new DownloadClientException("error")
|
|
||||||
};
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<ILocalizationService>()
|
|
||||||
.Setup(s => s.GetLocalizedString(It.IsAny<string>()))
|
|
||||||
.Returns("Some Warning Message");
|
|
||||||
|
|
||||||
_clientStatus = new DownloadClientInfo
|
|
||||||
{
|
|
||||||
IsLocalhost = true,
|
|
||||||
SortingMode = null
|
|
||||||
};
|
|
||||||
|
|
||||||
_downloadClient = Mocker.GetMock<IDownloadClient>();
|
|
||||||
_downloadClient.Setup(s => s.Definition)
|
|
||||||
.Returns(new DownloadClientDefinition { Name = "Test" });
|
|
||||||
|
|
||||||
_downloadClient.Setup(s => s.GetStatus())
|
|
||||||
.Returns(_clientStatus);
|
|
||||||
|
|
||||||
Mocker.GetMock<IProvideDownloadClient>()
|
|
||||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
|
||||||
.Returns(new IDownloadClient[] { _downloadClient.Object });
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_ok_if_sorting_is_not_enabled()
|
|
||||||
{
|
|
||||||
Subject.Check().ShouldBeOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_warning_if_sorting_is_enabled()
|
|
||||||
{
|
|
||||||
_clientStatus.SortingMode = "TV";
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeWarning();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
[TestCaseSource("DownloadClientExceptions")]
|
|
||||||
public void should_return_ok_if_client_throws_downloadclientexception(Exception ex)
|
|
||||||
{
|
|
||||||
_downloadClient.Setup(s => s.GetStatus())
|
|
||||||
.Throws(ex);
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeOk();
|
|
||||||
|
|
||||||
ExceptionVerification.ExpectedErrors(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||||||
.Returns(_clientStatus);
|
.Returns(_clientStatus);
|
||||||
|
|
||||||
Mocker.GetMock<IProvideDownloadClient>()
|
Mocker.GetMock<IProvideDownloadClient>()
|
||||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
.Setup(s => s.GetDownloadClients())
|
||||||
.Returns(new IDownloadClient[] { _downloadClient.Object });
|
.Returns(new IDownloadClient[] { _downloadClient.Object });
|
||||||
|
|
||||||
Mocker.GetMock<IConfigService>()
|
Mocker.GetMock<IConfigService>()
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
@@ -14,10 +13,10 @@ using NzbDrone.Core.Test.Framework;
|
|||||||
namespace NzbDrone.Core.Test.NotificationTests
|
namespace NzbDrone.Core.Test.NotificationTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TraktServiceFixture : CoreTest<Trakt>
|
public class TraktServiceFixture : CoreTest<TraktService>
|
||||||
{
|
{
|
||||||
private DownloadMessage _downloadMessage;
|
private DownloadMessage _downloadMessage;
|
||||||
private NotificationDefinition _traktDefinition;
|
private TraktSettings _traktSettings;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
@@ -35,17 +34,11 @@ namespace NzbDrone.Core.Test.NotificationTests
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_traktDefinition = new NotificationDefinition
|
_traktSettings = new TraktSettings
|
||||||
{
|
{
|
||||||
Settings = new TraktSettings
|
AccessToken = "",
|
||||||
{
|
RefreshToken = ""
|
||||||
AccessToken = "",
|
|
||||||
RefreshToken = "",
|
|
||||||
Expires = DateTime.Now.AddDays(1)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Subject.Definition = _traktDefinition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GiventValidMediaInfo(Quality quality, string audioChannels, string audioFormat, string scanType)
|
private void GiventValidMediaInfo(Quality quality, string audioChannels, string audioFormat, string scanType)
|
||||||
@@ -63,7 +56,7 @@ namespace NzbDrone.Core.Test.NotificationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_add_collection_movie_if_null_mediainfo()
|
public void should_add_collection_movie_if_null_mediainfo()
|
||||||
{
|
{
|
||||||
Subject.OnDownload(_downloadMessage);
|
Subject.AddMovieToCollection(_traktSettings, _downloadMessage.Movie, _downloadMessage.MovieFile);
|
||||||
|
|
||||||
Mocker.GetMock<ITraktProxy>()
|
Mocker.GetMock<ITraktProxy>()
|
||||||
.Verify(v => v.AddToCollection(It.IsAny<TraktCollectMoviesResource>(), It.IsAny<string>()), Times.Once());
|
.Verify(v => v.AddToCollection(It.IsAny<TraktCollectMoviesResource>(), It.IsAny<string>()), Times.Once());
|
||||||
@@ -74,7 +67,7 @@ namespace NzbDrone.Core.Test.NotificationTests
|
|||||||
{
|
{
|
||||||
GiventValidMediaInfo(Quality.Bluray1080p, "5.1", "DTS", "Progressive");
|
GiventValidMediaInfo(Quality.Bluray1080p, "5.1", "DTS", "Progressive");
|
||||||
|
|
||||||
Subject.OnDownload(_downloadMessage);
|
Subject.AddMovieToCollection(_traktSettings, _downloadMessage.Movie, _downloadMessage.MovieFile);
|
||||||
|
|
||||||
Mocker.GetMock<ITraktProxy>()
|
Mocker.GetMock<ITraktProxy>()
|
||||||
.Verify(v => v.AddToCollection(It.Is<TraktCollectMoviesResource>(t =>
|
.Verify(v => v.AddToCollection(It.Is<TraktCollectMoviesResource>(t =>
|
||||||
@@ -90,7 +83,7 @@ namespace NzbDrone.Core.Test.NotificationTests
|
|||||||
{
|
{
|
||||||
GiventValidMediaInfo(Quality.Bluray1080p, "2.0", "DTS", "Progressive");
|
GiventValidMediaInfo(Quality.Bluray1080p, "2.0", "DTS", "Progressive");
|
||||||
|
|
||||||
Subject.OnDownload(_downloadMessage);
|
Subject.AddMovieToCollection(_traktSettings, _downloadMessage.Movie, _downloadMessage.MovieFile);
|
||||||
|
|
||||||
Mocker.GetMock<ITraktProxy>()
|
Mocker.GetMock<ITraktProxy>()
|
||||||
.Verify(v => v.AddToCollection(It.Is<TraktCollectMoviesResource>(t =>
|
.Verify(v => v.AddToCollection(It.Is<TraktCollectMoviesResource>(t =>
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Movie.Title.1990.Ultimate.Rekall.Edition.NORDiC.REMUX.1080p.BluRay.AVC.DTS-HD.MA5.1-TWA", "Ultimate Rekall Edition")]
|
[TestCase("Movie.Title.1990.Ultimate.Rekall.Edition.NORDiC.REMUX.1080p.BluRay.AVC.DTS-HD.MA5.1-TWA", "Ultimate Rekall Edition")]
|
||||||
[TestCase("Movie.Title.1971.Signature.Edition.1080p.BluRay.FLAC.2.0.x264-TDD", "Signature Edition")]
|
[TestCase("Movie.Title.1971.Signature.Edition.1080p.BluRay.FLAC.2.0.x264-TDD", "Signature Edition")]
|
||||||
[TestCase("Movie.1979.The.Imperial.Edition.BluRay.720p.DTS.x264-CtrlHD", "Imperial Edition")]
|
[TestCase("Movie.1979.The.Imperial.Edition.BluRay.720p.DTS.x264-CtrlHD", "Imperial Edition")]
|
||||||
[TestCase("Movie.1997.Open.Matte.1080p.BluRay.x264.DTS-FGT", "Open Matte")]
|
|
||||||
public void should_parse_edition(string postTitle, string edition)
|
public void should_parse_edition(string postTitle, string edition)
|
||||||
{
|
{
|
||||||
var parsed = Parser.Parser.ParseMovieTitle(postTitle);
|
var parsed = Parser.Parser.ParseMovieTitle(postTitle);
|
||||||
|
|||||||
@@ -455,7 +455,6 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Movie.Title.2016.1080p.KORSUBS.WEBRip.x264.AAC2.0-RADARR", "KORSUBS")]
|
[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 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.2017.720p.SUBBED.HDRip.V2.XViD-26k.avi", "Generic Hardcoded Subs")]
|
||||||
[TestCase("Movie.Title.2000.1080p.BlueRay.x264.DTS.RoSubbed-playHD", null)]
|
|
||||||
[TestCase("Movie Title! 2018 [Web][MKV][h264][480p][AAC 2.0][Softsubs]", null)]
|
[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)]
|
[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)
|
public void should_parse_hardcoded_subs(string postTitle, string sub)
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ namespace NzbDrone.Core.Configuration
|
|||||||
|
|
||||||
public string LogLevel => GetValue("LogLevel", "info").ToLowerInvariant();
|
public string LogLevel => GetValue("LogLevel", "info").ToLowerInvariant();
|
||||||
public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false);
|
public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false);
|
||||||
public string Theme => GetValue("Theme", "auto", persist: false);
|
public string Theme => GetValue("Theme", "light", persist: false);
|
||||||
public string PostgresHost => _postgresOptions?.Host ?? GetValue("PostgresHost", string.Empty, persist: false);
|
public string PostgresHost => _postgresOptions?.Host ?? GetValue("PostgresHost", string.Empty, persist: false);
|
||||||
public string PostgresUser => _postgresOptions?.User ?? GetValue("PostgresUser", string.Empty, persist: false);
|
public string PostgresUser => _postgresOptions?.User ?? GetValue("PostgresUser", string.Empty, persist: false);
|
||||||
public string PostgresPassword => _postgresOptions?.Password ?? GetValue("PostgresPassword", string.Empty, persist: false);
|
public string PostgresPassword => _postgresOptions?.Password ?? GetValue("PostgresPassword", string.Empty, persist: false);
|
||||||
|
|||||||
@@ -144,13 +144,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((isQualityUpgrade || isCustomFormatUpgrade) && !qualityProfile.UpgradeAllowed)
|
return false;
|
||||||
{
|
|
||||||
_logger.Debug("Quality profile does not allow upgrades, skipping");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,22 +132,22 @@ namespace NzbDrone.Core.Download.Clients.Flood
|
|||||||
item.RemainingTime = TimeSpan.FromSeconds(properties.Eta);
|
item.RemainingTime = TimeSpan.FromSeconds(properties.Eta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (properties.Status.Contains("seeding") || properties.Status.Contains("complete"))
|
if (properties.Status.Contains("error"))
|
||||||
{
|
|
||||||
item.Status = DownloadItemStatus.Completed;
|
|
||||||
}
|
|
||||||
else if (properties.Status.Contains("stopped"))
|
|
||||||
{
|
|
||||||
item.Status = DownloadItemStatus.Paused;
|
|
||||||
}
|
|
||||||
else if (properties.Status.Contains("error"))
|
|
||||||
{
|
{
|
||||||
item.Status = DownloadItemStatus.Warning;
|
item.Status = DownloadItemStatus.Warning;
|
||||||
}
|
}
|
||||||
|
else if (properties.Status.Contains("seeding") || properties.Status.Contains("complete"))
|
||||||
|
{
|
||||||
|
item.Status = DownloadItemStatus.Completed;
|
||||||
|
}
|
||||||
else if (properties.Status.Contains("downloading"))
|
else if (properties.Status.Contains("downloading"))
|
||||||
{
|
{
|
||||||
item.Status = DownloadItemStatus.Downloading;
|
item.Status = DownloadItemStatus.Downloading;
|
||||||
}
|
}
|
||||||
|
else if (properties.Status.Contains("stopped"))
|
||||||
|
{
|
||||||
|
item.Status = DownloadItemStatus.Paused;
|
||||||
|
}
|
||||||
|
|
||||||
if (item.Status == DownloadItemStatus.Completed)
|
if (item.Status == DownloadItemStatus.Completed)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
namespace NzbDrone.Core.Download.Clients.FreeboxDownload
|
|
||||||
{
|
|
||||||
public static class EncodingForBase64
|
|
||||||
{
|
|
||||||
public static string EncodeBase64(this string text)
|
|
||||||
{
|
|
||||||
if (text == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] textAsBytes = System.Text.Encoding.UTF8.GetBytes(text);
|
|
||||||
return System.Convert.ToBase64String(textAsBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string DecodeBase64(this string encodedText)
|
|
||||||
{
|
|
||||||
if (encodedText == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] textAsBytes = System.Convert.FromBase64String(encodedText);
|
|
||||||
return System.Text.Encoding.UTF8.GetString(textAsBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
namespace NzbDrone.Core.Download.Clients.FreeboxDownload
|
|
||||||
{
|
|
||||||
public class FreeboxDownloadException : DownloadClientException
|
|
||||||
{
|
|
||||||
public FreeboxDownloadException(string message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace NzbDrone.Core.Download.Clients.FreeboxDownload
|
|
||||||
{
|
|
||||||
public enum FreeboxDownloadPriority
|
|
||||||
{
|
|
||||||
Last = 0,
|
|
||||||
First = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.Cache;
|
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Common.Http;
|
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
using NzbDrone.Core.Download.Clients.FreeboxDownload.Responses;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.FreeboxDownload
|
|
||||||
{
|
|
||||||
public interface IFreeboxDownloadProxy
|
|
||||||
{
|
|
||||||
void Authenticate(FreeboxDownloadSettings settings);
|
|
||||||
string AddTaskFromUrl(string url, string directory, bool addPaused, bool addFirst, double? seedRatio, FreeboxDownloadSettings settings);
|
|
||||||
string AddTaskFromFile(string fileName, byte[] fileContent, string directory, bool addPaused, bool addFirst, double? seedRatio, FreeboxDownloadSettings settings);
|
|
||||||
void DeleteTask(string id, bool deleteData, FreeboxDownloadSettings settings);
|
|
||||||
FreeboxDownloadConfiguration GetDownloadConfiguration(FreeboxDownloadSettings settings);
|
|
||||||
List<FreeboxDownloadTask> GetTasks(FreeboxDownloadSettings settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FreeboxDownloadProxy : IFreeboxDownloadProxy
|
|
||||||
{
|
|
||||||
private readonly IHttpClient _httpClient;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
private ICached<string> _authSessionTokenCache;
|
|
||||||
|
|
||||||
public FreeboxDownloadProxy(ICacheManager cacheManager, IHttpClient httpClient, Logger logger)
|
|
||||||
{
|
|
||||||
_httpClient = httpClient;
|
|
||||||
_logger = logger;
|
|
||||||
_authSessionTokenCache = cacheManager.GetCache<string>(GetType(), "authSessionToken");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Authenticate(FreeboxDownloadSettings settings)
|
|
||||||
{
|
|
||||||
var request = BuildRequest(settings).Resource("/login").Build();
|
|
||||||
|
|
||||||
var response = ProcessRequest<FreeboxLogin>(request, settings);
|
|
||||||
|
|
||||||
if (response.Result.LoggedIn == false)
|
|
||||||
{
|
|
||||||
throw new DownloadClientAuthenticationException("Not logged");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string AddTaskFromUrl(string url, string directory, bool addPaused, bool addFirst, double? seedRatio, FreeboxDownloadSettings settings)
|
|
||||||
{
|
|
||||||
var request = BuildRequest(settings).Resource("/downloads/add").Post();
|
|
||||||
request.Headers.ContentType = "application/x-www-form-urlencoded";
|
|
||||||
|
|
||||||
request.AddFormParameter("download_url", System.Web.HttpUtility.UrlPathEncode(url));
|
|
||||||
|
|
||||||
if (!directory.IsNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
request.AddFormParameter("download_dir", directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = ProcessRequest<FreeboxDownloadTask>(request.Build(), settings);
|
|
||||||
|
|
||||||
SetTorrentSettings(response.Result.Id, addPaused, addFirst, seedRatio, settings);
|
|
||||||
|
|
||||||
return response.Result.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string AddTaskFromFile(string fileName, byte[] fileContent, string directory, bool addPaused, bool addFirst, double? seedRatio, FreeboxDownloadSettings settings)
|
|
||||||
{
|
|
||||||
var request = BuildRequest(settings).Resource("/downloads/add").Post();
|
|
||||||
|
|
||||||
request.AddFormUpload("download_file", fileName, fileContent, "multipart/form-data");
|
|
||||||
|
|
||||||
if (directory.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
request.AddFormParameter("download_dir", directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = ProcessRequest<FreeboxDownloadTask>(request.Build(), settings);
|
|
||||||
|
|
||||||
SetTorrentSettings(response.Result.Id, addPaused, addFirst, seedRatio, settings);
|
|
||||||
|
|
||||||
return response.Result.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeleteTask(string id, bool deleteData, FreeboxDownloadSettings settings)
|
|
||||||
{
|
|
||||||
var uri = "/downloads/" + id;
|
|
||||||
|
|
||||||
if (deleteData == true)
|
|
||||||
{
|
|
||||||
uri += "/erase";
|
|
||||||
}
|
|
||||||
|
|
||||||
var request = BuildRequest(settings).Resource(uri).Build();
|
|
||||||
|
|
||||||
request.Method = HttpMethod.Delete;
|
|
||||||
|
|
||||||
ProcessRequest<string>(request, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FreeboxDownloadConfiguration GetDownloadConfiguration(FreeboxDownloadSettings settings)
|
|
||||||
{
|
|
||||||
var request = BuildRequest(settings).Resource("/downloads/config/").Build();
|
|
||||||
|
|
||||||
return ProcessRequest<FreeboxDownloadConfiguration>(request, settings).Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<FreeboxDownloadTask> GetTasks(FreeboxDownloadSettings settings)
|
|
||||||
{
|
|
||||||
var request = BuildRequest(settings).Resource("/downloads/").Build();
|
|
||||||
|
|
||||||
return ProcessRequest<List<FreeboxDownloadTask>>(request, settings).Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string BuildCachedHeaderKey(FreeboxDownloadSettings settings)
|
|
||||||
{
|
|
||||||
return $"{settings.Host}:{settings.AppId}:{settings.AppToken}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetTorrentSettings(string id, bool addPaused, bool addFirst, double? seedRatio, FreeboxDownloadSettings settings)
|
|
||||||
{
|
|
||||||
var request = BuildRequest(settings).Resource("/downloads/" + id).Build();
|
|
||||||
|
|
||||||
request.Method = HttpMethod.Put;
|
|
||||||
|
|
||||||
var body = new Dictionary<string, object> { };
|
|
||||||
|
|
||||||
if (addPaused)
|
|
||||||
{
|
|
||||||
body.Add("status", FreeboxDownloadTaskStatus.Stopped.ToString().ToLower());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addFirst)
|
|
||||||
{
|
|
||||||
body.Add("queue_pos", "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seedRatio != null)
|
|
||||||
{
|
|
||||||
// 0 means unlimited seeding
|
|
||||||
body.Add("stop_ratio", seedRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (body.Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
request.SetContent(body.ToJson());
|
|
||||||
|
|
||||||
ProcessRequest<FreeboxDownloadTask>(request, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetSessionToken(HttpRequestBuilder requestBuilder, FreeboxDownloadSettings settings, bool force = false)
|
|
||||||
{
|
|
||||||
var sessionToken = _authSessionTokenCache.Find(BuildCachedHeaderKey(settings));
|
|
||||||
|
|
||||||
if (sessionToken == null || force)
|
|
||||||
{
|
|
||||||
_authSessionTokenCache.Remove(BuildCachedHeaderKey(settings));
|
|
||||||
|
|
||||||
_logger.Debug($"Client needs a new Session Token to reach the API with App ID '{settings.AppId}'");
|
|
||||||
|
|
||||||
// Obtaining a Session Token (from official documentation):
|
|
||||||
// To protect the app_token secret, it will never be used directly to authenticate the
|
|
||||||
// application, instead the API will provide a challenge the app will combine to its
|
|
||||||
// app_token to open a session and get a session_token.
|
|
||||||
// The validity of the session_token is limited in time and the app will have to renew
|
|
||||||
// this session_token once in a while.
|
|
||||||
|
|
||||||
// Retrieving the 'challenge' value (it changes frequently and have a limited time validity)
|
|
||||||
// needed to build password
|
|
||||||
var challengeRequest = requestBuilder.Resource("/login").Build();
|
|
||||||
challengeRequest.Method = HttpMethod.Get;
|
|
||||||
|
|
||||||
var challenge = ProcessRequest<FreeboxLogin>(challengeRequest, settings).Result.Challenge;
|
|
||||||
|
|
||||||
// The password is computed using the 'challenge' value and the 'app_token' ('App Token' setting)
|
|
||||||
var enc = System.Text.Encoding.ASCII;
|
|
||||||
var hmac = new HMACSHA1(enc.GetBytes(settings.AppToken));
|
|
||||||
hmac.Initialize();
|
|
||||||
var buffer = enc.GetBytes(challenge);
|
|
||||||
var password = System.BitConverter.ToString(hmac.ComputeHash(buffer)).Replace("-", "").ToLower();
|
|
||||||
|
|
||||||
// Both 'app_id' ('App ID' setting) and computed password are set to get a Session Token
|
|
||||||
var sessionRequest = requestBuilder.Resource("/login/session").Post().Build();
|
|
||||||
var body = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{ "app_id", settings.AppId },
|
|
||||||
{ "password", password }
|
|
||||||
};
|
|
||||||
sessionRequest.SetContent(body.ToJson());
|
|
||||||
|
|
||||||
sessionToken = ProcessRequest<FreeboxLogin>(sessionRequest, settings).Result.SessionToken;
|
|
||||||
|
|
||||||
_authSessionTokenCache.Set(BuildCachedHeaderKey(settings), sessionToken);
|
|
||||||
|
|
||||||
_logger.Debug($"New Session Token stored in cache for App ID '{settings.AppId}', ready to reach API");
|
|
||||||
}
|
|
||||||
|
|
||||||
return sessionToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpRequestBuilder BuildRequest(FreeboxDownloadSettings settings, bool authentication = true)
|
|
||||||
{
|
|
||||||
var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port, settings.ApiUrl)
|
|
||||||
{
|
|
||||||
LogResponseContent = true
|
|
||||||
};
|
|
||||||
|
|
||||||
requestBuilder.Headers.ContentType = "application/json";
|
|
||||||
|
|
||||||
if (authentication == true)
|
|
||||||
{
|
|
||||||
requestBuilder.SetHeader("X-Fbx-App-Auth", GetSessionToken(requestBuilder, settings));
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FreeboxResponse<T> ProcessRequest<T>(HttpRequest request, FreeboxDownloadSettings settings)
|
|
||||||
{
|
|
||||||
request.LogResponseContent = true;
|
|
||||||
request.SuppressHttpError = true;
|
|
||||||
|
|
||||||
HttpResponse response;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
response = _httpClient.Execute(request);
|
|
||||||
}
|
|
||||||
catch (HttpRequestException ex)
|
|
||||||
{
|
|
||||||
throw new DownloadClientUnavailableException($"Unable to reach Freebox API. Verify 'Host', 'Port' or 'Use SSL' settings. (Error: {ex.Message})", ex);
|
|
||||||
}
|
|
||||||
catch (WebException ex)
|
|
||||||
{
|
|
||||||
throw new DownloadClientUnavailableException("Unable to connect to Freebox API, please check your settings", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.StatusCode == HttpStatusCode.Forbidden || response.StatusCode == HttpStatusCode.Unauthorized)
|
|
||||||
{
|
|
||||||
_authSessionTokenCache.Remove(BuildCachedHeaderKey(settings));
|
|
||||||
|
|
||||||
var responseContent = Json.Deserialize<FreeboxResponse<FreeboxLogin>>(response.Content);
|
|
||||||
|
|
||||||
var msg = $"Authentication to Freebox API failed. Reason: {responseContent.GetErrorDescription()}";
|
|
||||||
_logger.Error(msg);
|
|
||||||
throw new DownloadClientAuthenticationException(msg);
|
|
||||||
}
|
|
||||||
else if (response.StatusCode == HttpStatusCode.NotFound)
|
|
||||||
{
|
|
||||||
throw new FreeboxDownloadException("Unable to reach Freebox API. Verify 'API URL' setting for base URL and version.");
|
|
||||||
}
|
|
||||||
else if (response.StatusCode == HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
var responseContent = Json.Deserialize<FreeboxResponse<T>>(response.Content);
|
|
||||||
|
|
||||||
if (responseContent.Success)
|
|
||||||
{
|
|
||||||
return responseContent;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var msg = $"Freebox API returned error: {responseContent.GetErrorDescription()}";
|
|
||||||
_logger.Error(msg);
|
|
||||||
throw new DownloadClientException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new DownloadClientException("Unable to connect to Freebox, please check your settings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
using System.Text.RegularExpressions;
|
|
||||||
using FluentValidation;
|
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Core.Annotations;
|
|
||||||
using NzbDrone.Core.ThingiProvider;
|
|
||||||
using NzbDrone.Core.Validation;
|
|
||||||
using NzbDrone.Core.Validation.Paths;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.FreeboxDownload
|
|
||||||
{
|
|
||||||
public class FreeboxDownloadSettingsValidator : AbstractValidator<FreeboxDownloadSettings>
|
|
||||||
{
|
|
||||||
public FreeboxDownloadSettingsValidator()
|
|
||||||
{
|
|
||||||
RuleFor(c => c.Host).ValidHost();
|
|
||||||
RuleFor(c => c.Port).InclusiveBetween(1, 65535);
|
|
||||||
RuleFor(c => c.ApiUrl).NotEmpty()
|
|
||||||
.WithMessage("'API URL' must not be empty.");
|
|
||||||
RuleFor(c => c.ApiUrl).ValidUrlBase();
|
|
||||||
RuleFor(c => c.AppId).NotEmpty()
|
|
||||||
.WithMessage("'App ID' must not be empty.");
|
|
||||||
RuleFor(c => c.AppToken).NotEmpty()
|
|
||||||
.WithMessage("'App Token' must not be empty.");
|
|
||||||
RuleFor(c => c.Category).Matches(@"^\.?[-a-z]*$", RegexOptions.IgnoreCase)
|
|
||||||
.WithMessage("Allowed characters a-z and -");
|
|
||||||
RuleFor(c => c.DestinationDirectory).IsValidPath()
|
|
||||||
.When(c => c.DestinationDirectory.IsNotNullOrWhiteSpace());
|
|
||||||
RuleFor(c => c.DestinationDirectory).Empty()
|
|
||||||
.When(c => c.Category.IsNotNullOrWhiteSpace())
|
|
||||||
.WithMessage("Cannot use 'Category' and 'Destination Directory' at the same time.");
|
|
||||||
RuleFor(c => c.Category).Empty()
|
|
||||||
.When(c => c.DestinationDirectory.IsNotNullOrWhiteSpace())
|
|
||||||
.WithMessage("Cannot use 'Category' and 'Destination Directory' at the same time.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FreeboxDownloadSettings : IProviderConfig
|
|
||||||
{
|
|
||||||
private static readonly FreeboxDownloadSettingsValidator Validator = new FreeboxDownloadSettingsValidator();
|
|
||||||
|
|
||||||
public FreeboxDownloadSettings()
|
|
||||||
{
|
|
||||||
Host = "mafreebox.freebox.fr";
|
|
||||||
Port = 443;
|
|
||||||
UseSsl = true;
|
|
||||||
ApiUrl = "/api/v1/";
|
|
||||||
}
|
|
||||||
|
|
||||||
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox, HelpText = "Hostname or host IP address of the Freebox, defaults to 'mafreebox.freebox.fr' (will only work if on same network)")]
|
|
||||||
public string Host { get; set; }
|
|
||||||
|
|
||||||
[FieldDefinition(1, Label = "Port", Type = FieldType.Textbox, HelpText = "Port used to access Freebox interface, defaults to '443'")]
|
|
||||||
public int Port { get; set; }
|
|
||||||
|
|
||||||
[FieldDefinition(2, Label = "Use SSL", Type = FieldType.Checkbox, HelpText = "Use secured connection when connecting to Freebox API")]
|
|
||||||
public bool UseSsl { get; set; }
|
|
||||||
|
|
||||||
[FieldDefinition(3, Label = "API URL", Type = FieldType.Textbox, Advanced = true, HelpText = "Define Freebox API base URL with API version, eg http://[host]:[port]/[api_base_url]/[api_version]/, defaults to '/api/v1/'")]
|
|
||||||
public string ApiUrl { get; set; }
|
|
||||||
|
|
||||||
[FieldDefinition(4, Label = "App ID", Type = FieldType.Textbox, HelpText = "App ID given when creating access to Freebox API (ie 'app_id')")]
|
|
||||||
public string AppId { get; set; }
|
|
||||||
|
|
||||||
[FieldDefinition(5, Label = "App Token", Type = FieldType.Password, Privacy = PrivacyLevel.Password, HelpText = "App token retrieved when creating access to Freebox API (ie 'app_token')")]
|
|
||||||
public string AppToken { get; set; }
|
|
||||||
|
|
||||||
[FieldDefinition(6, Label = "Destination Directory", Type = FieldType.Textbox, Advanced = true, HelpText = "Optional location to put downloads in, leave blank to use the default Freebox download location")]
|
|
||||||
public string DestinationDirectory { get; set; }
|
|
||||||
|
|
||||||
[FieldDefinition(7, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated non-Sonarr downloads (will create a [category] subdirectory in the output directory)")]
|
|
||||||
public string Category { get; set; }
|
|
||||||
|
|
||||||
[FieldDefinition(8, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(FreeboxDownloadPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]
|
|
||||||
public int RecentPriority { get; set; }
|
|
||||||
|
|
||||||
[FieldDefinition(9, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(FreeboxDownloadPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")]
|
|
||||||
public int OlderPriority { get; set; }
|
|
||||||
|
|
||||||
[FieldDefinition(10, Label = "Add Paused", Type = FieldType.Checkbox)]
|
|
||||||
public bool AddPaused { get; set; }
|
|
||||||
|
|
||||||
public NzbDroneValidationResult Validate()
|
|
||||||
{
|
|
||||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.FreeboxDownload.Responses
|
|
||||||
{
|
|
||||||
public class FreeboxDownloadConfiguration
|
|
||||||
{
|
|
||||||
[JsonProperty(PropertyName = "download_dir")]
|
|
||||||
public string DownloadDirectory { get; set; }
|
|
||||||
public string DecodedDownloadDirectory
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return DownloadDirectory.DecodeBase64();
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
DownloadDirectory = value.EncodeBase64();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.FreeboxDownload.Responses
|
|
||||||
{
|
|
||||||
public enum FreeboxDownloadTaskType
|
|
||||||
{
|
|
||||||
Bt,
|
|
||||||
Nzb,
|
|
||||||
Http,
|
|
||||||
Ftp
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum FreeboxDownloadTaskStatus
|
|
||||||
{
|
|
||||||
Unknown,
|
|
||||||
Stopped,
|
|
||||||
Queued,
|
|
||||||
Starting,
|
|
||||||
Downloading,
|
|
||||||
Stopping,
|
|
||||||
Error,
|
|
||||||
Done,
|
|
||||||
Checking,
|
|
||||||
Repairing,
|
|
||||||
Extracting,
|
|
||||||
Seeding,
|
|
||||||
Retry
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum FreeboxDownloadTaskIoPriority
|
|
||||||
{
|
|
||||||
Low,
|
|
||||||
Normal,
|
|
||||||
High
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FreeboxDownloadTask
|
|
||||||
{
|
|
||||||
private static readonly Dictionary<string, string> Descriptions;
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "id")]
|
|
||||||
public string Id { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "name")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "download_dir")]
|
|
||||||
public string DownloadDirectory { get; set; }
|
|
||||||
public string DecodedDownloadDirectory
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return DownloadDirectory.DecodeBase64();
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
DownloadDirectory = value.EncodeBase64();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "info_hash")]
|
|
||||||
public string InfoHash { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "queue_pos")]
|
|
||||||
public int QueuePosition { get; set; }
|
|
||||||
[JsonConverter(typeof(UnderscoreStringEnumConverter), FreeboxDownloadTaskStatus.Unknown)]
|
|
||||||
public FreeboxDownloadTaskStatus Status { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "eta")]
|
|
||||||
public long Eta { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "error")]
|
|
||||||
public string Error { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "type")]
|
|
||||||
public string Type { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "io_priority")]
|
|
||||||
public string IoPriority { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "stop_ratio")]
|
|
||||||
public long StopRatio { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "piece_length")]
|
|
||||||
public long PieceLength { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "created_ts")]
|
|
||||||
public long CreatedTimestamp { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "size")]
|
|
||||||
public long Size { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "rx_pct")]
|
|
||||||
public long ReceivedPrct { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "rx_bytes")]
|
|
||||||
public long ReceivedBytes { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "rx_rate")]
|
|
||||||
public long ReceivedRate { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "tx_pct")]
|
|
||||||
public long TransmittedPrct { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "tx_bytes")]
|
|
||||||
public long TransmittedBytes { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "tx_rate")]
|
|
||||||
public long TransmittedRate { get; set; }
|
|
||||||
|
|
||||||
static FreeboxDownloadTask()
|
|
||||||
{
|
|
||||||
Descriptions = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "internal", "Internal error." },
|
|
||||||
{ "disk_full", "The disk is full." },
|
|
||||||
{ "unknown", "Unknown error." },
|
|
||||||
{ "parse_error", "Parse error." },
|
|
||||||
{ "unknown_host", "Unknown host." },
|
|
||||||
{ "timeout", "Timeout." },
|
|
||||||
{ "bad_authentication", "Invalid credentials." },
|
|
||||||
{ "connection_refused", "Remote host refused connection." },
|
|
||||||
{ "bt_tracker_error", "Unable to announce on tracker." },
|
|
||||||
{ "bt_missing_files", "Missing torrent files." },
|
|
||||||
{ "bt_file_error", "Error accessing torrent files." },
|
|
||||||
{ "missing_ctx_file", "Error accessing task context file." },
|
|
||||||
{ "nzb_no_group", "Cannot find the requested group on server." },
|
|
||||||
{ "nzb_not_found", "Article not fount on the server." },
|
|
||||||
{ "nzb_invalid_crc", "Invalid article CRC." },
|
|
||||||
{ "nzb_invalid_size", "Invalid article size." },
|
|
||||||
{ "nzb_invalid_filename", "Invalid filename." },
|
|
||||||
{ "nzb_open_failed", "Error opening." },
|
|
||||||
{ "nzb_write_failed", "Error writing." },
|
|
||||||
{ "nzb_missing_size", "Missing article size." },
|
|
||||||
{ "nzb_decode_error", "Article decoding error." },
|
|
||||||
{ "nzb_missing_segments", "Missing article segments." },
|
|
||||||
{ "nzb_error", "Other nzb error." },
|
|
||||||
{ "nzb_authentication_required", "Nzb server need authentication." }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetErrorDescription()
|
|
||||||
{
|
|
||||||
if (Descriptions.ContainsKey(Error))
|
|
||||||
{
|
|
||||||
return Descriptions[Error];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"{Error} - Unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.FreeboxDownload.Responses
|
|
||||||
{
|
|
||||||
public class FreeboxLogin
|
|
||||||
{
|
|
||||||
[JsonProperty(PropertyName = "logged_in")]
|
|
||||||
public bool LoggedIn { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "challenge")]
|
|
||||||
public string Challenge { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "password_salt")]
|
|
||||||
public string PasswordSalt { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "password_set")]
|
|
||||||
public bool PasswordSet { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "session_token")]
|
|
||||||
public string SessionToken { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.FreeboxDownload.Responses
|
|
||||||
{
|
|
||||||
public class FreeboxResponse<T>
|
|
||||||
{
|
|
||||||
private static readonly Dictionary<string, string> Descriptions;
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "success")]
|
|
||||||
public bool Success { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "msg")]
|
|
||||||
public string Message { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "error_code")]
|
|
||||||
public string ErrorCode { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "result")]
|
|
||||||
public T Result { get; set; }
|
|
||||||
|
|
||||||
static FreeboxResponse()
|
|
||||||
{
|
|
||||||
Descriptions = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
// Common errors
|
|
||||||
{ "invalid_request", "Your request is invalid." },
|
|
||||||
{ "invalid_api_version", "Invalid API base url or unknown API version." },
|
|
||||||
{ "internal_error", "Internal error." },
|
|
||||||
|
|
||||||
// Login API errors
|
|
||||||
{ "auth_required", "Invalid session token, or no session token sent." },
|
|
||||||
{ "invalid_token", "The app token you are trying to use is invalid or has been revoked." },
|
|
||||||
{ "pending_token", "The app token you are trying to use has not been validated by user yet." },
|
|
||||||
{ "insufficient_rights", "Your app permissions does not allow accessing this API." },
|
|
||||||
{ "denied_from_external_ip", "You are trying to get an app_token from a remote IP." },
|
|
||||||
{ "ratelimited", "Too many auth error have been made from your IP." },
|
|
||||||
{ "new_apps_denied", "New application token request has been disabled." },
|
|
||||||
{ "apps_denied", "API access from apps has been disabled." },
|
|
||||||
|
|
||||||
// Download API errors
|
|
||||||
{ "task_not_found", "No task was found with the given id." },
|
|
||||||
{ "invalid_operation", "Attempt to perform an invalid operation." },
|
|
||||||
{ "invalid_file", "Error with the download file (invalid format ?)." },
|
|
||||||
{ "invalid_url", "URL is invalid." },
|
|
||||||
{ "not_implemented", "Method not implemented." },
|
|
||||||
{ "out_of_memory", "No more memory available to perform the requested action." },
|
|
||||||
{ "invalid_task_type", "The task type is invalid." },
|
|
||||||
{ "hibernating", "The downloader is hibernating." },
|
|
||||||
{ "need_bt_stopped_done", "This action is only valid for Bittorrent task in stopped or done state." },
|
|
||||||
{ "bt_tracker_not_found", "Attempt to access an invalid tracker object." },
|
|
||||||
{ "too_many_tasks", "Too many tasks." },
|
|
||||||
{ "invalid_address", "Invalid peer address." },
|
|
||||||
{ "port_conflict", "Port conflict when setting config." },
|
|
||||||
{ "invalid_priority", "Invalid priority." },
|
|
||||||
{ "ctx_file_error", "Failed to initialize task context file (need to check disk)." },
|
|
||||||
{ "exists", "Same task already exists." },
|
|
||||||
{ "port_outside_range", "Incoming port is not available for this customer." }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetErrorDescription()
|
|
||||||
{
|
|
||||||
if (Descriptions.ContainsKey(ErrorCode))
|
|
||||||
{
|
|
||||||
return Descriptions[ErrorCode];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"{ErrorCode} - Unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using FluentValidation.Results;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.Cache;
|
|
||||||
using NzbDrone.Common.Disk;
|
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Common.Http;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
using NzbDrone.Core.Download.Clients.FreeboxDownload.Responses;
|
|
||||||
using NzbDrone.Core.Download.Clients.QBittorrent;
|
|
||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
|
||||||
using NzbDrone.Core.Organizer;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.FreeboxDownload
|
|
||||||
{
|
|
||||||
public class TorrentFreeboxDownload : TorrentClientBase<FreeboxDownloadSettings>
|
|
||||||
{
|
|
||||||
private readonly IFreeboxDownloadProxy _proxy;
|
|
||||||
|
|
||||||
public TorrentFreeboxDownload(IFreeboxDownloadProxy proxy,
|
|
||||||
ITorrentFileInfoReader torrentFileInfoReader,
|
|
||||||
IHttpClient httpClient,
|
|
||||||
IConfigService configService,
|
|
||||||
INamingConfigService namingConfigService,
|
|
||||||
IDiskProvider diskProvider,
|
|
||||||
IRemotePathMappingService remotePathMappingService,
|
|
||||||
ICacheManager cacheManager,
|
|
||||||
Logger logger)
|
|
||||||
: base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
|
|
||||||
{
|
|
||||||
_proxy = proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string Name => "Freebox Download";
|
|
||||||
|
|
||||||
protected IEnumerable<FreeboxDownloadTask> GetTorrents()
|
|
||||||
{
|
|
||||||
return _proxy.GetTasks(Settings).Where(v => v.Type.ToLower() == FreeboxDownloadTaskType.Bt.ToString().ToLower());
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<DownloadClientItem> GetItems()
|
|
||||||
{
|
|
||||||
var torrents = GetTorrents();
|
|
||||||
|
|
||||||
var queueItems = new List<DownloadClientItem>();
|
|
||||||
|
|
||||||
foreach (var torrent in torrents)
|
|
||||||
{
|
|
||||||
var outputPath = new OsPath(torrent.DecodedDownloadDirectory);
|
|
||||||
|
|
||||||
if (Settings.DestinationDirectory.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
if (!new OsPath(Settings.DestinationDirectory).Contains(outputPath))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Settings.Category.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
var directories = outputPath.FullPath.Split('\\', '/');
|
|
||||||
|
|
||||||
if (!directories.Contains(Settings.Category))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var item = new DownloadClientItem()
|
|
||||||
{
|
|
||||||
DownloadId = torrent.Id,
|
|
||||||
Category = Settings.Category,
|
|
||||||
Title = torrent.Name,
|
|
||||||
TotalSize = torrent.Size,
|
|
||||||
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
|
|
||||||
RemainingSize = (long)(torrent.Size * (double)(1 - ((double)torrent.ReceivedPrct / 10000))),
|
|
||||||
RemainingTime = torrent.Eta <= 0 ? null : TimeSpan.FromSeconds(torrent.Eta),
|
|
||||||
SeedRatio = torrent.StopRatio <= 0 ? 0 : torrent.StopRatio / 100,
|
|
||||||
OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, outputPath)
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (torrent.Status)
|
|
||||||
{
|
|
||||||
case FreeboxDownloadTaskStatus.Stopped: // task is stopped, can be resumed by setting the status to downloading
|
|
||||||
case FreeboxDownloadTaskStatus.Stopping: // task is gracefully stopping
|
|
||||||
item.Status = DownloadItemStatus.Paused;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FreeboxDownloadTaskStatus.Queued: // task will start when a new download slot is available the queue position is stored in queue_pos attribute
|
|
||||||
item.Status = DownloadItemStatus.Queued;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FreeboxDownloadTaskStatus.Starting: // task is preparing to start download
|
|
||||||
case FreeboxDownloadTaskStatus.Downloading:
|
|
||||||
case FreeboxDownloadTaskStatus.Retry: // you can set a task status to ‘retry’ to restart the download task.
|
|
||||||
case FreeboxDownloadTaskStatus.Checking: // checking data before lauching download.
|
|
||||||
item.Status = DownloadItemStatus.Downloading;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FreeboxDownloadTaskStatus.Error: // there was a problem with the download, you can get an error code in the error field
|
|
||||||
item.Status = DownloadItemStatus.Warning;
|
|
||||||
item.Message = torrent.GetErrorDescription();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FreeboxDownloadTaskStatus.Done: // the download is over. For bt you can resume seeding setting the status to seeding if the ratio is not reached yet
|
|
||||||
case FreeboxDownloadTaskStatus.Seeding: // download is over, the content is Change to being shared to other users. The task will automatically stop once the seed ratio has been reached
|
|
||||||
item.Status = DownloadItemStatus.Completed;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FreeboxDownloadTaskStatus.Unknown:
|
|
||||||
default: // new status in API? default to downloading
|
|
||||||
item.Message = "Unknown download state: " + torrent.Status;
|
|
||||||
_logger.Info(item.Message);
|
|
||||||
item.Status = DownloadItemStatus.Downloading;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.CanBeRemoved = item.CanMoveFiles = torrent.Status == FreeboxDownloadTaskStatus.Done;
|
|
||||||
|
|
||||||
queueItems.Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return queueItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
|
|
||||||
{
|
|
||||||
return _proxy.AddTaskFromUrl(magnetLink,
|
|
||||||
GetDownloadDirectory().EncodeBase64(),
|
|
||||||
ToBePaused(),
|
|
||||||
ToBeQueuedFirst(remoteMovie),
|
|
||||||
GetSeedRatio(remoteMovie),
|
|
||||||
Settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, byte[] fileContent)
|
|
||||||
{
|
|
||||||
return _proxy.AddTaskFromFile(filename,
|
|
||||||
fileContent,
|
|
||||||
GetDownloadDirectory().EncodeBase64(),
|
|
||||||
ToBePaused(),
|
|
||||||
ToBeQueuedFirst(remoteMovie),
|
|
||||||
GetSeedRatio(remoteMovie),
|
|
||||||
Settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void RemoveItem(DownloadClientItem item, bool deleteData)
|
|
||||||
{
|
|
||||||
_proxy.DeleteTask(item.DownloadId, deleteData, Settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override DownloadClientInfo GetStatus()
|
|
||||||
{
|
|
||||||
var destDir = GetDownloadDirectory();
|
|
||||||
|
|
||||||
return new DownloadClientInfo
|
|
||||||
{
|
|
||||||
IsLocalhost = Settings.Host == "127.0.0.1" || Settings.Host == "::1" || Settings.Host == "localhost",
|
|
||||||
OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(destDir)) }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Test(List<ValidationFailure> failures)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_proxy.Authenticate(Settings);
|
|
||||||
}
|
|
||||||
catch (DownloadClientUnavailableException ex)
|
|
||||||
{
|
|
||||||
failures.Add(new ValidationFailure("Host", ex.Message));
|
|
||||||
failures.Add(new ValidationFailure("Port", ex.Message));
|
|
||||||
}
|
|
||||||
catch (DownloadClientAuthenticationException ex)
|
|
||||||
{
|
|
||||||
failures.Add(new ValidationFailure("AppId", ex.Message));
|
|
||||||
failures.Add(new ValidationFailure("AppToken", ex.Message));
|
|
||||||
}
|
|
||||||
catch (FreeboxDownloadException ex)
|
|
||||||
{
|
|
||||||
failures.Add(new ValidationFailure("ApiUrl", ex.Message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetDownloadDirectory()
|
|
||||||
{
|
|
||||||
if (Settings.DestinationDirectory.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
return Settings.DestinationDirectory.TrimEnd('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
var destDir = _proxy.GetDownloadConfiguration(Settings).DecodedDownloadDirectory.TrimEnd('/');
|
|
||||||
|
|
||||||
if (Settings.Category.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
destDir = $"{destDir}/{Settings.Category}";
|
|
||||||
}
|
|
||||||
|
|
||||||
return destDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ToBePaused()
|
|
||||||
{
|
|
||||||
return Settings.AddPaused;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ToBeQueuedFirst(RemoteMovie remoteMovie)
|
|
||||||
{
|
|
||||||
var isRecentMovie = remoteMovie.Movie.MovieMetadata.Value.IsRecentMovie;
|
|
||||||
|
|
||||||
if ((isRecentMovie && Settings.RecentPriority == (int)FreeboxDownloadPriority.First) ||
|
|
||||||
(!isRecentMovie && Settings.OlderPriority == (int)FreeboxDownloadPriority.First))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private double? GetSeedRatio(RemoteMovie remoteMovie)
|
|
||||||
{
|
|
||||||
if (remoteMovie.SeedConfiguration == null || remoteMovie.SeedConfiguration.Ratio == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return remoteMovie.SeedConfiguration.Ratio.Value * 100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,11 +45,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
|
||||||
{
|
|
||||||
throw new DownloadClientException("Failed to connect to qBittorrent. Check your settings and qBittorrent configuration.", new HttpException(response));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.HasHttpError)
|
if (response.HasHttpError)
|
||||||
{
|
{
|
||||||
throw new DownloadClientException("Failed to connect to qBittorrent, check your settings.", new HttpException(response));
|
throw new DownloadClientException("Failed to connect to qBittorrent, check your settings.", new HttpException(response));
|
||||||
|
|||||||
@@ -262,19 +262,6 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||||||
|
|
||||||
if (category != null)
|
if (category != null)
|
||||||
{
|
{
|
||||||
if (config.Misc.enable_tv_sorting && ContainsCategory(config.Misc.tv_categories, Settings.MovieCategory))
|
|
||||||
{
|
|
||||||
status.SortingMode = "TV";
|
|
||||||
}
|
|
||||||
else if (config.Misc.enable_movie_sorting && ContainsCategory(config.Misc.movie_categories, Settings.MovieCategory))
|
|
||||||
{
|
|
||||||
status.SortingMode = "Movie";
|
|
||||||
}
|
|
||||||
else if (config.Misc.enable_date_sorting && ContainsCategory(config.Misc.date_categories, Settings.MovieCategory))
|
|
||||||
{
|
|
||||||
status.SortingMode = "Date";
|
|
||||||
}
|
|
||||||
|
|
||||||
status.OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, category.FullPath) };
|
status.OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, category.FullPath) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download
|
namespace NzbDrone.Core.Download
|
||||||
@@ -11,7 +11,6 @@ namespace NzbDrone.Core.Download
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool IsLocalhost { get; set; }
|
public bool IsLocalhost { get; set; }
|
||||||
public string SortingMode { get; set; }
|
|
||||||
public List<OsPath> OutputRootFolders { get; set; }
|
public List<OsPath> OutputRootFolders { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace NzbDrone.Core.Download
|
|||||||
public interface IProvideDownloadClient
|
public interface IProvideDownloadClient
|
||||||
{
|
{
|
||||||
IDownloadClient GetDownloadClient(DownloadProtocol downloadProtocol, int indexerId = 0);
|
IDownloadClient GetDownloadClient(DownloadProtocol downloadProtocol, int indexerId = 0);
|
||||||
IEnumerable<IDownloadClient> GetDownloadClients(bool filterBlockedClients = false);
|
IEnumerable<IDownloadClient> GetDownloadClients();
|
||||||
IDownloadClient Get(int id);
|
IDownloadClient Get(int id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,39 +86,14 @@ namespace NzbDrone.Core.Download
|
|||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IDownloadClient> GetDownloadClients(bool filterBlockedClients = false)
|
public IEnumerable<IDownloadClient> GetDownloadClients()
|
||||||
{
|
{
|
||||||
var enabledClients = _downloadClientFactory.GetAvailableProviders();
|
return _downloadClientFactory.GetAvailableProviders();
|
||||||
|
|
||||||
if (filterBlockedClients)
|
|
||||||
{
|
|
||||||
return FilterBlockedIndexers(enabledClients).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return enabledClients;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDownloadClient Get(int id)
|
public IDownloadClient Get(int id)
|
||||||
{
|
{
|
||||||
return _downloadClientFactory.GetAvailableProviders().Single(d => d.Definition.Id == id);
|
return _downloadClientFactory.GetAvailableProviders().Single(d => d.Definition.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<IDownloadClient> FilterBlockedIndexers(IEnumerable<IDownloadClient> clients)
|
|
||||||
{
|
|
||||||
var blockedClients = _downloadClientStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v);
|
|
||||||
|
|
||||||
foreach (var client in clients)
|
|
||||||
{
|
|
||||||
DownloadClientStatus blockedClientStatus;
|
|
||||||
|
|
||||||
if (blockedClients.TryGetValue(client.Definition.Id, out blockedClientStatus))
|
|
||||||
{
|
|
||||||
_logger.Debug("Temporarily ignoring client {0} till {1} due to recent failures.", client.Definition.Name, blockedClientStatus.DisabledTill.Value.ToLocalTime());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return client;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ namespace NzbDrone.Core.Download
|
|||||||
movieGrabbedEvent.DownloadId = downloadClientId;
|
movieGrabbedEvent.DownloadId = downloadClientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.ProgressInfo("Report for {0} ({1}) sent to {2} from indexer {3}. {4}", remoteMovie.Movie.Title, remoteMovie.Movie.Year, downloadClient.Definition.Name, remoteMovie.Release.Indexer, downloadTitle);
|
_logger.ProgressInfo("Report sent to {0} from indexer {1}. {2}", downloadClient.Definition.Name, remoteMovie.Release.Indexer, downloadTitle);
|
||||||
_eventAggregator.PublishEvent(movieGrabbedEvent);
|
_eventAggregator.PublishEvent(movieGrabbedEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -283,12 +283,6 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Languages will be empty if added before upgrading to v4, reparsing the languages if they're empty will set it to Unknown or better.
|
|
||||||
if (release.ParsedMovieInfo.Languages.Empty())
|
|
||||||
{
|
|
||||||
release.ParsedMovieInfo.Languages = LanguageParser.ParseLanguages(release.Title);
|
|
||||||
}
|
|
||||||
|
|
||||||
release.RemoteMovie = new RemoteMovie
|
release.RemoteMovie = new RemoteMovie
|
||||||
{
|
{
|
||||||
Movie = movie,
|
Movie = movie,
|
||||||
|
|||||||
@@ -5,7 +5,5 @@ namespace NzbDrone.Core.Download
|
|||||||
public class ProcessMonitoredDownloadsCommand : Command
|
public class ProcessMonitoredDownloadsCommand : Command
|
||||||
{
|
{
|
||||||
public override bool RequiresDiskAccess => true;
|
public override bool RequiresDiskAccess => true;
|
||||||
|
|
||||||
public override bool IsLongRunning => true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -343,12 +343,9 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
|||||||
|
|
||||||
if (movieFile.MediaInfo.Subtitles != null && movieFile.MediaInfo.Subtitles.Count > 0)
|
if (movieFile.MediaInfo.Subtitles != null && movieFile.MediaInfo.Subtitles.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var s in movieFile.MediaInfo.Subtitles)
|
var subtitle = new XElement("subtitle");
|
||||||
{
|
subtitle.Add(new XElement("language", movieFile.MediaInfo.Subtitles));
|
||||||
var subtitle = new XElement("subtitle");
|
streamDetails.Add(subtitle);
|
||||||
subtitle.Add(new XElement("language", s));
|
|
||||||
streamDetails.Add(subtitle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fileInfo.Add(streamDetails);
|
fileInfo.Add(streamDetails);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
@@ -38,9 +37,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
|||||||
|
|
||||||
public override HealthCheck Check()
|
public override HealthCheck Check()
|
||||||
{
|
{
|
||||||
// Only check clients not in failure status, those get another message
|
var clients = _downloadClientProvider.GetDownloadClients();
|
||||||
var clients = _downloadClientProvider.GetDownloadClients(true);
|
|
||||||
|
|
||||||
var rootFolders = _rootFolderService.All();
|
var rootFolders = _rootFolderService.All();
|
||||||
|
|
||||||
foreach (var client in clients)
|
foreach (var client in clients)
|
||||||
@@ -61,10 +58,6 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
|||||||
{
|
{
|
||||||
_logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name);
|
_logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name);
|
||||||
}
|
}
|
||||||
catch (HttpRequestException ex)
|
|
||||||
{
|
|
||||||
_logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.Error(ex, "Unknown error occured in DownloadClientRootFolderCheck HealthCheck");
|
_logger.Error(ex, "Unknown error occured in DownloadClientRootFolderCheck HealthCheck");
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
using System;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Core.Datastore.Events;
|
|
||||||
using NzbDrone.Core.Download;
|
|
||||||
using NzbDrone.Core.Download.Clients;
|
|
||||||
using NzbDrone.Core.Localization;
|
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
|
||||||
using NzbDrone.Core.RootFolders;
|
|
||||||
using NzbDrone.Core.ThingiProvider.Events;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.HealthCheck.Checks
|
|
||||||
{
|
|
||||||
[CheckOn(typeof(ProviderUpdatedEvent<IDownloadClient>))]
|
|
||||||
[CheckOn(typeof(ProviderDeletedEvent<IDownloadClient>))]
|
|
||||||
[CheckOn(typeof(ModelEvent<RootFolder>))]
|
|
||||||
[CheckOn(typeof(ModelEvent<RemotePathMapping>))]
|
|
||||||
|
|
||||||
public class DownloadClientSortingCheck : HealthCheckBase
|
|
||||||
{
|
|
||||||
private readonly IProvideDownloadClient _downloadClientProvider;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
public DownloadClientSortingCheck(IProvideDownloadClient downloadClientProvider,
|
|
||||||
Logger logger,
|
|
||||||
ILocalizationService localizationService)
|
|
||||||
: base(localizationService)
|
|
||||||
{
|
|
||||||
_downloadClientProvider = downloadClientProvider;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override HealthCheck Check()
|
|
||||||
{
|
|
||||||
var clients = _downloadClientProvider.GetDownloadClients();
|
|
||||||
|
|
||||||
foreach (var client in clients)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var clientName = client.Definition.Name;
|
|
||||||
var status = client.GetStatus();
|
|
||||||
|
|
||||||
if (status.SortingMode.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("DownloadClientSortingCheckMessage"), clientName, status.SortingMode), "#download-folder-and-library-folder-not-different-folders");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (DownloadClientException ex)
|
|
||||||
{
|
|
||||||
_logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.Error(ex, "Unknown error occurred in DownloadClientSortingCheck HealthCheck");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new HealthCheck(GetType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
@@ -54,8 +53,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
|||||||
return new HealthCheck(GetType());
|
return new HealthCheck(GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only check clients not in failure status, those get another message
|
var clients = _downloadClientProvider.GetDownloadClients();
|
||||||
var clients = _downloadClientProvider.GetDownloadClients(true);
|
|
||||||
|
|
||||||
foreach (var client in clients)
|
foreach (var client in clients)
|
||||||
{
|
{
|
||||||
@@ -102,10 +100,6 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
|||||||
{
|
{
|
||||||
_logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name);
|
_logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name);
|
||||||
}
|
}
|
||||||
catch (HttpRequestException ex)
|
|
||||||
{
|
|
||||||
_logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.Error(ex, "Unknown error occured in RemotePathMapping HealthCheck");
|
_logger.Error(ex, "Unknown error occured in RemotePathMapping HealthCheck");
|
||||||
@@ -145,14 +139,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
|||||||
|
|
||||||
// If the previous case did not match then the failure occured in DownloadedMovieImportService,
|
// If the previous case did not match then the failure occured in DownloadedMovieImportService,
|
||||||
// while trying to locate the files reported by the download client
|
// while trying to locate the files reported by the download client
|
||||||
// Only check clients not in failure status, those get another message
|
var client = _downloadClientProvider.GetDownloadClients().FirstOrDefault(x => x.Definition.Name == failureMessage.DownloadClientInfo.Name);
|
||||||
var client = _downloadClientProvider.GetDownloadClients(true).FirstOrDefault(x => x.Definition.Name == failureMessage.DownloadClientInfo.Name);
|
|
||||||
|
|
||||||
if (client == null)
|
|
||||||
{
|
|
||||||
return new HealthCheck(GetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var status = client.GetStatus();
|
var status = client.GetStatus();
|
||||||
@@ -205,10 +192,6 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
|||||||
{
|
{
|
||||||
_logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name);
|
_logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name);
|
||||||
}
|
}
|
||||||
catch (HttpRequestException ex)
|
|
||||||
{
|
|
||||||
_logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.Error(ex, "Unknown error occured in RemotePathMapping HealthCheck");
|
_logger.Error(ex, "Unknown error occured in RemotePathMapping HealthCheck");
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace NzbDrone.Core.ImportLists.Trakt.List
|
|||||||
var listName = Parser.Parser.ToUrlSlug(Settings.Listname.Trim(), true, "-", "-");
|
var listName = Parser.Parser.ToUrlSlug(Settings.Listname.Trim(), true, "-", "-");
|
||||||
link += $"users/{Settings.Username.Trim()}/lists/{listName}/items/movies?limit={Settings.Limit}";
|
link += $"users/{Settings.Username.Trim()}/lists/{listName}/items/movies?limit={Settings.Limit}";
|
||||||
|
|
||||||
var request = new ImportListRequest(_traktProxy.BuildRequest(link, HttpMethod.Get, Settings.AccessToken));
|
var request = new ImportListRequest(_traktProxy.BuildTraktRequest(link, HttpMethod.Get, Settings.AccessToken));
|
||||||
|
|
||||||
yield return request;
|
yield return request;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
using NzbDrone.Core.ImportLists.ImportListMovies;
|
using NzbDrone.Core.ImportLists.ImportListMovies;
|
||||||
using NzbDrone.Core.Notifications.Trakt.Resource;
|
using NzbDrone.Core.Notifications.Trakt.Resource;
|
||||||
|
|
||||||
@@ -31,11 +31,11 @@ namespace NzbDrone.Core.ImportLists.Trakt.Popular
|
|||||||
|
|
||||||
if (_settings.TraktListType == (int)TraktPopularListType.Popular)
|
if (_settings.TraktListType == (int)TraktPopularListType.Popular)
|
||||||
{
|
{
|
||||||
jsonResponse = STJson.Deserialize<List<TraktMovieResource>>(_importResponse.Content);
|
jsonResponse = JsonConvert.DeserializeObject<List<TraktMovieResource>>(_importResponse.Content);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
jsonResponse = STJson.Deserialize<List<TraktListResource>>(_importResponse.Content).SelectList(c => c.Movie);
|
jsonResponse = JsonConvert.DeserializeObject<List<TraktListResource>>(_importResponse.Content).SelectList(c => c.Movie);
|
||||||
}
|
}
|
||||||
|
|
||||||
// no movies were return
|
// no movies were return
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace NzbDrone.Core.ImportLists.Trakt.Popular
|
|||||||
|
|
||||||
link += filtersAndLimit;
|
link += filtersAndLimit;
|
||||||
|
|
||||||
var request = new ImportListRequest(_traktProxy.BuildRequest(link, HttpMethod.Get, Settings.AccessToken));
|
var request = new ImportListRequest(_traktProxy.BuildTraktRequest(link, HttpMethod.Get, Settings.AccessToken));
|
||||||
|
|
||||||
yield return request;
|
yield return request;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
using NzbDrone.Core.ImportLists.Exceptions;
|
using NzbDrone.Core.ImportLists.Exceptions;
|
||||||
using NzbDrone.Core.ImportLists.ImportListMovies;
|
using NzbDrone.Core.ImportLists.ImportListMovies;
|
||||||
using NzbDrone.Core.Notifications.Trakt.Resource;
|
using NzbDrone.Core.Notifications.Trakt.Resource;
|
||||||
@@ -27,7 +27,7 @@ namespace NzbDrone.Core.ImportLists.Trakt
|
|||||||
return movies;
|
return movies;
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsonResponse = STJson.Deserialize<List<TraktListResource>>(_importResponse.Content);
|
var jsonResponse = JsonConvert.DeserializeObject<List<TraktListResource>>(_importResponse.Content);
|
||||||
|
|
||||||
// no movies were return
|
// no movies were return
|
||||||
if (jsonResponse == null)
|
if (jsonResponse == null)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace NzbDrone.Core.ImportLists.Trakt.User
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = new ImportListRequest(_traktProxy.BuildRequest(link, HttpMethod.Get, Settings.AccessToken));
|
var request = new ImportListRequest(_traktProxy.BuildTraktRequest(link, HttpMethod.Get, Settings.AccessToken));
|
||||||
|
|
||||||
yield return request;
|
yield return request;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using NzbDrone.Core.Messaging.Commands;
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers
|
namespace NzbDrone.Core.Indexers
|
||||||
{
|
{
|
||||||
public class RssSyncCommand : Command
|
public class RssSyncCommand : Command
|
||||||
{
|
{
|
||||||
public override bool SendUpdatesToClient => true;
|
public override bool SendUpdatesToClient => true;
|
||||||
|
|
||||||
public override bool IsLongRunning => true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1 @@
|
|||||||
{
|
{}
|
||||||
"About": "সম্পর্কিত",
|
|
||||||
"AcceptConfirmationModal": "নিশ্চিতকরণ মডেল গ্রহণ করুন",
|
|
||||||
"Actions": "ক্রিয়াকাণ্ড",
|
|
||||||
"Activity": "কার্যকলাপ",
|
|
||||||
"Add": "যোগ করুন"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"EditDelayProfile": "Upravit profil zpoždění",
|
"EditDelayProfile": "Upravit profil zpoždění",
|
||||||
"AcceptConfirmationModal": "Přijměte potvrzovací modální okno",
|
"AcceptConfirmationModal": "Přijměte potvrzení Modal",
|
||||||
"Automatic": "Automatický",
|
"Automatic": "Automatický",
|
||||||
"CertificateValidation": "Ověření certifikátu",
|
"CertificateValidation": "Ověření certifikátu",
|
||||||
"CertificateValidationHelpText": "Změňte přísnost ověřování certifikátů HTTPS. Neměňte, pokud nerozumíte rizikům.",
|
"CertificateValidationHelpText": "Změňte, jak přísné je ověření certifikace HTTPS",
|
||||||
"Cast": "Obsazení",
|
"Cast": "Obsazení",
|
||||||
"CheckDownloadClientForDetails": "zkontrolujte stahování klienta pro více informací",
|
"CheckDownloadClientForDetails": "zkontrolujte stahování klienta pro více informací",
|
||||||
"CheckForFinishedDownloadsInterval": "Zkontrolujte interval dokončených stahování",
|
"CheckForFinishedDownloadsInterval": "Zkontrolujte interval dokončených stahování",
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
"Ungroup": "Oddělit skupinu",
|
"Ungroup": "Oddělit skupinu",
|
||||||
"Unlimited": "Neomezený",
|
"Unlimited": "Neomezený",
|
||||||
"UnsavedChanges": "Neuložené změny",
|
"UnsavedChanges": "Neuložené změny",
|
||||||
"UpdateMechanismHelpText": "Použijte vestavěný aktualizační program Radarr nebo skript",
|
"UpdateMechanismHelpText": "Použijte vestavěný aktualizátor Radarr nebo skript",
|
||||||
"UpgradeUntilQuality": "Upgradujte až do kvality",
|
"UpgradeUntilQuality": "Upgradujte až do kvality",
|
||||||
"UseHardlinksInsteadOfCopy": "Místo kopírování použijte pevné odkazy",
|
"UseHardlinksInsteadOfCopy": "Místo kopírování použijte pevné odkazy",
|
||||||
"UsenetDelayTime": "Usenet Zpoždění: {0}",
|
"UsenetDelayTime": "Usenet Zpoždění: {0}",
|
||||||
@@ -157,12 +157,12 @@
|
|||||||
"Announced": "Oznámeno",
|
"Announced": "Oznámeno",
|
||||||
"AvailabilityDelayHelpText": "Množství času před nebo po dostupném datu pro vyhledání filmu",
|
"AvailabilityDelayHelpText": "Množství času před nebo po dostupném datu pro vyhledání filmu",
|
||||||
"ImportExistingMovies": "Importovat existující filmy",
|
"ImportExistingMovies": "Importovat existující filmy",
|
||||||
"AddedToDownloadQueue": "Přidáno do fronty ke stažení",
|
"AddedToDownloadQueue": "Přidáno do stažené fronty",
|
||||||
"AddNotification": "Přidat oznámení",
|
"AddNotification": "Přidat oznámení",
|
||||||
"Add": "Přidat",
|
"Add": "Přidat",
|
||||||
"AddCustomFormat": "Přidat vlastní formát",
|
"AddCustomFormat": "Přidat vlastní formát",
|
||||||
"AddDelayProfile": "Přidat profil zpoždění",
|
"AddDelayProfile": "Přidat profil zpoždění",
|
||||||
"AddDownloadClient": "Přidat klienta pro stahování",
|
"AddDownloadClient": "Přidat staženého klienta",
|
||||||
"AddRootFolder": "Přidat kořenovou složku",
|
"AddRootFolder": "Přidat kořenovou složku",
|
||||||
"Always": "Vždy",
|
"Always": "Vždy",
|
||||||
"AnalyticsEnabledHelpText": "Odesílejte anonymní informace o použití a chybách na servery Radarru. To zahrnuje informace o vašem prohlížeči, které stránky Radarr WebUI používáte, hlášení chyb a také verzi operačního systému a běhového prostředí. Tyto informace použijeme k upřednostnění funkcí a oprav chyb.",
|
"AnalyticsEnabledHelpText": "Odesílejte anonymní informace o použití a chybách na servery Radarru. To zahrnuje informace o vašem prohlížeči, které stránky Radarr WebUI používáte, hlášení chyb a také verzi operačního systému a běhového prostředí. Tyto informace použijeme k upřednostnění funkcí a oprav chyb.",
|
||||||
@@ -677,7 +677,7 @@
|
|||||||
"IMDb": "IMDb",
|
"IMDb": "IMDb",
|
||||||
"ImportCustomFormat": "Importujte vlastní formát",
|
"ImportCustomFormat": "Importujte vlastní formát",
|
||||||
"ImportedTo": "Importováno do",
|
"ImportedTo": "Importováno do",
|
||||||
"ImportRootPath": "Nasměrujte Radarr na složku obsahující všechny vaše filmy, ne na konkrétní film. Např. {0} a ne {1}. Kromě toho musí být každý film ve vlastní složce v rámci kořenové složky nebo knihovny.",
|
"ImportRootPath": "Namiřte Radarr na složku obsahující všechny vaše filmy, nikoli konkrétní film. např. {0} a ne {1}. Každý film musí být navíc ve své vlastní složce v kořenové složce / složce knihovny.",
|
||||||
"ImportTipsMessage": "Několik tipů, jak zajistit bezproblémový import:",
|
"ImportTipsMessage": "Několik tipů, jak zajistit bezproblémový import:",
|
||||||
"InCinemasDate": "V kinech",
|
"InCinemasDate": "V kinech",
|
||||||
"InCinemasMsg": "Film je v kinech",
|
"InCinemasMsg": "Film je v kinech",
|
||||||
@@ -687,13 +687,13 @@
|
|||||||
"IncludeUnmonitored": "Zahrnout Nesledováno",
|
"IncludeUnmonitored": "Zahrnout Nesledováno",
|
||||||
"ImportMovies": "Importovat filmy",
|
"ImportMovies": "Importovat filmy",
|
||||||
"IndexerPriority": "Priorita indexování",
|
"IndexerPriority": "Priorita indexování",
|
||||||
"IndexerPriorityHelpText": "Priorita indexovacího modulu od 1 (nejvyšší) do 50 (nejnižší). Výchozí: 25. Používá se při získávání verzí jako rozhodující prvek pro jinak stejné verze, Radarr bude stále používat všechny povolené indexovací moduly pro Synchronizaci RSS a vyhledávání",
|
"IndexerPriorityHelpText": "Priorita indexování od 1 (nejvyšší) do 50 (nejnižší). Výchozí: 25.",
|
||||||
"IndexerRssHealthCheckNoAvailableIndexers": "Všechny indexery podporující rss jsou dočasně nedostupné kvůli nedávným chybám indexeru",
|
"IndexerRssHealthCheckNoAvailableIndexers": "Všechny indexery podporující rss jsou dočasně nedostupné kvůli nedávným chybám indexeru",
|
||||||
"IndexerRssHealthCheckNoIndexers": "Nejsou k dispozici žádné indexery se zapnutou synchronizací RSS, Radarr nové verze automaticky nezachytí",
|
"IndexerRssHealthCheckNoIndexers": "Nejsou k dispozici žádné indexery se zapnutou synchronizací RSS, Radarr nové verze automaticky nezachytí",
|
||||||
"Indexers": "Indexery",
|
"Indexers": "Indexery",
|
||||||
"IndexerSearchCheckNoAutomaticMessage": "Nejsou k dispozici žádné indexery se zapnutým automatickým vyhledáváním, Radarr neposkytne žádné automatické výsledky hledání",
|
"IndexerSearchCheckNoAutomaticMessage": "Nejsou k dispozici žádné indexery se zapnutým automatickým vyhledáváním, Radarr neposkytne žádné automatické výsledky hledání",
|
||||||
"IndexerSearchCheckNoAvailableIndexersMessage": "Všechny indexery podporující vyhledávání jsou dočasně nedostupné kvůli nedávným chybám indexeru",
|
"IndexerSearchCheckNoAvailableIndexersMessage": "Všechny indexery podporující vyhledávání jsou dočasně nedostupné kvůli nedávným chybám indexeru",
|
||||||
"IndexerSearchCheckNoInteractiveMessage": "Při povoleném interaktivním vyhledávání, nejsou dostupné žádné indexovací moduly, Radarr neposkytne žádné interaktivní výsledky hledání",
|
"IndexerSearchCheckNoInteractiveMessage": "Pokud je povoleno interaktivní vyhledávání, nejsou k dispozici žádné indexery, Radarr neposkytne žádné interaktivní výsledky hledání",
|
||||||
"IndexerSettings": "Nastavení indexeru",
|
"IndexerSettings": "Nastavení indexeru",
|
||||||
"IndexerStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání: {0}",
|
"IndexerStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání: {0}",
|
||||||
"InstallLatest": "Nainstalujte nejnovější",
|
"InstallLatest": "Nainstalujte nejnovější",
|
||||||
@@ -1061,6 +1061,6 @@
|
|||||||
"AllCollectionsHiddenDueToFilter": "Všechny filmy jsou skryty kvůli použitému filtru.",
|
"AllCollectionsHiddenDueToFilter": "Všechny filmy jsou skryty kvůli použitému filtru.",
|
||||||
"Collections": "Sbírka",
|
"Collections": "Sbírka",
|
||||||
"MonitorMovies": "Monitorujte film",
|
"MonitorMovies": "Monitorujte film",
|
||||||
"NoCollections": "Nebyly nalezeny žádné kolekce, pro začátek budete chtít přidat nový film nebo importovat některé stávající",
|
"NoCollections": "Nebyly nalezeny žádné filmy. Chcete-li začít, budete chtít přidat nový film nebo importovat některé stávající.",
|
||||||
"RssSyncHelpText": "Interval v minutách. Nastavením na nulu deaktivujete (tím se zastaví veškeré automatické uvolnění uvolnění)"
|
"RssSyncHelpText": "Interval v minutách. Nastavením na nulu deaktivujete (tím se zastaví veškeré automatické uvolnění uvolnění)"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -329,17 +329,17 @@
|
|||||||
"BackupRetentionHelpText": "Automatische Backups, die älter als die Aufbewahrungsfrist sind, werden automatisch gelöscht",
|
"BackupRetentionHelpText": "Automatische Backups, die älter als die Aufbewahrungsfrist sind, werden automatisch gelöscht",
|
||||||
"Backups": "Backups",
|
"Backups": "Backups",
|
||||||
"BindAddress": "Adresse binden",
|
"BindAddress": "Adresse binden",
|
||||||
"BindAddressHelpText": "Gültige IP Adresse oder \"*\" für alle Netzwerke",
|
"BindAddressHelpText": "Gültige IPv4 Adresse oder \"*\" für alle Netzwerke",
|
||||||
"Branch": "Git-Branch",
|
"Branch": "Git-Branch",
|
||||||
"BypassProxyForLocalAddresses": "Proxy für lokale Adressen umgehen",
|
"BypassProxyForLocalAddresses": "Proxy für lokale Adressen umgehen",
|
||||||
"CertificateValidation": "Zertifikat Validierung",
|
"CertificateValidation": "Zertifikat Validierung",
|
||||||
"CertificateValidationHelpText": "Ändere wie streng die Validierung der HTTPS-Zertifizierung ist. Ändern Sie nicht wenn Ihnen die Risiken nicht bewusst sind.",
|
"CertificateValidationHelpText": "Ändere wie streng die Validierung der HTTPS-Zertifizierung ist. Nicht anpassen, außer du kennst das Risiko.",
|
||||||
"CertificationCountry": "Zertifizierungs Land",
|
"CertificationCountry": "Zertifizierungs Land",
|
||||||
"ChangeFileDate": "Erstelldatum der Datei anpassen",
|
"ChangeFileDate": "Erstelldatum der Datei anpassen",
|
||||||
"ChangeHasNotBeenSavedYet": "Änderung wurde noch nicht gespeichert",
|
"ChangeHasNotBeenSavedYet": "Änderung wurde noch nicht gespeichert",
|
||||||
"CheckForFinishedDownloadsInterval": "Intervall zum prüfen von fertigen Downloads",
|
"CheckForFinishedDownloadsInterval": "Intervall zum prüfen von fertigen Downloads",
|
||||||
"CleanLibraryLevel": "Mediathek aufräumen",
|
"CleanLibraryLevel": "Mediathek aufräumen",
|
||||||
"ClickToChangeLanguage": "Sprache ändern",
|
"ClickToChangeLanguage": "Sprache ändern ...",
|
||||||
"ClickToChangeQuality": "Hier klicken um die Qualität zu ändern",
|
"ClickToChangeQuality": "Hier klicken um die Qualität zu ändern",
|
||||||
"ClientPriority": "Priorität",
|
"ClientPriority": "Priorität",
|
||||||
"CloneFormatTag": "Format Tag kopieren",
|
"CloneFormatTag": "Format Tag kopieren",
|
||||||
@@ -516,7 +516,7 @@
|
|||||||
"ShowTitleHelpText": "Filmtitel unter dem Plakat anzeigen",
|
"ShowTitleHelpText": "Filmtitel unter dem Plakat anzeigen",
|
||||||
"ShowUnknownMovieItems": "Unzugeordente Filmeinträge anzeigen",
|
"ShowUnknownMovieItems": "Unzugeordente Filmeinträge anzeigen",
|
||||||
"SkipFreeSpaceCheck": "Pürfung des freien Speichers überspringen",
|
"SkipFreeSpaceCheck": "Pürfung des freien Speichers überspringen",
|
||||||
"SkipFreeSpaceCheckWhenImportingHelpText": "Aktiviere diese Option, wenn es Radarr nicht möglich ist, den freien Speicherplatz des Stammverzeichnisses für Filme zu erkennen",
|
"SkipFreeSpaceCheckWhenImportingHelpText": "Aktiviere diese Option, wenn es nicht möglich ist, den freien Speicherplatz des Stammverzeichnisses für Filme zu erkennen",
|
||||||
"SorryThatMovieCannotBeFound": "Schade, dieser Film kann nicht gefunden werden.",
|
"SorryThatMovieCannotBeFound": "Schade, dieser Film kann nicht gefunden werden.",
|
||||||
"SourcePath": "Quellpfad",
|
"SourcePath": "Quellpfad",
|
||||||
"SourceRelativePath": "Relativer Quellpfad",
|
"SourceRelativePath": "Relativer Quellpfad",
|
||||||
@@ -531,7 +531,7 @@
|
|||||||
"TestAllIndexers": "Alle testen",
|
"TestAllIndexers": "Alle testen",
|
||||||
"TestAllLists": "Alle testen",
|
"TestAllLists": "Alle testen",
|
||||||
"TimeFormat": "Zeitformat",
|
"TimeFormat": "Zeitformat",
|
||||||
"UpdateMechanismHelpText": "Benutze Radarr's Build-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",
|
"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",
|
"UpgradeAllowedHelpText": "Wenn deaktiviert wird die Qualität nicht verbessert",
|
||||||
"Uptime": "Laufzeit",
|
"Uptime": "Laufzeit",
|
||||||
@@ -979,7 +979,7 @@
|
|||||||
"EditCustomFormat": "Eigenes Format bearbeiten",
|
"EditCustomFormat": "Eigenes Format bearbeiten",
|
||||||
"DoNotUpgradeAutomatically": "Nicht automatisch upgraden",
|
"DoNotUpgradeAutomatically": "Nicht automatisch upgraden",
|
||||||
"DoNotPrefer": "Nicht bevorzugen",
|
"DoNotPrefer": "Nicht bevorzugen",
|
||||||
"DoneEditingGroups": "Editieren der Gruppen abschließen",
|
"DoneEditingGroups": "Gruppen bearbeiten abgechlossen",
|
||||||
"Donations": "Spenden",
|
"Donations": "Spenden",
|
||||||
"DockerUpdater": "aktualisiere den Docker Container um das Update zu erhalten",
|
"DockerUpdater": "aktualisiere den Docker Container um das Update zu erhalten",
|
||||||
"Discord": "Discord",
|
"Discord": "Discord",
|
||||||
@@ -1063,7 +1063,7 @@
|
|||||||
"ImportListMissingRoot": "Fehlendes Stammverzeichnis für Importlist(en): {0}",
|
"ImportListMissingRoot": "Fehlendes Stammverzeichnis für Importlist(en): {0}",
|
||||||
"BypassDelayIfHighestQualityHelpText": "Verzögerung ignorieren wenn das Release die höchste aktivierte Qualität des Qualitätsprofils mit dem bevorzugtem Protokoll ist",
|
"BypassDelayIfHighestQualityHelpText": "Verzögerung ignorieren wenn das Release die höchste aktivierte Qualität des Qualitätsprofils mit dem bevorzugtem Protokoll ist",
|
||||||
"BypassDelayIfHighestQuality": "Ignoriere wenn höchste Qualität",
|
"BypassDelayIfHighestQuality": "Ignoriere wenn höchste Qualität",
|
||||||
"TaskUserAgentTooltip": "UserAgent von der App welche die API aufgerufen hat",
|
"TaskUserAgentTooltip": "UserAgent von der App die die API aufgerufen hat",
|
||||||
"Letterboxd": "Letterboxd",
|
"Letterboxd": "Letterboxd",
|
||||||
"From": "von",
|
"From": "von",
|
||||||
"NotificationTriggersHelpText": "Auslöser für diese Benachrichtigung auswählen",
|
"NotificationTriggersHelpText": "Auslöser für diese Benachrichtigung auswählen",
|
||||||
@@ -1146,12 +1146,5 @@
|
|||||||
"TotalMovies": "Filme insgesamt",
|
"TotalMovies": "Filme insgesamt",
|
||||||
"ApplicationURL": "Anwendungs-URL",
|
"ApplicationURL": "Anwendungs-URL",
|
||||||
"ApplicationUrlHelpText": "Die externe URL der Anwendung inklusive http(s)://, Port und URL-Basis",
|
"ApplicationUrlHelpText": "Die externe URL der Anwendung inklusive http(s)://, Port und URL-Basis",
|
||||||
"PreferredProtocol": "Bevorzugtes Protokoll",
|
"PreferredProtocol": "Bevorzugtes Protokoll"
|
||||||
"AreYouSureYouWantToResetQualityDefinitions": "Sicher, dass die Qualitätsdefinitionen zurückgesetzt werden sollen?",
|
|
||||||
"ResetDefinitions": "Definitionen zurücksetzen",
|
|
||||||
"ResetQualityDefinitions": "Qualitätsdefinitionen zurücksetzen",
|
|
||||||
"SettingsThemeHelpText": "Anwendungsdesign ändern, das 'Auto' Design passt sich an den Light/Dark-Mode deines Systems an. Inspiriert von Theme.Park",
|
|
||||||
"ResetTitles": "Titel zurücksetzen",
|
|
||||||
"ResetTitlesHelpText": "Definitionstitel und Werte zurücksetzen",
|
|
||||||
"SettingsTheme": "Design"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
"Backups": "Backups",
|
"Backups": "Backups",
|
||||||
"BeforeUpdate": "Before update",
|
"BeforeUpdate": "Before update",
|
||||||
"BindAddress": "Bind Address",
|
"BindAddress": "Bind Address",
|
||||||
"BindAddressHelpText": "Valid IP address, localhost or '*' for all interfaces",
|
"BindAddressHelpText": "Valid IPv4 address or '*' for all interfaces",
|
||||||
"Blocklist": "Blocklist",
|
"Blocklist": "Blocklist",
|
||||||
"Blocklisted": "Blocklisted",
|
"Blocklisted": "Blocklisted",
|
||||||
"BlocklistHelpText": "Prevents Radarr from automatically grabbing this release again",
|
"BlocklistHelpText": "Prevents Radarr from automatically grabbing this release again",
|
||||||
@@ -258,7 +258,6 @@
|
|||||||
"DownloadClients": "Download Clients",
|
"DownloadClients": "Download Clients",
|
||||||
"DownloadClientSettings": "Download Client Settings",
|
"DownloadClientSettings": "Download Client Settings",
|
||||||
"DownloadClientsSettingsSummary": "Download clients, download handling and remote path mappings",
|
"DownloadClientsSettingsSummary": "Download clients, download handling and remote path mappings",
|
||||||
"DownloadClientSortingCheckMessage": "Download client {0} has {1} sorting enabled for Radarr's category. You should disable sorting in your download client to avoid import issues.",
|
|
||||||
"DownloadClientStatusCheckAllClientMessage": "All download clients are unavailable due to failures",
|
"DownloadClientStatusCheckAllClientMessage": "All download clients are unavailable due to failures",
|
||||||
"DownloadClientStatusCheckSingleClientMessage": "Download clients unavailable due to failures: {0}",
|
"DownloadClientStatusCheckSingleClientMessage": "Download clients unavailable due to failures: {0}",
|
||||||
"DownloadClientUnavailable": "Download client is unavailable",
|
"DownloadClientUnavailable": "Download client is unavailable",
|
||||||
@@ -870,7 +869,6 @@
|
|||||||
"RootFolders": "Root Folders",
|
"RootFolders": "Root Folders",
|
||||||
"RottenTomatoesRating": "Tomato Rating",
|
"RottenTomatoesRating": "Tomato Rating",
|
||||||
"RSS": "RSS",
|
"RSS": "RSS",
|
||||||
"RSSHelpText": "Will be used when Radarr periodically looks for releases via RSS Sync",
|
|
||||||
"RSSIsNotSupportedWithThisIndexer": "RSS is not supported with this indexer",
|
"RSSIsNotSupportedWithThisIndexer": "RSS is not supported with this indexer",
|
||||||
"RSSSync": "RSS Sync",
|
"RSSSync": "RSS Sync",
|
||||||
"RssSyncHelpText": "Interval in minutes. Set to zero to disable (this will stop all automatic release grabbing)",
|
"RssSyncHelpText": "Interval in minutes. Set to zero to disable (this will stop all automatic release grabbing)",
|
||||||
@@ -930,7 +928,7 @@
|
|||||||
"SettingsShowRelativeDates": "Show Relative Dates",
|
"SettingsShowRelativeDates": "Show Relative Dates",
|
||||||
"SettingsShowRelativeDatesHelpText": "Show relative (Today/Yesterday/etc) or absolute dates",
|
"SettingsShowRelativeDatesHelpText": "Show relative (Today/Yesterday/etc) or absolute dates",
|
||||||
"SettingsTheme": "Theme",
|
"SettingsTheme": "Theme",
|
||||||
"SettingsThemeHelpText": "Change Application UI Theme, 'Auto' Theme will use your OS Theme to set Light or Dark mode. Inspired by Theme.Park",
|
"SettingsThemeHelpText": "Change Application UI Theme, Inspired by Theme.Park",
|
||||||
"SettingsTimeFormat": "Time Format",
|
"SettingsTimeFormat": "Time Format",
|
||||||
"SettingsWeekColumnHeader": "Week Column Header",
|
"SettingsWeekColumnHeader": "Week Column Header",
|
||||||
"SettingsWeekColumnHeaderHelpText": "Shown above each column when week is the active view",
|
"SettingsWeekColumnHeaderHelpText": "Shown above each column when week is the active view",
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
"BackupIntervalHelpText": "Prowlarrin tietokannan ja asetusten automaattisen varmuuskopioinnin suoritusaikaväli.",
|
"BackupIntervalHelpText": "Prowlarrin tietokannan ja asetusten automaattisen varmuuskopioinnin suoritusaikaväli.",
|
||||||
"AppDataDirectory": "AppData-kansio",
|
"AppDataDirectory": "AppData-kansio",
|
||||||
"BackupNow": "Varmuuskopioi nyt",
|
"BackupNow": "Varmuuskopioi nyt",
|
||||||
"BindAddressHelpText": "Toimiva IP-osoite, localhost tai '*' (tähti) kaikille yhteyksille.",
|
"BindAddressHelpText": "Toimiva IPv4-osoite tai '*' (tähti) kaikille yhteyksille.",
|
||||||
"Branch": "Kehityshaara",
|
"Branch": "Kehityshaara",
|
||||||
"BuiltIn": "Sisäänrakennettu",
|
"BuiltIn": "Sisäänrakennettu",
|
||||||
"CalendarOptions": "Kalenterin asetukset",
|
"CalendarOptions": "Kalenterin asetukset",
|
||||||
@@ -252,7 +252,7 @@
|
|||||||
"Profiles": "Profiilit",
|
"Profiles": "Profiilit",
|
||||||
"ProxyType": "Välityspalvelimen tyyppi",
|
"ProxyType": "Välityspalvelimen tyyppi",
|
||||||
"PtpOldSettingsCheckMessage": "Seuraavat PassThePopcorn-tietolähteet sisältävät vanhentuneita asetuksia, jotka olisi syytä päivittää: {0}",
|
"PtpOldSettingsCheckMessage": "Seuraavat PassThePopcorn-tietolähteet sisältävät vanhentuneita asetuksia, jotka olisi syytä päivittää: {0}",
|
||||||
"QualitiesHelpText": "Listalla ylempänä olevia laatuja painotetaan enemmän vaikkei niitä ole valittu. Samoissa ryhmissä olevat laadut ovat tasaveroisia. Valitse vain halutut laadut.",
|
"QualitiesHelpText": "Listalla ylempänä olevia laatuja painotetaan. Saman ryhmän laadut ovat tasaveroisia. Valitse vain haluamasi laadut.",
|
||||||
"QualityProfileInUse": "Elokuvaan, listaan tai kokelmaan liitettyä laatuprofiilia ei voida poistaa.",
|
"QualityProfileInUse": "Elokuvaan, listaan tai kokelmaan liitettyä laatuprofiilia ei voida poistaa.",
|
||||||
"QueueIsEmpty": "Jono on tyhjä",
|
"QueueIsEmpty": "Jono on tyhjä",
|
||||||
"RadarrCalendarFeed": "Radarr-kalenterisyöte",
|
"RadarrCalendarFeed": "Radarr-kalenterisyöte",
|
||||||
@@ -333,7 +333,7 @@
|
|||||||
"CreateEmptyMovieFoldersHelpText": "Luo puuttuvat elokuvakansiot levyn tarkistuksen yhteydessä.",
|
"CreateEmptyMovieFoldersHelpText": "Luo puuttuvat elokuvakansiot levyn tarkistuksen yhteydessä.",
|
||||||
"DeleteDownloadClient": "Poista lataustyökalu",
|
"DeleteDownloadClient": "Poista lataustyökalu",
|
||||||
"ImportHeader": "Lisää Radarriin elokuvia tuomalla olemassa oleva, järjestetty kirjasto.",
|
"ImportHeader": "Lisää Radarriin elokuvia tuomalla olemassa oleva, järjestetty kirjasto.",
|
||||||
"ImportMechanismHealthCheckMessage": "Käytä valmiiden latausten käsittelyä",
|
"ImportMechanismHealthCheckMessage": "Ota valmiiden latausten käsittely käyttöön",
|
||||||
"MinAvailability": "Pienin saatavuus",
|
"MinAvailability": "Pienin saatavuus",
|
||||||
"MovieIsUnmonitored": "Elokuvaa ei valvota",
|
"MovieIsUnmonitored": "Elokuvaa ei valvota",
|
||||||
"MovieNaming": "Elokuvien nimeäminen",
|
"MovieNaming": "Elokuvien nimeäminen",
|
||||||
@@ -435,7 +435,7 @@
|
|||||||
"StartTypingOrSelectAPathBelow": "Aloita kirjoitus tai valitse sijainti alta",
|
"StartTypingOrSelectAPathBelow": "Aloita kirjoitus tai valitse sijainti alta",
|
||||||
"StartupDirectory": "Käynnistyskansio",
|
"StartupDirectory": "Käynnistyskansio",
|
||||||
"System": "Järjestelmä",
|
"System": "Järjestelmä",
|
||||||
"SystemTimeCheckMessage": "Järjestelmän aika on pielessä yli vuorokauden. Ajoitetut tehtävät eivät luultavasti toimi oikein ennen sen korjausta.",
|
"SystemTimeCheckMessage": "Järjestelmän aika on heittä yli vuorokauden verran. Ajoitetut tehtävät eivät luultavasti toimi oikein ennen ajan korjausta.",
|
||||||
"Posters": "Julisteet",
|
"Posters": "Julisteet",
|
||||||
"PosterSize": "Julisteen koko",
|
"PosterSize": "Julisteen koko",
|
||||||
"TagCannotBeDeletedWhileInUse": "Tunnistetta ei voi poistaa, koska se on käytössä",
|
"TagCannotBeDeletedWhileInUse": "Tunnistetta ei voi poistaa, koska se on käytössä",
|
||||||
@@ -653,9 +653,9 @@
|
|||||||
"IndexerPriority": "Tietolähteiden painotus",
|
"IndexerPriority": "Tietolähteiden painotus",
|
||||||
"IndexerPriorityHelpText": "Tietolähteen painotus: 1 (korkein) - 50 (matalin). Oletusarvo on 25. Käytetään muutoin tasaveroisten julkaisujen sieppauspäätökseen. Kaikkia käytössä olevia tietolähteitä käytetään edelleen RSS-synkronointiin ja hakuun.",
|
"IndexerPriorityHelpText": "Tietolähteen painotus: 1 (korkein) - 50 (matalin). Oletusarvo on 25. Käytetään muutoin tasaveroisten julkaisujen sieppauspäätökseen. Kaikkia käytössä olevia tietolähteitä käytetään edelleen RSS-synkronointiin ja hakuun.",
|
||||||
"IndexerRssHealthCheckNoAvailableIndexers": "Kaikki RSS-tietolähteet ovat tilapaisesti tavoittamattomissa viimeaikaisten tietolähdevirheiden vuoksi.",
|
"IndexerRssHealthCheckNoAvailableIndexers": "Kaikki RSS-tietolähteet ovat tilapaisesti tavoittamattomissa viimeaikaisten tietolähdevirheiden vuoksi.",
|
||||||
"IndexerRssHealthCheckNoIndexers": "Yhtään RSS-synkronointia käyttävää tietolähdettä ei ole käytettävissä, eikä uusia julkaisuja sen vuoksi siepata automaattisesti.",
|
"IndexerRssHealthCheckNoIndexers": "Yhtään RSS-synkronointia käyttävää tietolähdettä ei ole käytettävissä, eikä Radarr tämän vuoksi sieppaa uusia julkaisuja automaattisesti.",
|
||||||
"Indexers": "Tietolähteet",
|
"Indexers": "Tietolähteet",
|
||||||
"IndexerSearchCheckNoAutomaticMessage": "Automaattihaussa käytettäviä tietolähteitä ei ole käytettävissä, eikä automaattisia hakutuloksia ole tämän vuoksi saatavilla.",
|
"IndexerSearchCheckNoAutomaticMessage": "Ei hakemistoja, joissa automaattinen haku on käytössä, Radarr ei tarjoa automaattisia hakutuloksia",
|
||||||
"IndexerSearchCheckNoAvailableIndexersMessage": "Kaikki hakukelpoiset tietolähteet ovat tilapaisesti tavoittamattomissa viimeaikaisten tietolähdevirheiden vuoksi.",
|
"IndexerSearchCheckNoAvailableIndexersMessage": "Kaikki hakukelpoiset tietolähteet ovat tilapaisesti tavoittamattomissa viimeaikaisten tietolähdevirheiden vuoksi.",
|
||||||
"IndexerSettings": "Tietolähteiden asetukset",
|
"IndexerSettings": "Tietolähteiden asetukset",
|
||||||
"IndexerStatusCheckSingleClientMessage": "Tietolähteet eivät ole käytettävissä virheiden vuoksi: {0}",
|
"IndexerStatusCheckSingleClientMessage": "Tietolähteet eivät ole käytettävissä virheiden vuoksi: {0}",
|
||||||
@@ -750,7 +750,7 @@
|
|||||||
"QualityDefinitions": "Laatumääritykset",
|
"QualityDefinitions": "Laatumääritykset",
|
||||||
"QualityLimitsHelpText": "Rajoitukset suhteutetaan automaattisesti elokuvan kestoon.",
|
"QualityLimitsHelpText": "Rajoitukset suhteutetaan automaattisesti elokuvan kestoon.",
|
||||||
"QualityProfileDeleteConfirm": "Haluatko varmasti poistaa laatuprofiilin {0}",
|
"QualityProfileDeleteConfirm": "Haluatko varmasti poistaa laatuprofiilin {0}",
|
||||||
"QualitySettingsSummary": "Laatumääritykset erilaisia sisältömuotoja ja tiedostokokoja varten.",
|
"QualitySettingsSummary": "Laatumääritykset erilaisia sisältömuotoja ja teidostokokoja varten.",
|
||||||
"RadarrSupportsAnyIndexer": "Radarr tukee Newznab- ja Torznab-yhteensopivien tietolähteiden ohella myös monia muita alla lueteltuja tietolähteitä.",
|
"RadarrSupportsAnyIndexer": "Radarr tukee Newznab- ja Torznab-yhteensopivien tietolähteiden ohella myös monia muita alla lueteltuja tietolähteitä.",
|
||||||
"RadarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Radarr tukee mukautettuja ehtoja perustuen julkaisujen alla oleviin ominaisuuksiin.",
|
"RadarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Radarr tukee mukautettuja ehtoja perustuen julkaisujen alla oleviin ominaisuuksiin.",
|
||||||
"Ratings": "Arviot",
|
"Ratings": "Arviot",
|
||||||
@@ -1146,13 +1146,5 @@
|
|||||||
"TotalMovies": "Elokuvia yhteensä",
|
"TotalMovies": "Elokuvia yhteensä",
|
||||||
"ApplicationURL": "Sovelluksen URL-osoite",
|
"ApplicationURL": "Sovelluksen URL-osoite",
|
||||||
"ApplicationUrlHelpText": "Sovelluksen ulkoinen URL-osoite, johon sisältyy http(s)://, portti ja URL-perusta.",
|
"ApplicationUrlHelpText": "Sovelluksen ulkoinen URL-osoite, johon sisältyy http(s)://, portti ja URL-perusta.",
|
||||||
"PreferredProtocol": "Ensisijainen protokolla",
|
"PreferredProtocol": "Ensisijainen protokolla"
|
||||||
"ResetQualityDefinitions": "Palauta laatumääritykset",
|
|
||||||
"ResetTitles": "Palauta nimet",
|
|
||||||
"SettingsTheme": "Teema",
|
|
||||||
"SettingsThemeHelpText": "Vaihda sovelluksen käyttöliittymän ulkoasua. \"Automaattinen\" vaihtaa vaalean ja tumman tilan käyttöjärjestelmäsi teemaa vastaavaksi. Innoittanut Theme.Park.",
|
|
||||||
"AreYouSureYouWantToResetQualityDefinitions": "Haluatko varmasti palauttaa laatumääritykset?",
|
|
||||||
"ResetDefinitions": "Palauta määritykset",
|
|
||||||
"ResetTitlesHelpText": "Palauta määritysten nimet ja arvot.",
|
|
||||||
"RSSHelpText": "Käytetään etsittäessä julkaisuja RSS-syötteistä ajoitetusti."
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1113,7 +1113,7 @@
|
|||||||
"SelectReleaseGroup": "Sélectionner le groupe de publication",
|
"SelectReleaseGroup": "Sélectionner le groupe de publication",
|
||||||
"SetReleaseGroup": "Régler le groupe de publication",
|
"SetReleaseGroup": "Régler le groupe de publication",
|
||||||
"RefreshMonitoredIntervalHelpText": "Intervalle en minutes entre chaque vérification des téléchargements, minimum 1 minute",
|
"RefreshMonitoredIntervalHelpText": "Intervalle en minutes entre chaque vérification des téléchargements, minimum 1 minute",
|
||||||
"AllCollectionsHiddenDueToFilter": "Toutes les collections sont masquées en raison du filtre appliqué.",
|
"AllCollectionsHiddenDueToFilter": "Tous les films sont masqués en raison du filtre appliqué.",
|
||||||
"Collections": "Collections",
|
"Collections": "Collections",
|
||||||
"MonitorMovies": "Surveiller le film",
|
"MonitorMovies": "Surveiller le film",
|
||||||
"NoCollections": "Aucun film trouvé, pour commencer, vous voudrez ajouter un nouveau film ou importer des films existants.",
|
"NoCollections": "Aucun film trouvé, pour commencer, vous voudrez ajouter un nouveau film ou importer des films existants.",
|
||||||
|
|||||||
@@ -159,7 +159,7 @@
|
|||||||
"BranchUpdateMechanism": "A külső frissítési mechanizmus által használt ágazat",
|
"BranchUpdateMechanism": "A külső frissítési mechanizmus által használt ágazat",
|
||||||
"BranchUpdate": "Ágazattípus a Radarr frissítéseihez",
|
"BranchUpdate": "Ágazattípus a Radarr frissítéseihez",
|
||||||
"Branch": "Ágazat",
|
"Branch": "Ágazat",
|
||||||
"BindAddressHelpText": "Érvényes IP-cím, localhost vagy '*' minden interfészhez",
|
"BindAddressHelpText": "Érvényes IPv4-cím, vagy „*” minden interfészhez",
|
||||||
"BindAddress": "Kapcsolási Cím",
|
"BindAddress": "Kapcsolási Cím",
|
||||||
"BeforeUpdate": "Alkalmazásfrissítés előtt",
|
"BeforeUpdate": "Alkalmazásfrissítés előtt",
|
||||||
"Backups": "Biztonsági Mentés",
|
"Backups": "Biztonsági Mentés",
|
||||||
@@ -838,7 +838,7 @@
|
|||||||
"EditCustomFormat": "Egyéni Formátumok szerkesztése",
|
"EditCustomFormat": "Egyéni Formátumok szerkesztése",
|
||||||
"DoNotUpgradeAutomatically": "Ne frissítsen automatikusan",
|
"DoNotUpgradeAutomatically": "Ne frissítsen automatikusan",
|
||||||
"DoNotPrefer": "Nem preferált",
|
"DoNotPrefer": "Nem preferált",
|
||||||
"DoneEditingGroups": "A csoportok szerkesztése kész",
|
"DoneEditingGroups": "Kész szerkesztő csoportok",
|
||||||
"Donations": "Adományok",
|
"Donations": "Adományok",
|
||||||
"DockerUpdater": "A Frissítéshez frissítenie kell a Docker tárolót",
|
"DockerUpdater": "A Frissítéshez frissítenie kell a Docker tárolót",
|
||||||
"Discord": "Discord",
|
"Discord": "Discord",
|
||||||
@@ -965,7 +965,7 @@
|
|||||||
"QueueIsEmpty": "A várakozási sor üres",
|
"QueueIsEmpty": "A várakozási sor üres",
|
||||||
"QualityProfileInUse": "A filmhez, listához vagy gyűjteményhez csatolt minőségi profil nem törölhető",
|
"QualityProfileInUse": "A filmhez, listához vagy gyűjteményhez csatolt minőségi profil nem törölhető",
|
||||||
"QualityLimitsHelpText": "A korlátozások automatikusan beállítódnak a film hossza szerint.",
|
"QualityLimitsHelpText": "A korlátozások automatikusan beállítódnak a film hossza szerint.",
|
||||||
"QualitiesHelpText": "A listán magasabb minőségek előnyösebbek, még akkor is, ha nincs bejelölve. Ugyanazon csoporton belül a tulajdonságok egyenlőek. Csak ellenőrzött minőségek szükségesek",
|
"QualitiesHelpText": "A jobb minőség a listában jobban preferált. Ugyanazon minőségek a csoportban egyenlőek. Csak a bejelölt minőségek a kívánt minőségek",
|
||||||
"Qualities": "Minőségek",
|
"Qualities": "Minőségek",
|
||||||
"PrioritySettings": "Prioritás: {0}",
|
"PrioritySettings": "Prioritás: {0}",
|
||||||
"PreviewRenameHelpText": "Tipp: Átnevezés előnézetéhez... válassza a 'Visszavonást' majd kattintson a film címére és használja a",
|
"PreviewRenameHelpText": "Tipp: Átnevezés előnézetéhez... válassza a 'Visszavonást' majd kattintson a film címére és használja a",
|
||||||
@@ -1144,15 +1144,7 @@
|
|||||||
"InstanceNameHelpText": "Példánynév a böngésző lapon és a syslog alkalmazás neve",
|
"InstanceNameHelpText": "Példánynév a böngésző lapon és a syslog alkalmazás neve",
|
||||||
"RottenTomatoesRating": "Tomato Értékelés",
|
"RottenTomatoesRating": "Tomato Értékelés",
|
||||||
"TotalMovies": "Összes film",
|
"TotalMovies": "Összes film",
|
||||||
"ApplicationUrlHelpText": "Az alkalmazás külső URL-címe, beleértve a http(s)://-t, a portot és az URL-alapot",
|
"ApplicationUrlHelpText": "Az alkalmazás külső URL-címe, beleértve a \"http(s)://\"-t, a \"Portot\" és az \"URL-alapot\" is",
|
||||||
"ApplicationURL": "Alkalmazás URL-je",
|
"ApplicationURL": "Alkalmazás URL-je",
|
||||||
"PreferredProtocol": "Preferált protokoll",
|
"PreferredProtocol": "Preferált protokoll"
|
||||||
"AreYouSureYouWantToResetQualityDefinitions": "Biztos visszaállítod a minőségi definíciókat?",
|
|
||||||
"SettingsTheme": "Téma",
|
|
||||||
"SettingsThemeHelpText": "Változtasd meg az alkalmazás felhasználói felület témáját, az „Auto” téma az operációs rendszer témáját használja a Világos vagy Sötét mód beállításához. A Theme.Park ihlette",
|
|
||||||
"ResetDefinitions": "Definíciók visszaállítása",
|
|
||||||
"ResetQualityDefinitions": "Állítsd vissza a minőségi meghatározásokat",
|
|
||||||
"ResetTitles": "Címek visszaállítása",
|
|
||||||
"ResetTitlesHelpText": "A definíciócímek és értékek visszaállítása",
|
|
||||||
"RSSHelpText": "Akkor használatos, amikor a Radarr rendszeresen keres kiadásokat az RSS Sync segítségével"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
"AppDataLocationHealthCheckMessage": "L'aggiornamento non sarà possibile per evitare la cancellazione di AppData durante l'aggiornamento",
|
"AppDataLocationHealthCheckMessage": "L'aggiornamento non sarà possibile per evitare la cancellazione di AppData durante l'aggiornamento",
|
||||||
"Analytics": "Analitica",
|
"Analytics": "Analitica",
|
||||||
"Added": "Aggiunto",
|
"Added": "Aggiunto",
|
||||||
"About": "Info",
|
"About": "Informazioni",
|
||||||
"Year": "Anno",
|
"Year": "Anno",
|
||||||
"Week": "Settimana",
|
"Week": "Settimana",
|
||||||
"Updates": "Aggiornamenti",
|
"Updates": "Aggiornamenti",
|
||||||
@@ -189,7 +189,7 @@
|
|||||||
"ChooseAnotherFolder": "Scegli un'altra Cartella",
|
"ChooseAnotherFolder": "Scegli un'altra Cartella",
|
||||||
"Cast": "Cast",
|
"Cast": "Cast",
|
||||||
"Calendar": "Calendario",
|
"Calendar": "Calendario",
|
||||||
"BackupNow": "Esegui backup ora",
|
"BackupNow": "Effettua il Backup adesso",
|
||||||
"Backup": "Backup",
|
"Backup": "Backup",
|
||||||
"All": "Tutti",
|
"All": "Tutti",
|
||||||
"Agenda": "Agenda",
|
"Agenda": "Agenda",
|
||||||
@@ -220,12 +220,12 @@
|
|||||||
"ChangeFileDate": "Cambiare la Data del File",
|
"ChangeFileDate": "Cambiare la Data del File",
|
||||||
"CertificationCountryHelpText": "Seleziona il Paese per le Certificazioni dei Film",
|
"CertificationCountryHelpText": "Seleziona il Paese per le Certificazioni dei Film",
|
||||||
"CertificationCountry": "Paese di Certificazione",
|
"CertificationCountry": "Paese di Certificazione",
|
||||||
"CertificateValidationHelpText": "Cambia quanto rigorosamente vengono validati i certificati HTTPS. Non cambiare senza conoscerne i rischi.",
|
"CertificateValidationHelpText": "Cambia quanto è rigorosa la convalida del certificato HTTPS. Non cambiare a meno che tu non comprenda i rischi.",
|
||||||
"CertificateValidation": "Convalida del Certificato",
|
"CertificateValidation": "Convalida del Certificato",
|
||||||
"Cancel": "Annulla",
|
"Cancel": "Annulla",
|
||||||
"BypassProxyForLocalAddresses": "Evita il Proxy per gli Indirizzi Locali",
|
"BypassProxyForLocalAddresses": "Evita il Proxy per gli Indirizzi Locali",
|
||||||
"Branch": "Ramo",
|
"Branch": "Ramo",
|
||||||
"BindAddressHelpText": "Indirizzo IPV4 valido o '*' per tutte le interfacce di rete",
|
"BindAddressHelpText": "Indirizzo IPv4 valido o '*' per tutte le interfacce",
|
||||||
"BindAddress": "Indirizzo di Bind",
|
"BindAddress": "Indirizzo di Bind",
|
||||||
"Backups": "I Backup",
|
"Backups": "I Backup",
|
||||||
"BackupRetentionHelpText": "I backup automatici più vecchi del periodo di conservazione verranno eliminati automaticamente",
|
"BackupRetentionHelpText": "I backup automatici più vecchi del periodo di conservazione verranno eliminati automaticamente",
|
||||||
@@ -261,7 +261,7 @@
|
|||||||
"TotalSpace": "Spazio Totale",
|
"TotalSpace": "Spazio Totale",
|
||||||
"Title": "Titolo",
|
"Title": "Titolo",
|
||||||
"Time": "Ora",
|
"Time": "Ora",
|
||||||
"TestAll": "Prova Tutti",
|
"TestAll": "Testa Tutti",
|
||||||
"Test": "Test",
|
"Test": "Test",
|
||||||
"TableOptionsColumnsMessage": "Scegli quali colonne rendere visibili ed il loro ordine",
|
"TableOptionsColumnsMessage": "Scegli quali colonne rendere visibili ed il loro ordine",
|
||||||
"TableOptions": "Opzioni della tabella",
|
"TableOptions": "Opzioni della tabella",
|
||||||
@@ -452,7 +452,7 @@
|
|||||||
"RadarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Radarr supporta qualunque Lista di film RSS, cosi come le altre sotto.",
|
"RadarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Radarr supporta qualunque Lista di film RSS, cosi come le altre sotto.",
|
||||||
"RadarrSupportsAnyDownloadClient": "Radarr supporta qualunque client di download che usi gli standard Newznab, cosi come gli altri client sotto.",
|
"RadarrSupportsAnyDownloadClient": "Radarr supporta qualunque client di download che usi gli standard Newznab, cosi come gli altri client sotto.",
|
||||||
"QuickImport": "Sposta automaticamente",
|
"QuickImport": "Sposta automaticamente",
|
||||||
"Queued": "In coda",
|
"Queued": "Messo in coda",
|
||||||
"QualitySettings": "Impostazione di Qualità",
|
"QualitySettings": "Impostazione di Qualità",
|
||||||
"QualityProfileDeleteConfirm": "Sicuro di voler cancellare il profilo di qualità {0}",
|
"QualityProfileDeleteConfirm": "Sicuro di voler cancellare il profilo di qualità {0}",
|
||||||
"QualityCutoffHasNotBeenMet": "Il qualità di taglio non è stata raggiunta",
|
"QualityCutoffHasNotBeenMet": "Il qualità di taglio non è stata raggiunta",
|
||||||
@@ -713,8 +713,8 @@
|
|||||||
"TimeFormat": "Formato orario",
|
"TimeFormat": "Formato orario",
|
||||||
"ThisConditionMatchesUsingRegularExpressions": "Questa condizione si applica usando espressione regolari. Nota che i caratteri {0} hanno significati speciali e devono essere evitati con un {1}",
|
"ThisConditionMatchesUsingRegularExpressions": "Questa condizione si applica usando espressione regolari. Nota che i caratteri {0} hanno significati speciali e devono essere evitati con un {1}",
|
||||||
"TestAllLists": "Testa tutte le liste",
|
"TestAllLists": "Testa tutte le liste",
|
||||||
"TestAllIndexers": "Prova tutti gli indicizzatori",
|
"TestAllIndexers": "Testa tutti gli Indicizzatori",
|
||||||
"TestAllClients": "Testa tutti i client",
|
"TestAllClients": "Testa Tutti i Client",
|
||||||
"TagsHelpText": "Si applica ai film con almeno un tag corrispondente",
|
"TagsHelpText": "Si applica ai film con almeno un tag corrispondente",
|
||||||
"TagIsNotUsedAndCanBeDeleted": "L'etichetta non è in uso e può essere eliminata",
|
"TagIsNotUsedAndCanBeDeleted": "L'etichetta non è in uso e può essere eliminata",
|
||||||
"TagCannotBeDeletedWhileInUse": "Non può essere cancellato mentre è in uso",
|
"TagCannotBeDeletedWhileInUse": "Non può essere cancellato mentre è in uso",
|
||||||
@@ -793,7 +793,7 @@
|
|||||||
"MovieDetailsPreviousMovie": "Dettagli del film: film precedente",
|
"MovieDetailsPreviousMovie": "Dettagli del film: film precedente",
|
||||||
"FocusSearchBox": "Evidenzia casella di ricerca",
|
"FocusSearchBox": "Evidenzia casella di ricerca",
|
||||||
"CloseCurrentModal": "Chiudi la Modale Attuale",
|
"CloseCurrentModal": "Chiudi la Modale Attuale",
|
||||||
"AcceptConfirmationModal": "Accetta Conferma Modale",
|
"AcceptConfirmationModal": "Acetta Conferma Modale",
|
||||||
"StartSearchForMissingMovie": "Avvia ricerca film mancanti",
|
"StartSearchForMissingMovie": "Avvia ricerca film mancanti",
|
||||||
"StartProcessing": "Avvia Lavorazione",
|
"StartProcessing": "Avvia Lavorazione",
|
||||||
"StartImport": "Avvia Importazione",
|
"StartImport": "Avvia Importazione",
|
||||||
@@ -842,7 +842,7 @@
|
|||||||
"AddQualityProfile": "Aggiungi Profilo Qualità",
|
"AddQualityProfile": "Aggiungi Profilo Qualità",
|
||||||
"AddNotification": "Aggiungi Notifica",
|
"AddNotification": "Aggiungi Notifica",
|
||||||
"AddedToDownloadQueue": "Aggiunto alla coda di download",
|
"AddedToDownloadQueue": "Aggiunto alla coda di download",
|
||||||
"AddDownloadClient": "Aggiungi Downloader",
|
"AddDownloadClient": "Aggiungi Client di Download",
|
||||||
"AddCustomFormat": "Aggiungi Formato Personalizzato",
|
"AddCustomFormat": "Aggiungi Formato Personalizzato",
|
||||||
"Add": "Aggiungi",
|
"Add": "Aggiungi",
|
||||||
"ImportLibrary": "Importazione della libreria",
|
"ImportLibrary": "Importazione della libreria",
|
||||||
@@ -1091,18 +1091,11 @@
|
|||||||
"ClickToChangeReleaseGroup": "Clicca per cambiare gruppo di rilascio",
|
"ClickToChangeReleaseGroup": "Clicca per cambiare gruppo di rilascio",
|
||||||
"DiscordUrlInSlackNotification": "Hai una notifica Discord configurata come notifica Slack. Configurala come notifica Discord per una miglior funzionalità. Le notifiche interessate sono: {0}",
|
"DiscordUrlInSlackNotification": "Hai una notifica Discord configurata come notifica Slack. Configurala come notifica Discord per una miglior funzionalità. Le notifiche interessate sono: {0}",
|
||||||
"Duration": "Durata",
|
"Duration": "Durata",
|
||||||
"InstanceNameHelpText": "Nome istanza nella scheda e per il nome dell'app nel Syslog",
|
"InstanceNameHelpText": "Nome dell'istanza nella scheda e per il nome dell'applicazione Syslog",
|
||||||
"InstanceName": "Nome Istanza",
|
"InstanceName": "Nome Istanza",
|
||||||
"AllCollectionsHiddenDueToFilter": "Tutti i film sono nascosti a causa del filtro applicato.",
|
"AllCollectionsHiddenDueToFilter": "Tutti i film sono nascosti a causa del filtro applicato.",
|
||||||
"Collections": "Collezione",
|
"Collections": "Collezione",
|
||||||
"MonitorMovies": "Monitora Film",
|
"MonitorMovies": "Monitora Film",
|
||||||
"NoCollections": "Nessun film trovato, per iniziare ti consigliamo di aggiungere un nuovo film o importarne alcuni esistenti.",
|
"NoCollections": "Nessun film trovato, per iniziare ti consigliamo di aggiungere un nuovo film o importarne alcuni esistenti.",
|
||||||
"RssSyncHelpText": "Intervallo in minuti. Imposta zero per disabilitarlo (ciò fermerà il recupero automatico di tutte le release)",
|
"RssSyncHelpText": "Intervallo in minuti. Imposta zero per disabilitarlo (ciò fermerà il recupero automatico di tutte le release)"
|
||||||
"ApplicationURL": "URL Applicazione",
|
|
||||||
"ApplicationUrlHelpText": "L'URL esterno di questa applicazione, incluso http(s)://, porta e URL base",
|
|
||||||
"CollectionOptions": "Opzioni della Collezione",
|
|
||||||
"CollectionShowDetailsHelpText": "Mostra lo stato e le proprietà della collezione",
|
|
||||||
"Started": "Iniziato",
|
|
||||||
"AreYouSureYouWantToResetQualityDefinitions": "Sei sicuro di voler ripristinare le definizioni della qualità?",
|
|
||||||
"ChooseImportMode": "Selezionare Metodo di Importazione"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -368,11 +368,11 @@
|
|||||||
"ChangeFileDate": "Wijzig Bestandsdatum",
|
"ChangeFileDate": "Wijzig Bestandsdatum",
|
||||||
"CertificationCountryHelpText": "Selecteer Land voor Film Certificatie",
|
"CertificationCountryHelpText": "Selecteer Land voor Film Certificatie",
|
||||||
"CertificationCountry": "Certificatie Land",
|
"CertificationCountry": "Certificatie Land",
|
||||||
"CertificateValidationHelpText": "Wijzig hoe strict HTTPS certificaat validatie is. Wijzig dit niet behalve als je de risico's begrijpt.",
|
"CertificateValidationHelpText": "Wijzig hoe strikt HTTPS certificaat validatie is",
|
||||||
"CertificateValidation": "Certificaat Validatie",
|
"CertificateValidation": "Certificaat Validatie",
|
||||||
"BypassProxyForLocalAddresses": "Omzeil Proxy voor Lokale Adressen",
|
"BypassProxyForLocalAddresses": "Omzeil Proxy voor Lokale Adressen",
|
||||||
"Branch": "Branch",
|
"Branch": "Branch",
|
||||||
"BindAddressHelpText": "Geldig IP-adres, localhost of '*' voor alle interfaces",
|
"BindAddressHelpText": "Geldig IPv4 adres of '*' voor alle interfaces",
|
||||||
"DeleteBackup": "Verwijder Veiligheidskopie",
|
"DeleteBackup": "Verwijder Veiligheidskopie",
|
||||||
"BackupIntervalHelpText": "Tussentijd voor automatische back-up",
|
"BackupIntervalHelpText": "Tussentijd voor automatische back-up",
|
||||||
"Backups": "Veiligheidskopieën",
|
"Backups": "Veiligheidskopieën",
|
||||||
@@ -723,7 +723,7 @@
|
|||||||
"HaveNotAddedMovies": "U heeft nog geen films toegevoegd, wilt u eerst enkele of al uw films importeren?",
|
"HaveNotAddedMovies": "U heeft nog geen films toegevoegd, wilt u eerst enkele of al uw films importeren?",
|
||||||
"ForMoreInformationOnTheIndividualIndexers": "Voor meer informatie over de individuele indexeerders, klik op de info knoppen.",
|
"ForMoreInformationOnTheIndividualIndexers": "Voor meer informatie over de individuele indexeerders, klik op de info knoppen.",
|
||||||
"ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Voor meer informatie over de individuele lijsten, klik op de info knoppen.",
|
"ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Voor meer informatie over de individuele lijsten, klik op de info knoppen.",
|
||||||
"ForMoreInformationOnTheIndividualDownloadClients": "Voor meer informatie over de individuele download applicaties, klik op de info knoppen.",
|
"ForMoreInformationOnTheIndividualDownloadClients": "Voor meer informatie over de individuele downloaders, klik op de info knoppen.",
|
||||||
"FailedLoadingSearchResults": "Laden van zoekresultaten is mislukt, gelieve opnieuw te proberen.",
|
"FailedLoadingSearchResults": "Laden van zoekresultaten is mislukt, gelieve opnieuw te proberen.",
|
||||||
"ExtraFileExtensionsHelpTexts1": "Komma gescheiden lijst met extra bestanden om te importeren (.nfo zal als .nfo-orig worden geïmporteerd)",
|
"ExtraFileExtensionsHelpTexts1": "Komma gescheiden lijst met extra bestanden om te importeren (.nfo zal als .nfo-orig worden geïmporteerd)",
|
||||||
"CouldNotFindResults": "Kon geen resultaten vinden voor '{0}'",
|
"CouldNotFindResults": "Kon geen resultaten vinden voor '{0}'",
|
||||||
@@ -806,10 +806,10 @@
|
|||||||
"AllMoviesInPathHaveBeenImported": "Alle films in {0} zijn geïmporteerd",
|
"AllMoviesInPathHaveBeenImported": "Alle films in {0} zijn geïmporteerd",
|
||||||
"AllFiles": "Alle bestanden",
|
"AllFiles": "Alle bestanden",
|
||||||
"AfterManualRefresh": "Na handmatig verversen",
|
"AfterManualRefresh": "Na handmatig verversen",
|
||||||
"AddToDownloadQueue": "Toegevoegd aan downloadwachtrij",
|
"AddToDownloadQueue": "Toegevoegd aan download wachtrij",
|
||||||
"AddQualityProfile": "Kwaliteitsprofiel toevoegen",
|
"AddQualityProfile": "Kwaliteitsprofiel toevoegen",
|
||||||
"AddNotification": "Notificatie toevoegen",
|
"AddNotification": "Notificatie toevoegen",
|
||||||
"AddedToDownloadQueue": "Aan de download wachtrijtoegevoegd",
|
"AddedToDownloadQueue": "Aan de download wachtrij toegevoegd",
|
||||||
"AddDownloadClient": "Download Client Toevoegen",
|
"AddDownloadClient": "Download Client Toevoegen",
|
||||||
"Add": "Toevoegen",
|
"Add": "Toevoegen",
|
||||||
"ChmodFolderHelpTextWarning": "Dit werkt alleen als de gebruiker die Radarr draait de eigenaar is van het bestand. Het is beter om zeker te zijn dat de downloader de juiste rechten zet.",
|
"ChmodFolderHelpTextWarning": "Dit werkt alleen als de gebruiker die Radarr draait de eigenaar is van het bestand. Het is beter om zeker te zijn dat de downloader de juiste rechten zet.",
|
||||||
@@ -1045,7 +1045,7 @@
|
|||||||
"DeleteFileLabel": "Verwijder {0} Film Bestanden",
|
"DeleteFileLabel": "Verwijder {0} Film Bestanden",
|
||||||
"UnableToAddRootFolder": "Kon hoofdmappen niet inladen",
|
"UnableToAddRootFolder": "Kon hoofdmappen niet inladen",
|
||||||
"UpdateAvailable": "Nieuwe update is beschikbaar",
|
"UpdateAvailable": "Nieuwe update is beschikbaar",
|
||||||
"From": "van",
|
"From": "Van",
|
||||||
"RemotePathMappingCheckDownloadPermissions": "Radarr kan gedownloade film {0} zien, maar niet openen. Waarschijnlijk fout met machtigingen.",
|
"RemotePathMappingCheckDownloadPermissions": "Radarr kan gedownloade film {0} zien, maar niet openen. Waarschijnlijk fout met machtigingen.",
|
||||||
"RemotePathMappingCheckFileRemoved": "Bestand {0} is halverwege de verwerking verwijderd.",
|
"RemotePathMappingCheckFileRemoved": "Bestand {0} is halverwege de verwerking verwijderd.",
|
||||||
"RemotePathMappingCheckFilesBadDockerPath": "U gebruikt docker; download client {0} gerapporteerde bestanden in {1} maar dit is geen geldig {2} pad. Controleer uw externe padtoewijzingen en download clientinstellingen.",
|
"RemotePathMappingCheckFilesBadDockerPath": "U gebruikt docker; download client {0} gerapporteerde bestanden in {1} maar dit is geen geldig {2} pad. Controleer uw externe padtoewijzingen en download clientinstellingen.",
|
||||||
@@ -1107,14 +1107,5 @@
|
|||||||
"Collections": "Collectie",
|
"Collections": "Collectie",
|
||||||
"MonitorMovies": "Bewaak Film",
|
"MonitorMovies": "Bewaak Film",
|
||||||
"ApplicationURL": "Applicatie URL",
|
"ApplicationURL": "Applicatie URL",
|
||||||
"ApplicationUrlHelpText": "De externe URL van deze applicatie inclusief http(s)://,Port en URL base",
|
"ApplicationUrlHelpText": "De externe URL van deze applicatie inclusief http(s)://,Port en URL base"
|
||||||
"CollectionsSelectedInterp": "{0} Collectie(s) geselecteerd",
|
|
||||||
"AreYouSureYouWantToResetQualityDefinitions": "Weet je zeker dat je de kwaliteitsdefinities wilt resetten?",
|
|
||||||
"ChooseImportMode": "Kies Importmodus",
|
|
||||||
"CollectionOptions": "Collectieopties",
|
|
||||||
"CollectionShowDetailsHelpText": "Collectie status en details weergeven",
|
|
||||||
"CollectionShowOverviewsHelpText": "Collectieoverzicht weergeven",
|
|
||||||
"EditCollection": "Bewerk collectie",
|
|
||||||
"BypassDelayIfHighestQualityHelpText": "Vertraging negeren wanneer een release de hoogst mogelijke kwaliteit heeft in het kwaliteitsprofiel van het geprefereerde protocol",
|
|
||||||
"CollectionShowPostersHelpText": "Posters van de collectie tonen"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"IndexerStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a falhas",
|
"IndexerStatusCheckAllClientMessage": "Todos os indexadores estão indisponíveis devido a falhas",
|
||||||
"IndexersSettingsSummary": "Indexadores e restrições de lançamento",
|
"IndexersSettingsSummary": "Indexadores e restrições de lançamento",
|
||||||
"IndexerSettings": "Configurações do indexador",
|
"IndexerSettings": "Configurações do indexador",
|
||||||
"IndexerSearchCheckNoInteractiveMessage": "Nenhum indexador disponível com a Pesquisa interativa habilitada, o Radarr não fornecerá nenhum resultado de pesquisa interativo",
|
"IndexerSearchCheckNoInteractiveMessage": "Nenhum indexador disponível com a Pesquisa interativa ativada, o Radarr não fornecerá nenhum resultado de pesquisa interativa",
|
||||||
"IndexerSearchCheckNoAvailableIndexersMessage": "Todos os indexadores com capacidade de pesquisa estão temporariamente indisponíveis devido a erros recentes do indexador",
|
"IndexerSearchCheckNoAvailableIndexersMessage": "Todos os indexadores com capacidade de pesquisa estão temporariamente indisponíveis devido a erros recentes do indexador",
|
||||||
"IndexerSearchCheckNoAutomaticMessage": "Nenhum indexador disponível com a Pesquisa automática habilitada, o Radarr não fornecerá nenhum resultado de pesquisa automática",
|
"IndexerSearchCheckNoAutomaticMessage": "Nenhum indexador disponível com a Pesquisa automática habilitada, o Radarr não fornecerá nenhum resultado de pesquisa automática",
|
||||||
"Indexers": "Indexadores",
|
"Indexers": "Indexadores",
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
"HealthNoIssues": "Nenhum problema com sua configuração",
|
"HealthNoIssues": "Nenhum problema com sua configuração",
|
||||||
"Health": "Integridade",
|
"Health": "Integridade",
|
||||||
"HaveNotAddedMovies": "Você ainda não adicionou nenhum filme, deseja importar alguns ou todos os seus filmes primeiro?",
|
"HaveNotAddedMovies": "Você ainda não adicionou nenhum filme, deseja importar alguns ou todos os seus filmes primeiro?",
|
||||||
"HardlinkCopyFiles": "Hardlink/Copiar arquivos",
|
"HardlinkCopyFiles": "Vínculo real/Copiar arquivos",
|
||||||
"Group": "Grupo",
|
"Group": "Grupo",
|
||||||
"GrabSelected": "Obter selecionado",
|
"GrabSelected": "Obter selecionado",
|
||||||
"GrabReleaseMessageText": "O Radarr não conseguiu determinar a qual filme este lançamento está relacionado. O Radarr pode não conseguir importar automaticamente este lançamento. Quer obter \"{0}\"?",
|
"GrabReleaseMessageText": "O Radarr não conseguiu determinar a qual filme este lançamento está relacionado. O Radarr pode não conseguir importar automaticamente este lançamento. Quer obter \"{0}\"?",
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
"EditListExclusion": "Editar exclusão da lista",
|
"EditListExclusion": "Editar exclusão da lista",
|
||||||
"Edition": "Edição",
|
"Edition": "Edição",
|
||||||
"EditIndexer": "Editar indexador",
|
"EditIndexer": "Editar indexador",
|
||||||
"EditGroups": "Editar Grupos",
|
"EditGroups": "Editar grupos",
|
||||||
"EditDelayProfile": "Editar perfil de atraso",
|
"EditDelayProfile": "Editar perfil de atraso",
|
||||||
"EditCustomFormat": "Editar formato personalizado",
|
"EditCustomFormat": "Editar formato personalizado",
|
||||||
"Edit": "Editar",
|
"Edit": "Editar",
|
||||||
@@ -202,7 +202,7 @@
|
|||||||
"DownloadClient": "Cliente de download",
|
"DownloadClient": "Cliente de download",
|
||||||
"DoNotUpgradeAutomatically": "Não atualizar automaticamente",
|
"DoNotUpgradeAutomatically": "Não atualizar automaticamente",
|
||||||
"DoNotPrefer": "Não preferir",
|
"DoNotPrefer": "Não preferir",
|
||||||
"DoneEditingGroups": "Concluído a Edição de Grupos",
|
"DoneEditingGroups": "Edição de grupos concluída",
|
||||||
"Donations": "Doações",
|
"Donations": "Doações",
|
||||||
"DockerUpdater": "atualizar o contêiner do Docker para receber a atualização",
|
"DockerUpdater": "atualizar o contêiner do Docker para receber a atualização",
|
||||||
"Docker": "Docker",
|
"Docker": "Docker",
|
||||||
@@ -340,7 +340,7 @@
|
|||||||
"BranchUpdateMechanism": "Ramificação usada pelo mecanismo de atualização externo",
|
"BranchUpdateMechanism": "Ramificação usada pelo mecanismo de atualização externo",
|
||||||
"BranchUpdate": "Ramificação para atualização do Radarr",
|
"BranchUpdate": "Ramificação para atualização do Radarr",
|
||||||
"Branch": "Ramo",
|
"Branch": "Ramo",
|
||||||
"BindAddressHelpText": "Endereço IP válido, localhost ou '*' para todas as interfaces",
|
"BindAddressHelpText": "Endereço IPv4 Válido ou '*' para todas as interfaces",
|
||||||
"BindAddress": "Fixar Endereço",
|
"BindAddress": "Fixar Endereço",
|
||||||
"BeforeUpdate": "Antes da atualização",
|
"BeforeUpdate": "Antes da atualização",
|
||||||
"Backups": "Backups",
|
"Backups": "Backups",
|
||||||
@@ -484,7 +484,7 @@
|
|||||||
"AddMovies": "Adicionar filmes",
|
"AddMovies": "Adicionar filmes",
|
||||||
"AddMovie": "Adicionar filme",
|
"AddMovie": "Adicionar filme",
|
||||||
"AddListExclusion": "Adicionar exclusão à lista",
|
"AddListExclusion": "Adicionar exclusão à lista",
|
||||||
"AddList": "Adicionar Lista",
|
"AddList": "Adicionar à Lista",
|
||||||
"AddingTag": "Adicionando etiqueta",
|
"AddingTag": "Adicionando etiqueta",
|
||||||
"AddIndexer": "Adicionar indexador",
|
"AddIndexer": "Adicionar indexador",
|
||||||
"AddImportExclusionHelpText": "Impedir a adição do filme ao Radarr por listas",
|
"AddImportExclusionHelpText": "Impedir a adição do filme ao Radarr por listas",
|
||||||
@@ -752,7 +752,7 @@
|
|||||||
"Restrictions": "Restrições",
|
"Restrictions": "Restrições",
|
||||||
"RestoreBackup": "Restaurar backup",
|
"RestoreBackup": "Restaurar backup",
|
||||||
"Restore": "Restaurar",
|
"Restore": "Restaurar",
|
||||||
"RestartRequiredHelpTextWarning": "Requer reinicialização para ter efeito",
|
"RestartRequiredHelpTextWarning": "Requer reinicio para fazer efeito",
|
||||||
"RestartRadarr": "Reiniciar o Radarr",
|
"RestartRadarr": "Reiniciar o Radarr",
|
||||||
"RestartNow": "Reiniciar agora",
|
"RestartNow": "Reiniciar agora",
|
||||||
"Restart": "Reiniciar",
|
"Restart": "Reiniciar",
|
||||||
@@ -854,7 +854,7 @@
|
|||||||
"QualityDefinitions": "Definições de qualidade",
|
"QualityDefinitions": "Definições de qualidade",
|
||||||
"QualityCutoffHasNotBeenMet": "Limite de qualidade não atingido",
|
"QualityCutoffHasNotBeenMet": "Limite de qualidade não atingido",
|
||||||
"Quality": "Qualidade",
|
"Quality": "Qualidade",
|
||||||
"QualitiesHelpText": "As qualidades mais altas na lista são mais preferidas, mesmo que não sejam verificadas. As qualidades dentro do mesmo grupo são iguais. Somente qualidades verificadas são desejadas",
|
"QualitiesHelpText": "As qualidades mais altas na lista são mais preferidas, mesmo que não estejam marcadas. As qualidades dentro do mesmo grupo são iguais. Apenas qualidades marcadas são desejadas",
|
||||||
"Qualities": "Qualidades",
|
"Qualities": "Qualidades",
|
||||||
"PublishedDate": "Data de publicação",
|
"PublishedDate": "Data de publicação",
|
||||||
"PtpOldSettingsCheckMessage": "As configurações dos seguintes indexadores do PassThePopcorn são obsoletas e devem ser atualizadas: {0}",
|
"PtpOldSettingsCheckMessage": "As configurações dos seguintes indexadores do PassThePopcorn são obsoletas e devem ser atualizadas: {0}",
|
||||||
@@ -868,7 +868,7 @@
|
|||||||
"Proxy": "Proxy",
|
"Proxy": "Proxy",
|
||||||
"ProtocolHelpText": "Escolha que protocolo(s) utilizar e qual o preferido ao escolher entre versões iguais",
|
"ProtocolHelpText": "Escolha que protocolo(s) utilizar e qual o preferido ao escolher entre versões iguais",
|
||||||
"Protocol": "Protocolo",
|
"Protocol": "Protocolo",
|
||||||
"Proper": "Apropriado",
|
"Proper": "Proper",
|
||||||
"Progress": "Progresso",
|
"Progress": "Progresso",
|
||||||
"ProfilesSettingsSummary": "Perfis de qualidade, idioma e atraso",
|
"ProfilesSettingsSummary": "Perfis de qualidade, idioma e atraso",
|
||||||
"Profiles": "Perfis",
|
"Profiles": "Perfis",
|
||||||
@@ -923,7 +923,7 @@
|
|||||||
"OnRenameHelpText": "Ao renomear",
|
"OnRenameHelpText": "Ao renomear",
|
||||||
"OnRename": "Ao Renomear",
|
"OnRename": "Ao Renomear",
|
||||||
"OnlyUsenet": "Apenas Usenet",
|
"OnlyUsenet": "Apenas Usenet",
|
||||||
"OnlyTorrent": "Apenas Torrents",
|
"OnlyTorrent": "Apenas torrents",
|
||||||
"OnLatestVersion": "A versão mais recente do Radarr já está instalada",
|
"OnLatestVersion": "A versão mais recente do Radarr já está instalada",
|
||||||
"OnImport": "Ao importar",
|
"OnImport": "Ao importar",
|
||||||
"OnHealthIssueHelpText": "Ao ter problema de integridade",
|
"OnHealthIssueHelpText": "Ao ter problema de integridade",
|
||||||
@@ -961,7 +961,7 @@
|
|||||||
"UpdateSelected": "Atualizar selecionado(s)",
|
"UpdateSelected": "Atualizar selecionado(s)",
|
||||||
"UpdateScriptPathHelpText": "Caminho para um script personalizado que usa um pacote de atualização extraído e lida com o restante do processo de atualização",
|
"UpdateScriptPathHelpText": "Caminho para um script personalizado que usa um pacote de atualização extraído e lida com o restante do processo de atualização",
|
||||||
"Updates": "Atualizações",
|
"Updates": "Atualizações",
|
||||||
"UpdateMechanismHelpText": "Usar o atualizador integrado do Radarr ou um script",
|
"UpdateMechanismHelpText": "Use o atualizador integrado do Radarr ou um script",
|
||||||
"UpdateCheckUINotWritableMessage": "Não é possível instalar a atualização porque a pasta de interface do usuário '{0}' não é gravável pelo usuário '{1}'.",
|
"UpdateCheckUINotWritableMessage": "Não é possível instalar a atualização porque a pasta de interface do usuário '{0}' não é gravável pelo usuário '{1}'.",
|
||||||
"UpdateCheckStartupTranslocationMessage": "Não é possível instalar a atualização porque a pasta de inicialização '{0}' está em uma pasta App Translocation.",
|
"UpdateCheckStartupTranslocationMessage": "Não é possível instalar a atualização porque a pasta de inicialização '{0}' está em uma pasta App Translocation.",
|
||||||
"UpdateCheckStartupNotWritableMessage": "Não é possível instalar a atualização porque a pasta de inicialização '{0}' não pode ser gravada pelo usuário '{1}'.",
|
"UpdateCheckStartupNotWritableMessage": "Não é possível instalar a atualização porque a pasta de inicialização '{0}' não pode ser gravada pelo usuário '{1}'.",
|
||||||
@@ -1053,7 +1053,7 @@
|
|||||||
"RemotePathMappingCheckImportFailed": "O Radarr não conseguiu importar um filme. Verifique os logs para saber mais.",
|
"RemotePathMappingCheckImportFailed": "O Radarr não conseguiu importar um filme. Verifique os logs para saber mais.",
|
||||||
"RemotePathMappingCheckFileRemoved": "O arquivo {0} foi removido no meio do processamento.",
|
"RemotePathMappingCheckFileRemoved": "O arquivo {0} foi removido no meio do processamento.",
|
||||||
"RemotePathMappingCheckDownloadPermissions": "O Radarr pode ver, mas não pode acessar o filme baixado {0}. Provável erro de permissões.",
|
"RemotePathMappingCheckDownloadPermissions": "O Radarr pode ver, mas não pode acessar o filme baixado {0}. Provável erro de permissões.",
|
||||||
"RemotePathMappingCheckGenericPermissions": "O cliente de download {0} coloca os downloads em {1}, mas o Radarr não pode ver este diretório. Pode ser necessário ajustar as permissões da pasta.",
|
"RemotePathMappingCheckGenericPermissions": "O cliente de download {0} coloca downloads em {1} mas o Radarr não pode ver este diretório. Pode ser necessário ajustar as permissões da pasta.",
|
||||||
"RemotePathMappingCheckWrongOSPath": "O cliente de download remoto {0} coloca downloads em {1}, mas este não é um caminho {2} válido. Revise seus mapeamentos de caminho remoto e baixe as configurações do cliente.",
|
"RemotePathMappingCheckWrongOSPath": "O cliente de download remoto {0} coloca downloads em {1}, mas este não é um caminho {2} válido. Revise seus mapeamentos de caminho remoto e baixe as configurações do cliente.",
|
||||||
"RemotePathMappingCheckLocalWrongOSPath": "O cliente de download local {0} coloca downloads em {1}, mas este não é um caminho {2} válido. Revise as configurações do seu cliente de download.",
|
"RemotePathMappingCheckLocalWrongOSPath": "O cliente de download local {0} coloca downloads em {1}, mas este não é um caminho {2} válido. Revise as configurações do seu cliente de download.",
|
||||||
"RemotePathMappingCheckLocalFolderMissing": "O cliente de download remoto {0} coloca downloads em {1}, mas esse diretório parece não existir. Mapeamento de caminho remoto provavelmente ausente ou incorreto.",
|
"RemotePathMappingCheckLocalFolderMissing": "O cliente de download remoto {0} coloca downloads em {1}, mas esse diretório parece não existir. Mapeamento de caminho remoto provavelmente ausente ou incorreto.",
|
||||||
@@ -1078,7 +1078,7 @@
|
|||||||
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Você tem certeza de que deseja remover {0} item{1} da fila?",
|
"AreYouSureYouWantToRemoveSelectedItemFromQueue": "Você tem certeza de que deseja remover {0} item{1} da fila?",
|
||||||
"BlocklistReleases": "Lançamento na lista de bloqueio",
|
"BlocklistReleases": "Lançamento na lista de bloqueio",
|
||||||
"RemoveSelectedItems": "Remover Itens Selecionados",
|
"RemoveSelectedItems": "Remover Itens Selecionados",
|
||||||
"IndexerTagHelpText": "Use este indexador apenas para filmes com pelo menos uma etiqueta correspondente. Deixe em branco para usar com todos os filmes.",
|
"IndexerTagHelpText": "Só use este indexador para filmes com ao menos uma etiqueta correspondente. Deixe em branco para usar com todos os filmes.",
|
||||||
"RemoveSelectedItem": "Remover Item Selecionado",
|
"RemoveSelectedItem": "Remover Item Selecionado",
|
||||||
"RemoveFailed": "Falha na Remoção",
|
"RemoveFailed": "Falha na Remoção",
|
||||||
"RemoveCompleted": "Remover Completos",
|
"RemoveCompleted": "Remover Completos",
|
||||||
@@ -1087,7 +1087,7 @@
|
|||||||
"OnApplicationUpdateHelpText": "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}",
|
"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}",
|
||||||
"AnnouncedMsg": "Filme foi anunciado",
|
"AnnouncedMsg": "Filme foi anunciado",
|
||||||
"IndexerDownloadClientHelpText": "Especificar qual cliente de download é utilizado para baixar a partir deste indexador",
|
"IndexerDownloadClientHelpText": "Especificar em que cliente de download é usado para baixar deste indexador",
|
||||||
"LocalPath": "Caminho Local",
|
"LocalPath": "Caminho Local",
|
||||||
"ManualImportSetReleaseGroup": "Importar Manual - Definir Grupo de Lançamento",
|
"ManualImportSetReleaseGroup": "Importar Manual - Definir Grupo de Lançamento",
|
||||||
"SelectLanguages": "Selecionar Idiomas",
|
"SelectLanguages": "Selecionar Idiomas",
|
||||||
@@ -1144,15 +1144,7 @@
|
|||||||
"CollectionShowPostersHelpText": "Mostrar pôsteres de itens da coleção",
|
"CollectionShowPostersHelpText": "Mostrar pôsteres de itens da coleção",
|
||||||
"RottenTomatoesRating": "Avaliação Tomato",
|
"RottenTomatoesRating": "Avaliação Tomato",
|
||||||
"TotalMovies": "Total de Filmes",
|
"TotalMovies": "Total de Filmes",
|
||||||
"ApplicationURL": "URL do Aplicativo",
|
"ApplicationURL": "URL da Aplicação",
|
||||||
"ApplicationUrlHelpText": "A URL externa deste aplicativo, incluindo http(s)://, porta e base da URL",
|
"ApplicationUrlHelpText": "O URL externa deste aplicativo, incluindo http(s)://, porta e base de URL",
|
||||||
"PreferredProtocol": "Protocolo Preferido",
|
"PreferredProtocol": "Protocolo Preferido"
|
||||||
"SettingsThemeHelpText": "Alterar o tema da interface do usuário do aplicativo, o tema 'Auto' usará o tema do sistema operacional para definir o modo Claro ou Escuro. Inspirado por Theme.Park",
|
|
||||||
"ResetDefinitions": "Redefinir definições",
|
|
||||||
"ResetQualityDefinitions": "Redefinir Definições de Qualidade",
|
|
||||||
"ResetTitles": "Redefinir Títulos",
|
|
||||||
"ResetTitlesHelpText": "Redefinir títulos de definição, bem como valores",
|
|
||||||
"SettingsTheme": "Tema",
|
|
||||||
"AreYouSureYouWantToResetQualityDefinitions": "Tem certeza de que deseja redefinir as definições de qualidade?",
|
|
||||||
"RSSHelpText": "Será usado quando o Radarr procurar periodicamente lançamentos via RSS Sync"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,7 +170,7 @@
|
|||||||
"ExcludeTitle": "Исключить {0}? Radarr не будет автоматически добавлять сканируя лист.",
|
"ExcludeTitle": "Исключить {0}? Radarr не будет автоматически добавлять сканируя лист.",
|
||||||
"InCinemasMsg": "Фильмы в кинотеатрах",
|
"InCinemasMsg": "Фильмы в кинотеатрах",
|
||||||
"IncludeRecommendationsHelpText": "Включить в отображении найденного фильмы рекомендованные Radar",
|
"IncludeRecommendationsHelpText": "Включить в отображении найденного фильмы рекомендованные Radar",
|
||||||
"IndexerPriorityHelpText": "Приоритет индексатора от 1 (самый высокий) до 50 (самый низкий). По умолчанию: 25. Используется при захвате выпусков в качестве средства разрешения конфликтов для равных в остальном выпусков, Radarr по-прежнему будет использовать все включенные индексаторы для синхронизации и поиска RSS",
|
"IndexerPriorityHelpText": "Приоритет индексатора от 1 (самый высокий) до 50 (самый низкий). По умолчанию: 25. Используется при захвате выпусков в качестве средства разрешения конфликтов для равных в остальном выпусков, Radarr по-прежнему будет использовать все включенные индексаторы для синхронизации и поиска RSS.",
|
||||||
"IndexerSearchCheckNoAvailableIndexersMessage": "Все индексаторы с возможностью поиска временно выключены из-за ошибок",
|
"IndexerSearchCheckNoAvailableIndexersMessage": "Все индексаторы с возможностью поиска временно выключены из-за ошибок",
|
||||||
"KeyboardShortcuts": "Горячие клавиши",
|
"KeyboardShortcuts": "Горячие клавиши",
|
||||||
"CantFindMovie": "Почему я не могу найти фильм?",
|
"CantFindMovie": "Почему я не могу найти фильм?",
|
||||||
@@ -330,7 +330,7 @@
|
|||||||
"Connect": "Подключить",
|
"Connect": "Подключить",
|
||||||
"Connections": "Соединения",
|
"Connections": "Соединения",
|
||||||
"CompletedDownloadHandling": "Обработка завершенных скачиваний",
|
"CompletedDownloadHandling": "Обработка завершенных скачиваний",
|
||||||
"IndexerSearchCheckNoInteractiveMessage": "Нет доступных индексаторов с включенным интерактивным поиском, Radarr не будет предоставлять результаты интерактивного поиска",
|
"IndexerSearchCheckNoInteractiveMessage": "Нет доступных индексаторов с интерактивным поиском, Radarr не будет предоставлять результаты интерактивного поиска",
|
||||||
"IndexersSettingsSummary": "Ограничения для индексаторов и релизов",
|
"IndexersSettingsSummary": "Ограничения для индексаторов и релизов",
|
||||||
"Language": "Язык",
|
"Language": "Язык",
|
||||||
"ImportListStatusCheckAllClientMessage": "Все листы недоступны из-за ошибок",
|
"ImportListStatusCheckAllClientMessage": "Все листы недоступны из-за ошибок",
|
||||||
@@ -421,7 +421,7 @@
|
|||||||
"QualitySettingsSummary": "Качественные размеры и наименования",
|
"QualitySettingsSummary": "Качественные размеры и наименования",
|
||||||
"QualitySettings": "Настройки качества",
|
"QualitySettings": "Настройки качества",
|
||||||
"QualityProfiles": "Профили качества",
|
"QualityProfiles": "Профили качества",
|
||||||
"QualityProfileInUse": "Невозможно удалить профиль качества, прикрепленный к фильму, списку или коллекции",
|
"QualityProfileInUse": "Невозможно удалить профиль качества прикрепленный к фильму",
|
||||||
"QualityProfileDeleteConfirm": "Вы действительно хотите удалить профиль качества {0}",
|
"QualityProfileDeleteConfirm": "Вы действительно хотите удалить профиль качества {0}",
|
||||||
"QualityProfile": "Профиль качества",
|
"QualityProfile": "Профиль качества",
|
||||||
"QualityOrLangCutoffHasNotBeenMet": "Не соблюдено ограничение по качеству или языку",
|
"QualityOrLangCutoffHasNotBeenMet": "Не соблюдено ограничение по качеству или языку",
|
||||||
@@ -429,7 +429,7 @@
|
|||||||
"QualityDefinitions": "Определения качества",
|
"QualityDefinitions": "Определения качества",
|
||||||
"QualityCutoffHasNotBeenMet": "Порог качества не соблюден",
|
"QualityCutoffHasNotBeenMet": "Порог качества не соблюден",
|
||||||
"Quality": "Качество",
|
"Quality": "Качество",
|
||||||
"QualitiesHelpText": "Качества, расположенные выше в списке, являются более предпочтительными, даже если они не отмечены. Качества внутри одной группы равны. Требуются только отмеченные качества",
|
"QualitiesHelpText": "Качества, расположенные выше в списке, более предпочтительны. Качества внутри одной группы равны. Требуются только отмеченные качества",
|
||||||
"Qualities": "Качества",
|
"Qualities": "Качества",
|
||||||
"PublishedDate": "Дата публикации",
|
"PublishedDate": "Дата публикации",
|
||||||
"PtpOldSettingsCheckMessage": "Следующие индексаторы PassThePopcorn устарели и должны быть обновлены: {0}",
|
"PtpOldSettingsCheckMessage": "Следующие индексаторы PassThePopcorn устарели и должны быть обновлены: {0}",
|
||||||
@@ -747,7 +747,7 @@
|
|||||||
"BranchUpdateMechanism": "Ветвь, используемая внешним механизмом обновления",
|
"BranchUpdateMechanism": "Ветвь, используемая внешним механизмом обновления",
|
||||||
"BranchUpdate": "Ветвь для обновления Radarr",
|
"BranchUpdate": "Ветвь для обновления Radarr",
|
||||||
"Branch": "Ветка",
|
"Branch": "Ветка",
|
||||||
"BindAddressHelpText": "Действительный IP-адрес, локальный адрес или '*' для всех интерфейсов",
|
"BindAddressHelpText": "Действительный IPv4-адрес или '*' для всех интерфейсов",
|
||||||
"BackupFolderHelpText": "Относительные пути будут в каталоге AppData Radarr",
|
"BackupFolderHelpText": "Относительные пути будут в каталоге AppData Radarr",
|
||||||
"AvailabilityDelayHelpText": "Время до или после доступной даты для поиска фильма",
|
"AvailabilityDelayHelpText": "Время до или после доступной даты для поиска фильма",
|
||||||
"AvailabilityDelay": "Задержка доступности",
|
"AvailabilityDelay": "Задержка доступности",
|
||||||
@@ -1047,7 +1047,7 @@
|
|||||||
"RemotePathMappingCheckRemoteDownloadClient": "Удалённый клиент загрузки {0} сообщил о файлах в {1}, но эта директория, похоже, не существует. Вероятно, отсутствует сопоставление удаленных путей.",
|
"RemotePathMappingCheckRemoteDownloadClient": "Удалённый клиент загрузки {0} сообщил о файлах в {1}, но эта директория, похоже, не существует. Вероятно, отсутствует сопоставление удаленных путей.",
|
||||||
"RemotePathMappingCheckLocalWrongOSPath": "Локальный клиент загрузки {0} загружает файлы в {1}, но это не правильный путь {2}. Проверьте настройки клиента загрузки.",
|
"RemotePathMappingCheckLocalWrongOSPath": "Локальный клиент загрузки {0} загружает файлы в {1}, но это не правильный путь {2}. Проверьте настройки клиента загрузки.",
|
||||||
"RemotePathMappingCheckLocalFolderMissing": "Удалённый клиент загрузки {0} загружает файлы в {1}, но эта директория, похоже, не существует. Вероятно, отсутствует или неправильно указан удаленный путь.",
|
"RemotePathMappingCheckLocalFolderMissing": "Удалённый клиент загрузки {0} загружает файлы в {1}, но эта директория, похоже, не существует. Вероятно, отсутствует или неправильно указан удаленный путь.",
|
||||||
"RemotePathMappingCheckGenericPermissions": "Клиент загрузки {0} загружает файлы в {1}, но Radarr не может видеть этот каталог. Возможно, вам нужно настроить права доступа к данной директории.",
|
"RemotePathMappingCheckGenericPermissions": "Клиент загрузки {0} загружает файлы в {1}, но Radarr не может найти эту директорию. Возможно, вам нужно настроить права доступа к данной директории.",
|
||||||
"RemotePathMappingCheckFilesBadDockerPath": "Вы используете docker; клиент загрузки {0} сообщил о файлах в {1}, но это не корректный путь {2}. Проверьте правильность указанного пути и настройки клиента загрузки.",
|
"RemotePathMappingCheckFilesBadDockerPath": "Вы используете docker; клиент загрузки {0} сообщил о файлах в {1}, но это не корректный путь {2}. Проверьте правильность указанного пути и настройки клиента загрузки.",
|
||||||
"RemotePathMappingCheckImportFailed": "Radarr не удалось импортировать фильм. Проверьте ваши логи для более подробной информации.",
|
"RemotePathMappingCheckImportFailed": "Radarr не удалось импортировать фильм. Проверьте ваши логи для более подробной информации.",
|
||||||
"RemotePathMappingCheckFolderPermissions": "Radarr видит директорию загрузки {0}, но не имеет доступа к ней. Возможно, ошибка в правах доступа.",
|
"RemotePathMappingCheckFolderPermissions": "Radarr видит директорию загрузки {0}, но не имеет доступа к ней. Возможно, ошибка в правах доступа.",
|
||||||
@@ -1108,7 +1108,7 @@
|
|||||||
"AllCollectionsHiddenDueToFilter": "Все фильмы скрыты в соответствии с фильтром.",
|
"AllCollectionsHiddenDueToFilter": "Все фильмы скрыты в соответствии с фильтром.",
|
||||||
"Collections": "Коллекции",
|
"Collections": "Коллекции",
|
||||||
"MonitorMovies": "Отслеживать фильм",
|
"MonitorMovies": "Отслеживать фильм",
|
||||||
"NoCollections": "Коллекции не найдены. Для начала вам нужно добавить новый фильм или импортировать несколько существующих",
|
"NoCollections": "Коллекции не найдены. Для начала вам нужно добавить новый фильм или импортировать несколько существующих.",
|
||||||
"CollectionOptions": "Параметры коллекции",
|
"CollectionOptions": "Параметры коллекции",
|
||||||
"CollectionShowDetailsHelpText": "Показать статус и свойства коллекции",
|
"CollectionShowDetailsHelpText": "Показать статус и свойства коллекции",
|
||||||
"CollectionShowOverviewsHelpText": "Показать обзоры коллекций",
|
"CollectionShowOverviewsHelpText": "Показать обзоры коллекций",
|
||||||
@@ -1142,17 +1142,5 @@
|
|||||||
"RottenTomatoesRating": "Tomato рейтинг",
|
"RottenTomatoesRating": "Tomato рейтинг",
|
||||||
"Started": "Запущено",
|
"Started": "Запущено",
|
||||||
"Database": "База данных",
|
"Database": "База данных",
|
||||||
"From": "из",
|
"From": "из"
|
||||||
"AreYouSureYouWantToResetQualityDefinitions": "Вы уверены, что хотите сбросить определения качества?",
|
|
||||||
"ResetDefinitions": "Сбросить определения",
|
|
||||||
"ResetQualityDefinitions": "Сбросить определения качества",
|
|
||||||
"ResetTitles": "Сбросить заголовки",
|
|
||||||
"ResetTitlesHelpText": "Сбросить заголовки определений, а также значения",
|
|
||||||
"RSSHelpText": "Будет использоваться, когда Radarr будет периодически искать выпуски через RSS Sync",
|
|
||||||
"SettingsTheme": "Тема",
|
|
||||||
"SettingsThemeHelpText": "Измените тему пользовательского интерфейса приложения, тема «Авто» будет использовать тему вашей ОС для установки светлого или темного режима. Вдохновленный Theme.Park",
|
|
||||||
"PreferredProtocol": "Предпочтительный протокол",
|
|
||||||
"ApplicationURL": "URL-адрес приложения",
|
|
||||||
"ApplicationUrlHelpText": "Внешний URL-адрес этого приложения, включая http(s)://, порт и базовый URL-адрес",
|
|
||||||
"ScrollMovies": "Прокрутите фильмы"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
"Backups": "Резервні копії",
|
"Backups": "Резервні копії",
|
||||||
"BeforeUpdate": "Перед оновленням",
|
"BeforeUpdate": "Перед оновленням",
|
||||||
"BindAddress": "Прив'язувати адресу",
|
"BindAddress": "Прив'язувати адресу",
|
||||||
"BindAddressHelpText": "Дійсна адреса IP або '*' для всіх інтерфейсів",
|
"BindAddressHelpText": "Дійсна адреса IPv4 або '*' для всіх інтерфейсів",
|
||||||
"Blocklist": "Чорний список",
|
"Blocklist": "Чорний список",
|
||||||
"Blocklisted": "Заблокований",
|
"Blocklisted": "Заблокований",
|
||||||
"BlocklistRelease": "Реліз із чорного списку",
|
"BlocklistRelease": "Реліз із чорного списку",
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"CloneProfile": "Клонувати профіль",
|
"CloneProfile": "Клонувати профіль",
|
||||||
"Close": "Закрити",
|
"Close": "Закрити",
|
||||||
"CloseCurrentModal": "Закрити поточне вікно",
|
"CloseCurrentModal": "Закрити поточне вікно",
|
||||||
"Collection": "Колекції",
|
"Collection": "Колекція",
|
||||||
"ColonReplacement": "Заміна двокрапок",
|
"ColonReplacement": "Заміна двокрапок",
|
||||||
"ColonReplacementFormatHelpText": "Змінити як Radarr обробляє заміну двокрапок",
|
"ColonReplacementFormatHelpText": "Змінити як Radarr обробляє заміну двокрапок",
|
||||||
"Columns": "Колонки",
|
"Columns": "Колонки",
|
||||||
@@ -218,941 +218,5 @@
|
|||||||
"ImportCustomFormat": "Додати свій формат",
|
"ImportCustomFormat": "Додати свій формат",
|
||||||
"DeleteRestrictionHelpText": "Ви впевнені, що хочете видалити цей профіль затримки?",
|
"DeleteRestrictionHelpText": "Ви впевнені, що хочете видалити цей профіль затримки?",
|
||||||
"AllCollectionsHiddenDueToFilter": "Всі фільми заховані відповідно до фільтра.",
|
"AllCollectionsHiddenDueToFilter": "Всі фільми заховані відповідно до фільтра.",
|
||||||
"Collections": "Колекція",
|
"Collections": "Колекція"
|
||||||
"CollectionOptions": "Параметри колекції",
|
|
||||||
"CollectionShowDetailsHelpText": "Показати статус і властивості колекції",
|
|
||||||
"CollectionShowOverviewsHelpText": "Показати огляд колекції",
|
|
||||||
"CollectionShowPostersHelpText": "Показати плакати предметів колекції",
|
|
||||||
"DeleteList": "Видалити список",
|
|
||||||
"DeleteMovieFolderHelpText": "Видалити папку з фільмами та її вміст",
|
|
||||||
"DeleteImportListExclusion": "Видалити виключення зі списку імпорту",
|
|
||||||
"DeleteIndexer": "Видалити індексатор",
|
|
||||||
"DeleteMovieFolderLabel": "Видалити папку з фільмами",
|
|
||||||
"DeleteSelectedMovie": "Видалити вибрані фільм(и)",
|
|
||||||
"Enable": "Увімкнути",
|
|
||||||
"EnableAutomaticAdd": "Увімкнути автоматичне додавання",
|
|
||||||
"EnableAutomaticSearchHelpText": "Використовуватиметься, коли автоматичний пошук виконується через інтерфейс користувача або Radarr",
|
|
||||||
"Ended": "Завершено",
|
|
||||||
"Fixed": "Виправлено",
|
|
||||||
"FocusSearchBox": "Перейти до вікна пошуку",
|
|
||||||
"Filters": "Фільтри",
|
|
||||||
"FirstDayOfWeek": "Перший день тижня",
|
|
||||||
"IgnoreDeletedMovies": "Відключити моніторинг видалених фільмів",
|
|
||||||
"IgnoredPlaceHolder": "Додайте нове обмеження",
|
|
||||||
"ImportedTo": "Імпортовано в",
|
|
||||||
"ImportErrors": "Помилки імпорту",
|
|
||||||
"Imported": "Імпортні",
|
|
||||||
"IndexersSettingsSummary": "Індексатори та обмеження випуску",
|
|
||||||
"LogLevelTraceHelpTextWarning": "Журнал трасування слід увімкнути лише тимчасово",
|
|
||||||
"LogLevel": "Рівень журналу",
|
|
||||||
"Monday": "Понеділок",
|
|
||||||
"MonitoredHelpText": "Завантажте фільм, якщо є",
|
|
||||||
"MoreDetails": "Детальніше",
|
|
||||||
"MountCheckMessage": "Монтування, що містить шлях до фільму, монтується лише для читання: ",
|
|
||||||
"MovieIsRecommend": "Фільм рекомендовано на основі останнього додавання",
|
|
||||||
"MovieIsOnImportExclusionList": "Фільм у списку винятків для імпорту",
|
|
||||||
"MultiLanguage": "Багатомовність",
|
|
||||||
"NoLeaveIt": "Ні, залиште це",
|
|
||||||
"NoLimitForAnyRuntime": "Немає обмежень для будь-якого часу виконання",
|
|
||||||
"NoCollections": "Колекції не знайдено. Щоб почати, ви захочете додати новий фільм або імпортувати кілька наявних",
|
|
||||||
"NoEventsFound": "Подій не знайдено",
|
|
||||||
"NoHistory": "Без історії",
|
|
||||||
"None": "Жодного",
|
|
||||||
"OnHealthIssue": "Про питання здоров'я",
|
|
||||||
"RemotePathMappingCheckDownloadPermissions": "Radarr може бачити, але не має доступу до завантаженого фільму {0}. Ймовірна помилка дозволів.",
|
|
||||||
"Remove": "Видалити",
|
|
||||||
"RemotePathMappingCheckWrongOSPath": "Клієнт віддаленого завантаження {0} розміщує завантаження в {1}, але це недійсний шлях {2}. Перегляньте свої віддалені відображення шляхів і завантажте налаштування клієнта.",
|
|
||||||
"ReplaceWithSpaceDashSpace": "Замінити на Пробіл Тире Пробіл",
|
|
||||||
"RequiredHelpText": "Ця умова {0} має збігатися, щоб користувацький формат застосовувався. В іншому випадку достатньо одного збігу {1}.",
|
|
||||||
"RequiredRestrictionHelpText": "Реліз має містити принаймні один із цих термінів (незалежно від регістру)",
|
|
||||||
"RequiredRestrictionPlaceHolder": "Додайте нове обмеження",
|
|
||||||
"Required": "Обов'язковий",
|
|
||||||
"SelectLanguage": "Оберіть мову",
|
|
||||||
"UnableToLoadDownloadClients": "Не вдалося завантажити клієнти для завантаження",
|
|
||||||
"OnApplicationUpdate": "Оновлення програми",
|
|
||||||
"OutputPath": "Вихідний шлях",
|
|
||||||
"Overview": "Огляд",
|
|
||||||
"ProxyType": "Тип проксі",
|
|
||||||
"RecyclingBin": "Сміттєвий кошик",
|
|
||||||
"Result": "Результат",
|
|
||||||
"Retention": "Утримання",
|
|
||||||
"RetryingDownloadInterp": "Повторна спроба завантажити {0} о {1}",
|
|
||||||
"Settings": "Налаштування",
|
|
||||||
"ShowSizeOnDisk": "Показати розмір на диску",
|
|
||||||
"ShowTitle": "Показати назву",
|
|
||||||
"ShowStudio": "Показати Студію",
|
|
||||||
"UnableToLoadCustomFormats": "Не вдалося завантажити спеціальні формати",
|
|
||||||
"Auto": "Авто",
|
|
||||||
"Downloading": "Завантаження",
|
|
||||||
"EnableColorImpairedMode": "Увімкнути режим із порушенням кольору",
|
|
||||||
"Duration": "Тривалість",
|
|
||||||
"EnableHelpText": "Увімкнути створення файлу метаданих для цього типу метаданих",
|
|
||||||
"Error": "Помилка",
|
|
||||||
"ErrorLoadingContents": "Помилка завантаження вмісту",
|
|
||||||
"ErrorLoadingPreviews": "Помилка завантаження попереднього перегляду",
|
|
||||||
"ErrorRestoringBackup": "Помилка відновлення резервної копії",
|
|
||||||
"Events": "Події",
|
|
||||||
"FailedLoadingSearchResults": "Не вдалося завантажити результати пошуку, повторіть спробу.",
|
|
||||||
"FailedToLoadMovieFromAPI": "Не вдалося завантажити фільм із API",
|
|
||||||
"FileDateHelpText": "Змінити дату файлу під час імпорту/повторного сканування",
|
|
||||||
"Files": "Файли",
|
|
||||||
"Filter": "Фільтр",
|
|
||||||
"Folders": "Папки",
|
|
||||||
"FollowPerson": "Слідкуйте за особою",
|
|
||||||
"From": "від",
|
|
||||||
"HideAdvanced": "Сховати додаткові",
|
|
||||||
"History": "Історія",
|
|
||||||
"MinimumAge": "Мінімальний вік",
|
|
||||||
"MinimumAvailability": "Мінімальна доступність",
|
|
||||||
"MinimumCustomFormatScore": "Мінімальна оцінка спеціального формату",
|
|
||||||
"MovieDetailsPreviousMovie": "Відомості про фільм: попередній фільм",
|
|
||||||
"MovieEditor": "Редактор фільмів",
|
|
||||||
"PtpOldSettingsCheckMessage": "Наведені нижче індексатори PassThePopcorn мають застарілі налаштування та їх потрібно оновити: {0}",
|
|
||||||
"ProxyPasswordHelpText": "Вам потрібно лише ввести ім’я користувача та пароль, якщо вони потрібні. В іншому випадку залиште їх порожніми.",
|
|
||||||
"PublishedDate": "Дата публікації",
|
|
||||||
"QualityDefinitions": "Визначення якості",
|
|
||||||
"QualityLimitsHelpText": "Обмеження автоматично регулюються для тривалості фільму.",
|
|
||||||
"RemotePathMappingCheckFilesGenericPermissions": "Завантажте файли звітів клієнта {0} в {1}, але Radarr не бачить цей каталог. Можливо, вам знадобиться налаштувати дозволи для папки.",
|
|
||||||
"RescanMovieFolderAfterRefresh": "Перескануйте папку фільму після оновлення",
|
|
||||||
"Reset": "Скинути",
|
|
||||||
"ResetAPIKey": "Скинути ключ API",
|
|
||||||
"Restart": "Перезавантажити",
|
|
||||||
"RestartRadarr": "Перезавантажити Radarr",
|
|
||||||
"RestartRequiredHelpTextWarning": "Щоб набуло чинності, потрібно перезапустити",
|
|
||||||
"RestoreBackup": "Відновлення резервної копії",
|
|
||||||
"Restrictions": "Обмеження",
|
|
||||||
"RootFolder": "Коренева папка",
|
|
||||||
"RootFolderCheckMultipleMessage": "Відсутні кілька кореневих папок: {0}",
|
|
||||||
"Runtime": "Час виконання",
|
|
||||||
"Search": "Пошук",
|
|
||||||
"SearchAll": "Пошук у всіх",
|
|
||||||
"UsenetDelay": "Затримка Usenet",
|
|
||||||
"Downloaded": "Завантажено",
|
|
||||||
"Existing": "Існуючий",
|
|
||||||
"ImportFailed": "Помилка імпорту: {0}",
|
|
||||||
"Importing": "Імпорт",
|
|
||||||
"InCinemas": "У кінотеатрах",
|
|
||||||
"IncludeRadarrRecommendations": "Включити рекомендації Radarr",
|
|
||||||
"Indexer": "Індексатор",
|
|
||||||
"Language": "Мова",
|
|
||||||
"MetadataSettingsSummary": "Створюйте файли метаданих, коли фільми імпортуються або оновлюються",
|
|
||||||
"Month": "Місяць",
|
|
||||||
"NoMoveFilesSelf": " Ні, я сам перенесу файли",
|
|
||||||
"Sunday": "Неділя",
|
|
||||||
"Tasks": "Задачі",
|
|
||||||
"Today": "Сьогодні",
|
|
||||||
"Tomorrow": "Завтра",
|
|
||||||
"TorrentDelay": "Затримка торрента",
|
|
||||||
"OnMovieAddedHelpText": "Фільм додано",
|
|
||||||
"OnMovieAdded": "У фільмі додано",
|
|
||||||
"OnMovieFileDelete": "Видаленні відеофайлу",
|
|
||||||
"OnMovieFileDeleteForUpgrade": "Видалити відеофайл для оновлення",
|
|
||||||
"OnMovieDelete": "Фільм видалено",
|
|
||||||
"OnRename": "При перейменуванні",
|
|
||||||
"OnMovieFileDeleteHelpText": "Видаленні відеофайлу",
|
|
||||||
"OnRenameHelpText": "При перейменуванні",
|
|
||||||
"OpenThisModal": "Відкрийте цей модальний вікно",
|
|
||||||
"PageSize": "Розмір сторінки",
|
|
||||||
"PageSizeHelpText": "Кількість елементів для показу на кожній сторінці",
|
|
||||||
"Password": "Пароль",
|
|
||||||
"Path": "Шлях",
|
|
||||||
"OriginalTitle": "Оригінальна назва",
|
|
||||||
"Presets": "Предустановки",
|
|
||||||
"PreviewRename": "Попередній перегляд Перейменування",
|
|
||||||
"PreviewRenameHelpText": "Порада: щоб переглянути перейменування... виберіть «Скасувати», потім клацніть назву будь-якого фільму та скористайтеся",
|
|
||||||
"Priority": "Пріоритет",
|
|
||||||
"Profiles": "Профілі",
|
|
||||||
"ProcessingFolders": "Обробка папок",
|
|
||||||
"Proxy": "Проксі",
|
|
||||||
"ProxyBypassFilterHelpText": "Використовуйте «,» як роздільник і «*». як символ підстановки для субдоменів",
|
|
||||||
"ProtocolHelpText": "Виберіть протокол(и) для використання та який із них є кращим під час вибору між однаковими випусками",
|
|
||||||
"ProxyUsernameHelpText": "Вам потрібно лише ввести ім’я користувача та пароль, якщо вони потрібні. В іншому випадку залиште їх порожніми.",
|
|
||||||
"QualitySettings": "Налаштування якості",
|
|
||||||
"QualitySettingsSummary": "Якісні розміри та найменування",
|
|
||||||
"QualityProfiles": "Профілі якості",
|
|
||||||
"Queue": "Черга",
|
|
||||||
"Queued": "У черзі",
|
|
||||||
"RadarrSupportsAnyIndexer": "Radarr підтримує будь-який індексатор, який використовує стандарт Newznab, а також інші індексатори, перелічені нижче.",
|
|
||||||
"RadarrSupportsAnyDownloadClient": "Radarr підтримує багато популярних торрент-клієнтів і клієнтів для завантаження через Usenet.",
|
|
||||||
"RadarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow": "Radarr підтримує будь-які списки фільмів RSS, а також наведений нижче.",
|
|
||||||
"RecentChanges": "Останні зміни",
|
|
||||||
"Reason": "Причина",
|
|
||||||
"RecentFolders": "Останні папки",
|
|
||||||
"RecycleBinCleanupDaysHelpText": "Встановіть значення 0, щоб вимкнути автоматичне очищення",
|
|
||||||
"RecyclingBinCleanup": "Очищення сміттєвого кошика",
|
|
||||||
"RefreshInformationAndScanDisk": "Оновити інформацію та сканувати диск",
|
|
||||||
"RefreshCollections": "Оновити колекції",
|
|
||||||
"RefreshLists": "Оновити списки",
|
|
||||||
"RefreshMonitoredIntervalHelpText": "Як часто оновлювати відстежувані завантаження з клієнтів завантаження, мінімум 1 хвилина",
|
|
||||||
"ReleaseDates": "Дати випуску",
|
|
||||||
"ReleasedMsg": "Фільм виходить",
|
|
||||||
"ReleaseGroup": "Група випуску",
|
|
||||||
"ReleaseRejected": "Реліз відхилено",
|
|
||||||
"RemoveFailed": "Не вдалося видалити",
|
|
||||||
"RemoveDownloadsAlert": "Параметри видалення переміщено до окремих налаштувань клієнта завантаження в таблиці вище.",
|
|
||||||
"RetentionHelpText": "Лише Usenet: встановіть нуль, щоб налаштувати необмежену утримку",
|
|
||||||
"Seconds": "Секунди",
|
|
||||||
"Security": "Безпека",
|
|
||||||
"SelectMovie": "Виберіть Фільм",
|
|
||||||
"SetPermissionsLinuxHelpTextWarning": "Якщо ви не впевнені, що ці налаштування роблять, не змінюйте їх.",
|
|
||||||
"SetTags": "Встановити теги",
|
|
||||||
"SettingsFirstDayOfWeek": "Перший день тижня",
|
|
||||||
"SettingsRemotePathMappingRemotePathHelpText": "Кореневий шлях до каталогу, до якого має доступ клієнт завантаження",
|
|
||||||
"SettingsRuntimeFormat": "Формат виконання",
|
|
||||||
"SettingsWeekColumnHeader": "Заголовок стовпця тижня",
|
|
||||||
"SettingsShowRelativeDatesHelpText": "Показати відносні (сьогодні/вчора/тощо) або абсолютні дати",
|
|
||||||
"ShowMovieInformation": "Показати інформацію про фільм",
|
|
||||||
"ShowMovieInformationHelpText": "Показати жанри фільмів і сертифікати",
|
|
||||||
"ShownClickToHide": "Показано, натисніть, щоб приховати",
|
|
||||||
"ShowOverview": "Показати огляд",
|
|
||||||
"ShowMonitoredHelpText": "Показати відстежуваний статус під плакатом",
|
|
||||||
"ShowSearchHelpText": "Показувати кнопку пошуку при наведенні",
|
|
||||||
"Size": "Розмір",
|
|
||||||
"StartupDirectory": "Каталог запуску",
|
|
||||||
"ThisConditionMatchesUsingRegularExpressions": "Ця умова відповідає використанню регулярних виразів. Зауважте, що символи {0} мають особливі значення та потребують екранування за допомогою {1}",
|
|
||||||
"UILanguage": "Мова інтерфейсу користувача",
|
|
||||||
"UnableToAddANewCustomFormatPleaseTryAgain": "Не вдалося додати новий спеціальний формат, спробуйте ще раз.",
|
|
||||||
"UnableToAddANewDownloadClientPleaseTryAgain": "Не вдається додати новий клієнт для завантаження, повторіть спробу.",
|
|
||||||
"UnableToAddANewIndexerPleaseTryAgain": "Не вдалося додати новий індексатор, спробуйте ще раз.",
|
|
||||||
"UnableToAddANewListExclusionPleaseTryAgain": "Не вдається додати нове виключення зі списку, повторіть спробу.",
|
|
||||||
"UnableToAddANewListPleaseTryAgain": "Не вдалося додати новий список, спробуйте ще раз.",
|
|
||||||
"UnableToLoadIndexers": "Не вдалося завантажити індексатори",
|
|
||||||
"UnableToLoadQualities": "Неможливо завантажити якості",
|
|
||||||
"UpperCase": "Великі літери",
|
|
||||||
"TotalMovies": "Всього фільмів",
|
|
||||||
"TotalSpace": "Загальний простір",
|
|
||||||
"UISettings": "Налаштування інтерфейсу користувача",
|
|
||||||
"UILanguageHelpText": "Мова, яку Radarr використовуватиме для інтерфейсу користувача",
|
|
||||||
"UILanguageHelpTextWarning": "Потрібно перезавантажити браузер",
|
|
||||||
"UnableToLoadBackups": "Не вдалося завантажити резервні копії",
|
|
||||||
"UnableToLoadBlocklist": "Не вдалося завантажити список блокувань",
|
|
||||||
"UnableToLoadCollections": "Не вдалося завантажити колекції",
|
|
||||||
"UnableToLoadAltTitle": "Не вдалося завантажити альтернативні назви.",
|
|
||||||
"UnableToLoadNamingSettings": "Не вдалося завантажити налаштування імен",
|
|
||||||
"UnableToLoadRestrictions": "Не вдалося завантажити обмеження",
|
|
||||||
"UnableToLoadTheCalendar": "Неможливо завантажити календар",
|
|
||||||
"UnableToLoadTags": "Не вдалося завантажити теги",
|
|
||||||
"Unreleased": "Недоступний",
|
|
||||||
"UnsavedChanges": "Незбережені зміни",
|
|
||||||
"Indexers": "Індексатори",
|
|
||||||
"ListTagsHelpText": "Буде додано елементи списку тегів",
|
|
||||||
"ListUpdateInterval": "Інтервал оновлення списку",
|
|
||||||
"LoadingMovieCreditsFailed": "Не вдалося завантажити титри фільму",
|
|
||||||
"MustContain": "Має містити",
|
|
||||||
"PreferUsenet": "Віддавайте перевагу Usenet",
|
|
||||||
"SSLCertPathHelpText": "Шлях до файлу pfx",
|
|
||||||
"StartProcessing": "Почати обробку",
|
|
||||||
"Waiting": "Очікування",
|
|
||||||
"WaitingToImport": "Очікування імпорту",
|
|
||||||
"WaitingToProcess": "Очікування обробки",
|
|
||||||
"VisitGithubCustomFormatsAphrodite": "Відвідайте вікі для отримання додаткової інформації: ",
|
|
||||||
"EnableAutoHelpText": "Якщо ввімкнено, фільми автоматично додаватимуться до Radarr із цього списку",
|
|
||||||
"Enabled": "Увімкнено",
|
|
||||||
"EnabledHelpText": "Увімкнути цей список для використання в Radarr",
|
|
||||||
"EnableMediaInfoHelpText": "Отримайте з файлів інформацію про відео, таку як роздільна здатність, час виконання та кодек. Це вимагає, щоб Radarr читав частини файлу, що може спричинити високу дискову або мережеву активність під час сканування.",
|
|
||||||
"ExtraFileExtensionsHelpTexts1": "Розділений комами список додаткових файлів для імпорту (.nfo буде імпортовано як .nfo-orig)",
|
|
||||||
"FileNameTokens": "Маркери імен файлів",
|
|
||||||
"FolderMoveRenameWarning": "Це також перейменує папку з фільмами відповідно до формату папки з фільмами в налаштуваннях.",
|
|
||||||
"IndexerSearchCheckNoAutomaticMessage": "Немає доступних індексаторів із увімкненим автоматичним пошуком, Radarr не надаватиме автоматичних результатів пошуку",
|
|
||||||
"HiddenClickToShow": "Приховано, натисніть, щоб показати",
|
|
||||||
"HomePage": "Домашня сторінка",
|
|
||||||
"IgnoredHelpText": "Випуск буде відхилено, якщо він містить один або кілька термінів (незалежно від регістру)",
|
|
||||||
"ImportExtraFilesHelpText": "Імпортуйте відповідні додаткові файли (субтитри, nfo тощо) після імпортування файлу фільму",
|
|
||||||
"ImportListMissingRoot": "Відсутня коренева папка для списків імпорту: {0}",
|
|
||||||
"IncludeRecommendationsHelpText": "Включіть рекомендовані Radarr фільми в режим Discovery",
|
|
||||||
"IndexerLongTermStatusCheckAllClientMessage": "Усі індексатори недоступні через збої більше 6 годин",
|
|
||||||
"DestinationRelativePath": "Відносний шлях призначення",
|
|
||||||
"EditCollection": "Редагувати колекцію",
|
|
||||||
"ForMoreInformationOnTheIndividualDownloadClients": "Щоб отримати додаткові відомості про окремі клієнти для завантаження, натисніть кнопки додаткових відомостей.",
|
|
||||||
"IndexerTagHelpText": "Використовуйте цей індексатор лише для фільмів із принаймні одним відповідним тегом. Залиште поле порожнім для використання з усіма фільмами.",
|
|
||||||
"Info": "Інформація",
|
|
||||||
"InstanceName": "Ім'я екземпляра",
|
|
||||||
"InstanceNameHelpText": "Ім’я екземпляра на вкладці та ім’я програми Syslog",
|
|
||||||
"KeepAndUnmonitorMovie": "Зберегти та скасувати моніторинг фільму",
|
|
||||||
"LaunchBrowserHelpText": " Відкрийте веб-браузер і перейдіть на домашню сторінку Radarr під час запуску програми.",
|
|
||||||
"ListSyncLevelHelpText": "Фільми з бібліотеки буде видалено або відстежуватись не буде, якщо їх немає у вашому списку",
|
|
||||||
"LocalPath": "Місцевий шлях",
|
|
||||||
"LowerCase": "Малі літери",
|
|
||||||
"MaximumLimits": "Максимальні обмеження",
|
|
||||||
"MinimumAgeHelpText": "Тільки Usenet: мінімальний вік NZB у хвилинах до їх захоплення. Використовуйте це, щоб дати новим випускам час для поширення до вашого провайдера usenet.",
|
|
||||||
"MinimumFreeSpace": "Мінімальний вільний простір",
|
|
||||||
"MinimumLimits": "Мінімальні обмеження",
|
|
||||||
"MovieCollectionMissingRoot": "Відсутня коренева папка для колекції фільмів: {0}",
|
|
||||||
"MoveFolders1": "Бажаєте перемістити папки з фільмами до \"{0}\"?",
|
|
||||||
"MoveFolders2": "Бажаєте перемістити файли фільму з \"{0}\" до \"{1}\"?",
|
|
||||||
"MovieFolderFormat": "Формат папки фільму",
|
|
||||||
"MovieIndexScrollTop": "Індекс фільму: прокрутка вгору",
|
|
||||||
"MovieInfoLanguageHelpText": "Мова, яку Radarr використовуватиме для інформації про фільм в інтерфейсі користувача",
|
|
||||||
"MovieIsDownloadingInterp": "Фільм завантажується - {0}% {1}",
|
|
||||||
"NextExecution": "Наступне виконання",
|
|
||||||
"OnMovieFileDeleteForUpgradeHelpText": "Видалити відеофайл для оновлення",
|
|
||||||
"OrganizeModalDisabled": "Перейменування вимкнено, перейменовувати нічого",
|
|
||||||
"OrganizeModalSuccess": "Успіх! Мою роботу виконано, немає файлів для перейменування.",
|
|
||||||
"OrganizeSelectedMovies": "Упорядкуйте вибрані фільми",
|
|
||||||
"PendingChangesMessage": "У вас є незбережені зміни. Ви впевнені, що бажаєте залишити цю сторінку?",
|
|
||||||
"PosterSize": "Розмір плаката",
|
|
||||||
"PreferredProtocol": "Переважний протокол",
|
|
||||||
"PriorityHelpText": "Надайте пріоритет кільком клієнтам завантаження. Круговий алгоритм використовується для клієнтів з таким же пріоритетом.",
|
|
||||||
"ProxyCheckBadRequestMessage": "Не вдалося перевірити проксі. Код стану: {0}",
|
|
||||||
"ProxyCheckResolveIpMessage": "Не вдалося визначити IP-адресу для налаштованого проксі-сервера {0}",
|
|
||||||
"QualitiesHelpText": "Якості, які стоять вище в списку, є кращими, навіть якщо не позначено. Якості в одній групі рівні. Потрібні тільки перевірені якості",
|
|
||||||
"QualityProfileInUse": "Неможливо видалити профіль якості, доданий до фільму, списку або колекції",
|
|
||||||
"RemotePathMappingCheckBadDockerPath": "Ви використовуєте docker; клієнт завантаження {0} розміщує завантаження в {1}, але це недійсний шлях {2}. Перегляньте свої віддалені відображення шляхів і завантажте налаштування клієнта.",
|
|
||||||
"RemotePathMappingCheckRemoteDownloadClient": "Клієнт віддаленого завантаження {0} повідомив про файли в {1}, але цей каталог, здається, не існує. Ймовірно, відсутнє відображення віддаленого шляху.",
|
|
||||||
"RemoveSelected": "Видалити вибране",
|
|
||||||
"ReplaceIllegalCharactersHelpText": "Замінити недопустимі символи. Якщо не позначено, Radarr видалить їх",
|
|
||||||
"RescanAfterRefreshHelpTextWarning": "Radarr не визначатиме автоматично зміни файлів, якщо не встановлено значення «Завжди»",
|
|
||||||
"RestartReloadNote": "Примітка: Radarr автоматично перезапуститься та перезавантажить інтерфейс під час процесу відновлення.",
|
|
||||||
"RottenTomatoesRating": "Рейтинг томатів",
|
|
||||||
"RssSyncHelpText": "Інтервал у хвилинах. Встановіть нуль, щоб вимкнути (це зупинить автоматичне захоплення звільнення)",
|
|
||||||
"ScriptPath": "Шлях сценарію",
|
|
||||||
"SearchFailedPleaseTryAgainLater": "Помилка пошуку, спробуйте пізніше.",
|
|
||||||
"SearchOnAddCollectionHelpText": "Шукайте фільми в цій колекції після додавання в бібліотеку",
|
|
||||||
"SelectReleaseGroup": "Виберіть Release Group",
|
|
||||||
"SendAnonymousUsageData": "Надсилати анонімні дані про використання",
|
|
||||||
"SettingsEnableColorImpairedMode": "Увімкнути режим із порушенням кольору",
|
|
||||||
"SettingsEnableColorImpairedModeHelpText": "Змінений стиль, щоб користувачі з вадами кольору могли краще розрізняти кольорову кодовану інформацію",
|
|
||||||
"SettingsThemeHelpText": "Змініть тему інтерфейсу додатка, тема «Авто» використовуватиме вашу тему ОС, щоб установити світлий або темний режим. Натхненний Theme.Park",
|
|
||||||
"SettingsWeekColumnHeaderHelpText": "Відображається над кожним стовпцем, коли тиждень є активним переглядом",
|
|
||||||
"ShowCertification": "Показати сертифікат",
|
|
||||||
"ShowCollectionDetails": "Показати статус колекції",
|
|
||||||
"ShowPath": "Показати шлях",
|
|
||||||
"ShowQualityProfileHelpText": "Покажіть якісний профіль під плакатом",
|
|
||||||
"ShowTitleHelpText": "Показати назву фільму під постером",
|
|
||||||
"SkipFreeSpaceCheck": "Пропустити перевірку вільного місця",
|
|
||||||
"SkipFreeSpaceCheckWhenImportingHelpText": "Використовуйте, коли Radarr не може виявити вільне місце в кореневій папці фільму",
|
|
||||||
"SqliteVersionCheckUpgradeRequiredMessage": "Наразі встановлена версія SQLite {0} більше не підтримується. Оновіть SQLite принаймні до версії {1}.",
|
|
||||||
"TheLogLevelDefault": "Рівень журналу за замовчуванням має значення «Інформація», і його можна змінити",
|
|
||||||
"ThisCannotBeCancelled": "Це не можна скасувати після запуску без вимкнення всіх ваших індексаторів.",
|
|
||||||
"TorrentDelayHelpText": "Затримка в хвилинах, щоб зачекати, перш ніж захопити торрент",
|
|
||||||
"UISettingsSummary": "Параметри календаря, дати та кольору",
|
|
||||||
"UnableToAddANewNotificationPleaseTryAgain": "Не вдалося додати нове сповіщення, спробуйте ще раз.",
|
|
||||||
"UnableToAddANewRemotePathMappingPleaseTryAgain": "Не вдалося додати нове зіставлення віддаленого шляху, спробуйте ще раз.",
|
|
||||||
"UnableToLoadDownloadClientOptions": "Не вдалося завантажити параметри клієнта для завантаження",
|
|
||||||
"UnableToLoadListExclusions": "Неможливо завантажити список винятків",
|
|
||||||
"UnableToLoadManualImportItems": "Не вдалося завантажити елементи ручного імпорту",
|
|
||||||
"UnableToLoadMovies": "Неможливо завантажити фільми",
|
|
||||||
"UnableToLoadQualityProfiles": "Не вдалося завантажити профілі якості",
|
|
||||||
"UnableToLoadResultsIntSearch": "Неможливо завантажити результати для цього пошуку фільмів. Спробуйте ще раз пізніше",
|
|
||||||
"Unmonitored": "Неконтрольований",
|
|
||||||
"UnmonitoredHelpText": "Включайте неконтрольовані фільми в канал iCal",
|
|
||||||
"IndexerJackettAll": "Індексатори, які використовують непідтримувану кінцеву точку Jackett 'all': {0}",
|
|
||||||
"UpdateAutomaticallyHelpText": "Автоматичне завантаження та встановлення оновлень. Ви все ще зможете встановити з System: Updates",
|
|
||||||
"UpdateCheckStartupNotWritableMessage": "Неможливо встановити оновлення, оскільки папка запуску \"{0}\" не може бути записана користувачем \"{1}\".",
|
|
||||||
"UpdateCheckUINotWritableMessage": "Неможливо встановити оновлення, оскільки папка інтерфейсу користувача \"{0}\" не може бути записана користувачем \"{1}\".",
|
|
||||||
"UpgradeUntilCustomFormatScore": "Оновлення до оцінки спеціального формату",
|
|
||||||
"UpgradeUntilThisQualityIsMetOrExceeded": "Оновлюйте, поки ця якість не буде досягнута або перевищена",
|
|
||||||
"UsenetDelayHelpText": "Затримка в хвилинах, щоб зачекати, перш ніж отримати випуск від Usenet",
|
|
||||||
"VersionUpdateText": "Встановлено версію Radarr {0}. Щоб отримати останні зміни, потрібно перезавантажити Radarr.",
|
|
||||||
"WhitelistedHardcodedSubsHelpText": "Встановлені тут теги субтитрів не вважатимуться жорстко закодованими",
|
|
||||||
"DockerUpdater": "оновіть контейнер docker, щоб отримати оновлення",
|
|
||||||
"EnableAutomaticSearch": "Увімкнути автоматичний пошук",
|
|
||||||
"Images": "Зображення",
|
|
||||||
"IMDb": "IMDb",
|
|
||||||
"Import": "Імпорт",
|
|
||||||
"LastUsed": "Останнє використання",
|
|
||||||
"Lists": "Списки",
|
|
||||||
"NoVideoFilesFoundSelectedFolder": "У вибраній папці не знайдено відеофайлів",
|
|
||||||
"Released": "Випуск",
|
|
||||||
"SourcePath": "Вихідний шлях",
|
|
||||||
"UnableToLoadUISettings": "Не вдалося завантажити налаштування інтерфейсу користувача",
|
|
||||||
"WouldYouLikeToRestoreBackup": "Бажаєте відновити резервну копію {0}?",
|
|
||||||
"IndexerFlags": "Прапори індексатора",
|
|
||||||
"OnMovieDeleteHelpText": "Фільм видалено",
|
|
||||||
"TagDetails": "Деталі тегу - {0}",
|
|
||||||
"DiscordUrlInSlackNotification": "Ви налаштували сповіщення Discord як сповіщення Slack. Налаштуйте це як сповіщення Discord для кращої роботи. Сповіщення, на які впливає: {0}",
|
|
||||||
"Missing": "Відсутня",
|
|
||||||
"SettingsTimeFormat": "Формат часу",
|
|
||||||
"iCalLink": "Посилання iCal",
|
|
||||||
"InCinemasDate": "У кінотеатрах Дата",
|
|
||||||
"IndexerSettings": "Налаштування індексатора",
|
|
||||||
"List": "Список",
|
|
||||||
"ListExclusions": "Список виключень",
|
|
||||||
"ListSettings": "Параметри списку",
|
|
||||||
"LinkHere": "тут",
|
|
||||||
"Links": "Посилання",
|
|
||||||
"ListsSettingsSummary": "Імпорт списків, список виключень",
|
|
||||||
"OrganizeConfirm": "Ви впевнені, що бажаєте впорядкувати всі файли у {0} вибраних фільмах?",
|
|
||||||
"OrganizeModalAllPathsRelative": "Усі шляхи відносяться до:",
|
|
||||||
"Options": "Опції",
|
|
||||||
"Organize": "Організувати",
|
|
||||||
"OrganizeAndRename": "Організувати та перейменувати",
|
|
||||||
"OverviewOptions": "Параметри огляду",
|
|
||||||
"PackageVersion": "Версія пакета",
|
|
||||||
"Quality": "Якість",
|
|
||||||
"Time": "Час",
|
|
||||||
"UsenetDelayTime": "Затримка Usenet: {0}",
|
|
||||||
"ChooseImportMode": "Виберіть режим імпорту",
|
|
||||||
"DeleteHeader": "Видалити - {0}",
|
|
||||||
"IncludeCustomFormatWhenRenaming": "Включати спеціальний формат під час перейменування",
|
|
||||||
"IncludeCustomFormatWhenRenamingHelpText": "Включіть у формат перейменування {Custom Formats}",
|
|
||||||
"MaximumSizeHelpText": "Максимальний розмір випуску для захоплення в МБ. Встановіть нуль, щоб встановити необмежений",
|
|
||||||
"Ungroup": "Розгрупувати",
|
|
||||||
"InteractiveImport": "Інтерактивний імпорт",
|
|
||||||
"Large": "Великий",
|
|
||||||
"LastDuration": "Остання тривалість",
|
|
||||||
"Scheduled": "За розкладом",
|
|
||||||
"UpdateSelected": "Оновити вибране",
|
|
||||||
"PreferTorrent": "Віддаю перевагу Torrent",
|
|
||||||
"PrioritySettings": "Пріоритет: {0}",
|
|
||||||
"ProxyCheckFailedToTestMessage": "Не вдалося перевірити проксі: {0}",
|
|
||||||
"Qualities": "Якості",
|
|
||||||
"QualityCutoffHasNotBeenMet": "Порогова якість не досягнута",
|
|
||||||
"QualityOrLangCutoffHasNotBeenMet": "Обрізання якості чи мови не виконано",
|
|
||||||
"QualityProfile": "Профіль якості",
|
|
||||||
"QueueIsEmpty": "Черга порожня",
|
|
||||||
"QuickImport": "Рухатися автоматично",
|
|
||||||
"RadarrCalendarFeed": "Стрічка календаря Radarr",
|
|
||||||
"RadarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow": "Radarr підтримує спеціальні умови щодо наведених нижче властивостей випуску.",
|
|
||||||
"RadarrTags": "Теги Radar",
|
|
||||||
"RadarrUpdated": "Radarr оновлено",
|
|
||||||
"Rating": "Рейтинг",
|
|
||||||
"Ratings": "Рейтинги",
|
|
||||||
"Real": "Справжня",
|
|
||||||
"Refresh": "Оновити",
|
|
||||||
"RefreshAndScan": "Оновити та сканувати",
|
|
||||||
"RelativePath": "Відносний шлях",
|
|
||||||
"SearchForMissing": "Розшук зниклих",
|
|
||||||
"SearchForMovie": "Пошук фільму",
|
|
||||||
"SearchMissing": "Пошук відсутній",
|
|
||||||
"StartImport": "Розпочати імпорт",
|
|
||||||
"System": "Система",
|
|
||||||
"AreYouSureYouWantToResetQualityDefinitions": "Ви впевнені, що бажаєте скинути визначення якості?",
|
|
||||||
"CollectionsSelectedInterp": "Вибрано колекцій: {0}",
|
|
||||||
"DeleteNotification": "Видалити сповіщення",
|
|
||||||
"DeleteFileLabel": "Видалити файл фільму {0}",
|
|
||||||
"DeleteFilesHelpText": "Видалити файли фільмів і папку фільмів",
|
|
||||||
"DeleteFilesLabel": "Видалити файли фільмів {0}",
|
|
||||||
"DeleteQualityProfile": "Видалити профіль якості",
|
|
||||||
"DeleteRestriction": "Видалити обмеження",
|
|
||||||
"DownloadedAndMonitored": "Завантажено (Відстежується)",
|
|
||||||
"DownloadClientUnavailable": "Клієнт завантажувача недоступний",
|
|
||||||
"DownloadedButNotMonitored": "Завантажено (Не відстежується)",
|
|
||||||
"DownloadFailed": "Помилка завантаження",
|
|
||||||
"DownloadFailedCheckDownloadClientForMoreDetails": "Помилка завантаження: перевірте клієнт завантаження, щоб дізнатися більше",
|
|
||||||
"DownloadFailedInterp": "Помилка завантаження: {0}",
|
|
||||||
"DownloadWarning": "Попередження про завантаження: {0}",
|
|
||||||
"DownloadWarningCheckDownloadClientForMoreDetails": "Попередження про завантаження: перевірте клієнт завантаження, щоб дізнатися більше",
|
|
||||||
"Edit": "Редагувати",
|
|
||||||
"EditGroups": "Редагувати групи",
|
|
||||||
"EditIndexer": "Редагувати індексатор",
|
|
||||||
"Edition": "Видання",
|
|
||||||
"EditMovie": "Редагувати фільм",
|
|
||||||
"EditMovieFile": "Редагувати файл фільму",
|
|
||||||
"EditPerson": "Редагувати особу",
|
|
||||||
"DeleteSelectedMovieFiles": "Видалити вибрані файли фільмів",
|
|
||||||
"DeleteSelectedMovieFilesMessage": "Ви впевнені, що бажаєте видалити вибрані файли фільмів?",
|
|
||||||
"DeleteTag": "Видалити тег",
|
|
||||||
"DeleteTheMovieFolder": "Папку фільму \"{0}\" і весь її вміст буде видалено.",
|
|
||||||
"DestinationPath": "Шлях призначення",
|
|
||||||
"DetailedProgressBar": "Детальний індикатор прогресу",
|
|
||||||
"DetailedProgressBarHelpText": "Показати текст на панелі виконання",
|
|
||||||
"Details": "Подробиці",
|
|
||||||
"Donations": "Пожертви",
|
|
||||||
"EnableCompletedDownloadHandlingHelpText": "Автоматично імпортувати завершені завантаження з клієнта завантажень",
|
|
||||||
"EnableAutomaticSearchHelpTextWarning": "Буде використано, коли використовується інтерактивний пошук",
|
|
||||||
"EnableColorImpairedModeHelpText": "Змінений стиль, щоб користувачі з вадами кольору могли краще розрізняти кольорову кодовану інформацію",
|
|
||||||
"EnableInteractiveSearch": "Увімкнути інтерактивний пошук",
|
|
||||||
"EnableInteractiveSearchHelpText": "Буде використано, коли використовується інтерактивний пошук",
|
|
||||||
"EnableInteractiveSearchHelpTextWarning": "Пошук не підтримується цим індексатором",
|
|
||||||
"EnableRSS": "Увімкнути RSS",
|
|
||||||
"EnableSSL": "Увімкнути SSL",
|
|
||||||
"EnableSslHelpText": " Щоб набуло чинності, потрібно перезапустити роботу від імені адміністратора",
|
|
||||||
"EventType": "Тип події",
|
|
||||||
"Exception": "Виняток",
|
|
||||||
"Excluded": "Виключено",
|
|
||||||
"ExcludeMovie": "Виключити фільм",
|
|
||||||
"ExcludeTitle": "Виключити {0}? Це не дозволить Radarr автоматично додавати через синхронізацію списку.",
|
|
||||||
"ExistingMovies": "Існуючі фільми",
|
|
||||||
"ExistingTag": "Існуючий тег",
|
|
||||||
"Extension": "Розширення",
|
|
||||||
"ExternalUpdater": "Radarr налаштовано на використання зовнішнього механізму оновлення",
|
|
||||||
"ExtraFileExtensionsHelpTexts2": "Приклади: '.sub, .nfo' або 'sub,nfo'",
|
|
||||||
"Failed": "Не вдалося",
|
|
||||||
"FailedDownloadHandling": "Помилка обробки завантаження",
|
|
||||||
"FailedToLoadQueue": "Не вдалося завантажити чергу",
|
|
||||||
"FeatureRequests": "Майбутні запити",
|
|
||||||
"FileManagement": "Керування файлами",
|
|
||||||
"Filename": "Ім'я файлу",
|
|
||||||
"FileNames": "Імена файлів",
|
|
||||||
"FileWasDeletedByUpgrade": "Файл видалено, щоб імпортувати оновлення",
|
|
||||||
"FileWasDeletedByViaUI": "Файл видалено через інтерфейс користувача",
|
|
||||||
"FilterPlaceHolder": "Пошук фільмів",
|
|
||||||
"Folder": "Папка",
|
|
||||||
"Forecast": "Прогноз",
|
|
||||||
"Formats": "Формати",
|
|
||||||
"ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons": "Щоб отримати додаткову інформацію про окремі списки імпорту, натисніть інформаційні кнопки.",
|
|
||||||
"ForMoreInformationOnTheIndividualIndexers": "Щоб отримати додаткову інформацію про окремих індексаторів, натисніть кнопки інформації.",
|
|
||||||
"FreeSpace": "Вільний простір",
|
|
||||||
"General": "Загальний",
|
|
||||||
"Host": "Хост",
|
|
||||||
"Hostname": "Ім'я хоста",
|
|
||||||
"Hours": "Години",
|
|
||||||
"HttpHttps": "HTTP(S)",
|
|
||||||
"ICalFeed": "Канал iCal",
|
|
||||||
"ICalHttpUrlHelpText": "Скопіюйте цю URL-адресу до своїх клієнтів або натисніть, щоб підписатися, якщо ваш браузер підтримує веб-канал",
|
|
||||||
"Ignored": "Ігнорується",
|
|
||||||
"IgnoredAddresses": "Ігноровані адреси",
|
|
||||||
"IllRestartLater": "Я перезапущу пізніше",
|
|
||||||
"ImportExistingMovies": "Імпорт наявних фільмів",
|
|
||||||
"ImportExtraFiles": "Імпорт додаткових файлів",
|
|
||||||
"ImportFailedInterp": "Помилка імпорту: {0}",
|
|
||||||
"ImportHeader": "Імпортуйте існуючу організовану бібліотеку, щоб додати фільми до Radarr",
|
|
||||||
"ImportIncludeQuality": "Переконайтеся, що назви ваших файлів містять якість. напр. {0}",
|
|
||||||
"ImportLibrary": "Імпорт бібліотеки",
|
|
||||||
"ImportListMultipleMissingRoots": "Кілька кореневих папок відсутні для списків імпорту: {0}",
|
|
||||||
"IndexerLongTermStatusCheckSingleClientMessage": "Індексатори недоступні через збої більше 6 годин: {0}",
|
|
||||||
"ImdbRating": "Рейтинг IMDb",
|
|
||||||
"ImdbVotes": "Голоси IMDb",
|
|
||||||
"IndexerDownloadClientHelpText": "Укажіть, який клієнт завантаження використовується для захоплення з цього індексатора",
|
|
||||||
"IndexerRssHealthCheckNoAvailableIndexers": "Усі індексатори з підтримкою rss тимчасово недоступні через нещодавні помилки індексатора",
|
|
||||||
"IndexerPriorityHelpText": "Пріоритет індексатора від 1 (найвищий) до 50 (найнижчий). За замовчуванням: 25. Використовується під час захоплення випусків як тай-брейку для інших однакових випусків, Radarr все одно використовуватиме всі ввімкнені індексатори для RSS-синхронізації та пошуку",
|
|
||||||
"IndexerRssHealthCheckNoIndexers": "Немає доступних індексаторів із увімкненою синхронізацією RSS, Radarr не збиратиме нові випуски автоматично",
|
|
||||||
"IndexerSearchCheckNoInteractiveMessage": "Немає доступних індексаторів, коли ввімкнено інтерактивний пошук, Radarr не надаватиме жодних інтерактивних результатів пошуку",
|
|
||||||
"IndexerStatusCheckAllClientMessage": "Усі індексатори недоступні через збої",
|
|
||||||
"IndexerStatusCheckSingleClientMessage": "Індексатори недоступні через помилки: {0}",
|
|
||||||
"InteractiveImportErrLanguage": "Для кожного вибраного файлу необхідно вибрати мову",
|
|
||||||
"InteractiveImportErrMovie": "Фільм потрібно вибрати для кожного вибраного файлу",
|
|
||||||
"InteractiveImportErrQuality": "Для кожного вибраного файлу необхідно вибрати якість",
|
|
||||||
"InteractiveSearch": "Інтерактивний пошук",
|
|
||||||
"Interval": "Інтервал",
|
|
||||||
"InvalidFormat": "Недійсний формат",
|
|
||||||
"KeyboardShortcuts": "Гарячі клавіши",
|
|
||||||
"LanguageHelpText": "Мова для релізів",
|
|
||||||
"Languages": "Мови",
|
|
||||||
"LastExecution": "Останнє виконання",
|
|
||||||
"LastWriteTime": "Час останнього запису",
|
|
||||||
"Level": "Рівень",
|
|
||||||
"ListSyncLevelHelpTextWarning": "Файли фільмів буде остаточно видалено, це може призвести до видалення вашої бібліотеки, якщо ваші списки порожні",
|
|
||||||
"LoadingMovieExtraFilesFailed": "Не вдалося завантажити додаткові файли фільму",
|
|
||||||
"LoadingMovieFilesFailed": "Не вдалося завантажити файли фільму",
|
|
||||||
"Local": "Місцевий",
|
|
||||||
"Location": "Місцезнаходження",
|
|
||||||
"LogFiles": "Файли журналів",
|
|
||||||
"LogOnly": "Лише журнал",
|
|
||||||
"Logs": "Журнали",
|
|
||||||
"Manual": "Інструкція",
|
|
||||||
"ManualImport": "Імпорт вручну",
|
|
||||||
"ManualImportSelectLanguage": "Імпорт вручну - виберіть мову",
|
|
||||||
"ManualImportSelectMovie": "Імпорт вручну - виберіть фільм",
|
|
||||||
"ManualImportSelectQuality": " Імпорт вручну - Виберіть якість",
|
|
||||||
"ManualImportSetReleaseGroup": "Імпорт вручну - встановити групу випуску",
|
|
||||||
"MappedDrivesRunningAsService": "Підключені мережеві диски недоступні під час роботи як служби Windows. Щоб отримати додаткову інформацію, перегляньте FAQ",
|
|
||||||
"MarkAsFailed": "Позначити як помилку",
|
|
||||||
"MarkAsFailedMessageText": "Ви впевнені, що бажаєте позначити \"{0}\" як невдале?",
|
|
||||||
"MassMovieSearch": "Масовий пошук фільмів",
|
|
||||||
"Max": "Максимальний",
|
|
||||||
"MaximumSize": "Максимальний розмір",
|
|
||||||
"Mechanism": "Механізм",
|
|
||||||
"MediaInfo": "Медіа інформація",
|
|
||||||
"MediaManagementSettingsSummary": "Налаштування іменування та керування файлами",
|
|
||||||
"Medium": "Середній",
|
|
||||||
"MIA": "MIA",
|
|
||||||
"MinAvailability": "Мінімальна доступність",
|
|
||||||
"MinFormatScoreHelpText": "Мінімальна оцінка спеціального формату, дозволена для завантаження",
|
|
||||||
"MinimumFreeSpaceWhenImportingHelpText": "Заборонити імпорт, якщо він залишить менше, ніж цей обсяг доступного дискового простору",
|
|
||||||
"Minutes": "Хвилин",
|
|
||||||
"MinutesHundredTwenty": "120 хвилин: {0}",
|
|
||||||
"MinutesNinety": "90 хвилин: {0}",
|
|
||||||
"MinutesSixty": "60 хвилин: {0}",
|
|
||||||
"MissingFromDisk": "Radarr не зміг знайти файл на диску, тому файл було від’єднано від фільму в базі даних",
|
|
||||||
"MissingMonitoredAndConsideredAvailable": "Відсутній (відстежується)",
|
|
||||||
"Mode": "Режим",
|
|
||||||
"Months": "Місяці",
|
|
||||||
"More": "Більше",
|
|
||||||
"MoveFiles": "Перемістити файли",
|
|
||||||
"MovieChat": "Кіночат",
|
|
||||||
"MovieCollectionMultipleMissingRoots": "Кілька кореневих папок відсутні для колекцій фільмів: {0}",
|
|
||||||
"MovieDetailsNextMovie": "Подробиці про фільм: наступний фільм",
|
|
||||||
"MovieAlreadyExcluded": "Фільм уже виключено",
|
|
||||||
"MovieAndCollection": "Фільм і колекція",
|
|
||||||
"MovieExcludedFromAutomaticAdd": "Фільм виключено з автоматичного додавання",
|
|
||||||
"MovieFiles": "Файли фільмів",
|
|
||||||
"MovieFilesTotaling": "Підсумок файлів фільмів",
|
|
||||||
"MovieID": "ID фільму",
|
|
||||||
"MovieIndex": "Індекс фільму",
|
|
||||||
"MovieIndexScrollBottom": "Індекс фільму: прокрутка внизу",
|
|
||||||
"MovieInfoLanguage": "Мова інформації про фільм",
|
|
||||||
"MovieInfoLanguageHelpTextWarning": "Потрібно перезавантажити браузер",
|
|
||||||
"MovieInvalidFormat": "Фільм: недійсний формат",
|
|
||||||
"MovieIsDownloading": "Фільм завантажується",
|
|
||||||
"MovieIsMonitored": "Фільм відстежується",
|
|
||||||
"MovieIsUnmonitored": "Фільм без моніторингу",
|
|
||||||
"MovieNaming": "Назва фільму",
|
|
||||||
"MovieOnly": "Тільки кіно",
|
|
||||||
"MoviesSelectedInterp": "Вибрано фільмів: {0}",
|
|
||||||
"MovieTitle": "Назва фільму",
|
|
||||||
"MustNotContain": "Не повинен містити",
|
|
||||||
"Name": "Ім'я",
|
|
||||||
"NamingSettings": "Налаштування імен",
|
|
||||||
"Negate": "Заперечувати",
|
|
||||||
"Negated": "Заперечено",
|
|
||||||
"NoLogFiles": "Немає файлів журналу",
|
|
||||||
"NoMatchFound": "Збігів не знайдено!",
|
|
||||||
"NoResultsFound": "Нічого не знайдено",
|
|
||||||
"NoTagsHaveBeenAddedYet": "Теги ще не додано",
|
|
||||||
"NotAvailable": "Недоступний",
|
|
||||||
"NotificationTriggers": "Тригери сповіщень",
|
|
||||||
"NotificationTriggersHelpText": "Виберіть, які події мають викликати це сповіщення",
|
|
||||||
"NotMonitored": "Не контролюється",
|
|
||||||
"OAuthPopupMessage": "Ваш браузер блокує спливаючі вікна",
|
|
||||||
"Ok": "Гаразд",
|
|
||||||
"OnApplicationUpdateHelpText": "Оновлення програми",
|
|
||||||
"OnDownloadHelpText": "При імпорті",
|
|
||||||
"OnHealthIssueHelpText": "Про питання здоров'я",
|
|
||||||
"OnImport": "При імпорті",
|
|
||||||
"OnLatestVersion": "Остання версія Radarr вже встановлена",
|
|
||||||
"OnlyTorrent": "Тільки торрент",
|
|
||||||
"OnlyUsenet": "Тільки Usenet",
|
|
||||||
"OnUpgrade": "При оновленні",
|
|
||||||
"OnUpgradeHelpText": "При оновленні",
|
|
||||||
"OpenBrowserOnStart": "Відкрийте браузер при запуску",
|
|
||||||
"OrganizeModalNamingPattern": "Шаблон іменування:",
|
|
||||||
"Original": "Оригінал",
|
|
||||||
"OriginalLanguage": "Мова оригіналу",
|
|
||||||
"Paused": "Призупинено",
|
|
||||||
"Pending": "В очікуванні",
|
|
||||||
"PendingChangesDiscardChanges": "Відкинути зміни та залишити",
|
|
||||||
"PendingChangesStayReview": "Залишайтеся та переглядайте зміни",
|
|
||||||
"Permissions": "Дозволи",
|
|
||||||
"PhysicalRelease": "Фізичний реліз",
|
|
||||||
"PhysicalReleaseDate": "Дата фізичного випуску",
|
|
||||||
"Port": "Порт",
|
|
||||||
"PortNumber": "Номер порту",
|
|
||||||
"PosterOptions": "Параметри плаката",
|
|
||||||
"Posters": "Плакати",
|
|
||||||
"PreferAndUpgrade": "Віддайте перевагу та оновіть",
|
|
||||||
"PreferIndexerFlags": "Віддавати перевагу прапорцям індексатора",
|
|
||||||
"PreferIndexerFlagsHelpText": "Пріоритезуйте випуски за допомогою спеціальних прапорців",
|
|
||||||
"Preferred": "Бажано",
|
|
||||||
"PreferredSize": "Бажаний розмір",
|
|
||||||
"ProfilesSettingsSummary": "Профілі якості, мови та затримки",
|
|
||||||
"Progress": "Прогрес",
|
|
||||||
"Proper": "Належний",
|
|
||||||
"Protocol": "Протокол",
|
|
||||||
"ReadTheWikiForMoreInformation": "Читайте Wiki для отримання додаткової інформації",
|
|
||||||
"RecycleBinCleanupDaysHelpTextWarning": "Файли в кошику, старші за вибрану кількість днів, будуть очищені автоматично",
|
|
||||||
"RecycleBinHelpText": "Файли фільмів потраплять сюди після видалення, а не назавжди",
|
|
||||||
"Redownload": "Повторне завантаження",
|
|
||||||
"RejectionCount": "Кількість відмов",
|
|
||||||
"ReleaseBranchCheckOfficialBranchMessage": "Гілка {0} не є дійсною гілкою випуску Radarr, ви не отримуватимете оновлення",
|
|
||||||
"ReleaseStatus": "Статус випуску",
|
|
||||||
"ReleaseTitle": "Назва випуску",
|
|
||||||
"ReleaseWillBeProcessedInterp": "Випуск буде оброблено {0}",
|
|
||||||
"Reload": "Перезавантажити",
|
|
||||||
"RemotePath": "Віддалений шлях",
|
|
||||||
"RemotePathMappingCheckDockerFolderMissing": "Ви використовуєте docker; клієнт завантаження {0} розміщує завантаження в {1}, але цей каталог не існує всередині контейнера. Перегляньте свої віддалені відображення шляхів і налаштування обсягу контейнера.",
|
|
||||||
"RemotePathMappingCheckFileRemoved": "Файл {0} видалено під час обробки.",
|
|
||||||
"RemotePathMappingCheckFilesBadDockerPath": "Ви використовуєте docker; завантажити клієнтські {0} звітні файли в {1}, але це недійсний {2} шлях. Перегляньте свої віддалені відображення шляхів і завантажте налаштування клієнта.",
|
|
||||||
"RemotePathMappingCheckFilesLocalWrongOSPath": "Локальний клієнт завантаження {0} повідомив про файли в {1}, але це недійсний шлях {2}. Перегляньте налаштування клієнта завантаження.",
|
|
||||||
"RemotePathMappingCheckFilesWrongOSPath": "Клієнт віддаленого завантаження {0} повідомив про файли в {1}, але це недійсний шлях {2}. Перегляньте свої віддалені відображення шляхів і завантажте налаштування клієнта.",
|
|
||||||
"RemotePathMappingCheckFolderPermissions": "Radarr може бачити, але не має доступу до каталогу завантажень {0}. Ймовірна помилка дозволів.",
|
|
||||||
"RemotePathMappingCheckGenericPermissions": "Клієнт завантаження {0} розміщує завантаження в {1}, але Radarr не бачить цей каталог. Можливо, вам знадобиться налаштувати дозволи для папки.",
|
|
||||||
"RemotePathMappingCheckImportFailed": "Radarr не вдалося імпортувати фільм. Подробиці перевірте у своїх журналах.",
|
|
||||||
"RemotePathMappingCheckLocalFolderMissing": "Клієнт віддаленого завантаження {0} розміщує завантаження в {1}, але цей каталог не існує. Ймовірно, віддалений шлях відсутній або неправильний.",
|
|
||||||
"RemotePathMappingCheckLocalWrongOSPath": "Локальний клієнт завантаження {0} розміщує завантаження в {1}, але це недійсний шлях {2}. Перегляньте налаштування клієнта завантаження.",
|
|
||||||
"RemotePathMappings": "Віддалені відображення шляхів",
|
|
||||||
"RemoveCompleted": "Видалення завершено",
|
|
||||||
"RemoveCompletedDownloadsHelpText": "Видалити імпортовані завантаження з історії клієнта завантажень",
|
|
||||||
"RemovedFromTaskQueue": "Видалено з черги завдань",
|
|
||||||
"RemovedMovieCheckMultipleMessage": "Фільми {0} видалено з TMDb",
|
|
||||||
"RemovedMovieCheckSingleMessage": "Фільм {0} видалено з TMDb",
|
|
||||||
"RemoveFromDownloadClient": "Видалити з клієнта завантаження",
|
|
||||||
"Reorder": "Змінити порядок",
|
|
||||||
"Replace": "Замінити",
|
|
||||||
"ReplaceIllegalCharacters": "Замінити неприпустимі символи",
|
|
||||||
"ReplaceWithDash": "Замінити тире",
|
|
||||||
"ReplaceWithSpaceDash": "Замінити пробілом",
|
|
||||||
"RescanAfterRefreshHelpText": "Перескануйте папку фільму після оновлення фільму",
|
|
||||||
"ResetDefinitions": "Скинути визначення",
|
|
||||||
"ResetQualityDefinitions": "Скинути визначення якості",
|
|
||||||
"ResetTitles": "Скинути заголовки",
|
|
||||||
"ResetTitlesHelpText": "Скинути заголовки визначень, а також значення",
|
|
||||||
"RestartNow": "Перезавантажити зараз",
|
|
||||||
"Restore": "Відновлення",
|
|
||||||
"RootFolderCheckSingleMessage": "Відсутня коренева папка: {0}",
|
|
||||||
"RootFolders": "Кореневі папки",
|
|
||||||
"RSSIsNotSupportedWithThisIndexer": "Цей індексатор не підтримує RSS",
|
|
||||||
"RSSSync": "Синхронізація RSS",
|
|
||||||
"RSSSyncInterval": "Інтервал синхронізації RSS",
|
|
||||||
"RSSSyncIntervalHelpTextWarning": "Це стосується всіх індексаторів, будь ласка, дотримуйтеся встановлених ними правил",
|
|
||||||
"Save": "Зберегти",
|
|
||||||
"SaveChanges": "Зберегти зміни",
|
|
||||||
"SaveSettings": "Зберегти зміни",
|
|
||||||
"Score": "Оцінка",
|
|
||||||
"Script": "Сценарій",
|
|
||||||
"ScrollMovies": "Прокрутка фільмів",
|
|
||||||
"SearchCutoffUnmet": "Обрізка пошуку не виконана",
|
|
||||||
"SearchFiltered": "Пошук відфільтровано",
|
|
||||||
"SearchMovie": "Пошук фільму",
|
|
||||||
"SearchOnAdd": "Шукати при додаванні",
|
|
||||||
"SearchOnAddHelpText": "Шукайте фільми в цьому списку після додавання в бібліотеку",
|
|
||||||
"SearchSelected": "Пошук вибрано",
|
|
||||||
"SelectAll": "Вибрати все",
|
|
||||||
"SelectDotDot": "Виберіть...",
|
|
||||||
"SelectFolder": "Виберіть папку",
|
|
||||||
"SelectLanguages": "Виберіть Мови",
|
|
||||||
"SelectQuality": "Виберіть Якість",
|
|
||||||
"SetPermissions": "Встановити дозволи",
|
|
||||||
"SetPermissionsLinuxHelpText": "Чи слід запускати chmod, коли файли імпортуються/перейменовуються?",
|
|
||||||
"SetReleaseGroup": "Встановити групу випуску",
|
|
||||||
"SettingsLongDateFormat": "Довгий формат дати",
|
|
||||||
"SettingsRemotePathMappingLocalPathHelpText": "Шлях, який має використовувати Radarr для локального доступу до віддаленого шляху",
|
|
||||||
"SettingsRemotePathMappingRemotePath": "Віддалений шлях",
|
|
||||||
"SettingsShortDateFormat": "Короткий формат дати",
|
|
||||||
"SettingsShowRelativeDates": "Показати відносні дати",
|
|
||||||
"SettingsTheme": "Тема",
|
|
||||||
"ShouldMonitorHelpText": "Чи слід додавати фільми чи колекції, додані до цього списку, як контрольовані",
|
|
||||||
"ShowAdvanced": "Показати Додатково",
|
|
||||||
"ShowAsAllDayEvents": "Показати як події на весь день",
|
|
||||||
"ShowCinemaRelease": "Показати дату виходу в кіно",
|
|
||||||
"showCinemaReleaseHelpText": "Покажіть дату виходу в кіно під афішею",
|
|
||||||
"ShowCutoffUnmetIconHelpText": "Показувати піктограму для файлів, коли обмеження не досягнуто",
|
|
||||||
"ShowDateAdded": "Показати дату додавання",
|
|
||||||
"ShowMonitored": "Показати Моніторинг",
|
|
||||||
"ShowPosters": "Показати плакати",
|
|
||||||
"ShowRatings": "Показати рейтинги",
|
|
||||||
"ShowReleaseDate": "Показати дату випуску",
|
|
||||||
"ShowReleaseDateHelpText": "Показати дату випуску під плакатом",
|
|
||||||
"ShowSearch": "Показати пошук",
|
|
||||||
"ShowUnknownMovieItems": "Показати невідомі елементи фільму",
|
|
||||||
"ShowYear": "Показати рік",
|
|
||||||
"Shutdown": "Вимкнення",
|
|
||||||
"SizeLimit": "Обмеження розміру",
|
|
||||||
"SizeOnDisk": "Розмір на диску",
|
|
||||||
"Small": "Маленький",
|
|
||||||
"SorryThatMovieCannotBeFound": "Вибачте, цей фільм неможливо знайти.",
|
|
||||||
"Sort": "Сортування",
|
|
||||||
"Source": "Джерело",
|
|
||||||
"SourceRelativePath": "Відносний шлях джерела",
|
|
||||||
"SourceTitle": "Назва джерела",
|
|
||||||
"SSLCertPasswordHelpText": "Пароль для файлу pfx",
|
|
||||||
"SSLPort": "Порт SSL",
|
|
||||||
"StandardMovieFormat": "Стандартний формат фільму",
|
|
||||||
"Started": "Розпочато",
|
|
||||||
"StartSearchForMissingMovie": "Почніть пошук зниклого фільму",
|
|
||||||
"StartTypingOrSelectAPathBelow": "Почніть вводити текст або виберіть шлях нижче",
|
|
||||||
"Status": "Статус",
|
|
||||||
"Studio": "Студія",
|
|
||||||
"Style": "Стиль",
|
|
||||||
"SubfolderWillBeCreatedAutomaticallyInterp": "Вкладена папка \"{0}\" буде створена автоматично",
|
|
||||||
"SuggestTranslationChange": "Запропонуйте зміну перекладу",
|
|
||||||
"SystemTimeCheckMessage": "Системний час вимкнено більш ніж на 1 день. Заплановані завдання можуть не працювати належним чином, доки час не буде виправлено",
|
|
||||||
"Table": "Таблиця",
|
|
||||||
"TableOptions": "Параметри таблиці",
|
|
||||||
"TableOptionsColumnsMessage": "Виберіть, які стовпці відображаються та в якому порядку вони відображаються",
|
|
||||||
"TagCannotBeDeletedWhileInUse": "Неможливо видалити під час використання",
|
|
||||||
"TagIsNotUsedAndCanBeDeleted": "Тег не використовується і може бути видалений",
|
|
||||||
"Tags": "Теги",
|
|
||||||
"TagsHelpText": "Застосовується до фільмів із принаймні одним відповідним тегом",
|
|
||||||
"TagsSettingsSummary": "Перегляньте всі теги та те, як вони використовуються. Невикористані теги можна видалити",
|
|
||||||
"TestAll": "Перевірити все",
|
|
||||||
"TestAllClients": "Перевірте всіх клієнтів",
|
|
||||||
"TestAllIndexers": "Перевірити всі індексатори",
|
|
||||||
"TestAllLists": "Перевірити всі списки",
|
|
||||||
"TimeFormat": "Формат часу",
|
|
||||||
"Timeleft": "Час залишився",
|
|
||||||
"Title": "Назва",
|
|
||||||
"Titles": "Назви",
|
|
||||||
"TmdbIdHelpText": "Ідентифікатор TMDb фільму, який потрібно виключити",
|
|
||||||
"TmdbRating": "Рейтинг TMDb",
|
|
||||||
"TmdbVotes": "Голоси TMDb",
|
|
||||||
"TorrentDelayTime": "Затримка торрента: {0}",
|
|
||||||
"Torrents": "Торренти",
|
|
||||||
"Trace": "Трасувати",
|
|
||||||
"Trailer": "Трейлер",
|
|
||||||
"Trigger": "Тригер",
|
|
||||||
"Type": "Тип",
|
|
||||||
"UnableToAddANewConditionPleaseTryAgain": "Не вдалося додати нову умову, спробуйте ще раз.",
|
|
||||||
"UnableToAddANewQualityProfilePleaseTryAgain": "Не вдалося додати новий профіль якості, спробуйте ще раз.",
|
|
||||||
"UnableToAddRootFolder": "Не вдалося додати кореневу папку",
|
|
||||||
"UnableToImportCheckLogs": "Завантажено – неможливо імпортувати: подробиці перевірте в журналах",
|
|
||||||
"UnableToLoadDelayProfiles": "Неможливо завантажити профілі затримки",
|
|
||||||
"UnableToLoadGeneralSettings": "Не вдалося завантажити загальні налаштування",
|
|
||||||
"UnableToLoadHistory": "Не вдалося завантажити історію",
|
|
||||||
"UnableToLoadIndexerOptions": "Не вдалося завантажити параметри індексатора",
|
|
||||||
"UnableToLoadLanguages": "Не вдалося завантажити мови",
|
|
||||||
"UnableToLoadListOptions": "Не вдалося завантажити параметри списку",
|
|
||||||
"UnableToLoadLists": "Не вдалося завантажити списки",
|
|
||||||
"UnableToLoadMediaManagementSettings": "Не вдалося завантажити налаштування керування медіафайлами",
|
|
||||||
"UnableToLoadMetadata": "Не вдалося завантажити метадані",
|
|
||||||
"UnableToLoadNotifications": "Не вдалося завантажити сповіщення",
|
|
||||||
"UnableToLoadQualityDefinitions": "Не вдалося завантажити визначення якості",
|
|
||||||
"UnableToLoadRemotePathMappings": "Неможливо завантажити віддалені відображення шляхів",
|
|
||||||
"UnableToLoadRootFolders": "Не вдалося завантажити кореневі папки",
|
|
||||||
"UnableToUpdateRadarrDirectly": "Неможливо оновити Radarr безпосередньо,",
|
|
||||||
"Unavailable": "Недоступний",
|
|
||||||
"Unlimited": "Необмежений",
|
|
||||||
"UnmappedFilesOnly": "Лише незіставлені файли",
|
|
||||||
"UnmappedFolders": "Невідповідні папки",
|
|
||||||
"UnselectAll": "Скасувати вибір усіх",
|
|
||||||
"UpdateAll": "Оновити все",
|
|
||||||
"UpdateCheckStartupTranslocationMessage": "Неможливо встановити оновлення, оскільки папка запуску \"{0}\" знаходиться в папці переміщення програми.",
|
|
||||||
"UpdateMechanismHelpText": "Використовуйте вбудований засіб оновлення Radarr або скрипт",
|
|
||||||
"UpdateScriptPathHelpText": "Шлях до спеціального сценарію, який приймає витягнутий пакет оновлення та обробляє решту процесу оновлення",
|
|
||||||
"UpgradeAllowedHelpText": "Якщо відключені якості не будуть покращені",
|
|
||||||
"UpgradesAllowed": "Якщо відключені якості не будуть покращені",
|
|
||||||
"UpgradeUntilQuality": "Оновлення до якості",
|
|
||||||
"Uptime": "Час роботи",
|
|
||||||
"URLBase": "URL-адреса",
|
|
||||||
"UrlBaseHelpText": "Для підтримки зворотного проксі-сервера значення за умовчанням порожнє",
|
|
||||||
"UseHardlinksInsteadOfCopy": "Використовуйте жорсткі посилання замість копіювати",
|
|
||||||
"UsenetDisabled": "Usenet вимкнено",
|
|
||||||
"UseProxy": "Використовуйте проксі",
|
|
||||||
"Username": "Ім'я користувача",
|
|
||||||
"Version": "Версія",
|
|
||||||
"VideoCodec": "Відеокодек",
|
|
||||||
"View": "Переглянути",
|
|
||||||
"Wanted": "Розшукується",
|
|
||||||
"Warn": "Попередити",
|
|
||||||
"Week": "Тиждень",
|
|
||||||
"WeekColumnHeader": "Заголовок стовпця тижня",
|
|
||||||
"Weeks": "Тижнів",
|
|
||||||
"WhatsNew": "Що нового?",
|
|
||||||
"WhitelistedSubtitleTags": "Теги субтитрів із білого списку",
|
|
||||||
"Year": "Рік",
|
|
||||||
"YesCancel": "Так, скасувати",
|
|
||||||
"YesMoveFiles": "Так, перемістити файли",
|
|
||||||
"Yesterday": "Вчора",
|
|
||||||
"ApplicationURL": "URL програми",
|
|
||||||
"ApplicationUrlHelpText": "Зовнішня URL-адреса цієї програми, включаючи http(s)://, порт і базу URL-адрес",
|
|
||||||
"ImportRootPath": "Наведіть Radarr на папку з усіма вашими фільмами, а не на певний фільм. напр. {0}, а не {1}. Крім того, кожен фільм має бути у власній папці в кореневій папці/теці бібліотеки.",
|
|
||||||
"ImportTipsMessage": "Кілька порад, щоб забезпечити безперешкодне імпортування:",
|
|
||||||
"InCinemasMsg": "Фільм у кінотеатрах",
|
|
||||||
"IncludeHealthWarningsHelpText": "Включайте попередження про здоров’я",
|
|
||||||
"IncludeUnknownMovieItemsHelpText": "Показати елементи без фільму в черзі. Це може включати видалені фільми чи будь-що інше в категорії Radarr",
|
|
||||||
"IndexerPriority": "Пріоритет індексатора",
|
|
||||||
"ImportListStatusCheckAllClientMessage": "Усі списки недоступні через помилки",
|
|
||||||
"ImportListStatusCheckSingleClientMessage": "Списки недоступні через помилки: {0}",
|
|
||||||
"ImportListSyncIntervalHelpText": "Як часто Radarr синхронізує ваші списки. Мінімальне значення 6 годин",
|
|
||||||
"ImportMechanismHealthCheckMessage": "Увімкнути обробку завершених завантажень",
|
|
||||||
"ImportMovies": "Імпорт фільмів",
|
|
||||||
"ImportNotForDownloads": "Не використовуйте для імпортування завантажень із вашого клієнта завантаження, це лише для існуючих упорядкованих бібліотек, а не для несортованих файлів.",
|
|
||||||
"IndexerSearchCheckNoAvailableIndexersMessage": "Усі індексатори з можливістю пошуку тимчасово недоступні через нещодавні помилки індексатора",
|
|
||||||
"InstallLatest": "Встановити останній",
|
|
||||||
"MegabytesPerMinute": "Мегабайт за хвилину",
|
|
||||||
"Message": "Повідомлення",
|
|
||||||
"MovieTitleHelpText": "Назва фільму, який потрібно виключити (може бути будь-яким значущим)",
|
|
||||||
"MovieYear": "Фільм рік",
|
|
||||||
"MovieYearHelpText": "Рік фільму виключити",
|
|
||||||
"NegateHelpText": "Якщо позначено, настроюваний формат не застосовуватиметься, якщо ця умова {0} збігається.",
|
|
||||||
"Never": "Ніколи",
|
|
||||||
"New": "Новий",
|
|
||||||
"NoAltTitle": "Без альтернативних назв.",
|
|
||||||
"NoBackupsAreAvailable": "Немає резервних копій",
|
|
||||||
"NoChange": "Без змін",
|
|
||||||
"NoChanges": "Жодних змін",
|
|
||||||
"NoLinks": "Немає посилань",
|
|
||||||
"NoListRecommendations": "Елементів списку чи рекомендацій не знайдено. Щоб почати, ви захочете додати новий фільм, імпортувати кілька наявних або додати список.",
|
|
||||||
"NoMinimumForAnyRuntime": "Немає мінімуму для будь-якого часу виконання",
|
|
||||||
"NoMoviesExist": "Фільми не знайдено. Щоб почати, ви захочете додати новий фільм або імпортувати кілька наявних.",
|
|
||||||
"NoUpdatesAreAvailable": "Немає оновлень",
|
|
||||||
"Test": "Тест",
|
|
||||||
"TorrentsDisabled": "Торренти вимкнено",
|
|
||||||
"TotalFileSize": "Загальний розмір файлу",
|
|
||||||
"DownloadClientCheckDownloadingToRoot": "Клієнт завантаження {0} розміщує завантаження в кореневій папці {1}. Ви не повинні завантажувати в кореневу папку.",
|
|
||||||
"DigitalRelease": "Цифровий випуск",
|
|
||||||
"Disabled": "Вимкнено",
|
|
||||||
"DeleteEmptyFoldersHelpText": "Видаляти порожні папки фільмів під час сканування диска та під час видалення файлів фільмів",
|
|
||||||
"DeleteFile": "Видалити файл",
|
|
||||||
"Discord": "Discord",
|
|
||||||
"Docker": "Docker",
|
|
||||||
"DownloadClientCheckNoneAvailableMessage": "Немає доступного клієнта для завантаження",
|
|
||||||
"DownloadClientCheckUnableToCommunicateMessage": "Неможливо зв'язатися з {0}.",
|
|
||||||
"DiskSpace": "Дисковий простір",
|
|
||||||
"DoneEditingGroups": "Редагування груп завершено",
|
|
||||||
"DoNotPrefer": "Не віддавати перевагу",
|
|
||||||
"DoNotUpgradeAutomatically": "Не оновлювати автоматично",
|
|
||||||
"Download": "Завантажити",
|
|
||||||
"DownloadClient": "Клієнт завантажувача",
|
|
||||||
"DownloadClients": "Клієнти завантажувачів",
|
|
||||||
"DownloadClientSettings": "Налаштування клієнта завантажувача",
|
|
||||||
"DownloadClientsSettingsSummary": "Клієнти завантаження, обробка завантажень і віддалені відображення шляхів",
|
|
||||||
"DownloadClientStatusCheckAllClientMessage": "Усі клієнти завантаження недоступні через збої",
|
|
||||||
"DownloadClientStatusCheckSingleClientMessage": "Завантаження клієнтів недоступне через помилки: {0}",
|
|
||||||
"Genres": "Жанри",
|
|
||||||
"Global": "Глобальний",
|
|
||||||
"GoToInterp": "Перейти до {0}",
|
|
||||||
"Group": "Група",
|
|
||||||
"HardlinkCopyFiles": "Жорстке посилання/Копіювати файли",
|
|
||||||
"HaveNotAddedMovies": "Ви ще не додали жодного фільму. Бажаєте спершу імпортувати деякі або всі свої фільми?",
|
|
||||||
"Health": "Здоров'я",
|
|
||||||
"HealthNoIssues": "Немає проблем із вашою конфігурацією",
|
|
||||||
"GeneralSettings": "Загальні налаштування",
|
|
||||||
"GeneralSettingsSummary": "Порт, SSL, ім’я користувача/пароль, проксі, аналітика та оновлення",
|
|
||||||
"MoreInfo": "Більше інформації",
|
|
||||||
"RefreshMovie": "Оновити фільм",
|
|
||||||
"RegularExpressionsCanBeTested": "Регулярні вирази можна перевірити ",
|
|
||||||
"RemoveSelectedItems": "Видалити вибрані елементи",
|
|
||||||
"RemovingTag": "Видалення мітки",
|
|
||||||
"Renamed": "Перейменовано",
|
|
||||||
"RenameFiles": "Перейменування файлів",
|
|
||||||
"RenameMovies": "Перейменувати фільми",
|
|
||||||
"RenameMoviesHelpText": "Radarr використовуватиме існуючу назву файлу, якщо перейменування вимкнено",
|
|
||||||
"RemoveFailedDownloadsHelpText": "Видаліть невдалі завантаження з історії завантажень клієнта",
|
|
||||||
"RemoveFilter": "Видалити фільтр",
|
|
||||||
"RemoveFromBlocklist": "Видалити зі списку блокувань",
|
|
||||||
"RemoveFromQueue": "Видалити з черги",
|
|
||||||
"RemoveHelpTextWarning": "Видалення видалить завантаження та файл(и) із клієнта завантаження.",
|
|
||||||
"RemoveMovieAndDeleteFiles": "Видалити фільм і видалити файли",
|
|
||||||
"RemoveMovieAndKeepFiles": "Видалити фільм і зберегти файли",
|
|
||||||
"RemoveRootFolder": "Видалити кореневу папку",
|
|
||||||
"RemoveSelectedItem": "Видалити вибраний елемент",
|
|
||||||
"SettingsRemotePathMappingHostHelpText": "Той самий хост, який ви вказали для віддаленого клієнта завантаження",
|
|
||||||
"SettingsRemotePathMappingLocalPath": "Місцевий шлях",
|
|
||||||
"ShowGenres": "Показати жанри",
|
|
||||||
"UpdateAvailable": "Доступне нове оновлення",
|
|
||||||
"Updates": "Оновлення",
|
|
||||||
"Monitor": "Контрольований",
|
|
||||||
"MonitorCollection": "Контрольовані Колекції",
|
|
||||||
"Monitored": "Відстежується",
|
|
||||||
"MonitoredCollectionHelpText": "Відстежуйте, щоб фільми з цієї колекції автоматично додавалися до бібліотеки",
|
|
||||||
"MonitoredOnly": "Тільки під контролем",
|
|
||||||
"MonitoredStatus": "Відстежується/Стан",
|
|
||||||
"MoreControlCFText": "Хочете більше контролювати, яким завантаженням віддавати перевагу? Додайте",
|
|
||||||
"DownloadPropersAndRepacks": "Пропери та Репаки",
|
|
||||||
"LookingForReleaseProfiles2": "замість цього.",
|
|
||||||
"Usenet": "Usenet",
|
|
||||||
"Grab": "Захопити",
|
|
||||||
"IncludeUnmonitored": "Включити неконтрольований",
|
|
||||||
"Letterboxd": "Letterboxd",
|
|
||||||
"Reddit": "Reddit",
|
|
||||||
"Socks5": "Socks5 (Підтримка TOR)",
|
|
||||||
"Socks4": "Socks4",
|
|
||||||
"SSLCertPath": "Шлях сертифіката SSL",
|
|
||||||
"Wiki": "Wiki",
|
|
||||||
"RSSHelpText": "Використовуватиметься, коли Radarr періодично шукатиме випуски через RSS Sync",
|
|
||||||
"DownloadPropersAndRepacksHelpText1": "Автоматичне оновлення до Propers/Repacks чи ні",
|
|
||||||
"DownloadPropersAndRepacksHelpText2": "Використовуйте «Не віддавати перевагу», щоб відсортувати за користувальницьким форматом оцінки над Propers/Repacks",
|
|
||||||
"DownloadPropersAndRepacksHelpTextWarning": "Використовуйте спеціальні формати для автоматичного оновлення до Propers/Repacks",
|
|
||||||
"IconForCutoffUnmet": "Значок \"Не виконано відсікання\"",
|
|
||||||
"Logging": "Журналування",
|
|
||||||
"LookingForReleaseProfiles1": "Шукайте профілі релізів? Спробуйте",
|
|
||||||
"MaintenanceRelease": "Випуск для обслуговування: виправлення помилок та інші покращення. Щоб отримати докладнішу інформацію, перегляньте історію фіксації Github",
|
|
||||||
"MediaManagement": "Управління медіа",
|
|
||||||
"MediaManagementSettings": "Налаштування Управління медіа",
|
|
||||||
"MetadataSettings": "Налаштування метаданих",
|
|
||||||
"Min": "Мінімум",
|
|
||||||
"MissingNotMonitored": "Відсутній (неконтрольований)",
|
|
||||||
"MonitorMovie": "Відстежувати фільм",
|
|
||||||
"MonitorMovies": "Відстежувати фільми",
|
|
||||||
"NetCore": ".NET",
|
|
||||||
"OnGrabHelpText": "При захопленні",
|
|
||||||
"Peers": "Піри",
|
|
||||||
"RSS": "RSS",
|
|
||||||
"Seeders": "Сиди",
|
|
||||||
"SSLCertPassword": "Пароль SSL сертифіката",
|
|
||||||
"TaskUserAgentTooltip": "Агент користувача, наданий програмою, яка викликала API",
|
|
||||||
"TMDb": "TMDb",
|
|
||||||
"TMDBId": "Ідентифікатор TMDb",
|
|
||||||
"Trakt": "Trakt",
|
|
||||||
"UI": "Інтерфейс користувача",
|
|
||||||
"Metadata": "Метадані",
|
|
||||||
"OnGrab": "При захопленні",
|
|
||||||
"Discover": "Відкрийте для себе",
|
|
||||||
"Grabbed": "Захоплений",
|
|
||||||
"GrabID": "Захопити ID",
|
|
||||||
"GrabRelease": "Захопити реліз",
|
|
||||||
"GrabReleaseMessageText": "Radarr не зміг визначити, для якого фільму цей випуск. Можливо, Radarr не зможе автоматично імпортувати цей випуск. Ви хочете взяти '{0}'?",
|
|
||||||
"GrabSelected": "Захопити вибране"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -636,7 +636,7 @@
|
|||||||
"InstallLatest": "安装最新版",
|
"InstallLatest": "安装最新版",
|
||||||
"IndexerStatusCheckSingleClientMessage": "搜刮器因错误不可用:{0}",
|
"IndexerStatusCheckSingleClientMessage": "搜刮器因错误不可用:{0}",
|
||||||
"IndexerStatusCheckAllClientMessage": "所有搜刮器都因错误不可用",
|
"IndexerStatusCheckAllClientMessage": "所有搜刮器都因错误不可用",
|
||||||
"IndexerSearchCheckNoInteractiveMessage": "没有任何索引器开启了手动搜索,因此 Radarr 不会提供任何手动搜索的结果",
|
"IndexerSearchCheckNoInteractiveMessage": "没有任何索引器开启了手动搜索,因此Radarr 不会提供任何手动搜索的结果",
|
||||||
"IndexerRssHealthCheckNoIndexers": "没有任何索引器开启了RSS同步,Radarr不会自动抓取新发布的影片",
|
"IndexerRssHealthCheckNoIndexers": "没有任何索引器开启了RSS同步,Radarr不会自动抓取新发布的影片",
|
||||||
"IndexerLongTermStatusCheckSingleClientMessage": "由于故障6小时,下列索引器都已不可用:{0}",
|
"IndexerLongTermStatusCheckSingleClientMessage": "由于故障6小时,下列索引器都已不可用:{0}",
|
||||||
"IndexerLongTermStatusCheckAllClientMessage": "由于故障超过6小时,所有索引器均不可用",
|
"IndexerLongTermStatusCheckAllClientMessage": "由于故障超过6小时,所有索引器均不可用",
|
||||||
@@ -1016,7 +1016,7 @@
|
|||||||
"ChmodGroupHelpText": "组名称或GID。对于远程文件系统请使用GID。",
|
"ChmodGroupHelpText": "组名称或GID。对于远程文件系统请使用GID。",
|
||||||
"MinAvailability": "最小可用性",
|
"MinAvailability": "最小可用性",
|
||||||
"RequiredHelpText": "此{0}条件必须匹配才能应用自定义格式。否则,单个{1}匹配就足够了。",
|
"RequiredHelpText": "此{0}条件必须匹配才能应用自定义格式。否则,单个{1}匹配就足够了。",
|
||||||
"QualitiesHelpText": "即使未选中,列表中的质量排序越高优先级也越高。同组内的质量优先级相同。质量只有选中才标记为需要",
|
"QualitiesHelpText": "列表中较高的质量更可取。同一组内的质量相同。只需要检查质量",
|
||||||
"DownloadPropersAndRepacksHelpText2": "使用“不喜欢”按Propers / Repacks中的自定义格式分数排序",
|
"DownloadPropersAndRepacksHelpText2": "使用“不喜欢”按Propers / Repacks中的自定义格式分数排序",
|
||||||
"LookingForReleaseProfiles1": "寻找发行档案?尝试",
|
"LookingForReleaseProfiles1": "寻找发行档案?尝试",
|
||||||
"QualityLimitsHelpText": "影片运行时会自动调整限制。",
|
"QualityLimitsHelpText": "影片运行时会自动调整限制。",
|
||||||
@@ -1072,7 +1072,7 @@
|
|||||||
"IndexerTagHelpText": "仅对至少有一个匹配标记的电影使用此索引器。留空则适用于所有电影。",
|
"IndexerTagHelpText": "仅对至少有一个匹配标记的电影使用此索引器。留空则适用于所有电影。",
|
||||||
"RemotePathMappingCheckFileRemoved": "文件{0} 在处理的过程中被部分删除。",
|
"RemotePathMappingCheckFileRemoved": "文件{0} 在处理的过程中被部分删除。",
|
||||||
"RemotePathMappingCheckFilesGenericPermissions": "下载{1}中客户端{0}报告的文件,但Radarr无法看到此目录。您可能需要调整文件夹的权限。",
|
"RemotePathMappingCheckFilesGenericPermissions": "下载{1}中客户端{0}报告的文件,但Radarr无法看到此目录。您可能需要调整文件夹的权限。",
|
||||||
"RemotePathMappingCheckGenericPermissions": "下载客户端{0}将下载放置在{1}中,但 Radarr 无法看到此目录。您可能需要调整文件夹的权限。",
|
"RemotePathMappingCheckGenericPermissions": "下载客户端{0}将下载放置在{1}中,但Radarr无法看到此目录。您可能需要调整文件夹的权限。",
|
||||||
"UpdateAvailable": "有新的更新可用",
|
"UpdateAvailable": "有新的更新可用",
|
||||||
"Letterboxd": "Letterboxd",
|
"Letterboxd": "Letterboxd",
|
||||||
"RemoveSelectedItem": "删除所选项目",
|
"RemoveSelectedItem": "删除所选项目",
|
||||||
@@ -1143,16 +1143,8 @@
|
|||||||
"OnMovieAdded": "电影添加时",
|
"OnMovieAdded": "电影添加时",
|
||||||
"OnMovieAddedHelpText": "电影添加时",
|
"OnMovieAddedHelpText": "电影添加时",
|
||||||
"TotalMovies": "电影总数",
|
"TotalMovies": "电影总数",
|
||||||
"ApplicationUrlHelpText": "此应用的外部URL,包含 http(s)://、端口和基本URL",
|
"ApplicationUrlHelpText": "此应用的外部URL包含 http(s)://,端口和基本URL",
|
||||||
"ApplicationURL": "程序URL",
|
"ApplicationURL": "程序URL",
|
||||||
"BindAddressHelpText": "有效的 IP 地址,localhost,或以'*'代表所有地址",
|
"BindAddressHelpText": "有效的 IPv4 地址或以'*'代表所有接口",
|
||||||
"PreferredProtocol": "首选协议",
|
"PreferredProtocol": "首选协议"
|
||||||
"AreYouSureYouWantToResetQualityDefinitions": "确定要重置质量定义吗?",
|
|
||||||
"SettingsThemeHelpText": "更改程序界面主题,“自动”主题将根据您的操作系统主题来设置浅色或深色模式。灵感来自Theme.Park",
|
|
||||||
"ResetDefinitions": "重置定义",
|
|
||||||
"ResetQualityDefinitions": "重置质量定义",
|
|
||||||
"ResetTitles": "重置标题",
|
|
||||||
"ResetTitlesHelpText": "重置定义标题与参数值",
|
|
||||||
"SettingsTheme": "主题",
|
|
||||||
"RSSHelpText": "当Radarr定期通过RSS同步查找发布时使用"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Specifications
|
|||||||
|
|
||||||
if (qualityCompare < 0)
|
if (qualityCompare < 0)
|
||||||
{
|
{
|
||||||
_logger.Debug("This file isn't a quality upgrade for movie. New Quality is {0}. Skipping {1}", localMovie.Quality.Quality, localMovie.Path);
|
_logger.Debug("This file isn't a quality upgrade for movie. Skipping {0}", localMovie.Path);
|
||||||
return Decision.Reject("Not an upgrade for existing movie file. New Quality is {0}", localMovie.Quality.Quality);
|
return Decision.Reject("Not a quality upgrade for existing movie file(s)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ namespace NzbDrone.Core.Messaging.Commands
|
|||||||
public virtual bool RequiresDiskAccess => false;
|
public virtual bool RequiresDiskAccess => false;
|
||||||
public virtual bool IsExclusive => false;
|
public virtual bool IsExclusive => false;
|
||||||
public virtual bool IsTypeExclusive => false;
|
public virtual bool IsTypeExclusive => false;
|
||||||
public virtual bool IsLongRunning => false;
|
|
||||||
|
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
public DateTime? LastExecutionTime { get; set; }
|
public DateTime? LastExecutionTime { get; set; }
|
||||||
|
|||||||
@@ -176,11 +176,6 @@ namespace NzbDrone.Core.Messaging.Commands
|
|||||||
queuedCommands = queuedCommands.Where(c => !exclusiveTypes.Any(x => x == c.Body.Name));
|
queuedCommands = queuedCommands.Where(c => !exclusiveTypes.Any(x => x == c.Body.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startedCommands.Any(x => x.Body.IsLongRunning))
|
|
||||||
{
|
|
||||||
queuedCommands = queuedCommands.Where(c => !c.Body.IsExclusive);
|
|
||||||
}
|
|
||||||
|
|
||||||
var localItem = queuedCommands.OrderByDescending(c => c.Priority)
|
var localItem = queuedCommands.OrderByDescending(c => c.Priority)
|
||||||
.ThenBy(c => c.QueuedAt)
|
.ThenBy(c => c.QueuedAt)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|||||||
@@ -45,39 +45,7 @@ namespace NzbDrone.Core.Movies
|
|||||||
|
|
||||||
public List<MovieMetadata> GetMoviesWithCollections()
|
public List<MovieMetadata> GetMoviesWithCollections()
|
||||||
{
|
{
|
||||||
var movieDictionary = new Dictionary<int, MovieMetadata>();
|
return Query(x => x.CollectionTmdbId > 0);
|
||||||
|
|
||||||
var builder = new SqlBuilder(_database.DatabaseType)
|
|
||||||
.LeftJoin<MovieMetadata, MovieTranslation>((mm, t) => mm.Id == t.MovieMetadataId)
|
|
||||||
.Where<MovieMetadata>(x => x.CollectionTmdbId > 0);
|
|
||||||
|
|
||||||
_ = _database.QueryJoined<MovieMetadata, MovieTranslation>(
|
|
||||||
builder,
|
|
||||||
(metadata, translation) =>
|
|
||||||
{
|
|
||||||
MovieMetadata movieEntry;
|
|
||||||
|
|
||||||
if (!movieDictionary.TryGetValue(metadata.Id, out movieEntry))
|
|
||||||
{
|
|
||||||
movieEntry = metadata;
|
|
||||||
movieDictionary.Add(movieEntry.Id, movieEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (translation != null)
|
|
||||||
{
|
|
||||||
movieEntry.Translations.Add(translation);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Add a translation to avoid filename builder making another call thinking translations are not loaded
|
|
||||||
// Optimize this later by pulling translations with metadata always
|
|
||||||
movieEntry.Translations.Add(new MovieTranslation { Title = movieEntry.Title, Language = Language.English });
|
|
||||||
}
|
|
||||||
|
|
||||||
return movieEntry;
|
|
||||||
});
|
|
||||||
|
|
||||||
return movieDictionary.Values.ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MovieMetadata> GetMoviesByCollectionTmdbId(int collectionId)
|
public List<MovieMetadata> GetMoviesByCollectionTmdbId(int collectionId)
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ namespace NzbDrone.Core.Movies
|
|||||||
AddMethod = AddMovieMethod.Collection
|
AddMethod = AddMovieMethod.Collection
|
||||||
},
|
},
|
||||||
Monitored = true
|
Monitored = true
|
||||||
}).ToList(), true);
|
}).ToList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Core.MediaCover;
|
|
||||||
using NzbDrone.Core.Movies;
|
using NzbDrone.Core.Movies;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Gotify
|
namespace NzbDrone.Core.Notifications.Gotify
|
||||||
@@ -23,39 +20,39 @@ namespace NzbDrone.Core.Notifications.Gotify
|
|||||||
public override string Name => "Gotify";
|
public override string Name => "Gotify";
|
||||||
public override string Link => "https://gotify.net/";
|
public override string Link => "https://gotify.net/";
|
||||||
|
|
||||||
public override void OnGrab(GrabMessage message)
|
public override void OnGrab(GrabMessage grabMessage)
|
||||||
{
|
{
|
||||||
SendNotification(MOVIE_GRABBED_TITLE, message.Message, message.Movie);
|
_proxy.SendNotification(MOVIE_GRABBED_TITLE, grabMessage.Message, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnDownload(DownloadMessage message)
|
public override void OnDownload(DownloadMessage message)
|
||||||
{
|
{
|
||||||
SendNotification(MOVIE_DOWNLOADED_TITLE, message.Message, message.Movie);
|
_proxy.SendNotification(MOVIE_DOWNLOADED_TITLE, message.Message, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnMovieAdded(Movie movie)
|
public override void OnMovieAdded(Movie movie)
|
||||||
{
|
{
|
||||||
SendNotification(MOVIE_ADDED_TITLE, $"{movie.Title} added to library", movie);
|
_proxy.SendNotification(MOVIE_ADDED_TITLE, $"{movie.Title} added to library", Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnMovieFileDelete(MovieFileDeleteMessage deleteMessage)
|
public override void OnMovieFileDelete(MovieFileDeleteMessage deleteMessage)
|
||||||
{
|
{
|
||||||
SendNotification(MOVIE_FILE_DELETED_TITLE, deleteMessage.Message, deleteMessage.Movie);
|
_proxy.SendNotification(MOVIE_FILE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnMovieDelete(MovieDeleteMessage deleteMessage)
|
public override void OnMovieDelete(MovieDeleteMessage deleteMessage)
|
||||||
{
|
{
|
||||||
SendNotification(MOVIE_DELETED_TITLE, deleteMessage.Message, deleteMessage.Movie);
|
_proxy.SendNotification(MOVIE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck)
|
public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck)
|
||||||
{
|
{
|
||||||
SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, null);
|
_proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnApplicationUpdate(ApplicationUpdateMessage message)
|
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
|
||||||
{
|
{
|
||||||
SendNotification(APPLICATION_UPDATE_TITLE, message.Message, null);
|
_proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ValidationResult Test()
|
public override ValidationResult Test()
|
||||||
@@ -64,29 +61,10 @@ namespace NzbDrone.Core.Notifications.Gotify
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var isMarkdown = false;
|
|
||||||
const string title = "Test Notification";
|
const string title = "Test Notification";
|
||||||
|
const string body = "This is a test message from Radarr";
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
_proxy.SendNotification(title, body, Settings);
|
||||||
sb.AppendLine("This is a test message from Radarr");
|
|
||||||
|
|
||||||
if (Settings.IncludeMoviePoster)
|
|
||||||
{
|
|
||||||
isMarkdown = true;
|
|
||||||
|
|
||||||
sb.AppendLine("\r");
|
|
||||||
}
|
|
||||||
|
|
||||||
var payload = new GotifyMessage
|
|
||||||
{
|
|
||||||
Title = title,
|
|
||||||
Message = sb.ToString(),
|
|
||||||
Priority = Settings.Priority
|
|
||||||
};
|
|
||||||
|
|
||||||
payload.SetContentType(isMarkdown);
|
|
||||||
|
|
||||||
_proxy.SendNotification(payload, Settings);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -96,35 +74,5 @@ namespace NzbDrone.Core.Notifications.Gotify
|
|||||||
|
|
||||||
return new ValidationResult(failures);
|
return new ValidationResult(failures);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendNotification(string title, string message, Movie movie)
|
|
||||||
{
|
|
||||||
var isMarkdown = false;
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.AppendLine(message);
|
|
||||||
|
|
||||||
if (Settings.IncludeMoviePoster && movie != null)
|
|
||||||
{
|
|
||||||
var poster = movie.MovieMetadata.Value.Images.FirstOrDefault(x => x.CoverType == MediaCoverTypes.Poster)?.Url;
|
|
||||||
|
|
||||||
if (poster != null)
|
|
||||||
{
|
|
||||||
isMarkdown = true;
|
|
||||||
sb.AppendLine($"\r");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var payload = new GotifyMessage
|
|
||||||
{
|
|
||||||
Title = title,
|
|
||||||
Message = sb.ToString(),
|
|
||||||
Priority = Settings.Priority
|
|
||||||
};
|
|
||||||
|
|
||||||
payload.SetContentType(isMarkdown);
|
|
||||||
|
|
||||||
_proxy.SendNotification(payload, Settings);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Gotify
|
|
||||||
{
|
|
||||||
public class GotifyMessage
|
|
||||||
{
|
|
||||||
public string Title { get; set; }
|
|
||||||
public string Message { get; set; }
|
|
||||||
public int Priority { get; set; }
|
|
||||||
public GotifyExtras Extras { get; set; }
|
|
||||||
|
|
||||||
public GotifyMessage()
|
|
||||||
{
|
|
||||||
Extras = new GotifyExtras();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetContentType(bool isMarkdown)
|
|
||||||
{
|
|
||||||
var contentType = isMarkdown ? "text/markdown" : "text/plain";
|
|
||||||
|
|
||||||
Extras.ClientDisplay = new GotifyClientDisplay(contentType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GotifyExtras
|
|
||||||
{
|
|
||||||
[JsonProperty("client::display")]
|
|
||||||
public GotifyClientDisplay ClientDisplay { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GotifyClientDisplay
|
|
||||||
{
|
|
||||||
public string ContentType { get; set; }
|
|
||||||
|
|
||||||
public GotifyClientDisplay(string contentType)
|
|
||||||
{
|
|
||||||
ContentType = contentType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Gotify
|
namespace NzbDrone.Core.Notifications.Gotify
|
||||||
{
|
{
|
||||||
public interface IGotifyProxy
|
public interface IGotifyProxy
|
||||||
{
|
{
|
||||||
void SendNotification(GotifyMessage payload, GotifySettings settings);
|
void SendNotification(string title, string message, GotifySettings settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GotifyProxy : IGotifyProxy
|
public class GotifyProxy : IGotifyProxy
|
||||||
@@ -18,20 +17,16 @@ namespace NzbDrone.Core.Notifications.Gotify
|
|||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendNotification(GotifyMessage payload, GotifySettings settings)
|
public void SendNotification(string title, string message, GotifySettings settings)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var request = new HttpRequestBuilder(settings.Server)
|
var request = new HttpRequestBuilder(settings.Server).Resource("message").Post()
|
||||||
.Resource("message")
|
.AddQueryParam("token", settings.AppToken)
|
||||||
.Post()
|
.AddFormParameter("title", title)
|
||||||
.AddQueryParam("token", settings.AppToken)
|
.AddFormParameter("message", message)
|
||||||
.Build();
|
.AddFormParameter("priority", settings.Priority)
|
||||||
|
.Build();
|
||||||
request.Headers.ContentType = "application/json";
|
|
||||||
|
|
||||||
var json = payload.ToJson();
|
|
||||||
request.SetContent(payload.ToJson());
|
|
||||||
|
|
||||||
_httpClient.Execute(request);
|
_httpClient.Execute(request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,9 +32,6 @@ namespace NzbDrone.Core.Notifications.Gotify
|
|||||||
[FieldDefinition(2, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(GotifyPriority), HelpText = "Priority of the notification")]
|
[FieldDefinition(2, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(GotifyPriority), HelpText = "Priority of the notification")]
|
||||||
public int Priority { get; set; }
|
public int Priority { get; set; }
|
||||||
|
|
||||||
[FieldDefinition(3, Label = "Include Movie Poster", Type = FieldType.Checkbox, HelpText = "Include movie poster in message")]
|
|
||||||
public bool IncludeMoviePoster { get; set; }
|
|
||||||
|
|
||||||
public NzbDroneValidationResult Validate()
|
public NzbDroneValidationResult Validate()
|
||||||
{
|
{
|
||||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace NzbDrone.Core.Notifications.Emby
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override string Link => "https://emby.media/";
|
public override string Link => "https://emby.media/";
|
||||||
public override string Name => "Emby / Jellyfin";
|
public override string Name => "Emby";
|
||||||
|
|
||||||
public override void OnGrab(GrabMessage grabMessage)
|
public override void OnGrab(GrabMessage grabMessage)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
@@ -44,7 +43,7 @@ namespace NzbDrone.Core.Notifications.Emby
|
|||||||
public bool UpdateLibrary { get; set; }
|
public bool UpdateLibrary { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string Address => $"{Host.ToUrlHost()}:{Port}";
|
public string Address => $"{Host}:{Port}";
|
||||||
|
|
||||||
public bool IsValid => !string.IsNullOrWhiteSpace(Host) && Port > 0;
|
public bool IsValid => !string.IsNullOrWhiteSpace(Host) && Port > 0;
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ namespace NzbDrone.Core.Notifications.Plex.Server
|
|||||||
{
|
{
|
||||||
var scheme = settings.UseSsl ? "https" : "http";
|
var scheme = settings.UseSsl ? "https" : "http";
|
||||||
|
|
||||||
var requestBuilder = new HttpRequestBuilder($"{scheme}://{settings.Host.ToUrlHost()}:{settings.Port}")
|
var requestBuilder = new HttpRequestBuilder($"{scheme}://{settings.Host}:{settings.Port}")
|
||||||
.Accept(HttpAccept.Json)
|
.Accept(HttpAccept.Json)
|
||||||
.AddQueryParam("X-Plex-Client-Identifier", _configService.PlexClientIdentifier)
|
.AddQueryParam("X-Plex-Client-Identifier", _configService.PlexClientIdentifier)
|
||||||
.AddQueryParam("X-Plex-Product", BuildInfo.AppName)
|
.AddQueryParam("X-Plex-Product", BuildInfo.AppName)
|
||||||
|
|||||||
@@ -1,28 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.MediaFiles;
|
|
||||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
|
||||||
using NzbDrone.Core.Movies;
|
|
||||||
using NzbDrone.Core.Notifications.Trakt.Resource;
|
|
||||||
using NzbDrone.Core.Qualities;
|
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Trakt
|
namespace NzbDrone.Core.Notifications.Trakt
|
||||||
{
|
{
|
||||||
public class Trakt : NotificationBase<TraktSettings>
|
public class Trakt : NotificationBase<TraktSettings>
|
||||||
{
|
{
|
||||||
private readonly ITraktProxy _proxy;
|
private readonly ITraktService _traktService;
|
||||||
private readonly INotificationRepository _notificationRepository;
|
private readonly INotificationRepository _notificationRepository;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public Trakt(ITraktProxy proxy, INotificationRepository notificationRepository, Logger logger)
|
public Trakt(ITraktService traktService, INotificationRepository notificationRepository, Logger logger)
|
||||||
{
|
{
|
||||||
_proxy = proxy;
|
_traktService = traktService;
|
||||||
_notificationRepository = notificationRepository;
|
_notificationRepository = notificationRepository;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
@@ -32,53 +26,27 @@ namespace NzbDrone.Core.Notifications.Trakt
|
|||||||
|
|
||||||
public override void OnDownload(DownloadMessage message)
|
public override void OnDownload(DownloadMessage message)
|
||||||
{
|
{
|
||||||
RefreshTokenIfNecessary();
|
_traktService.AddMovieToCollection(Settings, message.Movie, message.MovieFile);
|
||||||
AddMovieToCollection(Settings, message.Movie, message.MovieFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnMovieFileDelete(MovieFileDeleteMessage deleteMessage)
|
public override void OnMovieFileDelete(MovieFileDeleteMessage deleteMessage)
|
||||||
{
|
{
|
||||||
RefreshTokenIfNecessary();
|
_traktService.RemoveMovieFromCollection(Settings, deleteMessage.Movie);
|
||||||
RemoveMovieFromCollection(Settings, deleteMessage.Movie);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnMovieDelete(MovieDeleteMessage deleteMessage)
|
public override void OnMovieDelete(MovieDeleteMessage deleteMessage)
|
||||||
{
|
{
|
||||||
RefreshTokenIfNecessary();
|
if (deleteMessage.DeletedFiles)
|
||||||
RemoveMovieFromCollection(Settings, deleteMessage.Movie);
|
{
|
||||||
|
_traktService.RemoveMovieFromCollection(Settings, deleteMessage.Movie);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ValidationResult Test()
|
public override ValidationResult Test()
|
||||||
{
|
{
|
||||||
var failures = new List<ValidationFailure>();
|
var failures = new List<ValidationFailure>();
|
||||||
|
|
||||||
RefreshTokenIfNecessary();
|
failures.AddIfNotNull(_traktService.Test(Settings));
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_proxy.GetUserName(Settings.AccessToken);
|
|
||||||
}
|
|
||||||
catch (HttpException ex)
|
|
||||||
{
|
|
||||||
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
|
|
||||||
{
|
|
||||||
_logger.Error(ex, "Access Token is invalid: " + ex.Message);
|
|
||||||
|
|
||||||
failures.Add(new ValidationFailure("Token", "Access Token is invalid"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Error(ex, "Unable to send test message: " + ex.Message);
|
|
||||||
|
|
||||||
failures.Add(new ValidationFailure("Token", "Unable to send test message"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.Error(ex, "Unable to send test message: " + ex.Message);
|
|
||||||
|
|
||||||
failures.Add(new ValidationFailure("", "Unable to send test message"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ValidationResult(failures);
|
return new ValidationResult(failures);
|
||||||
}
|
}
|
||||||
@@ -87,7 +55,7 @@ namespace NzbDrone.Core.Notifications.Trakt
|
|||||||
{
|
{
|
||||||
if (action == "startOAuth")
|
if (action == "startOAuth")
|
||||||
{
|
{
|
||||||
var request = _proxy.GetOAuthRequest(query["callbackUrl"]);
|
var request = _traktService.GetOAuthRequest(query["callbackUrl"]);
|
||||||
|
|
||||||
return new
|
return new
|
||||||
{
|
{
|
||||||
@@ -101,22 +69,14 @@ namespace NzbDrone.Core.Notifications.Trakt
|
|||||||
accessToken = query["access_token"],
|
accessToken = query["access_token"],
|
||||||
expires = DateTime.UtcNow.AddSeconds(int.Parse(query["expires_in"])),
|
expires = DateTime.UtcNow.AddSeconds(int.Parse(query["expires_in"])),
|
||||||
refreshToken = query["refresh_token"],
|
refreshToken = query["refresh_token"],
|
||||||
authUser = _proxy.GetUserName(query["access_token"])
|
authUser = _traktService.GetUserName(query["access_token"])
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return new { };
|
return new { };
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshTokenIfNecessary()
|
public void RefreshToken()
|
||||||
{
|
|
||||||
if (Settings.Expires < DateTime.UtcNow.AddMinutes(5))
|
|
||||||
{
|
|
||||||
RefreshToken();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RefreshToken()
|
|
||||||
{
|
{
|
||||||
_logger.Trace("Refreshing Token");
|
_logger.Trace("Refreshing Token");
|
||||||
|
|
||||||
@@ -124,12 +84,11 @@ namespace NzbDrone.Core.Notifications.Trakt
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = _proxy.RefreshAuthToken(Settings.RefreshToken);
|
var response = _traktService.RefreshAuthToken(Settings.RefreshToken);
|
||||||
|
|
||||||
if (response != null)
|
if (response != null)
|
||||||
{
|
{
|
||||||
var token = response;
|
var token = response;
|
||||||
|
|
||||||
Settings.AccessToken = token.AccessToken;
|
Settings.AccessToken = token.AccessToken;
|
||||||
Settings.Expires = DateTime.UtcNow.AddSeconds(token.ExpiresIn);
|
Settings.Expires = DateTime.UtcNow.AddSeconds(token.ExpiresIn);
|
||||||
Settings.RefreshToken = token.RefreshToken ?? Settings.RefreshToken;
|
Settings.RefreshToken = token.RefreshToken ?? Settings.RefreshToken;
|
||||||
@@ -140,193 +99,10 @@ namespace NzbDrone.Core.Notifications.Trakt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (HttpException ex)
|
catch (HttpException)
|
||||||
{
|
{
|
||||||
_logger.Warn(ex, "Error refreshing trakt access token");
|
_logger.Warn($"Error refreshing trakt access token");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddMovieToCollection(TraktSettings settings, Movie movie, MovieFile movieFile)
|
|
||||||
{
|
|
||||||
var payload = new TraktCollectMoviesResource
|
|
||||||
{
|
|
||||||
Movies = new List<TraktCollectMovie>()
|
|
||||||
};
|
|
||||||
|
|
||||||
var traktResolution = MapResolution(movieFile.Quality.Quality.Resolution, movieFile.MediaInfo?.ScanType);
|
|
||||||
var mediaType = MapMediaType(movieFile.Quality.Quality.Source);
|
|
||||||
var audio = MapAudio(movieFile);
|
|
||||||
var audioChannels = MapAudioChannels(movieFile);
|
|
||||||
|
|
||||||
payload.Movies.Add(new TraktCollectMovie
|
|
||||||
{
|
|
||||||
Title = movie.Title,
|
|
||||||
Year = movie.Year,
|
|
||||||
CollectedAt = DateTime.Now,
|
|
||||||
Resolution = traktResolution,
|
|
||||||
MediaType = mediaType,
|
|
||||||
AudioChannels = audioChannels,
|
|
||||||
Audio = audio,
|
|
||||||
Ids = new TraktMovieIdsResource
|
|
||||||
{
|
|
||||||
Tmdb = movie.MovieMetadata.Value.TmdbId,
|
|
||||||
Imdb = movie.MovieMetadata.Value.ImdbId ?? "",
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
_proxy.AddToCollection(payload, settings.AccessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveMovieFromCollection(TraktSettings settings, Movie movie)
|
|
||||||
{
|
|
||||||
var payload = new TraktCollectMoviesResource
|
|
||||||
{
|
|
||||||
Movies = new List<TraktCollectMovie>()
|
|
||||||
};
|
|
||||||
|
|
||||||
payload.Movies.Add(new TraktCollectMovie
|
|
||||||
{
|
|
||||||
Title = movie.Title,
|
|
||||||
Year = movie.Year,
|
|
||||||
Ids = new TraktMovieIdsResource
|
|
||||||
{
|
|
||||||
Tmdb = movie.MovieMetadata.Value.TmdbId,
|
|
||||||
Imdb = movie.MovieMetadata.Value.ImdbId ?? "",
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
_proxy.RemoveFromCollection(payload, settings.AccessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string MapMediaType(Source source)
|
|
||||||
{
|
|
||||||
var traktSource = string.Empty;
|
|
||||||
|
|
||||||
switch (source)
|
|
||||||
{
|
|
||||||
case Source.BLURAY:
|
|
||||||
traktSource = "bluray";
|
|
||||||
break;
|
|
||||||
case Source.WEBDL:
|
|
||||||
traktSource = "digital";
|
|
||||||
break;
|
|
||||||
case Source.WEBRIP:
|
|
||||||
traktSource = "digital";
|
|
||||||
break;
|
|
||||||
case Source.DVD:
|
|
||||||
traktSource = "dvd";
|
|
||||||
break;
|
|
||||||
case Source.TV:
|
|
||||||
traktSource = "dvd";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return traktSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string MapResolution(int resolution, string scanType)
|
|
||||||
{
|
|
||||||
var traktResolution = string.Empty;
|
|
||||||
|
|
||||||
var scanIdentifier = scanType.IsNotNullOrWhiteSpace() && TraktInterlacedTypes.interlacedTypes.Contains(scanType) ? "i" : "p";
|
|
||||||
|
|
||||||
switch (resolution)
|
|
||||||
{
|
|
||||||
case 2160:
|
|
||||||
traktResolution = "uhd_4k";
|
|
||||||
break;
|
|
||||||
case 1080:
|
|
||||||
traktResolution = $"hd_1080{scanIdentifier}";
|
|
||||||
break;
|
|
||||||
case 720:
|
|
||||||
traktResolution = "hd_720p";
|
|
||||||
break;
|
|
||||||
case 576:
|
|
||||||
traktResolution = $"sd_576{scanIdentifier}";
|
|
||||||
break;
|
|
||||||
case 480:
|
|
||||||
traktResolution = $"sd_480{scanIdentifier}";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return traktResolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string MapAudio(MovieFile movieFile)
|
|
||||||
{
|
|
||||||
var traktAudioFormat = string.Empty;
|
|
||||||
|
|
||||||
var audioCodec = movieFile.MediaInfo != null ? MediaInfoFormatter.FormatAudioCodec(movieFile.MediaInfo, movieFile.SceneName) : string.Empty;
|
|
||||||
|
|
||||||
switch (audioCodec)
|
|
||||||
{
|
|
||||||
case "AC3":
|
|
||||||
traktAudioFormat = "dolby_digital";
|
|
||||||
break;
|
|
||||||
case "EAC3":
|
|
||||||
traktAudioFormat = "dolby_digital_plus";
|
|
||||||
break;
|
|
||||||
case "TrueHD":
|
|
||||||
traktAudioFormat = "dolby_truehd";
|
|
||||||
break;
|
|
||||||
case "EAC3 Atmos":
|
|
||||||
traktAudioFormat = "dolby_digital_plus_atmos";
|
|
||||||
break;
|
|
||||||
case "TrueHD Atmos":
|
|
||||||
traktAudioFormat = "dolby_atmos";
|
|
||||||
break;
|
|
||||||
case "DTS":
|
|
||||||
case "DTS-ES":
|
|
||||||
traktAudioFormat = "dts";
|
|
||||||
break;
|
|
||||||
case "DTS-HD MA":
|
|
||||||
traktAudioFormat = "dts_ma";
|
|
||||||
break;
|
|
||||||
case "DTS-HD HRA":
|
|
||||||
traktAudioFormat = "dts_hr";
|
|
||||||
break;
|
|
||||||
case "DTS-X":
|
|
||||||
traktAudioFormat = "dts_x";
|
|
||||||
break;
|
|
||||||
case "MP3":
|
|
||||||
traktAudioFormat = "mp3";
|
|
||||||
break;
|
|
||||||
case "MP2":
|
|
||||||
traktAudioFormat = "mp2";
|
|
||||||
break;
|
|
||||||
case "Vorbis":
|
|
||||||
traktAudioFormat = "ogg";
|
|
||||||
break;
|
|
||||||
case "WMA":
|
|
||||||
traktAudioFormat = "wma";
|
|
||||||
break;
|
|
||||||
case "AAC":
|
|
||||||
traktAudioFormat = "aac";
|
|
||||||
break;
|
|
||||||
case "PCM":
|
|
||||||
traktAudioFormat = "lpcm";
|
|
||||||
break;
|
|
||||||
case "FLAC":
|
|
||||||
traktAudioFormat = "flac";
|
|
||||||
break;
|
|
||||||
case "Opus":
|
|
||||||
traktAudioFormat = "ogg_opus";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return traktAudioFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string MapAudioChannels(MovieFile movieFile)
|
|
||||||
{
|
|
||||||
var audioChannels = movieFile.MediaInfo != null ? MediaInfoFormatter.FormatAudioChannels(movieFile.MediaInfo).ToString("0.0") : string.Empty;
|
|
||||||
|
|
||||||
if (audioChannels == "0.0")
|
|
||||||
{
|
|
||||||
audioChannels = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
return audioChannels;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Trakt
|
|
||||||
{
|
|
||||||
public static class TraktInterlacedTypes
|
|
||||||
{
|
|
||||||
private static HashSet<string> _interlacedTypes;
|
|
||||||
|
|
||||||
static TraktInterlacedTypes()
|
|
||||||
{
|
|
||||||
_interlacedTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
|
||||||
{
|
|
||||||
"Interlaced", "MBAFF", "PAFF"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HashSet<string> interlacedTypes => _interlacedTypes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@ namespace NzbDrone.Core.Notifications.Trakt
|
|||||||
TraktAuthRefreshResource RefreshAuthToken(string refreshToken);
|
TraktAuthRefreshResource RefreshAuthToken(string refreshToken);
|
||||||
void AddToCollection(TraktCollectMoviesResource payload, string accessToken);
|
void AddToCollection(TraktCollectMoviesResource payload, string accessToken);
|
||||||
void RemoveFromCollection(TraktCollectMoviesResource payload, string accessToken);
|
void RemoveFromCollection(TraktCollectMoviesResource payload, string accessToken);
|
||||||
HttpRequest BuildRequest(string resource, HttpMethod method, string accessToken);
|
HttpRequest BuildTraktRequest(string resource, HttpMethod method, string accessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TraktProxy : ITraktProxy
|
public class TraktProxy : ITraktProxy
|
||||||
@@ -36,30 +36,59 @@ namespace NzbDrone.Core.Notifications.Trakt
|
|||||||
|
|
||||||
public void AddToCollection(TraktCollectMoviesResource payload, string accessToken)
|
public void AddToCollection(TraktCollectMoviesResource payload, string accessToken)
|
||||||
{
|
{
|
||||||
var request = BuildRequest("sync/collection", HttpMethod.Post, accessToken);
|
var request = BuildTraktRequest("sync/collection", HttpMethod.Post, accessToken);
|
||||||
|
|
||||||
request.Headers.ContentType = "application/json";
|
request.Headers.ContentType = "application/json";
|
||||||
request.SetContent(payload.ToJson());
|
request.SetContent(payload.ToJson());
|
||||||
|
|
||||||
MakeRequest(request);
|
try
|
||||||
|
{
|
||||||
|
_httpClient.Execute(request);
|
||||||
|
}
|
||||||
|
catch (HttpException ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Unable to post payload {0}", payload);
|
||||||
|
throw new TraktException("Unable to post payload", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveFromCollection(TraktCollectMoviesResource payload, string accessToken)
|
public void RemoveFromCollection(TraktCollectMoviesResource payload, string accessToken)
|
||||||
{
|
{
|
||||||
var request = BuildRequest("sync/collection/remove", HttpMethod.Post, accessToken);
|
var request = BuildTraktRequest("sync/collection/remove", HttpMethod.Post, accessToken);
|
||||||
|
|
||||||
request.Headers.ContentType = "application/json";
|
request.Headers.ContentType = "application/json";
|
||||||
request.SetContent(payload.ToJson());
|
request.SetContent(payload.ToJson());
|
||||||
|
|
||||||
MakeRequest(request);
|
try
|
||||||
|
{
|
||||||
|
_httpClient.Execute(request);
|
||||||
|
}
|
||||||
|
catch (HttpException ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Unable to post payload {0}", payload);
|
||||||
|
throw new TraktException("Unable to post payload", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetUserName(string accessToken)
|
public string GetUserName(string accessToken)
|
||||||
{
|
{
|
||||||
var request = BuildRequest("users/settings", HttpMethod.Get, accessToken);
|
var request = BuildTraktRequest("users/settings", HttpMethod.Get, accessToken);
|
||||||
var response = _httpClient.Get<TraktUserSettingsResource>(request);
|
|
||||||
|
|
||||||
return response?.Resource?.User?.Ids?.Slug;
|
try
|
||||||
|
{
|
||||||
|
var response = _httpClient.Get<TraktUserSettingsResource>(request);
|
||||||
|
|
||||||
|
if (response != null && response.Resource != null)
|
||||||
|
{
|
||||||
|
return response.Resource.User.Ids.Slug;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (HttpException)
|
||||||
|
{
|
||||||
|
_logger.Warn($"Error refreshing trakt access token");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpRequest GetOAuthRequest(string callbackUrl)
|
public HttpRequest GetOAuthRequest(string callbackUrl)
|
||||||
@@ -81,7 +110,7 @@ namespace NzbDrone.Core.Notifications.Trakt
|
|||||||
return _httpClient.Get<TraktAuthRefreshResource>(request)?.Resource ?? null;
|
return _httpClient.Get<TraktAuthRefreshResource>(request)?.Resource ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpRequest BuildRequest(string resource, HttpMethod method, string accessToken)
|
public HttpRequest BuildTraktRequest(string resource, HttpMethod method, string accessToken)
|
||||||
{
|
{
|
||||||
var request = new HttpRequestBuilder(URL).Resource(resource).Build();
|
var request = new HttpRequestBuilder(URL).Resource(resource).Build();
|
||||||
|
|
||||||
@@ -98,17 +127,5 @@ namespace NzbDrone.Core.Notifications.Trakt
|
|||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MakeRequest(HttpRequest request)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_httpClient.Execute(request);
|
|
||||||
}
|
|
||||||
catch (HttpException ex)
|
|
||||||
{
|
|
||||||
throw new TraktException("Unable to send payload", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,263 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||||
|
using NzbDrone.Core.Movies;
|
||||||
|
using NzbDrone.Core.Notifications.Trakt.Resource;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Trakt
|
||||||
|
{
|
||||||
|
public interface ITraktService
|
||||||
|
{
|
||||||
|
HttpRequest GetOAuthRequest(string callbackUrl);
|
||||||
|
TraktAuthRefreshResource RefreshAuthToken(string refreshToken);
|
||||||
|
void AddMovieToCollection(TraktSettings settings, Movie movie, MovieFile movieFile);
|
||||||
|
void RemoveMovieFromCollection(TraktSettings settings, Movie movie);
|
||||||
|
string GetUserName(string accessToken);
|
||||||
|
ValidationFailure Test(TraktSettings settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TraktService : ITraktService
|
||||||
|
{
|
||||||
|
private readonly ITraktProxy _proxy;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public TraktService(ITraktProxy proxy,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_proxy = proxy;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetUserName(string accessToken)
|
||||||
|
{
|
||||||
|
return _proxy.GetUserName(accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpRequest GetOAuthRequest(string callbackUrl)
|
||||||
|
{
|
||||||
|
return _proxy.GetOAuthRequest(callbackUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TraktAuthRefreshResource RefreshAuthToken(string refreshToken)
|
||||||
|
{
|
||||||
|
return _proxy.RefreshAuthToken(refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValidationFailure Test(TraktSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
GetUserName(settings.AccessToken);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (HttpException ex)
|
||||||
|
{
|
||||||
|
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Access Token is invalid: " + ex.Message);
|
||||||
|
return new ValidationFailure("Token", "Access Token is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Error(ex, "Unable to send test message: " + ex.Message);
|
||||||
|
return new ValidationFailure("Token", "Unable to send test message");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Unable to send test message: " + ex.Message);
|
||||||
|
return new ValidationFailure("", "Unable to send test message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveMovieFromCollection(TraktSettings settings, Movie movie)
|
||||||
|
{
|
||||||
|
var payload = new TraktCollectMoviesResource
|
||||||
|
{
|
||||||
|
Movies = new List<TraktCollectMovie>()
|
||||||
|
};
|
||||||
|
|
||||||
|
payload.Movies.Add(new TraktCollectMovie
|
||||||
|
{
|
||||||
|
Title = movie.Title,
|
||||||
|
Year = movie.Year,
|
||||||
|
Ids = new TraktMovieIdsResource
|
||||||
|
{
|
||||||
|
Tmdb = movie.MovieMetadata.Value.TmdbId,
|
||||||
|
Imdb = movie.MovieMetadata.Value.ImdbId ?? "",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_proxy.RemoveFromCollection(payload, settings.AccessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMovieToCollection(TraktSettings settings, Movie movie, MovieFile movieFile)
|
||||||
|
{
|
||||||
|
var payload = new TraktCollectMoviesResource
|
||||||
|
{
|
||||||
|
Movies = new List<TraktCollectMovie>()
|
||||||
|
};
|
||||||
|
|
||||||
|
var traktResolution = MapResolution(movieFile.Quality.Quality.Resolution, movieFile.MediaInfo?.ScanType);
|
||||||
|
var mediaType = MapMediaType(movieFile.Quality.Quality.Source);
|
||||||
|
var audio = MapAudio(movieFile);
|
||||||
|
var audioChannels = MapAudioChannels(movieFile, audio);
|
||||||
|
|
||||||
|
payload.Movies.Add(new TraktCollectMovie
|
||||||
|
{
|
||||||
|
Title = movie.Title,
|
||||||
|
Year = movie.Year,
|
||||||
|
CollectedAt = DateTime.Now,
|
||||||
|
Resolution = traktResolution,
|
||||||
|
MediaType = mediaType,
|
||||||
|
AudioChannels = audioChannels,
|
||||||
|
Audio = audio,
|
||||||
|
Ids = new TraktMovieIdsResource
|
||||||
|
{
|
||||||
|
Tmdb = movie.MovieMetadata.Value.TmdbId,
|
||||||
|
Imdb = movie.MovieMetadata.Value.ImdbId ?? "",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_proxy.AddToCollection(payload, settings.AccessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string MapMediaType(Source source)
|
||||||
|
{
|
||||||
|
var traktSource = string.Empty;
|
||||||
|
|
||||||
|
switch (source)
|
||||||
|
{
|
||||||
|
case Source.BLURAY:
|
||||||
|
traktSource = "bluray";
|
||||||
|
break;
|
||||||
|
case Source.WEBDL:
|
||||||
|
traktSource = "digital";
|
||||||
|
break;
|
||||||
|
case Source.WEBRIP:
|
||||||
|
traktSource = "digital";
|
||||||
|
break;
|
||||||
|
case Source.DVD:
|
||||||
|
traktSource = "dvd";
|
||||||
|
break;
|
||||||
|
case Source.TV:
|
||||||
|
traktSource = "dvd";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return traktSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string MapResolution(int resolution, string scanType)
|
||||||
|
{
|
||||||
|
var traktResolution = string.Empty;
|
||||||
|
var interlacedTypes = new string[] { "Interlaced", "MBAFF", "PAFF" };
|
||||||
|
|
||||||
|
var scanIdentifier = scanType.IsNotNullOrWhiteSpace() && interlacedTypes.Contains(scanType) ? "i" : "p";
|
||||||
|
|
||||||
|
switch (resolution)
|
||||||
|
{
|
||||||
|
case 2160:
|
||||||
|
traktResolution = "uhd_4k";
|
||||||
|
break;
|
||||||
|
case 1080:
|
||||||
|
traktResolution = string.Format("hd_1080{0}", scanIdentifier);
|
||||||
|
break;
|
||||||
|
case 720:
|
||||||
|
traktResolution = "hd_720p";
|
||||||
|
break;
|
||||||
|
case 576:
|
||||||
|
traktResolution = string.Format("sd_576{0}", scanIdentifier);
|
||||||
|
break;
|
||||||
|
case 480:
|
||||||
|
traktResolution = string.Format("sd_480{0}", scanIdentifier);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return traktResolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string MapAudio(MovieFile movieFile)
|
||||||
|
{
|
||||||
|
var traktAudioFormat = string.Empty;
|
||||||
|
|
||||||
|
var audioCodec = movieFile.MediaInfo != null ? MediaInfoFormatter.FormatAudioCodec(movieFile.MediaInfo, movieFile.SceneName) : string.Empty;
|
||||||
|
|
||||||
|
switch (audioCodec)
|
||||||
|
{
|
||||||
|
case "AC3":
|
||||||
|
traktAudioFormat = "dolby_digital";
|
||||||
|
break;
|
||||||
|
case "EAC3":
|
||||||
|
traktAudioFormat = "dolby_digital_plus";
|
||||||
|
break;
|
||||||
|
case "TrueHD":
|
||||||
|
traktAudioFormat = "dolby_truehd";
|
||||||
|
break;
|
||||||
|
case "EAC3 Atmos":
|
||||||
|
traktAudioFormat = "dolby_digital_plus_atmos";
|
||||||
|
break;
|
||||||
|
case "TrueHD Atmos":
|
||||||
|
traktAudioFormat = "dolby_atmos";
|
||||||
|
break;
|
||||||
|
case "DTS":
|
||||||
|
case "DTS-ES":
|
||||||
|
traktAudioFormat = "dts";
|
||||||
|
break;
|
||||||
|
case "DTS-HD MA":
|
||||||
|
traktAudioFormat = "dts_ma";
|
||||||
|
break;
|
||||||
|
case "DTS-HD HRA":
|
||||||
|
traktAudioFormat = "dts_hr";
|
||||||
|
break;
|
||||||
|
case "DTS-X":
|
||||||
|
traktAudioFormat = "dts_x";
|
||||||
|
break;
|
||||||
|
case "MP3":
|
||||||
|
traktAudioFormat = "mp3";
|
||||||
|
break;
|
||||||
|
case "MP2":
|
||||||
|
traktAudioFormat = "mp2";
|
||||||
|
break;
|
||||||
|
case "Vorbis":
|
||||||
|
traktAudioFormat = "ogg";
|
||||||
|
break;
|
||||||
|
case "WMA":
|
||||||
|
traktAudioFormat = "wma";
|
||||||
|
break;
|
||||||
|
case "AAC":
|
||||||
|
traktAudioFormat = "aac";
|
||||||
|
break;
|
||||||
|
case "PCM":
|
||||||
|
traktAudioFormat = "lpcm";
|
||||||
|
break;
|
||||||
|
case "FLAC":
|
||||||
|
traktAudioFormat = "flac";
|
||||||
|
break;
|
||||||
|
case "Opus":
|
||||||
|
traktAudioFormat = "ogg_opus";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return traktAudioFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string MapAudioChannels(MovieFile movieFile, string audioFormat)
|
||||||
|
{
|
||||||
|
var audioChannels = movieFile.MediaInfo != null ? MediaInfoFormatter.FormatAudioChannels(movieFile.MediaInfo).ToString("0.0") : string.Empty;
|
||||||
|
|
||||||
|
if (audioChannels == "0.0")
|
||||||
|
{
|
||||||
|
audioChannels = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return audioChannels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,11 +21,7 @@ namespace NzbDrone.Core.Notifications.Webhook
|
|||||||
IndexerFlags = movieFile.IndexerFlags.ToString();
|
IndexerFlags = movieFile.IndexerFlags.ToString();
|
||||||
Size = movieFile.Size;
|
Size = movieFile.Size;
|
||||||
DateAdded = movieFile.DateAdded;
|
DateAdded = movieFile.DateAdded;
|
||||||
|
MediaInfo = new WebhookMovieFileMediaInfo(movieFile);
|
||||||
if (movieFile.MediaInfo != null)
|
|
||||||
{
|
|
||||||
MediaInfo = new WebhookMovieFileMediaInfo(movieFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||||||
|
|
||||||
if (moviePath != null)
|
if (moviePath != null)
|
||||||
{
|
{
|
||||||
|
moviePath = new OsPath(moviePath).Directory.FullPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
_logger.Debug("Updating movie {0} (Path: {1}) on XBMC host: {2}", movie, moviePath, settings.Address);
|
_logger.Debug("Updating movie {0} (Path: {1}) on XBMC host: {2}", movie, moviePath, settings.Address);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
@@ -59,7 +58,7 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||||||
public bool AlwaysUpdate { get; set; }
|
public bool AlwaysUpdate { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string Address => $"{Host.ToUrlHost()}:{Port}";
|
public string Address => string.Format("{0}:{1}", Host, Port);
|
||||||
|
|
||||||
public NzbDroneValidationResult Validate()
|
public NzbDroneValidationResult Validate()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Microsoft.Extensions.FileSystemGlobbing;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Instrumentation;
|
using NzbDrone.Common.Instrumentation;
|
||||||
@@ -198,34 +197,31 @@ namespace NzbDrone.Core.Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Case sensitive
|
// Case sensitive
|
||||||
var caseSensitiveMatchs = CaseSensitiveLanguageRegex.Matches(title);
|
var caseSensitiveMatch = CaseSensitiveLanguageRegex.Match(title);
|
||||||
|
|
||||||
foreach (Match match in caseSensitiveMatchs)
|
if (caseSensitiveMatch.Groups["lithuanian"].Captures.Cast<Capture>().Any())
|
||||||
{
|
{
|
||||||
if (match.Groups["lithuanian"].Captures.Cast<Capture>().Any())
|
languages.Add(Language.Lithuanian);
|
||||||
{
|
}
|
||||||
languages.Add(Language.Lithuanian);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match.Groups["czech"].Captures.Cast<Capture>().Any())
|
if (caseSensitiveMatch.Groups["czech"].Captures.Cast<Capture>().Any())
|
||||||
{
|
{
|
||||||
languages.Add(Language.Czech);
|
languages.Add(Language.Czech);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.Groups["polish"].Captures.Cast<Capture>().Any())
|
if (caseSensitiveMatch.Groups["polish"].Captures.Cast<Capture>().Any())
|
||||||
{
|
{
|
||||||
languages.Add(Language.Polish);
|
languages.Add(Language.Polish);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.Groups["bulgarian"].Captures.Cast<Capture>().Any())
|
if (caseSensitiveMatch.Groups["bulgarian"].Captures.Cast<Capture>().Any())
|
||||||
{
|
{
|
||||||
languages.Add(Language.Bulgarian);
|
languages.Add(Language.Bulgarian);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.Groups["slovak"].Captures.Cast<Capture>().Any())
|
if (caseSensitiveMatch.Groups["slovak"].Captures.Cast<Capture>().Any())
|
||||||
{
|
{
|
||||||
languages.Add(Language.Slovak);
|
languages.Add(Language.Slovak);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var matches = LanguageRegex.Matches(title);
|
var matches = LanguageRegex.Matches(title);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace NzbDrone.Core.Parser
|
|||||||
{
|
{
|
||||||
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(Parser));
|
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(Parser));
|
||||||
|
|
||||||
private static readonly Regex EditionRegex = new Regex(@"\(?\b(?<edition>(((Recut.|Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Extended|Despecialized|(Special|Rouge|Final|Assembly|Imperial|Diamond|Signature|Hunter|Rekall)(?=(.(Cut|Edition|Version)))|\d{2,3}(th)?.Anniversary)(?:.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|Open.?Matte|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|Open?.Matte|IMAX|Fan.?Edit|Restored|((2|3|4)in1))))))\b\)?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
private static readonly Regex EditionRegex = new Regex(@"\(?\b(?<edition>(((Recut.|Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Extended|Despecialized|(Special|Rouge|Final|Assembly|Imperial|Diamond|Signature|Hunter|Rekall)(?=(.(Cut|Edition|Version)))|\d{2,3}(th)?.Anniversary)(?:.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit|Restored|((2|3|4)in1))))))\b\)?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
private static readonly Regex ReportEditionRegex = new Regex(@"^.+?" + EditionRegex, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
private static readonly Regex ReportEditionRegex = new Regex(@"^.+?" + EditionRegex, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ namespace NzbDrone.Core.Parser
|
|||||||
private static readonly Regex RealRegex = new Regex(@"\b(?<real>REAL)\b",
|
private static readonly Regex RealRegex = new Regex(@"\b(?<real>REAL)\b",
|
||||||
RegexOptions.Compiled);
|
RegexOptions.Compiled);
|
||||||
|
|
||||||
private static readonly Regex ResolutionRegex = new Regex(@"\b(?:(?<R360p>360p)|(?<R480p>480p|640x480|848x480)|(?<R540p>540p)|(?<R576p>576p)|(?<R720p>720p|1280x720|960p)|(?<R1080p>1080p|1920x1080|1440p|FHD|1080i|4kto1080p)|(?<R2160p>2160p|3840x2160|4k[-_. ](?:UHD|HEVC|BD|H\.?265)|(?:UHD|HEVC|BD|H\.?265)[-_. ]4k))\b",
|
private static readonly Regex ResolutionRegex = new Regex(@"\b(?:(?<R360p>360p)|(?<R480p>480p|640x480|848x480)|(?<R540p>540p)|(?<R576p>576p)|(?<R720p>720p|1280x720|960p)|(?<R1080p>1080p|1920x1080|1440p|FHD|1080i|4kto1080p)|(?<R2160p>2160p|3840x2160|4k[-_. ](?:UHD|HEVC|BD|H265)|(?:UHD|HEVC|BD|H265)[-_. ]4k))\b",
|
||||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
// Handle cases where no resolution is in the release name; assume if UHD then 4k
|
// Handle cases where no resolution is in the release name; assume if UHD then 4k
|
||||||
@@ -75,7 +75,7 @@ namespace NzbDrone.Core.Parser
|
|||||||
|
|
||||||
private static readonly Regex RemuxRegex = new Regex(@"(?:[_. \[]|\d{4}p-)(?<remux>(?:(BD|UHD)[-_. ]?)?Remux)\b|(?<remux>(?:(BD|UHD)[-_. ]?)?Remux[_. ]\d{4}p)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
private static readonly Regex RemuxRegex = new Regex(@"(?:[_. \[]|\d{4}p-)(?<remux>(?:(BD|UHD)[-_. ]?)?Remux)\b|(?<remux>(?:(BD|UHD)[-_. ]?)?Remux[_. ]\d{4}p)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
private static readonly Regex HardcodedSubsRegex = new Regex(@"\b((?<hcsub>(\w+(?<!SOFT|HORRIBLE)SUBS?))|(?<hc>(HC|SUBBED)))\b",
|
private static readonly Regex HardcodedSubsRegex = new Regex(@"\b(?<hcsub>(\w+(?<!(SOFT|HORRIBLE))SUBS?)\b)|(?<hc>(HC|SUBBED))\b",
|
||||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||||
|
|
||||||
public static QualityModel ParseQuality(string name)
|
public static QualityModel ParseQuality(string name)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<PackageReference Include="MailKit" Version="2.15.0" />
|
<PackageReference Include="MailKit" Version="2.15.0" />
|
||||||
<PackageReference Include="Npgsql" Version="6.0.3" />
|
<PackageReference Include="Npgsql" Version="6.0.3" />
|
||||||
<PackageReference Include="Servarr.FFMpegCore" Version="4.7.0-26" />
|
<PackageReference Include="Servarr.FFMpegCore" Version="4.7.0-26" />
|
||||||
<PackageReference Include="Servarr.FFprobe" Version="5.1.2.106" />
|
<PackageReference Include="Servarr.FFprobe" Version="5.0.1.93" />
|
||||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
@@ -18,10 +18,10 @@
|
|||||||
<PackageReference Include="Servarr.FluentMigrator.Runner.Postgres" Version="3.3.2.9" />
|
<PackageReference Include="Servarr.FluentMigrator.Runner.Postgres" Version="3.3.2.9" />
|
||||||
<PackageReference Include="FluentValidation" Version="8.6.2" />
|
<PackageReference Include="FluentValidation" Version="8.6.2" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="NLog" Version="5.0.1" />
|
<PackageReference Include="NLog" Version="5.0.1" />
|
||||||
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
|
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
|
||||||
<PackageReference Include="MonoTorrent" Version="2.0.7" />
|
<PackageReference Include="MonoTorrent" Version="2.0.5" />
|
||||||
<PackageReference Include="System.Text.Json" Version="6.0.5" />
|
<PackageReference Include="System.Text.Json" Version="6.0.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user