Compare commits

..

27 Commits

Author SHA1 Message Date
Bogdan
7bada440d2 Log invalid torrent files contents as debug
Fixes #2169
2024-07-12 13:00:23 +03:00
Bogdan
803c4752db Fixed: Sending health restored notifications with Gotify
Fixed #2176
2024-07-11 13:35:02 +03:00
Bogdan
c0777474c0 Bump Polly 2024-07-09 23:47:23 +03:00
Weblate
66dcea5604 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: MattiaPell <mattiapellegrini16@gmail.com>
Co-authored-by: Serhii Matrunchyk <serhii@digitalidea.studio>
Co-authored-by: Taylan Tatlı <taylantatli90@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: quek76 <quek@libertysurf.fr>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/
Translation: Servarr/Prowlarr
2024-07-09 11:06:17 +03:00
Qstick
a2a12d2450 Update SonarCloud pipeline versions (#2171)
* Update SonarCloud pipeline versions

* Update reportgenerator to remove PublishCodeCoverage dep warnings
2024-07-07 17:55:24 +03:00
Bogdan
39593bd5a8 Bump version to 1.21.0 2024-07-07 10:44:00 +03:00
Bogdan
45d8a8a4e6 Minor fixes and cover link for SubsPlease 2024-07-06 22:12:36 +03:00
Bogdan
a4546c77ce Avoid invalid requests for Nebulance 2024-07-06 11:33:21 +03:00
Bogdan
d69bf6360a Fixed: (Nebulance) Improve searching by release names 2024-07-06 09:21:55 +03:00
Bogdan
da9ce5b5c3 New: Enable "Sync Anime Standard Format Search" by default for new Sonarr apps 2024-07-05 22:26:34 +03:00
Bogdan
e092098101 Minor improvements to season parsing from titles for AnimeBytes 2024-07-05 16:39:04 +03:00
Bogdan
1a89a79b74 Avoid NullRef for missing filelist and tags fields 2024-07-05 16:13:32 +03:00
Bogdan
cb6bf49922 New: (Nebulance) Improvements for season and episode searching 2024-07-05 12:42:51 +03:00
Bogdan
4bcaba0be0 Fixed: Trimming disabled logs database
(cherry picked from commit d5dff8e8d6301b661a713702e1c476705423fc4f)
2024-07-01 05:41:37 +03:00
Bogdan
220ef723c7 Bump version to 1.20.1 2024-06-30 07:22:49 +03:00
Bogdan
9c599a6be4 New: (UI) Indexer privacy label
Fixes #2132
2024-06-28 05:43:09 +03:00
Bogdan
715ce1fc6c Refresh indexers list and status on page change 2024-06-28 04:57:24 +03:00
Bogdan
8c3a192dd0 Fixed: Ignore auth events from queries and grab stats 2024-06-28 04:56:18 +03:00
Bogdan
d22bf93dfd Fixed: Searches with season/episodes should not be treated as ID searches 2024-06-27 08:06:26 +03:00
Bogdan
886054fdf8 Bump indexers definition version to 11 2024-06-27 04:35:27 +03:00
Bogdan
4188510586 New: (Cardigann) Add info_category_8000 2024-06-27 04:35:27 +03:00
Bogdan
fedebca5e1 New: (Cardigann) Optional login selectorinputs and getselectorinputs 2024-06-27 04:35:27 +03:00
Bogdan
e2ce6437e9 Bump mac image to 12 2024-06-26 23:52:41 +03:00
Mark McDowall
bdae60bac9 Improvements to EnhancedSelectInput
(cherry picked from commit 4c622fd41289cd293a68a6a9f6b8da2a086edecb)
2024-06-26 04:47:25 +03:00
Bogdan
2d6c818aec Fixed: Exclude invalid releases from Newznab and Torznab parsers 2024-06-26 03:47:08 +03:00
Bogdan
a1d19852dc Switch TorrentsCSV to STJson 2024-06-21 02:25:21 +03:00
Bogdan
104c95f28f Bump version to 1.20.0 2024-06-20 19:03:57 +03:00
41 changed files with 535 additions and 267 deletions

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '1.19.0'
majorVersion: '1.21.0'
minorVersion: $[counter('minorVersion', 1)]
prowlarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'
@@ -20,7 +20,7 @@ variables:
innoVersion: '6.2.2'
windowsImage: 'windows-2022'
linuxImage: 'ubuntu-20.04'
macImage: 'macOS-11'
macImage: 'macOS-12'
trigger:
branches:
@@ -1169,7 +1169,7 @@ stages:
submodules: true
- powershell: Set-Service SCardSvr -StartupType Manual
displayName: Enable Windows Test Service
- task: SonarCloudPrepare@1
- task: SonarCloudPrepare@2
condition: eq(variables['System.PullRequest.IsFork'], 'False')
inputs:
SonarCloud: 'SonarCloud'
@@ -1187,21 +1187,16 @@ stages:
./build.sh --backend -f net6.0 -r win-x64
TEST_DIR=_tests/net6.0/win-x64/publish/ ./test.sh Windows Unit Coverage
displayName: Coverage Unit Tests
- task: SonarCloudAnalyze@1
- task: SonarCloudAnalyze@2
condition: eq(variables['System.PullRequest.IsFork'], 'False')
displayName: Publish SonarCloud Results
- task: reportgenerator@4
- task: reportgenerator@5
displayName: Generate Coverage Report
inputs:
reports: '$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml'
targetdir: '$(Build.SourcesDirectory)/CoverageResults/combined'
reporttypes: 'HtmlInline_AzurePipelines;Cobertura;Badges'
- task: PublishCodeCoverageResults@1
displayName: Publish Coverage Report
inputs:
codeCoverageTool: 'cobertura'
summaryFileLocation: './CoverageResults/combined/Cobertura.xml'
reportDirectory: './CoverageResults/combined/'
publishCodeCoverageResults: true
- stage: Report_Out
dependsOn:

View File

@@ -271,26 +271,29 @@ class EnhancedSelectInput extends Component {
this.setState({ isOpen: !this.state.isOpen });
};
onSelect = (value) => {
if (Array.isArray(this.props.value)) {
let newValue = null;
const index = this.props.value.indexOf(value);
onSelect = (newValue) => {
const { name, value, values, onChange } = this.props;
if (Array.isArray(value)) {
let arrayValue = null;
const index = value.indexOf(newValue);
if (index === -1) {
newValue = this.props.values.map((v) => v.key).filter((v) => (v === value) || this.props.value.includes(v));
arrayValue = values.map((v) => v.key).filter((v) => (v === newValue) || value.includes(v));
} else {
newValue = [...this.props.value];
newValue.splice(index, 1);
arrayValue = [...value];
arrayValue.splice(index, 1);
}
this.props.onChange({
name: this.props.name,
value: newValue
onChange({
name,
value: arrayValue
});
} else {
this.setState({ isOpen: false });
this.props.onChange({
name: this.props.name,
value
onChange({
name,
value: newValue
});
}
};
@@ -485,7 +488,7 @@ class EnhancedSelectInput extends Component {
values.map((v, index) => {
const hasParent = v.parentKey !== undefined;
const depth = hasParent ? 1 : 0;
const parentSelected = hasParent && value.includes(v.parentKey);
const parentSelected = hasParent && Array.isArray(value) && value.includes(v.parentKey);
return (
<OptionComponent
key={v.key}

View File

@@ -34,7 +34,8 @@ function getSelectOptions(items) {
key: option.value,
value: option.name,
hint: option.hint,
parentKey: option.parentValue
parentKey: option.parentValue,
isDisabled: option.isDisabled
};
});
}

View File

@@ -4,16 +4,16 @@ import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRowButton from 'Components/Table/TableRowButton';
import { icons } from 'Helpers/Props';
import CapabilitiesLabel from 'Indexer/Index/Table/CapabilitiesLabel';
import PrivacyLabel from 'Indexer/Index/Table/PrivacyLabel';
import ProtocolLabel from 'Indexer/Index/Table/ProtocolLabel';
import { IndexerCapabilities } from 'Indexer/Indexer';
import firstCharToUpper from 'Utilities/String/firstCharToUpper';
import { IndexerCapabilities, IndexerPrivacy } from 'Indexer/Indexer';
import translate from 'Utilities/String/translate';
import styles from './SelectIndexerRow.css';
interface SelectIndexerRowProps {
name: string;
protocol: string;
privacy: string;
privacy: IndexerPrivacy;
language: string;
description: string;
capabilities: IndexerCapabilities;
@@ -63,7 +63,9 @@ function SelectIndexerRow(props: SelectIndexerRowProps) {
<TableRowCell>{description}</TableRowCell>
<TableRowCell>{translate(firstCharToUpper(privacy))}</TableRowCell>
<TableRowCell>
<PrivacyLabel privacy={privacy} />
</TableRowCell>
<TableRowCell>
<CapabilitiesLabel capabilities={capabilities} />

View File

@@ -1,4 +1,10 @@
import React, { useCallback, useMemo, useRef, useState } from 'react';
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { SelectProvider } from 'App/SelectContext';
import ClientSideCollectionAppState from 'App/State/ClientSideCollectionAppState';
@@ -22,12 +28,17 @@ import AddIndexerModal from 'Indexer/Add/AddIndexerModal';
import EditIndexerModalConnector from 'Indexer/Edit/EditIndexerModalConnector';
import NoIndexer from 'Indexer/NoIndexer';
import { executeCommand } from 'Store/Actions/commandActions';
import { cloneIndexer, testAllIndexers } from 'Store/Actions/indexerActions';
import {
cloneIndexer,
fetchIndexers,
testAllIndexers,
} from 'Store/Actions/indexerActions';
import {
setIndexerFilter,
setIndexerSort,
setIndexerTableOption,
} from 'Store/Actions/indexerIndexActions';
import { fetchIndexerStatus } from 'Store/Actions/indexerStatusActions';
import scrollPositions from 'Store/scrollPositions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
@@ -82,6 +93,11 @@ const IndexerIndex = withScrollPosition((props: IndexerIndexProps) => {
);
const [isSelectMode, setIsSelectMode] = useState(false);
useEffect(() => {
dispatch(fetchIndexers());
dispatch(fetchIndexerStatus());
}, [dispatch]);
const onAddIndexerPress = useCallback(() => {
setIsAddIndexerModalOpen(true);
}, [setIsAddIndexerModalOpen]);

View File

@@ -1,7 +1,6 @@
import React, { useCallback, useState } from 'react';
import { useSelector } from 'react-redux';
import { useSelect } from 'App/SelectContext';
import Label from 'Components/Label';
import IconButton from 'Components/Link/IconButton';
import RelativeDateCell from 'Components/Table/Cells/RelativeDateCell';
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
@@ -15,10 +14,10 @@ import createIndexerIndexItemSelector from 'Indexer/Index/createIndexerIndexItem
import Indexer from 'Indexer/Indexer';
import IndexerTitleLink from 'Indexer/IndexerTitleLink';
import { SelectStateInputProps } from 'typings/props';
import firstCharToUpper from 'Utilities/String/firstCharToUpper';
import translate from 'Utilities/String/translate';
import CapabilitiesLabel from './CapabilitiesLabel';
import IndexerStatusCell from './IndexerStatusCell';
import PrivacyLabel from './PrivacyLabel';
import ProtocolLabel from './ProtocolLabel';
import styles from './IndexerIndexRow.css';
@@ -175,7 +174,7 @@ function IndexerIndexRow(props: IndexerIndexRowProps) {
if (name === 'privacy') {
return (
<VirtualTableRowCell key={name} className={styles[name]}>
<Label>{translate(firstCharToUpper(privacy))}</Label>
<PrivacyLabel privacy={privacy} />
</VirtualTableRowCell>
);
}

View File

@@ -0,0 +1,20 @@
.publicLabel {
composes: label from '~Components/Label.css';
border-color: var(--dangerColor);
background-color: var(--dangerColor);
}
.semiPrivateLabel {
composes: label from '~Components/Label.css';
border-color: var(--warningColor);
background-color: var(--warningColor);
}
.privateLabel {
composes: label from '~Components/Label.css';
border-color: var(--infoColor);
background-color: var(--infoColor);
}

View File

@@ -0,0 +1,9 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'privateLabel': string;
'publicLabel': string;
'semiPrivateLabel': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -0,0 +1,20 @@
import React from 'react';
import Label from 'Components/Label';
import { IndexerPrivacy } from 'Indexer/Indexer';
import firstCharToUpper from 'Utilities/String/firstCharToUpper';
import translate from 'Utilities/String/translate';
import styles from './PrivacyLabel.css';
interface PrivacyLabelProps {
privacy: IndexerPrivacy;
}
function PrivacyLabel({ privacy }: PrivacyLabelProps) {
return (
<Label className={styles[`${privacy}Label`]}>
{translate(firstCharToUpper(privacy))}
</Label>
);
}
export default PrivacyLabel;

View File

@@ -24,6 +24,8 @@ export interface IndexerCapabilities extends ModelBase {
categories: IndexerCategory[];
}
export type IndexerPrivacy = 'public' | 'semiPrivate' | 'private';
export interface IndexerField extends ModelBase {
order: number;
name: string;
@@ -47,7 +49,7 @@ interface Indexer extends ModelBase {
supportsRedirect: boolean;
supportsPagination: boolean;
protocol: string;
privacy: string;
privacy: IndexerPrivacy;
priority: number;
fields: IndexerField[];
tags: number[];

View File

@@ -24,6 +24,7 @@ import TagListConnector from 'Components/TagListConnector';
import { kinds } from 'Helpers/Props';
import DeleteIndexerModal from 'Indexer/Delete/DeleteIndexerModal';
import EditIndexerModalConnector from 'Indexer/Edit/EditIndexerModalConnector';
import PrivacyLabel from 'Indexer/Index/Table/PrivacyLabel';
import Indexer, { IndexerCapabilities } from 'Indexer/Indexer';
import { createIndexerSelectorForHook } from 'Store/Selectors/createIndexerSelector';
import translate from 'Utilities/String/translate';
@@ -64,6 +65,7 @@ function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
fields,
tags,
protocol,
privacy,
capabilities = {} as IndexerCapabilities,
} = indexer as Indexer;
@@ -160,6 +162,11 @@ function IndexerInfoModalContent(props: IndexerInfoModalContentProps) {
title={translate('Language')}
data={language ?? '-'}
/>
<DescriptionListItem
descriptionClassName={styles.description}
title={translate('Privacy')}
data={privacy ? <PrivacyLabel privacy={privacy} /> : '-'}
/>
{vipExpiration ? (
<DescriptionListItem
descriptionClassName={styles.description}

View File

@@ -44,7 +44,7 @@ namespace NzbDrone.Core.Applications.Sonarr
public IEnumerable<int> AnimeSyncCategories { get; set; }
[FieldDefinition(5, Label = "Sync Anime Standard Format Search", Type = FieldType.Checkbox, HelpText = "Sync also searching for anime using the standard numbering", Advanced = true)]
public bool SyncAnimeStandardFormatSearch { get; set; }
public bool SyncAnimeStandardFormatSearch { get; set; } = true;
[FieldDefinition(6, Type = FieldType.Checkbox, Label = "ApplicationSettingsSyncRejectBlocklistedTorrentHashes", HelpText = "ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool SyncRejectBlocklistedTorrentHashesWhileGrabbing { get; set; }

View File

@@ -1,18 +1,26 @@
using NzbDrone.Core.Instrumentation;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Instrumentation;
namespace NzbDrone.Core.Housekeeping.Housekeepers
{
public class TrimLogDatabase : IHousekeepingTask
{
private readonly ILogRepository _logRepo;
private readonly IConfigFileProvider _configFileProvider;
public TrimLogDatabase(ILogRepository logRepo)
public TrimLogDatabase(ILogRepository logRepo, IConfigFileProvider configFileProvider)
{
_logRepo = logRepo;
_configFileProvider = configFileProvider;
}
public void Clean()
{
if (!_configFileProvider.LogDbEnabled)
{
return;
}
_logRepo.Trim();
}
}

View File

@@ -31,9 +31,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
!IsIdSearch;
public override bool IsIdSearch =>
Episode.IsNotNullOrWhiteSpace() ||
ImdbId.IsNotNullOrWhiteSpace() ||
Season.HasValue ||
TvdbId.HasValue ||
RId.HasValue ||
TraktId.HasValue ||
@@ -116,7 +114,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
string episodeString;
if (DateTime.TryParseExact($"{Season} {Episode}", "yyyy MM/dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var showDate))
{
episodeString = showDate.ToString("yyyy.MM.dd");
episodeString = showDate.ToString("yyyy.MM.dd", CultureInfo.InvariantCulture);
}
else if (Episode.IsNullOrWhiteSpace())
{

View File

@@ -26,11 +26,15 @@ namespace NzbDrone.Core.IndexerStats
{
var history = _historyService.Between(start, end);
var filteredHistory = history.Where(h => indexerIds.Contains(h.IndexerId));
var filteredHistory = history.Where(h => indexerIds.Contains(h.IndexerId)).ToArray();
var groupedByIndexer = filteredHistory.GroupBy(h => h.IndexerId);
var groupedByUserAgent = filteredHistory.GroupBy(h => h.Data.GetValueOrDefault("source") ?? "");
var groupedByHost = filteredHistory.GroupBy(h => h.Data.GetValueOrDefault("host") ?? "");
var groupedByIndexer = filteredHistory.GroupBy(h => h.IndexerId).ToArray();
var groupedByUserAgent = filteredHistory
.Where(h => h.EventType != HistoryEventType.IndexerAuth)
.GroupBy(h => h.Data.GetValueOrDefault("source") ?? "").ToArray();
var groupedByHost = filteredHistory
.Where(h => h.EventType != HistoryEventType.IndexerAuth)
.GroupBy(h => h.Data.GetValueOrDefault("host") ?? "").ToArray();
var indexerStatsList = new List<IndexerStatistics>();
var userAgentStatsList = new List<UserAgentStatistics>();
@@ -60,7 +64,7 @@ namespace NzbDrone.Core.IndexerStats
var temp = 0;
var elapsedTimeEvents = sortedEvents
.Where(h => int.TryParse(h.Data.GetValueOrDefault("elapsedTime"), out temp) && h.Data.GetValueOrDefault("cached") != "1")
.Select(h => temp)
.Select(_ => temp)
.ToArray();
indexerStats.AverageResponseTime = elapsedTimeEvents.Any() ? (int)elapsedTimeEvents.Average() : 0;
@@ -68,6 +72,7 @@ namespace NzbDrone.Core.IndexerStats
foreach (var historyEvent in sortedEvents)
{
var failed = !historyEvent.Successful;
switch (historyEvent.EventType)
{
case HistoryEventType.IndexerQuery:
@@ -101,8 +106,6 @@ namespace NzbDrone.Core.IndexerStats
indexerStats.NumberOfFailedRssQueries++;
}
break;
default:
break;
}
}
@@ -118,8 +121,8 @@ namespace NzbDrone.Core.IndexerStats
};
var sortedEvents = indexer.OrderBy(v => v.Date)
.ThenBy(v => v.Id)
.ToArray();
.ThenBy(v => v.Id)
.ToArray();
foreach (var historyEvent in sortedEvents)
{
@@ -128,13 +131,10 @@ namespace NzbDrone.Core.IndexerStats
case HistoryEventType.IndexerRss:
case HistoryEventType.IndexerQuery:
indexerStats.NumberOfQueries++;
break;
case HistoryEventType.ReleaseGrabbed:
indexerStats.NumberOfGrabs++;
break;
default:
break;
}
}
@@ -149,8 +149,8 @@ namespace NzbDrone.Core.IndexerStats
};
var sortedEvents = indexer.OrderBy(v => v.Date)
.ThenBy(v => v.Id)
.ToArray();
.ThenBy(v => v.Id)
.ToArray();
foreach (var historyEvent in sortedEvents)
{
@@ -163,8 +163,6 @@ namespace NzbDrone.Core.IndexerStats
case HistoryEventType.ReleaseGrabbed:
indexerStats.NumberOfGrabs++;
break;
default:
break;
}
}

View File

@@ -29,7 +29,7 @@ namespace NzbDrone.Core.IndexerVersions
/* Update Service will fall back if version # does not exist for an indexer per Ta */
private const string DEFINITION_BRANCH = "master";
private const int DEFINITION_VERSION = 10;
private const int DEFINITION_VERSION = 11;
// Used when moving yml to C#
private readonly List<string> _definitionBlocklist = new ()

View File

@@ -644,16 +644,16 @@ namespace NzbDrone.Core.Indexers.Definitions
private static int? ParseSeasonFromTitles(IReadOnlyCollection<string> titles)
{
var advancedSeasonRegex = new Regex(@"(\d+)(st|nd|rd|th) Season", RegexOptions.Compiled | RegexOptions.IgnoreCase);
var advancedSeasonRegex = new Regex(@"\b(?:(?<season>\d+)(?:st|nd|rd|th) Season|Season (?<season>\d+))\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
var seasonCharactersRegex = new Regex(@"(I{2,})$", RegexOptions.Compiled);
var seasonNumberRegex = new Regex(@"\b(?:S)?([2-9])$", RegexOptions.Compiled);
var seasonNumberRegex = new Regex(@"\b(?<!Part[- ._])(?:S)?(?<season>[2-9])$", RegexOptions.Compiled);
foreach (var title in titles)
{
var advancedSeasonRegexMatch = advancedSeasonRegex.Match(title);
if (advancedSeasonRegexMatch.Success)
{
return ParseUtil.CoerceInt(advancedSeasonRegexMatch.Groups[1].Value);
return ParseUtil.CoerceInt(advancedSeasonRegexMatch.Groups["season"].Value);
}
var seasonCharactersRegexMatch = seasonCharactersRegex.Match(title);
@@ -665,7 +665,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var seasonNumberRegexMatch = seasonNumberRegex.Match(title);
if (seasonNumberRegexMatch.Success)
{
return ParseUtil.CoerceInt(seasonNumberRegexMatch.Groups[1].Value);
return ParseUtil.CoerceInt(seasonNumberRegexMatch.Groups["season"].Value);
}
}

View File

@@ -74,7 +74,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
else if (DateTime.TryParseExact($"{searchCriteria.Season} {searchCriteria.Episode}", "yyyy MM/dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var showDate))
{
// Daily Episode
parameters.Name = showDate.ToString("yyyy.MM.dd");
parameters.Name = showDate.ToString("yyyy.MM.dd", CultureInfo.InvariantCulture);
parameters.Category = "Episode";
pageableRequests.Add(GetPagedRequests(parameters, btnResults, btnOffset));
}

View File

@@ -139,20 +139,13 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
{
var selectorSelector = ApplyGoTemplateText(selector.Selector, variables);
if (dom.Matches(selectorSelector))
{
selection = dom;
}
else
{
selection = QuerySelector(dom, selectorSelector);
}
selection = dom.Matches(selectorSelector) ? dom : QuerySelector(dom, selectorSelector);
if (selection == null)
{
if (required)
{
throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selectorSelector, dom.ToHtmlPretty()));
throw new Exception($"Selector \"{selectorSelector}\" didn't match {dom.ToHtmlPretty()}");
}
return null;
@@ -195,7 +188,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
{
if (required)
{
throw new Exception(string.Format("Attribute \"{0}\" is not set for element {1}", selector.Attribute, selection.ToHtmlPretty()));
throw new Exception($"Attribute \"{selector.Attribute}\" is not set for element {selection.ToHtmlPretty()}");
}
return null;
@@ -340,6 +333,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
case "info_cookie":
case "info_flaresolverr":
case "info_useragent":
case "info_category_8000":
case "cardigannCaptcha":
// no-op
break;

View File

@@ -332,37 +332,47 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
}
// selector inputs
if (login.Selectorinputs != null)
if (login.Selectorinputs != null && login.Selectorinputs.Any())
{
foreach (var selectorinput in login.Selectorinputs)
foreach (var selectorInput in login.Selectorinputs)
{
string value = null;
try
{
value = HandleSelector(selectorinput.Value, landingResultDocument.FirstElementChild);
pairs[selectorinput.Key] = value;
var value = HandleSelector(selectorInput.Value, landingResultDocument.FirstElementChild, required: !selectorInput.Value.Optional);
if (selectorInput.Value.Optional && value == null)
{
continue;
}
pairs[selectorInput.Key] = value;
}
catch (Exception ex)
{
throw new CardigannException(string.Format("Error while parsing selector input={0}, selector={1}, value={2}: {3}", selectorinput.Key, selectorinput.Value.Selector, value, ex.Message));
throw new CardigannException($"Error while parsing selector input={selectorInput.Key}, selector={selectorInput.Value.Selector}: {ex.Message}", ex);
}
}
}
// getselector inputs
if (login.Getselectorinputs != null)
if (login.Getselectorinputs != null && login.Getselectorinputs.Any())
{
foreach (var selectorinput in login.Getselectorinputs)
foreach (var selectorInput in login.Getselectorinputs)
{
string value = null;
try
{
value = HandleSelector(selectorinput.Value, landingResultDocument.FirstElementChild);
queryCollection[selectorinput.Key] = value;
var value = HandleSelector(selectorInput.Value, landingResultDocument.FirstElementChild, required: !selectorInput.Value.Optional);
if (selectorInput.Value.Optional && value == null)
{
continue;
}
queryCollection[selectorInput.Key] = value;
}
catch (Exception ex)
{
throw new CardigannException(string.Format("Error while parsing get selector input={0}, selector={1}, value={2}: {3}", selectorinput.Key, selectorinput.Value.Selector, value, ex.Message));
throw new CardigannException($"Error while parsing get selector input={selectorInput.Key}, selector={selectorInput.Value.Selector}: {ex.Message}", ex);
}
}
}

View File

@@ -66,7 +66,7 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
if (DateTime.TryParseExact($"{searchCriteria.Season} {searchCriteria.Episode}", "yyyy MM/dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var showDate))
{
query.Search = showDate.ToString("yyyy-MM-dd");
query.Search = showDate.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
}
else
{

View File

@@ -70,16 +70,17 @@ namespace NzbDrone.Core.Indexers.Headphones
protected override bool PostProcess(IndexerResponse indexerResponse, List<XElement> items, List<ReleaseInfo> releases)
{
var enclosureTypes = items.SelectMany(GetEnclosures).Select(v => v.Type).Distinct().ToArray();
if (enclosureTypes.Any() && enclosureTypes.Intersect(PreferredEnclosureMimeTypes).Empty())
{
if (enclosureTypes.Intersect(TorrentEnclosureMimeTypes).Any())
{
_logger.Warn("Feed does not contain {0}, found {1}, did you intend to add a Torznab indexer?", NzbEnclosureMimeType, enclosureTypes[0]);
}
else
{
_logger.Warn("Feed does not contain {0}, found {1}.", NzbEnclosureMimeType, enclosureTypes[0]);
_logger.Warn("{0} does not contain {1}, found {2}, did you intend to add a Torznab indexer?", indexerResponse.Request.Url, NzbEnclosureMimeType, enclosureTypes[0]);
return false;
}
_logger.Warn("{0} does not contain {1}, found {2}.", indexerResponse.Request.Url, NzbEnclosureMimeType, enclosureTypes[0]);
}
return true;

View File

@@ -5,7 +5,6 @@ using System.Linq;
using System.Net;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NLog;
@@ -42,7 +41,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new NebulanceRequestGenerator(Settings);
return new NebulanceRequestGenerator(Settings, _logger);
}
public override IParseIndexerResponse GetParser()
@@ -68,26 +67,6 @@ namespace NzbDrone.Core.Indexers.Definitions
return Task.FromResult(request);
}
protected override IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
{
var cleanReleases = base.CleanupReleases(releases, searchCriteria);
return FilterReleasesByQuery(cleanReleases, searchCriteria).ToList();
}
protected override IEnumerable<ReleaseInfo> FilterReleasesByQuery(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
{
if (!searchCriteria.IsRssSearch &&
searchCriteria.IsIdSearch &&
searchCriteria is TvSearchCriteria tvSearchCriteria &&
tvSearchCriteria.EpisodeSearchString.IsNotNullOrWhiteSpace())
{
releases = releases.Where(r => r.Title.IsNotNullOrWhiteSpace() && r.Title.ContainsIgnoreCase(tvSearchCriteria.EpisodeSearchString)).ToList();
}
return releases;
}
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
@@ -111,10 +90,12 @@ namespace NzbDrone.Core.Indexers.Definitions
public class NebulanceRequestGenerator : IIndexerRequestGenerator
{
private readonly NebulanceSettings _settings;
private readonly Logger _logger;
public NebulanceRequestGenerator(NebulanceSettings settings)
public NebulanceRequestGenerator(NebulanceSettings settings, Logger logger)
{
_settings = settings;
_logger = logger;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
@@ -136,40 +117,53 @@ namespace NzbDrone.Core.Indexers.Definitions
Age = ">0"
};
if (searchCriteria.SanitizedTvSearchString.IsNotNullOrWhiteSpace())
if (searchCriteria.TvMazeId is > 0)
{
queryParams.Name = "%" + Regex.Replace(searchCriteria.SanitizedTvSearchString, "[\\W]+", "%").Trim() + "%";
queryParams.TvMaze = searchCriteria.TvMazeId.Value;
}
else if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
{
queryParams.Imdb = searchCriteria.FullImdbId;
}
if (searchCriteria.TvMazeId.HasValue)
{
queryParams.Tvmaze = searchCriteria.TvMazeId.Value;
var searchQuery = searchCriteria.SanitizedSearchTerm.Trim();
if (searchCriteria.EpisodeSearchString.IsNotNullOrWhiteSpace())
if (searchQuery.IsNotNullOrWhiteSpace())
{
queryParams.Release = searchQuery;
}
if (DateTime.TryParseExact($"{searchCriteria.Season} {searchCriteria.Episode}", "yyyy MM/dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var showDate))
{
queryParams.Name = searchQuery;
queryParams.Release = showDate.ToString("yyyy.MM.dd", CultureInfo.InvariantCulture);
}
else
{
if (searchCriteria.Season.HasValue)
{
queryParams.Name = "%" + Regex.Replace(searchCriteria.EpisodeSearchString, "[\\W]+", "%").Trim() + "%";
queryParams.Season = searchCriteria.Season.Value;
}
if (searchCriteria.Episode.IsNotNullOrWhiteSpace() && int.TryParse(searchCriteria.Episode, out var episodeNumber))
{
queryParams.Episode = episodeNumber;
}
}
else if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace() && int.TryParse(searchCriteria.ImdbId, out var intImdb))
{
queryParams.Imdb = intImdb;
if (searchCriteria.EpisodeSearchString.IsNotNullOrWhiteSpace())
{
queryParams.Name = "%" + Regex.Replace(searchCriteria.EpisodeSearchString, "[\\W]+", "%").Trim() + "%";
}
if ((queryParams.Season.HasValue || queryParams.Episode.HasValue) &&
queryParams.Name.IsNullOrWhiteSpace() &&
queryParams.Release.IsNullOrWhiteSpace() &&
!queryParams.TvMaze.HasValue &&
queryParams.Imdb.IsNullOrWhiteSpace())
{
_logger.Debug("NBL API does not support season calls without name, series, id, imdb, tvmaze, or time keys.");
return new IndexerPageableRequestChain();
}
pageableRequests.Add(GetPagedRequests(queryParams, searchCriteria.Limit, searchCriteria.Offset));
if (queryParams.Name.IsNotNullOrWhiteSpace() && (queryParams.Tvmaze is > 0 || queryParams.Imdb is > 0))
{
queryParams = queryParams.Clone();
queryParams.Name = null;
pageableRequests.Add(GetPagedRequests(queryParams, searchCriteria.Limit, searchCriteria.Offset));
}
return pageableRequests;
}
@@ -187,9 +181,11 @@ namespace NzbDrone.Core.Indexers.Definitions
Age = ">0"
};
if (searchCriteria.SanitizedSearchTerm.IsNotNullOrWhiteSpace())
var searchQuery = searchCriteria.SanitizedSearchTerm.Trim();
if (searchQuery.IsNotNullOrWhiteSpace())
{
queryParams.Name = "%" + Regex.Replace(searchCriteria.SanitizedSearchTerm, "[\\W]+", "%").Trim() + "%";
queryParams.Release = searchQuery;
}
pageableRequests.Add(GetPagedRequests(queryParams, searchCriteria.Limit, searchCriteria.Offset));
@@ -231,11 +227,11 @@ namespace NzbDrone.Core.Indexers.Definitions
throw new IndexerException(indexerResponse, "Unexpected response status '{0}' code from indexer request", indexerResponse.HttpResponse.StatusCode);
}
JsonRpcResponse<NebulanceTorrents> jsonResponse;
JsonRpcResponse<NebulanceResponse> jsonResponse;
try
{
jsonResponse = STJson.Deserialize<JsonRpcResponse<NebulanceTorrents>>(indexerResponse.HttpResponse.Content);
jsonResponse = STJson.Deserialize<JsonRpcResponse<NebulanceResponse>>(indexerResponse.HttpResponse.Content);
}
catch (Exception ex)
{
@@ -249,7 +245,7 @@ namespace NzbDrone.Core.Indexers.Definitions
throw new IndexerException(indexerResponse, "Indexer API call returned an error [{0}]", jsonResponse.Error);
}
if (jsonResponse.Result.Items.Count == 0)
if (jsonResponse.Result?.Items == null || jsonResponse.Result.Items.Count == 0)
{
return torrentInfos;
}
@@ -264,14 +260,13 @@ namespace NzbDrone.Core.Indexers.Definitions
var release = new TorrentInfo
{
Title = title,
Guid = details,
InfoUrl = details,
PosterUrl = row.Banner,
DownloadUrl = row.Download,
Title = title.Trim(),
Categories = new List<IndexerCategory> { TvCategoryFromQualityParser.ParseTvShowQuality(row.ReleaseTitle) },
Size = ParseUtil.CoerceLong(row.Size),
Files = row.FileList.Length,
Files = row.FileList.Count(),
PublishDate = DateTime.Parse(row.PublishDateUtc, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal),
Grabs = ParseUtil.CoerceInt(row.Snatch),
Seeders = ParseUtil.CoerceInt(row.Seed),
@@ -280,7 +275,8 @@ namespace NzbDrone.Core.Indexers.Definitions
MinimumRatio = 0, // ratioless
MinimumSeedTime = row.Category.ToLower() == "season" ? 432000 : 86400, // 120 hours for seasons and 24 hours for episodes
DownloadVolumeFactor = 0, // ratioless tracker
UploadVolumeFactor = 1
UploadVolumeFactor = 1,
PosterUrl = row.Banner
};
if (row.TvMazeId.IsNotNullOrWhiteSpace())
@@ -312,60 +308,86 @@ namespace NzbDrone.Core.Indexers.Definitions
{
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Id { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Time { get; set; }
[JsonProperty(PropertyName="age", DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Age { get; set; }
[JsonProperty(PropertyName="tvmaze", DefaultValueHandling = DefaultValueHandling.Ignore)]
public int? Tvmaze { get; set; }
public int? TvMaze { get; set; }
[JsonProperty(PropertyName="imdb", DefaultValueHandling = DefaultValueHandling.Ignore)]
public int? Imdb { get; set; }
public string Imdb { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Hash { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string[] Tags { get; set; }
[JsonProperty(PropertyName="name", DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Name { get; set; }
[JsonProperty(PropertyName="release", DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Release { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Category { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Series { get; set; }
[JsonProperty(PropertyName="season", DefaultValueHandling = DefaultValueHandling.Ignore)]
public int? Season { get; set; }
[JsonProperty(PropertyName="episode", DefaultValueHandling = DefaultValueHandling.Ignore)]
public int? Episode { get; set; }
public NebulanceQuery Clone()
{
return MemberwiseClone() as NebulanceQuery;
}
}
public class NebulanceResponse
{
public List<NebulanceTorrent> Items { get; set; }
}
public class NebulanceTorrent
{
[JsonPropertyName("rls_name")]
public string ReleaseTitle { get; set; }
[JsonPropertyName("cat")]
public string Category { get; set; }
public string Size { get; set; }
public string Seed { get; set; }
public string Leech { get; set; }
public string Snatch { get; set; }
public string Download { get; set; }
[JsonPropertyName("file_list")]
public string[] FileList { get; set; }
public IEnumerable<string> FileList { get; set; } = Array.Empty<string>();
[JsonPropertyName("group_name")]
public string GroupName { get; set; }
[JsonPropertyName("series_banner")]
public string Banner { get; set; }
[JsonPropertyName("group_id")]
public string TorrentId { get; set; }
[JsonPropertyName("series_id")]
public string TvMazeId { get; set; }
[JsonPropertyName("rls_utc")]
public string PublishDateUtc { get; set; }
public IEnumerable<string> Tags { get; set; }
}
public class NebulanceTorrents
{
public List<NebulanceTorrent> Items { get; set; }
public int Results { get; set; }
public IEnumerable<string> Tags { get; set; } = Array.Empty<string>();
}
}

View File

@@ -74,16 +74,17 @@ namespace NzbDrone.Core.Indexers.Newznab
protected override bool PostProcess(IndexerResponse indexerResponse, List<XElement> items, List<ReleaseInfo> releases)
{
var enclosureTypes = items.SelectMany(GetEnclosures).Select(v => v.Type).Distinct().ToArray();
if (enclosureTypes.Any() && enclosureTypes.Intersect(PreferredEnclosureMimeTypes).Empty())
{
if (enclosureTypes.Intersect(TorrentEnclosureMimeTypes).Any())
{
_logger.Warn("Feed does not contain {0}, found {1}, did you intend to add a Torznab indexer?", NzbEnclosureMimeType, enclosureTypes[0]);
}
else
{
_logger.Warn("Feed does not contain {0}, found {1}.", NzbEnclosureMimeType, enclosureTypes[0]);
_logger.Warn("{0} does not contain {1}, found {2}, did you intend to add a Torznab indexer?", indexerResponse.Request.Url, NzbEnclosureMimeType, enclosureTypes[0]);
return false;
}
_logger.Warn("{0} does not contain {1}, found {2}.", indexerResponse.Request.Url, NzbEnclosureMimeType, enclosureTypes[0]);
}
return true;

View File

@@ -75,6 +75,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public class SubsPleaseRequestGenerator : IIndexerRequestGenerator
{
private static readonly Regex ResolutionRegex = new (@"\d{3,4}p", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private readonly NoAuthTorrentBaseSettings _settings;
public SubsPleaseRequestGenerator(NoAuthTorrentBaseSettings settings)
@@ -134,15 +136,6 @@ namespace NzbDrone.Core.Indexers.Definitions
private IEnumerable<IndexerRequest> GetSearchRequests(string term, SearchCriteriaBase searchCriteria)
{
var searchTerm = Regex.Replace(term, "\\[?SubsPlease\\]?\\s*", string.Empty, RegexOptions.IgnoreCase).Trim();
// If the search terms contain a resolution, remove it from the query sent to the API
var resMatch = Regex.Match(searchTerm, "\\d{3,4}[p|P]");
if (resMatch.Success)
{
searchTerm = searchTerm.Replace(resMatch.Value, string.Empty).Trim();
}
var queryParameters = new NameValueCollection
{
{ "tz", "UTC" }
@@ -154,6 +147,16 @@ namespace NzbDrone.Core.Indexers.Definitions
}
else
{
var searchTerm = Regex.Replace(term, "\\[?SubsPlease\\]?\\s*", string.Empty, RegexOptions.IgnoreCase).Trim();
// If the search terms contain a resolution, remove it from the query sent to the API
var resolutionMatch = ResolutionRegex.Match(searchTerm);
if (resolutionMatch.Success)
{
searchTerm = searchTerm.Replace(resolutionMatch.Value, string.Empty).Trim();
}
queryParameters.Set("f", "search");
queryParameters.Set("s", searchTerm);
}
@@ -201,7 +204,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var release = new TorrentInfo
{
InfoUrl = _settings.BaseUrl + $"shows/{value.Page}/",
InfoUrl = $"{_settings.BaseUrl}shows/{value.Page}/",
PublishDate = value.ReleaseDate.LocalDateTime,
Files = 1,
Categories = new List<IndexerCategory> { NewznabStandardCategory.TVAnime },
@@ -213,13 +216,18 @@ namespace NzbDrone.Core.Indexers.Definitions
UploadVolumeFactor = 1
};
if (value.ImageUrl.IsNotNullOrWhiteSpace())
{
release.PosterUrl = _settings.BaseUrl + value.ImageUrl.TrimStart('/');
}
if (value.Episode.ToLowerInvariant() == "movie")
{
release.Categories.Add(NewznabStandardCategory.MoviesOther);
}
// Ex: [SubsPlease] Shingeki no Kyojin (The Final Season) - 64 (1080p)
release.Title += $"[SubsPlease] {value.Show} - {value.Episode} ({d.Resolution}p)";
release.Title = $"[SubsPlease] {value.Show} - {value.Episode} ({d.Resolution}p)";
release.MagnetUrl = d.Magnet;
release.DownloadUrl = null;
release.Guid = d.Magnet;
@@ -269,6 +277,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public string Episode { get; set; }
public SubPleaseDownloadInfo[] Downloads { get; set; }
public string Xdcc { get; set; }
[JsonProperty("image_url")]
public string ImageUrl { get; set; }
public string Page { get; set; }
}

View File

@@ -3,10 +3,11 @@ using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Linq;
using System.Text.Json.Serialization;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions;
@@ -145,32 +146,31 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var releaseInfos = new List<ReleaseInfo>();
var jsonContent = JArray.Parse(indexerResponse.Content);
var jsonResponse = STJson.Deserialize<TorrentsCSVResponse>(indexerResponse.Content);
foreach (var torrent in jsonContent)
foreach (var torrent in jsonResponse.Torrents)
{
if (torrent == null)
{
continue;
}
var infoHash = torrent.Value<string>("infohash");
var title = torrent.Value<string>("name");
var size = torrent.Value<long>("size_bytes");
var seeders = torrent.Value<int?>("seeders") ?? 0;
var leechers = torrent.Value<int?>("leechers") ?? 0;
var grabs = torrent.Value<int?>("completed") ?? 0;
var publishDate = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.Value<long>("created_unix"));
var infoHash = torrent.InfoHash;
var title = torrent.Name;
var seeders = torrent.Seeders ?? 0;
var leechers = torrent.Leechers ?? 0;
var grabs = torrent.Completed ?? 0;
var publishDate = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.Created);
var release = new TorrentInfo
{
Title = title,
InfoUrl = $"{_settings.BaseUrl.TrimEnd('/')}/search/{title}", // there is no details link
Guid = $"magnet:?xt=urn:btih:{infoHash}",
InfoUrl = $"{_settings.BaseUrl.TrimEnd('/')}/search?q={title}", // there is no details link
Title = title,
InfoHash = infoHash, // magnet link is auto generated from infohash
Categories = new List<IndexerCategory> { NewznabStandardCategory.Other },
PublishDate = publishDate,
Size = size,
Size = torrent.Size,
Grabs = grabs,
Seeders = seeders,
Peers = leechers + seeders,
@@ -188,4 +188,29 @@ namespace NzbDrone.Core.Indexers.Definitions
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
public class TorrentsCSVResponse
{
public IReadOnlyCollection<TorrentsCSVTorrent> Torrents { get; set; }
}
public class TorrentsCSVTorrent
{
[JsonPropertyName("infohash")]
public string InfoHash { get; set; }
public string Name { get; set; }
[JsonPropertyName("size_bytes")]
public long Size { get; set; }
[JsonPropertyName("created_unix")]
public long Created { get; set; }
public int? Leechers { get; set; }
public int? Seeders { get; set; }
public int? Completed { get; set; }
}
}

View File

@@ -100,16 +100,17 @@ namespace NzbDrone.Core.Indexers.Torznab
protected override bool PostProcess(IndexerResponse indexerResponse, List<XElement> items, List<ReleaseInfo> releases)
{
var enclosureTypes = items.SelectMany(GetEnclosures).Select(v => v.Type).Distinct().ToArray();
if (enclosureTypes.Any() && enclosureTypes.Intersect(PreferredEnclosureMimeTypes).Empty())
{
if (enclosureTypes.Intersect(UsenetEnclosureMimeTypes).Any())
{
_logger.Warn("Feed does not contain {0}, found {1}, did you intend to add a Newznab indexer?", TorrentEnclosureMimeType, enclosureTypes[0]);
}
else
{
_logger.Warn("Feed does not contain {0}, found {1}.", TorrentEnclosureMimeType, enclosureTypes[0]);
_logger.Warn("{0} does not contain {1}, found {2}, did you intend to add a Newznab indexer?", indexerResponse.Request.Url, TorrentEnclosureMimeType, enclosureTypes[0]);
return false;
}
_logger.Warn("{0} does not contain {1}, found {2}.", indexerResponse.Request.Url, TorrentEnclosureMimeType, enclosureTypes[0]);
}
return true;

View File

@@ -290,9 +290,9 @@ namespace NzbDrone.Core.Indexers
Length = v.Attribute("length")?.Value?.ParseInt64() ?? 0
};
}
catch (Exception e)
catch (Exception ex)
{
_logger.Warn(e, "Failed to get enclosure for: {0}", item.Title());
_logger.Warn(ex, "Failed to get enclosure for: {0}", item.Title());
}
return null;

View File

@@ -24,7 +24,7 @@ namespace NzbDrone.Core.Indexers
}
catch
{
_logger.Info("Invalid torrent file contents: {0}", Encoding.ASCII.GetString(fileData));
_logger.Debug("Invalid torrent file contents: {0}", Encoding.ASCII.GetString(fileData));
throw;
}
}

View File

@@ -468,5 +468,14 @@
"Stats": "Estadístiques",
"Private": "Privat",
"Proxies": "Servidors intermediaris",
"Public": "Públic"
"Public": "Públic",
"DeleteSelectedIndexer": "Suprimeix els indexadors seleccionats",
"EditSyncProfile": "Afegeix perfil de sincronització",
"Menu": "Menú",
"OnGrabHelpText": "Al capturar llançament",
"ProxyValidationBadRequest": "No s'ha pogut provar el servidor intermediari. Codi d'estat: {statusCode}",
"Default": "Per defecte",
"GrabRelease": "Captura novetat",
"ManualGrab": "Captura manual",
"PrioritySettings": "Prioritat: {priority}"
}

View File

@@ -12,7 +12,7 @@
"Events": "Événements",
"Edit": "Modifier",
"DownloadClientStatusAllClientHealthCheckMessage": "Aucun client de téléchargement n'est disponible en raison d'échecs",
"DownloadClients": "Clients de téléchargement",
"DownloadClients": "Clients de télécharg.",
"Dates": "Dates",
"Date": "Date",
"Delete": "Supprimer",
@@ -404,9 +404,9 @@
"Website": "Site internet",
"AudioSearch": "Recherche de musique",
"BookSearch": "Recherche de livres",
"OnApplicationUpdate": "Sur la mise à jour de l'application",
"OnApplicationUpdateHelpText": "Lors de la mise à jour de l'app",
"IndexerNoDefinitionCheckHealthCheckMessage": "Les indexeurs ne sont pas définis et ne fonctionneront pas: {indexerNames}. Merci de les retirer et (ou) les ajouter à nouveau à {appName}",
"OnApplicationUpdate": "Lors de la mise à jour de l'application",
"OnApplicationUpdateHelpText": "Lors de la mise à jour de l'application",
"IndexerNoDefinitionCheckHealthCheckMessage": "Les indexeurs ne sont pas définis et ne fonctionneront pas : {indexerNames}. Merci de les retirer et (ou) les ajouter à nouveau à {appName}.",
"MovieSearch": "Recherche de films",
"TvSearch": "Recherche de séries TV",
"Application": "Applications",

View File

@@ -5,11 +5,11 @@
"TagsSettingsSummary": "Vedi tutte le etichette e come vengono utilizzate. Le etichette non utilizzate possono essere rimosse",
"SetTags": "Imposta Etichette",
"SelectAll": "Seleziona Tutto",
"Scheduled": "Programmato",
"Scheduled": "Pianificato",
"ReleaseBranchCheckOfficialBranchMessage": "La versione {0} non è una versione valida per le release di {appName}, non riceverai aggiornamenti",
"ProxyResolveIpHealthCheckMessage": "Impossibile risolvere l'indirizzo IP per l'Host Configurato del Proxy {proxyHostName}",
"NoChanges": "Nessuna Modifica",
"NoChange": "Nessuna Modifica",
"NoChanges": "Nessun Cambiamento",
"NoChange": "Nessun Cambio",
"LastWriteTime": "Orario di Ultima Scrittura",
"Indexer": "Indicizzatore",
"HideAdvanced": "Nascondi Avanzate",
@@ -35,8 +35,8 @@
"ShowAdvanced": "Mostra Avanzate",
"Settings": "Impostazioni",
"Security": "Sicurezza",
"Search": "Cerca",
"SaveChanges": "Salva Modifiche",
"Search": "Ricerca",
"SaveChanges": "Salva Cambiamenti",
"RestoreBackup": "Ripristina Backup",
"ReleaseStatus": "Stato Release",
"Refresh": "Aggiorna",
@@ -46,7 +46,7 @@
"Proxy": "Proxy",
"Protocol": "Protocollo",
"Options": "Opzioni",
"MoreInfo": "Maggiori Info",
"MoreInfo": "Ulteriori Informazioni",
"Logging": "Logging",
"LogFiles": "File di Log",
"Language": "Lingua",
@@ -91,15 +91,15 @@
"CertificateValidation": "Convalida del Certificato",
"Cancel": "Annulla",
"BypassProxyForLocalAddresses": "Evita il Proxy per gli Indirizzi Locali",
"Branch": "Ramo",
"Branch": "Branca",
"BindAddressHelpText": "Indirizzi IP validi, localhost o '*' per tutte le interfacce",
"BindAddress": "Indirizzo di Ascolto",
"Backups": "Backups",
"Backups": "Backup",
"BackupRetentionHelpText": "I backup più vecchi del periodo specificato saranno cancellati automaticamente",
"BackupIntervalHelpText": "Intervallo fra i backup automatici",
"BackupFolderHelpText": "I percorsi relativi saranno nella cartella AppData di {appName}",
"Automatic": "Automatico",
"AuthenticationMethodHelpText": "Inserisci Username e Password per accedere a {appName}",
"AuthenticationMethodHelpText": "Utilizza nome utente e password per accedere a {appName}",
"Authentication": "Autenticazione",
"ApplyTags": "Applica Etichette",
"Apply": "Applica",
@@ -109,14 +109,14 @@
"Warn": "Attenzione",
"Type": "Tipo",
"Title": "Titolo",
"Time": "Ora",
"TestAll": "Prova Tutti",
"Test": "Test",
"Time": "Orario",
"TestAll": "Prova Tutto",
"Test": "Prova",
"TableOptionsColumnsMessage": "Scegli quali colonne rendere visibili ed il loro ordine",
"TableOptions": "Opzioni della tabella",
"TableOptions": "Opzioni Tabella",
"SystemTimeCheckMessage": "L'orario di sistema è sbagliato di più di un giorno. Le attività pianificate potrebbero non essere eseguite correttamente fino alla correzione",
"Source": "Fonte",
"Shutdown": "Spegni",
"Shutdown": "Spegnimento",
"Seeders": "Seeders",
"Save": "Salva",
"Restart": "Riavvia",
@@ -139,15 +139,15 @@
"DeleteNotification": "Cancella Notifica",
"DeleteDownloadClient": "Cancella Client di Download",
"DeleteBackup": "Cancella Backup",
"DatabaseMigration": "Migrazione DB",
"DatabaseMigration": "Migrazione Database",
"ConnectSettings": "Impostazioni Collegamento",
"ConnectionLost": "Connessione Persa",
"Component": "Componente",
"Columns": "Colonne",
"DeleteBackupMessageText": "Sei sicuro di voler cancellare il backup '{0}'?",
"DeleteBackupMessageText": "Sei sicuro di voler cancellare il backup '{name}'?",
"CancelPendingTask": "Sei sicuro di voler cancellare questa operazione in sospeso?",
"BranchUpdateMechanism": "Ramo utilizzato dal sistema di aggiornamento esterno",
"BranchUpdate": "Ramo da usare per aggiornare {appName}",
"BranchUpdate": "Branca da usare per aggiornare {appName}",
"AddingTag": "Aggiungendo etichetta",
"Password": "Password",
"OnHealthIssueHelpText": "Quando c'è un problema",
@@ -162,41 +162,41 @@
"SettingsEnableColorImpairedMode": "Abilità la Modalità Daltonica",
"SendAnonymousUsageData": "Invia dati anonimi sull'uso",
"ScriptPath": "Percorso dello script",
"RssIsNotSupportedWithThisIndexer": "RSS non è supportato con questo Indicizzatore",
"RssIsNotSupportedWithThisIndexer": "RSS non è supportato con questo indicizzatore",
"Retention": "Ritenzione",
"Result": "Risultato",
"Restore": "Ripristina",
"RestartRequiredHelpTextWarning": "Richiede il riavvio per avere effetto",
"RestartProwlarr": "Riavvia {appName}",
"RestartNow": "Riavvia adesso",
"RestartNow": "Riavvia ora",
"ResetAPIKey": "Resetta la Chiave API",
"Reset": "Resetta",
"Reset": "Reimposta",
"RemovingTag": "Eliminando l'etichetta",
"RemoveFilter": "Rimuovi filtro",
"RemovedFromTaskQueue": "Rimosso dalla coda lavori",
"RefreshMovie": "Aggiorna il Film",
"ReadTheWikiForMoreInformation": "Leggi la Wiki per maggiori informazioni",
"ReadTheWikiForMoreInformation": "Leggi la Wiki per più informazioni",
"ProwlarrSupportsAnyIndexer": "{appName} supporta molti indicizzatori oltre a qualsiasi indicizzatore che utilizza lo standard Newznab/Torznab utilizzando \"Generic Newznab\" (per usenet) o \"Generic Torznab\" (per torrent). Cerca e seleziona il tuo indicizzatore da qua sotto.",
"ProwlarrSupportsAnyDownloadClient": "{appName} supporta qualunque client di download elencato sotto.",
"ProxyUsernameHelpText": "Devi inserire nome utente e password solo se richiesto. Altrimenti lascia vuoto.",
"ProxyType": "Tipo di Proxy",
"ProxyType": "Tipo Proxy",
"ProxyPasswordHelpText": "Devi inserire nome utente e password solo se richiesto. Altrimenti lascia vuoto.",
"ProxyBypassFilterHelpText": "Usa ',' come separatore, e '*.' come jolly per i sottodomini",
"PortNumber": "Numero di porta",
"ProxyBypassFilterHelpText": "Usa ',' come separatore, e '*.' come wildcard per i sottodomini",
"PortNumber": "Numero Porta",
"Port": "Porta",
"PendingChangesStayReview": "Rimani e rivedi modifiche",
"PendingChangesMessage": "Hai cambiamenti non salvati, sicuro di voler abbandonare la pagina?",
"PendingChangesStayReview": "Rimani e rivedi i cambiamenti",
"PendingChangesMessage": "Hai dei cambiamenti non salvati, sei sicuro di volere lasciare questa pagina?",
"PendingChangesDiscardChanges": "Abbandona le modifiche ed esci",
"PageSizeHelpText": "Numero di voci da mostrare in ogni pagina",
"PackageVersion": "Versione del Pacchetto",
"OpenBrowserOnStart": "Apri il browser all'avvio",
"OpenBrowserOnStart": "Apri browser all'avvio",
"NoUpdatesAreAvailable": "Nessun aggiornamento disponibile",
"NoTagsHaveBeenAddedYet": "Nessuna etichetta è ancora stata aggiunta",
"NoLogFiles": "Nessun file di log",
"NoLeaveIt": "No, Lascialo",
"NoBackupsAreAvailable": "Nessun Backup disponibile",
"NoBackupsAreAvailable": "Nessun backup disponibile",
"New": "Nuovo",
"Mode": "Modo",
"Mode": "Modalità",
"Mechanism": "Meccanismo",
"Manual": "Manuale",
"MaintenanceRelease": "Release di Manutenzione: correzione di bug e altri miglioramenti. Vedi la storia dei Commit su Github per maggiori dettagli",
@@ -209,8 +209,7 @@
"IgnoredAddresses": "Indirizzi Ignorati",
"GeneralSettings": "Impostazioni Generali",
"ForMoreInformationOnTheIndividualDownloadClients": "Per più informazioni sui singoli client di download clicca sui pulsanti info.",
"Fixed": "Fissato",
"FilterPlaceHolder": "Cerca Indicizzatori",
"FilterPlaceHolder": "Cerca indicizzatori",
"ExistingTag": "Etichetta esistente",
"Exception": "Eccezione",
"ErrorLoadingContents": "Errore nel caricare i contenuti",
@@ -219,22 +218,22 @@
"EnableInteractiveSearch": "Abilita la Ricerca Interattiva",
"EnableAutomaticSearchHelpText": "Sarà usata quando la ricerca automatica è eseguita dalla l'intrfaccia o da {appName}",
"EnableAutomaticSearch": "Attiva la Ricerca Automatica",
"DeleteTagMessageText": "Sei sicuro di voler eliminare l'etichetta '{0}'?",
"DeleteNotificationMessageText": "Sei sicuro di voler eliminare la notifica '{0}'?",
"DeleteDownloadClientMessageText": "Sei sicuro di voler eliminare il client di download '{0}'?",
"DeleteTagMessageText": "Sei sicuro di voler eliminare l'etichetta '{label}'?",
"DeleteNotificationMessageText": "Sei sicuro di voler eliminare la notifica '{name}'?",
"DeleteDownloadClientMessageText": "Sei sicuro di voler eliminare il client di download '{name}'?",
"BeforeUpdate": "Prima dell'aggiornamento",
"Usenet": "Usenet",
"Uptime": "Tempo di attività",
"YesCancel": "Si, Cancella",
"YesCancel": "Sì, Cancella",
"Version": "Versione",
"Username": "Nome utente",
"Username": "Nome Utente",
"UseProxy": "Usa Proxy",
"UrlBaseHelpText": "Per il supporto al reverse proxy, di default è vuoto",
"URLBase": "Base Url",
"UpdateScriptPathHelpText": "Percorso verso uno script personalizzato che prende un pacchetto di aggiornamento estratto e gestisce il resto del processo di aggiornamento",
"UpdateMechanismHelpText": "Usa il sistema di aggiornamento interno di {appName} o uno script",
"UpdateMechanismHelpText": "Usa il sistema di aggiornamento incorporato di {appName} o uno script",
"UpdateAutomaticallyHelpText": "Scarica e installa automaticamente gli aggiornamenti. Sarai comunque in grado in installarli da Sistema: Aggiornamenti",
"UnsavedChanges": "Modifiche non salvate",
"UnsavedChanges": "Cambiamenti Non Salvati",
"UnableToLoadUISettings": "Impossibile caricare le impostazioni interfaccia",
"UnableToLoadTags": "Impossibile caricare le Etichette",
"UnableToLoadNotifications": "Impossibile caricare le Notifiche",
@@ -255,7 +254,7 @@
"TagIsNotUsedAndCanBeDeleted": "L'etichetta non è in uso e può essere eliminata",
"TagCannotBeDeletedWhileInUse": "Non può essere cancellato mentre è in uso",
"SuggestTranslationChange": "Suggerisci un cambio nella traduzione",
"StartupDirectory": "Cartella di avvio",
"StartupDirectory": "Cartella di Avvio",
"StartTypingOrSelectAPathBelow": "Comincia a digitare o seleziona un percorso sotto",
"SSLPort": "Porta SSL",
"SSLCertPathHelpText": "Percorso file pfx",
@@ -300,15 +299,15 @@
"Donations": "Donazioni",
"EnableRssHelpText": "Abilita feed RSS per l'Indicizzatore",
"HomePage": "Pagina Iniziale",
"Id": "Id",
"Id": "ID",
"IndexerHealthCheckNoIndexers": "Nessun Indicizzatore abilitato, {appName} non restituirà risultati di ricerca",
"EnableRss": "Abilita RSS",
"NoLinks": "Nessun Collegamento",
"Rss": "RSS",
"Wiki": "Wiki",
"AllIndexersHiddenDueToFilter": "Tutti gli Indexer sono nascosti a causa del filtro applicato.",
"DeleteApplicationMessageText": "Sei sicuro di voler eliminare l'applicazione '{0}'?",
"DeleteIndexerProxyMessageText": "Sei sicuro di voler eliminare il proxy '{0}'?",
"DeleteApplicationMessageText": "Sei sicuro di voler eliminare l'applicazione '{name}'?",
"DeleteIndexerProxyMessageText": "Sei sicuro di voler eliminare il proxy '{name}'?",
"Presets": "Preset",
"SearchIndexers": "Cerca Indicizzatori",
"UnableToAddANewIndexerProxyPleaseTryAgain": "Impossibile aggiungere un nuovo proxy per l'Indicizzatore, riprova.",
@@ -342,7 +341,7 @@
"MappedDrivesRunningAsService": "Le unità di rete mappate non sono disponibili eseguendo come servizio di Windows. Vedere le FAQ per maggiori informazioni",
"No": "No",
"UnableToLoadIndexers": "Impossibile caricare gli Indicizzatori",
"Yes": "Si",
"Yes": "Sì",
"AddIndexerProxy": "Aggiungi proxy dell'Indexer",
"AudioSearch": "Ricerca Audio",
"BookSearch": "Ricerca Libri",
@@ -385,7 +384,7 @@
"IndexerDetails": "Dettagli dell'Indicizzatore",
"IndexerInfo": "Info sull'Indicizzatore",
"IndexerName": "Nome dell'Indicizzatore",
"IndexerNoDefinitionCheckHealthCheckMessage": "Gli indicizzatori non hanno una definizione e non funzioneranno: {0}. Si prega di rimuoverli e/o di riaggiungerli a {appName}",
"IndexerNoDefinitionCheckHealthCheckMessage": "Gli indicizzatori non hanno una definizione e non funzioneranno: {indexerNames}. Si prega di rimuoverli e/o di riaggiungerli a {appName}",
"HistoryCleanup": "Pulizia della Cronologia",
"IndexerRss": "RSS dell'Indicizzatore",
"IndexerSite": "Sito dell'Indicizzatore",
@@ -434,10 +433,10 @@
"MinimumSeeders": "Seeder Minimi",
"InstanceName": "Nome Istanza",
"InstanceNameHelpText": "Nome istanza nella scheda e per il nome dell'app nel Syslog",
"ThemeHelpText": "Cambia il Tema dell'interfaccia dellapplicazione, il Tema 'Auto' userà il suo Tema di Sistema per impostare la modalità Chiara o Scura. Ispirato da {0}",
"ThemeHelpText": "Cambia il Tema dell'interfaccia dellapplicazione, il Tema 'Auto' userà il tuo Tema di Sistema per impostare la modalità Chiara o Scura. Ispirato da {inspiredBy}.",
"LastDuration": "Ultima Durata",
"LastExecution": "Ultima esecuzione",
"Queued": "In coda",
"Queued": "In Coda",
"ApplicationLongTermStatusCheckAllClientMessage": "Tutte le app non disponibili da almeno 6 ore a causa di errori",
"ApplicationLongTermStatusCheckSingleClientMessage": "Alcune app non sono disponibili da almeno 6 ore a causa di errori: {0}",
"Duration": "Durata",
@@ -466,9 +465,9 @@
"ApplyTagsHelpTextAdd": "Aggiungi: Aggiunge le etichette alla lista esistente di etichette",
"ApplyTagsHelpTextHowToApplyApplications": "Come applicare etichette agli autori selezionati",
"ApplyTagsHelpTextHowToApplyIndexers": "Come applicare etichette agli indicizzatori selezionati",
"CountIndexersSelected": "{0} indicizzatore(i) selezionato(i)",
"DeleteSelectedApplicationsMessageText": "Sei sicuro di voler eliminare l'indexer '{0}'?",
"DeleteSelectedDownloadClientsMessageText": "Sei sicuro di voler eliminare l'indexer '{0}'?",
"CountIndexersSelected": "{count} indicizzatore(i) selezionato(i)",
"DeleteSelectedApplicationsMessageText": "Sei sicuro di voler eliminare {count} applicazione(i) selezionata(e)?",
"DeleteSelectedDownloadClientsMessageText": "Sei sicuro di voler eliminare i '{count}' client di download selezionato/i?",
"SelectIndexers": "Cerca Indicizzatori",
"Track": "Traccia",
"Book": "Libro",
@@ -477,22 +476,21 @@
"ApplyTagsHelpTextReplace": "Sostituire: Sostituisce le etichette con quelle inserite (non inserire nessuna etichette per eliminarle tutte)",
"DownloadClientPriorityHelpText": "Dai priorità a multipli Client di download. Round-Robin è usato per i client con la stessa priorità.",
"DeleteSelectedDownloadClients": "Cancella i Client di Download",
"DeleteSelectedIndexersMessageText": "Sei sicuro di voler eliminare l'indexer '{0}'?",
"Album": "Album",
"Artist": "Artista",
"Label": "Etichetta",
"More": "Di più",
"More": "Altro",
"Season": "Stagione",
"Year": "Anno",
"UpdateAvailableHealthCheckMessage": "É disponibile un nuovo aggiornamento",
"UpdateAvailableHealthCheckMessage": "Nuovo aggiornamento disponibile",
"Author": "Autore",
"ApplyChanges": "Applica Cambiamenti",
"ApiKeyValidationHealthCheckMessage": "Aggiorna la tua chiave API in modo che abbia una lunghezza di almeno {length} caratteri. Puoi farlo dalle impostazioni o dal file di configurazione",
"DeleteAppProfileMessageText": "Sicuro di voler cancellare il profilo di qualità {0}",
"RecentChanges": "Cambiamenti recenti",
"DeleteAppProfileMessageText": "Sicuro di voler cancellare il profilo dell'app '{name}'?",
"RecentChanges": "Cambiamenti Recenti",
"WhatsNew": "Cosa c'è di nuovo?",
"ConnectionLostReconnect": "Radarr cercherà di connettersi automaticamente, oppure clicca su ricarica qui sotto.",
"ConnectionLostToBackend": "Radarr ha perso la connessione al backend e dovrà essere ricaricato per ripristinare la funzionalità.",
"ConnectionLostReconnect": "{appName} cercherà di connettersi automaticamente, oppure clicca su ricarica qui sotto.",
"ConnectionLostToBackend": "{appName} ha perso la connessione al backend e dovrà essere ricaricato per ripristinare la funzionalità.",
"minutes": "Minuti",
"AddConnection": "Aggiungi Connessione",
"NotificationStatusAllClientHealthCheckMessage": "Tutte le applicazioni non sono disponibili a causa di errori",
@@ -532,9 +530,114 @@
"ActiveIndexers": "Indicizzatori Attivi",
"IndexerBeyondHDSettingsSearchTypes": "Tipi di Ricerca",
"Directory": "Cartella",
"CustomFilter": "Filtri Personalizzati",
"CustomFilter": "Filtro Personalizzato",
"IndexerHDBitsSettingsCodecs": "Codec",
"IndexerHDBitsSettingsMediums": "medio",
"GrabRelease": "Preleva Release",
"ProxyValidationBadRequest": "Il test del proxy è fallito. Codice Stato: {statusCode}"
"ProxyValidationBadRequest": "Il test del proxy è fallito. Codice Stato: {statusCode}",
"Discord": "Discord",
"Donate": "Dona",
"Destination": "Destinazione",
"DownloadClientFreeboxSettingsApiUrl": "API URL",
"DownloadClientFreeboxSettingsAppId": "ID App",
"DownloadClientFreeboxSettingsAppToken": "Token App",
"DownloadClientPneumaticSettingsNzbFolder": "Cartella Nzb",
"DownloadClientPneumaticSettingsNzbFolderHelpText": "Questa cartella dovrà essere raggiungibile da XBMC",
"DownloadClientRTorrentSettingsUrlPath": "Percorso Url",
"Default": "Predefinito",
"DownloadClientPneumaticSettingsStrmFolder": "Cartella Strm",
"IndexerDisabled": "Indexer Disattivato",
"GoToApplication": "Vai all'applicazione",
"AreYouSureYouWantToDeleteIndexer": "Sei sicuro di voler eliminare '{name}' da {appName}?",
"IndexerStatus": "Stato Indicizzatore",
"XmlRpcPath": "Percorso XML RPC",
"EditCategory": "Modifica Categoria",
"IndexerSettingsAdditionalParameters": "Parametri Addizionali",
"IndexerSettingsApiPath": "Percorso API",
"IndexerSettingsVipExpiration": "Scadenza VIP",
"DefaultCategory": "Categoria Predefinita",
"DownloadClientFloodSettingsAdditionalTags": "Tag addizionali",
"IndexerHDBitsSettingsMediumsHelpText": "Se non specificato, saranno utilizzate tutte le opzioni.",
"IndexerHDBitsSettingsOrigins": "Origini",
"IndexerHDBitsSettingsOriginsHelpText": "Se non specificato, saranno utilizzate tutte le opzioni.",
"IndexerSettingsCookie": "Cookie",
"DeleteSelectedApplications": "Elimina Applicazioni Selezionate",
"IndexerHDBitsSettingsCodecsHelpText": "Se non specificato, saranno utilizzate tutte le opzioni.",
"IndexerSettingsApiUser": "Utente API",
"PrioritySettings": "Priorità: {priority}",
"CountDownloadClientsSelected": "{count} client di download selezionato/i",
"NotificationsTelegramSettingsIncludeAppName": "Includi {appName} nel Titolo",
"Menu": "Menu",
"NoIndexersFound": "Nessun indicizzatore trovato",
"PasswordConfirmation": "Conferma Password",
"NoHistoryFound": "Nessun storico trovato",
"DeleteSelectedIndexersMessageText": "Sei sicuro di voler eliminare {count} applicazione(i) selezionata(e)?",
"UsenetBlackholeNzbFolder": "Cartella Nzb",
"VipExpiration": "Scadenza VIP",
"OverrideAndAddToDownloadClient": "Sovrascrivi e aggiungi alla coda di download",
"BasicSearch": "Ricerca basica",
"CountIndexersAvailable": "{count} indicizzatore/i disponibili",
"EditSelectedIndexers": "Modifica Indicizzatori Selezionati",
"FoundCountReleases": "Trovate {itemCount} release",
"ManageApplications": "Gestisci Applicazioni",
"ManageDownloadClients": "Gestisci Clients di Download",
"HistoryDetails": "Dettagli Storico",
"NotificationsEmailSettingsUseEncryption": "Usa Crittografia",
"SearchAllIndexers": "Cerca tutti gli indicizzatori",
"SearchCountIndexers": "Cerca {count} indicizzatore/i",
"SearchQueries": "Cerca Richieste",
"SeedRatio": "Rapporto Seed",
"TorznabUrl": "Url Torznab",
"TorrentBlackholeTorrentFolder": "Cartella Torrent",
"UseSsl": "Usa SSL",
"days": "giorni",
"IndexerCategories": "Categorie degli Indicizzatori",
"IndexerTorrentSyndikatSettingsApiKeyHelpText": "API Key Sito",
"LabelIsRequired": "Etichetta richiesta",
"NoIndexerHistory": "Nessun storico trovato per questo indicizzatore",
"RssFeed": "Feed RSS",
"AverageResponseTimesMs": "Tempo di Risposta Medio dell'Indicizzatore (ms)",
"DeleteSelectedIndexer": "Elimina Indicizzatore Selezionato",
"DisabledUntil": "Disattiva fino",
"DownloadClientDelugeSettingsUrlBaseHelpText": "Aggiungi un prefisso all'url del json di deluge, vedi {url}",
"Implementation": "Implementazione",
"ManageClients": "Gestisci Clients",
"NewznabUrl": "Url Newznab",
"NoApplicationsFound": "Nessuna applicazione trovata",
"IndexerSettingsBaseUrl": "Url Base",
"IndexerId": "ID Indicizzatore",
"NoDownloadClientsFound": "Nessun client di download trovato",
"BlackholeFolderHelpText": "Cartella nella quale {appName} salverà i file di tipo {extension}",
"DownloadClientNzbgetSettingsAddPausedHelpText": "Questa opzione richiede almeno la versione 16.0 di NzbGet",
"DownloadClientQbittorrentSettingsSequentialOrderHelpText": "Scarica in ordine sequenziale (qBittorrent 4.1.0+)",
"DownloadClientQbittorrentSettingsUseSslHelpText": "Usa una connessione sicura. Vedi Opzioni -> Web UI -> 'Usa HTTPS invece di HTTP' in qBittorrent.",
"DownloadClientRTorrentSettingsAddStopped": "Aggiungi Fermato",
"DownloadClientSettingsInitialState": "Stato Iniziale",
"DownloadClientSettingsInitialStateHelpText": "Stato iniziale per i torrent aggiunti a {clientName}",
"DownloadClientSettingsAddPaused": "Aggiungi In Pausa",
"DownloadClientSettingsUseSslHelpText": "Usa connessione sicura quando connetti a {clientName}",
"IndexerIPTorrentsSettingsCookieUserAgent": "Cookie User-Agent",
"IndexerSettingsApiPathHelpText": "Percorso API, solitamente {url}",
"IndexerSettingsBaseUrlHelpText": "Seleziona quale url base {appName} userà per le richieste al sito",
"NoIndexerCategories": "Nessuna categoria trovata per questo indicizzatore",
"SecretToken": "Secret Token",
"SeedRatioHelpText": "Il rapporto che un torrent dovrebbe raggiungere prima di essere fermato, vuoto è il predefinito dell'app",
"TotalQueries": "Totale Richieste",
"IndexerHistoryLoadError": "Errore caricando lo storico dell'indicizzatore",
"DeleteSelectedIndexers": "Elimina Indicizzatori Selezionati",
"InvalidUILanguage": "L'interfaccia è impostata in una lingua non valida, correggi e salva le tue impostazioni",
"IndexerSettingsSeedRatio": "Rapporto Seed",
"IndexerSettingsRssKey": "Chiave RSS",
"RssQueries": "Richieste RSS",
"DownloadClientQbittorrentSettingsSequentialOrder": "Ordine Sequenziale",
"External": "Esterno",
"IndexerNewznabSettingsAdditionalParametersHelpText": "Parametri Newznab addizionali",
"SelectDownloadClientModalTitle": "{modalTitle} - Seleziona Client di Download",
"DownloadClientSettingsDestinationHelpText": "Specifica manualmente la destinazione dei download, lascia vuoti per usare la predefinita",
"IndexerDownloadClientHealthCheckMessage": "Indicizzatori con client di download non validi: {indexerNames}.",
"SeedTimeHelpText": "Il rapporto che un torrent dovrebbe raggiungere prima di essere fermato, vuoto è il predefinito dell'app",
"IndexerPassThePopcornSettingsApiKeyHelpText": "API Key Sito",
"IndexerNzbIndexSettingsApiKeyHelpText": "API Key Sito",
"IndexerNewznabSettingsApiKeyHelpText": "API Key Sito",
"Fixed": "Fissato"
}

View File

@@ -152,5 +152,7 @@
"AddConnectionImplementation": "Legg til betingelse - {implementationName}",
"AddIndexerImplementation": "Legg til betingelse - {implementationName}",
"AddIndexerProxyImplementation": "Legg til betingelse - {implementationName}",
"UnableToAddANewApplicationPleaseTryAgain": "Ikke mulig å legge til ny betingelse, vennligst prøv igjen"
"UnableToAddANewApplicationPleaseTryAgain": "Ikke mulig å legge til ny betingelse, vennligst prøv igjen",
"EditIndexerProxyImplementation": "Legg til betingelse - {implementationName}",
"UnableToAddANewAppProfilePleaseTryAgain": "Ikke mulig å legge til ny betingelse, vennligst prøv igjen"
}

View File

@@ -201,7 +201,7 @@
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Todos os indexadores estão indisponíveis devido a falhas por mais de 6 horas",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexadores indisponíveis devido a falhas por mais de 6 horas: {indexerNames}",
"IndexerName": "Nome do Indexador",
"IndexerNoDefinitionCheckHealthCheckMessage": "Os indexadores não têm definição e não funcionarão: {0}. Por favor, remova e (ou) adicione novamente ao {appName}",
"IndexerNoDefinitionCheckHealthCheckMessage": "Os indexadores não têm definição e não funcionarão: {indexerNames}. Remova e (ou) adicione novamente ao {appName}.",
"IndexerObsoleteCheckMessage": "Os seguintes indexadores são obsoletos ou foram atualizados: {0}. Remova-os e/ou adicione-os novamente ao {appName}",
"IndexerPriority": "Prioridade do indexador",
"IndexerPriorityHelpText": "Prioridade do Indexador de 1 (Mais Alta) a 50 (Mais Baixa). Padrão: 25.",
@@ -479,7 +479,7 @@
"UpdateStartupNotWritableHealthCheckMessage": "Não é possível instalar a atualização porque a pasta de inicialização '{startupFolder}' não pode ser gravada pelo usuário '{userName}'.",
"UpdateStartupTranslocationHealthCheckMessage": "Não é possível instalar a atualização porque a pasta de inicialização '{startupFolder}' está em uma pasta de translocação de aplicativo.",
"UpdateUiNotWritableHealthCheckMessage": "Não é possível instalar a atualização porque a pasta de IU '{uiFolder}' não pode ser gravada pelo usuário '{userName}'.",
"UpdateMechanismHelpText": "Use o atualizador integrado do {appName} ou um script",
"UpdateMechanismHelpText": "Usar o atualizador integrado do {appName} ou um script",
"UpdateScriptPathHelpText": "Caminho para um script personalizado que usa um pacote de atualização extraído e lida com o restante do processo de atualização",
"Updates": "Atualizações",
"Uptime": "Tempo de atividade",

View File

@@ -142,5 +142,6 @@
"IndexerHDBitsSettingsCodecs": "Kodek",
"AddIndexerProxyImplementation": "Pridať Indexer - {implementationName}",
"EditIndexerProxyImplementation": "Pridať Indexer - {implementationName}",
"EditApplicationImplementation": "Pridať podmienku - {implementationName}"
"EditApplicationImplementation": "Pridať podmienku - {implementationName}",
"UnableToAddANewAppProfilePleaseTryAgain": "Nie je možné pridať novú podmienku, skúste to znova."
}

View File

@@ -336,7 +336,7 @@
"ApplyTagsHelpTextAdd": "Ekle: Etiketleri mevcut etiket listesine ekleyin",
"ApplyTagsHelpTextHowToApplyApplications": "Seçilen filmlere etiketler nasıl uygulanır",
"ApplyTagsHelpTextRemove": "Kaldır: Girilen etiketleri kaldırın",
"ApplyTagsHelpTextHowToApplyIndexers": "Seçilen indeksleyicilere etiketler nasıl uygulanır?",
"ApplyTagsHelpTextHowToApplyIndexers": "Seçilen indeksleyicilere etiketler nasıl uygulanır",
"ApplyTagsHelpTextReplace": "Değiştir: Etiketleri girilen etiketlerle değiştirin (tüm etiketleri kaldırmak için etiket girmeyin)",
"DeleteSelectedDownloadClients": "İndirme İstemcilerini Sil",
"DownloadClientPriorityHelpText": "Birden çok İndirme İstemcisine öncelik verin. Round-Robin, aynı önceliğe sahip müşteriler için kullanılır.",

View File

@@ -420,5 +420,7 @@
"CustomFilter": "Користувацькі фільтри",
"IndexerHDBitsSettingsMediums": "Середній",
"Default": "За замовчуванням",
"GrabRelease": "Захопити реліз"
"GrabRelease": "Захопити реліз",
"Clone": "Клонування",
"CountDownloadClientsSelected": "Вибрано {count} клієнтів завантажувача"
}

View File

@@ -128,5 +128,10 @@
"ApplyChanges": "應用",
"ApplyTagsHelpTextHowToApplyApplications": "如何套用標籤在所選擇的輸入清單",
"Artist": "演員",
"Id": "ID"
"Id": "ID",
"Usenet": "Usenet",
"ApplyTagsHelpTextHowToApplyIndexers": "如何套用標籤在所選擇的輸入清單",
"Docker": "Docker",
"IndexerHDBitsSettingsCodecs": "編解碼器",
"Directory": "目錄"
}

View File

@@ -31,7 +31,7 @@ namespace NzbDrone.Core.Notifications.Gotify
public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck)
{
_proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", null);
_proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", Settings);
}
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)

View File

@@ -10,7 +10,7 @@
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
<PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" />
<PackageReference Include="Npgsql" Version="7.0.7" />
<PackageReference Include="Polly" Version="8.4.0" />
<PackageReference Include="Polly" Version="8.4.1" />
<PackageReference Include="Servarr.FluentMigrator.Runner" Version="3.3.2.9" />
<PackageReference Include="Servarr.FluentMigrator.Runner.Postgres" Version="3.3.2.9" />
<PackageReference Include="Servarr.FluentMigrator.Runner.SQLite" Version="3.3.2.9" />

View File

@@ -60,7 +60,7 @@ namespace Prowlarr.Api.V1.Indexers
if (definition.Implementation == nameof(Cardigann))
{
var extraFields = definition.ExtraFields?.Select(MapCardigannField).ToList() ?? new List<Field>();
var extraFields = definition.ExtraFields?.Select((field, i) => MapCardigannField(definition, field, i)).ToList() ?? new List<Field>();
resource.Fields.AddRange(extraFields);
@@ -160,7 +160,7 @@ namespace Prowlarr.Api.V1.Indexers
};
}
private Field MapCardigannField(SettingsField setting, int order)
private Field MapCardigannField(IndexerDefinition definition, SettingsField setting, int order)
{
var field = new Field
{
@@ -185,7 +185,7 @@ namespace Prowlarr.Api.V1.Indexers
{
field.Value = bool.TryParse(setting.Default, out var value) && value;
}
else if (setting.Type is "info_cookie" or "info_flaresolverr" or "info_useragent")
else if (setting.Type is "info_cookie" or "info_flaresolverr" or "info_useragent" or "info_category_8000")
{
field.Type = "info";
@@ -203,6 +203,10 @@ namespace Prowlarr.Api.V1.Indexers
field.Label = "How to get the User-Agent";
field.Value = "<ol><li>From the same place you fetched the cookie,</li><li>Find <b>'user-agent:'</b> in the <b>Request Headers</b> section</li><li><b>Select</b> and <b>Copy</b> the whole user-agent string <i>(everything after 'user-agent: ')</i> and <b>Paste</b> here.</li></ol>";
break;
case "info_category_8000":
field.Label = $"About {definition.Name} Categories";
field.Value = $"{definition.Name} does not return categories in its search results. To sync to your apps, include 8000(Other) in your Apps' Sync Categories.";
break;
}
}
else