mirror of
https://github.com/Sonarr/Sonarr.git
synced 2026-04-18 21:35:27 -04:00
Compare commits
63 Commits
v4.0.11.2784
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 97e85a908d | |||
| 6d91c3b62e | |||
| f30207c3d1 | |||
| 028d2414e7 | |||
| cbd7df2c91 | |||
| 52972e7efc | |||
| 8c50919499 | |||
| fdc07a47b1 | |||
| 36225c3709 | |||
| bc037ae356 | |||
| 77a335de30 | |||
| 88d56361c4 | |||
| d10107739b | |||
| 7db7567c8e | |||
| 2b2b973b30 | |||
| bb954a7424 | |||
| 640e3e5d44 | |||
| 1260d3c800 | |||
| feeed9a7cf | |||
| c8cb74a976 | |||
| 7193acb5ee | |||
| 6f1fc1686f | |||
| b7407837b7 | |||
| 4e65669c48 | |||
| fa38498db0 | |||
| 3b024443c5 | |||
| 4ba9b21bb7 | |||
| e37684e045 | |||
| 103ccd74f3 | |||
| ba22992265 | |||
| 963395b969 | |||
| 970df1a1d8 | |||
| 2ac139ab4d | |||
| c69db1ff92 | |||
| 6dae2f0d84 | |||
| 87934c7761 | |||
| fe8478f42a | |||
| a840bb5423 | |||
| 8f5d628c55 | |||
| acebe87dba | |||
| 7d77500667 | |||
| ec73a13396 | |||
| fa0f77659c | |||
| 1609f0c964 | |||
| 1fea0b3d10 | |||
| 3c8268c428 | |||
| c589c4f85e | |||
| f843107c25 | |||
| 035c474f10 | |||
| 4dcc015fb1 | |||
| 1969e0107f | |||
| ac7c05c050 | |||
| 8aad79fd3e | |||
| f05e552e8e | |||
| 8cd5cd603a | |||
| ef358e6f24 | |||
| fae24e98fb | |||
| c885fb81f9 | |||
| 514c04935f | |||
| 4b14368736 | |||
| 1c30ecd66d | |||
| f7b54f9d6b | |||
| ce7d8a175e |
@@ -22,7 +22,7 @@ env:
|
|||||||
FRAMEWORK: net6.0
|
FRAMEWORK: net6.0
|
||||||
RAW_BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
RAW_BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
SONARR_MAJOR_VERSION: 4
|
SONARR_MAJOR_VERSION: 4
|
||||||
VERSION: 4.0.11
|
VERSION: 4.0.17
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
backend:
|
backend:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# <img width="24px" src="./Logo/256.png" alt="Sonarr"></img> Sonarr
|
# <img width="24px" src="./Logo/256.png" alt="Sonarr"></img> Sonarr
|
||||||
|
|
||||||
[](https://translate.servarr.com/engage/servarr/)
|
[](https://translate.servarr.com/engage/servarr/)
|
||||||
[](#backers)
|
[](#backers)
|
||||||
[](#sponsors)
|
[](#sponsors)
|
||||||
[](#mega-sponsors)
|
[](#mega-sponsors)
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ function HistoryDetails(props: HistoryDetailsProps) {
|
|||||||
indexer,
|
indexer,
|
||||||
releaseGroup,
|
releaseGroup,
|
||||||
seriesMatchType,
|
seriesMatchType,
|
||||||
|
releaseSource,
|
||||||
customFormatScore,
|
customFormatScore,
|
||||||
nzbInfoUrl,
|
nzbInfoUrl,
|
||||||
downloadClient,
|
downloadClient,
|
||||||
@@ -53,6 +54,31 @@ function HistoryDetails(props: HistoryDetailsProps) {
|
|||||||
|
|
||||||
const downloadClientNameInfo = downloadClientName ?? downloadClient;
|
const downloadClientNameInfo = downloadClientName ?? downloadClient;
|
||||||
|
|
||||||
|
let releaseSourceMessage = '';
|
||||||
|
|
||||||
|
switch (releaseSource) {
|
||||||
|
case 'Unknown':
|
||||||
|
releaseSourceMessage = translate('Unknown');
|
||||||
|
break;
|
||||||
|
case 'Rss':
|
||||||
|
releaseSourceMessage = translate('Rss');
|
||||||
|
break;
|
||||||
|
case 'Search':
|
||||||
|
releaseSourceMessage = translate('Search');
|
||||||
|
break;
|
||||||
|
case 'UserInvokedSearch':
|
||||||
|
releaseSourceMessage = translate('UserInvokedSearch');
|
||||||
|
break;
|
||||||
|
case 'InteractiveSearch':
|
||||||
|
releaseSourceMessage = translate('InteractiveSearch');
|
||||||
|
break;
|
||||||
|
case 'ReleasePush':
|
||||||
|
releaseSourceMessage = translate('ReleasePush');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
releaseSourceMessage = '';
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DescriptionList>
|
<DescriptionList>
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
@@ -88,6 +114,14 @@ function HistoryDetails(props: HistoryDetailsProps) {
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
{releaseSource ? (
|
||||||
|
<DescriptionListItem
|
||||||
|
descriptionClassName={styles.description}
|
||||||
|
title={translate('ReleaseSource')}
|
||||||
|
data={releaseSourceMessage}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
{nzbInfoUrl ? (
|
{nzbInfoUrl ? (
|
||||||
<span>
|
<span>
|
||||||
<DescriptionListItemTitle>
|
<DescriptionListItemTitle>
|
||||||
|
|||||||
@@ -258,14 +258,7 @@ function FormInputGroup<T>(props: FormInputGroupProps<T>) {
|
|||||||
{helpLink ? <Link to={helpLink}>{translate('MoreInfo')}</Link> : null}
|
{helpLink ? <Link to={helpLink}>{translate('MoreInfo')}</Link> : null}
|
||||||
|
|
||||||
{errors.map((error, index) => {
|
{errors.map((error, index) => {
|
||||||
return 'message' in error ? (
|
return 'errorMessage' in error ? (
|
||||||
<FormInputHelpText
|
|
||||||
key={index}
|
|
||||||
text={error.message}
|
|
||||||
isError={true}
|
|
||||||
isCheckInput={checkInput}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<FormInputHelpText
|
<FormInputHelpText
|
||||||
key={index}
|
key={index}
|
||||||
text={error.errorMessage}
|
text={error.errorMessage}
|
||||||
@@ -274,23 +267,30 @@ function FormInputGroup<T>(props: FormInputGroupProps<T>) {
|
|||||||
isError={true}
|
isError={true}
|
||||||
isCheckInput={checkInput}
|
isCheckInput={checkInput}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<FormInputHelpText
|
||||||
|
key={index}
|
||||||
|
text={error.message}
|
||||||
|
isError={true}
|
||||||
|
isCheckInput={checkInput}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{warnings.map((warning, index) => {
|
{warnings.map((warning, index) => {
|
||||||
return 'message' in warning ? (
|
return 'errorMessage' in warning ? (
|
||||||
<FormInputHelpText
|
<FormInputHelpText
|
||||||
key={index}
|
key={index}
|
||||||
text={warning.message}
|
text={warning.errorMessage}
|
||||||
|
link={warning.infoLink}
|
||||||
|
tooltip={warning.detailedDescription}
|
||||||
isWarning={true}
|
isWarning={true}
|
||||||
isCheckInput={checkInput}
|
isCheckInput={checkInput}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<FormInputHelpText
|
<FormInputHelpText
|
||||||
key={index}
|
key={index}
|
||||||
text={warning.errorMessage}
|
text={warning.message}
|
||||||
link={warning.infoLink}
|
|
||||||
tooltip={warning.detailedDescription}
|
|
||||||
isWarning={true}
|
isWarning={true}
|
||||||
isCheckInput={checkInput}
|
isCheckInput={checkInput}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import HintedSelectInputOption from './HintedSelectInputOption';
|
|||||||
import HintedSelectInputSelectedValue from './HintedSelectInputSelectedValue';
|
import HintedSelectInputSelectedValue from './HintedSelectInputSelectedValue';
|
||||||
import styles from './EnhancedSelectInput.css';
|
import styles from './EnhancedSelectInput.css';
|
||||||
|
|
||||||
|
const MINIMUM_DISTANCE_FROM_EDGE = 10;
|
||||||
|
|
||||||
function isArrowKey(keyCode: number) {
|
function isArrowKey(keyCode: number) {
|
||||||
return keyCode === keyCodes.UP_ARROW || keyCode === keyCodes.DOWN_ARROW;
|
return keyCode === keyCodes.UP_ARROW || keyCode === keyCodes.DOWN_ARROW;
|
||||||
}
|
}
|
||||||
@@ -189,14 +191,9 @@ function EnhancedSelectInput<T extends EnhancedSelectInputValue<V>, V>(
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const handleComputeMaxHeight = useCallback((data: any) => {
|
const handleComputeMaxHeight = useCallback((data: any) => {
|
||||||
const { top, bottom } = data.offsets.reference;
|
|
||||||
const windowHeight = window.innerHeight;
|
const windowHeight = window.innerHeight;
|
||||||
|
|
||||||
if (/^bottom/.test(data.placement)) {
|
data.styles.maxHeight = windowHeight - MINIMUM_DISTANCE_FROM_EDGE;
|
||||||
data.styles.maxHeight = windowHeight - bottom;
|
|
||||||
} else {
|
|
||||||
data.styles.maxHeight = top;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}, []);
|
}, []);
|
||||||
@@ -508,6 +505,10 @@ function EnhancedSelectInput<T extends EnhancedSelectInputValue<V>, V>(
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
fn: handleComputeMaxHeight,
|
fn: handleComputeMaxHeight,
|
||||||
},
|
},
|
||||||
|
preventOverflow: {
|
||||||
|
enabled: true,
|
||||||
|
boundariesElement: 'viewport',
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ ref, style, scheduleUpdate }) => {
|
{({ ref, style, scheduleUpdate }) => {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
.modal {
|
.modal {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
max-width: 90%;
|
||||||
max-height: 90%;
|
max-height: 90%;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import AppState from 'App/State/AppState';
|
||||||
import Modal from 'Components/Modal/Modal';
|
import Modal from 'Components/Modal/Modal';
|
||||||
import { sizes } from 'Helpers/Props';
|
import { sizes } from 'Helpers/Props';
|
||||||
import { clearPendingChanges } from 'Store/Actions/baseActions';
|
import { clearPendingChanges } from 'Store/Actions/baseActions';
|
||||||
@@ -7,7 +8,8 @@ import EditMetadataModalContent, {
|
|||||||
EditMetadataModalContentProps,
|
EditMetadataModalContentProps,
|
||||||
} from './EditMetadataModalContent';
|
} from './EditMetadataModalContent';
|
||||||
|
|
||||||
interface EditMetadataModalProps extends EditMetadataModalContentProps {
|
interface EditMetadataModalProps
|
||||||
|
extends Omit<EditMetadataModalContentProps, 'advancedSettings'> {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,6 +20,10 @@ function EditMetadataModal({
|
|||||||
}: EditMetadataModalProps) {
|
}: EditMetadataModalProps) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const advancedSettings = useSelector(
|
||||||
|
(state: AppState) => state.settings.advancedSettings
|
||||||
|
);
|
||||||
|
|
||||||
const handleModalClose = useCallback(() => {
|
const handleModalClose = useCallback(() => {
|
||||||
dispatch(clearPendingChanges({ section: 'metadata' }));
|
dispatch(clearPendingChanges({ section: 'metadata' }));
|
||||||
onModalClose();
|
onModalClose();
|
||||||
@@ -27,6 +33,7 @@ function EditMetadataModal({
|
|||||||
<Modal size={sizes.MEDIUM} isOpen={isOpen} onModalClose={handleModalClose}>
|
<Modal size={sizes.MEDIUM} isOpen={isOpen} onModalClose={handleModalClose}>
|
||||||
<EditMetadataModalContent
|
<EditMetadataModalContent
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
|
advancedSettings={advancedSettings}
|
||||||
onModalClose={handleModalClose}
|
onModalClose={handleModalClose}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ function Metadata({ id, name, enable, fields }: MetadataProps) {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<EditMetadataModal
|
<EditMetadataModal
|
||||||
advancedSettings={false}
|
|
||||||
id={id}
|
id={id}
|
||||||
isOpen={isEditMetadataModalOpen}
|
isOpen={isEditMetadataModalOpen}
|
||||||
onModalClose={handleModalClose}
|
onModalClose={handleModalClose}
|
||||||
|
|||||||
@@ -23,12 +23,13 @@ const error = console.error;
|
|||||||
function logError(...parameters: any[]) {
|
function logError(...parameters: any[]) {
|
||||||
const filter = parameters.find((parameter) => {
|
const filter = parameters.find((parameter) => {
|
||||||
return (
|
return (
|
||||||
parameter.includes(
|
typeof parameter === 'string' &&
|
||||||
|
(parameter.includes(
|
||||||
'Support for defaultProps will be removed from function components in a future major release'
|
'Support for defaultProps will be removed from function components in a future major release'
|
||||||
) ||
|
) ||
|
||||||
parameter.includes(
|
parameter.includes(
|
||||||
'findDOMNode is deprecated and will be removed in the next major release'
|
'findDOMNode is deprecated and will be removed in the next major release'
|
||||||
)
|
))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -42,17 +42,18 @@ namespace NzbDrone.Common
|
|||||||
|
|
||||||
public void CreateZip(string path, IEnumerable<string> files)
|
public void CreateZip(string path, IEnumerable<string> files)
|
||||||
{
|
{
|
||||||
using (var zipFile = ZipFile.Create(path))
|
_logger.Debug("Creating archive {0}", path);
|
||||||
|
|
||||||
|
using var zipFile = ZipFile.Create(path);
|
||||||
|
|
||||||
|
zipFile.BeginUpdate();
|
||||||
|
|
||||||
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
zipFile.BeginUpdate();
|
zipFile.Add(file, Path.GetFileName(file));
|
||||||
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
zipFile.Add(file, Path.GetFileName(file));
|
|
||||||
}
|
|
||||||
|
|
||||||
zipFile.CommitUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zipFile.CommitUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExtractZip(string compressedFile, string destination)
|
private void ExtractZip(string compressedFile, string destination)
|
||||||
|
|||||||
@@ -341,10 +341,11 @@ namespace NzbDrone.Common.Disk
|
|||||||
|
|
||||||
var isCifs = targetDriveFormat == "cifs";
|
var isCifs = targetDriveFormat == "cifs";
|
||||||
var isBtrfs = sourceDriveFormat == "btrfs" && targetDriveFormat == "btrfs";
|
var isBtrfs = sourceDriveFormat == "btrfs" && targetDriveFormat == "btrfs";
|
||||||
|
var isZfs = sourceDriveFormat == "zfs" && targetDriveFormat == "zfs";
|
||||||
|
|
||||||
if (mode.HasFlag(TransferMode.Copy))
|
if (mode.HasFlag(TransferMode.Copy))
|
||||||
{
|
{
|
||||||
if (isBtrfs)
|
if (isBtrfs || isZfs)
|
||||||
{
|
{
|
||||||
if (_diskProvider.TryCreateRefLink(sourcePath, targetPath))
|
if (_diskProvider.TryCreateRefLink(sourcePath, targetPath))
|
||||||
{
|
{
|
||||||
@@ -358,7 +359,7 @@ namespace NzbDrone.Common.Disk
|
|||||||
|
|
||||||
if (mode.HasFlag(TransferMode.Move))
|
if (mode.HasFlag(TransferMode.Move))
|
||||||
{
|
{
|
||||||
if (isBtrfs)
|
if (isBtrfs || isZfs)
|
||||||
{
|
{
|
||||||
if (isSameMount && _diskProvider.TryRenameFile(sourcePath, targetPath))
|
if (isSameMount && _diskProvider.TryRenameFile(sourcePath, targetPath))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -390,5 +390,12 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual HttpRequestBuilder AllowRedirect(bool allowAutoRedirect = true)
|
||||||
|
{
|
||||||
|
AllowAutoRedirect = allowAutoRedirect;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry
|
|||||||
o.Environment = BuildInfo.Branch;
|
o.Environment = BuildInfo.Branch;
|
||||||
|
|
||||||
// Crash free run statistics (sends a ping for healthy and for crashes sessions)
|
// Crash free run statistics (sends a ping for healthy and for crashes sessions)
|
||||||
o.AutoSessionTracking = true;
|
o.AutoSessionTracking = false;
|
||||||
|
|
||||||
// Caches files in the event device is offline
|
// Caches files in the event device is offline
|
||||||
// Sentry creates a 'sentry' sub directory, no need to concat here
|
// Sentry creates a 'sentry' sub directory, no need to concat here
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Common;
|
||||||
|
|
||||||
|
public class Utf8StringWriter : StringWriter
|
||||||
|
{
|
||||||
|
public override Encoding Encoding => Encoding.UTF8;
|
||||||
|
}
|
||||||
@@ -168,6 +168,50 @@ namespace NzbDrone.Core.Test.Download.Aggregation.Aggregators
|
|||||||
Mocker.GetMock<IIndexerFactory>().VerifyNoOtherCalls();
|
Mocker.GetMock<IIndexerFactory>().VerifyNoOtherCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_multi_languages_when_release_as_specified_language_and_indexer_has_multi_languages_configuration()
|
||||||
|
{
|
||||||
|
var releaseTitle = "Series.Title.S01E01.MULTi.VFF.VFQ.1080p.BluRay.DTS.HDMA.x264-RlsGroup";
|
||||||
|
var indexerDefinition = new IndexerDefinition
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Settings = new TorrentRssIndexerSettings { MultiLanguages = new List<int> { Language.Original.Id, Language.French.Id } }
|
||||||
|
};
|
||||||
|
Mocker.GetMock<IIndexerFactory>()
|
||||||
|
.Setup(v => v.Find(1))
|
||||||
|
.Returns(indexerDefinition);
|
||||||
|
|
||||||
|
_remoteEpisode.ParsedEpisodeInfo = GetParsedEpisodeInfo(new List<Language> { Language.French }, releaseTitle);
|
||||||
|
_remoteEpisode.Release.IndexerId = 1;
|
||||||
|
_remoteEpisode.Release.Title = releaseTitle;
|
||||||
|
|
||||||
|
Subject.Aggregate(_remoteEpisode).Languages.Should().BeEquivalentTo(new List<Language> { _series.OriginalLanguage, Language.French });
|
||||||
|
Mocker.GetMock<IIndexerFactory>().Verify(c => c.Find(1), Times.Once());
|
||||||
|
Mocker.GetMock<IIndexerFactory>().VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_multi_languages_when_release_as_other_language_and_indexer_has_multi_languages_configuration()
|
||||||
|
{
|
||||||
|
var releaseTitle = "Series.Title.S01E01.MULTi.GERMAN.1080p.BluRay.DTS.HDMA.x264-RlsGroup";
|
||||||
|
var indexerDefinition = new IndexerDefinition
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Settings = new TorrentRssIndexerSettings { MultiLanguages = new List<int> { Language.Original.Id, Language.French.Id } }
|
||||||
|
};
|
||||||
|
Mocker.GetMock<IIndexerFactory>()
|
||||||
|
.Setup(v => v.Find(1))
|
||||||
|
.Returns(indexerDefinition);
|
||||||
|
|
||||||
|
_remoteEpisode.ParsedEpisodeInfo = GetParsedEpisodeInfo(new List<Language> { Language.German }, releaseTitle);
|
||||||
|
_remoteEpisode.Release.IndexerId = 1;
|
||||||
|
_remoteEpisode.Release.Title = releaseTitle;
|
||||||
|
|
||||||
|
Subject.Aggregate(_remoteEpisode).Languages.Should().BeEquivalentTo(new List<Language> { _series.OriginalLanguage, Language.French, Language.German });
|
||||||
|
Mocker.GetMock<IIndexerFactory>().Verify(c => c.Find(1), Times.Once());
|
||||||
|
Mocker.GetMock<IIndexerFactory>().VerifyNoOtherCalls();
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_original_when_indexer_has_no_multi_languages_configuration()
|
public void should_return_original_when_indexer_has_no_multi_languages_configuration()
|
||||||
{
|
{
|
||||||
|
|||||||
+48
@@ -712,6 +712,30 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
|||||||
item.CanMoveFiles.Should().BeTrue();
|
item.CanMoveFiles.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase("pausedUP")]
|
||||||
|
[TestCase("stoppedUP")]
|
||||||
|
public void should_be_removable_and_should_allow_move_files_if_max_ratio_reached_after_rounding_and_paused(string state)
|
||||||
|
{
|
||||||
|
GivenGlobalSeedLimits(1.0f);
|
||||||
|
GivenCompletedTorrent(state, ratio: 1.1006066990976857f);
|
||||||
|
|
||||||
|
var item = Subject.GetItems().Single();
|
||||||
|
item.CanBeRemoved.Should().BeTrue();
|
||||||
|
item.CanMoveFiles.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("pausedUP")]
|
||||||
|
[TestCase("stoppedUP")]
|
||||||
|
public void should_be_removable_and_should_allow_move_files_if_just_under_max_ratio_reached_after_rounding_and_paused(string state)
|
||||||
|
{
|
||||||
|
GivenGlobalSeedLimits(1.0f);
|
||||||
|
GivenCompletedTorrent(state, ratio: 0.9999f);
|
||||||
|
|
||||||
|
var item = Subject.GetItems().Single();
|
||||||
|
item.CanBeRemoved.Should().BeTrue();
|
||||||
|
item.CanMoveFiles.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
[TestCase("pausedUP")]
|
[TestCase("pausedUP")]
|
||||||
[TestCase("stoppedUP")]
|
[TestCase("stoppedUP")]
|
||||||
public void should_be_removable_and_should_allow_move_files_if_overridden_max_ratio_reached_and_paused(string state)
|
public void should_be_removable_and_should_allow_move_files_if_overridden_max_ratio_reached_and_paused(string state)
|
||||||
@@ -724,6 +748,30 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
|
|||||||
item.CanMoveFiles.Should().BeTrue();
|
item.CanMoveFiles.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase("pausedUP")]
|
||||||
|
[TestCase("stoppedUP")]
|
||||||
|
public void should_be_removable_and_should_allow_move_files_if_overridden_max_ratio_reached_after_rounding_and_paused(string state)
|
||||||
|
{
|
||||||
|
GivenGlobalSeedLimits(2.0f);
|
||||||
|
GivenCompletedTorrent(state, ratio: 1.1006066990976857f, ratioLimit: 1.1f);
|
||||||
|
|
||||||
|
var item = Subject.GetItems().Single();
|
||||||
|
item.CanBeRemoved.Should().BeTrue();
|
||||||
|
item.CanMoveFiles.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("pausedUP")]
|
||||||
|
[TestCase("stoppedUP")]
|
||||||
|
public void should_be_removable_and_should_allow_move_files_if_just_under_overridden_max_ratio_reached_after_rounding_and_paused(string state)
|
||||||
|
{
|
||||||
|
GivenGlobalSeedLimits(2.0f);
|
||||||
|
GivenCompletedTorrent(state, ratio: 0.9999f, ratioLimit: 1.0f);
|
||||||
|
|
||||||
|
var item = Subject.GetItems().Single();
|
||||||
|
item.CanBeRemoved.Should().BeTrue();
|
||||||
|
item.CanMoveFiles.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
[TestCase("pausedUP")]
|
[TestCase("pausedUP")]
|
||||||
[TestCase("stoppedUP")]
|
[TestCase("stoppedUP")]
|
||||||
public void should_not_be_removable_if_overridden_max_ratio_not_reached_and_paused(string state)
|
public void should_not_be_removable_if_overridden_max_ratio_not_reached_and_paused(string state)
|
||||||
|
|||||||
@@ -12,46 +12,256 @@ namespace NzbDrone.Core.Test.ImportListTests
|
|||||||
{
|
{
|
||||||
public class ImportListItemServiceFixture : CoreTest<ImportListItemService>
|
public class ImportListItemServiceFixture : CoreTest<ImportListItemService>
|
||||||
{
|
{
|
||||||
[SetUp]
|
private void GivenExisting(List<ImportListItemInfo> existing)
|
||||||
public void SetUp()
|
|
||||||
{
|
{
|
||||||
var existing = Builder<ImportListItemInfo>.CreateListOfSize(3)
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
.TheFirst(1)
|
|
||||||
.With(s => s.TvdbId = 6)
|
|
||||||
.With(s => s.ImdbId = "6")
|
|
||||||
.TheNext(1)
|
|
||||||
.With(s => s.TvdbId = 7)
|
|
||||||
.With(s => s.ImdbId = "7")
|
|
||||||
.TheNext(1)
|
|
||||||
.With(s => s.TvdbId = 8)
|
|
||||||
.With(s => s.ImdbId = "8")
|
|
||||||
.Build().ToList();
|
|
||||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
|
||||||
.Setup(v => v.GetAllForLists(It.IsAny<List<int>>()))
|
.Setup(v => v.GetAllForLists(It.IsAny<List<int>>()))
|
||||||
.Returns(existing);
|
.Returns(existing);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_insert_new_update_existing_and_delete_missing()
|
public void should_insert_new_update_existing_and_delete_missing_based_on_tvdb_id()
|
||||||
{
|
{
|
||||||
var newItems = Builder<ImportListItemInfo>.CreateListOfSize(3)
|
var existing = Builder<ImportListItemInfo>.CreateListOfSize(2)
|
||||||
|
.All()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
.TheFirst(1)
|
.TheFirst(1)
|
||||||
.With(s => s.TvdbId = 5)
|
|
||||||
.TheNext(1)
|
|
||||||
.With(s => s.TvdbId = 6)
|
.With(s => s.TvdbId = 6)
|
||||||
.TheNext(1)
|
.TheNext(1)
|
||||||
.With(s => s.TvdbId = 7)
|
.With(s => s.TvdbId = 7)
|
||||||
.Build().ToList();
|
.Build().ToList();
|
||||||
|
|
||||||
|
var newItem = Builder<ImportListItemInfo>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 5)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var updatedItem = Builder<ImportListItemInfo>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 6)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
GivenExisting(existing);
|
||||||
|
var newItems = new List<ImportListItemInfo> { newItem, updatedItem };
|
||||||
|
|
||||||
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
||||||
|
|
||||||
numDeleted.Should().Be(1);
|
numDeleted.Should().Be(1);
|
||||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
|
||||||
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId == 5)), Times.Once());
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId == newItem.TvdbId)), Times.Once());
|
||||||
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 2 && s[0].TvdbId == 6 && s[1].TvdbId == 7)), Times.Once());
|
|
||||||
Mocker.GetMock<IImportListItemInfoRepository>()
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId == 8)), Times.Once());
|
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId == updatedItem.TvdbId)), Times.Once());
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TvdbId != newItem.TvdbId && s[0].TvdbId != updatedItem.TvdbId)), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_insert_new_update_existing_and_delete_missing_based_on_imdb_id()
|
||||||
|
{
|
||||||
|
var existing = Builder<ImportListItemInfo>.CreateListOfSize(2)
|
||||||
|
.All()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.TheFirst(1)
|
||||||
|
.With(s => s.ImdbId = "6")
|
||||||
|
.TheNext(1)
|
||||||
|
.With(s => s.ImdbId = "7")
|
||||||
|
.Build().ToList();
|
||||||
|
|
||||||
|
var newItem = Builder<ImportListItemInfo>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = "5")
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var updatedItem = Builder<ImportListItemInfo>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = "6")
|
||||||
|
.With(s => s.TmdbId = 6)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
GivenExisting(existing);
|
||||||
|
var newItems = new List<ImportListItemInfo> { newItem, updatedItem };
|
||||||
|
|
||||||
|
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
||||||
|
|
||||||
|
numDeleted.Should().Be(1);
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].ImdbId == newItem.ImdbId)), Times.Once());
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].ImdbId == updatedItem.ImdbId)), Times.Once());
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].ImdbId != newItem.ImdbId && s[0].ImdbId != updatedItem.ImdbId)), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_insert_new_update_existing_and_delete_missing_based_on_tmdb_id()
|
||||||
|
{
|
||||||
|
var existing = Builder<ImportListItemInfo>.CreateListOfSize(2)
|
||||||
|
.All()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.TheFirst(1)
|
||||||
|
.With(s => s.TmdbId = 6)
|
||||||
|
.TheNext(1)
|
||||||
|
.With(s => s.TmdbId = 7)
|
||||||
|
.Build().ToList();
|
||||||
|
|
||||||
|
var newItem = Builder<ImportListItemInfo>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 5)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var updatedItem = Builder<ImportListItemInfo>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 6)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
GivenExisting(existing);
|
||||||
|
var newItems = new List<ImportListItemInfo> { newItem, updatedItem };
|
||||||
|
|
||||||
|
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
||||||
|
|
||||||
|
numDeleted.Should().Be(1);
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TmdbId == newItem.TmdbId)), Times.Once());
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TmdbId == updatedItem.TmdbId)), Times.Once());
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].TmdbId != newItem.TmdbId && s[0].TmdbId != updatedItem.TmdbId)), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_insert_new_update_existing_and_delete_missing_based_on_mal_id()
|
||||||
|
{
|
||||||
|
var existing = Builder<ImportListItemInfo>.CreateListOfSize(2)
|
||||||
|
.All()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.TheFirst(1)
|
||||||
|
.With(s => s.MalId = 6)
|
||||||
|
.TheNext(1)
|
||||||
|
.With(s => s.MalId = 7)
|
||||||
|
.Build().ToList();
|
||||||
|
|
||||||
|
var newItem = Builder<ImportListItemInfo>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 5)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var updatedItem = Builder<ImportListItemInfo>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 6)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
GivenExisting(existing);
|
||||||
|
var newItems = new List<ImportListItemInfo> { newItem, updatedItem };
|
||||||
|
|
||||||
|
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
||||||
|
|
||||||
|
numDeleted.Should().Be(1);
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].MalId == newItem.MalId)), Times.Once());
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].MalId == updatedItem.MalId)), Times.Once());
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].MalId != newItem.MalId && s[0].MalId != updatedItem.MalId)), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_insert_new_update_existing_and_delete_missing_based_on_anilist_id()
|
||||||
|
{
|
||||||
|
var existing = Builder<ImportListItemInfo>.CreateListOfSize(2)
|
||||||
|
.All()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 0)
|
||||||
|
.TheFirst(1)
|
||||||
|
.With(s => s.AniListId = 6)
|
||||||
|
.TheNext(1)
|
||||||
|
.With(s => s.AniListId = 7)
|
||||||
|
.Build().ToList();
|
||||||
|
|
||||||
|
var newItem = Builder<ImportListItemInfo>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 5)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var updatedItem = Builder<ImportListItemInfo>.CreateNew()
|
||||||
|
.With(s => s.TvdbId = 0)
|
||||||
|
.With(s => s.ImdbId = null)
|
||||||
|
.With(s => s.TmdbId = 0)
|
||||||
|
.With(s => s.MalId = 0)
|
||||||
|
.With(s => s.AniListId = 6)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
GivenExisting(existing);
|
||||||
|
var newItems = new List<ImportListItemInfo> { newItem, updatedItem };
|
||||||
|
|
||||||
|
var numDeleted = Subject.SyncSeriesForList(newItems, 1);
|
||||||
|
|
||||||
|
numDeleted.Should().Be(1);
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.InsertMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].AniListId == newItem.AniListId)), Times.Once());
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].AniListId == updatedItem.AniListId)), Times.Once());
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemRepository>()
|
||||||
|
.Verify(v => v.DeleteMany(It.Is<List<ImportListItemInfo>>(s => s.Count == 1 && s[0].AniListId != newItem.AniListId && s[0].AniListId != updatedItem.AniListId)), Times.Once());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,24 +42,45 @@ namespace NzbDrone.Core.Test.ImportListTests
|
|||||||
.TheFirst(1)
|
.TheFirst(1)
|
||||||
.With(s => s.TvdbId = 6)
|
.With(s => s.TvdbId = 6)
|
||||||
.With(s => s.ImdbId = "6")
|
.With(s => s.ImdbId = "6")
|
||||||
|
.With(s => s.TmdbId = 6)
|
||||||
|
.With(s => s.MalIds = new HashSet<int> { 6 })
|
||||||
|
.With(s => s.AniListIds = new HashSet<int> { 6 })
|
||||||
|
.With(s => s.Monitored = true)
|
||||||
.TheNext(1)
|
.TheNext(1)
|
||||||
.With(s => s.TvdbId = 7)
|
.With(s => s.TvdbId = 7)
|
||||||
.With(s => s.ImdbId = "7")
|
.With(s => s.ImdbId = "7")
|
||||||
|
.With(s => s.TmdbId = 7)
|
||||||
|
.With(s => s.MalIds = new HashSet<int> { 7 })
|
||||||
|
.With(s => s.AniListIds = new HashSet<int> { 7 })
|
||||||
|
.With(s => s.Monitored = true)
|
||||||
.TheNext(1)
|
.TheNext(1)
|
||||||
.With(s => s.TvdbId = 8)
|
.With(s => s.TvdbId = 8)
|
||||||
.With(s => s.ImdbId = "8")
|
.With(s => s.ImdbId = "8")
|
||||||
|
.With(s => s.TmdbId = 8)
|
||||||
|
.With(s => s.MalIds = new HashSet<int> { 8 })
|
||||||
|
.With(s => s.AniListIds = new HashSet<int> { 8 })
|
||||||
|
.With(s => s.Monitored = true)
|
||||||
.Build().ToList();
|
.Build().ToList();
|
||||||
|
|
||||||
_list2Series = Builder<ImportListItemInfo>.CreateListOfSize(3)
|
_list2Series = Builder<ImportListItemInfo>.CreateListOfSize(3)
|
||||||
.TheFirst(1)
|
.TheFirst(1)
|
||||||
.With(s => s.TvdbId = 6)
|
.With(s => s.TvdbId = 6)
|
||||||
.With(s => s.ImdbId = "6")
|
.With(s => s.ImdbId = "6")
|
||||||
|
.With(s => s.TmdbId = 6)
|
||||||
|
.With(s => s.MalId = 6)
|
||||||
|
.With(s => s.AniListId = 6)
|
||||||
.TheNext(1)
|
.TheNext(1)
|
||||||
.With(s => s.TvdbId = 7)
|
.With(s => s.TvdbId = 7)
|
||||||
.With(s => s.ImdbId = "7")
|
.With(s => s.ImdbId = "7")
|
||||||
|
.With(s => s.TmdbId = 7)
|
||||||
|
.With(s => s.MalId = 7)
|
||||||
|
.With(s => s.AniListId = 7)
|
||||||
.TheNext(1)
|
.TheNext(1)
|
||||||
.With(s => s.TvdbId = 8)
|
.With(s => s.TvdbId = 8)
|
||||||
.With(s => s.ImdbId = "8")
|
.With(s => s.ImdbId = "8")
|
||||||
|
.With(s => s.TmdbId = 8)
|
||||||
|
.With(s => s.MalId = 8)
|
||||||
|
.With(s => s.AniListId = 8)
|
||||||
.Build().ToList();
|
.Build().ToList();
|
||||||
|
|
||||||
_importListFetch = new ImportListFetchResult(_list1Series, false);
|
_importListFetch = new ImportListFetchResult(_list1Series, false);
|
||||||
@@ -110,6 +131,10 @@ namespace NzbDrone.Core.Test.ImportListTests
|
|||||||
Mocker.GetMock<IImportListExclusionService>()
|
Mocker.GetMock<IImportListExclusionService>()
|
||||||
.Setup(v => v.All())
|
.Setup(v => v.All())
|
||||||
.Returns(new List<ImportListExclusion>());
|
.Returns(new List<ImportListExclusion>());
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemService>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(new List<ImportListItemInfo>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WithTvdbId()
|
private void WithTvdbId()
|
||||||
@@ -153,6 +178,19 @@ namespace NzbDrone.Core.Test.ImportListTests
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ImportListItemInfo> WithImportListItems(int count)
|
||||||
|
{
|
||||||
|
var importListItems = Builder<ImportListItemInfo>.CreateListOfSize(count)
|
||||||
|
.Build()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
Mocker.GetMock<IImportListItemService>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(importListItems);
|
||||||
|
|
||||||
|
return importListItems;
|
||||||
|
}
|
||||||
|
|
||||||
private void WithMonitorType(MonitorTypes monitor)
|
private void WithMonitorType(MonitorTypes monitor)
|
||||||
{
|
{
|
||||||
_importLists.ForEach(li => (li.Definition as ImportListDefinition).ShouldMonitor = monitor);
|
_importLists.ForEach(li => (li.Definition as ImportListDefinition).ShouldMonitor = monitor);
|
||||||
@@ -285,16 +323,18 @@ namespace NzbDrone.Core.Test.ImportListTests
|
|||||||
{
|
{
|
||||||
WithList(1, true);
|
WithList(1, true);
|
||||||
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
|
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
|
||||||
|
var importListItems = WithImportListItems(_existingSeries.Count - 1);
|
||||||
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
|
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
|
||||||
|
|
||||||
Mocker.GetMock<IImportListItemService>()
|
for (var i = 0; i < importListItems.Count; i++)
|
||||||
.Setup(v => v.Exists(6, It.IsAny<string>()))
|
{
|
||||||
.Returns(true);
|
importListItems[i].TvdbId = _existingSeries[i].TvdbId;
|
||||||
|
}
|
||||||
|
|
||||||
Subject.Execute(_commandAll);
|
Subject.Execute(_commandAll);
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count > 0 && s.All(m => !m.Monitored)), true), Times.Once());
|
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count == 1 && s.All(m => !m.Monitored)), true), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -302,18 +342,75 @@ namespace NzbDrone.Core.Test.ImportListTests
|
|||||||
{
|
{
|
||||||
WithList(1, true);
|
WithList(1, true);
|
||||||
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
|
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
|
||||||
|
var importListItems = WithImportListItems(_existingSeries.Count - 1);
|
||||||
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
|
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
|
||||||
|
|
||||||
var x = _importLists;
|
for (var i = 0; i < importListItems.Count; i++)
|
||||||
|
{
|
||||||
Mocker.GetMock<IImportListItemService>()
|
importListItems[i].ImdbId = _existingSeries[i].ImdbId;
|
||||||
.Setup(v => v.Exists(It.IsAny<int>(), "6"))
|
}
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
Subject.Execute(_commandAll);
|
Subject.Execute(_commandAll);
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count > 0 && s.All(m => !m.Monitored)), true), Times.Once());
|
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count == 1 && s.All(m => !m.Monitored)), true), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_clean_on_clean_library_if_tmdb_match()
|
||||||
|
{
|
||||||
|
WithList(1, true);
|
||||||
|
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
|
||||||
|
var importListItems = WithImportListItems(_existingSeries.Count - 1);
|
||||||
|
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
|
||||||
|
|
||||||
|
for (var i = 0; i < importListItems.Count; i++)
|
||||||
|
{
|
||||||
|
importListItems[i].TmdbId = _existingSeries[i].TmdbId;
|
||||||
|
}
|
||||||
|
|
||||||
|
Subject.Execute(_commandAll);
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesService>()
|
||||||
|
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count == 1 && s.All(m => !m.Monitored)), true), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_clean_on_clean_library_if_malid_match()
|
||||||
|
{
|
||||||
|
WithList(1, true);
|
||||||
|
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
|
||||||
|
var importListItems = WithImportListItems(_existingSeries.Count - 1);
|
||||||
|
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
|
||||||
|
|
||||||
|
for (var i = 0; i < importListItems.Count; i++)
|
||||||
|
{
|
||||||
|
importListItems[i].MalId = _existingSeries[i].MalIds.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
Subject.Execute(_commandAll);
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesService>()
|
||||||
|
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count == 1 && s.All(m => !m.Monitored)), true), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_clean_on_clean_library_if_anilistid_match()
|
||||||
|
{
|
||||||
|
WithList(1, true);
|
||||||
|
WithCleanLevel(ListSyncLevelType.KeepAndUnmonitor);
|
||||||
|
var importListItems = WithImportListItems(_existingSeries.Count - 1);
|
||||||
|
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
|
||||||
|
|
||||||
|
for (var i = 0; i < importListItems.Count; i++)
|
||||||
|
{
|
||||||
|
importListItems[i].AniListId = _existingSeries[i].AniListIds.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
Subject.Execute(_commandAll);
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesService>()
|
||||||
|
.Verify(v => v.UpdateSeries(It.Is<List<Series>>(s => s.Count == 1 && s.All(m => !m.Monitored)), true), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -345,6 +442,7 @@ namespace NzbDrone.Core.Test.ImportListTests
|
|||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.IsAny<List<Series>>(), It.IsAny<bool>()), Times.Never());
|
.Verify(v => v.UpdateSeries(It.IsAny<List<Series>>(), It.IsAny<bool>()), Times.Never());
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.DeleteSeries(It.IsAny<List<int>>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Never());
|
.Verify(v => v.DeleteSeries(It.IsAny<List<int>>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Never());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||||||
|
|
||||||
var result = Subject.GetSeedConfiguration(new RemoteEpisode
|
var result = Subject.GetSeedConfiguration(new RemoteEpisode
|
||||||
{
|
{
|
||||||
Release = new ReleaseInfo()
|
Release = new ReleaseInfo
|
||||||
{
|
{
|
||||||
DownloadProtocol = DownloadProtocol.Torrent,
|
DownloadProtocol = DownloadProtocol.Torrent,
|
||||||
IndexerId = 0
|
IndexerId = 0
|
||||||
@@ -32,6 +32,29 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||||||
result.Should().BeNull();
|
result.Should().BeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_return_config_for_invalid_indexer()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<ICachedIndexerSettingsProvider>()
|
||||||
|
.Setup(v => v.GetSettings(It.IsAny<int>()))
|
||||||
|
.Returns<CachedIndexerSettings>(null);
|
||||||
|
|
||||||
|
var result = Subject.GetSeedConfiguration(new RemoteEpisode
|
||||||
|
{
|
||||||
|
Release = new ReleaseInfo
|
||||||
|
{
|
||||||
|
DownloadProtocol = DownloadProtocol.Torrent,
|
||||||
|
IndexerId = 1
|
||||||
|
},
|
||||||
|
ParsedEpisodeInfo = new ParsedEpisodeInfo
|
||||||
|
{
|
||||||
|
FullSeason = true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
result.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_season_time_for_season_packs()
|
public void should_return_season_time_for_season_packs()
|
||||||
{
|
{
|
||||||
@@ -48,7 +71,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||||||
|
|
||||||
var result = Subject.GetSeedConfiguration(new RemoteEpisode
|
var result = Subject.GetSeedConfiguration(new RemoteEpisode
|
||||||
{
|
{
|
||||||
Release = new ReleaseInfo()
|
Release = new ReleaseInfo
|
||||||
{
|
{
|
||||||
DownloadProtocol = DownloadProtocol.Torrent,
|
DownloadProtocol = DownloadProtocol.Torrent,
|
||||||
IndexerId = 1
|
IndexerId = 1
|
||||||
|
|||||||
@@ -213,5 +213,16 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||||||
|
|
||||||
Subject.IsSample(_localEpisode).Should().Be(DetectSampleResult.Sample);
|
Subject.IsSample(_localEpisode).Should().Be(DetectSampleResult.Sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_default_to_45_minutes_if_runtime_is_zero()
|
||||||
|
{
|
||||||
|
GivenRuntime(120);
|
||||||
|
|
||||||
|
_localEpisode.Series.Runtime = 0;
|
||||||
|
_localEpisode.Episodes.First().Runtime = 0;
|
||||||
|
|
||||||
|
Subject.IsSample(_localEpisode).Should().Be(DetectSampleResult.Sample);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,8 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
|
|
||||||
[TestCase("Босх: Спадок (S2E1) / Series: Legacy (S2E1) (2023) WEB-DL 1080p Ukr/Eng | sub Eng", "Босх: Спадок", "Series: Legacy")]
|
[TestCase("Босх: Спадок (S2E1) / Series: Legacy (S2E1) (2023) WEB-DL 1080p Ukr/Eng | sub Eng", "Босх: Спадок", "Series: Legacy")]
|
||||||
[TestCase("Босх: Спадок / Series: Legacy / S2E1-4 of 10 (2023) WEB-DL 1080p Ukr/Eng | sub Eng", "Босх: Спадок", "Series: Legacy")]
|
[TestCase("Босх: Спадок / Series: Legacy / S2E1-4 of 10 (2023) WEB-DL 1080p Ukr/Eng | sub Eng", "Босх: Спадок", "Series: Legacy")]
|
||||||
|
[TestCase("Босх: Спадок AKA Series: Legacy S02 1080p NF WEB-DL Dual- Audio DD+ 5.1 Atmos H.264-APEX", "Босх: Спадок", "Series: Legacy")]
|
||||||
|
[TestCase("Босх.Спадок.AKA.Series.Legacy.S02.1080p.NF.WEB-DL.DUAL.DDP5.1.Atmos.H.264-APEX", "Босх Спадок", "Series Legacy")]
|
||||||
public void should_parse_multiple_series_titles(string postTitle, params string[] titles)
|
public void should_parse_multiple_series_titles(string postTitle, params string[] titles)
|
||||||
{
|
{
|
||||||
var seriesTitleInfo = Parser.Parser.ParseTitle(postTitle).SeriesTitleInfo;
|
var seriesTitleInfo = Parser.Parser.ParseTitle(postTitle).SeriesTitleInfo;
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Series Title / S2E1-16 of 16 [2022, WEB-DL] RUS", "Series Title", 2)]
|
[TestCase("Series Title / S2E1-16 of 16 [2022, WEB-DL] RUS", "Series Title", 2)]
|
||||||
[TestCase("[hchcsen] Mobile Series 00 S01 [BD Remux Dual Audio 1080p AVC 2xFLAC] (Kidou Senshi Gundam 00 Season 1)", "Mobile Series 00", 1)]
|
[TestCase("[hchcsen] Mobile Series 00 S01 [BD Remux Dual Audio 1080p AVC 2xFLAC] (Kidou Senshi Gundam 00 Season 1)", "Mobile Series 00", 1)]
|
||||||
[TestCase("[HorribleRips] Mobile Series 00 S1 [1080p]", "Mobile Series 00", 1)]
|
[TestCase("[HorribleRips] Mobile Series 00 S1 [1080p]", "Mobile Series 00", 1)]
|
||||||
[TestCase("[Zoombie] Zom 100: Bucket List of the Dead S01 [Web][MKV][h265 10-bit][1080p][AC3 2.0][Softsubs (Zoombie)]", "Zom 100: Bucket List of the Dead", 1)]
|
[TestCase("[Zoombie] Series 100: Bucket List S01 [Web][MKV][h265 10-bit][1080p][AC3 2.0][Softsubs (Zoombie)]", "Series 100: Bucket List", 1)]
|
||||||
|
[TestCase("Seriesless (2016/S01/WEB-DL/1080p/AC3 5.1/DUAL/SUB)", "Seriesless (2016)", 1)]
|
||||||
public void should_parse_full_season_release(string postTitle, string title, int season)
|
public void should_parse_full_season_release(string postTitle, string title, int season)
|
||||||
{
|
{
|
||||||
var result = Parser.Parser.ParseTitle(postTitle);
|
var result = Parser.Parser.ParseTitle(postTitle);
|
||||||
|
|||||||
@@ -175,6 +175,8 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Series - Temporada 1 - [HDTV 1080p][Cap.101](wolfmax4k.com)", "Series", 1, 1)]
|
[TestCase("Series - Temporada 1 - [HDTV 1080p][Cap.101](wolfmax4k.com)", "Series", 1, 1)]
|
||||||
[TestCase("Series [HDTV 1080p][Cap.101](wolfmax4k.com)", "Series", 1, 1)]
|
[TestCase("Series [HDTV 1080p][Cap.101](wolfmax4k.com)", "Series", 1, 1)]
|
||||||
[TestCase("Series [HDTV 1080p][Cap. 101](wolfmax4k.com).mkv", "Series", 1, 1)]
|
[TestCase("Series [HDTV 1080p][Cap. 101](wolfmax4k.com).mkv", "Series", 1, 1)]
|
||||||
|
[TestCase("Amazing Title (2024/S01E07/DSNP/WEB-DL/1080p/ESP/EAC3 5.1/ING/EAC3 5.1 Atmos/SUBS) SPWEB", "Amazing Title (2024)", 1, 7)]
|
||||||
|
[TestCase("Mini Title (Miniserie) (2024/S01E07/DSNP/WEB-DL/1080p/ESP/EAC3 5.1/ING/EAC3 5.1 Atmos/SUBS) SPWEB", "Mini Title (2024)", 1, 7)]
|
||||||
|
|
||||||
// [TestCase("", "", 0, 0)]
|
// [TestCase("", "", 0, 0)]
|
||||||
public void should_parse_single_episode(string postTitle, string title, int seasonNumber, int episodeNumber)
|
public void should_parse_single_episode(string postTitle, string title, int seasonNumber, int episodeNumber)
|
||||||
|
|||||||
@@ -66,12 +66,19 @@ namespace NzbDrone.Core.Backup
|
|||||||
{
|
{
|
||||||
_logger.ProgressInfo("Starting Backup");
|
_logger.ProgressInfo("Starting Backup");
|
||||||
|
|
||||||
|
var backupFolder = GetBackupFolder(backupType);
|
||||||
|
|
||||||
_diskProvider.EnsureFolder(_backupTempFolder);
|
_diskProvider.EnsureFolder(_backupTempFolder);
|
||||||
_diskProvider.EnsureFolder(GetBackupFolder(backupType));
|
_diskProvider.EnsureFolder(backupFolder);
|
||||||
|
|
||||||
|
if (!_diskProvider.FolderWritable(backupFolder))
|
||||||
|
{
|
||||||
|
throw new UnauthorizedAccessException($"Backup folder {backupFolder} is not writable");
|
||||||
|
}
|
||||||
|
|
||||||
var dateNow = DateTime.Now;
|
var dateNow = DateTime.Now;
|
||||||
var backupFilename = $"sonarr_backup_v{BuildInfo.Version}_{dateNow:yyyy.MM.dd_HH.mm.ss}.zip";
|
var backupFilename = $"sonarr_backup_v{BuildInfo.Version}_{dateNow:yyyy.MM.dd_HH.mm.ss}.zip";
|
||||||
var backupPath = Path.Combine(GetBackupFolder(backupType), backupFilename);
|
var backupPath = Path.Combine(backupFolder, backupFilename);
|
||||||
|
|
||||||
Cleanup();
|
Cleanup();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(217)]
|
||||||
|
public class add_mal_and_anilist_ids : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Alter.Table("Series").AddColumn("MalIds").AsString().WithDefaultValue("[]");
|
||||||
|
Alter.Table("Series").AddColumn("AniListIds").AsString().WithDefaultValue("[]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -117,6 +117,8 @@ namespace NzbDrone.Core.DecisionEngine
|
|||||||
remoteEpisode.CustomFormats = _formatCalculator.ParseCustomFormat(remoteEpisode, remoteEpisode.Release.Size);
|
remoteEpisode.CustomFormats = _formatCalculator.ParseCustomFormat(remoteEpisode, remoteEpisode.Release.Size);
|
||||||
remoteEpisode.CustomFormatScore = remoteEpisode?.Series?.QualityProfile?.Value.CalculateCustomFormatScore(remoteEpisode.CustomFormats) ?? 0;
|
remoteEpisode.CustomFormatScore = remoteEpisode?.Series?.QualityProfile?.Value.CalculateCustomFormatScore(remoteEpisode.CustomFormats) ?? 0;
|
||||||
|
|
||||||
|
_logger.Trace("Custom Format Score of '{0}' [{1}] calculated for '{2}'", remoteEpisode.CustomFormatScore, remoteEpisode.CustomFormats?.ConcatToString(), report.Title);
|
||||||
|
|
||||||
remoteEpisode.DownloadAllowed = remoteEpisode.Episodes.Any();
|
remoteEpisode.DownloadAllowed = remoteEpisode.Episodes.Any();
|
||||||
decision = GetDecisionForReport(remoteEpisode, searchCriteria);
|
decision = GetDecisionForReport(remoteEpisode, searchCriteria);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -1,3 +1,4 @@
|
|||||||
|
using NLog;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
@@ -6,6 +7,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||||||
{
|
{
|
||||||
public class CustomFormatAllowedbyProfileSpecification : IDownloadDecisionEngineSpecification
|
public class CustomFormatAllowedbyProfileSpecification : IDownloadDecisionEngineSpecification
|
||||||
{
|
{
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public CustomFormatAllowedbyProfileSpecification(Logger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
public SpecificationPriority Priority => SpecificationPriority.Default;
|
public SpecificationPriority Priority => SpecificationPriority.Default;
|
||||||
public RejectionType Type => RejectionType.Permanent;
|
public RejectionType Type => RejectionType.Permanent;
|
||||||
|
|
||||||
@@ -19,6 +27,8 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||||||
return DownloadSpecDecision.Reject(DownloadRejectionReason.CustomFormatMinimumScore, "Custom Formats {0} have score {1} below Series profile minimum {2}", subject.CustomFormats.ConcatToString(), score, minScore);
|
return DownloadSpecDecision.Reject(DownloadRejectionReason.CustomFormatMinimumScore, "Custom Formats {0} have score {1} below Series profile minimum {2}", subject.CustomFormats.ConcatToString(), score, minScore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.Trace("Custom Format Score of {0} [{1}] above Series profile minimum {2}", score, subject.CustomFormats.ConcatToString(), minScore);
|
||||||
|
|
||||||
return DownloadSpecDecision.Accept();
|
return DownloadSpecDecision.Accept();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,10 +41,12 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||||||
|
|
||||||
if (delay == 0)
|
if (delay == 0)
|
||||||
{
|
{
|
||||||
_logger.Debug("QualityProfile does not require a waiting period before download for {0}.", subject.Release.DownloadProtocol);
|
_logger.Debug("Delay Profile does not require a waiting period before download for {0}.", subject.Release.DownloadProtocol);
|
||||||
return DownloadSpecDecision.Accept();
|
return DownloadSpecDecision.Accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.Debug("Delay Profile requires a waiting period of {0} minutes for {1}", delay, subject.Release.DownloadProtocol);
|
||||||
|
|
||||||
var qualityComparer = new QualityModelComparer(qualityProfile);
|
var qualityComparer = new QualityModelComparer(qualityProfile);
|
||||||
|
|
||||||
if (isPreferredProtocol)
|
if (isPreferredProtocol)
|
||||||
@@ -95,6 +97,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||||||
|
|
||||||
if (oldest != null && oldest.Release.AgeMinutes > delay)
|
if (oldest != null && oldest.Release.AgeMinutes > delay)
|
||||||
{
|
{
|
||||||
|
_logger.Debug("Oldest pending release {0} has been delayed for {1}, longer than the set delay of {2}. Release will be accepted", oldest.Release.Title, oldest.Release.AgeMinutes, delay);
|
||||||
return DownloadSpecDecision.Accept();
|
return DownloadSpecDecision.Accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ namespace NzbDrone.Core.Download.Aggregation.Aggregators
|
|||||||
languages = languages.Except(languagesToRemove).ToList();
|
languages = languages.Except(languagesToRemove).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((languages.Count == 0 || (languages.Count == 1 && languages.First() == Language.Unknown)) && releaseInfo?.Title?.IsNotNullOrWhiteSpace() == true)
|
if (releaseInfo?.Title?.IsNotNullOrWhiteSpace() == true)
|
||||||
{
|
{
|
||||||
IndexerDefinition indexer = null;
|
IndexerDefinition indexer = null;
|
||||||
|
|
||||||
@@ -93,7 +93,14 @@ namespace NzbDrone.Core.Download.Aggregation.Aggregators
|
|||||||
if (indexer?.Settings is IIndexerSettings settings && settings.MultiLanguages.Any() && Parser.Parser.HasMultipleLanguages(releaseInfo.Title))
|
if (indexer?.Settings is IIndexerSettings settings && settings.MultiLanguages.Any() && Parser.Parser.HasMultipleLanguages(releaseInfo.Title))
|
||||||
{
|
{
|
||||||
// Use indexer setting for Multi-languages
|
// Use indexer setting for Multi-languages
|
||||||
languages = settings.MultiLanguages.Select(i => (Language)i).ToList();
|
if (languages.Count == 0 || (languages.Count == 1 && languages.First() == Language.Unknown))
|
||||||
|
{
|
||||||
|
languages = settings.MultiLanguages.Select(i => (Language)i).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
languages.AddRange(settings.MultiLanguages.Select(i => (Language)i).Except(languages).ToList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -630,14 +630,14 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
{
|
{
|
||||||
if (torrent.RatioLimit >= 0)
|
if (torrent.RatioLimit >= 0)
|
||||||
{
|
{
|
||||||
if (torrent.Ratio >= torrent.RatioLimit)
|
if (torrent.RatioLimit - torrent.Ratio <= 0.001f)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (torrent.RatioLimit == -2 && config.MaxRatioEnabled)
|
else if (torrent.RatioLimit == -2 && config.MaxRatioEnabled)
|
||||||
{
|
{
|
||||||
if (Math.Round(torrent.Ratio, 2) >= config.MaxRatio)
|
if (config.MaxRatio - torrent.Ratio <= 0.001f)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -425,8 +425,8 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
}
|
}
|
||||||
catch (HttpException ex)
|
catch (HttpException ex)
|
||||||
{
|
{
|
||||||
_logger.Debug("qbitTorrent authentication failed.");
|
_logger.Debug(ex, "qbitTorrent authentication failed.");
|
||||||
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
|
if (ex.Response.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden)
|
||||||
{
|
{
|
||||||
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.", ex);
|
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.", ex);
|
||||||
}
|
}
|
||||||
@@ -438,7 +438,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
throw new DownloadClientUnavailableException("Failed to connect to qBittorrent, please check your settings.", ex);
|
throw new DownloadClientUnavailableException("Failed to connect to qBittorrent, please check your settings.", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.Content != "Ok.")
|
if (response.Content.IsNotNullOrWhiteSpace() && response.Content != "Ok.")
|
||||||
{
|
{
|
||||||
// returns "Fails." on bad login
|
// returns "Fails." on bad login
|
||||||
_logger.Debug("qbitTorrent authentication failed.");
|
_logger.Debug("qbitTorrent authentication failed.");
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Net;
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Cache;
|
using NzbDrone.Common.Cache;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
@@ -261,7 +262,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
|
|||||||
|
|
||||||
private void AuthenticateClient(HttpRequestBuilder requestBuilder, TransmissionSettings settings, bool reauthenticate = false)
|
private void AuthenticateClient(HttpRequestBuilder requestBuilder, TransmissionSettings settings, bool reauthenticate = false)
|
||||||
{
|
{
|
||||||
var authKey = string.Format("{0}:{1}", requestBuilder.BaseUrl, settings.Password);
|
var authKey = $"{requestBuilder.BaseUrl}:{settings.Password}";
|
||||||
|
|
||||||
var sessionId = _authSessionIdCache.Find(authKey);
|
var sessionId = _authSessionIdCache.Find(authKey);
|
||||||
|
|
||||||
@@ -273,24 +274,26 @@ namespace NzbDrone.Core.Download.Clients.Transmission
|
|||||||
authLoginRequest.SuppressHttpError = true;
|
authLoginRequest.SuppressHttpError = true;
|
||||||
|
|
||||||
var response = _httpClient.Execute(authLoginRequest);
|
var response = _httpClient.Execute(authLoginRequest);
|
||||||
if (response.StatusCode == HttpStatusCode.MovedPermanently)
|
|
||||||
{
|
|
||||||
var url = response.Headers.GetSingleValue("Location");
|
|
||||||
|
|
||||||
throw new DownloadClientException("Remote site redirected to " + url);
|
switch (response.StatusCode)
|
||||||
}
|
|
||||||
else if (response.StatusCode == HttpStatusCode.Conflict)
|
|
||||||
{
|
{
|
||||||
sessionId = response.Headers.GetSingleValue("X-Transmission-Session-Id");
|
case HttpStatusCode.MovedPermanently:
|
||||||
|
var url = response.Headers.GetSingleValue("Location");
|
||||||
|
|
||||||
if (sessionId == null)
|
throw new DownloadClientException("Remote site redirected to " + url);
|
||||||
{
|
case HttpStatusCode.Forbidden:
|
||||||
throw new DownloadClientException("Remote host did not return a Session Id.");
|
throw new DownloadClientException($"Failed to authenticate with Transmission. It may be necessary to add {BuildInfo.AppName}'s IP address to RPC whitelist.");
|
||||||
}
|
case HttpStatusCode.Conflict:
|
||||||
}
|
sessionId = response.Headers.GetSingleValue("X-Transmission-Session-Id");
|
||||||
else
|
|
||||||
{
|
if (sessionId == null)
|
||||||
throw new DownloadClientAuthenticationException("Failed to authenticate with Transmission.");
|
{
|
||||||
|
throw new DownloadClientException("Remote host did not return a Session Id.");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new DownloadClientAuthenticationException("Failed to authenticate with Transmission.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug("Transmission authentication succeeded.");
|
_logger.Debug("Transmission authentication succeeded.");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
using NzbDrone.Core.Download.TrackedDownloads;
|
using NzbDrone.Core.Download.TrackedDownloads;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||||
@@ -14,15 +14,17 @@ public interface IRejectedImportService
|
|||||||
public class RejectedImportService : IRejectedImportService
|
public class RejectedImportService : IRejectedImportService
|
||||||
{
|
{
|
||||||
private readonly ICachedIndexerSettingsProvider _cachedIndexerSettingsProvider;
|
private readonly ICachedIndexerSettingsProvider _cachedIndexerSettingsProvider;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public RejectedImportService(ICachedIndexerSettingsProvider cachedIndexerSettingsProvider)
|
public RejectedImportService(ICachedIndexerSettingsProvider cachedIndexerSettingsProvider, Logger logger)
|
||||||
{
|
{
|
||||||
_cachedIndexerSettingsProvider = cachedIndexerSettingsProvider;
|
_cachedIndexerSettingsProvider = cachedIndexerSettingsProvider;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Process(TrackedDownload trackedDownload, ImportResult importResult)
|
public bool Process(TrackedDownload trackedDownload, ImportResult importResult)
|
||||||
{
|
{
|
||||||
if (importResult.Result != ImportResultType.Rejected || importResult.ImportDecision.LocalEpisode != null)
|
if (importResult.Result != ImportResultType.Rejected || trackedDownload.RemoteEpisode?.Release == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -30,19 +32,27 @@ public class RejectedImportService : IRejectedImportService
|
|||||||
var indexerSettings = _cachedIndexerSettingsProvider.GetSettings(trackedDownload.RemoteEpisode.Release.IndexerId);
|
var indexerSettings = _cachedIndexerSettingsProvider.GetSettings(trackedDownload.RemoteEpisode.Release.IndexerId);
|
||||||
var rejectionReason = importResult.ImportDecision.Rejections.FirstOrDefault()?.Reason;
|
var rejectionReason = importResult.ImportDecision.Rejections.FirstOrDefault()?.Reason;
|
||||||
|
|
||||||
|
if (indexerSettings == null)
|
||||||
|
{
|
||||||
|
trackedDownload.Warn(new TrackedDownloadStatusMessage(trackedDownload.DownloadItem.Title, importResult.Errors));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (rejectionReason == ImportRejectionReason.DangerousFile &&
|
if (rejectionReason == ImportRejectionReason.DangerousFile &&
|
||||||
indexerSettings.FailDownloads.Contains(FailDownloads.PotentiallyDangerous))
|
indexerSettings.FailDownloads.Contains(FailDownloads.PotentiallyDangerous))
|
||||||
{
|
{
|
||||||
|
_logger.Trace("Download '{0}' contains potentially dangerous file, marking as failed", trackedDownload.DownloadItem.Title);
|
||||||
trackedDownload.Fail();
|
trackedDownload.Fail();
|
||||||
}
|
}
|
||||||
else if (rejectionReason == ImportRejectionReason.ExecutableFile &&
|
else if (rejectionReason == ImportRejectionReason.ExecutableFile &&
|
||||||
indexerSettings.FailDownloads.Contains(FailDownloads.Executables))
|
indexerSettings.FailDownloads.Contains(FailDownloads.Executables))
|
||||||
{
|
{
|
||||||
|
_logger.Trace("Download '{0}' contains executable file, marking as failed", trackedDownload.DownloadItem.Title);
|
||||||
trackedDownload.Fail();
|
trackedDownload.Fail();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trackedDownload.Warn(new TrackedDownloadStatusMessage(importResult.Errors.First(), new List<string>()));
|
trackedDownload.Warn(new TrackedDownloadStatusMessage(trackedDownload.DownloadItem.Title, importResult.Errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
|||||||
{
|
{
|
||||||
Status = TrackedDownloadStatus.Error;
|
Status = TrackedDownloadStatus.Error;
|
||||||
State = TrackedDownloadState.FailedPending;
|
State = TrackedDownloadState.FailedPending;
|
||||||
|
|
||||||
|
// Set CanBeRemoved to allow the failed item to be removed from the client
|
||||||
|
DownloadItem.CanBeRemoved = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Plex
|
|||||||
|
|
||||||
if (episodeFile.SeasonNumber == 0)
|
if (episodeFile.SeasonNumber == 0)
|
||||||
{
|
{
|
||||||
episodeFormat = $"SP{episodesInFile.First():00}";
|
episodeFormat = $"SP{episodesInFile.First().EpisodeNumber:00}";
|
||||||
}
|
}
|
||||||
|
|
||||||
content.AppendLine($"Episode: {episodeFormat}: {episodeFile.RelativePath}");
|
content.AppendLine($"Episode: {episodeFormat}: {episodeFile.RelativePath}");
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System.Text.RegularExpressions;
|
|||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
@@ -149,110 +150,116 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
|||||||
if (Settings.SeriesMetadata)
|
if (Settings.SeriesMetadata)
|
||||||
{
|
{
|
||||||
_logger.Debug("Generating Series Metadata for: {0}", series.Title);
|
_logger.Debug("Generating Series Metadata for: {0}", series.Title);
|
||||||
var sb = new StringBuilder();
|
|
||||||
var xws = new XmlWriterSettings();
|
|
||||||
xws.OmitXmlDeclaration = true;
|
|
||||||
xws.Indent = false;
|
|
||||||
|
|
||||||
using (var xw = XmlWriter.Create(sb, xws))
|
var tvShow = new XElement("tvshow");
|
||||||
|
|
||||||
|
tvShow.Add(new XElement("title", series.Title));
|
||||||
|
|
||||||
|
if (series.Ratings != null && series.Ratings.Votes > 0)
|
||||||
{
|
{
|
||||||
var tvShow = new XElement("tvshow");
|
tvShow.Add(new XElement("rating", series.Ratings.Value));
|
||||||
|
|
||||||
tvShow.Add(new XElement("title", series.Title));
|
|
||||||
|
|
||||||
if (series.Ratings != null && series.Ratings.Votes > 0)
|
|
||||||
{
|
|
||||||
tvShow.Add(new XElement("rating", series.Ratings.Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
tvShow.Add(new XElement("plot", series.Overview));
|
|
||||||
tvShow.Add(new XElement("mpaa", series.Certification));
|
|
||||||
tvShow.Add(new XElement("id", series.TvdbId));
|
|
||||||
|
|
||||||
var uniqueId = new XElement("uniqueid", series.TvdbId);
|
|
||||||
uniqueId.SetAttributeValue("type", "tvdb");
|
|
||||||
uniqueId.SetAttributeValue("default", true);
|
|
||||||
tvShow.Add(uniqueId);
|
|
||||||
|
|
||||||
if (series.ImdbId.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
var imdbId = new XElement("uniqueid", series.ImdbId);
|
|
||||||
imdbId.SetAttributeValue("type", "imdb");
|
|
||||||
tvShow.Add(imdbId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (series.TmdbId > 0)
|
|
||||||
{
|
|
||||||
var tmdbId = new XElement("uniqueid", series.TmdbId);
|
|
||||||
tmdbId.SetAttributeValue("type", "tmdb");
|
|
||||||
tvShow.Add(tmdbId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (series.TvMazeId > 0)
|
|
||||||
{
|
|
||||||
var tvMazeId = new XElement("uniqueid", series.TvMazeId);
|
|
||||||
tvMazeId.SetAttributeValue("type", "tvmaze");
|
|
||||||
tvShow.Add(tvMazeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var genre in series.Genres)
|
|
||||||
{
|
|
||||||
tvShow.Add(new XElement("genre", genre));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (series.Tags.Any())
|
|
||||||
{
|
|
||||||
var tags = _tagRepo.GetTags(series.Tags);
|
|
||||||
|
|
||||||
foreach (var tag in tags)
|
|
||||||
{
|
|
||||||
tvShow.Add(new XElement("tag", tag.Label));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tvShow.Add(new XElement("status", series.Status));
|
|
||||||
|
|
||||||
if (series.FirstAired.HasValue)
|
|
||||||
{
|
|
||||||
tvShow.Add(new XElement("premiered", series.FirstAired.Value.ToString("yyyy-MM-dd")));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add support for Jellyfin's "enddate" tag
|
|
||||||
if (series.Status == SeriesStatusType.Ended && series.LastAired.HasValue)
|
|
||||||
{
|
|
||||||
tvShow.Add(new XElement("enddate", series.LastAired.Value.ToString("yyyy-MM-dd")));
|
|
||||||
}
|
|
||||||
|
|
||||||
tvShow.Add(new XElement("studio", series.Network));
|
|
||||||
|
|
||||||
foreach (var actor in series.Actors)
|
|
||||||
{
|
|
||||||
var xmlActor = new XElement("actor",
|
|
||||||
new XElement("name", actor.Name),
|
|
||||||
new XElement("role", actor.Character));
|
|
||||||
|
|
||||||
if (actor.Images.Any())
|
|
||||||
{
|
|
||||||
xmlActor.Add(new XElement("thumb", actor.Images.First().RemoteUrl));
|
|
||||||
}
|
|
||||||
|
|
||||||
tvShow.Add(xmlActor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Settings.SeriesMetadataEpisodeGuide)
|
|
||||||
{
|
|
||||||
var episodeGuide = new KodiEpisodeGuide(series);
|
|
||||||
var serializerSettings = STJson.GetSerializerSettings();
|
|
||||||
serializerSettings.WriteIndented = false;
|
|
||||||
|
|
||||||
tvShow.Add(new XElement("episodeguide", JsonSerializer.Serialize(episodeGuide, serializerSettings)));
|
|
||||||
}
|
|
||||||
|
|
||||||
var doc = new XDocument(tvShow);
|
|
||||||
doc.Save(xw);
|
|
||||||
|
|
||||||
xmlResult += doc.ToString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tvShow.Add(new XElement("plot", series.Overview));
|
||||||
|
tvShow.Add(new XElement("mpaa", series.Certification));
|
||||||
|
tvShow.Add(new XElement("id", series.TvdbId));
|
||||||
|
|
||||||
|
var uniqueId = new XElement("uniqueid", series.TvdbId);
|
||||||
|
uniqueId.SetAttributeValue("type", "tvdb");
|
||||||
|
uniqueId.SetAttributeValue("default", true);
|
||||||
|
tvShow.Add(uniqueId);
|
||||||
|
|
||||||
|
if (series.ImdbId.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
var imdbId = new XElement("uniqueid", series.ImdbId);
|
||||||
|
imdbId.SetAttributeValue("type", "imdb");
|
||||||
|
tvShow.Add(imdbId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (series.TmdbId > 0)
|
||||||
|
{
|
||||||
|
var tmdbId = new XElement("uniqueid", series.TmdbId);
|
||||||
|
tmdbId.SetAttributeValue("type", "tmdb");
|
||||||
|
tvShow.Add(tmdbId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (series.TvMazeId > 0)
|
||||||
|
{
|
||||||
|
var tvMazeId = new XElement("uniqueid", series.TvMazeId);
|
||||||
|
tvMazeId.SetAttributeValue("type", "tvmaze");
|
||||||
|
tvShow.Add(tvMazeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var genre in series.Genres)
|
||||||
|
{
|
||||||
|
tvShow.Add(new XElement("genre", genre));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (series.Tags.Any())
|
||||||
|
{
|
||||||
|
var tags = _tagRepo.GetTags(series.Tags);
|
||||||
|
|
||||||
|
foreach (var tag in tags)
|
||||||
|
{
|
||||||
|
tvShow.Add(new XElement("tag", tag.Label));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tvShow.Add(new XElement("status", series.Status));
|
||||||
|
|
||||||
|
if (series.FirstAired.HasValue)
|
||||||
|
{
|
||||||
|
tvShow.Add(new XElement("premiered", series.FirstAired.Value.ToString("yyyy-MM-dd")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add support for Jellyfin's "enddate" tag
|
||||||
|
if (series.Status == SeriesStatusType.Ended && series.LastAired.HasValue)
|
||||||
|
{
|
||||||
|
tvShow.Add(new XElement("enddate", series.LastAired.Value.ToString("yyyy-MM-dd")));
|
||||||
|
}
|
||||||
|
|
||||||
|
tvShow.Add(new XElement("studio", series.Network));
|
||||||
|
|
||||||
|
foreach (var actor in series.Actors)
|
||||||
|
{
|
||||||
|
var xmlActor = new XElement("actor",
|
||||||
|
new XElement("name", actor.Name),
|
||||||
|
new XElement("role", actor.Character));
|
||||||
|
|
||||||
|
if (actor.Images.Any())
|
||||||
|
{
|
||||||
|
xmlActor.Add(new XElement("thumb", actor.Images.First().RemoteUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
tvShow.Add(xmlActor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings.SeriesMetadataEpisodeGuide)
|
||||||
|
{
|
||||||
|
var episodeGuide = new KodiEpisodeGuide(series);
|
||||||
|
var serializerSettings = STJson.GetSerializerSettings();
|
||||||
|
serializerSettings.WriteIndented = false;
|
||||||
|
|
||||||
|
tvShow.Add(new XElement("episodeguide", JsonSerializer.Serialize(episodeGuide, serializerSettings)));
|
||||||
|
}
|
||||||
|
|
||||||
|
var doc = new XDocument(tvShow)
|
||||||
|
{
|
||||||
|
Declaration = new XDeclaration("1.0", "UTF-8", "yes"),
|
||||||
|
};
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
using var sw = new Utf8StringWriter();
|
||||||
|
using var xw = XmlWriter.Create(sw, new XmlWriterSettings
|
||||||
|
{
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
Indent = true
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.Save(xw);
|
||||||
|
xw.Flush();
|
||||||
|
|
||||||
|
xmlResult += sw.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.SeriesMetadataUrl)
|
if (Settings.SeriesMetadataUrl)
|
||||||
@@ -279,116 +286,117 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
|||||||
|
|
||||||
var watched = GetExistingWatchedStatus(series, episodeFile.RelativePath);
|
var watched = GetExistingWatchedStatus(series, episodeFile.RelativePath);
|
||||||
|
|
||||||
var xmlResult = string.Empty;
|
var xws = new XmlWriterSettings
|
||||||
|
{
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
Indent = true,
|
||||||
|
ConformanceLevel = ConformanceLevel.Fragment
|
||||||
|
};
|
||||||
|
|
||||||
|
using var sw = new Utf8StringWriter();
|
||||||
|
using var xw = XmlWriter.Create(sw, xws);
|
||||||
|
|
||||||
|
xw.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"");
|
||||||
|
|
||||||
foreach (var episode in episodeFile.Episodes.Value)
|
foreach (var episode in episodeFile.Episodes.Value)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var image = episode.Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
|
||||||
var xws = new XmlWriterSettings();
|
|
||||||
xws.OmitXmlDeclaration = true;
|
|
||||||
xws.Indent = false;
|
|
||||||
|
|
||||||
using (var xw = XmlWriter.Create(sb, xws))
|
var details = new XElement("episodedetails");
|
||||||
|
details.Add(new XElement("title", episode.Title));
|
||||||
|
details.Add(new XElement("season", episode.SeasonNumber));
|
||||||
|
details.Add(new XElement("episode", episode.EpisodeNumber));
|
||||||
|
details.Add(new XElement("aired", episode.AirDate));
|
||||||
|
details.Add(new XElement("plot", episode.Overview));
|
||||||
|
|
||||||
|
if (episode.SeasonNumber == 0 && episode.AiredAfterSeasonNumber.HasValue)
|
||||||
{
|
{
|
||||||
var doc = new XDocument();
|
details.Add(new XElement("displayafterseason", episode.AiredAfterSeasonNumber));
|
||||||
var image = episode.Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
|
|
||||||
|
|
||||||
var details = new XElement("episodedetails");
|
|
||||||
details.Add(new XElement("title", episode.Title));
|
|
||||||
details.Add(new XElement("season", episode.SeasonNumber));
|
|
||||||
details.Add(new XElement("episode", episode.EpisodeNumber));
|
|
||||||
details.Add(new XElement("aired", episode.AirDate));
|
|
||||||
details.Add(new XElement("plot", episode.Overview));
|
|
||||||
|
|
||||||
if (episode.SeasonNumber == 0 && episode.AiredAfterSeasonNumber.HasValue)
|
|
||||||
{
|
|
||||||
details.Add(new XElement("displayafterseason", episode.AiredAfterSeasonNumber));
|
|
||||||
}
|
|
||||||
else if (episode.SeasonNumber == 0 && episode.AiredBeforeSeasonNumber.HasValue)
|
|
||||||
{
|
|
||||||
details.Add(new XElement("displayseason", episode.AiredBeforeSeasonNumber));
|
|
||||||
details.Add(new XElement("displayepisode", episode.AiredBeforeEpisodeNumber ?? -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
var tvdbId = new XElement("uniqueid", episode.TvdbId);
|
|
||||||
tvdbId.SetAttributeValue("type", "tvdb");
|
|
||||||
tvdbId.SetAttributeValue("default", true);
|
|
||||||
details.Add(tvdbId);
|
|
||||||
|
|
||||||
var sonarrId = new XElement("uniqueid", episode.Id);
|
|
||||||
sonarrId.SetAttributeValue("type", "sonarr");
|
|
||||||
details.Add(sonarrId);
|
|
||||||
|
|
||||||
if (image == null)
|
|
||||||
{
|
|
||||||
details.Add(new XElement("thumb"));
|
|
||||||
}
|
|
||||||
else if (Settings.EpisodeImageThumb)
|
|
||||||
{
|
|
||||||
details.Add(new XElement("thumb", image.RemoteUrl));
|
|
||||||
}
|
|
||||||
|
|
||||||
details.Add(new XElement("watched", watched));
|
|
||||||
|
|
||||||
if (episode.Ratings != null && episode.Ratings.Votes > 0)
|
|
||||||
{
|
|
||||||
details.Add(new XElement("rating", episode.Ratings.Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (episodeFile.MediaInfo != null)
|
|
||||||
{
|
|
||||||
var sceneName = episodeFile.GetSceneOrFileName();
|
|
||||||
|
|
||||||
var fileInfo = new XElement("fileinfo");
|
|
||||||
var streamDetails = new XElement("streamdetails");
|
|
||||||
|
|
||||||
var video = new XElement("video");
|
|
||||||
video.Add(new XElement("aspect", (float)episodeFile.MediaInfo.Width / (float)episodeFile.MediaInfo.Height));
|
|
||||||
video.Add(new XElement("bitrate", episodeFile.MediaInfo.VideoBitrate));
|
|
||||||
video.Add(new XElement("codec", MediaInfoFormatter.FormatVideoCodec(episodeFile.MediaInfo, sceneName)));
|
|
||||||
video.Add(new XElement("framerate", episodeFile.MediaInfo.VideoFps));
|
|
||||||
video.Add(new XElement("height", episodeFile.MediaInfo.Height));
|
|
||||||
video.Add(new XElement("scantype", episodeFile.MediaInfo.ScanType));
|
|
||||||
video.Add(new XElement("width", episodeFile.MediaInfo.Width));
|
|
||||||
|
|
||||||
video.Add(new XElement("duration", episodeFile.MediaInfo.RunTime.TotalMinutes));
|
|
||||||
video.Add(new XElement("durationinseconds", Math.Round(episodeFile.MediaInfo.RunTime.TotalSeconds)));
|
|
||||||
|
|
||||||
streamDetails.Add(video);
|
|
||||||
|
|
||||||
var audio = new XElement("audio");
|
|
||||||
var audioChannelCount = episodeFile.MediaInfo.AudioChannels;
|
|
||||||
audio.Add(new XElement("bitrate", episodeFile.MediaInfo.AudioBitrate));
|
|
||||||
audio.Add(new XElement("channels", audioChannelCount));
|
|
||||||
audio.Add(new XElement("codec", MediaInfoFormatter.FormatAudioCodec(episodeFile.MediaInfo, sceneName)));
|
|
||||||
audio.Add(new XElement("language", episodeFile.MediaInfo.AudioLanguages));
|
|
||||||
streamDetails.Add(audio);
|
|
||||||
|
|
||||||
if (episodeFile.MediaInfo.Subtitles != null && episodeFile.MediaInfo.Subtitles.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var s in episodeFile.MediaInfo.Subtitles)
|
|
||||||
{
|
|
||||||
var subtitle = new XElement("subtitle");
|
|
||||||
subtitle.Add(new XElement("language", s));
|
|
||||||
streamDetails.Add(subtitle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileInfo.Add(streamDetails);
|
|
||||||
details.Add(fileInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Todo: get guest stars, writer and director
|
|
||||||
// details.Add(new XElement("credits", tvdbEpisode.Writer.FirstOrDefault()));
|
|
||||||
// details.Add(new XElement("director", tvdbEpisode.Directors.FirstOrDefault()));
|
|
||||||
|
|
||||||
doc.Add(details);
|
|
||||||
doc.Save(xw);
|
|
||||||
|
|
||||||
xmlResult += doc.ToString();
|
|
||||||
xmlResult += Environment.NewLine;
|
|
||||||
}
|
}
|
||||||
|
else if (episode.SeasonNumber == 0 && episode.AiredBeforeSeasonNumber.HasValue)
|
||||||
|
{
|
||||||
|
details.Add(new XElement("displayseason", episode.AiredBeforeSeasonNumber));
|
||||||
|
details.Add(new XElement("displayepisode", episode.AiredBeforeEpisodeNumber ?? -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
var tvdbId = new XElement("uniqueid", episode.TvdbId);
|
||||||
|
tvdbId.SetAttributeValue("type", "tvdb");
|
||||||
|
tvdbId.SetAttributeValue("default", true);
|
||||||
|
details.Add(tvdbId);
|
||||||
|
|
||||||
|
var sonarrId = new XElement("uniqueid", episode.Id);
|
||||||
|
sonarrId.SetAttributeValue("type", "sonarr");
|
||||||
|
details.Add(sonarrId);
|
||||||
|
|
||||||
|
if (image == null)
|
||||||
|
{
|
||||||
|
details.Add(new XElement("thumb"));
|
||||||
|
}
|
||||||
|
else if (Settings.EpisodeImageThumb)
|
||||||
|
{
|
||||||
|
details.Add(new XElement("thumb", image.RemoteUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
details.Add(new XElement("watched", watched));
|
||||||
|
|
||||||
|
if (episode.Ratings != null && episode.Ratings.Votes > 0)
|
||||||
|
{
|
||||||
|
details.Add(new XElement("rating", episode.Ratings.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (episodeFile.MediaInfo != null)
|
||||||
|
{
|
||||||
|
var sceneName = episodeFile.GetSceneOrFileName();
|
||||||
|
|
||||||
|
var fileInfo = new XElement("fileinfo");
|
||||||
|
var streamDetails = new XElement("streamdetails");
|
||||||
|
|
||||||
|
var video = new XElement("video");
|
||||||
|
video.Add(new XElement("aspect", (float)episodeFile.MediaInfo.Width / (float)episodeFile.MediaInfo.Height));
|
||||||
|
video.Add(new XElement("bitrate", episodeFile.MediaInfo.VideoBitrate));
|
||||||
|
video.Add(new XElement("codec", MediaInfoFormatter.FormatVideoCodec(episodeFile.MediaInfo, sceneName)));
|
||||||
|
video.Add(new XElement("framerate", episodeFile.MediaInfo.VideoFps));
|
||||||
|
video.Add(new XElement("height", episodeFile.MediaInfo.Height));
|
||||||
|
video.Add(new XElement("scantype", episodeFile.MediaInfo.ScanType));
|
||||||
|
video.Add(new XElement("width", episodeFile.MediaInfo.Width));
|
||||||
|
|
||||||
|
video.Add(new XElement("duration", episodeFile.MediaInfo.RunTime.TotalMinutes));
|
||||||
|
video.Add(new XElement("durationinseconds", Math.Round(episodeFile.MediaInfo.RunTime.TotalSeconds)));
|
||||||
|
|
||||||
|
streamDetails.Add(video);
|
||||||
|
|
||||||
|
var audio = new XElement("audio");
|
||||||
|
var audioChannelCount = episodeFile.MediaInfo.AudioChannels;
|
||||||
|
audio.Add(new XElement("bitrate", episodeFile.MediaInfo.AudioBitrate));
|
||||||
|
audio.Add(new XElement("channels", audioChannelCount));
|
||||||
|
audio.Add(new XElement("codec", MediaInfoFormatter.FormatAudioCodec(episodeFile.MediaInfo, sceneName)));
|
||||||
|
audio.Add(new XElement("language", episodeFile.MediaInfo.AudioLanguages));
|
||||||
|
streamDetails.Add(audio);
|
||||||
|
|
||||||
|
if (episodeFile.MediaInfo.Subtitles != null && episodeFile.MediaInfo.Subtitles.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var s in episodeFile.MediaInfo.Subtitles)
|
||||||
|
{
|
||||||
|
var subtitle = new XElement("subtitle");
|
||||||
|
subtitle.Add(new XElement("language", s));
|
||||||
|
streamDetails.Add(subtitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfo.Add(streamDetails);
|
||||||
|
details.Add(fileInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Todo: get guest stars, writer and director
|
||||||
|
// details.Add(new XElement("credits", tvdbEpisode.Writer.FirstOrDefault()));
|
||||||
|
// details.Add(new XElement("director", tvdbEpisode.Directors.FirstOrDefault()));
|
||||||
|
|
||||||
|
details.WriteTo(xw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xw.Flush();
|
||||||
|
var xmlResult = sw.ToString();
|
||||||
|
|
||||||
return new MetadataFileResult(GetEpisodeMetadataFilename(episodeFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
return new MetadataFileResult(GetEpisodeMetadataFilename(episodeFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ namespace NzbDrone.Core.ImportLists.Custom
|
|||||||
}
|
}
|
||||||
|
|
||||||
var baseUrl = settings.BaseUrl.TrimEnd('/');
|
var baseUrl = settings.BaseUrl.TrimEnd('/');
|
||||||
var request = new HttpRequestBuilder(baseUrl).Accept(HttpAccept.Json).Build();
|
var request = new HttpRequestBuilder(baseUrl).Accept(HttpAccept.Json).AllowRedirect().Build();
|
||||||
var response = _httpClient.Get(request);
|
var response = _httpClient.Get(request);
|
||||||
var results = JsonConvert.DeserializeObject<List<TResource>>(response.Content);
|
var results = JsonConvert.DeserializeObject<List<TResource>>(response.Content);
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
namespace NzbDrone.Core.ImportLists.ImportListItems
|
namespace NzbDrone.Core.ImportLists.ImportListItems
|
||||||
{
|
{
|
||||||
public interface IImportListItemInfoRepository : IBasicRepository<ImportListItemInfo>
|
public interface IImportListItemRepository : IBasicRepository<ImportListItemInfo>
|
||||||
{
|
{
|
||||||
List<ImportListItemInfo> GetAllForLists(List<int> listIds);
|
List<ImportListItemInfo> GetAllForLists(List<int> listIds);
|
||||||
bool Exists(int tvdbId, string imdbId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImportListItemRepository : BasicRepository<ImportListItemInfo>, IImportListItemInfoRepository
|
public class ImportListItemRepository : BasicRepository<ImportListItemInfo>, IImportListItemRepository
|
||||||
{
|
{
|
||||||
public ImportListItemRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
public ImportListItemRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
||||||
: base(database, eventAggregator)
|
: base(database, eventAggregator)
|
||||||
@@ -23,21 +21,5 @@ namespace NzbDrone.Core.ImportLists.ImportListItems
|
|||||||
{
|
{
|
||||||
return Query(x => listIds.Contains(x.ImportListId));
|
return Query(x => listIds.Contains(x.ImportListId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Exists(int tvdbId, string imdbId)
|
|
||||||
{
|
|
||||||
List<ImportListItemInfo> items;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(imdbId))
|
|
||||||
{
|
|
||||||
items = Query(x => x.TvdbId == tvdbId);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
items = Query(x => x.TvdbId == tvdbId || x.ImdbId == imdbId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return items.Any();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NLog;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.ThingiProvider.Events;
|
using NzbDrone.Core.ThingiProvider.Events;
|
||||||
@@ -9,51 +9,105 @@ namespace NzbDrone.Core.ImportLists.ImportListItems
|
|||||||
{
|
{
|
||||||
public interface IImportListItemService
|
public interface IImportListItemService
|
||||||
{
|
{
|
||||||
|
List<ImportListItemInfo> All();
|
||||||
List<ImportListItemInfo> GetAllForLists(List<int> listIds);
|
List<ImportListItemInfo> GetAllForLists(List<int> listIds);
|
||||||
int SyncSeriesForList(List<ImportListItemInfo> listSeries, int listId);
|
int SyncSeriesForList(List<ImportListItemInfo> listSeries, int listId);
|
||||||
bool Exists(int tvdbId, string imdbId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImportListItemService : IImportListItemService, IHandleAsync<ProviderDeletedEvent<IImportList>>
|
public class ImportListItemService : IImportListItemService, IHandleAsync<ProviderDeletedEvent<IImportList>>
|
||||||
{
|
{
|
||||||
private readonly IImportListItemInfoRepository _importListSeriesRepository;
|
private readonly IImportListItemRepository _importListItemRepository;
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
public ImportListItemService(IImportListItemInfoRepository importListSeriesRepository,
|
public ImportListItemService(IImportListItemRepository importListItemRepository)
|
||||||
Logger logger)
|
|
||||||
{
|
{
|
||||||
_importListSeriesRepository = importListSeriesRepository;
|
_importListItemRepository = importListItemRepository;
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int SyncSeriesForList(List<ImportListItemInfo> listSeries, int listId)
|
public int SyncSeriesForList(List<ImportListItemInfo> listSeries, int listId)
|
||||||
{
|
{
|
||||||
var existingListSeries = GetAllForLists(new List<int> { listId });
|
var existingListSeries = GetAllForLists(new List<int> { listId });
|
||||||
|
|
||||||
listSeries.ForEach(l => l.Id = existingListSeries.FirstOrDefault(e => e.TvdbId == l.TvdbId)?.Id ?? 0);
|
var toAdd = new List<ImportListItemInfo>();
|
||||||
|
var toUpdate = new List<ImportListItemInfo>();
|
||||||
|
|
||||||
_importListSeriesRepository.InsertMany(listSeries.Where(l => l.Id == 0).ToList());
|
listSeries.ForEach(item =>
|
||||||
_importListSeriesRepository.UpdateMany(listSeries.Where(l => l.Id > 0).ToList());
|
{
|
||||||
var toDelete = existingListSeries.Where(l => !listSeries.Any(x => x.TvdbId == l.TvdbId)).ToList();
|
var existingItem = FindItem(existingListSeries, item);
|
||||||
_importListSeriesRepository.DeleteMany(toDelete);
|
|
||||||
|
|
||||||
return toDelete.Count;
|
if (existingItem == null)
|
||||||
|
{
|
||||||
|
toAdd.Add(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove so we'll only be left with items to remove at the end
|
||||||
|
existingListSeries.Remove(existingItem);
|
||||||
|
toUpdate.Add(existingItem);
|
||||||
|
|
||||||
|
existingItem.Title = item.Title;
|
||||||
|
existingItem.Year = item.Year;
|
||||||
|
existingItem.TvdbId = item.TvdbId;
|
||||||
|
existingItem.ImdbId = item.ImdbId;
|
||||||
|
existingItem.TmdbId = item.TmdbId;
|
||||||
|
existingItem.MalId = item.MalId;
|
||||||
|
existingItem.AniListId = item.AniListId;
|
||||||
|
existingItem.ReleaseDate = item.ReleaseDate;
|
||||||
|
});
|
||||||
|
|
||||||
|
_importListItemRepository.InsertMany(toAdd);
|
||||||
|
_importListItemRepository.UpdateMany(toUpdate);
|
||||||
|
_importListItemRepository.DeleteMany(existingListSeries);
|
||||||
|
|
||||||
|
return existingListSeries.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ImportListItemInfo> All()
|
||||||
|
{
|
||||||
|
return _importListItemRepository.All().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ImportListItemInfo> GetAllForLists(List<int> listIds)
|
public List<ImportListItemInfo> GetAllForLists(List<int> listIds)
|
||||||
{
|
{
|
||||||
return _importListSeriesRepository.GetAllForLists(listIds).ToList();
|
return _importListItemRepository.GetAllForLists(listIds).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleAsync(ProviderDeletedEvent<IImportList> message)
|
public void HandleAsync(ProviderDeletedEvent<IImportList> message)
|
||||||
{
|
{
|
||||||
var seriesOnList = _importListSeriesRepository.GetAllForLists(new List<int> { message.ProviderId });
|
var seriesOnList = _importListItemRepository.GetAllForLists(new List<int> { message.ProviderId });
|
||||||
_importListSeriesRepository.DeleteMany(seriesOnList);
|
_importListItemRepository.DeleteMany(seriesOnList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Exists(int tvdbId, string imdbId)
|
private ImportListItemInfo FindItem(List<ImportListItemInfo> existingItems, ImportListItemInfo item)
|
||||||
{
|
{
|
||||||
return _importListSeriesRepository.Exists(tvdbId, imdbId);
|
return existingItems.FirstOrDefault(e =>
|
||||||
|
{
|
||||||
|
if (e.TvdbId > 0 && item.TvdbId > 0 && e.TvdbId == item.TvdbId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.ImdbId.IsNotNullOrWhiteSpace() && item.ImdbId.IsNotNullOrWhiteSpace() && e.ImdbId == item.ImdbId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.TmdbId > 0 && item.TmdbId > 0 && e.TmdbId == item.TmdbId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.MalId > 0 && item.MalId > 0 && e.MalId == item.MalId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.AniListId > 0 && item.AniListId > 0 && e.AniListId == item.AniListId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -299,12 +299,18 @@ namespace NzbDrone.Core.ImportLists
|
|||||||
|
|
||||||
var seriesToUpdate = new List<Series>();
|
var seriesToUpdate = new List<Series>();
|
||||||
var seriesInLibrary = _seriesService.GetAllSeries();
|
var seriesInLibrary = _seriesService.GetAllSeries();
|
||||||
|
var allListItems = _importListItemService.All();
|
||||||
|
|
||||||
foreach (var series in seriesInLibrary)
|
foreach (var series in seriesInLibrary)
|
||||||
{
|
{
|
||||||
var seriesExists = _importListItemService.Exists(series.TvdbId, series.ImdbId);
|
var seriesExists = allListItems.Where(l =>
|
||||||
|
l.TvdbId == series.TvdbId ||
|
||||||
|
(l.ImdbId.IsNotNullOrWhiteSpace() && series.ImdbId.IsNotNullOrWhiteSpace() && l.ImdbId == series.ImdbId) ||
|
||||||
|
l.TmdbId == series.TmdbId ||
|
||||||
|
series.MalIds.Contains(l.MalId) ||
|
||||||
|
series.AniListIds.Contains(l.AniListId)).ToList();
|
||||||
|
|
||||||
if (!seriesExists)
|
if (!seriesExists.Any())
|
||||||
{
|
{
|
||||||
switch (_configService.ListSyncLevel)
|
switch (_configService.ListSyncLevel)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.Json.Serialization;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace NzbDrone.Core.ImportLists.Trakt
|
namespace NzbDrone.Core.ImportLists.Trakt
|
||||||
{
|
{
|
||||||
@@ -17,7 +17,7 @@ namespace NzbDrone.Core.ImportLists.Trakt
|
|||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public int? Year { get; set; }
|
public int? Year { get; set; }
|
||||||
public TraktSeriesIdsResource Ids { get; set; }
|
public TraktSeriesIdsResource Ids { get; set; }
|
||||||
[JsonPropertyName("aired_episodes")]
|
[JsonProperty("aired_episodes")]
|
||||||
public int AiredEpisodes { get; set; }
|
public int AiredEpisodes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,11 +44,11 @@ namespace NzbDrone.Core.ImportLists.Trakt
|
|||||||
|
|
||||||
public class RefreshRequestResponse
|
public class RefreshRequestResponse
|
||||||
{
|
{
|
||||||
[JsonPropertyName("access_token")]
|
[JsonProperty("access_token")]
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
[JsonPropertyName("expires_in")]
|
[JsonProperty("expires_in")]
|
||||||
public int ExpiresIn { get; set; }
|
public int ExpiresIn { get; set; }
|
||||||
[JsonPropertyName("refresh_token")]
|
[JsonProperty("refresh_token")]
|
||||||
public string RefreshToken { get; set; }
|
public string RefreshToken { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -367,7 +367,9 @@ namespace NzbDrone.Core.IndexerSearch
|
|||||||
|
|
||||||
// build list of queries for each episode in the form: "<series> <episode-title>"
|
// build list of queries for each episode in the form: "<series> <episode-title>"
|
||||||
searchSpec.EpisodeQueryTitles = episodes.Where(e => !string.IsNullOrWhiteSpace(e.Title))
|
searchSpec.EpisodeQueryTitles = episodes.Where(e => !string.IsNullOrWhiteSpace(e.Title))
|
||||||
|
.Where(e => interactiveSearch || !monitoredOnly || e.Monitored)
|
||||||
.SelectMany(e => searchSpec.CleanSceneTitles.Select(title => title + " " + SearchCriteriaBase.GetCleanSceneTitle(e.Title)))
|
.SelectMany(e => searchSpec.CleanSceneTitles.Select(title => title + " " + SearchCriteriaBase.GetCleanSceneTitle(e.Title)))
|
||||||
|
.Distinct(StringComparer.InvariantCultureIgnoreCase)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
downloadDecisions.AddRange(await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec));
|
downloadDecisions.AddRange(await Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec));
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
using NzbDrone.Common.Cache;
|
using NzbDrone.Common.Cache;
|
||||||
|
using NzbDrone.Common.Instrumentation;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.ThingiProvider.Events;
|
using NzbDrone.Core.ThingiProvider.Events;
|
||||||
|
|
||||||
@@ -12,8 +14,10 @@ public interface ICachedIndexerSettingsProvider
|
|||||||
CachedIndexerSettings GetSettings(int indexerId);
|
CachedIndexerSettings GetSettings(int indexerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CachedIndexerSettingsProvider : ICachedIndexerSettingsProvider, IHandle<ProviderUpdatedEvent<IIndexer>>
|
public class CachedIndexerSettingsProvider : ICachedIndexerSettingsProvider, IHandle<ProviderUpdatedEvent<IIndexer>>, IHandle<ProviderDeletedEvent<IIndexer>>
|
||||||
{
|
{
|
||||||
|
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(CachedIndexerSettingsProvider));
|
||||||
|
|
||||||
private readonly IIndexerFactory _indexerFactory;
|
private readonly IIndexerFactory _indexerFactory;
|
||||||
private readonly ICached<CachedIndexerSettings> _cache;
|
private readonly ICached<CachedIndexerSettings> _cache;
|
||||||
|
|
||||||
@@ -35,11 +39,12 @@ public class CachedIndexerSettingsProvider : ICachedIndexerSettingsProvider, IHa
|
|||||||
|
|
||||||
private CachedIndexerSettings FetchIndexerSettings(int indexerId)
|
private CachedIndexerSettings FetchIndexerSettings(int indexerId)
|
||||||
{
|
{
|
||||||
var indexer = _indexerFactory.Get(indexerId);
|
var indexer = _indexerFactory.Find(indexerId);
|
||||||
var indexerSettings = indexer.Settings as IIndexerSettings;
|
|
||||||
|
|
||||||
if (indexerSettings == null)
|
if (indexer?.Settings is not IIndexerSettings indexerSettings)
|
||||||
{
|
{
|
||||||
|
Logger.Trace("Could not load settings for indexer ID: {0}", indexerId);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +65,11 @@ public class CachedIndexerSettingsProvider : ICachedIndexerSettingsProvider, IHa
|
|||||||
{
|
{
|
||||||
_cache.Clear();
|
_cache.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Handle(ProviderDeletedEvent<IIndexer> message)
|
||||||
|
{
|
||||||
|
_cache.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CachedIndexerSettings
|
public class CachedIndexerSettings
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
|||||||
searchCriteria,
|
searchCriteria,
|
||||||
$"&season={NewznabifySeasonNumber(searchCriteria.SeasonNumber)}");
|
$"&season={NewznabifySeasonNumber(searchCriteria.SeasonNumber)}");
|
||||||
|
|
||||||
var queryTitles = TextSearchEngine == "raw" ? searchCriteria.SceneTitles : searchCriteria.CleanSceneTitles;
|
var queryTitles = TextSearchEngine == "raw" ? searchCriteria.AllSceneTitles : searchCriteria.CleanSceneTitles;
|
||||||
|
|
||||||
foreach (var queryTitle in queryTitles)
|
foreach (var queryTitle in queryTitles)
|
||||||
{
|
{
|
||||||
@@ -582,7 +582,7 @@ namespace NzbDrone.Core.Indexers.Newznab
|
|||||||
}
|
}
|
||||||
else if (SupportsTvQuerySearch)
|
else if (SupportsTvQuerySearch)
|
||||||
{
|
{
|
||||||
var queryTitles = TvTextSearchEngine == "raw" ? searchCriteria.SceneTitles : searchCriteria.CleanSceneTitles;
|
var queryTitles = TvTextSearchEngine == "raw" ? searchCriteria.AllSceneTitles : searchCriteria.CleanSceneTitles;
|
||||||
foreach (var queryTitle in queryTitles)
|
foreach (var queryTitle in queryTitles)
|
||||||
{
|
{
|
||||||
chain.Add(GetPagedRequests(MaxPages,
|
chain.Add(GetPagedRequests(MaxPages,
|
||||||
|
|||||||
@@ -1 +1,143 @@
|
|||||||
{}
|
{
|
||||||
|
"AddedDate": "Добавен: {date}",
|
||||||
|
"AddANewPath": "Добави нов път",
|
||||||
|
"AddCustomFilter": "Добави персонализиран филтър",
|
||||||
|
"AddDownloadClientImplementation": "Добави клиент за изтегляне - {implementationName}",
|
||||||
|
"AddExclusion": "Добави изключение",
|
||||||
|
"AddImportList": "Добави списък за импортиране",
|
||||||
|
"AddIndexer": "Добавете индексатор",
|
||||||
|
"AirsTomorrowOn": "Утре от {time} по {networkLabel}",
|
||||||
|
"AddedToDownloadQueue": "Добавен към опашката за изтегляне",
|
||||||
|
"AfterManualRefresh": "След ръчно опресняване",
|
||||||
|
"AirsDateAtTimeOn": "{date} в {time} по {networkLabel}",
|
||||||
|
"AirsTbaOn": "TBA по {networkLabel}",
|
||||||
|
"AirsTimeOn": "{time} по {networkLabel}",
|
||||||
|
"AllFiles": "Всички файлове",
|
||||||
|
"AlternateTitles": "Алтернативни заглавия",
|
||||||
|
"Any": "Всякакви",
|
||||||
|
"AddConditionImplementation": "Добави условие - {implementationName}",
|
||||||
|
"AddConnectionImplementation": "Добави връзка - {implementationName}",
|
||||||
|
"AddListExclusion": "Добавете изключение от списъка",
|
||||||
|
"AddImportListExclusion": "Добави изключение от списъка за импортиране",
|
||||||
|
"AddImportListExclusionError": "Не може да се добави ново изключение от списъка за импортиране, моля, опитайте отново.",
|
||||||
|
"AddListExclusionSeriesHelpText": "Предотвратете добавянето на сериали в {appName} чрез списъци",
|
||||||
|
"AnimeEpisodeTypeFormat": "Абсолютен номер на епизода ({format})",
|
||||||
|
"AddRootFolderError": "Не може да се добави основна папка, моля, опитайте отново",
|
||||||
|
"AnimeEpisodeTypeDescription": "Епизоди, издадени с абсолютен номер на епизод",
|
||||||
|
"AnalyseVideoFilesHelpText": "Извлича видео информация, като резолюция, продължителност и информация за кодека от файловете. Това изисква {appName} да прочете части от файла, което може да предизвика висока дискова или мрежова активност по време на сканирането.",
|
||||||
|
"AnalyticsEnabledHelpText": "Изпращайте анонимна информация за използването и грешките към сървърите на {appName}. Това включва информация за вашия браузър, кои страници на уеб интерфейса на {appName} използвате, докладваните грешки, както и версията на операционната система и изпълнителната среда. Ще използваме тази информация, за да приоритизираме нови функции и поправки на бъгове.",
|
||||||
|
"Anime": "Аниме",
|
||||||
|
"AddIndexerError": "Не може да се добави нов индексатор, моля, опитайте отново.",
|
||||||
|
"AddIndexerImplementation": "Добавете индексатор - {implementationName}",
|
||||||
|
"AddDelayProfileError": "Не може да се добави нов профил за забавяне, моля, опитайте отново.",
|
||||||
|
"AddNotificationError": "Не може да се добави ново известие, моля, опитайте отново.",
|
||||||
|
"AddImportListImplementation": "Добави списък за импортиране - {implementationName}",
|
||||||
|
"AddList": "Добавете списък",
|
||||||
|
"AddNewSeriesSearchForMissingEpisodes": "Започнете търсене на липсващи епизоди",
|
||||||
|
"AddRemotePathMapping": "Добавете мапиране към отдалечен път",
|
||||||
|
"AddRemotePathMappingError": "Не може да се добави ново мапиране към отдалечен път, моля, опитайте отново.",
|
||||||
|
"AddToDownloadQueue": "Добавете към опашката за изтегляне",
|
||||||
|
"AlreadyInYourLibrary": "Вече е във вашата библиотека",
|
||||||
|
"AnEpisodeIsDownloading": "Изтегля се епизод",
|
||||||
|
"AnimeEpisodeFormat": "Формат на Аниме епизодите",
|
||||||
|
"ApiKey": "API ключ",
|
||||||
|
"Added": "Добавен",
|
||||||
|
"ApiKeyValidationHealthCheckMessage": "Моля, актуализирайте вашия API ключ, за да бъде с дължина най-малко {length} знака. Може да направите това чрез настройките или конфигурационния файл",
|
||||||
|
"AddConditionError": "Не може да се добави новo условие, моля, опитайте отново.",
|
||||||
|
"AddAutoTagError": "Не може да се добави нов автоматичен таг, моля, опитайте отново.",
|
||||||
|
"AddConnection": "Добави връзка",
|
||||||
|
"AddCustomFormat": "Добавете персонализиран формат",
|
||||||
|
"AddCustomFormatError": "Не може да се добави нов персонализиран формат, моля, опитайте отново.",
|
||||||
|
"AddDelayProfile": "Добавете профил за забавяне",
|
||||||
|
"AddDownloadClient": "Добави клиент за изтегляне",
|
||||||
|
"AddDownloadClientError": "Не може да се добави нов клиент за изтегляне, моля, опитайте отново.",
|
||||||
|
"AddListExclusionError": "Не може да се добави ново изключение от списъка, моля, опитайте отново.",
|
||||||
|
"AddNewRestriction": "Добавете новo ограничение",
|
||||||
|
"AddListError": "Не може да се добави нов списък, моля, опитайте отново.",
|
||||||
|
"AddQualityProfile": "Добавете профил за качество",
|
||||||
|
"AddQualityProfileError": "Не може да се добави нов профил за качество, моля, опитайте отново.",
|
||||||
|
"AddReleaseProfile": "Добавете профил за издания",
|
||||||
|
"Always": "Винаги",
|
||||||
|
"AnalyseVideoFiles": "Анализирайте видео файловете",
|
||||||
|
"Analytics": "Анализ",
|
||||||
|
"AgeWhenGrabbed": "Възраст (при грабване)",
|
||||||
|
"AddAutoTag": "Добави автоматичен таг",
|
||||||
|
"AddCondition": "Добави условие",
|
||||||
|
"AirDate": "Ефирна дата",
|
||||||
|
"AllTitles": "Всички заглавия",
|
||||||
|
"AddRootFolder": "Добавете основна папка",
|
||||||
|
"Add": "Добавяне",
|
||||||
|
"AddingTag": "Добавяне на таг",
|
||||||
|
"Age": "Възраст",
|
||||||
|
"All": "Всички",
|
||||||
|
"Activity": "Дейност",
|
||||||
|
"AddNew": "Добавете нов",
|
||||||
|
"Actions": "Действия",
|
||||||
|
"About": "Относно",
|
||||||
|
"Agenda": "Агенда",
|
||||||
|
"AddNewSeries": "Добавете нов сериал",
|
||||||
|
"AddNewSeriesError": "Неуспешно зареждане на резултатите от търсенето, моля, опитайте отново.",
|
||||||
|
"AddNewSeriesHelpText": "Лесно е да добавите нов сериал, просто започнете да въвеждате името на сериала, който искате да добавите.",
|
||||||
|
"AddNewSeriesRootFolderHelpText": "Подпапката '{folder}' ще бъде създадена автоматично",
|
||||||
|
"AddNewSeriesSearchForCutoffUnmetEpisodes": "Започни търсене на епизоди, които не са достигнали максималното качество за надграждане",
|
||||||
|
"AddSeriesWithTitle": "Добавете {title}",
|
||||||
|
"Absolute": "Абсолютен",
|
||||||
|
"AllSeriesAreHiddenByTheAppliedFilter": "Всички резултати са скрити от приложения филтър",
|
||||||
|
"AllSeriesInRootFolderHaveBeenImported": "Всички сериали в {path} са импортирани",
|
||||||
|
"AbsoluteEpisodeNumber": "Абсолютен епизоден номер",
|
||||||
|
"AllResultsAreHiddenByTheAppliedFilter": "Всички резултати са скрити от приложения филтър",
|
||||||
|
"AppDataDirectory": "Директория на приложението",
|
||||||
|
"SeasonFolder": "Папка ( Сезони )",
|
||||||
|
"SeasonDetails": "Детайли за сезона",
|
||||||
|
"SeasonCount": "Брой сезони",
|
||||||
|
"SslPort": "SSL порт",
|
||||||
|
"AppDataLocationHealthCheckMessage": "Актуализирането няма да бъде възможно, за да се предотврати изтриването на папката на приложението по време на актуализацията",
|
||||||
|
"AppUpdated": "{appName} Актуализиран",
|
||||||
|
"ApplyTagsHelpTextReplace": "Замяна: Заменете таговете с въведените тагове (не въвеждайте тагове, за да изчистите всички тагове)",
|
||||||
|
"AudioLanguages": "Аудио езици",
|
||||||
|
"AuthBasic": "Основно (изскачащ прозорец на браузъра)",
|
||||||
|
"AuthForm": "Формуляри (Страница за вход)",
|
||||||
|
"AuthenticationMethodHelpText": "Изисквайте потребителско име и парола за достъп до {appName}",
|
||||||
|
"AuthenticationRequiredPasswordHelpTextWarning": "Въведете нова парола",
|
||||||
|
"ApplicationURL": "URL адрес на приложението",
|
||||||
|
"AuthenticationMethodHelpTextWarning": "Моля, изберете валиден метод за удостоверяване",
|
||||||
|
"AuthenticationRequiredUsernameHelpTextWarning": "Въведете ново потребителско име",
|
||||||
|
"AuthenticationRequiredWarning": "За да предотврати отдалечен достъп без удостоверяване, {appName} вече изисква удостоверяването да бъде активирано. По желание можете да деактивирате удостоверяването от локални адреси.",
|
||||||
|
"SeriesFolderFormat": "Формат на папката ( Сериали )",
|
||||||
|
"ApplyChanges": "Прилагане на промените",
|
||||||
|
"AutoTaggingLoadError": "Не може да се зареди автоматичното маркиране",
|
||||||
|
"SeasonFinale": "Финал на сезона",
|
||||||
|
"AppUpdatedVersion": "{appName} е актуализиран до версия `{version}`, за да получите най-новите промени, ще трябва да презаредите {appName} ",
|
||||||
|
"ApplicationUrlHelpText": "Външният URL на това приложение, включително http(s)://, порт и базов URL",
|
||||||
|
"AutoTagging": "Автоматично маркиране",
|
||||||
|
"Apply": "Приложете",
|
||||||
|
"ApplyTags": "Прилагане на тагове",
|
||||||
|
"AutoAdd": "Автоматично добавяне",
|
||||||
|
"ApplyTagsHelpTextHowToApplyImportLists": "Как да добавите тагове към избраните списъци за импортиране",
|
||||||
|
"ApplyTagsHelpTextHowToApplySeries": "Как да добавите тагове към избраните сериали",
|
||||||
|
"SeasonFolderFormat": "Формат на папката ( Сезони )",
|
||||||
|
"AudioInfo": "Аудио информация",
|
||||||
|
"Season": "Сезон",
|
||||||
|
"ApplyTagsHelpTextAdd": "Добавяне: Добавете маркерите към съществуващия списък с маркери",
|
||||||
|
"ApplyTagsHelpTextRemove": "Премахване: Премахнете въведените тагове",
|
||||||
|
"RenameEpisodesHelpText": "{appName} ще използва съществуващото име на файла, ако преименуването е деактивирано",
|
||||||
|
"ApplyTagsHelpTextHowToApplyDownloadClients": "Как да приложите тагове към избраните приложения за сваляне",
|
||||||
|
"Authentication": "Удостоверяване",
|
||||||
|
"AuthenticationRequiredHelpText": "Променете за кои заявки се изисква удостоверяване. Не променяйте, освен ако не разбирате рисковете.",
|
||||||
|
"AutoRedownloadFailed": "Неуспешно повторно изтегляне",
|
||||||
|
"AutoRedownloadFailedFromInteractiveSearchHelpText": "Автоматично търсене и опит за изтегляне на различна версия, когато неуспешната версия е била взета от интерактивно търсене",
|
||||||
|
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Потвърдете новата парола",
|
||||||
|
"AutoTaggingNegateHelpText": "Ако е отметнато, правилото за автоматично маркиране няма да се приложи, ако това условие {implementationName} съвпада.",
|
||||||
|
"AutoRedownloadFailedFromInteractiveSearch": "Неуспешно повторно изтегляне от интерактивното търсене",
|
||||||
|
"AutoRedownloadFailedHelpText": "Автоматично търсене и опит за сваляне на различна версия",
|
||||||
|
"AptUpdater": "Използвайте apt, за да инсталирате актуализацията",
|
||||||
|
"ApplyTagsHelpTextHowToApplyIndexers": "Как да добавите тагове към избраните индексатори",
|
||||||
|
"AuthenticationMethod": "Метод за удостоверяване",
|
||||||
|
"AuthenticationRequired": "Изисква се удостоверяване",
|
||||||
|
"RenameEpisodes": "Преименуване на епизоди",
|
||||||
|
"Standard": "Стандартен",
|
||||||
|
"StandardEpisodeFormat": "Формат на епизода ( Стандартен )",
|
||||||
|
"SslCertPathHelpText": "Път до \"pfx\" файл",
|
||||||
|
"EpisodeNaming": "Именуване на епизоди",
|
||||||
|
"Close": "Затвори"
|
||||||
|
}
|
||||||
|
|||||||
@@ -750,5 +750,13 @@
|
|||||||
"Organize": "Organitza",
|
"Organize": "Organitza",
|
||||||
"Search": "Cerca",
|
"Search": "Cerca",
|
||||||
"SelectDropdown": "Seleccioneu...",
|
"SelectDropdown": "Seleccioneu...",
|
||||||
"Shutdown": "Apaga"
|
"Shutdown": "Apaga",
|
||||||
|
"ClickToChangeReleaseType": "Feu clic per canviar el tipus de llançament",
|
||||||
|
"BlocklistFilterHasNoItems": "El filtre de la llista de bloqueig seleccionat no conté elements",
|
||||||
|
"CustomColonReplacement": "Reemplaçament personalitzat de dos punts",
|
||||||
|
"CountVotes": "{votes} vots",
|
||||||
|
"Completed": "Completat",
|
||||||
|
"ContinuingOnly": "Només en emissió",
|
||||||
|
"CleanLibraryLevel": "Neteja el nivell de la llibreria",
|
||||||
|
"CountCustomFormatsSelected": "{count} format(s) personalitzat(s) seleccionat(s)"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,19 +7,19 @@
|
|||||||
"AnalyseVideoFiles": "Analyzovat video soubory",
|
"AnalyseVideoFiles": "Analyzovat video soubory",
|
||||||
"AnalyseVideoFilesHelpText": "Extrahujte ze souborů informace o videu, jako je rozlišení, doba běhu a informace o kodeku. To vyžaduje, aby {appName} četl části souboru, což může způsobit vysokou aktivitu disku nebo sítě během skenování.",
|
"AnalyseVideoFilesHelpText": "Extrahujte ze souborů informace o videu, jako je rozlišení, doba běhu a informace o kodeku. To vyžaduje, aby {appName} četl části souboru, což může způsobit vysokou aktivitu disku nebo sítě během skenování.",
|
||||||
"ApplicationURL": "URL aplikace",
|
"ApplicationURL": "URL aplikace",
|
||||||
"ApplicationUrlHelpText": "Externí adresa URL této aplikace včetně http(s)://, portu a základní adresy URL",
|
"ApplicationUrlHelpText": "Externí adresa URL této aplikace včetně http(s)://, portu a základu URL",
|
||||||
"AuthenticationMethodHelpText": "Vyžadovat uživatelské jméno a heslo pro přístup k {appName}u",
|
"AuthenticationMethodHelpText": "Vyžadovat uživatelské jméno a heslo pro přístup k {appName}u",
|
||||||
"AuthenticationRequired": "Vyžadované ověření",
|
"AuthenticationRequired": "Vyžadováno ověření",
|
||||||
"AuthenticationRequiredHelpText": "Změnit, pro které požadavky je vyžadováno ověření. Pokud nerozumíte rizikům, neměňte je.",
|
"AuthenticationRequiredHelpText": "Změnit, pro které požadavky je vyžadováno ověření. Neměňte, pokud nerozumíte rizikům.",
|
||||||
"AuthenticationRequiredWarning": "Aby se zabránilo vzdálenému přístupu bez ověření, vyžaduje nyní {appName} povolení ověření. Ověřování z místních adres můžete volitelně zakázat.",
|
"AuthenticationRequiredWarning": "Aby se zabránilo vzdálenému přístupu bez ověření, vyžaduje nyní {appName}, aby bylo povoleno ověřování. Volitelně můžete zakázat ověřování z místních adres.",
|
||||||
"AutoRedownloadFailedHelpText": "Automatické vyhledání a pokus o stažení jiného vydání",
|
"AutoRedownloadFailedHelpText": "Automatické vyhledání a pokus o stažení jiného vydání",
|
||||||
"AutoTaggingLoadError": "Nepodařilo se načíst automatické značky",
|
"AutoTaggingLoadError": "Nepodařilo se načíst automatické značky",
|
||||||
"AutomaticAdd": "Přidat automaticky",
|
"AutomaticAdd": "Přidat automaticky",
|
||||||
"BackupIntervalHelpText": "Interval mezi automatickými zálohami",
|
"BackupIntervalHelpText": "Interval mezi automatickými zálohami",
|
||||||
"BackupRetentionHelpText": "Automatické zálohy starší než doba uchovávání budou automaticky vyčištěny",
|
"BackupRetentionHelpText": "Automatické zálohy starší než doba uchovávání budou automaticky vyčištěny",
|
||||||
"BackupsLoadError": "Nelze načíst zálohy",
|
"BackupsLoadError": "Nelze načíst zálohy",
|
||||||
"BranchUpdate": "Větev, která se použije k aktualizaci {appName}u",
|
"BranchUpdate": "Větev použitá k aktualizaci {appName}u",
|
||||||
"BranchUpdateMechanism": "Větev používaná externím aktualizačním mechanismem",
|
"BranchUpdateMechanism": "Větev použitá externím aktualizačním mechanismem",
|
||||||
"BrowserReloadRequired": "Vyžaduje se opětovné načtení prohlížeče",
|
"BrowserReloadRequired": "Vyžaduje se opětovné načtení prohlížeče",
|
||||||
"BuiltIn": "Vestavěný",
|
"BuiltIn": "Vestavěný",
|
||||||
"BypassDelayIfHighestQualityHelpText": "Obejít zpoždění, když má vydání nejvyšší povolenou kvalitu v profilu kvality s preferovaným protokolem",
|
"BypassDelayIfHighestQualityHelpText": "Obejít zpoždění, když má vydání nejvyšší povolenou kvalitu v profilu kvality s preferovaným protokolem",
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
"Connect": "Připojit",
|
"Connect": "Připojit",
|
||||||
"ConnectSettingsSummary": "Oznámení, připojení k mediálním serverům/přehrávačům a vlastní skripty",
|
"ConnectSettingsSummary": "Oznámení, připojení k mediálním serverům/přehrávačům a vlastní skripty",
|
||||||
"Connections": "Připojení",
|
"Connections": "Připojení",
|
||||||
"AbsoluteEpisodeNumber": "Úplné číslo dílu",
|
"AbsoluteEpisodeNumber": "Celkový počet epizod",
|
||||||
"AddAutoTagError": "Nepodařilo se přidat novou automatickou značku, zkuste to prosím znovu.",
|
"AddAutoTagError": "Nepodařilo se přidat novou automatickou značku, zkuste to prosím znovu.",
|
||||||
"AddConditionError": "Nepodařilo se přidat novou podmínku, prosím, zkuste to znovu.",
|
"AddConditionError": "Nepodařilo se přidat novou podmínku, prosím, zkuste to znovu.",
|
||||||
"AddConnection": "Přidat spojení",
|
"AddConnection": "Přidat spojení",
|
||||||
@@ -58,12 +58,12 @@
|
|||||||
"Automatic": "Automatický",
|
"Automatic": "Automatický",
|
||||||
"AutoTaggingNegateHelpText": "Pokud je zaškrtnuto, pravidlo automatického označování se nepoužije, pokud odpovídá této podmínce {implementationName}.",
|
"AutoTaggingNegateHelpText": "Pokud je zaškrtnuto, pravidlo automatického označování se nepoužije, pokud odpovídá této podmínce {implementationName}.",
|
||||||
"BindAddress": "Vázat adresu",
|
"BindAddress": "Vázat adresu",
|
||||||
"BindAddressHelpText": "Platná IP adresa, localhost nebo '*' pro všechna rozhraní",
|
"BindAddressHelpText": "Platná IP adresa, localhost nebo ‚*‘ pro všechna rozhraní",
|
||||||
"BlocklistLoadError": "Nelze načíst černou listinu",
|
"BlocklistLoadError": "Nelze načíst černou listinu",
|
||||||
"BypassDelayIfHighestQuality": "Obejít v případě nejvyšší kvality",
|
"BypassDelayIfHighestQuality": "Obejít v případě nejvyšší kvality",
|
||||||
"BypassDelayIfAboveCustomFormatScoreHelpText": "Povolit obcházení, pokud má vydání vyšší skóre, než je nakonfigurované minimální skóre vlastního formátu",
|
"BypassDelayIfAboveCustomFormatScoreHelpText": "Povolit obcházení, pokud má vydání vyšší skóre, než je nakonfigurované minimální skóre vlastního formátu",
|
||||||
"BypassDelayIfAboveCustomFormatScoreMinimumScore": "Minimální skóre vlastního formátu",
|
"BypassDelayIfAboveCustomFormatScoreMinimumScore": "Minimální skóre vlastního formátu",
|
||||||
"CertificateValidation": "Ověření certifikátu",
|
"CertificateValidation": "Ověřování certifikátu",
|
||||||
"CalendarLoadError": "Nelze načíst kalendář",
|
"CalendarLoadError": "Nelze načíst kalendář",
|
||||||
"CertificateValidationHelpText": "Změňte přísnost ověřování certifikátů HTTPS. Neměňte, pokud nerozumíte rizikům.",
|
"CertificateValidationHelpText": "Změňte přísnost ověřování certifikátů HTTPS. Neměňte, pokud nerozumíte rizikům.",
|
||||||
"ChownGroupHelpText": "Název skupiny nebo gid. Použijte gid pro vzdálené systémy souborů.",
|
"ChownGroupHelpText": "Název skupiny nebo gid. Použijte gid pro vzdálené systémy souborů.",
|
||||||
@@ -76,29 +76,29 @@
|
|||||||
"CollectionsLoadError": "Nelze načíst sbírky",
|
"CollectionsLoadError": "Nelze načíst sbírky",
|
||||||
"CompletedDownloadHandling": "Zpracování stahování bylo dokončeno",
|
"CompletedDownloadHandling": "Zpracování stahování bylo dokončeno",
|
||||||
"Condition": "Stav",
|
"Condition": "Stav",
|
||||||
"UpdateMechanismHelpText": "Použijte vestavěný nástroj {appName}u pro aktualizaci nebo skript",
|
"UpdateMechanismHelpText": "Použij vestavěný nástroj {appName}u pro aktualizaci nebo skript",
|
||||||
"AddCondition": "Přidat podmínku",
|
"AddCondition": "Přidat podmínku",
|
||||||
"AutoTagging": "Automatické označování",
|
"AutoTagging": "Automatické označování",
|
||||||
"AddAutoTag": "Přidat automatickou značku",
|
"AddAutoTag": "Přidat automatickou značku",
|
||||||
"AutoTaggingRequiredHelpText": "Tato podmínka {implementationName} musí odpovídat, aby se pravidlo automatického označování použilo. V opačném případě postačí jediná shoda s {implementationName}.",
|
"AutoTaggingRequiredHelpText": "Tato podmínka {implementationName} musí odpovídat, aby se pravidlo automatického označování použilo. V opačném případě postačí jediná shoda s {implementationName}.",
|
||||||
"AirDate": "Datum vysílání",
|
"AirDate": "Datum vysílání",
|
||||||
"AllTitles": "Všechny názvy",
|
"AllTitles": "Všechny názvy",
|
||||||
"AbsoluteEpisodeNumbers": "Úplné číslo dílu(ů)",
|
"AbsoluteEpisodeNumbers": "Celkový počet epizod",
|
||||||
"AddRootFolder": "Přidat kořenový adresář",
|
"AddRootFolder": "Přidat kořenový adresář",
|
||||||
"Backups": "Zálohy",
|
"Backups": "Zálohy",
|
||||||
"Clear": "Vyčistit",
|
"Clear": "Vymazat",
|
||||||
"BeforeUpdate": "Před zálohováním",
|
"BeforeUpdate": "Před aktualizací",
|
||||||
"CloneAutoTag": "Klonovat automatické značky",
|
"CloneAutoTag": "Klonovat automatické značky",
|
||||||
"Conditions": "Podmínky",
|
"Conditions": "Podmínky",
|
||||||
"CancelPendingTask": "Opravdu chcete zrušit tento nevyřízený úkol?",
|
"CancelPendingTask": "Opravdu chcete zrušit tento úkol čekající na vyřízení?",
|
||||||
"Apply": "Použít",
|
"Apply": "Použít",
|
||||||
"AddingTag": "Přidání značky",
|
"AddingTag": "Přidávání štítku",
|
||||||
"ApplyTags": "Použít značky",
|
"ApplyTags": "Použít štítky",
|
||||||
"AutoAdd": "Přidat automaticky",
|
"AutoAdd": "Přidat automaticky",
|
||||||
"Cancel": "Zrušit",
|
"Cancel": "Zrušit",
|
||||||
"ApplyTagsHelpTextHowToApplyDownloadClients": "Jak použít značky na vybrané klienty pro stahování",
|
"ApplyTagsHelpTextHowToApplyDownloadClients": "Jak použít značky na vybrané klienty pro stahování",
|
||||||
"ApplyTagsHelpTextHowToApplyImportLists": "Jak použít značky na vybrané seznamy k importu",
|
"ApplyTagsHelpTextHowToApplyImportLists": "Jak použít značky na vybrané seznamy k importu",
|
||||||
"ApplyTagsHelpTextHowToApplyIndexers": "Jak použít značky na vybrané indexery",
|
"ApplyTagsHelpTextHowToApplyIndexers": "Jak použít štítky na vybrané indexery",
|
||||||
"AudioInfo": "Audio informace",
|
"AudioInfo": "Audio informace",
|
||||||
"Age": "Stáří",
|
"Age": "Stáří",
|
||||||
"AudioLanguages": "Jazyky zvuku",
|
"AudioLanguages": "Jazyky zvuku",
|
||||||
@@ -114,22 +114,22 @@
|
|||||||
"AllResultsAreHiddenByTheAppliedFilter": "Všechny výsledky jsou schovány použitým filtrem",
|
"AllResultsAreHiddenByTheAppliedFilter": "Všechny výsledky jsou schovány použitým filtrem",
|
||||||
"AddANewPath": "Přidat novou cestu",
|
"AddANewPath": "Přidat novou cestu",
|
||||||
"AddCustomFormatError": "Nebylo možné přidat nový vlastní formát, prosím zkuste to později.",
|
"AddCustomFormatError": "Nebylo možné přidat nový vlastní formát, prosím zkuste to později.",
|
||||||
"AddDownloadClientImplementation": "Přidat klienta pro stahování - {implementationName}",
|
"AddDownloadClientImplementation": "Přidat klienta pro stahování – {implementationName}",
|
||||||
"AddImportListExclusionError": "Nebylo možné přidat nové importované položky, prosím zkuste to později.",
|
"AddImportListExclusionError": "Nebylo možné přidat nové importované položky, prosím zkuste to později.",
|
||||||
"ApplyTagsHelpTextRemove": "Odebrat: Odebrat zadané značky",
|
"ApplyTagsHelpTextRemove": "Odebrat: Odebrat zadané štítky",
|
||||||
"ApplyTagsHelpTextAdd": "Přidat: Přidá značky k již existujícímu seznamu",
|
"ApplyTagsHelpTextAdd": "Přidat: Přidat štítky do existujícího seznamu štítků",
|
||||||
"ApplyTagsHelpTextReplace": "Nahradit: Nahradit značky zadanými značkami (prázdné pole vymaže všechny značky)",
|
"ApplyTagsHelpTextReplace": "Nahradit: Nahradit štítky zadanými štítky (prázdné pole vymaže všechny štítky)",
|
||||||
"Backup": "Záloha",
|
"Backup": "Záloha",
|
||||||
"Activity": "Aktivita",
|
"Activity": "Aktivita",
|
||||||
"Blocklist": "Blocklist",
|
"Blocklist": "Blocklist",
|
||||||
"AddNew": "Přidat nové",
|
"AddNew": "Přidat nové",
|
||||||
"About": "O aplikaci",
|
"About": "O aplikaci",
|
||||||
"Actions": "Akce",
|
"Actions": "Akce",
|
||||||
"AptUpdater": "K instalaci aktualizace použijte apt",
|
"AptUpdater": "K instalaci aktualizace používat apt",
|
||||||
"BackupNow": "Ihned zálohovat",
|
"BackupNow": "Zálohovat nyní",
|
||||||
"AppDataDirectory": "Adresář AppData",
|
"AppDataDirectory": "AppData Adresář",
|
||||||
"ApplyTagsHelpTextHowToApplySeries": "Jak použít značky na vybrané seriály",
|
"ApplyTagsHelpTextHowToApplySeries": "Jak použít značky na vybrané seriály",
|
||||||
"BackupFolderHelpText": "Relativní cesty se budou nacházet v adresáři AppData systému {appName}",
|
"BackupFolderHelpText": "Relativní cesty budou v adresáři AppData {appName}u",
|
||||||
"BlocklistReleases": "Blocklist pro vydání",
|
"BlocklistReleases": "Blocklist pro vydání",
|
||||||
"Agenda": "Agenda",
|
"Agenda": "Agenda",
|
||||||
"AnEpisodeIsDownloading": "Epizoda se stahuje",
|
"AnEpisodeIsDownloading": "Epizoda se stahuje",
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
"AddNewSeriesError": "Výsledky vyhledávání se nepodařilo načíst, zkuste to prosím znovu.",
|
"AddNewSeriesError": "Výsledky vyhledávání se nepodařilo načíst, zkuste to prosím znovu.",
|
||||||
"AddNewSeriesHelpText": "Přidání nového seriálu je snadné, stačí začít psát název seriálu, který chcete přidat.",
|
"AddNewSeriesHelpText": "Přidání nového seriálu je snadné, stačí začít psát název seriálu, který chcete přidat.",
|
||||||
"AddNewSeriesRootFolderHelpText": "'{folder}' posdložka bude vytvořena automaticky",
|
"AddNewSeriesRootFolderHelpText": "'{folder}' posdložka bude vytvořena automaticky",
|
||||||
"AddNewSeriesSearchForCutoffUnmetEpisodes": "Zahájit hledání vynechaných epizod",
|
"AddNewSeriesSearchForCutoffUnmetEpisodes": "Zahájit hledání Neodpovídajících vynechaných epizod",
|
||||||
"AddNewSeriesSearchForMissingEpisodes": "Zahájit hledání chybějících epizod",
|
"AddNewSeriesSearchForMissingEpisodes": "Zahájit hledání chybějících epizod",
|
||||||
"AddReleaseProfile": "Přidat profil vydání",
|
"AddReleaseProfile": "Přidat profil vydání",
|
||||||
"AddRemotePathMapping": "Přidat mapování vzdálených cest",
|
"AddRemotePathMapping": "Přidat mapování vzdálených cest",
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
"ClickToChangeSeries": "Kliknutím změníte seriál",
|
"ClickToChangeSeries": "Kliknutím změníte seriál",
|
||||||
"AddNotificationError": "Nebylo možné přidat nové oznámení, prosím zkuste to později.",
|
"AddNotificationError": "Nebylo možné přidat nové oznámení, prosím zkuste to později.",
|
||||||
"AddConditionImplementation": "Přidat podmínku - {implementationName}",
|
"AddConditionImplementation": "Přidat podmínku - {implementationName}",
|
||||||
"AddConnectionImplementation": "Přidat spojení - {implementationName}",
|
"AddConnectionImplementation": "Přidat spojení – {implementationName}",
|
||||||
"AddCustomFilter": "Přidat vlastní filtr",
|
"AddCustomFilter": "Přidat vlastní filtr",
|
||||||
"AddDownloadClient": "Přidat klienta pro stahování",
|
"AddDownloadClient": "Přidat klienta pro stahování",
|
||||||
"AddDelayProfile": "Přidat profil zpoždění",
|
"AddDelayProfile": "Přidat profil zpoždění",
|
||||||
@@ -159,7 +159,7 @@
|
|||||||
"AddImportListExclusion": "Přidat výjimku ze seznamu k importu",
|
"AddImportListExclusion": "Přidat výjimku ze seznamu k importu",
|
||||||
"AddImportList": "Přidat importované položky",
|
"AddImportList": "Přidat importované položky",
|
||||||
"AddImportListImplementation": "Přidat seznam k importu - {implementationName}",
|
"AddImportListImplementation": "Přidat seznam k importu - {implementationName}",
|
||||||
"AddIndexerImplementation": "Přidat indexer - {implementationName}",
|
"AddIndexerImplementation": "Přidat indexer – {implementationName}",
|
||||||
"AddQualityProfileError": "Nebylo možné přidat nový profil kvality, prosím zkuste to později.",
|
"AddQualityProfileError": "Nebylo možné přidat nový profil kvality, prosím zkuste to později.",
|
||||||
"AddToDownloadQueue": "Přidat stahování do fronty",
|
"AddToDownloadQueue": "Přidat stahování do fronty",
|
||||||
"Airs": "Vysíláno",
|
"Airs": "Vysíláno",
|
||||||
@@ -170,7 +170,7 @@
|
|||||||
"CalendarOptions": "Možnosti kalendáře",
|
"CalendarOptions": "Možnosti kalendáře",
|
||||||
"AllFiles": "Všechny soubory",
|
"AllFiles": "Všechny soubory",
|
||||||
"Analytics": "Analýzy",
|
"Analytics": "Analýzy",
|
||||||
"AnalyticsEnabledHelpText": "Odesílání anonymních informací o používání a chybách na servery společnosti {appName}. To zahrnuje informace o vašem prohlížeči, o tom, které stránky webového rozhraní {appName} používáte, hlášení chyb a také informace o verzi operačního systému a běhového prostředí. Tyto informace použijeme k určení priorit funkcí a oprav chyb.",
|
"AnalyticsEnabledHelpText": "Odesílejte anonymní informace o použití a chybách na servery {appName}u. To zahrnuje informace o vašem prohlížeči, které stránky webového rozhraní {appName}u 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 určení priorit funkcí a oprav chyb.",
|
||||||
"Anime": "Anime",
|
"Anime": "Anime",
|
||||||
"AnimeEpisodeFormat": "Formát epizod pro Anime",
|
"AnimeEpisodeFormat": "Formát epizod pro Anime",
|
||||||
"AnimeEpisodeTypeDescription": "Epizody vydané s použitím absolutního čísla epizody",
|
"AnimeEpisodeTypeDescription": "Epizody vydané s použitím absolutního čísla epizody",
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
"ChooseImportMode": "Vyberte mód importu",
|
"ChooseImportMode": "Vyberte mód importu",
|
||||||
"ClickToChangeEpisode": "Kliknutím změníte epizodu",
|
"ClickToChangeEpisode": "Kliknutím změníte epizodu",
|
||||||
"ClickToChangeLanguage": "Kliknutím změníte jazyk",
|
"ClickToChangeLanguage": "Kliknutím změníte jazyk",
|
||||||
"AutomaticSearch": "Vyhledat automaticky",
|
"AutomaticSearch": "Automatické vyhledávání",
|
||||||
"AutomaticUpdatesDisabledDocker": "Automatické aktualizace nejsou při použití aktualizačního mechanismu Docker přímo podporovány. Obraz kontejneru je nutné aktualizovat mimo {appName} nebo použít skript",
|
"AutomaticUpdatesDisabledDocker": "Automatické aktualizace nejsou při použití aktualizačního mechanismu Docker přímo podporovány. Obraz kontejneru je nutné aktualizovat mimo {appName} nebo použít skript",
|
||||||
"Branch": "Větev",
|
"Branch": "Větev",
|
||||||
"BypassDelayIfAboveCustomFormatScore": "Obejít, pokud je vyšší než skóre vlastního formátu",
|
"BypassDelayIfAboveCustomFormatScore": "Obejít, pokud je vyšší než skóre vlastního formátu",
|
||||||
@@ -202,9 +202,9 @@
|
|||||||
"CloneProfile": "Klonovat profil",
|
"CloneProfile": "Klonovat profil",
|
||||||
"CollapseMultipleEpisodes": "Sbalení více epizod",
|
"CollapseMultipleEpisodes": "Sbalení více epizod",
|
||||||
"CollapseMultipleEpisodesHelpText": "Sbalení více epizod vysílaných ve stejný den",
|
"CollapseMultipleEpisodesHelpText": "Sbalení více epizod vysílaných ve stejný den",
|
||||||
"ConnectionLost": "Spojení ztraceno",
|
"ConnectionLost": "Ztráta spojení",
|
||||||
"ConnectionLostReconnect": "{appName} se pokusí připojit automaticky, nebo můžete kliknout na tlačítko znovunačtení níže.",
|
"ConnectionLostReconnect": "{appName} se pokusí připojit automaticky, nebo můžete kliknout na tlačítko znovunačtení níže.",
|
||||||
"ConnectionLostToBackend": "{appName} ztratil spojení s backendem a pro obnovení funkčnosti bude třebaho znovu načíst.",
|
"ConnectionLostToBackend": "{appName} ztratil spojení s backendem a pro obnovení funkčnosti bude potřeba ho znovu načíst.",
|
||||||
"Continuing": "Pokračující",
|
"Continuing": "Pokračující",
|
||||||
"CountSeasons": "{count} Řad",
|
"CountSeasons": "{count} Řad",
|
||||||
"CustomFormat": "Vlastní formát",
|
"CustomFormat": "Vlastní formát",
|
||||||
@@ -229,7 +229,7 @@
|
|||||||
"CurrentlyInstalled": "Aktuálně nainstalováno",
|
"CurrentlyInstalled": "Aktuálně nainstalováno",
|
||||||
"CountImportListsSelected": "{count} vybraných seznamů pro import",
|
"CountImportListsSelected": "{count} vybraných seznamů pro import",
|
||||||
"CustomFormatScore": "Skóre vlastního formátu",
|
"CustomFormatScore": "Skóre vlastního formátu",
|
||||||
"CountDownloadClientsSelected": "{count} vybraných klientů ke stahování",
|
"CountDownloadClientsSelected": "{count} vybraných klientů pro stahování",
|
||||||
"CouldNotFindResults": "Nepodařilo se najít žádné výsledky pro '{term}'",
|
"CouldNotFindResults": "Nepodařilo se najít žádné výsledky pro '{term}'",
|
||||||
"CustomFormatsSettings": "Nastavení vlastních formátů",
|
"CustomFormatsSettings": "Nastavení vlastních formátů",
|
||||||
"CopyToClipboard": "Zkopírovat do schránky",
|
"CopyToClipboard": "Zkopírovat do schránky",
|
||||||
@@ -266,12 +266,12 @@
|
|||||||
"Dash": "Pomlčka",
|
"Dash": "Pomlčka",
|
||||||
"Database": "Databáze",
|
"Database": "Databáze",
|
||||||
"Date": "Datum",
|
"Date": "Datum",
|
||||||
"Dates": "Termíny",
|
"Dates": "Data",
|
||||||
"DefaultCase": "Výchozí případ",
|
"DefaultCase": "Výchozí případ",
|
||||||
"DailyEpisodeTypeFormat": "Datum ({format})",
|
"DailyEpisodeTypeFormat": "Datum ({format})",
|
||||||
"Default": "Výchozí",
|
"Default": "Výchozí",
|
||||||
"IndexerDownloadClientHelpText": "Zvolte, který klient pro stahování bude použit pro zachytávání z toho indexeru",
|
"IndexerDownloadClientHelpText": "Zvolte, který klient pro stahování bude použit pro zachytávání z toho indexeru",
|
||||||
"DeletedReasonManual": "Soubor byl smazán pomocí UI",
|
"DeletedReasonManual": "Soubor byl odstraněn pomocí {appName}, a to buď ručně, nebo jiným nástrojem prostřednictvím rozhraní API",
|
||||||
"DeletedReasonUpgrade": "Soubor byl odstraněn pro import lepší verze",
|
"DeletedReasonUpgrade": "Soubor byl odstraněn pro import lepší verze",
|
||||||
"EditConditionImplementation": "Upravit sbírku - {implementationName}",
|
"EditConditionImplementation": "Upravit sbírku - {implementationName}",
|
||||||
"ClearBlocklist": "Vyčistit blocklist",
|
"ClearBlocklist": "Vyčistit blocklist",
|
||||||
@@ -303,10 +303,10 @@
|
|||||||
"FormatAgeHour": "hodina",
|
"FormatAgeHour": "hodina",
|
||||||
"FormatAgeHours": "hodin",
|
"FormatAgeHours": "hodin",
|
||||||
"AuthenticationMethod": "Metoda ověřování",
|
"AuthenticationMethod": "Metoda ověřování",
|
||||||
"AuthenticationMethodHelpTextWarning": "Prosím vyberte platnou metodu ověřování",
|
"AuthenticationMethodHelpTextWarning": "Vyberte platnou metodu ověřování",
|
||||||
"AuthenticationRequiredPasswordHelpTextWarning": "Vložte nové heslo",
|
"AuthenticationRequiredPasswordHelpTextWarning": "Zadejte nové heslo",
|
||||||
"EditSelectedIndexers": "Upravit vybrané indexery",
|
"EditSelectedIndexers": "Upravit vybrané indexery",
|
||||||
"AuthenticationRequiredUsernameHelpTextWarning": "Vložte nové uživatelské jméno",
|
"AuthenticationRequiredUsernameHelpTextWarning": "Zadejte nové uživatelské jméno",
|
||||||
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Potvrďte nové heslo",
|
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Potvrďte nové heslo",
|
||||||
"AutoRedownloadFailedFromInteractiveSearchHelpText": "Automaticky vyhledat a pokusit se o stažení jiného vydání, pokud bylo neúspěšné vydání zachyceno z interaktivního vyhledávání",
|
"AutoRedownloadFailedFromInteractiveSearchHelpText": "Automaticky vyhledat a pokusit se o stažení jiného vydání, pokud bylo neúspěšné vydání zachyceno z interaktivního vyhledávání",
|
||||||
"AutoRedownloadFailed": "Opětovné stažení se nezdařilo",
|
"AutoRedownloadFailed": "Opětovné stažení se nezdařilo",
|
||||||
@@ -321,8 +321,8 @@
|
|||||||
"DownloadClientRemovesCompletedDownloadsHealthCheckMessage": "Klient stahování {downloadClientName} je nastaven na odstranění dokončených stahování. To může vést k tomu, že stahování budou z klienta odstraněna dříve, než je bude moci importovat {appName}.",
|
"DownloadClientRemovesCompletedDownloadsHealthCheckMessage": "Klient stahování {downloadClientName} je nastaven na odstranění dokončených stahování. To může vést k tomu, že stahování budou z klienta odstraněna dříve, než je bude moci importovat {appName}.",
|
||||||
"ConnectionSettingsUrlBaseHelpText": "Přidá předponu do {connectionName} url, jako např. {url}",
|
"ConnectionSettingsUrlBaseHelpText": "Přidá předponu do {connectionName} url, jako např. {url}",
|
||||||
"CustomFormatsSpecificationRegularExpressionHelpText": "Vlastní formát RegEx nerozlišuje velká a malá písmena",
|
"CustomFormatsSpecificationRegularExpressionHelpText": "Vlastní formát RegEx nerozlišuje velká a malá písmena",
|
||||||
"CustomFormatsSpecificationFlag": "Vlajka",
|
"CustomFormatsSpecificationFlag": "Značka",
|
||||||
"BlackholeFolderHelpText": "Složka do které {appName} uloží {extension} soubor",
|
"BlackholeFolderHelpText": "Složka, do které {appName} uloží soubor {extension}",
|
||||||
"BlackholeWatchFolder": "Složka sledování",
|
"BlackholeWatchFolder": "Složka sledování",
|
||||||
"Category": "Kategorie",
|
"Category": "Kategorie",
|
||||||
"BlocklistAndSearch": "Seznam blokovaných a vyhledávání",
|
"BlocklistAndSearch": "Seznam blokovaných a vyhledávání",
|
||||||
@@ -330,5 +330,190 @@
|
|||||||
"BlocklistReleaseHelpText": "Zabránit {appName} v opětovném sebrání tohoto vydání pomocí RSS nebo automatického vyhledávání",
|
"BlocklistReleaseHelpText": "Zabránit {appName} v opětovném sebrání tohoto vydání pomocí RSS nebo automatického vyhledávání",
|
||||||
"BlocklistMultipleOnlyHint": "Blokovat a nehledat náhradu",
|
"BlocklistMultipleOnlyHint": "Blokovat a nehledat náhradu",
|
||||||
"CustomFormatsSettingsTriggerInfo": "Vlastní formát se použije na vydání nebo soubor, pokud odpovídá alespoň jednomu z různých typů zvolených podmínek.",
|
"CustomFormatsSettingsTriggerInfo": "Vlastní formát se použije na vydání nebo soubor, pokud odpovídá alespoň jednomu z různých typů zvolených podmínek.",
|
||||||
"ChangeCategory": "Změnit kategorii"
|
"ChangeCategory": "Změnit kategorii",
|
||||||
|
"CustomFilter": "Vlastní filtr",
|
||||||
|
"ClickToChangeIndexerFlags": "Kliknutím změníte značky indexeru",
|
||||||
|
"QualityProfile": "Profil Kvality",
|
||||||
|
"ContinuingSeriesDescription": "Očekává se více dílů/další sezóna",
|
||||||
|
"DeleteReleaseProfile": "Smazat profil vydání",
|
||||||
|
"DownloadClientDelugeSettingsUrlBaseHelpText": "Přidá prefix do url adresy json deluge, viz {url}",
|
||||||
|
"DownloadClientQbittorrentSettingsFirstAndLastFirst": "Nejprve první a poslední",
|
||||||
|
"DownloadClientRTorrentSettingsAddStopped": "Přidat zastavené",
|
||||||
|
"DownloadClientRTorrentSettingsUrlPathHelpText": "Cesta ke koncovému bodu XMLRPC, viz {url}. Při použití ruTorrentu je to obvykle RPC2 nebo [cesta k ruTorrentu]{url2}.",
|
||||||
|
"AddListExclusion": "Přidej Seznam Výjimek",
|
||||||
|
"DeleteSelectedSeries": "Smazat vybrané seriály",
|
||||||
|
"AllSeriesAreHiddenByTheAppliedFilter": "Všechny výsledky jsou skryté použitým filtrem",
|
||||||
|
"DeleteSeriesFoldersHelpText": "Smazat složky seriálu a všechno v nich",
|
||||||
|
"DownloadClientNzbgetSettingsAddPausedHelpText": "Tato volba vyžaduje NzbGet verze alespoň 16.0",
|
||||||
|
"Priority": "Přednost",
|
||||||
|
"ProxyBadRequestHealthCheckMessage": "Nepodařilo se otestovat proxy. Kód Stavu: {statusCode}",
|
||||||
|
"DownloadClientFreeboxSettingsPortHelpText": "Port použitý pro přístup k rozhraní Freeboxu, výchozí hodnota je ‚{port}‘",
|
||||||
|
"CountSeriesSelected": "{count} vybrané seriály",
|
||||||
|
"CleanLibraryLevel": "Vyčistit Úroveň Knihovny",
|
||||||
|
"DeleteSeriesFolders": "Smazat složky seriálu",
|
||||||
|
"DoNotPrefer": "Neupřednostňovat",
|
||||||
|
"Destination": "Cesta",
|
||||||
|
"AddListExclusionSeriesHelpText": "„Zamezit přidávání Seriálu do {appName} prostřednictvím seznamů“",
|
||||||
|
"CountCustomFormatsSelected": "{count} vybraný vlastní formát(y)",
|
||||||
|
"DeleteQualityProfile": "Smazat profil kvality",
|
||||||
|
"DeleteSpecification": "Smaž specifikace",
|
||||||
|
"MappedNetworkDrivesWindowsService": "Mapované síťové jednotky nejsou k dispozici, když běží jako služba Windows. Další informace najdete v [FAQ]({url}).",
|
||||||
|
"DeletedSeriesDescription": "Seriál byl smazán z TheTVDB",
|
||||||
|
"RecycleBinUnableToWriteHealthCheckMessage": "Nelze zapisovat do nakonfigurované složky koše: {path}. Ujistěte se, že tato cesta existuje a že do ní může zapisovat uživatel se spuštěnou {appName}",
|
||||||
|
"DeleteSelectedImportListExclusionsMessageText": "Opravdu smazat vybraný importovaný seznam vyjímek?",
|
||||||
|
"DoNotUpgradeAutomatically": "Neupgradovat automaticky",
|
||||||
|
"DownloadClientQbittorrentSettingsInitialStateHelpText": "Počáteční stav torrentů přidaných do qBittorrentu. Pamatujte, že vynucené torrenty nedodržují omezení týkající se seedů",
|
||||||
|
"DeleteSelectedCustomFormats": "Smazat vlastní formát(y)",
|
||||||
|
"ClickToChangeReleaseType": "Kliknutím změníte typ verze",
|
||||||
|
"CollapseAll": "Sbal Všechno",
|
||||||
|
"CutoffUnmetNoItems": "Žádné neodpovídající nesplněné položky",
|
||||||
|
"CutoffUnmetLoadError": "Chybné načítání nesplněných položek",
|
||||||
|
"AddDelayProfileError": "Nelze přidat nový profil zpoždění, zkuste to prosím znovu.",
|
||||||
|
"AddedDate": "Přidáno: {date}",
|
||||||
|
"AlternateTitles": "Střídej tituly",
|
||||||
|
"BlocklistAndSearchHint": "Začne hledat náhradu po blokaci",
|
||||||
|
"BlocklistAndSearchMultipleHint": "Začne vyhledávat náhrady po blokaci",
|
||||||
|
"BlocklistFilterHasNoItems": "Vybraný filtr blokování neobsahuje žádné položky",
|
||||||
|
"BlocklistOnly": "Pouze seznam blokování",
|
||||||
|
"BlocklistOnlyHint": "Přidat do seznamu blokování bez náhrady",
|
||||||
|
"DeleteRemotePathMapping": "Smazat externí cestu k souboru",
|
||||||
|
"AutoTaggingSpecificationTag": "Značka",
|
||||||
|
"ChangeCategoryHint": "Změní stahování do kategorie „Post-Import“ z aplikace Download Client",
|
||||||
|
"ChangeCategoryMultipleHint": "Změní stahování do kategorie „Post-Import“ z aplikace Download Client",
|
||||||
|
"DeleteSelected": "Smazat vybrané",
|
||||||
|
"DownloadClientDelugeValidationLabelPluginFailureDetail": "{appName} nemohl(a) přidat etiketu k {clientName}.",
|
||||||
|
"DayOfWeekAt": "{day} v {time}",
|
||||||
|
"CountVotes": "{votes} hlasy",
|
||||||
|
"CustomColonReplacementFormatHint": "Platný znak souborového systému, například dvojtečka (písmeno)",
|
||||||
|
"ProxyFailedToTestHealthCheckMessage": "Nepodařilo se otestovat proxy: {url}",
|
||||||
|
"Completed": "Hotovo",
|
||||||
|
"DockerUpdater": "Aby jsi získal aktualizaci proveď update docker kontejneru",
|
||||||
|
"CustomFormatsSpecificationExceptLanguage": "Vyjma jazyka",
|
||||||
|
"CustomFormatsSpecificationExceptLanguageHelpText": "Odpovídá, pokud je přítomen jiný jazyk než vybraný",
|
||||||
|
"CustomFormatsSpecificationMaximumSize": "Maximální velikost",
|
||||||
|
"CustomFormatsSpecificationReleaseGroup": "Vydávající Skupina",
|
||||||
|
"CutoffNotMet": "Mezní hodnota není splněna",
|
||||||
|
"DeleteEpisodeFile": "Smazat Soubor Epizody",
|
||||||
|
"DeleteEpisodeFileMessage": "Opravdu chceš smazat '{path}'?",
|
||||||
|
"DeleteEpisodeFromDisk": "Smazat Epizodu z disku",
|
||||||
|
"DeleteIndexer": "Smazat Indexer",
|
||||||
|
"DeleteRemotePathMappingMessageText": "Opravdu chceš smazat tohle externí cestu k souboru?",
|
||||||
|
"Directory": "Adresář",
|
||||||
|
"DoNotBlocklist": "Nepřidávat do Seznamu blokování",
|
||||||
|
"DoneEditingGroups": "Úpravy skupin dokončeny",
|
||||||
|
"DeleteSeriesModalHeader": "Smazat - {title}",
|
||||||
|
"DeleteSelectedCustomFormatsMessageText": "Opravdu odstranit {count} vybraný vlastní formát(y)?",
|
||||||
|
"DownloadClientCheckNoneAvailableHealthCheckMessage": "Nedostupný klient pro stahování",
|
||||||
|
"DownloadClientCheckUnableToCommunicateWithHealthCheckMessage": "Nelze komunikovat s {downloadClientName}. {errorMessage}",
|
||||||
|
"DownloadClientFreeboxSettingsAppTokenHelpText": "Token aplikace získaný při vytváření přístupu k Freebox API (tj. ‚app_token‘)",
|
||||||
|
"DownloadClientFreeboxSettingsAppToken": "Token aplikace",
|
||||||
|
"Enable": "Povolit",
|
||||||
|
"Episode": "Epizoda",
|
||||||
|
"DestinationPath": "Cesta Destinace",
|
||||||
|
"EnableAutomaticSearchHelpText": "Použije se při automatickém vyhledávání prostřednictvím uživatelského rozhraní nebo pomocí {appName}",
|
||||||
|
"CustomColonReplacement": "Vlastní Náhrada znaku dvojtečky",
|
||||||
|
"CustomColonReplacementFormatHelpText": "Znaky které nahradí dvojtečky",
|
||||||
|
"DeleteEpisodesFiles": "Smazat{episodeFileCount} Soubory Epizody",
|
||||||
|
"DeleteEpisodesFilesHelpText": "Smazat soubory epizody a složku seriálu",
|
||||||
|
"DeleteImportListExclusionMessageText": "Opravdu chceš smazat tento import Seznamu Vyjímek?",
|
||||||
|
"DeleteSelectedEpisodeFiles": "Smazat soubory vybrané epizody",
|
||||||
|
"DeleteSelectedEpisodeFilesHelpText": "Opravdu smazat soubory vybrané epizody?",
|
||||||
|
"DeleteSeriesFolderConfirmation": "Složka seriálu `{path}` a veškerý její obsah bude smazán.",
|
||||||
|
"DeleteSeriesFolderEpisodeCount": "{episodeFileCount} celkově souborů epizody {size}",
|
||||||
|
"Details": "Detaily",
|
||||||
|
"DetailedProgressBar": "Podrobný ukazatel průběhu",
|
||||||
|
"DeleteSeriesFolderHelpText": "Smazat složku seriálu a její obsah",
|
||||||
|
"DoNotBlocklistHint": "Odstraň bez přidání do seznamu blokování",
|
||||||
|
"Donate": "Daruj",
|
||||||
|
"DownloadClientAriaSettingsDirectoryHelpText": "Volitelné umístění pro stahování, pokud chcete použít výchozí umístění Aria2, ponechte prázdné",
|
||||||
|
"DownloadClientDelugeValidationLabelPluginFailure": "Konfigurace etikety selhala",
|
||||||
|
"DownloadClientFloodSettingsAdditionalTagsHelpText": "Přidá vlastnosti médií jako značky. Nápovědy jsou příklady.",
|
||||||
|
"DownloadClientFreeboxSettingsApiUrl": "API URL",
|
||||||
|
"DownloadClientFreeboxSettingsApiUrlHelpText": "Definuj základní adresu URL rozhraní Freebox API s verzí rozhraní API, např. ‚{url}‘, výchozí hodnota je ‚{defaultApiUrl}‘",
|
||||||
|
"DownloadClientFreeboxSettingsAppId": "ID aplikace",
|
||||||
|
"DownloadClientFreeboxSettingsAppIdHelpText": "ID aplikace zadané při vytváření přístupu k Freebox API (tj. ‚app_id‘)",
|
||||||
|
"DownloadClientQbittorrentSettingsContentLayout": "Rozvržení obsahu",
|
||||||
|
"DownloadClientQbittorrentSettingsSequentialOrder": "Postupné pořadí",
|
||||||
|
"DownloadClientRTorrentSettingsAddStoppedHelpText": "Povolení přidá torrenty a magnety do rTorrentu v zastaveném stavu. To může způsobit poškození souborů magnet.",
|
||||||
|
"DownloadClientRTorrentSettingsDirectoryHelpText": "Volitelné umístění pro stahování, ponechte prázdné pro použití výchozího umístění rTorrentu",
|
||||||
|
"Donations": "Dary",
|
||||||
|
"Connection": "Spojení",
|
||||||
|
"DeleteSeriesFolder": "Smazat složku seriálu",
|
||||||
|
"DeleteNotification": "Smazat Oznámení",
|
||||||
|
"DownloadClientFloodSettingsAdditionalTags": "Další Značky",
|
||||||
|
"DownloadClientFloodSettingsUrlBaseHelpText": "Přidá prefix do Flood API, viz {url}",
|
||||||
|
"DownloadClientDownloadStationSettingsDirectoryHelpText": "Volitelná sdílená složka, do které se mají stahované soubory ukládat, pokud chcete použít výchozí umístění Download Station, ponechte prázdné",
|
||||||
|
"DownloadClientFreeboxSettingsHostHelpText": "Název hostitele nebo IP adresa hostitele Freeboxu, výchozí hodnota je ‚{url}‘ (funguje pouze ve stejné síti)",
|
||||||
|
"DownloadClientQbittorrentSettingsFirstAndLastFirstHelpText": "Stahovat nejprve první a poslední kusy (qBittorrent 4.1.0+)",
|
||||||
|
"DownloadClientQbittorrentSettingsSequentialOrderHelpText": "Stahovat v postupném pořadí (qBittorrent 4.1.0+)",
|
||||||
|
"DownloadClientQbittorrentSettingsUseSslHelpText": "Používat zabezpečené připojení. Viz Možnosti -> WebUI -> Webové uživatelské rozhraní -> ‚Použít HTTPS místo HTTP‘ v qBittorrentu.",
|
||||||
|
"DownloadClientTransmissionSettingsDirectoryHelpText": "Volitelné umístění pro stahování, ponechte prázdné pro použití výchozího umístění Transmission",
|
||||||
|
"DownloadClients": "Klienti pro stahování",
|
||||||
|
"HealthMessagesInfoBox": "Další informace o příčině těchto zpráv o kontrole zdraví najdete kliknutím na odkaz wiki (ikona knihy) na konci řádku nebo kontrolou [logů]({link}). Pokud máte potíže s interpretací těchto zpráv, můžete se obrátit na naši podporu, a to na níže uvedených odkazech.",
|
||||||
|
"GrabRelease": "Získat vydání",
|
||||||
|
"DownloadClientRTorrentSettingsUrlPath": "Cesta URL",
|
||||||
|
"Indexer": "Indexer",
|
||||||
|
"CustomFormatsSpecificationMaximumSizeHelpText": "Vydání musí odpovídat nebo být menší než tato velikost",
|
||||||
|
"CustomFormatsSpecificationMinimumSize": "Minimální velikost",
|
||||||
|
"Deleted": "Smazáno",
|
||||||
|
"DeletedReasonEpisodeMissingFromDisk": "{appName} nenalezen soubor na disku, Došlo k odvázání souboru na epizodu v databázi",
|
||||||
|
"DeleteSeriesFolderCountConfirmation": "Opravdu smazat {count} vybraný seriál?",
|
||||||
|
"DetailedProgressBarHelpText": "Zobrazit text na Ukazateli průběhu",
|
||||||
|
"Disabled": "Zakázáno",
|
||||||
|
"DownloadClientFloodSettingsTagsHelpText": "Počáteční značky stahování. Aby bylo stahování rozpoznáno, musí mít všechny počáteční značky. Tím se zabrání konfliktům s nesouvisejícími stahováními.",
|
||||||
|
"Filters": "Filtry",
|
||||||
|
"Implementation": "Implementace",
|
||||||
|
"DownloadClientPneumaticSettingsStrmFolderHelpText": "Soubory .strm v této složce budou importovány pomocí drone",
|
||||||
|
"History": "Historie",
|
||||||
|
"Discord": "Discord",
|
||||||
|
"DotNetVersion": ".NET",
|
||||||
|
"Download": "Stáhnout",
|
||||||
|
"DownloadClient": "Download klient",
|
||||||
|
"DownloadClientSettingsInitialStateHelpText": "Počáteční stav pro torrenty přidané do {clientName}",
|
||||||
|
"DownloadClientSettingsInitialState": "Počáteční stav",
|
||||||
|
"DownloadClientSettingsDestinationHelpText": "Ručně určuje cíl stahování, pro použití výchozího nastavení nechte prázdné",
|
||||||
|
"DownloadClientSettingsUseSslHelpText": "Při připojení k {clientName} použít zabezpečené připojení",
|
||||||
|
"EditConnectionImplementation": "Upravit připojení - {implementationName}",
|
||||||
|
"EnableInteractiveSearchHelpText": "Použije se při interaktivním vyhledávání",
|
||||||
|
"Ended": "Ukončeno",
|
||||||
|
"External": "Externí",
|
||||||
|
"General": "Obecné",
|
||||||
|
"AutoTaggingSpecificationGenre": "Žánr(y)",
|
||||||
|
"AutoTaggingSpecificationMaximumYear": "Maximální Rok",
|
||||||
|
"AutoTaggingSpecificationMinimumYear": "Minimální Rok",
|
||||||
|
"AutoTaggingSpecificationOriginalLanguage": "Jazyk",
|
||||||
|
"AutoTaggingSpecificationQualityProfile": "Profil Kvality",
|
||||||
|
"AutoTaggingSpecificationRootFolder": "Kořenová Složka",
|
||||||
|
"AutoTaggingSpecificationSeriesType": "Typ seriálu",
|
||||||
|
"AutoTaggingSpecificationStatus": "Status",
|
||||||
|
"CustomFormatsSpecificationLanguage": "Jazyk",
|
||||||
|
"CustomFormatsSpecificationRegularExpression": "Běžný výraz",
|
||||||
|
"CustomFormatsSpecificationMinimumSizeHelpText": "Vydání musí být větší než tato velikost",
|
||||||
|
"CustomFormatsSpecificationResolution": "Rozlišení",
|
||||||
|
"CustomFormatsSpecificationSource": "Zdroj",
|
||||||
|
"DeleteImportListExclusion": "Smazat import Seznamu Vyjímek",
|
||||||
|
"DiskSpace": "Místo na disku",
|
||||||
|
"DeleteReleaseProfileMessageText": "Opravdu smazat profil vydání '{name}'?",
|
||||||
|
"Docker": "Docker",
|
||||||
|
"DownloadClientQbittorrentSettingsContentLayoutHelpText": "Zda použít rozvržení obsahu nakonfigurované v qBittorrentu, původní rozvržení z torrentu nebo vždy vytvořit podsložku (qBittorrent 4.3.2+)",
|
||||||
|
"DownloadClientSettingsAddPaused": "Přidat pozastavené",
|
||||||
|
"DownloadClientSettingsUrlBaseHelpText": "Přidá prefix k {clientName}, například {url}",
|
||||||
|
"ExistingTag": "Stávající značka",
|
||||||
|
"ProxyResolveIpHealthCheckMessage": "Nepodařilo se vyřešit adresu IP konfigurovaného hostitele proxy {proxyHostName}",
|
||||||
|
"DownloadClientDelugeSettingsDirectory": "Adresář stahování",
|
||||||
|
"DownloadClientPneumaticSettingsNzbFolder": "Složka Nzb",
|
||||||
|
"FailedToFetchSettings": "Nepodařilo se načíst nastavení",
|
||||||
|
"DownloadClientSettings": "Nastavení klienta pro stahování",
|
||||||
|
"Grabbed": "Získáno",
|
||||||
|
"DatabaseMigration": "Migrace databáze",
|
||||||
|
"Delay": "Zpoždění",
|
||||||
|
"DeleteEmptyFolders": "Vymazat prázdné složky",
|
||||||
|
"DeleteEmptySeriesFoldersHelpText": "Smazat Složky prázdného Seriálu a Sezóny Během skenování a pokud jsou soubory epizody vymazány",
|
||||||
|
"DeleteTag": "Smazat štítek",
|
||||||
|
"DeleteTagMessageText": "Opravdu chceš smazat štítek \"{label}\"?",
|
||||||
|
"DestinationRelativePath": "Relativní cesta Destinace",
|
||||||
|
"DeleteSpecificationHelpText": "Opravdu smazat specifikaci '{name}'?",
|
||||||
|
"DownloadClientStatusAllClientHealthCheckMessage": "Všichni klienti pro stahování jsou nedostupní z důvodu selhání",
|
||||||
|
"DownloadClientStatusSingleClientHealthCheckMessage": "Klienti pro stahování jsou nedostupní z důvodu selhání: {downloadClientNames}",
|
||||||
|
"DownloadClientTransmissionSettingsUrlBaseHelpText": "Přidá předponu k url {clientName} rpc, např. {url}, výchozí hodnota je ‚{defaultUrl}‘"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,5 +103,20 @@
|
|||||||
"DeleteReleaseProfileMessageText": "Er du sikker på, at du vil slette udgivelsesprofilen »{name}«?",
|
"DeleteReleaseProfileMessageText": "Er du sikker på, at du vil slette udgivelsesprofilen »{name}«?",
|
||||||
"MinutesSixty": "60 minutter: {sixty}",
|
"MinutesSixty": "60 minutter: {sixty}",
|
||||||
"NegateHelpText": "Hvis dette er markeret, gælder det tilpassede format ikke, hvis denne {implementationName}-betingelse stemmer overens.",
|
"NegateHelpText": "Hvis dette er markeret, gælder det tilpassede format ikke, hvis denne {implementationName}-betingelse stemmer overens.",
|
||||||
"RemoveSelectedItemsQueueMessageText": "Er du sikker på, at du vil fjerne {selectedCount} elementer fra køen?"
|
"RemoveSelectedItemsQueueMessageText": "Er du sikker på, at du vil fjerne {selectedCount} elementer fra køen?",
|
||||||
|
"AddNewSeriesSearchForCutoffUnmetEpisodes": "Start søgning efter uopfyldte cutoff epsioder",
|
||||||
|
"AddNewSeriesRootFolderHelpText": "'{folder}' undermappen vil blive oprettet automatisk",
|
||||||
|
"AddNewSeriesSearchForMissingEpisodes": "Start søgning efter manglende episoder",
|
||||||
|
"AddListExclusionSeriesHelpText": "Forhindre serie fra at blive tilføjet til {appName} af lister",
|
||||||
|
"AddQualityProfile": "Tilføj Kvalitetsprofil",
|
||||||
|
"AddReleaseProfile": "Tilføj udgivelsesprofil",
|
||||||
|
"AddNewSeriesError": "Kunne ikke indlæse søgeresultater, prøv igen.",
|
||||||
|
"AddNewSeriesHelpText": "Det er nemt at tilføje en ny serie, bare start med at skrive navnet på serien du gerne vil tilføje.",
|
||||||
|
"AddQualityProfileError": "Kunne ikke tilføje ny kvalitetsprofil, prøv igen.",
|
||||||
|
"AddListExclusionError": "Kunne ikke tilføje den nye liste eksklusion, prøv igen.",
|
||||||
|
"AddNewRestriction": "Tilføj ny restriktion",
|
||||||
|
"AddNotificationError": "Kunne ikke tilføje ny notifikation, prøv igen.",
|
||||||
|
"AddRemotePathMapping": "Tilføj Sammenkædning med fjernsti",
|
||||||
|
"AddNew": "Tilføj ny",
|
||||||
|
"AddNewSeries": "Tilføj ny serie"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"Language": "Sprache",
|
"Language": "Sprache",
|
||||||
"CloneCondition": "Bedingung klonen",
|
"CloneCondition": "Bedingung klonen",
|
||||||
"DeleteCondition": "Bedingung löschen",
|
"DeleteCondition": "Bedingung löschen",
|
||||||
"DeleteConditionMessageText": "Bist du sicher, dass du die Bedingung '{0}' löschen willst?",
|
"DeleteConditionMessageText": "Bist du sicher, dass du die Bedingung '{name}' löschen willst?",
|
||||||
"DeleteCustomFormatMessageText": "Bist du sicher, dass du das benutzerdefinierte Format '{name}' wirklich löschen willst?",
|
"DeleteCustomFormatMessageText": "Bist du sicher, dass du das benutzerdefinierte Format '{name}' wirklich löschen willst?",
|
||||||
"RemoveSelectedItemQueueMessageText": "Bist du sicher, dass du ein Eintrag aus der Warteschlange entfernen willst?",
|
"RemoveSelectedItemQueueMessageText": "Bist du sicher, dass du ein Eintrag aus der Warteschlange entfernen willst?",
|
||||||
"RemoveSelectedItemsQueueMessageText": "Bist du sicher, dass du {selectedCount} Einträge aus der Warteschlange entfernen willst?",
|
"RemoveSelectedItemsQueueMessageText": "Bist du sicher, dass du {selectedCount} Einträge aus der Warteschlange entfernen willst?",
|
||||||
@@ -162,7 +162,7 @@
|
|||||||
"SelectEpisodesModalTitle": "{modalTitle} – Episode(n) auswählen",
|
"SelectEpisodesModalTitle": "{modalTitle} – Episode(n) auswählen",
|
||||||
"SeasonPassTruncated": "Es werden nur die letzten 25 Staffeln gezeigt. Gehen Sie zu den Details, um alle Staffeln zu sehen",
|
"SeasonPassTruncated": "Es werden nur die letzten 25 Staffeln gezeigt. Gehen Sie zu den Details, um alle Staffeln zu sehen",
|
||||||
"RestartReloadNote": "Hinweis: {appName} startet während des Wiederherstellungsvorgangs automatisch neu und lädt die Benutzeroberfläche neu.",
|
"RestartReloadNote": "Hinweis: {appName} startet während des Wiederherstellungsvorgangs automatisch neu und lädt die Benutzeroberfläche neu.",
|
||||||
"AutoRedownloadFailedHelpText": "Suchen Sie automatisch nach einer anderen Version und versuchen Sie, sie herunterzuladen",
|
"AutoRedownloadFailedHelpText": "Automatisch nach einem anderen Release suchen und versuchen es herunterzuladen",
|
||||||
"AirDate": "Ausstrahlungsdatum",
|
"AirDate": "Ausstrahlungsdatum",
|
||||||
"AgeWhenGrabbed": "Alter (bei Erfassung)",
|
"AgeWhenGrabbed": "Alter (bei Erfassung)",
|
||||||
"ApplyTagsHelpTextHowToApplySeries": "So wenden Sie Tags auf die ausgewählte Serie an",
|
"ApplyTagsHelpTextHowToApplySeries": "So wenden Sie Tags auf die ausgewählte Serie an",
|
||||||
@@ -229,7 +229,7 @@
|
|||||||
"UiLanguageHelpText": "Sprache, die {appName} für die Benutzeroberfläche verwendet",
|
"UiLanguageHelpText": "Sprache, die {appName} für die Benutzeroberfläche verwendet",
|
||||||
"UsenetBlackhole": "Usenet Blackhole",
|
"UsenetBlackhole": "Usenet Blackhole",
|
||||||
"YesCancel": "Ja Abbrechen",
|
"YesCancel": "Ja Abbrechen",
|
||||||
"AutoRedownloadFailedFromInteractiveSearchHelpText": "Suchen Sie automatisch nach einer anderen Version und versuchen Sie, sie herunterzuladen, wenn eine fehlerhafte Version aus der interaktiven Suche ausgewählt wurde",
|
"AutoRedownloadFailedFromInteractiveSearchHelpText": "Falls ein Release aus der interaktiven Suche fehlschlägt, automatisch nach einer alternativen Version suchen und versuchen, sie herunterzuladen",
|
||||||
"DownloadClientQbittorrentSettingsSequentialOrder": "Fortlaufende Reihenfolge",
|
"DownloadClientQbittorrentSettingsSequentialOrder": "Fortlaufende Reihenfolge",
|
||||||
"AutoTagging": "Automatisches Tagging",
|
"AutoTagging": "Automatisches Tagging",
|
||||||
"AddRootFolder": "Stammverzeichnis hinzufügen",
|
"AddRootFolder": "Stammverzeichnis hinzufügen",
|
||||||
@@ -486,7 +486,7 @@
|
|||||||
"StartImport": "Import starten",
|
"StartImport": "Import starten",
|
||||||
"StartProcessing": "Verarbeitung starten",
|
"StartProcessing": "Verarbeitung starten",
|
||||||
"Tasks": "Aufgaben",
|
"Tasks": "Aufgaben",
|
||||||
"ThemeHelpText": "Ändern Sie das Benutzeroberflächen-Design der Anwendung. Das „Auto“-Design verwendet Ihr Betriebssystemdesign, um den Hell- oder Dunkelmodus festzulegen. Inspiriert vom Theme.Park",
|
"ThemeHelpText": "UI-Design ändern: Der 'Auto'-Modus übernimmt das Betriebssystem-Theme, um automatisch zwischen Light- und Dark-Modus zu wechseln. Inspiriert von Theme.Park",
|
||||||
"Theme": "Design",
|
"Theme": "Design",
|
||||||
"TestAllLists": "Prüfe alle Listen",
|
"TestAllLists": "Prüfe alle Listen",
|
||||||
"Titles": "Titel",
|
"Titles": "Titel",
|
||||||
@@ -2138,5 +2138,14 @@
|
|||||||
"UpgradeUntilCustomFormatScoreEpisodeHelpText": "Sobald dieser benutzerdefinierte Formatwert erreicht ist, wird {appName} keine Episoden-Releases mehr herunterladen",
|
"UpgradeUntilCustomFormatScoreEpisodeHelpText": "Sobald dieser benutzerdefinierte Formatwert erreicht ist, wird {appName} keine Episoden-Releases mehr herunterladen",
|
||||||
"UpgradesAllowedHelpText": "Wenn deaktiviert, werden Qualitäten nicht aktualisiert.",
|
"UpgradesAllowedHelpText": "Wenn deaktiviert, werden Qualitäten nicht aktualisiert.",
|
||||||
"VideoDynamicRange": "Video-Dynamikbereich",
|
"VideoDynamicRange": "Video-Dynamikbereich",
|
||||||
"Warning": "Warnung"
|
"Warning": "Warnung",
|
||||||
|
"ReleasePush": "Veröffentlichung-Push",
|
||||||
|
"ReleaseSource": "Veröffentlichungsquelle",
|
||||||
|
"MetadataKometaDeprecatedSetting": "Veraltet",
|
||||||
|
"MetadataKometaDeprecated": "Kometa-Dateien werden nicht mehr erstellt, die Unterstützung wird in Version 5 vollständig entfernt",
|
||||||
|
"NotificationsTelegramSettingsIncludeInstanceName": "Instanzname im Titel einfügen",
|
||||||
|
"NotificationsTelegramSettingsIncludeInstanceNameHelpText": "Optional den Instanznamen in die Benachrichtigung einfügen",
|
||||||
|
"IndexerSettingsFailDownloadsHelpText": "Beim Verarbeiten abgeschlossener Downloads behandelt {appName} diese ausgewählten Dateitypen als fehlgeschlagene Downloads.",
|
||||||
|
"UserInvokedSearch": "Benutzerinitiierte Suche",
|
||||||
|
"IndexerSettingsFailDownloads": "Fehlgeschlagene Downloads"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1667,12 +1667,14 @@
|
|||||||
"ReleaseProfiles": "Release Profiles",
|
"ReleaseProfiles": "Release Profiles",
|
||||||
"ReleaseProfilesLoadError": "Unable to load Release Profiles",
|
"ReleaseProfilesLoadError": "Unable to load Release Profiles",
|
||||||
"ReleaseRejected": "Release Rejected",
|
"ReleaseRejected": "Release Rejected",
|
||||||
|
"ReleasePush": "Release Push",
|
||||||
"ReleaseSceneIndicatorAssumingScene": "Assuming Scene numbering.",
|
"ReleaseSceneIndicatorAssumingScene": "Assuming Scene numbering.",
|
||||||
"ReleaseSceneIndicatorAssumingTvdb": "Assuming TVDB numbering.",
|
"ReleaseSceneIndicatorAssumingTvdb": "Assuming TVDB numbering.",
|
||||||
"ReleaseSceneIndicatorMappedNotRequested": "Mapped episode wasn't requested in this search.",
|
"ReleaseSceneIndicatorMappedNotRequested": "Mapped episode wasn't requested in this search.",
|
||||||
"ReleaseSceneIndicatorSourceMessage": "{message} releases exist with ambiguous numbering, unable to reliably identify episode.",
|
"ReleaseSceneIndicatorSourceMessage": "{message} releases exist with ambiguous numbering, unable to reliably identify episode.",
|
||||||
"ReleaseSceneIndicatorUnknownMessage": "Numbering varies for this episode and release does not match any known mappings.",
|
"ReleaseSceneIndicatorUnknownMessage": "Numbering varies for this episode and release does not match any known mappings.",
|
||||||
"ReleaseSceneIndicatorUnknownSeries": "Unknown episode or series.",
|
"ReleaseSceneIndicatorUnknownSeries": "Unknown episode or series.",
|
||||||
|
"ReleaseSource": "Release Source",
|
||||||
"ReleaseTitle": "Release Title",
|
"ReleaseTitle": "Release Title",
|
||||||
"ReleaseType": "Release Type",
|
"ReleaseType": "Release Type",
|
||||||
"Reload": "Reload",
|
"Reload": "Reload",
|
||||||
@@ -2118,6 +2120,7 @@
|
|||||||
"UsenetDelayTime": "Usenet Delay: {usenetDelay}",
|
"UsenetDelayTime": "Usenet Delay: {usenetDelay}",
|
||||||
"UsenetDisabled": "Usenet Disabled",
|
"UsenetDisabled": "Usenet Disabled",
|
||||||
"Username": "Username",
|
"Username": "Username",
|
||||||
|
"UserInvokedSearch": "User Invoked Search",
|
||||||
"UtcAirDate": "UTC Air Date",
|
"UtcAirDate": "UTC Air Date",
|
||||||
"Version": "Version",
|
"Version": "Version",
|
||||||
"VersionNumber": "Version {version}",
|
"VersionNumber": "Version {version}",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -294,7 +294,7 @@
|
|||||||
"Restart": "Redémarrer",
|
"Restart": "Redémarrer",
|
||||||
"RestartNow": "Redémarrer maintenant",
|
"RestartNow": "Redémarrer maintenant",
|
||||||
"SaveSettings": "Enregistrer les paramètres",
|
"SaveSettings": "Enregistrer les paramètres",
|
||||||
"ShowMonitoredHelpText": "Afficher l'état de surveillance sous le poster",
|
"ShowMonitoredHelpText": "Affiche l'état de surveillance sous le poster",
|
||||||
"SkipFreeSpaceCheck": "Ignorer la vérification de l'espace libre",
|
"SkipFreeSpaceCheck": "Ignorer la vérification de l'espace libre",
|
||||||
"Sunday": "Dimanche",
|
"Sunday": "Dimanche",
|
||||||
"TorrentDelay": "Retard du torrent",
|
"TorrentDelay": "Retard du torrent",
|
||||||
@@ -401,7 +401,7 @@
|
|||||||
"SearchForMissing": "Rechercher les manquants",
|
"SearchForMissing": "Rechercher les manquants",
|
||||||
"SearchAll": "Tout rechercher",
|
"SearchAll": "Tout rechercher",
|
||||||
"Series": "Série",
|
"Series": "Série",
|
||||||
"ShowSearchHelpText": "Afficher le bouton de recherche au survol",
|
"ShowSearchHelpText": "Affiche le bouton de recherche au survol",
|
||||||
"SmartReplace": "Remplacement intelligent",
|
"SmartReplace": "Remplacement intelligent",
|
||||||
"SmartReplaceHint": "Dash ou Space Dash selon le nom",
|
"SmartReplaceHint": "Dash ou Space Dash selon le nom",
|
||||||
"Space": "Espace",
|
"Space": "Espace",
|
||||||
@@ -435,7 +435,7 @@
|
|||||||
"EditDownloadClientImplementation": "Modifier le client de téléchargement - {implementationName}",
|
"EditDownloadClientImplementation": "Modifier le client de téléchargement - {implementationName}",
|
||||||
"External": "Externe",
|
"External": "Externe",
|
||||||
"Monday": "Lundi",
|
"Monday": "Lundi",
|
||||||
"ShowQualityProfileHelpText": "Afficher le profil de qualité sous l'affiche",
|
"ShowQualityProfileHelpText": "Affiche le profil de qualité sous l'affiche",
|
||||||
"IncludeCustomFormatWhenRenamingHelpText": "Inclure dans le format de renommage {Formats personnalisés}",
|
"IncludeCustomFormatWhenRenamingHelpText": "Inclure dans le format de renommage {Formats personnalisés}",
|
||||||
"SelectDropdown": "Sélectionner...",
|
"SelectDropdown": "Sélectionner...",
|
||||||
"InteractiveImportNoFilesFound": "Aucun fichier vidéo n'a été trouvé dans le dossier sélectionné",
|
"InteractiveImportNoFilesFound": "Aucun fichier vidéo n'a été trouvé dans le dossier sélectionné",
|
||||||
@@ -728,7 +728,7 @@
|
|||||||
"ShowEpisodeInformation": "Afficher les informations sur l'épisode",
|
"ShowEpisodeInformation": "Afficher les informations sur l'épisode",
|
||||||
"ShowEpisodeInformationHelpText": "Afficher le titre et le numéro de l'épisode",
|
"ShowEpisodeInformationHelpText": "Afficher le titre et le numéro de l'épisode",
|
||||||
"ShowEpisodes": "Afficher les épisodes",
|
"ShowEpisodes": "Afficher les épisodes",
|
||||||
"ShowMonitored": "Afficher le chemin",
|
"ShowMonitored": "Afficher l'état de surveillance",
|
||||||
"ShowNetwork": "Afficher le réseau",
|
"ShowNetwork": "Afficher le réseau",
|
||||||
"ShowPath": "Afficher le chemin",
|
"ShowPath": "Afficher le chemin",
|
||||||
"ShowPreviousAiring": "Afficher la diffusion précédente",
|
"ShowPreviousAiring": "Afficher la diffusion précédente",
|
||||||
@@ -737,7 +737,7 @@
|
|||||||
"ShowSearch": "Afficher la recherche",
|
"ShowSearch": "Afficher la recherche",
|
||||||
"ShowSeasonCount": "Afficher le nombre de saisons",
|
"ShowSeasonCount": "Afficher le nombre de saisons",
|
||||||
"ShowSizeOnDisk": "Afficher la taille sur le disque",
|
"ShowSizeOnDisk": "Afficher la taille sur le disque",
|
||||||
"ShowTitle": "Montrer le titre",
|
"ShowTitle": "Afficher le titre",
|
||||||
"ShowSeriesTitleHelpText": "Afficher le titre de la série sous l'affiche",
|
"ShowSeriesTitleHelpText": "Afficher le titre de la série sous l'affiche",
|
||||||
"ShowUnknownSeriesItems": "Afficher les éléments de série inconnus",
|
"ShowUnknownSeriesItems": "Afficher les éléments de série inconnus",
|
||||||
"ShowUnknownSeriesItemsHelpText": "Afficher les éléments sans série dans la file d'attente. Cela peut inclure des séries, des films ou tout autre élément supprimé dans la catégorie de {appName}",
|
"ShowUnknownSeriesItemsHelpText": "Afficher les éléments sans série dans la file d'attente. Cela peut inclure des séries, des films ou tout autre élément supprimé dans la catégorie de {appName}",
|
||||||
@@ -1047,7 +1047,7 @@
|
|||||||
"IncludeCustomFormatWhenRenaming": "Inclure un format personnalisé lors du changement de nom",
|
"IncludeCustomFormatWhenRenaming": "Inclure un format personnalisé lors du changement de nom",
|
||||||
"InteractiveImportNoSeries": "Les séries doivent être choisies pour chaque fichier sélectionné",
|
"InteractiveImportNoSeries": "Les séries doivent être choisies pour chaque fichier sélectionné",
|
||||||
"Level": "Niveau",
|
"Level": "Niveau",
|
||||||
"LibraryImport": "Importer biblio.",
|
"LibraryImport": "Importer bibliothèque",
|
||||||
"ListExclusionsLoadError": "Impossible de charger les exclusions de liste",
|
"ListExclusionsLoadError": "Impossible de charger les exclusions de liste",
|
||||||
"ListQualityProfileHelpText": "Les éléments de la liste du profil de qualité seront ajoutés avec",
|
"ListQualityProfileHelpText": "Les éléments de la liste du profil de qualité seront ajoutés avec",
|
||||||
"ListTagsHelpText": "Balises qui seront ajoutées lors de l'importation à partir de cette liste",
|
"ListTagsHelpText": "Balises qui seront ajoutées lors de l'importation à partir de cette liste",
|
||||||
@@ -2075,7 +2075,7 @@
|
|||||||
"DayOfWeekAt": "{day} à {time}",
|
"DayOfWeekAt": "{day} à {time}",
|
||||||
"TomorrowAt": "Demain à {time}",
|
"TomorrowAt": "Demain à {time}",
|
||||||
"TodayAt": "Aujourd'hui à {time}",
|
"TodayAt": "Aujourd'hui à {time}",
|
||||||
"ShowTagsHelpText": "Afficher les labels sous l'affiche",
|
"ShowTagsHelpText": "Affiche les labels sous l'affiche",
|
||||||
"ShowTags": "Afficher les labels",
|
"ShowTags": "Afficher les labels",
|
||||||
"CountVotes": "{votes} votes",
|
"CountVotes": "{votes} votes",
|
||||||
"NoBlocklistItems": "Aucun élément de la liste de blocage",
|
"NoBlocklistItems": "Aucun élément de la liste de blocage",
|
||||||
@@ -2104,5 +2104,31 @@
|
|||||||
"LogSizeLimit": "Limite de taille du journal",
|
"LogSizeLimit": "Limite de taille du journal",
|
||||||
"DeleteSelectedImportListExclusionsMessageText": "Êtes-vous sûr de vouloir supprimer les exclusions de la liste d'importation sélectionnée ?",
|
"DeleteSelectedImportListExclusionsMessageText": "Êtes-vous sûr de vouloir supprimer les exclusions de la liste d'importation sélectionnée ?",
|
||||||
"CustomFormatsSpecificationExceptLanguage": "Excepté Langue",
|
"CustomFormatsSpecificationExceptLanguage": "Excepté Langue",
|
||||||
"CustomFormatsSpecificationExceptLanguageHelpText": "Corresponf si l'autre langue que celle sélectionné est présente"
|
"CustomFormatsSpecificationExceptLanguageHelpText": "Correspond si l'autre langue que celle sélectionné est présente",
|
||||||
|
"IndexerSettingsFailDownloadsHelpText": "Lors du traitement des téléchargements terminés, {appName} traitera ces types de fichiers sélectionnés comme des téléchargements ayant échoué.",
|
||||||
|
"IndexerSettingsFailDownloads": "Échec des téléchargements",
|
||||||
|
"Completed": "Complété",
|
||||||
|
"CutoffNotMet": "Seuil non atteint",
|
||||||
|
"DownloadClientUnavailable": "Client de téléchargement indisponible",
|
||||||
|
"CountCustomFormatsSelected": "{count} format(s) personnalisé(s) sélectionné(s)",
|
||||||
|
"Delay": "Retard",
|
||||||
|
"NotificationsGotifySettingsMetadataLinks": "Liens de métadonnées",
|
||||||
|
"NotificationsGotifySettingsMetadataLinksHelpText": "Ajouter un lien vers les métadonnées de la série lors de l'envoi de notifications",
|
||||||
|
"MetadataKometaDeprecated": "Les fichiers Kometa ne seront plus créés, le support sera complètement supprimé dans la v5",
|
||||||
|
"Premiere": "Première",
|
||||||
|
"RecentFolders": "Dossiers récents",
|
||||||
|
"UpdatePath": "Chemin de mise à jour",
|
||||||
|
"UpdateSeriesPath": "Mettre à jour le chemin de la série",
|
||||||
|
"NoCustomFormatsFound": "Aucun format personnalisé trouvé",
|
||||||
|
"EditSelectedCustomFormats": "Modifier les formats personnalisés sélectionnés",
|
||||||
|
"SkipFreeSpaceCheckHelpText": "À utiliser lorsque {appName} ne parvient pas à détecter l'espace libre de votre dossier racine",
|
||||||
|
"MetadataPlexSettingsEpisodeMappings": "Mappages des épisodes",
|
||||||
|
"MetadataPlexSettingsEpisodeMappingsHelpText": "Inclure les mappages d'épisodes pour tous les fichiers dans le fichier .plexmatch",
|
||||||
|
"FailedToFetchSettings": "Impossible de récupérer les paramètres",
|
||||||
|
"DeleteSelectedCustomFormats": "Supprimer les format(s) personnalisé(s)",
|
||||||
|
"DeleteSelectedCustomFormatsMessageText": "Êtes-vous sûr de vouloir supprimer {count} format(s) personnalisé(s) sélectionné(s) ?",
|
||||||
|
"LastSearched": "Dernière recherche",
|
||||||
|
"FolderNameTokens": "Jetons de nom de dossier",
|
||||||
|
"ManageCustomFormats": "Gérer les formats personnalisés",
|
||||||
|
"Menu": "Menu"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,7 +250,7 @@
|
|||||||
"AutoRedownloadFailed": "Download fallito",
|
"AutoRedownloadFailed": "Download fallito",
|
||||||
"AddDelayProfileError": "Impossibile aggiungere un nuovo profilo di ritardo, riprova.",
|
"AddDelayProfileError": "Impossibile aggiungere un nuovo profilo di ritardo, riprova.",
|
||||||
"Cutoff": "Taglio",
|
"Cutoff": "Taglio",
|
||||||
"AddListExclusion": "Aggiungi Lista esclusioni",
|
"AddListExclusion": "Aggiungi elenco esclusioni",
|
||||||
"DownloadClientValidationApiKeyRequired": "API Key Richiesta",
|
"DownloadClientValidationApiKeyRequired": "API Key Richiesta",
|
||||||
"Donate": "Dona",
|
"Donate": "Dona",
|
||||||
"DownloadClientDownloadStationValidationNoDefaultDestination": "Nessuna destinazione predefinita",
|
"DownloadClientDownloadStationValidationNoDefaultDestination": "Nessuna destinazione predefinita",
|
||||||
|
|||||||
@@ -55,5 +55,207 @@
|
|||||||
"AddCondition": "조건 추가",
|
"AddCondition": "조건 추가",
|
||||||
"AddIndexerError": "새 인덱서를 추가 할 수 없습니다. 다시 시도해주세요.",
|
"AddIndexerError": "새 인덱서를 추가 할 수 없습니다. 다시 시도해주세요.",
|
||||||
"TorrentBlackholeTorrentFolder": "토렌트 폴더",
|
"TorrentBlackholeTorrentFolder": "토렌트 폴더",
|
||||||
"UseSsl": "SSL 사용"
|
"UseSsl": "SSL 사용",
|
||||||
|
"AddListExclusion": "목록 예외 추가",
|
||||||
|
"BeforeUpdate": "업데이트 전",
|
||||||
|
"BindAddress": "바인드 주소",
|
||||||
|
"RemotePathMappingsInfo": "원격 경로 매핑은 거의 필요하지 않습니다. {appName}와(과) 다운로드 클라이언트가 동일한 시스템에 있는 경우 경로를 일치시키는 것이 좋습니다. 상세 내용은 [위키]({wikiLink})를 참조하세요.",
|
||||||
|
"RemoveSelectedBlocklistMessageText": "블랙리스트에서 선택한 항목을 제거 하시겠습니까?",
|
||||||
|
"RemoveSelectedItemQueueMessageText": "대기열에서 {0} 항목 {1}을 제거하시겠습니까?",
|
||||||
|
"RssSync": "RSS 동기화",
|
||||||
|
"RssSyncInterval": "RSS 동기화 간격",
|
||||||
|
"SelectLanguages": "언어 선택",
|
||||||
|
"SizeOnDisk": "디스크 상 크기",
|
||||||
|
"SslCertPassword": "SSL 인증서 비밀번호",
|
||||||
|
"SslCertPasswordHelpText": "pfx 파일의 비밀번호",
|
||||||
|
"SslCertPath": "SSL 인증서 경로",
|
||||||
|
"SupportedIndexersMoreInfo": "개별 인덱서에 대한 상세 내용을 보려면 정보 버튼을 클릭하세요.",
|
||||||
|
"SupportedListsMoreInfo": "개별 가져오기 목록에 대한 상세 내용을 보려면 정보 버튼을 클릭하세요.",
|
||||||
|
"UiLanguage": "UI 언어",
|
||||||
|
"UiSettings": "UI 설정",
|
||||||
|
"UpgradeUntil": "품질까지 업그레이드",
|
||||||
|
"Uppercase": "대문자",
|
||||||
|
"AutoTaggingSpecificationStatus": "상태",
|
||||||
|
"BuiltIn": "내장",
|
||||||
|
"ChangeFileDate": "파일 날짜 변경",
|
||||||
|
"Delete": "삭제",
|
||||||
|
"DeleteSelectedIndexers": "인덱서 삭제",
|
||||||
|
"DownloadClientSettings": "클라이언트 설정 다운로드",
|
||||||
|
"GrabId": "ID 잡아",
|
||||||
|
"ImportLists": "기울기",
|
||||||
|
"LocalPath": "로컬 경로",
|
||||||
|
"AnalyticsEnabledHelpText": "익명의 사용 및 오류 정보를 {appName}의 서버에 보냅니다. 여기에는 브라우저에 대한 정보, 사용하는 {appName} WebUI 페이지, 오류 보고, OS 및 런타임 버전이 포함됩니다. 이 정보를 사용하여 기능 및 버그 수정의 우선 순위를 지정합니다.",
|
||||||
|
"Connection": "연결",
|
||||||
|
"Dates": "날짜",
|
||||||
|
"DownloadClientSettingsRecentPriority": "클라이언트 우선 순위",
|
||||||
|
"Day": "일",
|
||||||
|
"Debug": "디버그",
|
||||||
|
"EditIndexerImplementation": "인덱서 추가 - {implementationName}",
|
||||||
|
"Clone": "닫기",
|
||||||
|
"CleanLibraryLevel": "정리 라이브러리 수준",
|
||||||
|
"ClickToChangeQuality": "품질을 변경하려면 클릭",
|
||||||
|
"ClientPriority": "클라이언트 우선 순위",
|
||||||
|
"Component": "구성 요소",
|
||||||
|
"DeleteEmptyFolders": "빈 폴더 삭제",
|
||||||
|
"MinimumCustomFormatScore": "최소 사용자 정의 형식 점수",
|
||||||
|
"MinimumFreeSpaceHelpText": "사용 가능한 디스크 공간을 이보다 적게 남겨 둘 경우 가져오기 방지",
|
||||||
|
"MoveAutomatically": "빠른 가져오기",
|
||||||
|
"No": "아니",
|
||||||
|
"IndexerSettingsRejectBlocklistedTorrentHashes": "동기화 중 차단 목록에 있는 토렌트 해시 거부",
|
||||||
|
"NotificationsSimplepushSettingsEvent": "이벤트",
|
||||||
|
"AutomaticSearch": "자동 검색",
|
||||||
|
"CustomFormat": "사용자 정의 형식",
|
||||||
|
"DelayProfile": "지연 프로필",
|
||||||
|
"DelayProfiles": "지연 프로필",
|
||||||
|
"EnableRss": "RSS 활성화",
|
||||||
|
"ChangeFileDateHelpText": "가져오기 / 재검색시 파일 날짜 변경",
|
||||||
|
"CreateGroup": "그룹 만들기",
|
||||||
|
"RecyclingBinHelpText": "영화 파일은 영구적으로 삭제되지 않고 삭제되면 여기로 이동합니다",
|
||||||
|
"IconForCutoffUnmetHelpText": "컷오프가 충족되지 않은 경우 파일 아이콘 표시",
|
||||||
|
"RemotePath": "원격 경로",
|
||||||
|
"ChmodFolder": "chmod 폴더",
|
||||||
|
"RemotePathMappingHostHelpText": "원격 다운로드 클라이언트에 지정한 것과 동일한 호스트",
|
||||||
|
"RemotePathMappingRemotePathHelpText": "다운로드 클라이언트가 액세스하는 디렉토리의 루트 경로",
|
||||||
|
"RemoveFromBlocklist": "블랙리스트에서 제거",
|
||||||
|
"RequiredHelpText": "이 {implementationName} 조건은 적용 할 맞춤 형식에 대해 일치해야합니다. 그렇지 않으면 단일 {implementationName} 일치로 충분합니다.",
|
||||||
|
"ShowRelativeDates": "상대 날짜 표시",
|
||||||
|
"ShowRelativeDatesHelpText": "상대 (오늘 / 어제 / 기타) 또는 절대 날짜 표시",
|
||||||
|
"TablePageSize": "페이지 크기",
|
||||||
|
"TablePageSizeHelpText": "각 페이지에 표시 할 항목 수",
|
||||||
|
"TagCannotBeDeletedWhileInUse": "사용 중에는 삭제할 수 없습니다",
|
||||||
|
"AddImportListExclusionError": "새 목록 제외를 추가 할 수 없음 재시도해주세요.",
|
||||||
|
"AddQualityProfile": "품질 프로필 추가",
|
||||||
|
"AddReleaseProfile": "지연 프로필 편집",
|
||||||
|
"AutoRedownloadFailedHelpText": "다른 출시를 자동으로 검색하고 다운로드 시도",
|
||||||
|
"BypassProxyForLocalAddresses": "로컬 주소에 대한 프록시 우회",
|
||||||
|
"CancelPendingTask": "이 보류 중인 작업을 취소하시겠습니까?",
|
||||||
|
"CancelProcessing": "처리 취소",
|
||||||
|
"Certification": "인증",
|
||||||
|
"SslPort": "SSL 포트",
|
||||||
|
"CustomFormatsSettings": "사용자 정의 형식 설정",
|
||||||
|
"CustomFormatsSpecificationReleaseGroup": "출시 그룹",
|
||||||
|
"DownloadClientPneumaticSettingsNzbFolder": "Nzb 폴더",
|
||||||
|
"CopyToClipboard": "클립 보드에 복사",
|
||||||
|
"DeleteQualityProfile": "품질 프로필 삭제",
|
||||||
|
"DetailedProgressBarHelpText": "진행률 표시줄에 텍스트 표시",
|
||||||
|
"Disabled": "비활성화됨",
|
||||||
|
"DisabledForLocalAddresses": "로컬 주소에 대해 비활성화됨",
|
||||||
|
"DiskSpace": "디스크 공간",
|
||||||
|
"Filters": "필터",
|
||||||
|
"ImportListExclusions": "제외 목록",
|
||||||
|
"AddRemotePathMapping": "원격 경로 매핑 추가",
|
||||||
|
"AppUpdatedVersion": "{appName}이 버전 `{version}`으로 업데이트되었습니다. 최신 변경 사항을 받으려면 {appName}을 재로드해야 합니다 ",
|
||||||
|
"BackupIntervalHelpText": "자동 백업 간격",
|
||||||
|
"BackupNow": "지금 백업",
|
||||||
|
"Backups": "백업",
|
||||||
|
"ChmodFolderHelpText": "8 진수, 미디어 폴더 및 파일로 가져오기 / 이름 변경 중에 적용됨 (실행 비트 없음)",
|
||||||
|
"ChooseAnotherFolder": "다른 폴더 선택",
|
||||||
|
"CompletedDownloadHandling": "완료된 다운로드 처리",
|
||||||
|
"CopyUsingHardlinksHelpTextWarning": "간혹 파일 잠금으로 인해 시드중인 파일의 이름을 바꾸지 못할 수 있습니다. 일시적으로 시드를 비활성화하고 {appName}의 이름 바꾸기 기능을 해결 방법으로 사용할 수 있습니다.",
|
||||||
|
"CurrentlyInstalled": "현재 설치됨",
|
||||||
|
"CustomFormatsSettingsSummary": "사용자 정의 형식 및 설정",
|
||||||
|
"DeleteIndexer": "인덱서 삭제",
|
||||||
|
"DeleteNotification": "알림 삭제",
|
||||||
|
"DeleteRemotePathMapping": "원격 경로 매핑 편집",
|
||||||
|
"DeleteTag": "태그 삭제",
|
||||||
|
"Download": "다운로드",
|
||||||
|
"DownloadClientRootFolderHealthCheckMessage": "다운로드 클라이언트 {downloadClientName} 은(는) 루트 폴더 {rootFolderPath}에 다운로드를 저장합니다. 루트 폴더에 다운로드해서는 안됩니다.",
|
||||||
|
"IndexerSettingsRejectBlocklistedTorrentHashesHelpText": "해시에 의해 토렌트가 차단된 경우 일부 인덱서의 RSS/검색 중에 토렌트가 제대로 거부되지 않을 수 있습니다. 이 기능을 활성화하면 토렌트를 가져온 후 클라이언트로 전송하기 전에 토렌트를 거부할 수 있습니다.",
|
||||||
|
"DoneEditingGroups": "그룹 편집 완료",
|
||||||
|
"DotNetVersion": ".NET",
|
||||||
|
"EditImportListExclusion": "목록 제외 편집",
|
||||||
|
"EnableSsl": "SSL 활성화",
|
||||||
|
"Conditions": "조건",
|
||||||
|
"ConnectSettings": "연결 설정",
|
||||||
|
"AddImportListExclusion": "목록 예외 추가",
|
||||||
|
"AllFiles": "모든 파일",
|
||||||
|
"Always": "항상",
|
||||||
|
"Connect": "연결",
|
||||||
|
"ConnectionLostReconnect": "Radarr가 자동으로 연결을 시도하거나 아래에서 새로고침을 클릭할 수 있습니다.",
|
||||||
|
"CustomFormats": "사용자 정의 형식",
|
||||||
|
"Ui": "UI",
|
||||||
|
"DockerUpdater": "Docker 컨테이너를 업데이트하여 업데이트를 받으세요",
|
||||||
|
"EditConnectionImplementation": "애플리케이션 추가 - {implementationName}",
|
||||||
|
"From": "부터",
|
||||||
|
"BranchUpdate": "{appName} 업데이트에 사용할 파생 버전",
|
||||||
|
"DeleteBackup": "백업 삭제",
|
||||||
|
"DeleteSelectedDownloadClients": "다운로드 클라이언트 삭제",
|
||||||
|
"AgeWhenGrabbed": "연령 (잡았을 때)",
|
||||||
|
"AnalyseVideoFiles": "비디오 파일 분석",
|
||||||
|
"ApiKey": "API 키",
|
||||||
|
"AptUpdater": "apt를 사용하여 업데이트 설치",
|
||||||
|
"BranchUpdateMechanism": "외부 업데이트 메커니즘에서 사용하는 파생 버전",
|
||||||
|
"DeleteSpecification": "알림 삭제",
|
||||||
|
"Deleted": "삭제됨",
|
||||||
|
"Clear": "지우기",
|
||||||
|
"CloneProfile": "프로필 복제",
|
||||||
|
"CloneIndexer": "인덱서 복제",
|
||||||
|
"Cutoff": "중단점",
|
||||||
|
"Date": "날짜",
|
||||||
|
"DeleteDelayProfileMessageText": "이 지연 프로필을 삭제하시겠습니까?",
|
||||||
|
"DoNotBlocklistHint": "차단 목록에 추가하지 않고 제거",
|
||||||
|
"DoNotPrefer": "선호하지 않음",
|
||||||
|
"EnableHelpText": "이 메타데이터 유형에 대한 메타데이터 파일 생성 활성화",
|
||||||
|
"Docker": "Docker",
|
||||||
|
"Donations": "기부",
|
||||||
|
"ImportList": "기울기",
|
||||||
|
"ImportListSettings": "목록 설정",
|
||||||
|
"Add": "추가",
|
||||||
|
"Apply": "적용",
|
||||||
|
"ApplyTags": "태그 적용",
|
||||||
|
"Cancel": "취소",
|
||||||
|
"EditDownloadClientImplementation": "다운로드 클라이언트 추가 - {implementationName}",
|
||||||
|
"EditReleaseProfile": "지연 프로필 편집",
|
||||||
|
"AddRootFolder": "루트 폴더 추가",
|
||||||
|
"ExtraFileExtensionsHelpText": "가져올 추가 파일의 쉼표로 구분 된 목록 (.nfo는 .nfo-orig로 가져옴)",
|
||||||
|
"AddDelayProfile": "지연 프로필 추가",
|
||||||
|
"AddDownloadClient": "다운로드 클라이언트 추가",
|
||||||
|
"AddExclusion": "예외 추가",
|
||||||
|
"AddNewRestriction": "새로운 제한 추가",
|
||||||
|
"AuthForm": "양식 (로그인 페이지)",
|
||||||
|
"AuthBasic": "기본 (브라우저 팝업)",
|
||||||
|
"Authentication": "인증",
|
||||||
|
"Automatic": "자동",
|
||||||
|
"CertificateValidation": "인증서 검증",
|
||||||
|
"Close": "닫기",
|
||||||
|
"Connections": "연결",
|
||||||
|
"DeleteImportListExclusion": "가져오기 목록 제외 삭제",
|
||||||
|
"DoNotUpgradeAutomatically": "자동 업그레이드 안함",
|
||||||
|
"DownloadPropersAndRepacksHelpText": "Propers / Repacks로 자동 업그레이드할지 여부",
|
||||||
|
"NoIssuesWithYourConfiguration": "구성에 문제 없음",
|
||||||
|
"IncludeHealthWarnings": "건강 경고 포함",
|
||||||
|
"DownloadClientsSettingsSummary": "클라이언트 다운로드, 다운로드 처리 및 원격 경로 매핑",
|
||||||
|
"DownloadFailed": "다운로드 실패함",
|
||||||
|
"Downloaded": "다운로드됨",
|
||||||
|
"Downloading": "다운로드 중",
|
||||||
|
"ICalShowAsAllDayEvents": "종일 이벤트로 표시",
|
||||||
|
"Rating": "등급",
|
||||||
|
"RegularExpression": "일반 표현",
|
||||||
|
"Activity": "활동",
|
||||||
|
"Backup": "백업",
|
||||||
|
"AudioInfo": "오디오 정보",
|
||||||
|
"DownloadClient": "클라이언트 다운로드",
|
||||||
|
"ShortDateFormat": "짧은 날짜 형식",
|
||||||
|
"Yes": "예",
|
||||||
|
"Actions": "동작",
|
||||||
|
"About": "정보",
|
||||||
|
"EditConditionImplementation": "연결 추가 - {implementationName}",
|
||||||
|
"ICalLink": "iCal 링크",
|
||||||
|
"Agenda": "일정",
|
||||||
|
"DownloadClients": "클라이언트 다운로드",
|
||||||
|
"QualityProfile": "품질 프로필",
|
||||||
|
"Rss": "RSS",
|
||||||
|
"WhatsNew": "새로운 소식?",
|
||||||
|
"MaximumSize": "최대 크기",
|
||||||
|
"DeleteDownloadClient": "다운로드 클라이언트 삭제",
|
||||||
|
"DeleteImportListExclusionMessageText": "이 가져오기 목록 제외를 삭제하시겠습니까?",
|
||||||
|
"DeleteDelayProfile": "지연 프로필 삭제",
|
||||||
|
"DestinationRelativePath": "대상 상대 경로",
|
||||||
|
"File": "파일",
|
||||||
|
"ImportListsTraktSettingsGenres": "장르",
|
||||||
|
"InteractiveSearchModalHeader": "대화형 검색",
|
||||||
|
"ManualImportItemsLoadError": "수동 가져오기 항목을 로드할 수 없습니다",
|
||||||
|
"LongDateFormat": "긴 날짜 형식",
|
||||||
|
"Lowercase": "소문자",
|
||||||
|
"KeyboardShortcutsSaveSettings": "설정 저장"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,5 +18,42 @@
|
|||||||
"Actions": "Handlinger",
|
"Actions": "Handlinger",
|
||||||
"AddCustomFilter": "Legg til eget filter",
|
"AddCustomFilter": "Legg til eget filter",
|
||||||
"AddConnection": "Legg til tilkobling",
|
"AddConnection": "Legg til tilkobling",
|
||||||
"AddDelayProfile": "Legg til forsinkelsesprofil"
|
"AddDelayProfile": "Legg til forsinkelsesprofil",
|
||||||
|
"AddRootFolderError": "Kunne ikke legge til rotmappe",
|
||||||
|
"AddDelayProfileError": "Kunne ikke legge til ny forsinkelsesprofil, vennligst prøv igjen.",
|
||||||
|
"AddIndexerError": "Kunne ikke legge til ny indekser, vennligst prøv igjen.",
|
||||||
|
"AddList": "Legg til liste",
|
||||||
|
"AddListError": "Kunne ikke legge til ny liste, vennligst prøv igjen.",
|
||||||
|
"AddRootFolder": "Legg til Rotmappe",
|
||||||
|
"AddConnectionImplementation": "Legg til tilkobling - {implementationName}",
|
||||||
|
"AddDownloadClientImplementation": "Ny Nedlastingsklient - {implementationName}",
|
||||||
|
"AddImportListImplementation": "Legg til importliste - {implementationName}",
|
||||||
|
"AddIndexerImplementation": "Legg til indekser - {implementationName}",
|
||||||
|
"AddToDownloadQueue": "Legg til nedlastningskø",
|
||||||
|
"AddedToDownloadQueue": "Lagt til nedlastningskø",
|
||||||
|
"AfterManualRefresh": "Etter manuell oppdatering",
|
||||||
|
"AddCustomFormat": "Nytt Egendefinert format",
|
||||||
|
"AddCustomFormatError": "Kunne ikke legge til nytt egendefinert format, vennligst prøv på nytt.",
|
||||||
|
"AddDownloadClient": "Ny Nedlastingsklient",
|
||||||
|
"AddDownloadClientError": "Kunne ikke legge til ny Nedlastingsklient, vennligst prøv igjen.",
|
||||||
|
"AddImportList": "Ny Importliste",
|
||||||
|
"AddIndexer": "Legg til indekser",
|
||||||
|
"AddNewRestriction": "Legg til ny begrensning",
|
||||||
|
"AddNotificationError": "Kunne ikke legge til ny varsling, vennligst prøv igjen.",
|
||||||
|
"AddQualityProfile": "Legg til kvalitetsprofil",
|
||||||
|
"AddQualityProfileError": "Kunne ikke legge til ny kvalitetsprofil, vennligst prøv igjen.",
|
||||||
|
"AddReleaseProfile": "Legg til utgivelsesprofil",
|
||||||
|
"AddNew": "Legg til ny",
|
||||||
|
"Age": "Alder",
|
||||||
|
"Agenda": "Agenda",
|
||||||
|
"AddNewSeries": "Legg til ny serie",
|
||||||
|
"AddNewSeriesError": "Kunne ikke laste søkeresultat, vennligst prøv igjen.",
|
||||||
|
"AddNewSeriesHelpText": "Det er enkelt å legge til en ny serie. Bare begynn å taste navnet på serien du vil legge til.",
|
||||||
|
"AddNewSeriesRootFolderHelpText": "Undermappa \"{folder}\" vil bli automatisk laget",
|
||||||
|
"AddNewSeriesSearchForMissingEpisodes": "Søk etter manglende episoder",
|
||||||
|
"AddRemotePathMapping": "Legg til ekstern stimapping",
|
||||||
|
"AddRemotePathMappingError": "Kunne ikke legge til ny ekstern stimapping, vennligst prøv igjen.",
|
||||||
|
"AddSeriesWithTitle": "Legg til {title}",
|
||||||
|
"Added": "Lagt til",
|
||||||
|
"AddedDate": "Lagt til: {date}"
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -209,5 +209,8 @@
|
|||||||
"CloneIndexer": "Clonează Indexer",
|
"CloneIndexer": "Clonează Indexer",
|
||||||
"CloneProfile": "Clonează Profil",
|
"CloneProfile": "Clonează Profil",
|
||||||
"DownloadClientUnavailable": "Client de descărcare indisponibil",
|
"DownloadClientUnavailable": "Client de descărcare indisponibil",
|
||||||
"Clone": "Clonează"
|
"Clone": "Clonează",
|
||||||
|
"DownloadClientSettingsOlderPriority": "Prioritate mai vechi",
|
||||||
|
"DownloadClientSettingsRecentPriority": "Prioritate recente",
|
||||||
|
"Absolute": "Absolut"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2061,7 +2061,7 @@
|
|||||||
"Umask770Description": "{octal} - Владелец и группа - запись",
|
"Umask770Description": "{octal} - Владелец и группа - запись",
|
||||||
"UiSettings": "Настройки пользовательского интерфейса",
|
"UiSettings": "Настройки пользовательского интерфейса",
|
||||||
"UiLanguage": "Язык пользовательского интерфейса",
|
"UiLanguage": "Язык пользовательского интерфейса",
|
||||||
"Ui": "Пользовательский интерфейс",
|
"Ui": "Интерфейс",
|
||||||
"ShowSeriesTitleHelpText": "Показать название сериала под постером",
|
"ShowSeriesTitleHelpText": "Показать название сериала под постером",
|
||||||
"ShowSeasonCount": "Показать количество сезонов",
|
"ShowSeasonCount": "Показать количество сезонов",
|
||||||
"TorrentBlackholeSaveMagnetFilesExtension": "Сохранить магнет-файлы с расширением",
|
"TorrentBlackholeSaveMagnetFilesExtension": "Сохранить магнет-файлы с расширением",
|
||||||
@@ -2089,5 +2089,9 @@
|
|||||||
"LogSizeLimit": "Ограничение размера журнала",
|
"LogSizeLimit": "Ограничение размера журнала",
|
||||||
"LogSizeLimitHelpText": "Максимальный размер файла журнала в МБ перед архивированием. По умолчанию - 1 МБ.",
|
"LogSizeLimitHelpText": "Максимальный размер файла журнала в МБ перед архивированием. По умолчанию - 1 МБ.",
|
||||||
"IndexerHDBitsSettingsMediums": "Mediums",
|
"IndexerHDBitsSettingsMediums": "Mediums",
|
||||||
"CountCustomFormatsSelected": "{count} пользовательских форматов выбрано"
|
"CountCustomFormatsSelected": "{count} пользовательских форматов выбрано",
|
||||||
|
"Completed": "Завершено",
|
||||||
|
"CutoffNotMet": "Порог не достигнут",
|
||||||
|
"CustomFormatsSpecificationExceptLanguage": "Кроме языка",
|
||||||
|
"CustomFormatsSpecificationExceptLanguageHelpText": "Подходит, если есть любой язык кроме указанного"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"AddConditionImplementation": "Koşul Ekle - {implementationName}",
|
"AddConditionImplementation": "Koşul Ekle - {implementationName}",
|
||||||
"EditConnectionImplementation": "Bildirimi Düzenle - {implementationName}",
|
"EditConnectionImplementation": "Bildirimi Düzenle - {implementationName}",
|
||||||
"AddConnectionImplementation": "Bağlantı Ekle - {implementationName}",
|
"AddConnectionImplementation": "Bağlantı Ekle - {implementationName}",
|
||||||
"AddIndexerImplementation": "Yeni Dizinleyici Ekle - {implementationName}",
|
"AddIndexerImplementation": "Yeni İndeksleyici Ekle - {implementationName}",
|
||||||
"EditIndexerImplementation": "Koşul Ekle - {implementationName}",
|
"EditIndexerImplementation": "Koşul Ekle - {implementationName}",
|
||||||
"AddToDownloadQueue": "İndirme kuyruğuna ekleyin",
|
"AddToDownloadQueue": "İndirme kuyruğuna ekleyin",
|
||||||
"AddedToDownloadQueue": "İndirme kuyruğuna eklendi",
|
"AddedToDownloadQueue": "İndirme kuyruğuna eklendi",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"AddImportListExclusion": "İçe Aktarma Listesi Hariç Tutma Ekle",
|
"AddImportListExclusion": "İçe Aktarma Listesi Hariç Tutma Ekle",
|
||||||
"AddImportListExclusionError": "Yeni bir liste dışlaması eklenemiyor, lütfen tekrar deneyin.",
|
"AddImportListExclusionError": "Yeni bir liste dışlaması eklenemiyor, lütfen tekrar deneyin.",
|
||||||
"AddImportListImplementation": "İçe Aktarım Listesi Ekle -{implementationName}",
|
"AddImportListImplementation": "İçe Aktarım Listesi Ekle -{implementationName}",
|
||||||
"AddIndexer": "Dizinleyici Ekle",
|
"AddIndexer": "İndeksleyici Ekle",
|
||||||
"AddNewSeriesSearchForMissingEpisodes": "Kayıp bölümleri aramaya başlayın",
|
"AddNewSeriesSearchForMissingEpisodes": "Kayıp bölümleri aramaya başlayın",
|
||||||
"AddNotificationError": "Yeni bir bildirim eklenemiyor, lütfen tekrar deneyin.",
|
"AddNotificationError": "Yeni bir bildirim eklenemiyor, lütfen tekrar deneyin.",
|
||||||
"AddReleaseProfile": "Yayın Profili Ekle",
|
"AddReleaseProfile": "Yayın Profili Ekle",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"AddSeriesWithTitle": "{title} Ekleyin",
|
"AddSeriesWithTitle": "{title} Ekleyin",
|
||||||
"Agenda": "Ajanda",
|
"Agenda": "Ajanda",
|
||||||
"Airs": "Yayınlar",
|
"Airs": "Yayınlar",
|
||||||
"AddIndexerError": "Yeni dizinleyici eklenemiyor, lütfen tekrar deneyin.",
|
"AddIndexerError": "Yeni indeksleyici eklenemiyor, lütfen tekrar deneyin.",
|
||||||
"AddNewSeriesSearchForCutoffUnmetEpisodes": "Karşılanmamış bölümleri aramaya başlayın",
|
"AddNewSeriesSearchForCutoffUnmetEpisodes": "Karşılanmamış bölümleri aramaya başlayın",
|
||||||
"AddQualityProfileError": "Yeni kalite profili eklenemiyor, lütfen tekrar deneyin.",
|
"AddQualityProfileError": "Yeni kalite profili eklenemiyor, lütfen tekrar deneyin.",
|
||||||
"AddRemotePathMappingError": "Yeni bir uzak yol eşlemesi eklenemiyor, lütfen tekrar deneyin.",
|
"AddRemotePathMappingError": "Yeni bir uzak yol eşlemesi eklenemiyor, lütfen tekrar deneyin.",
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
"AddRootFolderError": "Kök klasör eklenemiyor",
|
"AddRootFolderError": "Kök klasör eklenemiyor",
|
||||||
"CountImportListsSelected": "{count} içe aktarma listesi seçildi",
|
"CountImportListsSelected": "{count} içe aktarma listesi seçildi",
|
||||||
"CustomFormatsSpecificationFlag": "Bayrak",
|
"CustomFormatsSpecificationFlag": "Bayrak",
|
||||||
"ClickToChangeIndexerFlags": "Dizinleyici bayraklarını değiştirmek için tıklayın",
|
"ClickToChangeIndexerFlags": "İndeksleyici bayraklarını değiştirmek için tıklayın",
|
||||||
"ClickToChangeReleaseGroup": "Yayım grubunu değiştirmek için tıklayın",
|
"ClickToChangeReleaseGroup": "Yayım grubunu değiştirmek için tıklayın",
|
||||||
"AppUpdated": "{appName} Güncellendi",
|
"AppUpdated": "{appName} Güncellendi",
|
||||||
"ApplicationURL": "Uygulama URL'si",
|
"ApplicationURL": "Uygulama URL'si",
|
||||||
@@ -127,7 +127,7 @@
|
|||||||
"Category": "Kategori",
|
"Category": "Kategori",
|
||||||
"CertificateValidationHelpText": "HTTPS sertifika doğrulamasının sıkılığını değiştirin. Riskleri anlamadığınız sürece değişmeyin.",
|
"CertificateValidationHelpText": "HTTPS sertifika doğrulamasının sıkılığını değiştirin. Riskleri anlamadığınız sürece değişmeyin.",
|
||||||
"CloneCondition": "Klon Durumu",
|
"CloneCondition": "Klon Durumu",
|
||||||
"CountIndexersSelected": "{count} dizinleyici seçildi",
|
"CountIndexersSelected": "{count} indeksleyici seçildi",
|
||||||
"CustomFormatsSpecificationRegularExpressionHelpText": "Özel Format RegEx Büyük/Küçük Harfe Duyarsızdır",
|
"CustomFormatsSpecificationRegularExpressionHelpText": "Özel Format RegEx Büyük/Küçük Harfe Duyarsızdır",
|
||||||
"AutoRedownloadFailed": "Başarısız İndirmeleri Yenile",
|
"AutoRedownloadFailed": "Başarısız İndirmeleri Yenile",
|
||||||
"AutoRedownloadFailedFromInteractiveSearch": "Etkileşimli Arama'dan Başarısız İndirmeleri Yenile",
|
"AutoRedownloadFailedFromInteractiveSearch": "Etkileşimli Arama'dan Başarısız İndirmeleri Yenile",
|
||||||
@@ -155,7 +155,7 @@
|
|||||||
"DelayMinutes": "{delay} Dakika",
|
"DelayMinutes": "{delay} Dakika",
|
||||||
"DeleteImportListMessageText": "'{name}' listesini silmek istediğinizden emin misiniz?",
|
"DeleteImportListMessageText": "'{name}' listesini silmek istediğinizden emin misiniz?",
|
||||||
"DeleteReleaseProfile": "Yayımlama Profilini Sil",
|
"DeleteReleaseProfile": "Yayımlama Profilini Sil",
|
||||||
"DeleteSelectedIndexers": "Dizinleyicileri Sil",
|
"DeleteSelectedIndexers": "İndeksleyicileri Sil",
|
||||||
"Directory": "Dizin",
|
"Directory": "Dizin",
|
||||||
"Donate": "Bağış yap",
|
"Donate": "Bağış yap",
|
||||||
"DownloadClientDownloadStationValidationFolderMissing": "Klasör mevcut değil",
|
"DownloadClientDownloadStationValidationFolderMissing": "Klasör mevcut değil",
|
||||||
@@ -176,11 +176,11 @@
|
|||||||
"DeleteConditionMessageText": "'{name}' koşulunu silmek istediğinizden emin misiniz?",
|
"DeleteConditionMessageText": "'{name}' koşulunu silmek istediğinizden emin misiniz?",
|
||||||
"DeleteImportListExclusionMessageText": "Bu içe aktarma listesi hariç tutma işlemini silmek istediğinizden emin misiniz?",
|
"DeleteImportListExclusionMessageText": "Bu içe aktarma listesi hariç tutma işlemini silmek istediğinizden emin misiniz?",
|
||||||
"DeleteQualityProfileMessageText": "'{name}' kalite profilini silmek istediğinizden emin misiniz?",
|
"DeleteQualityProfileMessageText": "'{name}' kalite profilini silmek istediğinizden emin misiniz?",
|
||||||
"DeleteSelectedIndexersMessageText": "Seçilen {count} dizinleyiciyi silmek istediğinizden emin misiniz?",
|
"DeleteSelectedIndexersMessageText": "Seçilen {count} indeksleyiciyi silmek istediğinizden emin misiniz?",
|
||||||
"DownloadClientDelugeValidationLabelPluginFailureDetail": "{appName}, etiketi {clientName} uygulamasına ekleyemedi.",
|
"DownloadClientDelugeValidationLabelPluginFailureDetail": "{appName}, etiketi {clientName} uygulamasına ekleyemedi.",
|
||||||
"DownloadClientDownloadStationProviderMessage": "DSM hesabınızda 2 Faktörlü Kimlik Doğrulama etkinleştirilmişse {appName}, Download Station'a bağlanamaz",
|
"DownloadClientDownloadStationProviderMessage": "DSM hesabınızda 2 Faktörlü Kimlik Doğrulama etkinleştirilmişse {appName}, Download Station'a bağlanamaz",
|
||||||
"DownloadClientDownloadStationValidationApiVersion": "Download Station API sürümü desteklenmiyor; en az {requiredVersion} olmalıdır. {minVersion}'dan {maxVersion}'a kadar destekler",
|
"DownloadClientDownloadStationValidationApiVersion": "Download Station API sürümü desteklenmiyor; en az {requiredVersion} olmalıdır. {minVersion}'dan {maxVersion}'a kadar destekler",
|
||||||
"DownloadClientDownloadStationValidationNoDefaultDestination": "Varsayılan hedef yok",
|
"DownloadClientDownloadStationValidationNoDefaultDestination": "Varsayılan hedef bulunamadı",
|
||||||
"DownloadClientFloodSettingsAdditionalTagsHelpText": "Medyanın özelliklerini etiket olarak ekler. İpuçları örnektir.",
|
"DownloadClientFloodSettingsAdditionalTagsHelpText": "Medyanın özelliklerini etiket olarak ekler. İpuçları örnektir.",
|
||||||
"DownloadClientFloodSettingsPostImportTagsHelpText": "İndirmelere içe aktarıldıktan sonra etiket ekler.",
|
"DownloadClientFloodSettingsPostImportTagsHelpText": "İndirmelere içe aktarıldıktan sonra etiket ekler.",
|
||||||
"DownloadClientFloodSettingsUrlBaseHelpText": "Flood API'sine {url} gibi bir önek ekler",
|
"DownloadClientFloodSettingsUrlBaseHelpText": "Flood API'sine {url} gibi bir önek ekler",
|
||||||
@@ -195,13 +195,13 @@
|
|||||||
"DownloadClientDelugeValidationLabelPluginFailure": "Etiket yapılandırılması başarısız oldu",
|
"DownloadClientDelugeValidationLabelPluginFailure": "Etiket yapılandırılması başarısız oldu",
|
||||||
"DownloadClientDownloadStationValidationSharedFolderMissing": "Paylaşılan klasör mevcut değil",
|
"DownloadClientDownloadStationValidationSharedFolderMissing": "Paylaşılan klasör mevcut değil",
|
||||||
"DeleteImportList": "İçe Aktarma Listesini Sil",
|
"DeleteImportList": "İçe Aktarma Listesini Sil",
|
||||||
"IndexerPriorityHelpText": "Dizinleyici Önceliği (En Yüksek) 1'den (En Düşük) 50'ye kadar. Varsayılan: 25'dir. Eşit olmayan yayınlar için eşitlik bozucu olarak yayınlar alınırken kullanılan {appName}, RSS Senkronizasyonu ve Arama için etkinleştirilmiş tüm dizin oluşturucuları kullanmaya devam edecek",
|
"IndexerPriorityHelpText": "İndeksleyici Önceliği (En Yüksek) 1'den (En Düşük) 50'ye kadar. Varsayılan: 25'dir. Eşit olmayan yayınlar için eşitlik bozucu olarak yayınlar alınırken kullanılan {appName}, RSS Senkronizasyonu ve Arama için etkinleştirilmiş tüm indeksleyicileri kullanmaya devam edecek",
|
||||||
"DisabledForLocalAddresses": "Yerel Adreslerde Devre Dışı Bırak",
|
"DisabledForLocalAddresses": "Yerel Adreslerde Devre Dışı Bırak",
|
||||||
"DownloadClientDelugeValidationLabelPluginInactive": "Etiket eklentisi etkinleştirilmedi",
|
"DownloadClientDelugeValidationLabelPluginInactive": "Etiket eklentisi etkinleştirilmedi",
|
||||||
"DownloadClientDelugeValidationLabelPluginInactiveDetail": "Kategorileri kullanmak için {clientName} uygulamasında Etiket eklentisini etkinleştirmiş olmanız gerekir.",
|
"DownloadClientDelugeValidationLabelPluginInactiveDetail": "Kategorileri kullanmak için {clientName} uygulamasında Etiket eklentisini etkinleştirmiş olmanız gerekir.",
|
||||||
"DownloadClientDownloadStationValidationNoDefaultDestinationDetail": "Diskstation'ınızda {username} olarak oturum açmalı ve BT/HTTP/FTP/NZB -> Konum altında DownloadStation ayarlarında manuel olarak ayarlamalısınız.",
|
"DownloadClientDownloadStationValidationNoDefaultDestinationDetail": "Diskstation'ınızda {username} olarak oturum açmalı ve BT/HTTP/FTP/NZB -> Konum altında DownloadStation ayarlarında manuel olarak ayarlamalısınız.",
|
||||||
"DownloadClientDownloadStationValidationSharedFolderMissingDetail": "Diskstation'da '{sharedFolder}' adında bir Paylaşımlı Klasör yok, bunu doğru belirttiğinizden emin misiniz?",
|
"DownloadClientDownloadStationValidationSharedFolderMissingDetail": "Diskstation'da '{sharedFolder}' adında bir Paylaşımlı Klasör yok, bunu doğru belirttiğinizden emin misiniz?",
|
||||||
"DownloadClientFloodSettingsRemovalInfo": "{appName}, Ayarlar -> Dizinleyiciler'deki geçerli başlangıç ölçütlerine göre torrentlerin otomatik olarak kaldırılmasını sağlar",
|
"DownloadClientFloodSettingsRemovalInfo": "{appName}, Ayarlar -> İndeksleyiciler'deki geçerli başlangıç ölçütlerine göre torrentlerin otomatik olarak kaldırılmasını sağlar",
|
||||||
"Database": "Veri tabanı",
|
"Database": "Veri tabanı",
|
||||||
"DelayProfileProtocol": "Protokol: {preferredProtocol}",
|
"DelayProfileProtocol": "Protokol: {preferredProtocol}",
|
||||||
"DownloadClientDownloadStationValidationFolderMissingDetail": "'{downloadDir}' klasörü mevcut değil, '{sharedFolder}' Paylaşımlı Klasöründe manuel olarak oluşturulması gerekiyor.",
|
"DownloadClientDownloadStationValidationFolderMissingDetail": "'{downloadDir}' klasörü mevcut değil, '{sharedFolder}' Paylaşımlı Klasöründe manuel olarak oluşturulması gerekiyor.",
|
||||||
@@ -321,7 +321,7 @@
|
|||||||
"DownloadClientRemovesCompletedDownloadsHealthCheckMessage": "{downloadClientName} indirme istemcisi, tamamlanan indirmeleri kaldıracak şekilde ayarlandı. Bu, indirilenlerin {appName} içe aktarılmadan önce istemcinizden kaldırılmasına neden olabilir.",
|
"DownloadClientRemovesCompletedDownloadsHealthCheckMessage": "{downloadClientName} indirme istemcisi, tamamlanan indirmeleri kaldıracak şekilde ayarlandı. Bu, indirilenlerin {appName} içe aktarılmadan önce istemcinizden kaldırılmasına neden olabilir.",
|
||||||
"DownloadClientQbittorrentTorrentStatePathError": "İçe Aktarılamıyor. Yol, istemci tabanlı indirme dizini ile eşleşiyor, bu torrent için 'Üst düzey klasörü tut' seçeneği devre dışı bırakılmış olabilir veya 'Torrent İçerik Düzeni' 'Orijinal' veya 'Alt Klasör Oluştur' olarak ayarlanmamış olabilir mi?",
|
"DownloadClientQbittorrentTorrentStatePathError": "İçe Aktarılamıyor. Yol, istemci tabanlı indirme dizini ile eşleşiyor, bu torrent için 'Üst düzey klasörü tut' seçeneği devre dışı bırakılmış olabilir veya 'Torrent İçerik Düzeni' 'Orijinal' veya 'Alt Klasör Oluştur' olarak ayarlanmamış olabilir mi?",
|
||||||
"DownloadClientQbittorrentValidationRemovesAtRatioLimit": "qBittorrent, Torrentleri Paylaşım Oranı Sınırına ulaştıklarında kaldıracak şekilde yapılandırılmıştır",
|
"DownloadClientQbittorrentValidationRemovesAtRatioLimit": "qBittorrent, Torrentleri Paylaşım Oranı Sınırına ulaştıklarında kaldıracak şekilde yapılandırılmıştır",
|
||||||
"DownloadClientRTorrentProviderMessage": "rTorrent, başlangıç kriterlerini karşılayan torrentleri duraklatmaz. {appName}, torrentlerin otomatik olarak kaldırılmasını Ayarlar->Dizinleyiciler'deki geçerli tohum kriterlerine göre yalnızca Tamamlandı Kaldırma etkinleştirildiğinde gerçekleştirecektir. İçe aktardıktan sonra, davranışı özelleştirmek için rTorrent komut dosyalarında kullanılabilen {importedView}'ı bir rTorrent görünümü olarak ayarlayacaktır.",
|
"DownloadClientRTorrentProviderMessage": "rTorrent, başlangıç kriterlerini karşılayan torrentleri duraklatmaz. {appName}, torrentlerin otomatik olarak kaldırılmasını Ayarlar->İndeksleyiciler'deki geçerli tohum kriterlerine göre yalnızca Tamamlandı Kaldırma etkinleştirildiğinde gerçekleştirecektir. İçe aktardıktan sonra, davranışı özelleştirmek için rTorrent komut dosyalarında kullanılabilen {importedView}'ı bir rTorrent görünümü olarak ayarlayacaktır.",
|
||||||
"DownloadClientValidationAuthenticationFailureDetail": "Kullanıcı adınızı ve şifrenizi kontrol edin. Ayrıca, {appName} çalıştıran ana bilgisayarın, {clientName} yapılandırmasındaki WhiteList sınırlamaları nedeniyle {clientName} erişiminin engellenip engellenmediğini de doğrulayın.",
|
"DownloadClientValidationAuthenticationFailureDetail": "Kullanıcı adınızı ve şifrenizi kontrol edin. Ayrıca, {appName} çalıştıran ana bilgisayarın, {clientName} yapılandırmasındaki WhiteList sınırlamaları nedeniyle {clientName} erişiminin engellenip engellenmediğini de doğrulayın.",
|
||||||
"DownloadStationStatusExtracting": "Çıkarılıyor: %{progress}",
|
"DownloadStationStatusExtracting": "Çıkarılıyor: %{progress}",
|
||||||
"DownloadClientNzbVortexMultipleFilesMessage": "İndirme birden fazla dosya içeriyor ve bir iş klasöründe değil: {outputPath}",
|
"DownloadClientNzbVortexMultipleFilesMessage": "İndirme birden fazla dosya içeriyor ve bir iş klasöründe değil: {outputPath}",
|
||||||
@@ -392,7 +392,7 @@
|
|||||||
"MoveAutomatically": "Otomatik Olarak Taşı",
|
"MoveAutomatically": "Otomatik Olarak Taşı",
|
||||||
"MustContainHelpText": "Yayın, bu terimlerden en az birini içermelidir (büyük / küçük harfe duyarsız)",
|
"MustContainHelpText": "Yayın, bu terimlerden en az birini içermelidir (büyük / küçük harfe duyarsız)",
|
||||||
"NotificationStatusAllClientHealthCheckMessage": "Arızalar nedeniyle tüm bildirimler kullanılamıyor",
|
"NotificationStatusAllClientHealthCheckMessage": "Arızalar nedeniyle tüm bildirimler kullanılamıyor",
|
||||||
"EditSelectedIndexers": "Seçili Dizinleyicileri Düzenle",
|
"EditSelectedIndexers": "Seçili İndeksleyicileri Düzenle",
|
||||||
"EnableProfileHelpText": "Yayımlama profilini etkinleştirmek için işaretleyin",
|
"EnableProfileHelpText": "Yayımlama profilini etkinleştirmek için işaretleyin",
|
||||||
"EnableRssHelpText": "{appName}, RSS Senkronizasyonu aracılığıyla düzenli periyotlarda yayın değişikliği aradığında kullanacak",
|
"EnableRssHelpText": "{appName}, RSS Senkronizasyonu aracılığıyla düzenli periyotlarda yayın değişikliği aradığında kullanacak",
|
||||||
"FormatTimeSpanDays": "{days}g {time}",
|
"FormatTimeSpanDays": "{days}g {time}",
|
||||||
@@ -407,7 +407,7 @@
|
|||||||
"FormatRuntimeHours": "{hours}s",
|
"FormatRuntimeHours": "{hours}s",
|
||||||
"LanguagesLoadError": "Diller yüklenemiyor",
|
"LanguagesLoadError": "Diller yüklenemiyor",
|
||||||
"ListWillRefreshEveryInterval": "Liste yenileme periyodu {refreshInterval}dır",
|
"ListWillRefreshEveryInterval": "Liste yenileme periyodu {refreshInterval}dır",
|
||||||
"ManageIndexers": "Dizinleyicileri Yönet",
|
"ManageIndexers": "İndeksleyicileri Yönet",
|
||||||
"ManualGrab": "Manuel Alımlarda",
|
"ManualGrab": "Manuel Alımlarda",
|
||||||
"DownloadClientsSettingsSummary": "İndirme İstemcileri, indirme işlemleri ve uzaktan yol eşlemeleri",
|
"DownloadClientsSettingsSummary": "İndirme İstemcileri, indirme işlemleri ve uzaktan yol eşlemeleri",
|
||||||
"DownloadClients": "İndirme İstemcileri",
|
"DownloadClients": "İndirme İstemcileri",
|
||||||
@@ -445,7 +445,7 @@
|
|||||||
"ManageLists": "Listeleri Yönet",
|
"ManageLists": "Listeleri Yönet",
|
||||||
"MediaInfoFootNote": "Full/AudioLanguages/SubtitleLanguages, dosya adında yer alan dilleri filtrelemenize olanak tanıyan bir `:EN+DE` son ekini destekler. Belirli dilleri hariç tutmak için '-DE'yi kullanın. `+` (örneğin `:EN+`) eklenmesi, hariç tutulan dillere bağlı olarak `[EN]`/`[EN+--]`/`[--]` sonucunu verecektir. Örneğin `{MediaInfo Full:EN+DE}`.",
|
"MediaInfoFootNote": "Full/AudioLanguages/SubtitleLanguages, dosya adında yer alan dilleri filtrelemenize olanak tanıyan bir `:EN+DE` son ekini destekler. Belirli dilleri hariç tutmak için '-DE'yi kullanın. `+` (örneğin `:EN+`) eklenmesi, hariç tutulan dillere bağlı olarak `[EN]`/`[EN+--]`/`[--]` sonucunu verecektir. Örneğin `{MediaInfo Full:EN+DE}`.",
|
||||||
"Never": "Asla",
|
"Never": "Asla",
|
||||||
"NoIndexersFound": "Dizinleyici bulunamadı",
|
"NoIndexersFound": "İndeksleyici bulunamadı",
|
||||||
"NotificationsAppriseSettingsConfigurationKeyHelpText": "Kalıcı Depolama Çözümü için Yapılandırma Anahtarı. Durum Bilgisi Olmayan URL'ler kullanılıyorsa boş bırakın.",
|
"NotificationsAppriseSettingsConfigurationKeyHelpText": "Kalıcı Depolama Çözümü için Yapılandırma Anahtarı. Durum Bilgisi Olmayan URL'ler kullanılıyorsa boş bırakın.",
|
||||||
"NotificationsAppriseSettingsPasswordHelpText": "HTTP Temel Kimlik Doğrulama Parolası",
|
"NotificationsAppriseSettingsPasswordHelpText": "HTTP Temel Kimlik Doğrulama Parolası",
|
||||||
"NotificationsAppriseSettingsUsernameHelpText": "HTTP Temel Kimlik Doğrulama Kullanıcı Adı",
|
"NotificationsAppriseSettingsUsernameHelpText": "HTTP Temel Kimlik Doğrulama Kullanıcı Adı",
|
||||||
@@ -486,14 +486,14 @@
|
|||||||
"Test": "Test Et",
|
"Test": "Test Et",
|
||||||
"HealthMessagesInfoBox": "Satırın sonundaki wiki bağlantısını (kitap simgesi) tıklayarak veya [log kayıtlarınızı]({link}) kontrol ederek bu durum kontrolü mesajlarının nedeni hakkında daha fazla bilgi bulabilirsiniz. Bu mesajları yorumlamakta zorluk yaşıyorsanız aşağıdaki bağlantılardan destek ekibimize ulaşabilirsiniz.",
|
"HealthMessagesInfoBox": "Satırın sonundaki wiki bağlantısını (kitap simgesi) tıklayarak veya [log kayıtlarınızı]({link}) kontrol ederek bu durum kontrolü mesajlarının nedeni hakkında daha fazla bilgi bulabilirsiniz. Bu mesajları yorumlamakta zorluk yaşıyorsanız aşağıdaki bağlantılardan destek ekibimize ulaşabilirsiniz.",
|
||||||
"IndexerSettingsRejectBlocklistedTorrentHashes": "Alırken Engellenen Torrent Karmalarını Reddet",
|
"IndexerSettingsRejectBlocklistedTorrentHashes": "Alırken Engellenen Torrent Karmalarını Reddet",
|
||||||
"IndexerSettingsRejectBlocklistedTorrentHashesHelpText": "Bir torrent hash tarafından engellenirse, bazı dizinleyiciler için RSS / Arama sırasında düzgün bir şekilde reddedilmeyebilir, bunun etkinleştirilmesi, torrent alındıktan sonra, ancak istemciye gönderilmeden önce reddedilmesine izin verecektir.",
|
"IndexerSettingsRejectBlocklistedTorrentHashesHelpText": "Bir torrent hash tarafından engellenirse, bazı indeksleyiciler için RSS / Arama sırasında düzgün bir şekilde reddedilmeyebilir, bunun etkinleştirilmesi, torrent alındıktan sonra, ancak istemciye gönderilmeden önce reddedilmesine izin verecektir.",
|
||||||
"NotificationsAppriseSettingsConfigurationKey": "Apprise Yapılandırma Anahtarı",
|
"NotificationsAppriseSettingsConfigurationKey": "Apprise Yapılandırma Anahtarı",
|
||||||
"NotificationsAppriseSettingsNotificationType": "Apprise Bildirim Türü",
|
"NotificationsAppriseSettingsNotificationType": "Apprise Bildirim Türü",
|
||||||
"NotificationsGotifySettingsServerHelpText": "Gerekiyorsa http(s):// ve bağlantı noktası dahil olmak üzere Gotify sunucu URL'si",
|
"NotificationsGotifySettingsServerHelpText": "Gerekiyorsa http(s):// ve bağlantı noktası dahil olmak üzere Gotify sunucu URL'si",
|
||||||
"NotificationsJoinSettingsApiKeyHelpText": "Katıl hesap ayarlarınızdaki API Anahtarı (API'ye Katıl düğmesine tıklayın).",
|
"NotificationsJoinSettingsApiKeyHelpText": "Katıl hesap ayarlarınızdaki API Anahtarı (API'ye Katıl düğmesine tıklayın).",
|
||||||
"ImportScriptPathHelpText": "İçe aktarma için kullanılacak komut dosyasının yolu",
|
"ImportScriptPathHelpText": "İçe aktarma için kullanılacak komut dosyasının yolu",
|
||||||
"Label": "Etiket",
|
"Label": "Etiket",
|
||||||
"NoDelay": "Gecikme yok",
|
"NoDelay": "Gecikmesiz",
|
||||||
"NoImportListsFound": "İçe aktarma listesi bulunamadı",
|
"NoImportListsFound": "İçe aktarma listesi bulunamadı",
|
||||||
"FormatAgeMinute": "dakika",
|
"FormatAgeMinute": "dakika",
|
||||||
"FormatAgeMinutes": "dakika",
|
"FormatAgeMinutes": "dakika",
|
||||||
@@ -504,7 +504,7 @@
|
|||||||
"NotificationsKodiSettingsUpdateLibraryHelpText": "İçe Aktarma ve Yeniden Adlandırmada kitaplık güncellensin mi?",
|
"NotificationsKodiSettingsUpdateLibraryHelpText": "İçe Aktarma ve Yeniden Adlandırmada kitaplık güncellensin mi?",
|
||||||
"NotificationsNtfySettingsServerUrlHelpText": "Genel sunucuyu ({url}) kullanmak için boş bırakın",
|
"NotificationsNtfySettingsServerUrlHelpText": "Genel sunucuyu ({url}) kullanmak için boş bırakın",
|
||||||
"InteractiveImportLoadError": "Manuel içe aktarma öğeleri yüklenemiyor",
|
"InteractiveImportLoadError": "Manuel içe aktarma öğeleri yüklenemiyor",
|
||||||
"IndexerDownloadClientHelpText": "Bu dizinleyiciden almak için hangi indirme istemcisinin kullanılacağını belirtin",
|
"IndexerDownloadClientHelpText": "Bu indeksleyiciden almak için hangi indirme istemcisinin kullanılacağını belirtin",
|
||||||
"DeleteRemotePathMapping": "Uzak Yol Eşlemeyi Sil",
|
"DeleteRemotePathMapping": "Uzak Yol Eşlemeyi Sil",
|
||||||
"LastDuration": "Yürütme Süresi",
|
"LastDuration": "Yürütme Süresi",
|
||||||
"NotificationsSettingsUpdateMapPathsToSeriesHelpText": "{serviceName}, kitaplık yolu konumunu {appName}'den farklı gördüğünde seri yollarını değiştirmek için kullanılan {serviceName} yolu ('Kütüphaneyi Güncelle' gerektirir)",
|
"NotificationsSettingsUpdateMapPathsToSeriesHelpText": "{serviceName}, kitaplık yolu konumunu {appName}'den farklı gördüğünde seri yollarını değiştirmek için kullanılan {serviceName} yolu ('Kütüphaneyi Güncelle' gerektirir)",
|
||||||
@@ -526,7 +526,7 @@
|
|||||||
"BlocklistRelease": "Kara Liste Sürümü",
|
"BlocklistRelease": "Kara Liste Sürümü",
|
||||||
"CustomFormats": "Özel Formatlar",
|
"CustomFormats": "Özel Formatlar",
|
||||||
"DeleteDownloadClientMessageText": "'{name}' indirme istemcisini silmek istediğinizden emin misiniz?",
|
"DeleteDownloadClientMessageText": "'{name}' indirme istemcisini silmek istediğinizden emin misiniz?",
|
||||||
"DeleteIndexerMessageText": "'{name}' dizinleyicisini silmek istediğinizden emin misiniz?",
|
"DeleteIndexerMessageText": "'{name}' indeksleyicisini silmek istediğinizden emin misiniz?",
|
||||||
"OneMinute": "1 dakika",
|
"OneMinute": "1 dakika",
|
||||||
"TaskUserAgentTooltip": "API'yi çağıran uygulama tarafından sağlanan Kullanıcı Aracısı",
|
"TaskUserAgentTooltip": "API'yi çağıran uygulama tarafından sağlanan Kullanıcı Aracısı",
|
||||||
"SkipRedownload": "Yeniden İndirmeyi Atla",
|
"SkipRedownload": "Yeniden İndirmeyi Atla",
|
||||||
@@ -555,9 +555,9 @@
|
|||||||
"RemoveFailedDownloads": "Başarısız İndirmeleri Kaldır",
|
"RemoveFailedDownloads": "Başarısız İndirmeleri Kaldır",
|
||||||
"Scheduled": "Planlı",
|
"Scheduled": "Planlı",
|
||||||
"Underscore": "Vurgula",
|
"Underscore": "Vurgula",
|
||||||
"SetIndexerFlags": "Dizinleyici Bayraklarını Ayarla",
|
"SetIndexerFlags": "İndeksleyici Bayraklarını Ayarla",
|
||||||
"SetReleaseGroup": "Yayımlama Grubunu Ayarla",
|
"SetReleaseGroup": "Yayımlama Grubunu Ayarla",
|
||||||
"SetIndexerFlagsModalTitle": "{modalTitle} - Dizinleyici Bayraklarını Ayarla",
|
"SetIndexerFlagsModalTitle": "{modalTitle} - İndeksleyici Bayraklarını Ayarla",
|
||||||
"SslCertPassword": "SSL Sertifika Parolası",
|
"SslCertPassword": "SSL Sertifika Parolası",
|
||||||
"Rating": "Puan",
|
"Rating": "Puan",
|
||||||
"GrabRelease": "Yayın Alma",
|
"GrabRelease": "Yayın Alma",
|
||||||
@@ -615,7 +615,7 @@
|
|||||||
"DeleteNotificationMessageText": "'{name}' bildirimini silmek istediğinizden emin misiniz?",
|
"DeleteNotificationMessageText": "'{name}' bildirimini silmek istediğinizden emin misiniz?",
|
||||||
"Or": "veya",
|
"Or": "veya",
|
||||||
"OverrideGrabModalTitle": "Geçersiz Kıl ve Al - {title}",
|
"OverrideGrabModalTitle": "Geçersiz Kıl ve Al - {title}",
|
||||||
"PreferProtocol": "{preferredProtocol}'u tercih edin",
|
"PreferProtocol": "{preferredProtocol} Tercih Edin",
|
||||||
"PreferredProtocol": "Tercih Edilen Protokol",
|
"PreferredProtocol": "Tercih Edilen Protokol",
|
||||||
"PublishedDate": "Yayınlanma Tarihi",
|
"PublishedDate": "Yayınlanma Tarihi",
|
||||||
"RemoveQueueItem": "Kaldır - {sourceTitle}",
|
"RemoveQueueItem": "Kaldır - {sourceTitle}",
|
||||||
@@ -704,7 +704,7 @@
|
|||||||
"PreviouslyInstalled": "Daha Önce Kurulmuş",
|
"PreviouslyInstalled": "Daha Önce Kurulmuş",
|
||||||
"QualityCutoffNotMet": "Kalite sınırı karşılanmadı",
|
"QualityCutoffNotMet": "Kalite sınırı karşılanmadı",
|
||||||
"QueueIsEmpty": "Kuyruk boş",
|
"QueueIsEmpty": "Kuyruk boş",
|
||||||
"ReleaseProfileIndexerHelpTextWarning": "Bir sürüm profilinde belirli bir dizinleyicinin ayarlanması, bu profilin yalnızca söz konusu dizinleyicinin yayınlarına uygulanmasına neden olur.",
|
"ReleaseProfileIndexerHelpTextWarning": "Bir sürüm profilinde belirli bir indeksleyicinin ayarlanması, bu profilin yalnızca söz konusu indeksleyicinin yayınlarına uygulanmasına neden olur.",
|
||||||
"ResetDefinitionTitlesHelpText": "Değerlerin yanı sıra tanım başlıklarını da sıfırlayın",
|
"ResetDefinitionTitlesHelpText": "Değerlerin yanı sıra tanım başlıklarını da sıfırlayın",
|
||||||
"SecretToken": "Gizlilik Token'ı",
|
"SecretToken": "Gizlilik Token'ı",
|
||||||
"SetReleaseGroupModalTitle": "{modalTitle} - Yayımlama Grubunu Ayarla",
|
"SetReleaseGroupModalTitle": "{modalTitle} - Yayımlama Grubunu Ayarla",
|
||||||
@@ -720,7 +720,7 @@
|
|||||||
"Uptime": "Çalışma süresi",
|
"Uptime": "Çalışma süresi",
|
||||||
"RemotePath": "Uzak Yol",
|
"RemotePath": "Uzak Yol",
|
||||||
"File": "Dosya",
|
"File": "Dosya",
|
||||||
"ReleaseProfileIndexerHelpText": "Profilin hangi dizinleyiciye uygulanacağını belirtin",
|
"ReleaseProfileIndexerHelpText": "Profilin hangi indeksleyiciye uygulanacağını belirtin",
|
||||||
"TablePageSize": "Sayfa Boyutu",
|
"TablePageSize": "Sayfa Boyutu",
|
||||||
"NotificationsSynologyValidationTestFailed": "Synology veya synoındex mevcut değil",
|
"NotificationsSynologyValidationTestFailed": "Synology veya synoındex mevcut değil",
|
||||||
"NotificationsTwitterSettingsAccessTokenSecret": "Erişim Token Gizliliği",
|
"NotificationsTwitterSettingsAccessTokenSecret": "Erişim Token Gizliliği",
|
||||||
@@ -736,7 +736,7 @@
|
|||||||
"RemoveQueueItemRemovalMethod": "Kaldırma Yöntemi",
|
"RemoveQueueItemRemovalMethod": "Kaldırma Yöntemi",
|
||||||
"RemoveQueueItemRemovalMethodHelpTextWarning": "'İndirme İstemcisinden Kaldır', indirme işlemini ve dosyaları indirme istemcisinden kaldıracaktır.",
|
"RemoveQueueItemRemovalMethodHelpTextWarning": "'İndirme İstemcisinden Kaldır', indirme işlemini ve dosyaları indirme istemcisinden kaldıracaktır.",
|
||||||
"RemoveSelectedItems": "Seçili öğeleri kaldır",
|
"RemoveSelectedItems": "Seçili öğeleri kaldır",
|
||||||
"SelectIndexerFlags": "Dizinleyici Bayraklarını Seçin",
|
"SelectIndexerFlags": "İndeksleyici Bayraklarını Seçin",
|
||||||
"Started": "Başlatıldı",
|
"Started": "Başlatıldı",
|
||||||
"Size": "Boyut",
|
"Size": "Boyut",
|
||||||
"SupportedCustomConditions": "{appName}, aşağıdaki yayın özelliklerine göre özel koşulları destekler.",
|
"SupportedCustomConditions": "{appName}, aşağıdaki yayın özelliklerine göre özel koşulları destekler.",
|
||||||
@@ -784,22 +784,22 @@
|
|||||||
"NotificationsSignalSettingsPasswordHelpText": "Signal-api'ye yönelik istekleri doğrulamak için kullanılan şifre",
|
"NotificationsSignalSettingsPasswordHelpText": "Signal-api'ye yönelik istekleri doğrulamak için kullanılan şifre",
|
||||||
"NotificationsSimplepushSettingsEventHelpText": "Anlık bildirimlerin davranışını özelleştirme",
|
"NotificationsSimplepushSettingsEventHelpText": "Anlık bildirimlerin davranışını özelleştirme",
|
||||||
"NotificationsSlackSettingsUsernameHelpText": "Slack'e gönderilecek kullanıcı adı",
|
"NotificationsSlackSettingsUsernameHelpText": "Slack'e gönderilecek kullanıcı adı",
|
||||||
"QueueFilterHasNoItems": "Seçilen kuyruk filtresinde hiç öğe yok",
|
"QueueFilterHasNoItems": "Seçilen kuyruk filtresinde hiç öğe bulunamadı",
|
||||||
"ReleaseGroups": "Yayımlama Grupları",
|
"ReleaseGroups": "Yayımlama Grupları",
|
||||||
"IncludeCustomFormatWhenRenamingHelpText": "Özel formatları yeniden adlandırma formatına dahil et",
|
"IncludeCustomFormatWhenRenamingHelpText": "Özel formatları yeniden adlandırma formatına dahil et",
|
||||||
"Logging": "Loglama",
|
"Logging": "Loglama",
|
||||||
"MinutesSixty": "60 Dakika: {sixty}",
|
"MinutesSixty": "60 Dakika: {sixty}",
|
||||||
"SelectDownloadClientModalTitle": "{modalTitle} - İndirme İstemcisini Seçin",
|
"SelectDownloadClientModalTitle": "{modalTitle} - İndirme İstemcisini Seçin",
|
||||||
"Repack": "Yeniden paketle",
|
"Repack": "Yeniden paketle",
|
||||||
"IndexerFlags": "Dizinleyici Bayrakları",
|
"IndexerFlags": "İndeksleyici Bayrakları",
|
||||||
"Indexer": "Dizinleyici",
|
"Indexer": "İndeksleyici",
|
||||||
"Indexers": "Dizinleyiciler",
|
"Indexers": "İndeksleyiciler",
|
||||||
"IndexerPriority": "Dizinleyici Önceliği",
|
"IndexerPriority": "İndeksleyici Önceliği",
|
||||||
"IndexerOptionsLoadError": "Dizinleyici seçenekleri yüklenemiyor",
|
"IndexerOptionsLoadError": "İndeksleyici seçenekleri yüklenemiyor",
|
||||||
"IndexerSettings": "Dizinleyici Ayarları",
|
"IndexerSettings": "İndeksleyici Ayarları",
|
||||||
"MustContain": "İçermeli",
|
"MustContain": "İçermeli",
|
||||||
"MustNotContain": "İçermemeli",
|
"MustNotContain": "İçermemeli",
|
||||||
"RssSyncIntervalHelpTextWarning": "Bu, tüm dizinleyiciler için geçerli olacaktır, lütfen onlar tarafından belirlenen kurallara uyun",
|
"RssSyncIntervalHelpTextWarning": "Bu, tüm indeksleyiciler için geçerli olacaktır, lütfen onlar tarafından belirlenen kurallara uyun",
|
||||||
"DownloadClientQbittorrentTorrentStateMissingFiles": "qBittorrent eksik dosya raporluyor",
|
"DownloadClientQbittorrentTorrentStateMissingFiles": "qBittorrent eksik dosya raporluyor",
|
||||||
"ImportListExclusions": "İçe Aktarma Listesinden Hariç Bırakılan(lar)",
|
"ImportListExclusions": "İçe Aktarma Listesinden Hariç Bırakılan(lar)",
|
||||||
"UiLanguage": "Arayüz Dili",
|
"UiLanguage": "Arayüz Dili",
|
||||||
@@ -820,7 +820,7 @@
|
|||||||
"Monitored": "Takip Ediliyor",
|
"Monitored": "Takip Ediliyor",
|
||||||
"MonitoredOnly": "Sadece Takip Edilen",
|
"MonitoredOnly": "Sadece Takip Edilen",
|
||||||
"External": "Harici",
|
"External": "Harici",
|
||||||
"MassSearchCancelWarning": "Bu işlem, {appName} yeniden başlatılmadan veya tüm dizin oluşturucularınız devre dışı bırakılmadan başlatılır ise iptal edilemez.",
|
"MassSearchCancelWarning": "Bu, {appName} uygulamasını yeniden başlatmadan veya tüm İndeksleyiciler devre dışı bırakılmadan başlatılır ise iptal edilemez.",
|
||||||
"IncludeUnmonitored": "Takip Edilmeyenleri Dahil Et",
|
"IncludeUnmonitored": "Takip Edilmeyenleri Dahil Et",
|
||||||
"MonitorSelected": "Seçilenleri Bırak",
|
"MonitorSelected": "Seçilenleri Bırak",
|
||||||
"MonitoredStatus": "Takip Edilen/Durum",
|
"MonitoredStatus": "Takip Edilen/Durum",
|
||||||
@@ -835,7 +835,7 @@
|
|||||||
"UpdateAutomaticallyHelpText": "Güncelleştirmeleri otomatik olarak indirip yükleyin. Sistem: Güncellemeler'den yükleme yapmaya devam edebileceksiniz",
|
"UpdateAutomaticallyHelpText": "Güncelleştirmeleri otomatik olarak indirip yükleyin. Sistem: Güncellemeler'den yükleme yapmaya devam edebileceksiniz",
|
||||||
"Wanted": "Arananlar",
|
"Wanted": "Arananlar",
|
||||||
"Cutoff": "Kesinti",
|
"Cutoff": "Kesinti",
|
||||||
"Required": "Gerekli",
|
"Required": "Zorunlu",
|
||||||
"AirsTbaOn": "Daha sonra duyurulacak {networkLabel}'de",
|
"AirsTbaOn": "Daha sonra duyurulacak {networkLabel}'de",
|
||||||
"AllFiles": "Tüm dosyalar",
|
"AllFiles": "Tüm dosyalar",
|
||||||
"AllSeriesAreHiddenByTheAppliedFilter": "Tüm sonuçlar uygulanan filtre tarafından gizlendi",
|
"AllSeriesAreHiddenByTheAppliedFilter": "Tüm sonuçlar uygulanan filtre tarafından gizlendi",
|
||||||
@@ -864,7 +864,7 @@
|
|||||||
"TomorrowAt": "Yarın {time}'da",
|
"TomorrowAt": "Yarın {time}'da",
|
||||||
"NoBlocklistItems": "Engellenenler listesi öğesi yok",
|
"NoBlocklistItems": "Engellenenler listesi öğesi yok",
|
||||||
"YesterdayAt": "Dün saat {time}'da",
|
"YesterdayAt": "Dün saat {time}'da",
|
||||||
"CustomFormatsSpecificationExceptLanguage": "Dil Dışında",
|
"CustomFormatsSpecificationExceptLanguage": "Dil Hariç",
|
||||||
"CustomFormatsSpecificationExceptLanguageHelpText": "Seçilen dil dışında herhangi bir dil mevcutsa eşleşir",
|
"CustomFormatsSpecificationExceptLanguageHelpText": "Seçilen dil dışında herhangi bir dil mevcutsa eşleşir",
|
||||||
"LastSearched": "Son Aranan",
|
"LastSearched": "Son Aranan",
|
||||||
"Enable": "Etkinleştir",
|
"Enable": "Etkinleştir",
|
||||||
@@ -958,7 +958,7 @@
|
|||||||
"DownloadClientRootFolderHealthCheckMessage": "İndirme istemcisi {downloadClientName}, indirmeleri kök klasöre yerleştirir {rootFolderPath}. Bir kök klasöre indirmemelisiniz.",
|
"DownloadClientRootFolderHealthCheckMessage": "İndirme istemcisi {downloadClientName}, indirmeleri kök klasöre yerleştirir {rootFolderPath}. Bir kök klasöre indirmemelisiniz.",
|
||||||
"DeleteBackup": "Yedeklemeyi Sil",
|
"DeleteBackup": "Yedeklemeyi Sil",
|
||||||
"CustomColonReplacementFormatHelpText": "İki nokta üst üste yerine kullanılacak karakterler",
|
"CustomColonReplacementFormatHelpText": "İki nokta üst üste yerine kullanılacak karakterler",
|
||||||
"CustomColonReplacement": "Özel Kolon Değişimi",
|
"CustomColonReplacement": "İki Nokta Üst Üste İşareti İçin Özel Değiştirme",
|
||||||
"CustomColonReplacementFormatHint": "İki Nokta (Harf) gibi geçerli dosya sistemi karakteri",
|
"CustomColonReplacementFormatHint": "İki Nokta (Harf) gibi geçerli dosya sistemi karakteri",
|
||||||
"CustomFormatsSpecificationReleaseGroup": "Yayın Grubu",
|
"CustomFormatsSpecificationReleaseGroup": "Yayın Grubu",
|
||||||
"CustomFormatsSpecificationResolution": "Çözünürlük",
|
"CustomFormatsSpecificationResolution": "Çözünürlük",
|
||||||
@@ -968,7 +968,7 @@
|
|||||||
"DeleteEmptySeriesFoldersHelpText": "Disk taraması sırasında ve bölüm dosyaları silindiğinde boş dizi ve sezon klasörlerini silin",
|
"DeleteEmptySeriesFoldersHelpText": "Disk taraması sırasında ve bölüm dosyaları silindiğinde boş dizi ve sezon klasörlerini silin",
|
||||||
"DeleteEpisodesFiles": "{episodeFileCount} Bölüm Dosyasını Sil",
|
"DeleteEpisodesFiles": "{episodeFileCount} Bölüm Dosyasını Sil",
|
||||||
"DeleteImportListExclusion": "İçe Aktarma Listesi Hariç Tutmasını Sil",
|
"DeleteImportListExclusion": "İçe Aktarma Listesi Hariç Tutmasını Sil",
|
||||||
"DeleteIndexer": "Dizinleyiciyi Sil",
|
"DeleteIndexer": "İndeksleyiciyi Sil",
|
||||||
"Docker": "Docker",
|
"Docker": "Docker",
|
||||||
"DockerUpdater": "Güncellemeyi almak için docker konteynerini güncelleyin",
|
"DockerUpdater": "Güncellemeyi almak için docker konteynerini güncelleyin",
|
||||||
"DeleteSelectedSeries": "Seçili Serileri Sil",
|
"DeleteSelectedSeries": "Seçili Serileri Sil",
|
||||||
@@ -1008,10 +1008,10 @@
|
|||||||
"Debug": "Hata ayıklama",
|
"Debug": "Hata ayıklama",
|
||||||
"DailyEpisodeTypeFormat": "Tarih ({format})",
|
"DailyEpisodeTypeFormat": "Tarih ({format})",
|
||||||
"DeleteSeriesFolders": "Dizi Klasörlerini Sil",
|
"DeleteSeriesFolders": "Dizi Klasörlerini Sil",
|
||||||
"Discord": "Uyuşmazlık",
|
"Discord": "Discord",
|
||||||
"DeleteSeriesFoldersHelpText": "Dizi klasörlerini ve tüm içeriklerini silin",
|
"DeleteSeriesFoldersHelpText": "Dizi klasörlerini ve tüm içeriklerini silin",
|
||||||
"QualitySettings": "Kalite Ayarları",
|
"QualitySettings": "Kalite Ayarları",
|
||||||
"ReplaceWithSpaceDashSpace": "Space Dash Space ile değiştirin",
|
"ReplaceWithSpaceDashSpace": "Boşluk, Tire ve Boşluk ile Değiştir",
|
||||||
"Continuing": "Devam Ediyor",
|
"Continuing": "Devam Ediyor",
|
||||||
"CleanLibraryLevel": "Kütüphane Seviyesini Temizle",
|
"CleanLibraryLevel": "Kütüphane Seviyesini Temizle",
|
||||||
"ClickToChangeSeason": "Sezonu değiştirmek için tıklayın",
|
"ClickToChangeSeason": "Sezonu değiştirmek için tıklayın",
|
||||||
@@ -1084,7 +1084,7 @@
|
|||||||
"EditDelayProfile": "Gecikme Profilini Düzenle",
|
"EditDelayProfile": "Gecikme Profilini Düzenle",
|
||||||
"EventType": "Etkinlik tipi",
|
"EventType": "Etkinlik tipi",
|
||||||
"ImportedTo": "İçeri Aktarıldı",
|
"ImportedTo": "İçeri Aktarıldı",
|
||||||
"IndexerDownloadClientHealthCheckMessage": "Geçersiz indirme istemcilerine sahip dizinleyiciler: {indexerNames}.",
|
"IndexerDownloadClientHealthCheckMessage": "Geçersiz indirme istemcilerine sahip indeksleyiciler: {indexerNames}.",
|
||||||
"Component": "Bileşen",
|
"Component": "Bileşen",
|
||||||
"Connection": "Bağlantılar",
|
"Connection": "Bağlantılar",
|
||||||
"Reorder": "Yeniden sırala",
|
"Reorder": "Yeniden sırala",
|
||||||
@@ -1188,7 +1188,7 @@
|
|||||||
"DeleteSeriesFolderEpisodeCount": "{episodeFileCount} bölüm dosyası toplamı {size}",
|
"DeleteSeriesFolderEpisodeCount": "{episodeFileCount} bölüm dosyası toplamı {size}",
|
||||||
"DestinationPath": "Hedef yol",
|
"DestinationPath": "Hedef yol",
|
||||||
"Disabled": "Devre dışı",
|
"Disabled": "Devre dışı",
|
||||||
"ColonReplacementFormatHelpText": "{appName}'ın kolon değişimini nasıl işlediğini değiştirin",
|
"ColonReplacementFormatHelpText": "{appName} uygulamasının iki nokta üst üste işaretini değiştirme ayarı",
|
||||||
"DeleteTag": "Etiketi Sil",
|
"DeleteTag": "Etiketi Sil",
|
||||||
"NamingSettingsLoadError": "Adlandırma ayarları yüklenemiyor",
|
"NamingSettingsLoadError": "Adlandırma ayarları yüklenemiyor",
|
||||||
"NotificationTriggers": "Bildirim Tetikleyicileri",
|
"NotificationTriggers": "Bildirim Tetikleyicileri",
|
||||||
@@ -1296,7 +1296,7 @@
|
|||||||
"DeleteSelectedEpisodeFilesHelpText": "Seçili bölüm dosyalarını silmek istediğinizden emin misiniz?",
|
"DeleteSelectedEpisodeFilesHelpText": "Seçili bölüm dosyalarını silmek istediğinizden emin misiniz?",
|
||||||
"DownloadClientCheckUnableToCommunicateWithHealthCheckMessage": "{downloadClientName} ile iletişim kurulamıyor. {errorMessage}",
|
"DownloadClientCheckUnableToCommunicateWithHealthCheckMessage": "{downloadClientName} ile iletişim kurulamıyor. {errorMessage}",
|
||||||
"DownloadClientSettingsRecentPriorityEpisodeHelpText": "Son 14 gün içinde yayınlanan bölümleri almaya öncelik verin",
|
"DownloadClientSettingsRecentPriorityEpisodeHelpText": "Son 14 gün içinde yayınlanan bölümleri almaya öncelik verin",
|
||||||
"EnableInteractiveSearchHelpTextWarning": "Bu dizinleyici ile arama desteklenmiyor",
|
"EnableInteractiveSearchHelpTextWarning": "Bu indeksleyici ile arama desteklenmiyor",
|
||||||
"EpisodeAirDate": "Bölüm Yayın Tarihi",
|
"EpisodeAirDate": "Bölüm Yayın Tarihi",
|
||||||
"EnableColorImpairedModeHelpText": "Renk engelli kullanıcıların renkleri daha iyi ayırt edebilmelerini sağlamak için değiştirilmiş stil",
|
"EnableColorImpairedModeHelpText": "Renk engelli kullanıcıların renkleri daha iyi ayırt edebilmelerini sağlamak için değiştirilmiş stil",
|
||||||
"EnableRss": "RSS'yi etkinleştir",
|
"EnableRss": "RSS'yi etkinleştir",
|
||||||
@@ -1318,8 +1318,8 @@
|
|||||||
"ImportList": "Listeler",
|
"ImportList": "Listeler",
|
||||||
"ImportListExclusionsLoadError": "Hariç Tutulanlar Listesi yüklenemiyor",
|
"ImportListExclusionsLoadError": "Hariç Tutulanlar Listesi yüklenemiyor",
|
||||||
"ImportLists": "Listeler",
|
"ImportLists": "Listeler",
|
||||||
"IndexersLoadError": "Dizinleyiciler yüklenemiyor",
|
"IndexersLoadError": "İndeksleyiciler yüklenemiyor",
|
||||||
"IndexersSettingsSummary": "Dizinleyiciler ve yayımlama kısıtlamaları",
|
"IndexersSettingsSummary": "İndeksleyiciler ve indeksleyici seçenekleri",
|
||||||
"InteractiveImport": "Etkileşimli İçe Aktarma",
|
"InteractiveImport": "Etkileşimli İçe Aktarma",
|
||||||
"InteractiveImportNoLanguage": "Seçilen her dosya için dil seçilmelidir",
|
"InteractiveImportNoLanguage": "Seçilen her dosya için dil seçilmelidir",
|
||||||
"InteractiveSearch": "Etkileşimli Arama",
|
"InteractiveSearch": "Etkileşimli Arama",
|
||||||
@@ -1360,12 +1360,12 @@
|
|||||||
"NoLeaveIt": "Hayır, Bırak",
|
"NoLeaveIt": "Hayır, Bırak",
|
||||||
"NoLimitForAnyRuntime": "Herhangi bir çalışma zamanı için sınır yok",
|
"NoLimitForAnyRuntime": "Herhangi bir çalışma zamanı için sınır yok",
|
||||||
"NoLinks": "Bağlantı Yok",
|
"NoLinks": "Bağlantı Yok",
|
||||||
"NoLogFiles": "Log kayıt dosyası henüz yok",
|
"NoLogFiles": "Log kayıt dosyası henüz oluşturulmadı",
|
||||||
"NoMatchFound": "Eşleşme bulunamadı!",
|
"NoMatchFound": "Eşleşme bulunamadı!",
|
||||||
"NoMinimumForAnyRuntime": "Herhangi bir çalışma süresi için minimum değer yok",
|
"NoMinimumForAnyRuntime": "Herhangi bir çalışma süresi için minimum değer yok",
|
||||||
"NoResultsFound": "Sonuç bulunamadı",
|
"NoResultsFound": "Sonuç bulunamadı",
|
||||||
"NoTagsHaveBeenAddedYet": "Henüz etiket eklenmedi",
|
"NoTagsHaveBeenAddedYet": "Henüz etiket eklenmedi",
|
||||||
"NoUpdatesAreAvailable": "Güncelleme yok",
|
"NoUpdatesAreAvailable": "Güncelleme bulunamadı",
|
||||||
"None": "Yok",
|
"None": "Yok",
|
||||||
"NotificationsGotifySettingsPreferredMetadataLink": "Tercih Edilen Meta Veri Bağlantısı",
|
"NotificationsGotifySettingsPreferredMetadataLink": "Tercih Edilen Meta Veri Bağlantısı",
|
||||||
"NotificationsGotifySettingsPreferredMetadataLinkHelpText": "Yalnızca tek bir bağlantıyı destekleyen istemciler için meta veri bağlantısı",
|
"NotificationsGotifySettingsPreferredMetadataLinkHelpText": "Yalnızca tek bir bağlantıyı destekleyen istemciler için meta veri bağlantısı",
|
||||||
@@ -1435,8 +1435,8 @@
|
|||||||
"RenameFiles": "Yeniden Adlandır",
|
"RenameFiles": "Yeniden Adlandır",
|
||||||
"Renamed": "Yeniden adlandırıldı",
|
"Renamed": "Yeniden adlandırıldı",
|
||||||
"Replace": "Değiştir",
|
"Replace": "Değiştir",
|
||||||
"ReplaceWithDash": "Dash ile değiştir",
|
"ReplaceWithDash": "Tire ile değiştir",
|
||||||
"ReplaceWithSpaceDash": "Space Dash ile değiştirin",
|
"ReplaceWithSpaceDash": "Tire ve Boşluk ile Değiştir",
|
||||||
"RequiredHelpText": "Özel formatın uygulanabilmesi için bu {implementationName} koşulunun eşleşmesi gerekir. Aksi takdirde tek bir {implementationName} eşleşmesi yeterlidir.",
|
"RequiredHelpText": "Özel formatın uygulanabilmesi için bu {implementationName} koşulunun eşleşmesi gerekir. Aksi takdirde tek bir {implementationName} eşleşmesi yeterlidir.",
|
||||||
"RestartRequiredHelpTextWarning": "Etkili olması için yeniden başlatma gerektirir",
|
"RestartRequiredHelpTextWarning": "Etkili olması için yeniden başlatma gerektirir",
|
||||||
"RetentionHelpText": "Yalnızca Usenet: Sınırsız saklamaya ayarlamak için sıfıra ayarlayın",
|
"RetentionHelpText": "Yalnızca Usenet: Sınırsız saklamaya ayarlamak için sıfıra ayarlayın",
|
||||||
@@ -1495,7 +1495,7 @@
|
|||||||
"Tasks": "Görevler",
|
"Tasks": "Görevler",
|
||||||
"TestAll": "Tümünü Test Et",
|
"TestAll": "Tümünü Test Et",
|
||||||
"TestAllClients": "Tüm İstemcileri Test Et",
|
"TestAllClients": "Tüm İstemcileri Test Et",
|
||||||
"TestAllIndexers": "Dizinleyicileri Test Et",
|
"TestAllIndexers": "İndeksleyicileri Test Et",
|
||||||
"TestAllLists": "Tüm Listeleri Test Et",
|
"TestAllLists": "Tüm Listeleri Test Et",
|
||||||
"Time": "Zaman",
|
"Time": "Zaman",
|
||||||
"TimeFormat": "Zaman formatı",
|
"TimeFormat": "Zaman formatı",
|
||||||
@@ -1658,9 +1658,9 @@
|
|||||||
"ImportListsSimklSettingsUserListTypeHold": "Tut",
|
"ImportListsSimklSettingsUserListTypeHold": "Tut",
|
||||||
"ImportListsSimklSettingsUserListTypeWatching": "İzlenen",
|
"ImportListsSimklSettingsUserListTypeWatching": "İzlenen",
|
||||||
"ImportListsSonarrSettingsFullUrl": "Tam URL",
|
"ImportListsSonarrSettingsFullUrl": "Tam URL",
|
||||||
"IndexerJackettAllHealthCheckMessage": "Desteklenmeyen Jackett 'tümü' uç noktasını kullanan dizinleyiciler: {indexerNames}",
|
"IndexerJackettAllHealthCheckMessage": "Desteklenmeyen Jackett 'tümü' uç noktasını kullanan indeksleyiciler: {indexerNames}",
|
||||||
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "6 saatten uzun süren hatalar nedeniyle tüm dizinleyiciler kullanılamıyor",
|
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "6 saatten uzun süren hatalar nedeniyle tüm indeksleyiciler kullanılamıyor",
|
||||||
"IndexerSearchNoInteractiveHealthCheckMessage": "Etkileşimli Arama etkinleştirildiğinde hiçbir dizinleyici kullanılamaz, {appName} herhangi bir etkileşimli arama sonucu sağlamayacaktır",
|
"IndexerSearchNoInteractiveHealthCheckMessage": "Etkileşimli Arama etkinleştirildiğinde hiçbir indeksleyici kullanılamaz, {appName} herhangi bir etkileşimli arama sonucu sağlamayacaktır",
|
||||||
"IndexerSettingsAllowZeroSizeHelpText": "Bunu etkinleştirmek, sürüm boyutunu belirtmeyen beslemeleri kullanmanıza olanak tanır; ancak dikkatli olun, boyutla ilgili kontroller gerçekleştirilmeyecektir.",
|
"IndexerSettingsAllowZeroSizeHelpText": "Bunu etkinleştirmek, sürüm boyutunu belirtmeyen beslemeleri kullanmanıza olanak tanır; ancak dikkatli olun, boyutla ilgili kontroller gerçekleştirilmeyecektir.",
|
||||||
"IndexerSettingsAnimeCategoriesHelpText": "Açılır listeyi boş bırakın, animeyi devre dışı bırakın",
|
"IndexerSettingsAnimeCategoriesHelpText": "Açılır listeyi boş bırakın, animeyi devre dışı bırakın",
|
||||||
"IndexerSettingsAnimeStandardFormatSearch": "Anime Standart Format Arama",
|
"IndexerSettingsAnimeStandardFormatSearch": "Anime Standart Format Arama",
|
||||||
@@ -1679,7 +1679,7 @@
|
|||||||
"IRCLinkText": "#sonarr Daima Özgür",
|
"IRCLinkText": "#sonarr Daima Özgür",
|
||||||
"EpisodeTitleRequiredHelpText": "Bölüm başlığı adlandırma biçimindeyse ve bölüm başlığı TBA ise 48 saate kadar içe aktarmayı önleyin",
|
"EpisodeTitleRequiredHelpText": "Bölüm başlığı adlandırma biçimindeyse ve bölüm başlığı TBA ise 48 saate kadar içe aktarmayı önleyin",
|
||||||
"FullSeason": "Tam Sezon",
|
"FullSeason": "Tam Sezon",
|
||||||
"IndexerLongTermStatusUnavailableHealthCheckMessage": "6 saatten uzun süren hatalar nedeniyle kullanılamayan dizinleyiciler: {indexerNames}",
|
"IndexerLongTermStatusUnavailableHealthCheckMessage": "6 saatten uzun süren hatalar nedeniyle kullanılamayan indeksleyiciler: {indexerNames}",
|
||||||
"IndexerSettingsAdditionalParametersNyaa": "Ek Parametreler",
|
"IndexerSettingsAdditionalParametersNyaa": "Ek Parametreler",
|
||||||
"IndexerSettingsApiUrl": "API URL'si",
|
"IndexerSettingsApiUrl": "API URL'si",
|
||||||
"IndexerSettingsCookieHelpText": "Sitenizin rss'e erişmek için bir giriş çerezine ihtiyacı varsa, bunu bir tarayıcı aracılığıyla almanız gerekecektir.",
|
"IndexerSettingsCookieHelpText": "Sitenizin rss'e erişmek için bir giriş çerezine ihtiyacı varsa, bunu bir tarayıcı aracılığıyla almanız gerekecektir.",
|
||||||
@@ -1764,8 +1764,8 @@
|
|||||||
"ImportListsTraktSettingsPopularListTypeTopYearShows": "Yıla Göre En Çok İzlenen Diziler",
|
"ImportListsTraktSettingsPopularListTypeTopYearShows": "Yıla Göre En Çok İzlenen Diziler",
|
||||||
"ImportListsValidationUnableToConnectException": "İçe aktarma listesine bağlanılamıyor: {exceptionMessage}. Ayrıntılar için bu hatayla ilgili günlüğü kontrol edin.",
|
"ImportListsValidationUnableToConnectException": "İçe aktarma listesine bağlanılamıyor: {exceptionMessage}. Ayrıntılar için bu hatayla ilgili günlüğü kontrol edin.",
|
||||||
"ImportMechanismHandlingDisabledHealthCheckMessage": "Tamamlanmış İndirme İşlemini Etkinleştir",
|
"ImportMechanismHandlingDisabledHealthCheckMessage": "Tamamlanmış İndirme İşlemini Etkinleştir",
|
||||||
"IndexerRssNoIndexersAvailableHealthCheckMessage": "Son zamanlardaki dizinleyici hataları nedeniyle tüm rss uyumlu dizinleyiciler geçici olarak kullanılamıyor",
|
"IndexerRssNoIndexersAvailableHealthCheckMessage": "Son zamanlardaki indeksleyici hataları nedeniyle tüm rss uyumlu indeksleyiciler geçici olarak kullanılamıyor",
|
||||||
"IndexerRssNoIndexersEnabledHealthCheckMessage": "RSS senkronizasyonu etkinleştirildiğinde dizinleyiciler kullanılamaz, {appName} yeni sürümleri otomatik olarak almayacaktır",
|
"IndexerRssNoIndexersEnabledHealthCheckMessage": "RSS senkronizasyonu etkinleştirildiğinde tüm indeksleyiciler kullanılamaz, {appName} yeni sürümleri otomatik olarak almayacaktır",
|
||||||
"IndexerSettingsCategoriesHelpText": "Açılır listeyi boş bırakın, standart/günlük gösterileri devre dışı bırakın",
|
"IndexerSettingsCategoriesHelpText": "Açılır listeyi boş bırakın, standart/günlük gösterileri devre dışı bırakın",
|
||||||
"EpisodeTitleFootNote": "İsteğe bağlı olarak kesmeyi üç nokta (`...`) dahil olarak maksimum bayt boyutuna göre kontrol edin. Sondan (örn. `{Episode Title:30}`) veya başlangıçtan (örn. `{Episode Title:-30}`) kesme her ikisi de desteklenmektedir. Bölüm başlıkları, gerekirse dosya sistemi sınırlamalarına göre otomatik olarak kesilecektir.",
|
"EpisodeTitleFootNote": "İsteğe bağlı olarak kesmeyi üç nokta (`...`) dahil olarak maksimum bayt boyutuna göre kontrol edin. Sondan (örn. `{Episode Title:30}`) veya başlangıçtan (örn. `{Episode Title:-30}`) kesme her ikisi de desteklenmektedir. Bölüm başlıkları, gerekirse dosya sistemi sınırlamalarına göre otomatik olarak kesilecektir.",
|
||||||
"GrabReleaseUnknownSeriesOrEpisodeMessageText": "{appName} bu sürümün hangi dizi ve bölüm için olduğunu belirleyemedi. {appName} bu sürümü otomatik olarak içe aktaramayabilir. '{title}' öğesini almak ister misiniz?",
|
"GrabReleaseUnknownSeriesOrEpisodeMessageText": "{appName} bu sürümün hangi dizi ve bölüm için olduğunu belirleyemedi. {appName} bu sürümü otomatik olarak içe aktaramayabilir. '{title}' öğesini almak ister misiniz?",
|
||||||
@@ -1773,8 +1773,8 @@
|
|||||||
"ImportMechanismEnableCompletedDownloadHandlingIfPossibleMultiComputerHealthCheckMessage": "Mümkünse Tamamlanmış İndirme İşlemini Etkinleştirin (Çoklu Bilgisayar desteklenmiyor)",
|
"ImportMechanismEnableCompletedDownloadHandlingIfPossibleMultiComputerHealthCheckMessage": "Mümkünse Tamamlanmış İndirme İşlemini Etkinleştirin (Çoklu Bilgisayar desteklenmiyor)",
|
||||||
"IndexerIPTorrentsSettingsFeedUrlHelpText": "IPTorrents tarafından yalnızca seçtiğiniz kategorileri (HD, SD, x264, vb.) kullanarak oluşturulan tam RSS besleme URL'si",
|
"IndexerIPTorrentsSettingsFeedUrlHelpText": "IPTorrents tarafından yalnızca seçtiğiniz kategorileri (HD, SD, x264, vb.) kullanarak oluşturulan tam RSS besleme URL'si",
|
||||||
"IndexerSettingsAdditionalNewznabParametersHelpText": "Lütfen kategoriyi değiştirmeniz durumunda yabancı dil sürümlerini önlemek için alt gruplar hakkında zorunlu/kısıtlı kurallar eklemeniz gerekeceğini unutmayın.",
|
"IndexerSettingsAdditionalNewznabParametersHelpText": "Lütfen kategoriyi değiştirmeniz durumunda yabancı dil sürümlerini önlemek için alt gruplar hakkında zorunlu/kısıtlı kurallar eklemeniz gerekeceğini unutmayın.",
|
||||||
"IndexerValidationNoResultsInConfiguredCategories": "Sorgu başarılı, ancak dizinleyicinizden yapılandırılan kategorilerde hiçbir sonuç döndürülmedi. Bu, dizinleyici veya dizinleyici kategori ayarlarınızdaki bir sorun olabilir.",
|
"IndexerValidationNoResultsInConfiguredCategories": "Sorgu başarılı, ancak indeksleyicinizden yapılandırılan kategorilerde hiçbir sonuç döndürülmedi. Bu, indeksleyici veya indeksleyici kategori ayarlarınızdan kaynaklı bir sorun olabilir.",
|
||||||
"IndexerValidationQuerySeasonEpisodesNotSupported": "Dizinleyici geçerli sorguyu desteklemiyor. Kategorilerin ve/veya sezon/bölüm aramasının desteklenip desteklenmediğini kontrol edin. Daha fazla ayrıntı için günlüğü kontrol edin.",
|
"IndexerValidationQuerySeasonEpisodesNotSupported": "İndeksleyici geçerli sorguyu desteklemiyor. Kategorilerin ve/veya sezon/bölüm aramasının desteklenip desteklenmediğini kontrol edin. Daha fazla ayrıntı için günlüğü kontrol edin.",
|
||||||
"MarkAsFailedConfirmation": "'{sourceTitle}' öğesini başarısız olarak işaretlemek istediğinizden emin misiniz?",
|
"MarkAsFailedConfirmation": "'{sourceTitle}' öğesini başarısız olarak işaretlemek istediğinizden emin misiniz?",
|
||||||
"ErrorLoadingContent": "Bu içerik yüklenirken bir hata oluştu",
|
"ErrorLoadingContent": "Bu içerik yüklenirken bir hata oluştu",
|
||||||
"FilterContains": "içerir",
|
"FilterContains": "içerir",
|
||||||
@@ -1784,39 +1784,39 @@
|
|||||||
"ImportListsTraktSettingsLimitHelpText": "Alınacak dizi sayısını sınırlayın",
|
"ImportListsTraktSettingsLimitHelpText": "Alınacak dizi sayısını sınırlayın",
|
||||||
"ImportListsTraktSettingsUsernameHelpText": "İçe aktarılacak Liste için Kullanıcı Adı",
|
"ImportListsTraktSettingsUsernameHelpText": "İçe aktarılacak Liste için Kullanıcı Adı",
|
||||||
"ImportListsTraktSettingsWatchedListSortingHelpText": "Liste Türü İzlenen ise, listeyi sıralamak için sırayı seçin",
|
"ImportListsTraktSettingsWatchedListSortingHelpText": "Liste Türü İzlenen ise, listeyi sıralamak için sırayı seçin",
|
||||||
"IndexerSearchNoAutomaticHealthCheckMessage": "Otomatik Arama etkinleştirildiğinde hiçbir dizinleyici kullanılamaz, {appName} herhangi bir otomatik arama sonucu sağlamayacaktır",
|
"IndexerSearchNoAutomaticHealthCheckMessage": "Otomatik Arama etkinleştirildiğinde hiçbir indeksleyici kullanılamaz, {appName} herhangi bir otomatik arama sonucu sağlamayacaktır",
|
||||||
"IndexerSettingsApiUrlHelpText": "Ne yaptığınızı bilmiyorsanız bunu değiştirmeyin. API anahtarınız ana sunucuya gönderilecektir.",
|
"IndexerSettingsApiUrlHelpText": "Ne yaptığınızı bilmiyorsanız bunu değiştirmeyin. API anahtarınız ana sunucuya gönderilecektir.",
|
||||||
"IndexerSettingsSeasonPackSeedTimeHelpText": "Bir sezon paketi torrentinin durdurulmadan önce başlatılması gereken süre, boş bırakıldığında indirme istemcisinin varsayılanı kullanılır",
|
"IndexerSettingsSeasonPackSeedTimeHelpText": "Bir sezon paketi torrentinin durdurulmadan önce başlatılması gereken süre, boş bırakıldığında indirme istemcisinin varsayılanı kullanılır",
|
||||||
"IndexerValidationCloudFlareCaptchaRequired": "Site CloudFlare CAPTCHA tarafından korunmaktadır. Geçerli CAPTCHA belirteci gereklidir.",
|
"IndexerValidationCloudFlareCaptchaRequired": "Site CloudFlare CAPTCHA tarafından korunmaktadır. Geçerli CAPTCHA belirteci gereklidir.",
|
||||||
"IndexerValidationUnableToConnectServerUnavailable": "Dizinleyiciye bağlanılamıyor, dizinleyicinin sunucusu kullanılamıyor. Daha sonra tekrar deneyin. {exceptionMessage}.",
|
"IndexerValidationUnableToConnectServerUnavailable": "İndeksleyiciye bağlanılamıyor, indeksleyicinin sunucusu kullanılamıyor. Daha sonra tekrar deneyin. {exceptionMessage}.",
|
||||||
"ImportListsTraktSettingsUserListUsernameHelpText": "İçe aktarılacak Liste için Kullanıcı Adı (Yetkili Kullanıcı için boş bırakın)",
|
"ImportListsTraktSettingsUserListUsernameHelpText": "İçe aktarılacak Liste için Kullanıcı Adı (Yetkili Kullanıcı için boş bırakın)",
|
||||||
"ImportListsTraktSettingsYearsHelpText": "Diziyi yıla veya yıl aralığına göre filtreleyin",
|
"ImportListsTraktSettingsYearsHelpText": "Diziyi yıla veya yıl aralığına göre filtreleyin",
|
||||||
"IndexerHDBitsSettingsMediums": "Ortamlar",
|
"IndexerHDBitsSettingsMediums": "Ortamlar",
|
||||||
"IndexerSearchNoAvailableIndexersHealthCheckMessage": "Son zamanlardaki dizinleyici hataları nedeniyle tüm arama yeteneğine sahip dizinleyiciler geçici olarak kullanılamıyor",
|
"IndexerSearchNoAvailableIndexersHealthCheckMessage": "Son zamanlardaki indeksleyici hataları nedeniyle tüm arama yeteneğine sahip indeksleyiciler geçici olarak kullanılamıyor",
|
||||||
"IndexerSettingsSeasonPackSeedTime": "Sezon Paketi Seed Süresi",
|
"IndexerSettingsSeasonPackSeedTime": "Sezon Paketi Seed Süresi",
|
||||||
"IndexerValidationJackettAllNotSupportedHelpText": "Jackett'in tüm uç noktaları desteklenmiyor, lütfen dizinleyicileri tek tek ekleyin",
|
"IndexerValidationJackettAllNotSupportedHelpText": "Jackett'in tüm uç noktaları desteklenmiyor, lütfen indeksleyicileri tek tek ekleyin",
|
||||||
"IndexerValidationNoRssFeedQueryAvailable": "RSS besleme sorgusu mevcut değil. Bu, dizinleyici veya dizinleyici kategori ayarlarınızdaki bir sorun olabilir.",
|
"IndexerValidationNoRssFeedQueryAvailable": "RSS besleme sorgusu mevcut değil. Bu, indeksleyici veya indeksleyici kategori ayarlarınızdan kaynaklı bir sorun olabilir.",
|
||||||
"IndexerValidationUnableToConnectResolutionFailure": "Dizinleyiciye bağlanılamıyor bağlantı hatası. Dizinleyicinin sunucusuna ve DNS'ine olan bağlantınızı kontrol edin. {exceptionMessage}.",
|
"IndexerValidationUnableToConnectResolutionFailure": "İndeksleyiciye bağlanılamıyor bağlantı hatası. İndeksleyicinin sunucusuna ve DNS'ine olan bağlantınızı kontrol edin. {exceptionMessage}.",
|
||||||
"IndexerSettingsFailDownloads": "Başarısız İndirmeler",
|
"IndexerSettingsFailDownloads": "Başarısız İndirmeler",
|
||||||
"IndexerSettingsFailDownloadsHelpText": "Tamamlanan indirmeler işlenirken {appName} bu seçili dosya türlerini başarısız indirmeler olarak değerlendirecektir.",
|
"IndexerSettingsFailDownloadsHelpText": "Tamamlanan indirmeler işlenirken {appName} bu seçili dosya türlerini başarısız indirmeler olarak değerlendirecektir.",
|
||||||
"IndexerSettingsMinimumSeeders": "Minimum Seeder",
|
"IndexerSettingsMinimumSeeders": "Minimum Seeder",
|
||||||
"IndexerSettingsRssUrl": "RSS URL",
|
"IndexerSettingsRssUrl": "RSS URL",
|
||||||
"IndexerSettingsRssUrlHelpText": "{indexer} uyumlu bir RSS beslemesine URL girin",
|
"IndexerSettingsRssUrlHelpText": "{indexer} uyumlu bir RSS beslemesine URL girin",
|
||||||
"IndexerSettingsWebsiteUrl": "Web site URL'si",
|
"IndexerSettingsWebsiteUrl": "Web site URL'si",
|
||||||
"IndexerStatusAllUnavailableHealthCheckMessage": "Tüm dizinleyiciler hatalar nedeniyle kullanılamıyor",
|
"IndexerStatusAllUnavailableHealthCheckMessage": "Tüm indeksleyiciler hatalar nedeniyle kullanılamıyor",
|
||||||
"IndexerStatusUnavailableHealthCheckMessage": "Hatalar nedeniyle kullanılamayan dizinleyiciler: {indexerNames}",
|
"IndexerStatusUnavailableHealthCheckMessage": "Hatalar nedeniyle kullanılamayan indeksleyiciler: {indexerNames}",
|
||||||
"IndexerTagSeriesHelpText": "Bu indeksleyiciyi yalnızca en az bir eşleşen etiketi olan seriler için kullanın. Tüm serilerle kullanmak için boş bırakın.",
|
"IndexerTagSeriesHelpText": "Bu indeksleyiciyi yalnızca en az bir eşleşen etiketi olan seriler için kullanın. Tüm serilerle kullanmak için boş bırakın.",
|
||||||
"IndexerValidationCloudFlareCaptchaExpired": "CloudFlare CAPTCHA token'ınızın süresi doldu, lütfen yenileyin.",
|
"IndexerValidationCloudFlareCaptchaExpired": "CloudFlare CAPTCHA token'ınızın süresi doldu, lütfen yenileyin.",
|
||||||
"IndexerValidationFeedNotSupported": "Dizinleyici beslemesi desteklenmiyor: {exceptionMessage}",
|
"IndexerValidationFeedNotSupported": "indeksleyici beslemesi desteklenmiyor: {exceptionMessage}",
|
||||||
"IndexerValidationInvalidApiKey": "Geçersiz API Anahtarı",
|
"IndexerValidationInvalidApiKey": "Geçersiz API Anahtarı",
|
||||||
"IndexerValidationJackettAllNotSupported": "Jackett'in tüm uç noktaları desteklenmiyor, lütfen dizinleyicileri tek tek ekleyin",
|
"IndexerValidationJackettAllNotSupported": "Jackett'in tüm uç noktaları desteklenmiyor, lütfen indeksleyicileri tek tek ekleyin",
|
||||||
"IndexerValidationRequestLimitReached": "Talep sınırına ulaşıldı: {exceptionMessage}",
|
"IndexerValidationRequestLimitReached": "Talep sınırına ulaşıldı: {exceptionMessage}",
|
||||||
"IndexerValidationSearchParametersNotSupported": "Dizinleyici gerekli arama parametrelerini desteklemiyor",
|
"IndexerValidationSearchParametersNotSupported": "İndeksleyici gerekli arama parametrelerini desteklemiyor",
|
||||||
"IndexerValidationTestAbortedDueToError": "Test bir hata nedeniyle iptal edildi: {exceptionMessage}",
|
"IndexerValidationTestAbortedDueToError": "Test bir hata nedeniyle iptal edildi: {exceptionMessage}",
|
||||||
"IndexerValidationUnableToConnect": "Dizinleyiciye bağlanılamıyor: {exceptionMessage}. Ayrıntılar için bu hatayla ilgili günlüğü kontrol edin",
|
"IndexerValidationUnableToConnect": "İndeksleyiciye bağlanılamıyor: {exceptionMessage}. Ayrıntılar için bu hatayla ilgili günlüğü kontrol edin",
|
||||||
"IndexerValidationUnableToConnectHttpError": "Dizinleyiciye bağlanılamıyor, lütfen DNS ayarlarınızı kontrol edin ve IPv6'nın çalıştığından veya devre dışı olduğundan emin olun. {exceptionMessage}.",
|
"IndexerValidationUnableToConnectHttpError": "İndeksleyiciye bağlanılamıyor, lütfen DNS ayarlarınızı kontrol edin ve IPv6'nın çalıştığından veya devre dışı olduğundan emin olun. {exceptionMessage}.",
|
||||||
"IndexerValidationUnableToConnectInvalidCredentials": "Dizinleyiciye bağlanılamıyor, geçersiz kimlik bilgileri. {exceptionMessage}.",
|
"IndexerValidationUnableToConnectInvalidCredentials": "İndeksleyiciye bağlanılamıyor, geçersiz kimlik bilgileri. {exceptionMessage}.",
|
||||||
"IndexerValidationUnableToConnectTimeout": "Dizinleyiciye bağlanılamıyor, muhtemelen zaman aşımı nedeniyle. Tekrar deneyin veya ağ ayarlarınızı kontrol edin. {exceptionMessage}.",
|
"IndexerValidationUnableToConnectTimeout": "İndeksleyiciye bağlanılamıyor, muhtemelen zaman aşımı nedeniyle. Tekrar deneyin veya ağ ayarlarınızı kontrol edin. {exceptionMessage}.",
|
||||||
"InteractiveImportNoEpisode": "Her seçili dosya için bir veya daha fazla bölüm seçilmelidir",
|
"InteractiveImportNoEpisode": "Her seçili dosya için bir veya daha fazla bölüm seçilmelidir",
|
||||||
"InteractiveImportNoSeason": "Her seçilen dosya için sezon seçilmelidir",
|
"InteractiveImportNoSeason": "Her seçilen dosya için sezon seçilmelidir",
|
||||||
"InteractiveImportNoSeries": "Her seçilen dosya için dizi seçilmelidir",
|
"InteractiveImportNoSeries": "Her seçilen dosya için dizi seçilmelidir",
|
||||||
@@ -1968,7 +1968,7 @@
|
|||||||
"ReleaseSceneIndicatorUnknownMessage": "Bu bölüm için numaralandırma değişiklik göstermektedir ve sürüm bilinen hiçbir eşleştirmeyle uyuşmamaktadır.",
|
"ReleaseSceneIndicatorUnknownMessage": "Bu bölüm için numaralandırma değişiklik göstermektedir ve sürüm bilinen hiçbir eşleştirmeyle uyuşmamaktadır.",
|
||||||
"ReleaseSceneIndicatorUnknownSeries": "Bilinmeyen bölüm veya dizi.",
|
"ReleaseSceneIndicatorUnknownSeries": "Bilinmeyen bölüm veya dizi.",
|
||||||
"ReleaseType": "Sürüm Türü",
|
"ReleaseType": "Sürüm Türü",
|
||||||
"RemotePathMappingDockerFolderMissingHealthCheckMessage": "Docker kullanıyorsunuz; indirme istemcisi {downloadClientName} indirmeleri {path} dizinine yerleştiriyor ancak bu dizin konteynerin içinde görünmüyor. Uzak yol eşlemelerinizi ve konteyner hacmi ayarlarınızı inceleyin.",
|
"RemotePathMappingDockerFolderMissingHealthCheckMessage": "Docker kullanıyorsunuz; indirme istemcisi {downloadClientName} indirmeleri {path} dizinine yerleştiriyor ancak bu dizin konteynerin içinde görünmüyor. Uzak yol eşlemelerinizi ve konteyner bağlama ayarlarınızı inceleyin.",
|
||||||
"RemotePathMappingDownloadPermissionsEpisodeHealthCheckMessage": "{appName} indirilen bölümü {path} görebiliyor ancak erişemiyor. Muhtemelen izin hatası.",
|
"RemotePathMappingDownloadPermissionsEpisodeHealthCheckMessage": "{appName} indirilen bölümü {path} görebiliyor ancak erişemiyor. Muhtemelen izin hatası.",
|
||||||
"RemotePathMappingFileRemovedHealthCheckMessage": "{path} dosyası işleme sırasında kaldırıldı.",
|
"RemotePathMappingFileRemovedHealthCheckMessage": "{path} dosyası işleme sırasında kaldırıldı.",
|
||||||
"RemotePathMappingFilesGenericPermissionsHealthCheckMessage": "{downloadClientName} indirme istemcisi {path} dizinindeki dosyaları raporladı ancak {appName} bu dizini göremiyor. Klasörün izinlerini ayarlamanız gerekebilir.",
|
"RemotePathMappingFilesGenericPermissionsHealthCheckMessage": "{downloadClientName} indirme istemcisi {path} dizinindeki dosyaları raporladı ancak {appName} bu dizini göremiyor. Klasörün izinlerini ayarlamanız gerekebilir.",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"AddListExclusion": "新增排除清單",
|
"AddListExclusion": "新增排除清單",
|
||||||
"Add": "新增",
|
"Add": "新增",
|
||||||
"About": "關於",
|
"About": "關於",
|
||||||
"Actions": "執行",
|
"Actions": "動作",
|
||||||
"AddAutoTagError": "無法加入新的自動標籤,請重新嘗試。",
|
"AddAutoTagError": "無法加入新的自動標籤,請重新嘗試。",
|
||||||
"AddAutoTag": "新增自動標籤",
|
"AddAutoTag": "新增自動標籤",
|
||||||
"AddCondition": "新增條件",
|
"AddCondition": "新增條件",
|
||||||
@@ -36,5 +36,36 @@
|
|||||||
"AddCustomFilter": "新增自定義過濾器",
|
"AddCustomFilter": "新增自定義過濾器",
|
||||||
"UnselectAll": "取消全選",
|
"UnselectAll": "取消全選",
|
||||||
"Any": "任何",
|
"Any": "任何",
|
||||||
"UpdateAvailableHealthCheckMessage": "可用的新版本: {version}"
|
"UpdateAvailableHealthCheckMessage": "可用的新版本: {version}",
|
||||||
|
"AutoRedownloadFailed": "失敗時重新下載",
|
||||||
|
"AutoRedownloadFailedFromInteractiveSearch": "失敗時重新下載來自手動搜索的資源",
|
||||||
|
"AuthenticationRequired": "需要驗證",
|
||||||
|
"AppDataDirectory": "AppData 路徑",
|
||||||
|
"AuthenticationMethod": "驗證方式",
|
||||||
|
"AuthenticationRequiredHelpText": "更改需要進行驗證的請求。除非你了解其中的風險,否則請勿修改。",
|
||||||
|
"AuthenticationRequiredPasswordHelpTextWarning": "請輸入新密碼",
|
||||||
|
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "確認新密碼",
|
||||||
|
"AuthenticationMethodHelpTextWarning": "請選擇一個有效的驗證方式",
|
||||||
|
"AuthenticationRequiredUsernameHelpTextWarning": "請輸入新用戶名",
|
||||||
|
"AudioLanguages": "音頻語言",
|
||||||
|
"Activity": "活動",
|
||||||
|
"AddNewRestriction": "加入新的限制",
|
||||||
|
"AuthenticationRequiredWarning": "為防止未經認證的遠程訪問,{appName} 現需要啟用身份認證。您可以選擇禁用本地地址的身份認證。",
|
||||||
|
"AddRemotePathMappingError": "無法加入新的遠程路徑對應,請重試。",
|
||||||
|
"AnalyseVideoFilesHelpText": "從文件中提取影像資訊,如解析度、運行環境和編解碼器資訊。這需要 {appName} 在掃描期間讀取文件並可能導致高磁盤或網絡佔用。",
|
||||||
|
"AddDelayProfileError": "無法加入新的延遲配置,請重新嘗試。",
|
||||||
|
"AddImportListExclusionError": "無法加入新的導入列表排除,請重試。",
|
||||||
|
"AddIndexerError": "無法加入新的索引器,請重試。",
|
||||||
|
"AddList": "加入清單",
|
||||||
|
"AddListError": "無法加入新的清單,請重試。",
|
||||||
|
"AddANewPath": "新增新的路徑",
|
||||||
|
"AddCustomFormat": "加入自訂格式",
|
||||||
|
"AddCustomFormatError": "無法加入自訂格式,請重試。",
|
||||||
|
"AddDownloadClient": "加入下載用戶端",
|
||||||
|
"AddDownloadClientError": "無法加入下載用戶端,請重試。",
|
||||||
|
"AddExclusion": "加入排除",
|
||||||
|
"AbsoluteEpisodeNumbers": "絕對集數",
|
||||||
|
"AbsoluteEpisodeNumber": "絕對集數",
|
||||||
|
"AddListExclusionError": "無法加入新的清單排除,請重試。",
|
||||||
|
"AddNew": "加入新的"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,6 +260,26 @@ namespace NzbDrone.Core.MediaFiles
|
|||||||
|
|
||||||
var extension = Path.GetExtension(fileInfo.Name);
|
var extension = Path.GetExtension(fileInfo.Name);
|
||||||
|
|
||||||
|
if (FileExtensions.DangerousExtensions.Contains(extension))
|
||||||
|
{
|
||||||
|
return new List<ImportResult>
|
||||||
|
{
|
||||||
|
new ImportResult(new ImportDecision(new LocalEpisode { Path = fileInfo.FullName },
|
||||||
|
new ImportRejection(ImportRejectionReason.DangerousFile, $"Caution: Found potentially dangerous file with extension: {extension}")),
|
||||||
|
$"Caution: Found potentially dangerous file with extension: {extension}")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FileExtensions.ExecutableExtensions.Contains(extension))
|
||||||
|
{
|
||||||
|
return new List<ImportResult>
|
||||||
|
{
|
||||||
|
new ImportResult(new ImportDecision(new LocalEpisode { Path = fileInfo.FullName },
|
||||||
|
new ImportRejection(ImportRejectionReason.ExecutableFile, $"Caution: Found executable file with extension: '{extension}'")),
|
||||||
|
$"Caution: Found executable file with extension: '{extension}'")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (extension.IsNullOrWhiteSpace() || !MediaFileExtensions.Extensions.Contains(extension))
|
if (extension.IsNullOrWhiteSpace() || !MediaFileExtensions.Extensions.Contains(extension))
|
||||||
{
|
{
|
||||||
_logger.Debug("[{0}] has an unsupported extension: '{1}'", fileInfo.FullName, extension);
|
_logger.Debug("[{0}] has an unsupported extension: '{1}'", fileInfo.FullName, extension);
|
||||||
|
|||||||
@@ -66,6 +66,12 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||||||
return DetectSampleResult.Indeterminate;
|
return DetectSampleResult.Indeterminate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (runtime == 0)
|
||||||
|
{
|
||||||
|
_logger.Debug("Series runtime is 0, defaulting runtime to 45 minutes");
|
||||||
|
runtime = 45;
|
||||||
|
}
|
||||||
|
|
||||||
return IsSample(localEpisode.Path, localEpisode.MediaInfo.RunTime, runtime);
|
return IsSample(localEpisode.Path, localEpisode.MediaInfo.RunTime, runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,11 @@ namespace NzbDrone.Core.MediaFiles
|
|||||||
|
|
||||||
private static List<string> _dangerousExtensions = new List<string>
|
private static List<string> _dangerousExtensions = new List<string>
|
||||||
{
|
{
|
||||||
|
".arj",
|
||||||
".lnk",
|
".lnk",
|
||||||
|
".lzh",
|
||||||
".ps1",
|
".ps1",
|
||||||
|
".scr",
|
||||||
".vbs",
|
".vbs",
|
||||||
".zipx"
|
".zipx"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
|
|||||||
public int? TvRageId { get; set; }
|
public int? TvRageId { get; set; }
|
||||||
public int? TvMazeId { get; set; }
|
public int? TvMazeId { get; set; }
|
||||||
public int? TmdbId { get; set; }
|
public int? TmdbId { get; set; }
|
||||||
|
public HashSet<int> MalIds { get; set; }
|
||||||
|
public HashSet<int> AniListIds { get; set; }
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public int? Runtime { get; set; }
|
public int? Runtime { get; set; }
|
||||||
public TimeOfDayResource TimeOfDay { get; set; }
|
public TimeOfDayResource TimeOfDay { get; set; }
|
||||||
|
|||||||
@@ -194,6 +194,8 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||||||
}
|
}
|
||||||
|
|
||||||
series.ImdbId = show.ImdbId;
|
series.ImdbId = show.ImdbId;
|
||||||
|
series.MalIds = show.MalIds;
|
||||||
|
series.AniListIds = show.AniListIds;
|
||||||
series.Title = show.Title;
|
series.Title = show.Title;
|
||||||
series.CleanTitle = Parser.Parser.CleanSeriesTitle(show.Title);
|
series.CleanTitle = Parser.Parser.CleanSeriesTitle(show.Title);
|
||||||
series.SortTitle = SeriesTitleNormalizer.Normalize(show.Title, show.TvdbId);
|
series.SortTitle = SeriesTitleNormalizer.Normalize(show.Title, show.TvdbId);
|
||||||
|
|||||||
@@ -554,7 +554,7 @@ namespace NzbDrone.Core.Notifications.Discord
|
|||||||
{
|
{
|
||||||
embed.Thumbnail = new DiscordImage
|
embed.Thumbnail = new DiscordImage
|
||||||
{
|
{
|
||||||
Url = series?.Images?.FirstOrDefault(x => x.CoverType == MediaCoverTypes.Poster)?.Url
|
Url = series?.Images?.FirstOrDefault(x => x.CoverType == MediaCoverTypes.Poster)?.RemoteUrl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,7 +562,7 @@ namespace NzbDrone.Core.Notifications.Discord
|
|||||||
{
|
{
|
||||||
embed.Image = new DiscordImage
|
embed.Image = new DiscordImage
|
||||||
{
|
{
|
||||||
Url = series?.Images?.FirstOrDefault(x => x.CoverType == MediaCoverTypes.Fanart)?.Url
|
Url = series?.Images?.FirstOrDefault(x => x.CoverType == MediaCoverTypes.Fanart)?.RemoteUrl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ namespace NzbDrone.Core.Parser
|
|||||||
|
|
||||||
// Some Chinese anime releases contain both Chinese and English titles separated by | instead of /, remove the Chinese title and replace with normal anime pattern
|
// Some Chinese anime releases contain both Chinese and English titles separated by | instead of /, remove the Chinese title and replace with normal anime pattern
|
||||||
new RegexReplace(@"^\[(?<subgroup>[^\]]+)\](?:\s)(?:(?<chinesetitle>(?=[^\]]*?[\u4E00-\u9FCC])[^\]]*?)(?:\s\|\s))(?<title>[^\]]+?)(?:[- ]+)(?<episode>[0-9]+(?:-[0-9]+)?(?![a-z]))话?(?:END|完)?", "[${subgroup}] ${title} - ${episode} ", RegexOptions.Compiled),
|
new RegexReplace(@"^\[(?<subgroup>[^\]]+)\](?:\s)(?:(?<chinesetitle>(?=[^\]]*?[\u4E00-\u9FCC])[^\]]*?)(?:\s\|\s))(?<title>[^\]]+?)(?:[- ]+)(?<episode>[0-9]+(?:-[0-9]+)?(?![a-z]))话?(?:END|完)?", "[${subgroup}] ${title} - ${episode} ", RegexOptions.Compiled),
|
||||||
|
|
||||||
|
// Spanish releases with information in brackets
|
||||||
|
new RegexReplace(@"^(?<title>.+?(?=[ ._-]\()).+?\((?<year>\d{4})\/(?<info>S[^\/]+)", "${title} (${year}) - ${info} ", RegexOptions.Compiled),
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Regex[] ReportTitleRegex = new[]
|
private static readonly Regex[] ReportTitleRegex = new[]
|
||||||
@@ -572,7 +575,7 @@ namespace NzbDrone.Core.Parser
|
|||||||
private static readonly Regex YearInTitleRegex = new Regex(@"^(?<title>.+?)[-_. ]+?[\(\[]?(?<year>\d{4})[\]\)]?",
|
private static readonly Regex YearInTitleRegex = new Regex(@"^(?<title>.+?)[-_. ]+?[\(\[]?(?<year>\d{4})[\]\)]?",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
private static readonly Regex TitleComponentsRegex = new Regex(@"^(?:(?<title>.+?) \((?<title>.+?)\)|(?<title>.+?) \| (?<title>.+?))$",
|
private static readonly Regex TitleComponentsRegex = new Regex(@"^(?:(?<title>.+?) \((?<title>.+?)\)|(?<title>.+?) \| (?<title>.+?)|(?<title>.+?) AKA (?<title>.+?))$",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
private static readonly Regex PartRegex = new Regex(@"\(\d+\)$", RegexOptions.Compiled);
|
private static readonly Regex PartRegex = new Regex(@"\(\d+\)$", RegexOptions.Compiled);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<PackageReference Include="Servarr.FluentMigrator.Runner.SQLite" Version="3.3.2.9" />
|
<PackageReference Include="Servarr.FluentMigrator.Runner.SQLite" Version="3.3.2.9" />
|
||||||
<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="9.5.4" />
|
<PackageReference Include="FluentValidation" Version="9.5.4" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.6" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="NLog" Version="5.3.4" />
|
<PackageReference Include="NLog" Version="5.3.4" />
|
||||||
<PackageReference Include="MonoTorrent" Version="2.0.7" />
|
<PackageReference Include="MonoTorrent" Version="2.0.7" />
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Tv.Events
|
||||||
|
{
|
||||||
|
public class SeriesBulkEditedEvent : IEvent
|
||||||
|
{
|
||||||
|
public List<Series> Series { get; private set; }
|
||||||
|
|
||||||
|
public SeriesBulkEditedEvent(List<Series> series)
|
||||||
|
{
|
||||||
|
Series = series;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -94,6 +94,8 @@ namespace NzbDrone.Core.Tv
|
|||||||
series.TvMazeId = seriesInfo.TvMazeId;
|
series.TvMazeId = seriesInfo.TvMazeId;
|
||||||
series.TmdbId = seriesInfo.TmdbId;
|
series.TmdbId = seriesInfo.TmdbId;
|
||||||
series.ImdbId = seriesInfo.ImdbId;
|
series.ImdbId = seriesInfo.ImdbId;
|
||||||
|
series.MalIds = seriesInfo.MalIds;
|
||||||
|
series.AniListIds = seriesInfo.AniListIds;
|
||||||
series.AirTime = seriesInfo.AirTime;
|
series.AirTime = seriesInfo.AirTime;
|
||||||
series.Overview = seriesInfo.Overview;
|
series.Overview = seriesInfo.Overview;
|
||||||
series.OriginalLanguage = seriesInfo.OriginalLanguage;
|
series.OriginalLanguage = seriesInfo.OriginalLanguage;
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ namespace NzbDrone.Core.Tv
|
|||||||
Seasons = new List<Season>();
|
Seasons = new List<Season>();
|
||||||
Tags = new HashSet<int>();
|
Tags = new HashSet<int>();
|
||||||
OriginalLanguage = Language.English;
|
OriginalLanguage = Language.English;
|
||||||
|
MalIds = new HashSet<int>();
|
||||||
|
AniListIds = new HashSet<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int TvdbId { get; set; }
|
public int TvdbId { get; set; }
|
||||||
@@ -24,6 +26,8 @@ namespace NzbDrone.Core.Tv
|
|||||||
public int TvMazeId { get; set; }
|
public int TvMazeId { get; set; }
|
||||||
public string ImdbId { get; set; }
|
public string ImdbId { get; set; }
|
||||||
public int TmdbId { get; set; }
|
public int TmdbId { get; set; }
|
||||||
|
public HashSet<int> MalIds { get; set; }
|
||||||
|
public HashSet<int> AniListIds { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string CleanTitle { get; set; }
|
public string CleanTitle { get; set; }
|
||||||
public string SortTitle { get; set; }
|
public string SortTitle { get; set; }
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ namespace NzbDrone.Core.Tv
|
|||||||
|
|
||||||
_seriesRepository.UpdateMany(series);
|
_seriesRepository.UpdateMany(series);
|
||||||
_logger.Debug("{0} series updated", series.Count);
|
_logger.Debug("{0} series updated", series.Count);
|
||||||
|
_eventAggregator.PublishEvent(new SeriesBulkEditedEvent(series));
|
||||||
|
|
||||||
return series;
|
return series;
|
||||||
}
|
}
|
||||||
@@ -298,6 +299,8 @@ namespace NzbDrone.Core.Tv
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.Debug("Tags not updated for '{0}'", series.Title);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using FluentValidation.Validators;
|
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Validation
|
namespace NzbDrone.Core.Validation
|
||||||
@@ -10,10 +9,5 @@ namespace NzbDrone.Core.Validation
|
|||||||
{
|
{
|
||||||
return ruleBuilder.Must(x => x.IsValidIpAddress()).WithMessage("Must contain wildcard (*) or a valid IP Address");
|
return ruleBuilder.Must(x => x.IsValidIpAddress()).WithMessage("Must contain wildcard (*) or a valid IP Address");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IRuleBuilderOptions<T, string> NotListenAllIp4Address<T>(this IRuleBuilder<T, string> ruleBuilder)
|
|
||||||
{
|
|
||||||
return ruleBuilder.SetValidator(new RegularExpressionValidator(@"^(?!0\.0\.0\.0)")).WithMessage("Use * instead of 0.0.0.0");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
using DryIoc;
|
using DryIoc;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
@@ -59,8 +60,11 @@ namespace NzbDrone.Host
|
|||||||
services.Configure<ForwardedHeadersOptions>(options =>
|
services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
{
|
{
|
||||||
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
|
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
|
||||||
options.KnownNetworks.Clear();
|
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
|
||||||
options.KnownProxies.Clear();
|
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("172.16.0.0"), 12));
|
||||||
|
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("192.168.0.0"), 16));
|
||||||
|
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("fc00::"), 7));
|
||||||
|
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("fe80::"), 10));
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddRouting(options => options.LowercaseUrls = true);
|
services.AddRouting(options => options.LowercaseUrls = true);
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ namespace Sonarr.Api.V3.Config
|
|||||||
|
|
||||||
SharedValidator.RuleFor(c => c.BindAddress)
|
SharedValidator.RuleFor(c => c.BindAddress)
|
||||||
.ValidIpAddress()
|
.ValidIpAddress()
|
||||||
.NotListenAllIp4Address()
|
|
||||||
.When(c => c.BindAddress != "*" && c.BindAddress != "localhost");
|
.When(c => c.BindAddress != "*" && c.BindAddress != "localhost");
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.Port).ValidPort();
|
SharedValidator.RuleFor(c => c.Port).ValidPort();
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ namespace Sonarr.Api.V3.Series
|
|||||||
IHandle<SeriesEditedEvent>,
|
IHandle<SeriesEditedEvent>,
|
||||||
IHandle<SeriesDeletedEvent>,
|
IHandle<SeriesDeletedEvent>,
|
||||||
IHandle<SeriesRenamedEvent>,
|
IHandle<SeriesRenamedEvent>,
|
||||||
|
IHandle<SeriesBulkEditedEvent>,
|
||||||
IHandle<MediaCoversUpdatedEvent>
|
IHandle<MediaCoversUpdatedEvent>
|
||||||
{
|
{
|
||||||
private readonly ISeriesService _seriesService;
|
private readonly ISeriesService _seriesService;
|
||||||
@@ -328,7 +329,7 @@ namespace Sonarr.Api.V3.Series
|
|||||||
{
|
{
|
||||||
foreach (var series in message.Series)
|
foreach (var series in message.Series)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(ModelAction.Deleted, series.ToResource());
|
BroadcastResourceChange(ModelAction.Deleted, GetSeriesResource(series, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,6 +339,15 @@ namespace Sonarr.Api.V3.Series
|
|||||||
BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
|
BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NonAction]
|
||||||
|
public void Handle(SeriesBulkEditedEvent message)
|
||||||
|
{
|
||||||
|
foreach (var series in message.Series)
|
||||||
|
{
|
||||||
|
BroadcastResourceChange(ModelAction.Updated, GetSeriesResource(series, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[NonAction]
|
[NonAction]
|
||||||
public void Handle(MediaCoversUpdatedEvent message)
|
public void Handle(MediaCoversUpdatedEvent message)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,11 +15,13 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
_backupService = backupService;
|
_backupService = backupService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => _backupService.GetBackupFolder();
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
var path = resourceUrl.Replace("/backup/", "").Replace('/', Path.DirectorySeparatorChar);
|
var path = resourceUrl.Replace("/backup/", "").Replace('/', Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
return Path.Combine(_backupService.GetBackupFolder(), path);
|
return Path.Combine(FolderPath, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanHandle(string resourceUrl)
|
public override bool CanHandle(string resourceUrl)
|
||||||
|
|||||||
@@ -8,13 +8,20 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
{
|
{
|
||||||
public class BrowserConfig : UrlBaseReplacementResourceMapperBase
|
public class BrowserConfig : UrlBaseReplacementResourceMapperBase
|
||||||
{
|
{
|
||||||
|
private readonly IAppFolderInfo _appFolderInfo;
|
||||||
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
|
|
||||||
public BrowserConfig(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger)
|
public BrowserConfig(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger)
|
||||||
: base(diskProvider, configFileProvider, logger)
|
: base(diskProvider, configFileProvider, logger)
|
||||||
{
|
{
|
||||||
FilePath = Path.Combine(appFolderInfo.StartUpFolder, configFileProvider.UiFolder, "Content", "browserconfig.xml");
|
_appFolderInfo = appFolderInfo;
|
||||||
|
_configFileProvider = configFileProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder);
|
||||||
|
protected override string FilePath => Path.Combine(FolderPath, "Content", "browserconfig.xml");
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
return FilePath;
|
return FilePath;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
|
|
||||||
var mapper = _diskMappers.Single(m => m.CanHandle(resourceUrl));
|
var mapper = _diskMappers.Single(m => m.CanHandle(resourceUrl));
|
||||||
var pathToFile = mapper.Map(resourceUrl);
|
var pathToFile = mapper.Map(resourceUrl);
|
||||||
|
|
||||||
|
if (pathToFile == null)
|
||||||
|
{
|
||||||
|
return resourceUrl;
|
||||||
|
}
|
||||||
|
|
||||||
var hash = _hashProvider.ComputeMd5(pathToFile).ToBase64();
|
var hash = _hashProvider.ComputeMd5(pathToFile).ToBase64();
|
||||||
|
|
||||||
return resourceUrl + "?h=" + hash.Trim('=');
|
return resourceUrl + "?h=" + hash.Trim('=');
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder);
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
var fileName = "favicon.ico";
|
var fileName = "favicon.ico";
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
|
|
||||||
var path = Path.Combine("Content", "Images", "Icons", fileName);
|
var path = Path.Combine("Content", "Images", "Icons", fileName);
|
||||||
|
|
||||||
return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path);
|
return Path.Combine(FolderPath, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanHandle(string resourceUrl)
|
public override bool CanHandle(string resourceUrl)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Text.RegularExpressions;
|
|||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
namespace Sonarr.Http.Frontend.Mappers
|
namespace Sonarr.Http.Frontend.Mappers
|
||||||
{
|
{
|
||||||
@@ -13,19 +14,22 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
private readonly Lazy<ICacheBreakerProvider> _cacheBreakProviderFactory;
|
private readonly Lazy<ICacheBreakerProvider> _cacheBreakProviderFactory;
|
||||||
private static readonly Regex ReplaceRegex = new Regex(@"(?:(?<attribute>href|src)=\"")(?<path>.*?(?<extension>css|js|png|ico|ics|svg|json))(?:\"")(?:\s(?<nohash>data-no-hash))?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
private static readonly Regex ReplaceRegex = new Regex(@"(?:(?<attribute>href|src)=\"")(?<path>.*?(?<extension>css|js|png|ico|ics|svg|json))(?:\"")(?:\s(?<nohash>data-no-hash))?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
|
private string _urlBase;
|
||||||
private string _generatedContent;
|
private string _generatedContent;
|
||||||
|
|
||||||
protected HtmlMapperBase(IDiskProvider diskProvider,
|
protected HtmlMapperBase(IDiskProvider diskProvider,
|
||||||
|
IConfigFileProvider configFileProvider,
|
||||||
Lazy<ICacheBreakerProvider> cacheBreakProviderFactory,
|
Lazy<ICacheBreakerProvider> cacheBreakProviderFactory,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(diskProvider, logger)
|
: base(diskProvider, logger)
|
||||||
{
|
{
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_cacheBreakProviderFactory = cacheBreakProviderFactory;
|
_cacheBreakProviderFactory = cacheBreakProviderFactory;
|
||||||
|
|
||||||
|
_urlBase = configFileProvider.UrlBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string HtmlPath;
|
protected abstract string HtmlPath { get; }
|
||||||
protected string UrlBase;
|
|
||||||
|
|
||||||
protected override Stream GetContentStream(string filePath)
|
protected override Stream GetContentStream(string filePath)
|
||||||
{
|
{
|
||||||
@@ -62,10 +66,10 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
url = cacheBreakProvider.AddCacheBreakerToPath(match.Groups["path"].Value);
|
url = cacheBreakProvider.AddCacheBreakerToPath(match.Groups["path"].Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{match.Groups["attribute"].Value}=\"{UrlBase}{url}\"";
|
return $"{match.Groups["attribute"].Value}=\"{_urlBase}{url}\"";
|
||||||
});
|
});
|
||||||
|
|
||||||
text = text.Replace("__URL_BASE__", UrlBase);
|
text = text.Replace("__URL_BASE__", _urlBase);
|
||||||
|
|
||||||
_generatedContent = text;
|
_generatedContent = text;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
{
|
{
|
||||||
public class IndexHtmlMapper : HtmlMapperBase
|
public class IndexHtmlMapper : HtmlMapperBase
|
||||||
{
|
{
|
||||||
|
private readonly IAppFolderInfo _appFolderInfo;
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
|
|
||||||
public IndexHtmlMapper(IAppFolderInfo appFolderInfo,
|
public IndexHtmlMapper(IAppFolderInfo appFolderInfo,
|
||||||
@@ -16,15 +17,16 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
IConfigFileProvider configFileProvider,
|
IConfigFileProvider configFileProvider,
|
||||||
Lazy<ICacheBreakerProvider> cacheBreakProviderFactory,
|
Lazy<ICacheBreakerProvider> cacheBreakProviderFactory,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(diskProvider, cacheBreakProviderFactory, logger)
|
: base(diskProvider, configFileProvider, cacheBreakProviderFactory, logger)
|
||||||
{
|
{
|
||||||
|
_appFolderInfo = appFolderInfo;
|
||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
|
|
||||||
HtmlPath = Path.Combine(appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, "index.html");
|
|
||||||
UrlBase = configFileProvider.UrlBase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder);
|
||||||
|
protected override string HtmlPath => Path.Combine(FolderPath, "index.html");
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
return HtmlPath;
|
return HtmlPath;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,14 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
_appFolderInfo = appFolderInfo;
|
_appFolderInfo = appFolderInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => _appFolderInfo.GetLogFolder();
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||||
path = Path.GetFileName(path);
|
path = Path.GetFileName(path);
|
||||||
|
|
||||||
return Path.Combine(_appFolderInfo.GetLogFolder(), path);
|
return Path.Combine(FolderPath, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanHandle(string resourceUrl)
|
public override bool CanHandle(string resourceUrl)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
{
|
{
|
||||||
public class LoginHtmlMapper : HtmlMapperBase
|
public class LoginHtmlMapper : HtmlMapperBase
|
||||||
{
|
{
|
||||||
|
private readonly IAppFolderInfo _appFolderInfo;
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
|
|
||||||
public LoginHtmlMapper(IAppFolderInfo appFolderInfo,
|
public LoginHtmlMapper(IAppFolderInfo appFolderInfo,
|
||||||
@@ -16,14 +17,16 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
Lazy<ICacheBreakerProvider> cacheBreakProviderFactory,
|
Lazy<ICacheBreakerProvider> cacheBreakProviderFactory,
|
||||||
IConfigFileProvider configFileProvider,
|
IConfigFileProvider configFileProvider,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(diskProvider, cacheBreakProviderFactory, logger)
|
: base(diskProvider, configFileProvider, cacheBreakProviderFactory, logger)
|
||||||
{
|
{
|
||||||
|
_appFolderInfo = appFolderInfo;
|
||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
HtmlPath = Path.Combine(appFolderInfo.StartUpFolder, configFileProvider.UiFolder, "login.html");
|
|
||||||
UrlBase = configFileProvider.UrlBase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder);
|
||||||
|
protected override string HtmlPath => Path.Combine(FolderPath, "login.html");
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
return HtmlPath;
|
return HtmlPath;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
{
|
{
|
||||||
public class ManifestMapper : UrlBaseReplacementResourceMapperBase
|
public class ManifestMapper : UrlBaseReplacementResourceMapperBase
|
||||||
{
|
{
|
||||||
|
private readonly IAppFolderInfo _appFolderInfo;
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
|
|
||||||
private string _generatedContent;
|
private string _generatedContent;
|
||||||
@@ -15,11 +16,14 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
public ManifestMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger)
|
public ManifestMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, IConfigFileProvider configFileProvider, Logger logger)
|
||||||
: base(diskProvider, configFileProvider, logger)
|
: base(diskProvider, configFileProvider, logger)
|
||||||
{
|
{
|
||||||
|
_appFolderInfo = appFolderInfo;
|
||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
FilePath = Path.Combine(appFolderInfo.StartUpFolder, configFileProvider.UiFolder, "Content", "manifest.json");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder);
|
||||||
|
protected override string FilePath => Path.Combine(FolderPath, "Content", "manifest.json");
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
return FilePath;
|
return FilePath;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover");
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||||
path = path.Trim(Path.DirectorySeparatorChar);
|
path = path.Trim(Path.DirectorySeparatorChar);
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder);
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
var path = Path.Combine("Content", "robots.txt");
|
var path = Path.Combine("Content", "robots.txt");
|
||||||
|
|
||||||
return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path);
|
return Path.Combine(FolderPath, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanHandle(string resourceUrl)
|
public override bool CanHandle(string resourceUrl)
|
||||||
|
|||||||
@@ -18,12 +18,14 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder);
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||||
path = path.Trim(Path.DirectorySeparatorChar);
|
path = path.Trim(Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
return Path.Combine(_appFolderInfo.StartUpFolder, _configFileProvider.UiFolder, path);
|
return Path.Combine(FolderPath, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanHandle(string resourceUrl)
|
public override bool CanHandle(string resourceUrl)
|
||||||
|
|||||||
@@ -27,14 +27,28 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
_caseSensitive = RuntimeInfo.IsProduction ? DiskProviderBase.PathStringComparison : StringComparison.OrdinalIgnoreCase;
|
_caseSensitive = RuntimeInfo.IsProduction ? DiskProviderBase.PathStringComparison : StringComparison.OrdinalIgnoreCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract string Map(string resourceUrl);
|
protected abstract string FolderPath { get; }
|
||||||
|
protected abstract string MapPath(string resourceUrl);
|
||||||
|
|
||||||
public abstract bool CanHandle(string resourceUrl);
|
public abstract bool CanHandle(string resourceUrl);
|
||||||
|
|
||||||
|
public string Map(string resourceUrl)
|
||||||
|
{
|
||||||
|
var filePath = Path.GetFullPath(MapPath(resourceUrl));
|
||||||
|
var parentPath = Path.GetFullPath(FolderPath) + Path.DirectorySeparatorChar;
|
||||||
|
|
||||||
|
return filePath.StartsWith(parentPath) ? filePath : null;
|
||||||
|
}
|
||||||
|
|
||||||
public Task<IActionResult> GetResponse(string resourceUrl)
|
public Task<IActionResult> GetResponse(string resourceUrl)
|
||||||
{
|
{
|
||||||
var filePath = Map(resourceUrl);
|
var filePath = Map(resourceUrl);
|
||||||
|
|
||||||
|
if (filePath == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<IActionResult>(null);
|
||||||
|
}
|
||||||
|
|
||||||
if (_diskProvider.FileExists(filePath, _caseSensitive))
|
if (_diskProvider.FileExists(filePath, _caseSensitive))
|
||||||
{
|
{
|
||||||
if (!_mimeTypeProvider.TryGetContentType(filePath, out var contentType))
|
if (!_mimeTypeProvider.TryGetContentType(filePath, out var contentType))
|
||||||
|
|||||||
@@ -16,12 +16,14 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
_appFolderInfo = appFolderInfo;
|
_appFolderInfo = appFolderInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string FolderPath => _appFolderInfo.GetUpdateLogFolder();
|
||||||
|
|
||||||
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar);
|
||||||
path = Path.GetFileName(path);
|
path = Path.GetFileName(path);
|
||||||
|
|
||||||
return Path.Combine(_appFolderInfo.GetUpdateLogFolder(), path);
|
return Path.Combine(FolderPath, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanHandle(string resourceUrl)
|
public override bool CanHandle(string resourceUrl)
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ namespace Sonarr.Http.Frontend.Mappers
|
|||||||
_urlBase = configFileProvider.UrlBase;
|
_urlBase = configFileProvider.UrlBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string FilePath;
|
protected abstract string FilePath { get; }
|
||||||
|
|
||||||
public override string Map(string resourceUrl)
|
protected override string MapPath(string resourceUrl)
|
||||||
{
|
{
|
||||||
return FilePath;
|
return FilePath;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
@@ -16,6 +17,7 @@ namespace Sonarr.Http.Frontend
|
|||||||
{
|
{
|
||||||
private readonly IEnumerable<IMapHttpRequestsToDisk> _requestMappers;
|
private readonly IEnumerable<IMapHttpRequestsToDisk> _requestMappers;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
private static readonly Regex InvalidPathRegex = new (@"([\/\\]|%2f|%5c)\.\.|\.\.([\/\\]|%2f|%5c)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
public StaticResourceController(IEnumerable<IMapHttpRequestsToDisk> requestMappers,
|
public StaticResourceController(IEnumerable<IMapHttpRequestsToDisk> requestMappers,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
@@ -50,6 +52,11 @@ namespace Sonarr.Http.Frontend
|
|||||||
{
|
{
|
||||||
path = "/" + (path ?? "");
|
path = "/" + (path ?? "");
|
||||||
|
|
||||||
|
if (InvalidPathRegex.IsMatch(path))
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
var mapper = _requestMappers.SingleOrDefault(m => m.CanHandle(path));
|
var mapper = _requestMappers.SingleOrDefault(m => m.CanHandle(path));
|
||||||
|
|
||||||
if (mapper != null)
|
if (mapper != null)
|
||||||
|
|||||||
Reference in New Issue
Block a user