1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-17 21:26:13 -04:00

Compare commits

..

14 Commits

Author SHA1 Message Date
Qstick
913b845faa Fixed: Prevent anime search with ep/season if not supported 2024-02-09 21:30:08 -05:00
Stas Panasiuk
6e81517d51 New: Parsing titles with multiple translated titles 2024-02-06 23:03:36 -05:00
Mark McDowall
34e74eecd7 Fixed: Don't attempt to import from list with title only (#6477)
Closes #6474
2024-02-06 23:02:26 -05:00
Mark McDowall
895eccebc5 New: Parse and reject split episode releases and files 2024-02-06 23:02:03 -05:00
Mark McDowall
f722d49b3a Fixed: Don't use sub folder to check for free disk space for update
Closes #6478
2024-02-06 20:01:30 -08:00
bakerboy448
cac97c057f Improve Custom Format rejection messaging 2024-02-06 23:01:07 -05:00
jab416171
63e132d257 Wrapped fields on series details page in div
This allows you to triple click to select the path for instance, similar
to the details page in radarr.
2024-02-06 19:59:02 -08:00
Mark McDowall
6ab1d8e16b New: Log database engine version on startup 2024-02-06 22:58:49 -05:00
Stevie Robinson
80630bf97f Fixed: Wrapping of naming tokens with alternate separators 2024-02-06 22:58:09 -05:00
Bogdan
904285045b Fixed: Naming validation when using max token length 2024-02-06 19:57:44 -08:00
Stevie Robinson
1006ec6b52 really fix translation key 2024-02-06 19:57:33 -08:00
Mark McDowall
4cb1100704 Fixed: Remove old naming config from v3 API responses
Closes #6460
2024-02-06 19:57:25 -08:00
Mark McDowall
745b92daf4 Fixed: Redirecting after login
Closes #6454
2024-02-06 19:57:17 -08:00
Weblate
9eafdbd1af Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Ole Nørby <ole@olenoerby.dk>
Co-authored-by: Stevie Robinson <stevie.robinson@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: aghus <aghus.m@outlook.com>
Co-authored-by: gr0sz <joshuatg727@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2024-02-06 19:57:09 -08:00
27 changed files with 314 additions and 268 deletions

View File

