diff --git a/frontend/build/webpack.config.js b/frontend/build/webpack.config.js
index 733e2bc4d..e0ec27c27 100644
--- a/frontend/build/webpack.config.js
+++ b/frontend/build/webpack.config.js
@@ -91,7 +91,8 @@ module.exports = (env) => {
}),
new MiniCssExtractPlugin({
- filename: 'Content/styles.css'
+ filename: 'Content/styles.css',
+ chunkFilename: 'Content/[id]-[chunkhash].css'
}),
new HtmlWebpackPlugin({
diff --git a/frontend/src/Activity/Queue/QueueRow.js b/frontend/src/Activity/Queue/QueueRow.js
index 708f960bb..0f66fbfa4 100644
--- a/frontend/src/Activity/Queue/QueueRow.js
+++ b/frontend/src/Activity/Queue/QueueRow.js
@@ -45,14 +45,14 @@ class QueueRow extends Component {
this.setState({ isRemoveQueueItemModalOpen: true });
};
- onRemoveQueueItemModalConfirmed = (blocklist) => {
+ onRemoveQueueItemModalConfirmed = (blocklist, skipRedownload) => {
const {
onRemoveQueueItemPress,
onQueueRowModalOpenOrClose
} = this.props;
onQueueRowModalOpenOrClose(false);
- onRemoveQueueItemPress(blocklist);
+ onRemoveQueueItemPress(blocklist, skipRedownload);
this.setState({ isRemoveQueueItemModalOpen: false });
};
diff --git a/frontend/src/Activity/Queue/RemoveQueueItemModal.js b/frontend/src/Activity/Queue/RemoveQueueItemModal.js
index f1a152734..8260d4362 100644
--- a/frontend/src/Activity/Queue/RemoveQueueItemModal.js
+++ b/frontend/src/Activity/Queue/RemoveQueueItemModal.js
@@ -10,6 +10,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
+import translate from 'Utilities/String/translate';
class RemoveQueueItemModal extends Component {
@@ -21,7 +22,8 @@ class RemoveQueueItemModal extends Component {
this.state = {
remove: true,
- blocklist: false
+ blocklist: false,
+ skipRedownload: false
};
}
@@ -31,7 +33,8 @@ class RemoveQueueItemModal extends Component {
resetState = function() {
this.setState({
remove: true,
- blocklist: false
+ blocklist: false,
+ skipRedownload: false
});
};
@@ -46,6 +49,10 @@ class RemoveQueueItemModal extends Component {
this.setState({ blocklist: value });
};
+ onSkipRedownloadChange = ({ value }) => {
+ this.setState({ skipRedownload: value });
+ };
+
onRemoveConfirmed = () => {
const state = this.state;
@@ -69,7 +76,7 @@ class RemoveQueueItemModal extends Component {
isPending
} = this.props;
- const { remove, blocklist } = this.state;
+ const { remove, blocklist, skipRedownload } = this.state;
return (
+ {
+ blocklist ?
+
+ {translate('SkipRedownload')}
+
+ :
+ null
+ }
diff --git a/frontend/src/Activity/Queue/RemoveQueueItemsModal.js b/frontend/src/Activity/Queue/RemoveQueueItemsModal.js
index 738559ed5..9ee6fef87 100644
--- a/frontend/src/Activity/Queue/RemoveQueueItemsModal.js
+++ b/frontend/src/Activity/Queue/RemoveQueueItemsModal.js
@@ -23,7 +23,8 @@ class RemoveQueueItemsModal extends Component {
this.state = {
remove: true,
- blocklist: false
+ blocklist: false,
+ skipRedownload: false
};
}
@@ -33,7 +34,8 @@ class RemoveQueueItemsModal extends Component {
resetState = function() {
this.setState({
remove: true,
- blocklist: false
+ blocklist: false,
+ skipRedownload: false
});
};
@@ -48,6 +50,10 @@ class RemoveQueueItemsModal extends Component {
this.setState({ blocklist: value });
};
+ onSkipRedownloadChange = ({ value }) => {
+ this.setState({ skipRedownload: value });
+ };
+
onRemoveConfirmed = () => {
const state = this.state;
@@ -71,7 +77,7 @@ class RemoveQueueItemsModal extends Component {
allPending
} = this.props;
- const { remove, blocklist } = this.state;
+ const { remove, blocklist, skipRedownload } = this.state;
return (
+ {
+ blocklist ?
+
+ {translate('SkipRedownload')}
+
+ :
+ null
+ }
diff --git a/frontend/src/Series/Index/Table/SeriesIndexTable.css b/frontend/src/Series/Index/Table/SeriesIndexTable.css
index 455f0bc7c..0bfc5fec4 100644
--- a/frontend/src/Series/Index/Table/SeriesIndexTable.css
+++ b/frontend/src/Series/Index/Table/SeriesIndexTable.css
@@ -1,3 +1,11 @@
.tableScroller {
position: relative;
}
+
+.row {
+ transition: background-color 500ms;
+
+ &:hover {
+ background-color: var(--tableRowHoverBackgroundColor);
+ }
+}
diff --git a/frontend/src/Series/Index/Table/SeriesIndexTable.css.d.ts b/frontend/src/Series/Index/Table/SeriesIndexTable.css.d.ts
index 712cb8f72..ff35c263f 100644
--- a/frontend/src/Series/Index/Table/SeriesIndexTable.css.d.ts
+++ b/frontend/src/Series/Index/Table/SeriesIndexTable.css.d.ts
@@ -1,6 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
+ 'row': string;
'tableScroller': string;
}
export const cssExports: CssExports;
diff --git a/frontend/src/Series/Index/Table/SeriesIndexTable.tsx b/frontend/src/Series/Index/Table/SeriesIndexTable.tsx
index c0d5e169c..c1401f984 100644
--- a/frontend/src/Series/Index/Table/SeriesIndexTable.tsx
+++ b/frontend/src/Series/Index/Table/SeriesIndexTable.tsx
@@ -65,6 +65,7 @@ const Row: React.FC> = ({
justifyContent: 'space-between',
...style,
}}
+ className={styles.row}
>
- #sonarr on Libera
+
+ {translate('IRCLinkText')}
+
- Libera webchat
+
+ {translate('LiberaWebchat')}
+
diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleFixture.cs
index 3c7a17c8a..674522748 100644
--- a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleFixture.cs
+++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleFixture.cs
@@ -70,6 +70,8 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
[TestCase("[a] title", "a title")]
[TestCase("backslash \\ backlash", "backslash backlash")]
[TestCase("I'm the Boss", "Im the Boss")]
+ [TestCase("The Title's", "The Title's")]
+ [TestCase("I'm after I'm", "Im after I'm")]
// [TestCase("", "")]
public void should_get_expected_title_back(string title, string expected)
diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleWithoutYearFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleWithoutYearFixture.cs
index 1cf761402..8e3a3f0b7 100644
--- a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleWithoutYearFixture.cs
+++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleWithoutYearFixture.cs
@@ -54,6 +54,8 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
[TestCase("The Mist", 2018, "The Mist")]
[TestCase("The Rat Pack (A&E)", 1999, "The Rat Pack AandE")]
[TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "The Climax I Almost Got Away With It")]
+ [TestCase("The Series Title's (2016)", 2016, "The Series Titles")]
+ [TestCase("The Series Title's", 2016, "The Series Title's")]
public void should_get_expected_title_back(string title, int year, string expected)
{
_series.Title = title;
diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleYearFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleYearFixture.cs
index 8ed607983..92fce8e8d 100644
--- a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleYearFixture.cs
+++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/CleanTitleYearFixture.cs
@@ -54,6 +54,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
[TestCase("The Mist", 2018, "The Mist 2018")]
[TestCase("The Rat Pack (A&E)", 1999, "The Rat Pack AandE 1999")]
[TestCase("The Climax: I (Almost) Got Away With It (2016)", 2016, "The Climax I Almost Got Away With It 2016")]
+ [TestCase("The Series Title's", 2016, "The Series Titles 2016")]
public void should_get_expected_title_back(string title, int year, string expected)
{
_series.Title = title;
diff --git a/src/NzbDrone.Core/Download/DownloadFailedEvent.cs b/src/NzbDrone.Core/Download/DownloadFailedEvent.cs
index 143eba14e..757e5da97 100644
--- a/src/NzbDrone.Core/Download/DownloadFailedEvent.cs
+++ b/src/NzbDrone.Core/Download/DownloadFailedEvent.cs
@@ -23,5 +23,6 @@ namespace NzbDrone.Core.Download
public Dictionary Data { get; set; }
public TrackedDownload TrackedDownload { get; set; }
public List Languages { get; set; }
+ public bool SkipRedownload { get; set; }
}
}
diff --git a/src/NzbDrone.Core/Download/FailedDownloadService.cs b/src/NzbDrone.Core/Download/FailedDownloadService.cs
index f26741ca8..8e07b23fd 100644
--- a/src/NzbDrone.Core/Download/FailedDownloadService.cs
+++ b/src/NzbDrone.Core/Download/FailedDownloadService.cs
@@ -9,8 +9,8 @@ namespace NzbDrone.Core.Download
{
public interface IFailedDownloadService
{
- void MarkAsFailed(int historyId);
- void MarkAsFailed(string downloadId);
+ void MarkAsFailed(int historyId, bool skipRedownload = false);
+ void MarkAsFailed(string downloadId, bool skipRedownload = false);
void Check(TrackedDownload trackedDownload);
void ProcessFailed(TrackedDownload trackedDownload);
}
@@ -30,14 +30,14 @@ namespace NzbDrone.Core.Download
_eventAggregator = eventAggregator;
}
- public void MarkAsFailed(int historyId)
+ public void MarkAsFailed(int historyId, bool skipRedownload = false)
{
var history = _historyService.Get(historyId);
var downloadId = history.DownloadId;
if (downloadId.IsNullOrWhiteSpace())
{
- PublishDownloadFailedEvent(new List { history }, "Manually marked as failed");
+ PublishDownloadFailedEvent(new List { history }, "Manually marked as failed", skipRedownload: skipRedownload);
return;
}
@@ -57,7 +57,7 @@ namespace NzbDrone.Core.Download
PublishDownloadFailedEvent(grabbedHistory, "Manually marked as failed");
}
- public void MarkAsFailed(string downloadId)
+ public void MarkAsFailed(string downloadId, bool skipRedownload = false)
{
var history = _historyService.Find(downloadId, EpisodeHistoryEventType.Grabbed);
@@ -65,7 +65,7 @@ namespace NzbDrone.Core.Download
{
var trackedDownload = _trackedDownloadService.Find(downloadId);
- PublishDownloadFailedEvent(history, "Manually marked as failed", trackedDownload);
+ PublishDownloadFailedEvent(history, "Manually marked as failed", trackedDownload, skipRedownload: skipRedownload);
}
}
@@ -125,7 +125,7 @@ namespace NzbDrone.Core.Download
PublishDownloadFailedEvent(grabbedItems, failure, trackedDownload);
}
- private void PublishDownloadFailedEvent(List historyItems, string message, TrackedDownload trackedDownload = null)
+ private void PublishDownloadFailedEvent(List historyItems, string message, TrackedDownload trackedDownload = null, bool skipRedownload = false)
{
var historyItem = historyItems.First();
@@ -140,7 +140,8 @@ namespace NzbDrone.Core.Download
Message = message,
Data = historyItem.Data,
TrackedDownload = trackedDownload,
- Languages = historyItem.Languages
+ Languages = historyItem.Languages,
+ SkipRedownload = skipRedownload
};
_eventAggregator.PublishEvent(downloadFailedEvent);
diff --git a/src/NzbDrone.Core/Download/RedownloadFailedDownloadService.cs b/src/NzbDrone.Core/Download/RedownloadFailedDownloadService.cs
index ed23f021b..20c19e15d 100644
--- a/src/NzbDrone.Core/Download/RedownloadFailedDownloadService.cs
+++ b/src/NzbDrone.Core/Download/RedownloadFailedDownloadService.cs
@@ -1,4 +1,4 @@
-using System.Linq;
+using System.Linq;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch;
@@ -30,6 +30,12 @@ namespace NzbDrone.Core.Download
[EventHandleOrder(EventHandleOrder.Last)]
public void Handle(DownloadFailedEvent message)
{
+ if (message.SkipRedownload)
+ {
+ _logger.Debug("Skip redownloading requested by user");
+ return;
+ }
+
if (!_configService.AutoRedownloadFailed)
{
_logger.Debug("Auto redownloading failed episodes is disabled");
diff --git a/src/NzbDrone.Core/ImportLists/Simkl/SimklAPI.cs b/src/NzbDrone.Core/ImportLists/Simkl/SimklAPI.cs
index 4472af249..0290dabfb 100644
--- a/src/NzbDrone.Core/ImportLists/Simkl/SimklAPI.cs
+++ b/src/NzbDrone.Core/ImportLists/Simkl/SimklAPI.cs
@@ -11,6 +11,7 @@ namespace NzbDrone.Core.ImportLists.Simkl
public string Imdb { get; set; }
public string Tmdb { get; set; }
public string Tvdb { get; set; }
+ public string Mal { get; set; }
}
public class SimklSeriesPropsResource
@@ -23,11 +24,15 @@ namespace NzbDrone.Core.ImportLists.Simkl
public class SimklSeriesResource
{
public SimklSeriesPropsResource Show { get; set; }
+
+ [JsonProperty("anime_type")]
+ public SimklAnimeType AnimeType { get; set; }
}
public class SimklResponse
{
public List Shows { get; set; }
+ public List Anime { get; set; }
}
public class RefreshRequestResponse
@@ -66,4 +71,10 @@ namespace NzbDrone.Core.ImportLists.Simkl
{
public DateTime All { get; set; }
}
+
+ public enum SimklAnimeType
+ {
+ Tv,
+ Movie
+ }
}
diff --git a/src/NzbDrone.Core/ImportLists/Simkl/SimklParser.cs b/src/NzbDrone.Core/ImportLists/Simkl/SimklParser.cs
index 6f5758369..1419c6be7 100644
--- a/src/NzbDrone.Core/ImportLists/Simkl/SimklParser.cs
+++ b/src/NzbDrone.Core/ImportLists/Simkl/SimklParser.cs
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Net;
+using NLog;
using NzbDrone.Common.Extensions;
+using NzbDrone.Common.Instrumentation;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.ImportLists.Exceptions;
using NzbDrone.Core.Parser.Model;
@@ -10,6 +12,11 @@ namespace NzbDrone.Core.ImportLists.Simkl
public class SimklParser : IParseImportListResponse
{
private ImportListResponse _importResponse;
+ private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(SimklParser));
+
+ public SimklParser()
+ {
+ }
public virtual IList ParseResponse(ImportListResponse importResponse)
{
@@ -22,7 +29,7 @@ namespace NzbDrone.Core.ImportLists.Simkl
return series;
}
- var jsonResponse = STJson.Deserialize(_importResponse.Content);
+ var jsonResponse = Json.Deserialize(_importResponse.Content);
// no shows were return
if (jsonResponse == null)
@@ -30,14 +37,40 @@ namespace NzbDrone.Core.ImportLists.Simkl
return series;
}
- foreach (var show in jsonResponse.Shows)
+ if (jsonResponse.Anime != null)
{
- series.AddIfNotNull(new ImportListItemInfo()
+ foreach (var show in jsonResponse.Anime)
{
- Title = show.Show.Title,
- TvdbId = int.TryParse(show.Show.Ids.Tvdb, out var tvdbId) ? tvdbId : 0,
- ImdbId = show.Show.Ids.Imdb
- });
+ var tentativeTvdbId = int.TryParse(show.Show.Ids.Tvdb, out var tvdbId) ? tvdbId : 0;
+
+ if (tentativeTvdbId > 0 && show.AnimeType == SimklAnimeType.Tv)
+ {
+ series.AddIfNotNull(new ImportListItemInfo()
+ {
+ Title = show.Show.Title,
+ ImdbId = show.Show.Ids.Imdb,
+ TvdbId = tvdbId,
+ MalId = int.TryParse(show.Show.Ids.Mal, out var malId) ? malId : 0
+ });
+ }
+ else
+ {
+ Logger.Warn("Skipping info grabbing for '{0}' because it is a movie or it is not the first season of the show", show.Show.Title);
+ }
+ }
+ }
+
+ if (jsonResponse.Shows != null)
+ {
+ foreach (var show in jsonResponse.Shows)
+ {
+ series.AddIfNotNull(new ImportListItemInfo()
+ {
+ Title = show.Show.Title,
+ TvdbId = int.TryParse(show.Show.Ids.Tvdb, out var tvdbId) ? tvdbId : 0,
+ ImdbId = show.Show.Ids.Imdb
+ });
+ }
}
return series;
diff --git a/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserRequestGenerator.cs b/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserRequestGenerator.cs
index 90bdccf1a..74ea05831 100644
--- a/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserRequestGenerator.cs
+++ b/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserRequestGenerator.cs
@@ -21,7 +21,7 @@ namespace NzbDrone.Core.ImportLists.Simkl.User
private IEnumerable GetSeriesRequest()
{
- var link = $"{Settings.BaseUrl.Trim()}/sync/all-items/shows/{((SimklUserListType)Settings.ListType).ToString().ToLowerInvariant()}";
+ var link = $"{Settings.BaseUrl.Trim()}/sync/all-items/{((SimklUserShowType)Settings.ShowType).ToString().ToLowerInvariant()}/{((SimklUserListType)Settings.ListType).ToString().ToLowerInvariant()}";
var request = new ImportListRequest(link, HttpAccept.Json);
diff --git a/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserSettings.cs b/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserSettings.cs
index 61cc48129..65f19aa3f 100644
--- a/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserSettings.cs
+++ b/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserSettings.cs
@@ -19,9 +19,13 @@ namespace NzbDrone.Core.ImportLists.Simkl.User
public SimklUserSettings()
{
ListType = (int)SimklUserListType.Watching;
+ ShowType = (int)SimklUserShowType.Shows;
}
[FieldDefinition(1, Label = "List Type", Type = FieldType.Select, SelectOptions = typeof(SimklUserListType), HelpText = "Type of list you're seeking to import from")]
public int ListType { get; set; }
+
+ [FieldDefinition(1, Label = "Show Type", Type = FieldType.Select, SelectOptions = typeof(SimklUserShowType), HelpText = "Type of show you're seeking to import from")]
+ public int ShowType { get; set; }
}
}
diff --git a/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserShowType.cs b/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserShowType.cs
new file mode 100644
index 000000000..8ff2eb16d
--- /dev/null
+++ b/src/NzbDrone.Core/ImportLists/Simkl/User/SimklUserShowType.cs
@@ -0,0 +1,8 @@
+namespace NzbDrone.Core.ImportLists.Simkl.User
+{
+ public enum SimklUserShowType
+ {
+ Shows = 0,
+ Anime = 1
+ }
+}
diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json
index 31d7cfe44..5a01aea69 100644
--- a/src/NzbDrone.Core/Localization/Core/en.json
+++ b/src/NzbDrone.Core/Localization/Core/en.json
@@ -139,12 +139,14 @@
"InstallLatest": "Install Latest",
"Interval": "Interval",
"IRC": "IRC",
+ "IRCLinkText": "#sonarr on Libera",
"Language": "Language",
"Language that Sonarr will use for UI": "Language that Sonarr will use for UI",
"Languages": "Languages",
"LastDuration": "Last Duration",
"LastExecution": "Last Execution",
"LastWriteTime": "Last Write Time",
+ "LiberaWebchat": "Libera Webchat",
"LibraryImport": "Library Import",
"Location": "Location",
"LogFiles": "Log Files",
@@ -189,7 +191,7 @@
"NoSeasons": "No seasons",
"NoUpdatesAreAvailable": "No updates are available",
"OneSeason": "1 season",
- "OnLatestVersion": "The latest version of Radarr is already installed",
+ "OnLatestVersion": "The latest version of Sonarr is already installed",
"Options": "Options",
"OriginalLanguage": "Original Language",
"PackageVersion": "Package Version",
@@ -276,6 +278,8 @@
"ShownClickToHide": "Shown, click to hide",
"Size": "Size",
"SizeOnDisk": "Size on disk",
+ "SkipRedownloadHelpText": "Prevents Sonarr from trying to download an alternative release for this item",
+ "SkipRedownload": "Skip Redownload",
"Source": "Source",
"Special": "Special",
"Started": "Started",
diff --git a/src/NzbDrone.Core/Localization/Core/pt_BR.json b/src/NzbDrone.Core/Localization/Core/pt_BR.json
index 881648a48..fa9e847d3 100644
--- a/src/NzbDrone.Core/Localization/Core/pt_BR.json
+++ b/src/NzbDrone.Core/Localization/Core/pt_BR.json
@@ -214,5 +214,100 @@
"SeasonNumber": "Número da Temporada",
"SeriesTitle": "Título da Série",
"Special": "Especial",
- "TestParsing": "Análise de Teste"
+ "TestParsing": "Análise de Teste",
+ "About": "Sobre",
+ "Actions": "Ações",
+ "AppDataDirectory": "Diretório AppData",
+ "AptUpdater": "Usar apt para instalar atualizações",
+ "BackupNow": "Fazer Backup Agora",
+ "Backups": "Backups",
+ "BeforeUpdate": "Antes de atualizar",
+ "CancelPendingTask": "Tem certeza de que deseja cancelar esta tarefa pendente?",
+ "Clear": "Limpar",
+ "CurrentlyInstalled": "Atualmente instalado",
+ "DeleteBackup": "Excluir Backup",
+ "DeleteBackupMessageText": "Tem certeza de que deseja excluir o backup '{name}'?",
+ "Discord": "Discord",
+ "DiskSpace": "Espaço em Disco",
+ "Docker": "Docker",
+ "DockerUpdater": "Atualize o contêiner docker para receber a atualização",
+ "Donations": "Doações",
+ "DotNetVersion": ".NET",
+ "Download": "Baixar",
+ "Duration": "Duração",
+ "ErrorRestoringBackup": "Erro ao restaurar o backup",
+ "Exception": "Exceção",
+ "ExternalUpdater": "O Sonarr está configurado para usar um mecanismo de atualização externo",
+ "FailedToFetchUpdates": "Falha ao buscar atualizações",
+ "FailedToUpdateSettings": "Falha ao atualizar as configurações",
+ "FeatureRequests": "Solicitações de recursos",
+ "Filename": "Nome do arquivo",
+ "Fixed": "Corrigido",
+ "Forums": "Fóruns",
+ "FreeSpace": "Espaço Livre",
+ "From": "De",
+ "GeneralSettings": "Configurações Gerais",
+ "Health": "Saúde",
+ "HomePage": "Página Inicial",
+ "OnLatestVersion": "A versão mais recente do Sonarr já está instalada",
+ "InstallLatest": "Instalar o mais recente",
+ "Interval": "Intervalo",
+ "IRC": "IRC",
+ "LastDuration": "Última Duração",
+ "LastExecution": "Última Execução",
+ "LastWriteTime": "Hora da Última Gravação",
+ "Location": "Localização",
+ "LogFilesLocation": "Os arquivos de log estão localizados em: {location}",
+ "Logs": "Logs",
+ "MaintenanceRelease": "Versão de manutenção: correções de bugs e outras melhorias. Veja Github Commit History para mais detalhes",
+ "Manual": "Manual",
+ "Message": "Mensagem",
+ "Mode": "Modo",
+ "MoreInfo": "Mais informações",
+ "New": "Novo",
+ "NextExecution": "Próxima Execução",
+ "NoBackupsAreAvailable": "Não há backups disponíveis",
+ "NoEventsFound": "Nenhum evento encontrado",
+ "NoIssuesWithYourConfiguration": "Sem problemas com sua configuração",
+ "NoLeaveIt": "Não, deixe-o",
+ "NoLogFiles": "Nenhum arquivo de log",
+ "NoUpdatesAreAvailable": "Nenhuma atualização está disponível",
+ "Options": "Opções",
+ "PackageVersion": "Versão do pacote",
+ "PackageVersionInfo": "{packageVersion} por {packageAuthor}",
+ "PreviouslyInstalled": "Instalado anteriormente",
+ "Queued": "Enfileirados",
+ "ReadTheWikiForMoreInformation": "Leia o Wiki para mais informações",
+ "Refresh": "Atualizar",
+ "Reload": "Recarregar",
+ "RemovedFromTaskQueue": "Removido da fila de tarefas",
+ "Restart": "Reiniciar",
+ "TaskUserAgentTooltip": "User-Agent fornecido pelo aplicativo que chamou a API",
+ "ResetQualityDefinitions": "Redefinir Definições de Qualidade",
+ "ResetQualityDefinitionsMessageText": "Tem certeza de que deseja redefinir as definições de qualidade?",
+ "ResetTitles": "Redefinir Títulos",
+ "Restore": "Restaurar",
+ "RestoreBackup": "Restaurar backup",
+ "Scheduled": "Agendado",
+ "SeriesEditor": "Editor de séries",
+ "Size": "Tamanho",
+ "Source": "Fonte",
+ "Started": "Iniciado",
+ "StartupDirectory": "Diretório de inicialização",
+ "Status": "Estado",
+ "TestAll": "Testar Tudo",
+ "TheLogLevelDefault": "O padrão do nível de log é 'Info' e pode ser alterado em [Configurações gerais](/configurações /geral)",
+ "Time": "Horário",
+ "TotalSpace": "Espaço Total",
+ "Twitter": "Twitter",
+ "UnableToLoadBackups": "Não foi possível carregar os backups",
+ "UnableToUpdateSonarrDirectly": "Incapaz de atualizar o Sonarr diretamente,",
+ "UpdaterLogFiles": "Arquivos de log do atualizador",
+ "Uptime": "Tempo de atividade",
+ "Wiki": "Wiki",
+ "WouldYouLikeToRestoreBackup": "Gostaria de restaurar o backup '{name}'?",
+ "YesCancel": "Sim, Cancelar",
+ "Reset": "Redefinir",
+ "ResetDefinitionTitlesHelpText": "Redefinir títulos de definição, bem como valores",
+ "RestartReloadNote": "Observação: o Sonarr reiniciará automaticamente e recarregará a IU durante o processo de restauração."
}
diff --git a/src/NzbDrone.Core/Organizer/FileNameSampleService.cs b/src/NzbDrone.Core/Organizer/FileNameSampleService.cs
index 6e66633d3..a8d89364a 100644
--- a/src/NzbDrone.Core/Organizer/FileNameSampleService.cs
+++ b/src/NzbDrone.Core/Organizer/FileNameSampleService.cs
@@ -44,7 +44,7 @@ namespace NzbDrone.Core.Organizer
_standardSeries = new Series
{
SeriesType = SeriesTypes.Standard,
- Title = "The Series Title!",
+ Title = "The Series Title's!",
Year = 2010,
ImdbId = "tt12345",
TvdbId = 12345,
@@ -54,7 +54,7 @@ namespace NzbDrone.Core.Organizer
_dailySeries = new Series
{
SeriesType = SeriesTypes.Daily,
- Title = "The Series Title!",
+ Title = "The Series Title's!",
Year = 2010,
ImdbId = "tt12345",
TvdbId = 12345,
@@ -64,7 +64,7 @@ namespace NzbDrone.Core.Organizer
_animeSeries = new Series
{
SeriesType = SeriesTypes.Anime,
- Title = "The Series Title!",
+ Title = "The Series Title's!",
Year = 2010,
ImdbId = "tt12345",
TvdbId = 12345,
@@ -141,45 +141,45 @@ namespace NzbDrone.Core.Organizer
_singleEpisodeFile = new EpisodeFile
{
- Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
- RelativePath = "Series.Title.S01E01.720p.HDTV.x264-EVOLVE.mkv",
- SceneName = "Series.Title.S01E01.720p.HDTV.x264-EVOLVE",
+ Quality = new QualityModel(Quality.WEBDL1080p, new Revision(2)),
+ RelativePath = "The.Series.Title's!.S01E01.1080p.WEBDL.x264-EVOLVE.mkv",
+ SceneName = "The.Series.Title's!.S01E01.1080p.WEBDL.x264-EVOLVE",
ReleaseGroup = "RlsGrp",
MediaInfo = mediaInfo
};
_multiEpisodeFile = new EpisodeFile
{
- Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
- RelativePath = "Series.Title.S01E01-E03.720p.HDTV.x264-EVOLVE.mkv",
- SceneName = "Series.Title.S01E01-E03.720p.HDTV.x264-EVOLVE",
+ Quality = new QualityModel(Quality.WEBDL1080p, new Revision(2)),
+ RelativePath = "The.Series.Title's!.S01E01-E03.1080p.WEBDL.x264-EVOLVE.mkv",
+ SceneName = "The.Series.Title's!.S01E01-E03.1080p.WEBDL.x264-EVOLVE",
ReleaseGroup = "RlsGrp",
MediaInfo = mediaInfo,
};
_dailyEpisodeFile = new EpisodeFile
{
- Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
- RelativePath = "Series.Title.2013.10.30.HDTV.x264-EVOLVE.mkv",
- SceneName = "Series.Title.2013.10.30.HDTV.x264-EVOLVE",
+ Quality = new QualityModel(Quality.WEBDL1080p, new Revision(2)),
+ RelativePath = "The.Series.Title's!.2013.10.30.1080p.WEBDL.x264-EVOLVE.mkv",
+ SceneName = "The.Series.Title's!.2013.10.30.1080p.WEBDL.x264-EVOLVE",
ReleaseGroup = "RlsGrp",
MediaInfo = mediaInfo
};
_animeEpisodeFile = new EpisodeFile
{
- Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
- RelativePath = "[RlsGroup] Series Title - 001 [720p].mkv",
- SceneName = "[RlsGroup] Series Title - 001 [720p]",
+ Quality = new QualityModel(Quality.WEBDL1080p, new Revision(2)),
+ RelativePath = "[RlsGroup] The Series Title's! - 001 [1080P].mkv",
+ SceneName = "[RlsGroup] The Series Title's! - 001 [1080P]",
ReleaseGroup = "RlsGrp",
MediaInfo = mediaInfoAnime
};
_animeMultiEpisodeFile = new EpisodeFile
{
- Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
- RelativePath = "[RlsGroup] Series Title - 001 - 103 [720p].mkv",
- SceneName = "[RlsGroup] Series Title - 001 - 103 [720p]",
+ Quality = new QualityModel(Quality.WEBDL1080p, new Revision(2)),
+ RelativePath = "[RlsGroup] The Series Title's! - 001 - 103 [1080p].mkv",
+ SceneName = "[RlsGroup] The Series Title's! - 001 - 103 [1080p]",
ReleaseGroup = "RlsGrp",
MediaInfo = mediaInfoAnime
};
diff --git a/src/NzbDrone.Core/Parser/Model/ImportListItemInfo.cs b/src/NzbDrone.Core/Parser/Model/ImportListItemInfo.cs
index df76ac2c2..182c2fca9 100644
--- a/src/NzbDrone.Core/Parser/Model/ImportListItemInfo.cs
+++ b/src/NzbDrone.Core/Parser/Model/ImportListItemInfo.cs
@@ -11,6 +11,7 @@ namespace NzbDrone.Core.Parser.Model
public int TvdbId { get; set; }
public int TmdbId { get; set; }
public string ImdbId { get; set; }
+ public int MalId { get; set; }
public DateTime ReleaseDate { get; set; }
public override string ToString()
diff --git a/src/Sonarr.Api.V3/Queue/QueueController.cs b/src/Sonarr.Api.V3/Queue/QueueController.cs
index 605bc9db9..6259956c3 100644
--- a/src/Sonarr.Api.V3/Queue/QueueController.cs
+++ b/src/Sonarr.Api.V3/Queue/QueueController.cs
@@ -70,7 +70,7 @@ namespace Sonarr.Api.V3.Queue
}
[RestDeleteById]
- public void RemoveAction(int id, bool removeFromClient = true, bool blocklist = false)
+ public void RemoveAction(int id, bool removeFromClient = true, bool blocklist = false, bool skipRedownload = false)
{
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
@@ -88,12 +88,12 @@ namespace Sonarr.Api.V3.Queue
throw new NotFoundException();
}
- Remove(trackedDownload, removeFromClient, blocklist);
+ Remove(trackedDownload, removeFromClient, blocklist, skipRedownload);
_trackedDownloadService.StopTracking(trackedDownload.DownloadItem.DownloadId);
}
[HttpDelete("bulk")]
- public object RemoveMany([FromBody] QueueBulkResource resource, [FromQuery] bool removeFromClient = true, [FromQuery] bool blocklist = false)
+ public object RemoveMany([FromBody] QueueBulkResource resource, [FromQuery] bool removeFromClient = true, [FromQuery] bool blocklist = false, [FromQuery] bool skipRedownload = false)
{
var trackedDownloadIds = new List();
var pendingToRemove = new List();
@@ -124,7 +124,7 @@ namespace Sonarr.Api.V3.Queue
foreach (var trackedDownload in trackedToRemove.DistinctBy(t => t.DownloadItem.DownloadId))
{
- Remove(trackedDownload, removeFromClient, blocklist);
+ Remove(trackedDownload, removeFromClient, blocklist, skipRedownload);
trackedDownloadIds.Add(trackedDownload.DownloadItem.DownloadId);
}
@@ -255,7 +255,7 @@ namespace Sonarr.Api.V3.Queue
_pendingReleaseService.RemovePendingQueueItems(pendingRelease.Id);
}
- private TrackedDownload Remove(TrackedDownload trackedDownload, bool removeFromClient, bool blocklist)
+ private TrackedDownload Remove(TrackedDownload trackedDownload, bool removeFromClient, bool blocklist, bool skipRedownload)
{
if (removeFromClient)
{
@@ -271,7 +271,7 @@ namespace Sonarr.Api.V3.Queue
if (blocklist)
{
- _failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId);
+ _failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId, skipRedownload);
}
if (!removeFromClient && !blocklist)
diff --git a/src/Sonarr.Api.V3/openapi.json b/src/Sonarr.Api.V3/openapi.json
index f585f2877..60543a7a3 100644
--- a/src/Sonarr.Api.V3/openapi.json
+++ b/src/Sonarr.Api.V3/openapi.json
@@ -5132,6 +5132,14 @@
"type": "boolean",
"default": false
}
+ },
+ {
+ "name": "skipRedownload",
+ "in": "query",
+ "schema": {
+ "type": "boolean",
+ "default": false
+ }
}
],
"responses": {
@@ -5162,6 +5170,14 @@
"type": "boolean",
"default": false
}
+ },
+ {
+ "name": "skipRedownload",
+ "in": "query",
+ "schema": {
+ "type": "boolean",
+ "default": false
+ }
}
],
"requestBody": {
diff --git a/src/Sonarr.Http/ClientSchema/SchemaBuilder.cs b/src/Sonarr.Http/ClientSchema/SchemaBuilder.cs
index dcbcb8ed0..4f1bb8383 100644
--- a/src/Sonarr.Http/ClientSchema/SchemaBuilder.cs
+++ b/src/Sonarr.Http/ClientSchema/SchemaBuilder.cs
@@ -123,7 +123,7 @@ namespace Sonarr.Http.ClientSchema
Placeholder = fieldAttribute.Placeholder
};
- if (fieldAttribute.Type == FieldType.Select || fieldAttribute.Type == FieldType.TagSelect)
+ if (fieldAttribute.Type is FieldType.Select or FieldType.TagSelect)
{
if (fieldAttribute.SelectOptionsProviderAction.IsNotNullOrWhiteSpace())
{
@@ -172,31 +172,33 @@ namespace Sonarr.Http.ClientSchema
{
if (selectOptions.IsEnum)
{
- var options = selectOptions.GetFields().Where(v => v.IsStatic).Select(v =>
- {
- var name = v.Name.Replace('_', ' ');
- var value = Convert.ToInt32(v.GetRawConstantValue());
- var attrib = v.GetCustomAttribute();
- if (attrib != null)
+ var options = selectOptions
+ .GetFields()
+ .Where(v => v.IsStatic && !v.GetCustomAttributes(false).OfType().Any())
+ .Select(v =>
{
- return new SelectOption
+ var name = v.Name.Replace('_', ' ');
+ var value = Convert.ToInt32(v.GetRawConstantValue());
+ var attrib = v.GetCustomAttribute();
+
+ if (attrib != null)
{
- Value = value,
- Name = attrib.Label ?? name,
- Order = attrib.Order,
- Hint = attrib.Hint ?? $"({value})"
- };
- }
- else
- {
+ return new SelectOption
+ {
+ Value = value,
+ Name = attrib.Label ?? name,
+ Order = attrib.Order,
+ Hint = attrib.Hint ?? $"({value})"
+ };
+ }
+
return new SelectOption
{
Value = value,
Name = name,
Order = value
};
- }
- });
+ });
return options.OrderBy(o => o.Order).ToList();
}