Merge branch 'develop' into NET8

pull/6580/head
Gauvino 4 weeks ago committed by GitHub
commit fbbf33b64b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,13 @@
// This file is used to open the backend and frontend in the same workspace, which is necessary as
// the frontend has vscode settings that are distinct from the backend
{
"folders": [
{
"path": ".."
},
{
"path": "../frontend"
}
],
"settings": {}
}

@ -1,17 +1,23 @@
'connection':
- src/NzbDrone.Core/Notifications/**/*
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Notifications/**/*
'db-migration':
- src/NzbDrone.Core/Datastore/Migration/*
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Datastore/Migration/*
'download-client':
- src/NzbDrone.Core/Download/Clients/**/*
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Download/Clients/**/*
'indexer':
- src/NzbDrone.Core/Indexers/**/*
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Indexers/**/*
'parsing':
- src/NzbDrone.Core/Parser/**/*
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Parser/**/*
'ui-only':
- all: ['frontend/**/*']
- changed-files:
- any-glob-to-all-files: frontend/**/*

@ -236,7 +236,7 @@ jobs:
steps:
- name: Notify
uses: tsickert/discord-webhook@v5.3.0
uses: tsickert/discord-webhook@v6.0.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
username: 'GitHub Actions'

@ -0,0 +1,26 @@
name: Merge Conflict Labeler
on:
push:
branches:
- develop
pull_request_target:
branches:
- develop
types: [synchronize]
jobs:
label:
name: Labeling
runs-on: ubuntu-latest
if: ${{ github.repository == 'Sonarr/Sonarr' }}
permissions:
contents: read
pull-requests: write
steps:
- name: Apply label
uses: eps1lon/actions-label-merge-conflict@v3
with:
dirtyLabel: 'merge-conflict'
repoToken: '${{ secrets.GITHUB_TOKEN }}'

@ -9,4 +9,4 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4
- uses: actions/labeler@v5

@ -9,13 +9,13 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2
- uses: dessant/lock-threads@v5
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '90'
issue-exclude-created-before: ''
issue-exclude-labels: 'one-day-maybe'
issue-lock-labels: ''
issue-lock-comment: ''
issue-inactive-days: '90'
exclude-issue-created-before: ''
exclude-any-issue-labels: 'one-day-maybe'
add-issue-labels: ''
issue-comment: ''
issue-lock-reason: 'resolved'
process-only: ''