@@ -428,14 +428,16 @@ class SeriesDetails extends Component {
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={icons.FOLDER}
size={17}
/>
<span className={styles.path}>
{path}
</span>
<div>
<Icon
name={icons.FOLDER}
size={17}
/>
<span className={styles.path}>
{path}
</span>
</div>
</Label>
<Tooltip
@@ -444,16 +446,18 @@ class SeriesDetails extends Component {
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={icons.DRIVE}
size={17}
/>
<span className={styles.sizeOnDisk}>
{
formatBytes(sizeOnDisk || 0)
}
</span>
<div>
<Icon
name={icons.DRIVE}
size={17}
/>
<span className={styles.sizeOnDisk}>
{
formatBytes(sizeOnDisk || 0)
}
</span>
</div>
</Label>
}
tooltip={
@@ -470,32 +474,36 @@ class SeriesDetails extends Component {
title={translate('QualityProfile')}
size={sizes.LARGE}
>
<Icon
name={icons.PROFILE}
size={17}
/>
<span className={styles.qualityProfileName}>
{
<QualityProfileNameConnector
qualityProfileId={qualityProfileId}
/>
}
</span>
<div>
<Icon
name={icons.PROFILE}
size={17}
/>
<span className={styles.qualityProfileName}>
{
<QualityProfileNameConnector
qualityProfileId={qualityProfileId}
/>
}
</span>
</div>
</Label>
<Label
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={monitored ? icons.MONITORED : icons.UNMONITORED}
size={17}
/>
<span className={styles.qualityProfileName}>
{monitored ? translate('Monitored') : translate('Unmonitored')}
</span>
<div>
<Icon
name={monitored ? icons.MONITORED : icons.UNMONITORED}
size={17}
/>
<span className={styles.qualityProfileName}>
{monitored ? translate('Monitored') : translate('Unmonitored')}
</span>
</div>
</Label>
<Label
@@ -503,14 +511,16 @@ class SeriesDetails extends Component {
title={statusDetails.message}
size={sizes.LARGE}
>
<Icon
name={statusDetails.icon}
size={17}
/>
<span className={styles.qualityProfileName}>
{statusDetails.title}
</span>
<div>
<Icon
name={statusDetails.icon}
size={17}
/>
<span className={styles.qualityProfileName}>
{statusDetails.title}
</span>
</div>
</Label>
{
@@ -520,14 +530,16 @@ class SeriesDetails extends Component {
title={translate('Network')}
size={sizes.LARGE}
>
<Icon
name={icons.NETWORK}
size={17}
/>
<span className={styles.qualityProfileName}>
{network}
</span>
<div>
<Icon
name={icons.NETWORK}
size={17}
/>
<span className={styles.qualityProfileName}>
{network}
</span>
</div>
</Label>
}
@@ -537,14 +549,16 @@ class SeriesDetails extends Component {
className={styles.detailsLabel}
size={sizes.LARGE}
>
<Icon
name={icons.EXTERNAL_LINK}
size={17}
/>
<span className={styles.links}>
{translate('Links')}
</span>
<div>
<Icon
name={icons.EXTERNAL_LINK}
size={17}
/>
<span className={styles.links}>
{translate('Links')}
</span>
</div>
</Label>
}
tooltip={

View File

@@ -17,7 +17,7 @@
}
.small {
width: 480px;
width: 490px;
}
.large {
@@ -26,7 +26,7 @@
.token {
flex: 0 0 50%;
padding: 6px 16px;
padding: 6px 6px;
background-color: var(--popoverTitleBackgroundColor);
font-family: $monoSpaceFontFamily;
}
@@ -36,7 +36,7 @@
align-items: center;
justify-content: space-between;
flex: 0 0 50%;
padding: 6px 16px;
padding: 6px 6px;
background-color: var(--popoverBodyBackgroundColor);
.footNote {

View File

@@ -406,17 +406,6 @@ namespace NzbDrone.Core.Test.ImportListTests
.Verify(v => v.AddSeries(It.Is<List<Series>>(s => s.Count == 3), true), Times.Once());
}
[Test]
public void should_search_if_series_title_and_no_series_id()
{
_importListFetch.Series.ForEach(m => m.ImportListId = 1);
WithList(1, true);
Subject.Execute(_commandAll);
Mocker.GetMock<ISearchForNewSeries>()
.Verify(v => v.SearchForNewSeries(It.IsAny<string>()), Times.Once());
}
[Test]
public void should_not_search_if_series_title_and_series_id()
{

View File

@@ -76,6 +76,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Series T Se.3 afl.3 en 4", "Series T", 3, new[] { 3, 4 })]
[TestCase("Series Title (S15E06-08) City Sushi", "Series Title", 15, new[] { 6, 7, 8 })]
[TestCase("Босх: Спадок (S2E1-4) / Series: Legacy (S2E1-4) (2023) WEB-DL 1080p Ukr/Eng | sub Eng", "Series: Legacy", 2, new[] { 1, 2, 3, 4 })]
[TestCase("Босх: Спадок / Series: Legacy / S2E1-4 of 10 (2023) WEB-DL 1080p Ukr/Eng | sub Eng", "Series: Legacy", 2, new[] { 1, 2, 3, 4 })]
// [TestCase("", "", , new [] { })]
public void should_parse_multiple_episodes(string postTitle, string title, int season, int[] episodes)

View File

@@ -94,6 +94,7 @@ namespace NzbDrone.Core.Test.ParserTests
}
[TestCase("Босх: Спадок (S2E1) / Series: Legacy (S2E1) (2023) WEB-DL 1080p Ukr/Eng | sub Eng", "Босх: Спадок", "Series: Legacy")]
[TestCase("Босх: Спадок / Series: Legacy / S2E1-4 of 10 (2023) WEB-DL 1080p Ukr/Eng | sub Eng", "Босх: Спадок", "Series: Legacy")]
public void should_parse_multiple_series_titles(string postTitle, params string[] titles)
{
var seriesTitleInfo = Parser.Parser.ParseTitle(postTitle).SeriesTitleInfo;

View File

@@ -165,6 +165,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Series Title [HDTV][Cap.402](website.com).avi", "Series Title", 4, 2)]
[TestCase("Series Title [HDTV 720p][Cap.101](website.com).mkv", "Series Title", 1, 1)]
[TestCase("Босх: Спадок (S2E1) / Series: Legacy (S2E1) (2023) WEB-DL 1080p Ukr/Eng | sub Eng", "Series: Legacy", 2, 1)]
[TestCase("Босх: Спадок / Series: Legacy / S2E1 of 10 (2023) WEB-DL 1080p Ukr/Eng | sub Eng", "Series: Legacy", 2, 1)]
// [TestCase("", "", 0, 0)]
public void should_parse_single_episode(string postTitle, string title, int seasonNumber, int episodeNumber)
@@ -211,5 +212,19 @@ namespace NzbDrone.Core.Test.ParserTests
result.FullSeason.Should().BeFalse();
result.Special.Should().BeTrue();
}
[TestCase("Series.Title.S06E01b.Fade.Out.Fade.in.Part.2.1080p.DSNP.WEB-DL.AAC2.0.H.264-FLUX", "Series Title", 6, 1)]
public void should_parse_split_episode(string postTitle, string title, int seasonNumber, int episodeNumber)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Should().NotBeNull();
result.EpisodeNumbers.Should().HaveCount(1);
result.SeasonNumber.Should().Be(seasonNumber);
result.EpisodeNumbers.First().Should().Be(episodeNumber);
result.SeriesTitle.Should().Be(title);
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeFalse();
result.IsSplitEpisode.Should().BeTrue();
}
}
}

View File

@@ -0,0 +1,69 @@
using System.Data;
using System.Text.RegularExpressions;
using FluentMigrator;
using NLog;
using NzbDrone.Common.Instrumentation;
namespace NzbDrone.Core.Datastore.Migration
{
[Maintenance(MigrationStage.BeforeAll, TransactionBehavior.None)]
public class DatabaseEngineVersionCheck : FluentMigrator.Migration
{
protected readonly Logger _logger;
public DatabaseEngineVersionCheck()
{
_logger = NzbDroneLogger.GetLogger(this);
}
public override void Up()
{
IfDatabase("sqlite").Execute.WithConnection(LogSqliteVersion);
IfDatabase("postgres").Execute.WithConnection(LogPostgresVersion);
}
public override void Down()
{
// No-op
}
private void LogSqliteVersion(IDbConnection conn, IDbTransaction tran)
{
using (var versionCmd = conn.CreateCommand())
{
versionCmd.Transaction = tran;
versionCmd.CommandText = "SELECT sqlite_version();";
using (var reader = versionCmd.ExecuteReader())
{
while (reader.Read())
{
var version = reader.GetString(0);
_logger.Info("SQLite {0}", version);
}
}
}
}
private void LogPostgresVersion(IDbConnection conn, IDbTransaction tran)
{
using (var versionCmd = conn.CreateCommand())
{
versionCmd.Transaction = tran;
versionCmd.CommandText = "SHOW server_version";
using (var reader = versionCmd.ExecuteReader())
{
while (reader.Read())
{
var version = reader.GetString(0);
var cleanVersion = Regex.Replace(version, @"\(.*?\)", "");
_logger.Info("Postgres {0}", cleanVersion);
}
}
}
}
}
}

View File

@@ -42,12 +42,13 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
serviceProvider = new ServiceCollection()
.AddLogging(b => b.AddNLog())
.AddFluentMigratorCore()
.Configure<RunnerOptions>(cfg => cfg.IncludeUntaggedMaintenances = true)
.ConfigureRunner(
builder => builder
.AddPostgres()
.AddNzbDroneSQLite()
.WithGlobalConnectionString(connectionString)
.WithMigrationsIn(Assembly.GetExecutingAssembly()))
.ScanIn(Assembly.GetExecutingAssembly()).For.All())
.Configure<TypeFilterOptions>(opt => opt.Namespace = "NzbDrone.Core.Datastore.Migration")
.Configure<ProcessorOptions>(opt =>
{

View File

@@ -0,0 +1,30 @@
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
public class SplitEpisodeSpecification : IDecisionEngineSpecification
{
private readonly Logger _logger;
public SplitEpisodeSpecification(Logger logger)
{
_logger = logger;
}
public SpecificationPriority Priority => SpecificationPriority.Default;
public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{
if (subject.ParsedEpisodeInfo.IsSplitEpisode)
{
_logger.Debug("Split episode release {0} rejected. Not supported", subject.Release.Title);
return Decision.Reject("Split episode releases are not supported");
}
return Decision.Accept();
}
}
}

View File

@@ -45,7 +45,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
[FieldToken(TokenField.HelpText, "UseSsl", "clientName", "Transmission")]
public bool UseSsl { get; set; }
[FieldDefinition(3, Label = "UrlBase", Type = FieldType.Textbox, Advanced = true, HelpText = "DownloadClientTransmissionSettingsDirectoryHelpText")]
[FieldDefinition(3, Label = "UrlBase", Type = FieldType.Textbox, Advanced = true, HelpText = "DownloadClientTransmissionSettingsUrlBaseHelpText")]
[FieldToken(TokenField.HelpText, "UrlBase", "clientName", "Transmission")]
[FieldToken(TokenField.HelpText, "UrlBase", "url", "http://[host]:[port]/[urlBase]/rpc")]
[FieldToken(TokenField.HelpText, "UrlBase", "defaultUrl", "/transmission/")]

View File

@@ -190,19 +190,6 @@ namespace NzbDrone.Core.ImportLists
item.Title = mappedSeries.Title;
}
// Map TVDb if we only have a series name
if (item.TvdbId <= 0 && item.Title.IsNotNullOrWhiteSpace())
{
var mappedSeries = _seriesSearchService.SearchForNewSeries(item.Title)
.FirstOrDefault();
if (mappedSeries != null)
{
item.TvdbId = mappedSeries.TvdbId;
item.Title = mappedSeries?.Title;
}
}
// Check to see if series excluded
var excludedSeries = listExclusions.Where(s => s.TvdbId == item.TvdbId).SingleOrDefault();

View File

@@ -402,7 +402,7 @@ namespace NzbDrone.Core.Indexers.Newznab
searchCriteria.SeasonNumber > 0 &&
searchCriteria.EpisodeNumber > 0;
if (includeAnimeStandardFormatSearch)
if (includeAnimeStandardFormatSearch && SupportsEpisodeSearch)
{
AddTvIdPageableRequests(pageableRequests,
Settings.AnimeCategories,
@@ -419,7 +419,7 @@ namespace NzbDrone.Core.Indexers.Newznab
"search",
$"&q={NewsnabifyTitle(queryTitle)}+{searchCriteria.AbsoluteEpisodeNumber:00}"));
if (includeAnimeStandardFormatSearch)
if (includeAnimeStandardFormatSearch && SupportsEpisodeSearch)
{
pageableRequests.Add(GetPagedRequests(MaxPages,
Settings.AnimeCategories,

View File

@@ -1,3 +1,21 @@
{
"Absolute": "Absolut"
"Absolute": "Absolut",
"AbsoluteEpisodeNumber": "Absolut Episode-nummer",
"AddConditionError": "Kan ikke tilføje en ny betingelse, prøv igen.",
"AddAutoTagError": "Kan ikke tilføje en ny liste, prøv igen.",
"AddConnection": "Tilføj forbindelse",
"AddCustomFormat": "Tilføj tilpasset format",
"AddCustomFormatError": "Kunne ikke tilføje et nyt tilpasset format, prøv igen.",
"AddDelayProfile": "Tilføj forsinkelsesprofil",
"AddCondition": "Tilføj betingelse",
"AddAutoTag": "Tilføj automatisk Tag",
"AbsoluteEpisodeNumbers": "Absolutte Episode-numre",
"Add": "Tilføj",
"Activity": "Aktivitet",
"About": "Om",
"Actions": "Handlinger",
"AddANewPath": "Tilføj en ny sti",
"AddConditionImplementation": "Tilføj betingelse - {implementationName}",
"AddConnectionImplementation": "Tilføj forbindelse - {implementationName}",
"AddCustomFilter": "Tilføj tilpasset filter"
}

View File

@@ -989,7 +989,7 @@
"ImportListsValidationInvalidApiKey": "La clave API es inválida",
"ImportListsValidationTestFailed": "El test fue abortado debido a un error: {exceptionMessage}",
"ImportScriptPathHelpText": "La ruta al script a usar para importar",
"ImportUsingScriptHelpText": "Copia archivos a importar usando un script (p. ej. para transcodificación)",
"ImportUsingScriptHelpText": "Copiar archivos para importar usando un script (p. ej. para transcodificación)",
"Importing": "Importando",
"IncludeUnmonitored": "Incluir sin monitorizar",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Ningún indexador disponible debido a fallos durante más de 6 horas",
@@ -1059,5 +1059,12 @@
"ICalTagsSeriesHelpText": "El feed solo contendrá series con al menos una etiqueta coincidente",
"IconForCutoffUnmet": "Icono para Umbrales no alcanzados",
"IconForCutoffUnmetHelpText": "Mostrar icono para archivos cuando el umbral no haya sido alcanzado",
"EpisodeCount": "Número de episodios"
"EpisodeCount": "Número de episodios",
"IndexerSettings": "Ajustes de Indexador",
"AddDelayProfileError": "No se pudo añadir un nuevo perfil de retraso, inténtelo de nuevo.",
"IndexerRssNoIndexersAvailableHealthCheckMessage": "Todos los indexers capaces de RSS están temporalmente desactivados debido a errores recientes con el indexer",
"IndexerRssNoIndexersEnabledHealthCheckMessage": "No hay indexadores disponibles con la sincronización RSS activada, {appName} no capturará nuevos estrenos automáticamente",
"IndexerSearchNoAutomaticHealthCheckMessage": "No hay indexadores disponibles con Búsqueda Automática activada, {appName} no proporcionará ningún resultado de búsquedas automáticas",
"IndexerSearchNoAvailableIndexersHealthCheckMessage": "Todos los indexadores con capacidad de búsqueda no están disponibles temporalmente debido a errores recientes del indexadores",
"IndexerSearchNoInteractiveHealthCheckMessage": "No hay indexadores disponibles con Búsqueda Interactiva activada, {appName} no proporcionará ningún resultado de búsquedas interactivas"
}

View File

@@ -392,8 +392,8 @@
"SelectFolder": "Selecionar Pasta",
"Unavailable": "Indisponível",
"UnmappedFolders": "Pastas não mapeadas",
"AutoTaggingNegateHelpText": "Se marcada, a regra de tagging automática não será aplicada se esta condição {implementationName} corresponder.",
"AutoTaggingRequiredHelpText": "Esta condição {implementationName} deve corresponder para que a regra de tagging automática seja aplicada. Caso contrário, uma única correspondência de {implementationName} será suficiente.",
"AutoTaggingNegateHelpText": "se marcada, a regra de etiqueta automática não será aplicada se esta condição {implementationName} corresponder.",
"AutoTaggingRequiredHelpText": "Esta condição {implementationName} deve corresponder para que a regra de etiqueta automática seja aplicada. Caso contrário, uma única correspondência de {implementationName} será suficiente.",
"SomeResultsAreHiddenByTheAppliedFilter": "Alguns resultados estão ocultos pelo filtro aplicado",
"UnableToLoadAutoTagging": "Não foi possível carregar a marcação automática",
"IndexerDownloadClientHealthCheckMessage": "Indexadores com clientes de download inválidos: {indexerNames}.",
@@ -417,7 +417,7 @@
"AddNotificationError": "Não foi possível adicionar uma nova notificação, tente novamente.",
"AddQualityProfile": "Adicionar perfil de qualidade",
"AddQualityProfileError": "Não foi possível adicionar uma nova notificação, tente novamente.",
"AddReleaseProfile": "Adicionar Perfil de Lançamento",
"AddReleaseProfile": "Adicionar um Perfil de Lançamento",
"AddRemotePathMapping": "Adicionar Mapeamento de Caminho Remoto",
"AddRemotePathMappingError": "Não foi possível adicionar um novo mapeamento de caminho remoto, tente novamente.",
"AfterManualRefresh": "Depois da Atualização Manual",
@@ -477,7 +477,7 @@
"ColonReplacementFormatHelpText": "Mude como o {appName} lida com a substituição do dois-pontos",
"CompletedDownloadHandling": "Gerenciamento de Downloads Completos",
"Condition": "Condição",
"ConditionUsingRegularExpressions": "Esta condição corresponde ao uso de expressões regulares. Observe que os caracteres `\\^$.|?*+()[{` têm significados especiais e precisam ser escapados com um `\\`",
"ConditionUsingRegularExpressions": "Esta condição corresponde ao uso de Expressões Regulares. Observe que os caracteres `\\^$.|?*+()[{` têm significados especiais e precisam escape com um `\\`",
"ConnectSettings": "Configurações de Conexão",
"ConnectSettingsSummary": "Notificações, conexões com servidores/reprodutores de mídia e scripts personalizados",
"Connections": "Conexões",
@@ -488,7 +488,7 @@
"CreateGroup": "Criar Grupo",
"Custom": "Personalizar",
"CustomFormat": "Formato personalizado",
"CustomFormatUnknownCondition": "Condição de formato personalizado desconhecido '{implementation}'",
"CustomFormatUnknownCondition": "Condição de Formato Personalizado desconhecida '{implementation}'",
"CustomFormatUnknownConditionOption": "Opção desconhecida '{key}' para a condição '{implementation}'",
"CustomFormatsLoadError": "Não foi possível carregar Formatos Personalizados",
"CustomFormatsSettings": "Configurações de Formatos Personalizados",
@@ -501,7 +501,7 @@
"DefaultDelayProfileSeries": "Este é o perfil padrão. Aplica-se a todas as séries que não possuem um perfil explícito.",
"DelayMinutes": "{delay} Minutos",
"DelayProfile": "Perfil de Atraso",
"DefaultCase": "Minúscula ou maiúscula",
"DefaultCase": "Padrão Maiúscula ou Minúscula",
"DelayProfileSeriesTagsHelpText": "Aplica-se a séries com pelo menos uma tag correspondente",
"DelayProfiles": "Perfis de Atraso",
"DelayProfilesLoadError": "Não foi possível carregar perfis de atraso",
@@ -544,7 +544,7 @@
"EditGroups": "Editar Grupos",
"EditImportListExclusion": "Editar Exclusão de Lista de Importação",
"EditListExclusion": "Editar Exclusão da Lista",
"EditMetadata": "Editar metadados {metadataType}",
"EditMetadata": "Editar {metadataType} Metadados",
"EditQualityProfile": "Editar Perfil de Qualidade",
"EditReleaseProfile": "Editar Perfil de Lançamento",
"EditRemotePathMapping": "Editar Mapeamento do Caminho Remoto",
@@ -574,7 +574,7 @@
"Extend": "Estender",
"ExtraFileExtensionsHelpTextsExamples": "Exemplos: '.sub, .nfo' or 'sub,nfo'",
"FileManagement": "Gerenciamento de Arquivo",
"FileNameTokens": "Tokens de Nome de Arquivo",
"FileNameTokens": "Tokens de nome de arquivo",
"FileNames": "Nomes de Arquivo",
"FirstDayOfWeek": "Primeiro Dia da Semana",
"Folders": "Pastas",
@@ -620,8 +620,8 @@
"LanguagesLoadError": "Não foi possível carregar os idiomas",
"ListExclusionsLoadError": "Não foi possível carregar as exclusões de lista",
"ListOptionsLoadError": "Não foi possível carregar as opções de lista",
"ListQualityProfileHelpText": "Os itens da lista de perfil de qualidade serão adicionados com",
"ListRootFolderHelpText": "Os itens da lista da pasta raiz serão adicionados a",
"ListQualityProfileHelpText": "Os itens da lista de Perfil de Qualidade que serão adicionados com",
"ListRootFolderHelpText": "Os itens da lista da pasta raiz que serão adicionados",
"ListTagsHelpText": "Tags que serão adicionadas ao importar esta lista",
"ListWillRefreshEveryInterval": "A lista será atualizada a cada {refreshInterval}",
"ListsLoadError": "Não foi possível carregar as listas",
@@ -631,7 +631,7 @@
"LogLevelTraceHelpTextWarning": "O registro em log deve ser habilitado apenas temporariamente",
"Logging": "Registro em log",
"LongDateFormat": "Formato longo de data",
"Lowercase": "Minúsculas",
"Lowercase": "Minúscula",
"ManualImportItemsLoadError": "Não foi possível carregar itens de importação manual",
"Max": "Máx.",
"MaximumLimits": "Limites máximos",
@@ -668,12 +668,12 @@
"MultiEpisodeStyle": "Estilo de multiepisódio",
"MustContain": "Deve conter",
"MustNotContain": "Não deve conter",
"MustNotContainHelpText": "O lançamento será rejeitado se contiver um ou mais destes termos (sem distinção entre maiúsculas e minúsculas)",
"MustNotContainHelpText": "O lançamento será rejeitado se contiver um ou mais termos (não diferenciar maiúsculas e minúsculas)",
"NamingSettings": "Configurações de nomenclatura",
"NamingSettingsLoadError": "Não foi possível carregar as configurações de nomenclatura",
"Never": "Nunca",
"NoChanges": "Sem alterações",
"NoDelay": "Sem atraso",
"NoDelay": "Sem Atraso",
"NoLinks": "Sem links",
"NoTagsHaveBeenAddedYet": "Nenhuma tag foi adicionada ainda",
"None": "Nenhum",
@@ -703,7 +703,7 @@
"Password": "Senha",
"PendingChangesDiscardChanges": "Descartar mudanças e sair",
"PendingChangesStayReview": "Ficar e revisar mudanças",
"Period": "Período",
"Period": "Ponto",
"Permissions": "Permissões",
"PortNumber": "Número da Porta",
"PreferAndUpgrade": "Preferir e Atualizar",
@@ -737,7 +737,7 @@
"RecyclingBinCleanupHelpTextWarning": "Os arquivos na lixeira mais antigos do que o número de dias selecionado serão limpos automaticamente",
"RecyclingBinHelpText": "Os arquivos irão para cá quando excluídos, em vez de serem excluídos permanentemente",
"AbsoluteEpisodeNumber": "Número Absoluto do Episódio",
"AddAutoTagError": "Não foi possível adicionar uma nova tag automática, por favor, tente novamente.",
"AddAutoTagError": "Não foi possível adicionar uma nova etiqueta automática, tente novamente.",
"AnalyseVideoFilesHelpText": "Extraia informações de vídeo, como resolução, tempo de execução e informações de codec de arquivos. Isso requer que o {appName} leia partes do arquivo que podem causar alta atividade no disco ou na rede durante as varreduras.",
"AuthenticationRequiredHelpText": "Altere para quais solicitações a autenticação é necessária. Não mude a menos que você entenda os riscos.",
"AuthenticationRequiredWarning": "Para evitar o acesso remoto sem autenticação, {appName} agora exige que a autenticação esteja habilitada. Opcionalmente, você pode desabilitar a autenticação de endereços locais.",
@@ -753,9 +753,9 @@
"ExtraFileExtensionsHelpText": "Lista separada por vírgulas de arquivos extras para importar (.nfo será importado como .nfo-orig)",
"HistoryLoadError": "Não foi possível carregar o histórico",
"IndexerTagSeriesHelpText": "Usar este indexador apenas para séries com pelo menos uma tag correspondente. Deixe em branco para usar com todas as séries.",
"MediaInfoFootNote": "MediaInfo Full/AudioLanguages/SubtitleLanguages oferece suporte a um sufixo \":EN+DE\", permitindo que você filtre os idiomas inclusos no nome do arquivo. Use \"-DE\" para excluir idiomas específicos. Usar \"+\" (p. ex.: \":EN+\") resultará em \"[EN]\"/\"[EN+--]\"/\"[--]\" dependendo dos idiomas excluídos. P. ex.: \"{MediaInfo Full:EN+DE}\".",
"MediaInfoFootNote": "MediaInfo Full/AudioLanguages/SubtitleLanguages suporta um sufixo `:EN+DE` permitindo filtrar os idiomas incluídos no nome do arquivo. Use `-DE` para excluir idiomas específicos. Anexar `+` (por exemplo, `:EN+`) resultará em `[EN]`/`[EN+--]`/`[--]` dependendo dos idiomas excluídos. Por exemplo, `{MediaInfo Full:EN+DE}`.",
"MinimumFreeSpaceHelpText": "Impedir a importação se deixar menos do que esta quantidade de espaço em disco disponível",
"MustContainHelpText": "O lançamento deve conter pelo menos um desses termos (sem distinção entre maiúsculas e minúsculas)",
"MustContainHelpText": "O lançamento deve conter pelo menos um destes termos (não diferenciar maiúsculas e minúsculas)",
"NegateHelpText": "Se marcado, o formato personalizado não será aplicado se esta condição {implementationName} corresponder.",
"NoLimitForAnyRuntime": "Sem limite para qualquer duração",
"NoMinimumForAnyRuntime": "Sem mínimo para qualquer duração",
@@ -772,7 +772,7 @@
"RegularExpressionsTutorialLink": "Mais detalhes sobre expressões regulares podem ser encontrados [aqui](https://www.regular-expressions.info/tutorial.html).",
"ReleaseProfile": "Perfil de Lançamento",
"ReleaseProfileIndexerHelpText": "Especifique a qual indexador o perfil se aplica",
"ReleaseProfileIndexerHelpTextWarning": "O uso de um indexador específico com perfis de lançamento pode levar à obtenção de lançamentos duplicados",
"ReleaseProfileIndexerHelpTextWarning": "Usar um indexador específico com perfis de lançamento pode levar à captura de lançamentos duplicados",
"ReleaseProfileTagSeriesHelpText": "Os perfis de lançamento serão aplicados a séries com pelo menos uma tag correspondente. Deixe em branco para aplicar a todas as séries",
"ReleaseProfiles": "Perfis de Lançamentos",
"ReleaseProfilesLoadError": "Não foi possível carregar perfis de lançamentos",
@@ -799,8 +799,8 @@
"RestartLater": "Vou reiniciar mais tarde",
"RestartNow": "Reiniciar Agora",
"RestartRequiredHelpTextWarning": "Requer reinicialização para entrar em vigor",
"RestartRequiredToApplyChanges": "O {appName} requer uma reinicialização para aplicar as alterações. Deseja reiniciar agora?",
"RestartRequiredWindowsService": "Dependendo de qual usuário está executando o serviço {appName}, pode ser necessário reiniciar o {appName} como administrador uma vez antes que o serviço seja iniciado automaticamente.",
"RestartRequiredToApplyChanges": "{appName} requer reinicialização para aplicar as alterações. Deseja reiniciar agora?",
"RestartRequiredWindowsService": "Dependendo de qual usuário está executando o serviço {appName}, pode ser necessário reiniciar {appName} como administrador uma vez antes que o serviço seja iniciado automaticamente.",
"RestartSonarr": "Reiniciar {appName}",
"RestrictionsLoadError": "Não foi possível carregar as Restrições",
"Retention": "Retenção",
@@ -901,7 +901,7 @@
"UpgradeUntilThisQualityIsMetOrExceeded": "Atualize até que essa qualidade seja atendida ou excedida",
"UpgradesAllowed": "Atualizações Permitidas",
"UpgradesAllowedHelpText": "se as qualidades desativadas não forem atualizadas",
"Uppercase": "Maiúsculo",
"Uppercase": "Maiuscula",
"UrlBase": "URL base",
"UrlBaseHelpText": "Para suporte a proxy reverso, o padrão é vazio",
"UseProxy": "Usar Proxy",
@@ -1198,7 +1198,7 @@
"InteractiveImportNoLanguage": "Defina um idioma para cada arquivo selecionado",
"InteractiveImportNoQuality": "Defina a qualidade para cada arquivo selecionado",
"InteractiveImportNoSeries": "A série deve ser escolhida para cada arquivo selecionado",
"KeyboardShortcuts": "Atalhos de teclado",
"KeyboardShortcuts": "Atalhos do Teclado",
"KeyboardShortcutsCloseModal": "Fechar pop-up atual",
"KeyboardShortcutsConfirmModal": "Aceitar o pop-up de confirmação",
"KeyboardShortcutsOpenModal": "Abrir este pop-up",
@@ -2038,5 +2038,6 @@
"ListSyncTagHelpText": "Esta etiqueta será adicionada quando uma série cair ou não estiver mais na(s) sua(s) lista(s)",
"LogOnly": "Só Registro",
"UnableToLoadListOptions": "Não foi possível carregar as opções da lista",
"CleanLibraryLevel": "Limpar Nível da Biblioteca"
"CleanLibraryLevel": "Limpar Nível da Biblioteca",
"AddDelayProfileError": "Não foi possível adicionar um novo perfil de atraso. Tente novamente."
}

View File

@@ -0,0 +1,33 @@
using NLog;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
{
public class SplitEpisodeSpecification : IImportDecisionEngineSpecification
{
private readonly Logger _logger;
public SplitEpisodeSpecification(Logger logger)
{
_logger = logger;
}
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem)
{
if (localEpisode.FileEpisodeInfo == null)
{
return Decision.Accept();
}
if (localEpisode.FileEpisodeInfo.IsSplitEpisode)
{
_logger.Debug("Single episode split into multiple files");
return Decision.Reject("Single episode split into multiple files");
}
return Decision.Accept();
}
}
}

View File

@@ -72,7 +72,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
currentFormats != null ? currentFormats.ConcatToString() : "",
currentFormatScore);
return Decision.Reject("Not a Custom Format upgrade for existing episode file(s)");
return Decision.Reject("Not a Custom Format upgrade for existing episode file(s). New: [{0}] ({1}) do not improve on Existing: [{2}] ({3})",
newFormats != null ? newFormats.ConcatToString() : "",
newFormatScore,
currentFormats != null ? currentFormats.ConcatToString() : "",
currentFormatScore);
}
_logger.Debug("New item's custom formats [{0}] ({1}) improve on [{2}] ({3}), accepting",

View File

@@ -1,12 +0,0 @@
namespace NzbDrone.Core.Organizer
{
public class BasicNamingConfig
{
public bool IncludeSeriesTitle { get; set; }
public bool IncludeEpisodeTitle { get; set; }
public bool IncludeQuality { get; set; }
public bool ReplaceSpaces { get; set; }
public string Separator { get; set; }
public string NumberStyle { get; set; }
}
}

View File

@@ -25,7 +25,6 @@ namespace NzbDrone.Core.Organizer
string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension = "", NamingConfig namingConfig = null, List<CustomFormat> customFormats = null);
string BuildFilePath(List<Episode> episodes, Series series, EpisodeFile episodeFile, string extension, NamingConfig namingConfig = null, List<CustomFormat> customFormats = null);
string BuildSeasonPath(Series series, int seasonNumber);
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
string GetSeriesFolder(Series series, NamingConfig namingConfig = null);
string GetSeasonFolder(Series series, int seasonNumber, NamingConfig namingConfig = null);
bool RequiresEpisodeTitle(Series series, List<Episode> episodes);
@@ -68,7 +67,7 @@ namespace NzbDrone.Core.Organizer
public static readonly Regex AirDateRegex = new Regex(@"\{Air(\s|\W|_)Date\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex SeriesTitleRegex = new Regex(@"(?<token>\{(?:Series)(?<separator>[- ._])(Clean)?Title(The)?(Without)?(Year)?\})",
public static readonly Regex SeriesTitleRegex = new Regex(@"(?<token>\{(?:Series)(?<separator>[- ._])(Clean)?Title(The)?(Without)?(Year)?(?::(?<customFormat>[0-9-]+))?\})",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled);
@@ -253,52 +252,6 @@ namespace NzbDrone.Core.Organizer
return path;
}
public BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec)
{
var episodeFormat = GetEpisodeFormat(nameSpec.StandardEpisodeFormat).LastOrDefault();
if (episodeFormat == null)
{
return new BasicNamingConfig();
}
var basicNamingConfig = new BasicNamingConfig
{
Separator = episodeFormat.Separator,
NumberStyle = episodeFormat.SeasonEpisodePattern
};
var titleTokens = TitleRegex.Matches(nameSpec.StandardEpisodeFormat);
foreach (Match match in titleTokens)
{
var separator = match.Groups["separator"].Value;
var token = match.Groups["token"].Value;
if (!separator.Equals(" "))
{
basicNamingConfig.ReplaceSpaces = true;
}
if (token.StartsWith("{Series", StringComparison.InvariantCultureIgnoreCase))
{
basicNamingConfig.IncludeSeriesTitle = true;
}
if (token.StartsWith("{Episode", StringComparison.InvariantCultureIgnoreCase))
{
basicNamingConfig.IncludeEpisodeTitle = true;
}
if (token.StartsWith("{Quality", StringComparison.InvariantCultureIgnoreCase))
{
basicNamingConfig.IncludeQuality = true;
}
}
return basicNamingConfig;
}
public string GetSeriesFolder(Series series, NamingConfig namingConfig = null)
{
if (namingConfig == null)

View File

@@ -23,6 +23,7 @@ namespace NzbDrone.Core.Parser.Model
public bool IsPartialSeason { get; set; }
public bool IsMultiSeason { get; set; }
public bool IsSeasonExtra { get; set; }
public bool IsSplitEpisode { get; set; }
public bool Special { get; set; }
public string ReleaseGroup { get; set; }
public string ReleaseHash { get; set; }

View File

@@ -74,6 +74,10 @@ namespace NzbDrone.Core.Parser
new Regex(@"^(?:S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[-_]|[ex]){1,2}(?<episode>\d{2,3}(?!\d+))){2,})",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
// Split episodes (S01E05a, S01E05b, etc)
new Regex(@"^(?<title>.+?)(?:S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[-_ ]?[ex])(?<episode>\d{2,3}(?!\d+))(?<splitepisode>[a-d])(?:[ _.])))",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
// Episodes without a title, Single (S01E05, 1x05)
new Regex(@"^(?:S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[-_ ]?[ex])(?<episode>\d{2,3}(?!\d+))))",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
@@ -178,6 +182,10 @@ namespace NzbDrone.Core.Parser
new Regex(@"^(?<title>.+?)?\W*(?<airyear>\d{4})\W+(?<airmonth>[0-1][0-9])\W+(?<airday>[0-3][0-9])(?!\W+[0-3][0-9]).+?(?:s?(?<season>(?<!\d+)(?:\d{1,2})(?!\d+)))(?:[ex](?<episode>(?<!\d+)(?:\d{1,3})(?!\d+)))",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
// Single or multi episode releases with multiple titles, then season and episode numbers after the last title. (Title1 / Title2 / ... / S1E1-2 of 6)
new Regex(@"^((?<title>.*?)[ ._]\/[ ._])+\(?S(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:\W|_)?E?[ ._]?(?<episode>(?<!\d+)\d{1,2}(?!\d+))(?:-(?<episode>(?<!\d+)\d{1,2}(?!\d+)))?([ ._]of[ ._]\d+)?\)?[ ._][\(\[]",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
// Multi-episode with title (S01E05-06, S01E05-6)
new Regex(@"^(?<title>.+?)(?:[-_\W](?<![()\[!]))+S(?<season>(?<!\d+)(?:\d{1,2})(?!\d+))E(?<episode>\d{1,2}(?!\d+))(?:-(?<episode>\d{1,2}(?!\d+)))+(?:[-_. ]|$)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
@@ -966,6 +974,11 @@ namespace NzbDrone.Core.Parser
{
result.Special = true;
}
if (matchGroup.Groups["splitepisode"].Success)
{
result.IsSplitEpisode = true;
}
}
if (absoluteEpisodeCaptures.Any())

View File

@@ -105,11 +105,12 @@ namespace NzbDrone.Core.Update
return false;
}
var tempFolder = _appFolderInfo.TempFolder;
var updateSandboxFolder = _appFolderInfo.GetUpdateSandboxFolder();
if (_diskProvider.GetTotalSize(updateSandboxFolder) < 1.Gigabytes())
if (_diskProvider.GetTotalSize(tempFolder) < 1.Gigabytes())
{
_logger.Warn("Temporary location '{0}' has less than 1 GB free space, Sonarr may not be able to update itself.", updateSandboxFolder);
_logger.Warn("Temporary location '{0}' has less than 1 GB free space, Sonarr may not be able to update itself.", tempFolder);
}
var packageDestination = Path.Combine(updateSandboxFolder, updatePackage.FileName);

View File

@@ -49,12 +49,6 @@ namespace Sonarr.Api.V3.Config
var nameSpec = _namingConfigService.GetConfig();
var resource = nameSpec.ToResource();
if (resource.StandardEpisodeFormat.IsNotNullOrWhiteSpace())
{
var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
basicConfig.AddToResource(resource);
}
return resource;
}

View File

@@ -14,11 +14,5 @@ namespace Sonarr.Api.V3.Config
public string SeriesFolderFormat { get; set; }
public string SeasonFolderFormat { get; set; }
public string SpecialsFolderFormat { get; set; }
public bool IncludeSeriesTitle { get; set; }
public bool IncludeEpisodeTitle { get; set; }
public bool IncludeQuality { get; set; }
public bool ReplaceSpaces { get; set; }
public string Separator { get; set; }
public string NumberStyle { get; set; }
}
}

View File

@@ -32,26 +32,9 @@ namespace Sonarr.Api.V3.Config
SeriesFolderFormat = model.SeriesFolderFormat,
SeasonFolderFormat = model.SeasonFolderFormat,
SpecialsFolderFormat = model.SpecialsFolderFormat
// IncludeSeriesTitle
// IncludeEpisodeTitle
// IncludeQuality
// ReplaceSpaces
// Separator
// NumberStyle
};
}
public static void AddToResource(this BasicNamingConfig basicNamingConfig, NamingConfigResource resource)
{
resource.IncludeSeriesTitle = basicNamingConfig.IncludeSeriesTitle;
resource.IncludeEpisodeTitle = basicNamingConfig.IncludeEpisodeTitle;
resource.IncludeQuality = basicNamingConfig.IncludeQuality;
resource.ReplaceSpaces = basicNamingConfig.ReplaceSpaces;
resource.Separator = basicNamingConfig.Separator;
resource.NumberStyle = basicNamingConfig.NumberStyle;
}
public static NamingConfig ToModel(this NamingConfigResource resource)
{
return new NamingConfig

View File

@@ -4737,48 +4737,6 @@
"type": "string"
}
},
{
"name": "includeSeriesTitle",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "includeEpisodeTitle",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "includeQuality",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "replaceSpaces",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "separator",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "numberStyle",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "id",
"in": "query",
@@ -9825,26 +9783,6 @@
"specialsFolderFormat": {
"type": "string",
"nullable": true
},
"includeSeriesTitle": {
"type": "boolean"
},
"includeEpisodeTitle": {
"type": "boolean"
},
"includeQuality": {
"type": "boolean"
},
"replaceSpaces": {
"type": "boolean"
},
"separator": {
"type": "string",
"nullable": true
},
"numberStyle": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
@@ -12082,4 +12020,4 @@
"apikey": [ ]
}
]
}
}

View File

@@ -4,6 +4,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration;
@@ -46,7 +47,17 @@ namespace Sonarr.Http.Authentication
await HttpContext.SignInAsync(AuthenticationType.Forms.ToString(), new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "identifier")), authProperties);
return Redirect(_configFileProvider.UrlBase + "/");
if (returnUrl.IsNullOrWhiteSpace())
{
return Redirect(_configFileProvider.UrlBase + "/");
}
if (_configFileProvider.UrlBase.IsNullOrWhiteSpace() || returnUrl.StartsWith(_configFileProvider.UrlBase))
{
return Redirect(returnUrl);
}
return Redirect(_configFileProvider.UrlBase + returnUrl);
}
[HttpGet("logout")]