@ -1,8 +1,11 @@
import $ from 'jquery';
import _ from 'lodash';
import createAjaxRequest from 'Utilities/createAjaxRequest';
import getProviderState from 'Utilities/State/getProviderState';
import { set } from '../baseActions';
const abortCurrentRequests = {};
let lastTestData = null;
export function createCancelTestProviderHandler(section) {
return function(getState, payload, dispatch) {
@ -17,10 +20,25 @@ function createTestProviderHandler(section, url) {
return function(getState, payload, dispatch) {
dispatch(set({ section, isTesting: true }));
const testData = getProviderState(payload, getState, section);
const {
queryParams = {},
...otherPayload
} = payload;
const testData = getProviderState({ ...otherPayload }, getState, section);
const params = { ...queryParams };
// If the user is re-testing the same provider without changes
// force it to be tested.
if (_.isEqual(testData, lastTestData)) {
params.forceTest = true;
}
lastTestData = testData;
const ajaxOptions = {
url: `${url}/test`,
url: `${url}/test?${$.param(params, true)}`,
method: 'POST',
contentType: 'application/json',
dataType: 'json',
@ -32,6 +50,8 @@ function createTestProviderHandler(section, url) {
abortCurrentRequests[section] = abortRequest;
request.done((data) => {
lastTestData = null;
dispatch(set({
section,
isTesting: false,

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Validation;
@ -12,5 +13,7 @@ namespace NzbDrone.Core.Test.IndexerTests
}
public string BaseUrl { get; set; }
public IEnumerable<int> MultiLanguages { get; set; }
}
}

@ -429,6 +429,26 @@ namespace NzbDrone.Core.Test.ParserTests
result.Languages.Should().Contain(Language.English);
}
[TestCase("Остання серія (Сезон 1) / The Last Series (Season 1) (2024) WEB-DLRip-AVC 2xUkr/Eng | Sub Ukr/Eng")]
[TestCase("Справжня серія (Сезон 1-3) / True Series (Season 1-3) (2014-2019) BDRip-AVC 3xUkr/Eng | Ukr/Eng")]
[TestCase("Серія (Сезон 1-3) / The Series (Seasons 1-3) (2019-2022) BDRip-AVC 4xUkr/Eng | Sub 2xUkr/Eng")]
public void should_parse_english_and_ukranian(string postTitle)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Languages.Count.Should().Be(2);
result.Languages.Should().Contain(Language.Ukrainian);
result.Languages.Should().Contain(Language.English);
}
[TestCase("Серія (Сезон 1, серії 01-26 із 51) / Seri (Season 1, episodes 01-26) (2018) WEBRip-AVC 2Ukr/Tur")]
public void should_parse_turkish_and_ukranian(string postTitle)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Languages.Count.Should().Be(2);
result.Languages.Should().Contain(Language.Ukrainian);
result.Languages.Should().Contain(Language.Turkish);
}
[TestCase("Name (2020) - S01E20 - [AAC 2.0].testtitle.default.eng.forced.ass", new[] { "default", "forced" }, "testtitle", "English")]
[TestCase("Name (2020) - S01E20 - [AAC 2.0].eng.default.testtitle.forced.ass", new[] { "default", "forced" }, "testtitle", "English")]
[TestCase("Name (2020) - S01E20 - [AAC 2.0].default.eng.testtitle.forced.ass", new[] { "default", "forced" }, "testtitle", "English")]

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.BroadcastheNet
@ -23,6 +26,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
{
BaseUrl = "https://api.broadcasthe.net/";
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
MultiLanguages = Array.Empty<int>();
}
[FieldDefinition(0, Label = "IndexerSettingsApiUrl", Advanced = true, HelpText = "IndexerSettingsApiUrlHelpText")]
@ -40,6 +44,9 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Fanzub
@ -19,6 +22,7 @@ namespace NzbDrone.Core.Indexers.Fanzub
public FanzubSettings()
{
BaseUrl = "http://fanzub.com/rss/";
MultiLanguages = Array.Empty<int>();
}
[FieldDefinition(0, Label = "IndexerSettingsRssUrl", HelpText = "IndexerSettingsRssUrlHelpText")]
@ -28,6 +32,9 @@ namespace NzbDrone.Core.Indexers.Fanzub
[FieldDefinition(1, Label = "IndexerSettingsAnimeStandardFormatSearch", Type = FieldType.Checkbox, HelpText = "IndexerSettingsAnimeStandardFormatSearchHelpText")]
public bool AnimeStandardFormatSearch { get; set; }
[FieldDefinition(2, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.FileList
@ -35,6 +36,7 @@ namespace NzbDrone.Core.Indexers.FileList
};
AnimeCategories = Array.Empty<int>();
MultiLanguages = Array.Empty<int>();
}
[FieldDefinition(0, Label = "Username", Privacy = PrivacyLevel.UserName)]
@ -43,6 +45,9 @@ namespace NzbDrone.Core.Indexers.FileList
[FieldDefinition(1, Label = "IndexerSettingsPasskey", Privacy = PrivacyLevel.ApiKey)]
public string Passkey { get; set; }
[FieldDefinition(2, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
[FieldDefinition(3, Label = "IndexerSettingsApiUrl", Advanced = true, HelpText = "IndexerSettingsApiUrlHelpText")]
public string BaseUrl { get; set; }

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.HDBits
@ -29,6 +30,7 @@ namespace NzbDrone.Core.Indexers.HDBits
Categories = new[] { (int)HdBitsCategory.Tv, (int)HdBitsCategory.Documentary };
Codecs = Array.Empty<int>();
Mediums = Array.Empty<int>();
MultiLanguages = Array.Empty<int>();
}
[FieldDefinition(0, Label = "IndexerSettingsApiUrl", Advanced = true, HelpText = "IndexerSettingsApiUrlHelpText")]
@ -58,6 +60,9 @@ namespace NzbDrone.Core.Indexers.HDBits
[FieldDefinition(8, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(9, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

@ -1,9 +1,12 @@
using NzbDrone.Core.ThingiProvider;
using System.Collections.Generic;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Indexers
{
public interface IIndexerSettings : IProviderConfig
{
string BaseUrl { get; set; }
IEnumerable<int> MultiLanguages { get; set; }
}
}

@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.IPTorrents
@ -29,6 +32,7 @@ namespace NzbDrone.Core.Indexers.IPTorrents
public IPTorrentsSettings()
{
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
MultiLanguages = Array.Empty<int>();
}
[FieldDefinition(0, Label = "IndexerIPTorrentsSettingsFeedUrl", HelpText = "IndexerIPTorrentsSettingsFeedUrlHelpText")]
@ -43,6 +47,9 @@ namespace NzbDrone.Core.Indexers.IPTorrents
[FieldDefinition(3, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(4, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

@ -1,12 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@ -17,6 +20,8 @@ namespace NzbDrone.Core.Indexers
public abstract class IndexerBase<TSettings> : IIndexer
where TSettings : IIndexerSettings, new()
{
private static readonly Regex MultiRegex = new (@"[_. ](?<multi>multi)[_. ]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
protected readonly IIndexerStatusService _indexerStatusService;
protected readonly IConfigService _configService;
protected readonly IParsingService _parsingService;
@ -84,9 +89,16 @@ namespace NzbDrone.Core.Indexers
protected virtual IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases)
{
var result = releases.DistinctBy(v => v.Guid).ToList();
var settings = Definition.Settings as IIndexerSettings;
result.ForEach(c =>
{
// Use multi languages from setting if ReleaseInfo languages is empty
if (c.Languages.Empty() && MultiRegex.IsMatch(c.Title) && settings.MultiLanguages.Any())
{
c.Languages = settings.MultiLanguages.Select(i => (Language)i).ToList();
}
c.IndexerId = Definition.Id;
c.Indexer = Definition.Name;
c.DownloadProtocol = Protocol;

@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Newznab
@ -55,6 +57,7 @@ namespace NzbDrone.Core.Indexers.Newznab
ApiPath = "/api";
Categories = new[] { 5030, 5040 };
AnimeCategories = Enumerable.Empty<int>();
MultiLanguages = Array.Empty<int>();
}
[FieldDefinition(0, Label = "URL")]
@ -79,7 +82,10 @@ namespace NzbDrone.Core.Indexers.Newznab
[FieldDefinition(6, Label = "IndexerSettingsAdditionalParameters", HelpText = "IndexerSettingsAdditionalNewznabParametersHelpText", Advanced = true)]
public string AdditionalParameters { get; set; }
// Field 7 is used by TorznabSettings MinimumSeeders
[FieldDefinition(7, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
// Field 8 is used by TorznabSettings MinimumSeeders
// If you need to add another field here, update TorznabSettings as well and this comment
public virtual NzbDroneValidationResult Validate()

@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Nyaa
@ -25,6 +28,7 @@ namespace NzbDrone.Core.Indexers.Nyaa
BaseUrl = "";
AdditionalParameters = "&cats=1_0&filter=1";
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
MultiLanguages = Array.Empty<int>();
}
[FieldDefinition(0, Label = "IndexerSettingsWebsiteUrl")]
@ -45,6 +49,9 @@ namespace NzbDrone.Core.Indexers.Nyaa
[FieldDefinition(5, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.TorrentRss
@ -23,6 +26,7 @@ namespace NzbDrone.Core.Indexers.TorrentRss
BaseUrl = string.Empty;
AllowZeroSize = false;
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
MultiLanguages = Array.Empty<int>();
}
[FieldDefinition(0, Label = "IndexerSettingsRssUrl")]
@ -43,6 +47,9 @@ namespace NzbDrone.Core.Indexers.TorrentRss
[FieldDefinition(5, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(6, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Torrentleech
@ -23,6 +26,7 @@ namespace NzbDrone.Core.Indexers.Torrentleech
{
BaseUrl = "http://rss.torrentleech.org";
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
MultiLanguages = Array.Empty<int>();
}
[FieldDefinition(0, Label = "IndexerSettingsWebsiteUrl")]
@ -40,6 +44,9 @@ namespace NzbDrone.Core.Indexers.Torrentleech
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
[FieldDefinition(5, Type = FieldType.Select, SelectOptions = typeof(RealLanguageFieldConverter), Label = "IndexerSettingsMultiLanguageRelease", HelpText = "IndexerSettingsMultiLanguageReleaseHelpText", Advanced = true)]
public IEnumerable<int> MultiLanguages { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

@ -49,13 +49,13 @@ namespace NzbDrone.Core.Indexers.Torznab
MinimumSeeders = IndexerDefaults.MINIMUM_SEEDERS;
}
[FieldDefinition(7, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
[FieldDefinition(8, Type = FieldType.Number, Label = "IndexerSettingsMinimumSeeders", HelpText = "IndexerSettingsMinimumSeedersHelpText", Advanced = true)]
public int MinimumSeeders { get; set; }
[FieldDefinition(8)]
[FieldDefinition(9)]
public SeedCriteriaSettings SeedCriteria { get; set; } = new SeedCriteriaSettings();
[FieldDefinition(9, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
[FieldDefinition(10, Type = FieldType.Checkbox, Label = "IndexerSettingsRejectBlocklistedTorrentHashes", HelpText = "IndexerSettingsRejectBlocklistedTorrentHashesHelpText", Advanced = true)]
public bool RejectBlocklistedTorrentHashesWhileGrabbing { get; set; }
public override NzbDroneValidationResult Validate()

@ -0,0 +1,18 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Annotations;
namespace NzbDrone.Core.Languages
{
public class RealLanguageFieldConverter : ISelectOptionsConverter
{
public List<SelectOption> GetSelectOptions()
{
return Language.All
.Where(l => l != Language.Unknown)
.OrderBy(l => l.Id > 0).ThenBy(l => l.Name)
.ToList()
.ConvertAll(v => new SelectOption { Value = v.Id, Name = v.Name });
}
}
}

@ -978,6 +978,8 @@
"IndexerSettingsPasskey": "Passkey",
"IndexerSettingsRejectBlocklistedTorrentHashes": "Reject Blocklisted Torrent Hashes While Grabbing",
"IndexerSettingsRejectBlocklistedTorrentHashesHelpText": "If a torrent is blocked by hash it may not properly be rejected during RSS/Search for some indexers, enabling this will allow it to be rejected after the torrent is grabbed, but before it is sent to the client.",
"IndexerSettingsMultiLanguageRelease": "Multi Languages",
"IndexerSettingsMultiLanguageReleaseHelpText": "What languages are normally in a multi release on this indexer?",
"IndexerSettingsRssUrl": "RSS URL",
"IndexerSettingsRssUrlHelpText": "Enter to URL to an {indexer} compatible RSS feed",
"IndexerSettingsSeasonPackSeedTime": "Season-Pack Seed Time",

@ -68,11 +68,11 @@
"CancelPendingTask": "Êtes-vous sur de vouloir annuler cette tâche en attente ?",
"Clear": "Effacer",
"AddAutoTagError": "Impossible d'ajouter un nouveau tag automatique, veuillez réessayer.",
"AddConditionError": "Impossible d'ajouter une nouvelle condition, Réessayer.",
"AddConditionError": "Impossible d'ajouter une nouvelle condition, veuillez réessayer.",
"AddCondition": "Ajouter une condition",
"AddAutoTag": "Ajouter un tag automatique",
"AddCustomFormatError": "Impossible d'ajouter un nouveau format personnalisé, veuillez réessayer.",
"AddIndexerError": "Impossible d'ajouter un nouvelle indexeur, veuillez réessayer.",
"AddIndexerError": "Impossible d'ajouter un nouvel indexeur, veuillez réessayer.",
"AddNewRestriction": "Ajouter une nouvelle restriction",
"AddListError": "Impossible d'ajouter une nouvelle liste, veuillez réessayer.",
"AddDownloadClientError": "Impossible d'ajouter un nouveau client de téléchargement, veuillez réessayer.",
@ -534,7 +534,7 @@
"IndexerSearchNoInteractiveHealthCheckMessage": "Aucun indexeur n'est disponible avec la recherche interactive activée. {appName} ne fournira aucun résultat de recherche interactif",
"IndexerStatusUnavailableHealthCheckMessage": "Indexeurs indisponibles en raison d'échecs : {indexerNames}",
"Info": "Information",
"InstallLatest": "Installer le dernier",
"InstallLatest": "Installer la dernière",
"InteractiveImportNoLanguage": "La ou les langues doivent être choisies pour chaque fichier sélectionné",
"InteractiveImportNoQuality": "La qualité doit être choisie pour chaque fichier sélectionné",
"InteractiveSearchModalHeader": "Recherche interactive",
@ -2066,5 +2066,8 @@
"EpisodeTitleFootNote": "Contrôlez éventuellement la troncature à un nombre maximum d'octets, y compris les points de suspension (`...`). La troncature de la fin (par exemple `{Episode Title:30}`) ou du début (par exemple `{Episode Title:-30}`) sont toutes deux prises en charge. Les titres des épisodes seront automatiquement tronqués en fonction des limitations du système de fichiers si nécessaire.",
"SelectReleaseType": "Sélectionnez le type de version",
"SeriesFootNote": "Contrôlez éventuellement la troncature à un nombre maximum d'octets, y compris les points de suspension (`...`). La troncature de la fin (par exemple `{Series Title:30}`) ou du début (par exemple `{Series Title:-30}`) sont toutes deux prises en charge.",
"ReleaseGroupFootNote": "Contrôlez éventuellement la troncature à un nombre maximum d'octets, y compris les points de suspension (`...`). La troncature de la fin (par exemple `{Release Group:30}`) ou du début (par exemple `{Release Group:-30}`) sont toutes deux prises en charge.`)."
"ReleaseGroupFootNote": "Contrôlez éventuellement la troncature à un nombre maximum d'octets, y compris les points de suspension (`...`). La troncature de la fin (par exemple `{Release Group:30}`) ou du début (par exemple `{Release Group:-30}`) sont toutes deux prises en charge.`).",
"AutoTaggingSpecificationTag": "Étiquette",
"NotificationsTelegramSettingsIncludeAppName": "Inclure {appName} dans le Titre",
"NotificationsTelegramSettingsIncludeAppNameHelpText": "Préfixer éventuellement le titre du message par {appName} pour différencier les notifications des différentes applications"
}

@ -249,5 +249,6 @@
"AnimeEpisodeTypeFormat": "Numero assoluto dell'episodio ({format})",
"AutoRedownloadFailed": "Download fallito",
"AddDelayProfileError": "Impossibile aggiungere un nuovo profilo di ritardo, riprova.",
"Cutoff": "Taglio"
"Cutoff": "Taglio",
"AddListExclusion": "Aggiungi elenco esclusioni"
}

@ -136,12 +136,90 @@
"AuthenticationMethod": "Kimlik Doğrulama Yöntemi",
"AuthenticationRequired": "Kimlik Doğrulama Gerekli",
"AuthenticationRequiredWarning": "Kimlik doğrulaması olmadan uzaktan erişimi engellemek için, {appName}'da artık kimlik doğrulamanın etkinleştirilmesini gerektiriyor. İsteğe bağlı olarak yerel adresler için kimlik doğrulamayı devre dışı bırakabilirsiniz.",
"ApiKeyValidationHealthCheckMessage": "Lütfen API anahtarınızı en az {length} karakter uzunluğunda olacak şekilde güncelleyin. Bunu ayarlar veya yapılandırma dosyası aracılığıyla yapabilirsiniz",
"ApiKeyValidationHealthCheckMessage": "Lütfen API anahtarınızı en az {length} karakter sayısı kadar güncelleyiniz. Bunu ayarlar veya yapılandırma dosyası üzerinden yapabilirsiniz",
"ClearBlocklistMessageText": "Engellenenler listesindeki tüm öğeleri temizlemek istediğinizden emin misiniz?",
"AutomaticUpdatesDisabledDocker": "Docker güncelleme mekanizması kullanıldığında otomatik güncellemeler doğrudan desteklenmez. Kapsayıcı görüntüsünü {appName} dışında güncellemeniz veya bir komut dosyası kullanmanız gerekecek",
"ConnectionLostReconnect": "{appName} otomatik bağlanmayı deneyecek veya aşağıda yeniden yükle seçeneğini işaretleyebilirsiniz.",
"BlackholeWatchFolderHelpText": "{appName} uygulamasının tamamlanmış indirmeleri içe aktaracağı klasör",
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Yeni şifreyi onayla",
"BindAddressHelpText": "Tüm arayüzler için geçerli IP adresi, localhost veya '*'",
"CloneAutoTag": "Otomatik Etiketi Klonla"
"CloneAutoTag": "Otomatik Etiketi Klonla",
"Dash": "Çizgi",
"DeleteReleaseProfileMessageText": "'{name}' bu sürüm profilini silmek istediğinizden emin misiniz?",
"DownloadClientFreeboxApiError": "Freebox API'si şu hatayı döndürdü: {errorDescription}",
"DeleteSelectedDownloadClients": "İndirme İstemcilerini Sil",
"DeleteSelectedDownloadClientsMessageText": "Seçilen {count} indirme istemcisini silmek istediğinizden emin misiniz?",
"DeleteRootFolderMessageText": "'{path}' kök klasörünü silmek istediğinizden emin misiniz?",
"DeleteSpecificationHelpText": "'{name}' spesifikasyonunu silmek istediğinizden emin misiniz?",
"DeletedReasonUpgrade": "Bir yükseltmeyi içe aktarmak için dosya silindi",
"DelayMinutes": "{delay} Dakika",
"DeleteImportListMessageText": "'{name}' listesini silmek istediğinizden emin misiniz?",
"DeleteReleaseProfile": "Sürüm Profilini Sil",
"DeleteSelectedIndexers": "Dizin Oluşturucuları Sil",
"Directory": "Rehber",
"Donate": "Bağış yap",
"DownloadClientDownloadStationValidationFolderMissing": "Klasör mevcut değil",
"DownloadClientFloodSettingsAdditionalTags": "Ek Etiketler",
"DownloadClientFloodSettingsPostImportTags": "İçe Aktarma Sonrası Etiketler",
"DownloadClientFloodSettingsStartOnAdd": "Eklemeye Başla",
"DownloadClientFloodSettingsTagsHelpText": "Bir indirme işleminin başlangıç etiketleri. Bir indirmenin tanınabilmesi için tüm başlangıç etiketlerine sahip olması gerekir. Bu, ilgisiz indirmelerle çakışmaları önler.",
"DownloadClientAriaSettingsDirectoryHelpText": "İndirilenlerin yerleştirileceği isteğe bağlı konum, varsayılan Aria2 konumunu kullanmak için boş bırakın",
"DefaultNameCopiedProfile": "{name} - Kopyala",
"DeleteAutoTag": "Etiketi Otomatik Sil",
"DeleteCondition": "Koşulu Sil",
"DeleteDelayProfileMessageText": "Bu gecikme profilini silmek istediğinizden emin misiniz?",
"DeleteRootFolder": "Kök Klasörü Sil",
"DeleteSpecification": "Spesifikasyonu Sil",
"DeletedReasonManual": "Dosya, {appName} kullanılarak manuel olarak veya API aracılığıyla başka bir araçla silindi",
"DeleteCustomFormatMessageText": "'{name}' özel biçimini silmek istediğinizden emin misiniz?",
"DefaultNameCopiedSpecification": "{name} - Kopyala",
"DeleteConditionMessageText": "'{name}' koşulunu 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?",
"DeleteSelectedIndexersMessageText": "Seçilen {count} dizin oluşturucuyu silmek istediğinizden emin misiniz?",
"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",
"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",
"DownloadClientFloodSettingsAdditionalTagsHelpText": "Medyanın özelliklerini etiket olarak ekler. İpuçları örnektir.",
"DownloadClientFloodSettingsPostImportTagsHelpText": "İndirmelere içe aktarıldıktan sonra etiket ekler.",
"DownloadClientFloodSettingsUrlBaseHelpText": "Flood API'sine {url} gibi bir önek ekler",
"ReplaceIllegalCharactersHelpText": "Geçersiz karakterleri değiştirin. İşaretlenmezse bunun yerine {appName} bunları kaldıracak",
"ConnectionSettingsUrlBaseHelpText": "{connectionName} URL'sine {url} gibi bir önek ekler",
"DeleteSelectedImportLists": "İçe Aktarma Listelerini Sil",
"DelayingDownloadUntil": "İndirme işlemi {date} tarihine, {time} tarihine kadar erteleniyor",
"Destination": "Hedef",
"DoNotBlocklist": "Engelleme Listesine Eklemeyin",
"DoNotBlocklistHint": "Engellenenler listesine eklemeden kaldır",
"DownloadClientDelugeTorrentStateError": "Deluge bir hata bildiriyor",
"DownloadClientDelugeValidationLabelPluginFailure": "Etiket yapılandırılması başarısız oldu",
"DownloadClientDownloadStationValidationSharedFolderMissing": "Paylaşılan klasör mevcut değil",
"DeleteImportList": "İçe Aktarma Listesini Sil",
"IndexerPriorityHelpText": "Dizin Oluşturucu Önceliği (En Yüksek) 1'den (En Düşük) 50'ye kadar. Varsayılan: 25'dir. Eşit olmayan sürümler için eşitlik bozucu olarak sürümler alınırken kullanılan {appName}, RSS Senkronizasyonu ve Arama için etkinleştirilmiş tüm dizin oluşturucuları kullanmaya devam edecek",
"DisabledForLocalAddresses": "Yerel Adresler için Devre Dışı Bırakıldı",
"DownloadClientDelugeValidationLabelPluginInactive": "Etiket eklentisi etkinleştirilmedi",
"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.",
"DownloadClientDownloadStationValidationSharedFolderMissingDetail": "Diskstation'da '{sharedFolder}' adında bir Paylaşımlı Klasör yok, bunu doğru belirttiğinizden emin misiniz?",
"DownloadClientFloodSettingsRemovalInfo": "{appName}, Ayarlar -> Dizin Oluşturucular'daki mevcut tohum kriterlerine göre torrentlerin otomatik olarak kaldırılmasını gerçekleştirecek",
"Database": "Veri tabanı",
"DelayProfileProtocol": "Protokol: {preferredProtocol}",
"DownloadClientDownloadStationValidationFolderMissingDetail": "'{downloadDir}' klasörü mevcut değil, '{sharedFolder}' Paylaşımlı Klasöründe manuel olarak oluşturulması gerekiyor.",
"DeleteAutoTagHelpText": "'{name}' etiketini otomatik silmek istediğinizden emin misiniz?",
"DownloadClientDelugeSettingsUrlBaseHelpText": "Deluge json URL'sine bir önek ekler, bkz. {url}",
"DownloadClientFreeboxSettingsPortHelpText": "Freebox arayüzüne erişim için kullanılan bağlantı noktası, varsayılan olarak '{port}' şeklindedir",
"DownloadClientFreeboxUnableToReachFreebox": "Freebox API'sine ulaşılamıyor. 'Ana Bilgisayar', 'Bağlantı Noktası' veya 'SSL Kullan' ayarlarını doğrulayın. (Hata: {istisnaMessage})",
"CustomFormatsSettingsTriggerInfo": "Bir yayına veya dosyaya, seçilen farklı koşul türlerinden en az biriyle eşleştiğinde Özel Format uygulanacaktır.",
"Default": "Varsayılan",
"DeleteSelectedImportListsMessageText": "Seçilen {count} içe aktarma listesini silmek istediğinizden emin misiniz?",
"DownloadClientDelugeSettingsDirectory": "İndirme Dizini",
"DownloadClientDelugeSettingsDirectoryCompleted": "Tamamlandığında Dizini Taşı",
"DownloadClientDelugeSettingsDirectoryCompletedHelpText": "Tamamlanan indirmelerin taşınacağı isteğe bağlı konum; varsayılan Deluge konumunu kullanmak için boş bırakın",
"DownloadClientDelugeSettingsDirectoryHelpText": "İndirilenlerin yerleştirileceği isteğe bağlı konum; varsayılan Deluge konumunu kullanmak için boş bırakın",
"DownloadClientDownloadStationSettingsDirectoryHelpText": "İndirilenlerin yerleştirileceği isteğe bağlı paylaşımlı klasör, varsayılan Download Station konumunu kullanmak için boş bırakın",
"ApiKey": "API Anahtarı",
"Analytics": "Analiz",
"All": "Herşey",
"AppDataLocationHealthCheckMessage": "Güncellemede AppData'nın silinmesini önlemek için güncelleme mümkün olmayacak",
"AnalyticsEnabledHelpText": "Anonim kullanım ve hata bilgilerini {appName} sunucularına gönderin. Bu, tarayıcınızla ilgili bilgileri, kullandığınız {appName} Web arayüz sayfalarını, hata raporlamasının yanı sıra işletim sistemi ve çalışma zamanı sürümünü içerir. Bu bilgileri, özellikleri ve hata düzeltmelerini önceliklendirmek için kullanacağız."
}

@ -20,7 +20,7 @@ namespace NzbDrone.Core.Parser
new RegexReplace(@".*?[_. ](S\d{2}(?:E\d{2,4})*[_. ].*)", "$1", RegexOptions.Compiled | RegexOptions.IgnoreCase)
};
private static readonly Regex LanguageRegex = new Regex(@"(?:\W|_)(?<english>\b(?:ing|eng)\b)|(?<italian>\b(?:ita|italian)\b)|(?<german>german\b|videomann|ger[. ]dub)|(?<flemish>flemish)|(?<greek>greek)|(?<french>(?:\W|_)(?:FR|VF|VF2|VFF|VFQ|TRUEFRENCH)(?:\W|_))|(?<russian>\b(?:rus|ru)\b)|(?<hungarian>\b(?:HUNDUB|HUN)\b)|(?<hebrew>\bHebDub\b)|(?<polish>\b(?:PL\W?DUB|DUB\W?PL|LEK\W?PL|PL\W?LEK)\b)|(?<chinese>\[(?:CH[ST]|BIG5|GB)\]|简|繁|字幕)|(?<bulgarian>\bbgaudio\b)|(?<spanish>\b(?:español|castellano|esp|spa(?!\(Latino\)))\b)|(?<ukrainian>\b(?:ukr)\b)|(?<thai>\b(?:THAI)\b)|(?<romanian>\b(?:RoDubbed|ROMANIAN)\b)|(?<catalan>[-,. ]cat[. ](?:DD|subs)|\b(?:catalan|catalán)\b)|(?<latvian>\b(?:lat|lav|lv)\b)",
private static readonly Regex LanguageRegex = new Regex(@"(?:\W|_)(?<english>\b(?:ing|eng)\b)|(?<italian>\b(?:ita|italian)\b)|(?<german>german\b|videomann|ger[. ]dub)|(?<flemish>flemish)|(?<greek>greek)|(?<french>(?:\W|_)(?:FR|VF|VF2|VFF|VFQ|TRUEFRENCH)(?:\W|_))|(?<russian>\b(?:rus|ru)\b)|(?<hungarian>\b(?:HUNDUB|HUN)\b)|(?<hebrew>\bHebDub\b)|(?<polish>\b(?:PL\W?DUB|DUB\W?PL|LEK\W?PL|PL\W?LEK)\b)|(?<chinese>\[(?:CH[ST]|BIG5|GB)\]|简|繁|字幕)|(?<bulgarian>\bbgaudio\b)|(?<spanish>\b(?:español|castellano|esp|spa(?!\(Latino\)))\b)|(?<ukrainian>\b(?:\dx?)?(?:ukr))|(?<thai>\b(?:THAI)\b)|(?<romanian>\b(?:RoDubbed|ROMANIAN)\b)|(?<catalan>[-,. ]cat[. ](?:DD|subs)|\b(?:catalan|catalán)\b)|(?<latvian>\b(?:lat|lav|lv)\b)|(?<turkish>\b(?:tur)\b)",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex CaseSensitiveLanguageRegex = new Regex(@"(?:(?i)(?<!SUB[\W|_|^]))(?:(?<lithuanian>\bLT\b)|(?<czech>\bCZ\b)|(?<polish>\bPL\b)|(?<bulgarian>\bBG\b)|(?<slovak>\bSK\b))(?:(?i)(?![\W|_|^]SUB))",
@ -470,6 +470,11 @@ namespace NzbDrone.Core.Parser
{
languages.Add(Language.Latvian);
}
if (match.Groups["turkish"].Success)
{
languages.Add(Language.Turkish);
}
}
return languages;

@ -7,7 +7,7 @@
<PackageReference Include="Diacritical.Net" Version="1.0.4" />
<PackageReference Include="MailKit" Version="4.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.2" />
<PackageReference Include="Polly" Version="8.3.0" />
<PackageReference Include="Polly" Version="8.3.1" />
<PackageReference Include="Servarr.FFMpegCore" Version="4.7.0-26" />
<PackageReference Include="Servarr.FFprobe" Version="5.1.4.112" />
<PackageReference Include="System.Memory" Version="4.5.5" />

@ -205,10 +205,10 @@ namespace Sonarr.Api.V3
[SkipValidation(true, false)]
[HttpPost("test")]
[Consumes("application/json")]
public object Test([FromBody] TProviderResource providerResource)
public object Test([FromBody] TProviderResource providerResource, [FromQuery] bool forceTest = false)
{
var existingDefinition = providerResource.Id > 0 ? _providerFactory.Find(providerResource.Id) : null;
var providerDefinition = GetDefinition(providerResource, existingDefinition, true, true, true);
var providerDefinition = GetDefinition(providerResource, existingDefinition, true, !forceTest, true);
Test(providerDefinition, true);

@ -1654,6 +1654,16 @@
"tags": [
"DownloadClient"
],
"parameters": [
{
"name": "forceTest",
"in": "query",
"schema": {
"type": "boolean",
"default": false
}
}
],
"requestBody": {
"content": {
"application/json": {
@ -2897,6 +2907,16 @@
"tags": [
"ImportList"
],
"parameters": [
{
"name": "forceTest",
"in": "query",
"schema": {
"type": "boolean",
"default": false
}
}
],
"requestBody": {
"content": {
"application/json": {
@ -3487,6 +3507,16 @@
"tags": [
"Indexer"
],
"parameters": [
{
"name": "forceTest",
"in": "query",
"schema": {
"type": "boolean",
"default": false
}
}
],
"requestBody": {
"content": {
"application/json": {
@ -4470,6 +4500,16 @@
"tags": [
"Metadata"
],
"parameters": [
{
"name": "forceTest",
"in": "query",
"schema": {
"type": "boolean",
"default": false
}
}
],
"requestBody": {
"content": {
"application/json": {
@ -5032,6 +5072,16 @@
"tags": [
"Notification"
],
"parameters": [
{
"name": "forceTest",
"in": "query",
"schema": {
"type": "boolean",
"default": false
}
}
],
"requestBody": {
"content": {
"application/json": {

Loading…
Cancel
Save