Compare commits

..

11 Commits

Author SHA1 Message Date
Bogdan
668dc6dfde Fix translation in RemoveQueueItemModal 2023-06-26 02:08:41 +03:00
Bogdan
ee989c9c67 Bump version to 0.2.1 2023-06-25 09:04:44 +03:00
servarr[bot]
acac3bd680 Add more trace logs related info to bug_report.yml [skip ci] 2023-06-22 16:40:17 +03:00
Servarr
3b18f3206d Automated API Docs update [skip ci] 2023-06-21 08:16:49 +03:00
Bogdan
fcf057a019 Remove not implemented endpoints from API docs 2023-06-21 08:00:04 +03:00
Servarr
c7399cdd2b Automated API Docs update [skip ci] 2023-06-21 07:45:48 +03:00
Bogdan
08a3682b89 Limit search input to first character matching when only one character is typed 2023-06-21 07:25:09 +03:00
Bogdan
3da00f75dc Remove not implemented endpoints from API docs
Closes #2613
2023-06-21 07:09:01 +03:00
Bogdan
60abb298b2 Convert to 'using' declaration in Housekeeping Tasks
Closes #2612
2023-06-21 07:03:13 +03:00
Bogdan
c710b117ab Prevent NullRef when deleting missing backups
(cherry picked from commit 0ff0fe2e68f3abf7b8e4d6bf0c1e9dee4eb68227)

Closes #2610
2023-06-21 06:37:09 +03:00
Weblate
816f53b36b Translated using Weblate (Chinese (Traditional) (zh_TW)) [skip ci]
Currently translated at 3.5% (33 of 942 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (942 of 942 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 60.6% (571 of 942 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 97.5% (919 of 942 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: KHng0284 <giakhang021109@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: ted09080037 <ted09080037@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/readarr/zh_TW/
Translation: Servarr/Readarr
2023-06-21 02:28:40 +03:00
37 changed files with 365 additions and 1336 deletions

View File

@@ -76,7 +76,7 @@ body:
- type: checkboxes
attributes:
label: Trace Logs have been provided as applicable. Reports may be closed if the required logs are not provided.
description: Trace logs are generally required for all bug reports
description: Trace logs are generally required for all bug reports and contain `trace`. Info logs are invalid for bug reports and do not contain `debug` nor `trace`
options:
- label: I have followed the steps in the wiki link above and provided the required trace logs that are relevant and show this issue.
- label: I have read and followed the steps in the wiki link above and provided the required trace logs - the logs contain `trace` - that are relevant and show this issue.
required: true

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '0.2.0'
majorVersion: '0.2.1'
minorVersion: $[counter('minorVersion', 1)]
readarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(readarrVersion)'

View File

@@ -124,7 +124,7 @@ class RemoveQueueItemModal extends Component {
type={inputTypes.CHECK}
name="blocklist"
value={blocklist}
helpText={translate('BlocklistHelpText')}
helpText={translate('BlocklistReleaseHelpText')}
onChange={this.onBlocklistChange}
/>
</FormGroup>

View File

@@ -26,6 +26,7 @@ function createCleanAuthorSelector() {
sortName,
titleSlug,
images,
firstCharacter: authorName.charAt(0).toLowerCase(),
tags: tags.reduce((acc, id) => {
const matchingTag = allTags.find((tag) => tag.id === id);
@@ -58,6 +59,7 @@ function createCleanBookSelector() {
sortName: title,
titleSlug,
images,
firstCharacter: title.charAt(0).toLowerCase(),
tags: []
};
});

View File

@@ -15,9 +15,36 @@ const fuseOptions = {
function getSuggestions(items, value) {
const limit = 10;
let suggestions = [];
const fuse = new Fuse(items, fuseOptions);
return fuse.search(value, { limit });
if (value.length === 1) {
for (let i = 0; i < items.length; i++) {
const s = items[i];
if (s.firstCharacter === value.toLowerCase()) {
suggestions.push({
item: items[i],
indices: [
[0, 0]
],
matches: [
{
value: s.title,
key: 'title'
}
],
arrayIndex: 0
});
if (suggestions.length > limit) {
break;
}
}
}
} else {
const fuse = new Fuse(items, fuseOptions);
suggestions = fuse.search(value, { limit });
}
return suggestions;
}
onmessage = function(e) {

View File

@@ -14,34 +14,32 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
using var mapper = _database.OpenConnection();
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" = ANY (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""RelativePath""
LIKE '_:\\%'
OR ""RelativePath""
LIKE '\\%'
OR ""RelativePath""
LIKE '/%'
)");
}
else
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""RelativePath""
LIKE '_:\%'
OR ""RelativePath""
LIKE '\%'
OR ""RelativePath""
LIKE '/%'
)");
}
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" = ANY (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""RelativePath""
LIKE '_:\\%'
OR ""RelativePath""
LIKE '\\%'
OR ""RelativePath""
LIKE '/%'
)");
}
else
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""RelativePath""
LIKE '_:\%'
OR ""RelativePath""
LIKE '\%'
OR ""RelativePath""
LIKE '/%'
)");
}
}
}

View File

@@ -14,13 +14,11 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""NamingConfig""
WHERE ""Id"" NOT IN (
SELECT ""Id"" FROM ""NamingConfig""
LIMIT 1)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""NamingConfig""
WHERE ""Id"" NOT IN (
SELECT ""Id"" FROM ""NamingConfig""
LIMIT 1)");
}
}
}

View File

@@ -14,13 +14,11 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""Users""
WHERE ""Id"" NOT IN (
SELECT ""Id"" FROM ""Users""
LIMIT 1)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""Users""
WHERE ""Id"" NOT IN (
SELECT ""Id"" FROM ""Users""
LIMIT 1)");
}
}
}

View File

@@ -21,24 +21,24 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
mapper.Execute(@"DELETE FROM ""PendingReleases""
WHERE ""Added"" < @TwoWeeksAgo
AND ""Reason"" = ANY (@Reasons)",
new
{
TwoWeeksAgo = DateTime.UtcNow.AddDays(-14),
Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback }
});
WHERE ""Added"" < @TwoWeeksAgo
AND ""Reason"" = ANY (@Reasons)",
new
{
TwoWeeksAgo = DateTime.UtcNow.AddDays(-14),
Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback }
});
}
else
{
mapper.Execute(@"DELETE FROM ""PendingReleases""
WHERE ""Added"" < @TwoWeeksAgo
AND ""REASON"" IN @Reasons",
new
{
TwoWeeksAgo = DateTime.UtcNow.AddDays(-14),
Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback }
});
WHERE ""Added"" < @TwoWeeksAgo
AND ""REASON"" IN @Reasons",
new
{
TwoWeeksAgo = DateTime.UtcNow.AddDays(-14),
Reasons = new[] { (int)PendingReleaseReason.DownloadClientUnavailable, (int)PendingReleaseReason.Fallback }
});
}
}
}

View File

@@ -21,44 +21,38 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
private void DeleteDuplicateAuthorMetadata()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT MIN(""Id"") FROM ""MetadataFiles""
WHERE ""Type"" = 1
GROUP BY ""AuthorId"", ""Consumer""
HAVING COUNT(""AuthorId"") > 1
)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT MIN(""Id"") FROM ""MetadataFiles""
WHERE ""Type"" = 1
GROUP BY ""AuthorId"", ""Consumer""
HAVING COUNT(""AuthorId"") > 1
)");
}
private void DeleteDuplicateBookMetadata()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT MIN(""Id"") FROM ""MetadataFiles""
WHERE ""Type"" IN (2, 4)
GROUP BY ""BookId"", ""Consumer""
HAVING COUNT(""BookId"") > 1
)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT MIN(""Id"") FROM ""MetadataFiles""
WHERE ""Type"" IN (2, 4)
GROUP BY ""BookId"", ""Consumer""
HAVING COUNT(""BookId"") > 1
)");
}
private void DeleteDuplicateBookFileMetadata()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT MIN(""Id"") FROM ""MetadataFiles""
WHERE ""Type"" IN (2, 4)
GROUP BY ""BookFileId"", ""Consumer""
HAVING COUNT(""BookFileId"") > 1
)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT MIN(""Id"") FROM ""MetadataFiles""
WHERE ""Type"" IN (2, 4)
GROUP BY ""BookFileId"", ""Consumer""
HAVING COUNT(""BookFileId"") > 1
)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""AuthorMetadata""
WHERE ""Id"" IN (
SELECT ""AuthorMetadata"".""Id"" FROM ""AuthorMetadata""
LEFT OUTER JOIN ""Books"" ON ""Books"".""AuthorMetadataId"" = ""AuthorMetadata"".""Id""
LEFT OUTER JOIN ""Authors"" ON ""Authors"".""AuthorMetadataId"" = ""AuthorMetadata"".""Id""
WHERE ""Books"".""Id"" IS NULL AND ""Authors"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""AuthorMetadata""
WHERE ""Id"" IN (
SELECT ""AuthorMetadata"".""Id"" FROM ""AuthorMetadata""
LEFT OUTER JOIN ""Books"" ON ""Books"".""AuthorMetadataId"" = ""AuthorMetadata"".""Id""
LEFT OUTER JOIN ""Authors"" ON ""Authors"".""AuthorMetadataId"" = ""AuthorMetadata"".""Id""
WHERE ""Books"".""Id"" IS NULL AND ""Authors"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""Blocklist""
WHERE ""Id"" IN (
SELECT ""Blocklist"".""Id"" FROM ""Blocklist""
LEFT OUTER JOIN ""Authors""
ON ""Blocklist"".""AuthorId"" = ""Authors"".""Id""
WHERE ""Authors"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""Blocklist""
WHERE ""Id"" IN (
SELECT ""Blocklist"".""Id"" FROM ""Blocklist""
LEFT OUTER JOIN ""Authors""
ON ""Blocklist"".""AuthorId"" = ""Authors"".""Id""
WHERE ""Authors"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,17 +14,16 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
// Unlink where track no longer exists
mapper.Execute(@"UPDATE ""BookFiles""
SET ""EditionId"" = 0
WHERE ""Id"" IN (
SELECT ""BookFiles"".""Id"" FROM ""BookFiles""
LEFT OUTER JOIN ""Editions""
ON ""BookFiles"".""EditionId"" = ""Editions"".""Id""
WHERE ""Editions"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
// Unlink where books no longer exists
mapper.Execute(@"UPDATE ""BookFiles""
SET ""EditionId"" = 0
WHERE ""Id"" IN (
SELECT ""BookFiles"".""Id"" FROM ""BookFiles""
LEFT OUTER JOIN ""Editions""
ON ""BookFiles"".""EditionId"" = ""Editions"".""Id""
WHERE ""Editions"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""Books""
WHERE ""Id"" IN (
SELECT ""Books"".""Id"" FROM ""Books""
LEFT OUTER JOIN ""Authors""
ON ""Books"".""AuthorMetadataId"" = ""Authors"".""AuthorMetadataId""
WHERE ""Authors"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""Books""
WHERE ""Id"" IN (
SELECT ""Books"".""Id"" FROM ""Books""
LEFT OUTER JOIN ""Authors""
ON ""Books"".""AuthorMetadataId"" = ""Authors"".""AuthorMetadataId""
WHERE ""Authors"".""Id"" IS NULL)");
}
}
}

View File

@@ -17,11 +17,11 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""DownloadClientStatus""
WHERE ""Id"" IN (
SELECT ""DownloadClientStatus"".""Id"" FROM ""DownloadClientStatus""
LEFT OUTER JOIN ""DownloadClients""
ON ""DownloadClientStatus"".""ProviderId"" = ""DownloadClients"".""Id""
WHERE ""DownloadClients"".""Id"" IS NULL)");
WHERE ""Id"" IN (
SELECT ""DownloadClientStatus"".""Id"" FROM ""DownloadClientStatus""
LEFT OUTER JOIN ""DownloadClients""
ON ""DownloadClientStatus"".""ProviderId"" = ""DownloadClients"".""Id""
WHERE ""DownloadClients"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""Editions""
WHERE ""Id"" IN (
SELECT ""Editions"".""Id"" FROM ""Editions""
LEFT OUTER JOIN ""Books""
ON ""Editions"".""BookId"" = ""Books"".""Id""
WHERE ""Books"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""Editions""
WHERE ""Id"" IN (
SELECT ""Editions"".""Id"" FROM ""Editions""
LEFT OUTER JOIN ""Books""
ON ""Editions"".""BookId"" = ""Books"".""Id""
WHERE ""Books"".""Id"" IS NULL)");
}
}
}

View File

@@ -20,28 +20,24 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
private void CleanupOrphanedByAuthor()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""History""
WHERE ""Id"" IN (
SELECT ""History"".""Id"" FROM ""History""
LEFT OUTER JOIN ""Authors""
ON ""History"".""AuthorId"" = ""Authors"".""Id""
WHERE ""Authors"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""History""
WHERE ""Id"" IN (
SELECT ""History"".""Id"" FROM ""History""
LEFT OUTER JOIN ""Authors""
ON ""History"".""AuthorId"" = ""Authors"".""Id""
WHERE ""Authors"".""Id"" IS NULL)");
}
private void CleanupOrphanedByBook()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""History""
WHERE ""Id"" IN (
SELECT ""History"".""Id"" FROM ""History""
LEFT OUTER JOIN ""Books""
ON ""History"".""BookId"" = ""Books"".""Id""
WHERE ""Books"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""History""
WHERE ""Id"" IN (
SELECT ""History"".""Id"" FROM ""History""
LEFT OUTER JOIN ""Books""
ON ""History"".""BookId"" = ""Books"".""Id""
WHERE ""Books"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""ImportListStatus""
WHERE ""Id"" IN (
SELECT ""ImportListStatus"".""Id"" FROM ""ImportListStatus""
LEFT OUTER JOIN ""ImportLists""
ON ""ImportListStatus"".""ProviderId"" = ""ImportLists"".""Id""
WHERE ""ImportLists"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""ImportListStatus""
WHERE ""Id"" IN (
SELECT ""ImportListStatus"".""Id"" FROM ""ImportListStatus""
LEFT OUTER JOIN ""ImportLists""
ON ""ImportListStatus"".""ProviderId"" = ""ImportLists"".""Id""
WHERE ""ImportLists"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""IndexerStatus""
WHERE ""Id"" IN (
SELECT ""IndexerStatus"".""Id"" FROM ""IndexerStatus""
LEFT OUTER JOIN ""Indexers""
ON ""IndexerStatus"".""ProviderId"" = ""Indexers"".""Id""
WHERE ""Indexers"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""IndexerStatus""
WHERE ""Id"" IN (
SELECT ""IndexerStatus"".""Id"" FROM ""IndexerStatus""
LEFT OUTER JOIN ""Indexers""
ON ""IndexerStatus"".""ProviderId"" = ""Indexers"".""Id""
WHERE ""Indexers"".""Id"" IS NULL)");
}
}
}

View File

@@ -23,67 +23,57 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
private void DeleteOrphanedByAuthor()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles""
LEFT OUTER JOIN ""Authors""
ON ""MetadataFiles"".""AuthorId"" = ""Authors"".""Id""
WHERE ""Authors"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles""
LEFT OUTER JOIN ""Authors""
ON ""MetadataFiles"".""AuthorId"" = ""Authors"".""Id""
WHERE ""Authors"".""Id"" IS NULL)");
}
private void DeleteOrphanedByBook()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles""
LEFT OUTER JOIN ""Books""
ON ""MetadataFiles"".""BookId"" = ""Books"".""Id""
WHERE ""MetadataFiles"".""BookId"" > 0
AND ""Books"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles""
LEFT OUTER JOIN ""Books""
ON ""MetadataFiles"".""BookId"" = ""Books"".""Id""
WHERE ""MetadataFiles"".""BookId"" > 0
AND ""Books"".""Id"" IS NULL)");
}
private void DeleteOrphanedByTrackFile()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles""
LEFT OUTER JOIN ""BookFiles""
ON ""MetadataFiles"".""BookFileId"" = ""BookFiles"".""Id""
WHERE ""MetadataFiles"".""BookFileId"" > 0
AND ""BookFiles"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""MetadataFiles"".""Id"" FROM ""MetadataFiles""
LEFT OUTER JOIN ""BookFiles""
ON ""MetadataFiles"".""BookFileId"" = ""BookFiles"".""Id""
WHERE ""MetadataFiles"".""BookFileId"" > 0
AND ""BookFiles"".""Id"" IS NULL)");
}
private void DeleteWhereBookIdIsZero()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""Type"" IN (2, 4)
AND ""BookId"" = 0)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""Type"" IN (2, 4)
AND ""BookId"" = 0)");
}
private void DeleteWhereTrackFileIsZero()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""Type"" IN (2, 4)
AND ""BookFileId"" = 0)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""MetadataFiles""
WHERE ""Id"" IN (
SELECT ""Id"" FROM ""MetadataFiles""
WHERE ""Type"" IN (2, 4)
AND ""BookFileId"" = 0)");
}
}
}

View File

@@ -14,15 +14,13 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""PendingReleases""
WHERE ""Id"" IN (
SELECT ""PendingReleases"".""Id"" FROM ""PendingReleases""
LEFT OUTER JOIN ""Authors""
ON ""PendingReleases"".""AuthorId"" = ""Authors"".""Id""
WHERE ""Authors"".""Id"" IS NULL)");
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""PendingReleases""
WHERE ""Id"" IN (
SELECT ""PendingReleases"".""Id"" FROM ""PendingReleases""
LEFT OUTER JOIN ""Authors""
ON ""PendingReleases"".""AuthorId"" = ""Authors"".""Id""
WHERE ""Authors"".""Id"" IS NULL)");
}
}
}

View File

@@ -14,22 +14,20 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"DELETE FROM ""SeriesBookLink""
WHERE ""Id"" IN (
SELECT ""SeriesBookLink"".""Id"" FROM ""SeriesBookLink""
LEFT OUTER JOIN ""Books""
ON ""SeriesBookLink"".""BookId"" = ""Books"".""Id""
WHERE ""Books"".""Id"" IS NULL)");
using var mapper = _database.OpenConnection();
mapper.Execute(@"DELETE FROM ""SeriesBookLink""
WHERE ""Id"" IN (
SELECT ""SeriesBookLink"".""Id"" FROM ""SeriesBookLink""
LEFT OUTER JOIN ""Books""
ON ""SeriesBookLink"".""BookId"" = ""Books"".""Id""
WHERE ""Books"".""Id"" IS NULL)");
mapper.Execute(@"DELETE FROM ""SeriesBookLink""
WHERE ""Id"" IN (
SELECT ""SeriesBookLink"".""Id"" FROM ""SeriesBookLink""
LEFT OUTER JOIN ""Series""
ON ""SeriesBookLink"".""SeriesId"" = ""Series"".""Id""
WHERE ""Series"".""Id"" IS NULL)");
}
mapper.Execute(@"DELETE FROM ""SeriesBookLink""
WHERE ""Id"" IN (
SELECT ""SeriesBookLink"".""Id"" FROM ""SeriesBookLink""
LEFT OUTER JOIN ""Series""
ON ""SeriesBookLink"".""SeriesId"" = ""Series"".""Id""
WHERE ""Series"".""Id"" IS NULL)");
}
}
}

View File

@@ -18,31 +18,29 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
using (var mapper = _database.OpenConnection())
using var mapper = _database.OpenConnection();
var usedTags = new[] { "Authors", "Notifications", "DelayProfiles", "ReleaseProfiles", "ImportLists", "Indexers" }
.SelectMany(v => GetUsedTags(v, mapper))
.Distinct()
.ToArray();
if (usedTags.Any())
{
var usedTags = new[] { "Authors", "Notifications", "DelayProfiles", "ReleaseProfiles", "ImportLists", "Indexers" }
.SelectMany(v => GetUsedTags(v, mapper))
.Distinct()
.ToArray();
var usedTagsList = usedTags.Select(d => d.ToString()).Join(",");
if (usedTags.Any())
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
var usedTagsList = usedTags.Select(d => d.ToString()).Join(",");
if (_database.DatabaseType == DatabaseType.PostgreSQL)
{
mapper.Execute($"DELETE FROM \"Tags\" WHERE NOT \"Id\" = ANY (\'{{{usedTagsList}}}\'::int[])");
}
else
{
mapper.Execute($"DELETE FROM \"Tags\" WHERE NOT \"Id\" IN ({usedTagsList})");
}
mapper.Execute($"DELETE FROM \"Tags\" WHERE NOT \"Id\" = ANY (\'{{{usedTagsList}}}\'::int[])");
}
else
{
mapper.Execute("DELETE FROM \"Tags\"");
mapper.Execute($"DELETE FROM \"Tags\" WHERE NOT \"Id\" IN ({usedTagsList})");
}
}
else
{
mapper.Execute("DELETE FROM \"Tags\"");
}
}
private int[] GetUsedTags(string table, IDbConnection mapper)

View File

@@ -24,13 +24,11 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
_logger.Debug("Not running scheduled task last execution cleanup during debug");
}
using (var mapper = _database.OpenConnection())
{
mapper.Execute(@"UPDATE ""ScheduledTasks""
SET ""LastExecution"" = @time
WHERE ""LastExecution"" > @time",
new { time = DateTime.UtcNow });
}
using var mapper = _database.OpenConnection();
mapper.Execute(@"UPDATE ""ScheduledTasks""
SET ""LastExecution"" = @time
WHERE ""LastExecution"" > @time",
new { time = DateTime.UtcNow });
}
}
}

View File

@@ -75,7 +75,7 @@
"DeleteBackup": "Backup löschen",
"DeleteBackupMessageText": "Backup '{0}' wirkich löschen?",
"DeleteDelayProfile": "Verzögerungsprofil löschen",
"DeleteDelayProfileMessageText": "Bist du sicher, dass du dieses Verzögerungs-Profil löschen willst?",
"DeleteDelayProfileMessageText": "Bist du sicher, dass du dieses Verzögerung-Profil löschen willst?",
"DeleteDownloadClient": "Downloader löschen",
"DeleteDownloadClientMessageText": "Downloader '{0}' wirklich löschen?",
"DeleteEmptyFolders": "Leere Ordner löschen",
@@ -807,7 +807,7 @@
"MonitorNewItems": "Neue Bücher überwachen",
"MonitorNewItemsHelpText": "Welche neuen Bücher sollen überwacht werden",
"NewBooks": "Neue Bücher",
"NoHistoryBlocklist": "Keine History Blockliste",
"NoHistoryBlocklist": "Keine Verlauf-Sperrliste",
"NoName": "Namen nicht anzeigen",
"OnAuthorDelete": "Beim Löschen eines Autors",
"OnAuthorDeleteHelpText": "Beim Löschen eines Autors",
@@ -883,7 +883,7 @@
"CustomFormat": "Eigenes Format",
"CustomFormats": "Eigene Formate",
"CutoffFormatScoreHelpText": "Sobald diese eigener Format Bewertung erreicht wird, werden keine neuen Releases erfasst",
"DeleteFormatMessageText": "Bist du sicher, dass du das Formatierungstag {0} löschen willst ?",
"DeleteFormatMessageText": "Bist du sicher, dass du das Formatierungstag {0} löschen willst?",
"ExportCustomFormat": "Eigenes Format exportieren",
"Formats": "Formate",
"MinFormatScoreHelpText": "Mindester eigener Format Score bis zum Download",
@@ -894,7 +894,7 @@
"CustomFormatSettings": "Einstellungen für eigene Formate",
"DataFutureBooks": "Überwachung von Alben die noch nicht veröffentlicht wurden",
"DeleteCustomFormat": "Eigenes Format löschen",
"DeleteCustomFormatMessageText": "Indexer '{0}' wirklich löschen?",
"DeleteCustomFormatMessageText": "Bist du sicher, dass du das eigene Format '{0}' löschen willst?",
"IncludeCustomFormatWhenRenamingHelpText": "In {Custom Formats} umbennenungs Format",
"ResetTitles": "Titel zurücksetzen",
"UnableToLoadCustomFormats": "Eigene Formate konnten nicht geladen werden",
@@ -913,5 +913,13 @@
"ReplaceWithSpaceDashSpace": "Mit Leerzeichen Bindestrich Leerzeichen ersetzen",
"ApiKeyValidationHealthCheckMessage": "Bitte den API Schlüssel korrigieren, dieser muss mindestens {0} Zeichen lang sein. Die Änderung kann über die Einstellungen oder die Konfigurationsdatei erfolgen",
"ThereWasAnErrorLoadingThisItem": "Beim Laden des Eintrags ist ein Fehler aufgetreten",
"ThereWasAnErrorLoadingThisPage": "Beim Laden der Seite ist ein Fehler aufgetreten"
"ThereWasAnErrorLoadingThisPage": "Beim Laden der Seite ist ein Fehler aufgetreten",
"DeleteRemotePathMapping": "Entfernte Pfadzuordnung löschen",
"DeleteRemotePathMappingMessageText": "Bist du sicher, dass du das diese entfernte Pfadzuordnung löschen willst?",
"CloneCondition": "Bedingung klonen",
"DeleteCondition": "Bedingung löschen",
"RemoveSelectedItemBlocklistMessageText": "Bist du sicher, dass du die ausgewählten Einträge aus der Sperrliste entfernen willst?",
"ResetQualityDefinitionsMessageText": "Bist du sicher, dass du die Qualitätsdefinitionen zurücksetzen willst?",
"RemoveSelectedItemQueueMessageText": "Bist du sicher, dass du ein Eintrag aus der Warteschlange entfernen willst?",
"RemoveSelectedItemsQueueMessageText": "Bist du sicher, dass du {0} Einträge aus der Warteschlange entfernen willst?"
}

View File

@@ -762,7 +762,7 @@
"UpdateAvailable": "Nova atualização está disponível",
"UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent fornecido pelo aplicativo que chamou a API",
"UpdateCheckUINotWritableMessage": "Não é possível instalar a atualização porque a pasta de IU '{0}' não pode ser gravada pelo usuário '{1}'.",
"FailedToLoadQueue": "Falha ao carregar fila",
"FailedToLoadQueue": "Falha ao carregar a fila",
"DownloadClientStatusCheckSingleClientMessage": "Clientes de download indisponíveis devido a falhas: {0}",
"EditBook": "Editar Livro",
"FileWasDeletedByUpgrade": "Arquivo foi excluído para importar uma atualização",

View File

@@ -46,9 +46,9 @@
"BackupFolderHelpText": "Các đường dẫn tương đối sẽ nằm trong thư mục AppData của Radarr",
"BackupNow": "Sao lưu ngay",
"BackupRetentionHelpText": "Các bản sao lưu tự động cũ hơn khoảng thời gian lưu giữ sẽ tự động được dọn dẹp",
"Backups": "Sao lưu",
"Backups": "Những bản sao lưu",
"BindAddress": "Địa chỉ ràng buộc",
"BindAddressHelpText": "Địa chỉ IP4 hợp lệ hoặc '*' cho tất cả các giao diện",
"BindAddressHelpText": "Địa chỉ IP hợp lệ, localhost hoặc '*' cho tất cả các giao diện",
"BindAddressHelpTextWarning": "Yêu cầu khởi động lại để có hiệu lực",
"BookIsDownloading": "Đang tải phim",
"BookIsDownloadingInterp": "Đang tải phim xuống - {0}% {1}",
@@ -59,7 +59,7 @@
"Cancel": "Huỷ bỏ",
"CancelMessageText": "Bạn có chắc chắn muốn hủy nhiệm vụ đang chờ xử lý này không?",
"CertificateValidation": "Xác thực chứng chỉ",
"CertificateValidationHelpText": "Thay đổi cách xác thực chứng chỉ HTTPS nghiêm ngặt",
"CertificateValidationHelpText": "Thay đổi cách xác thực chứng chỉ HTTPS nghiêm ngặt. Không được đổi nếu bạn biết rõ về",
"ChangeFileDate": "Thay đổi ngày tệp",
"ChangeHasNotBeenSavedYet": "Thay đổi vẫn chưa được lưu",
"ChmodFolder": "Thư mục chmod",
@@ -471,11 +471,11 @@
"Level": "Cấp độ",
"SelectedCountBooksSelectedInterp": "{0} Phim đã chọn",
"ThisCannotBeCancelled": "Điều này không thể bị hủy sau khi bắt đầu mà không khởi động lại Radarr.",
"Blocklist": "Danh sách đen",
"BlocklistRelease": "Phát hành danh sách đen",
"Blocklist": "Danh sách chặn",
"BlocklistRelease": "Chặn bản phát hành",
"IndexerLongTermStatusCheckAllClientMessage": "Tất cả các trình lập chỉ mục không khả dụng do lỗi trong hơn 6 giờ",
"Disabled": "Tàn tật",
"AppDataLocationHealthCheckMessage": "Việc cập nhật sẽ không thể ngăn việc xóa AppData khi cập nhật",
"AppDataLocationHealthCheckMessage": "Việc cập nhật sẽ không xảy ra để tránh xóa AppData khi cập nhật",
"ConnectSettingsSummary": "Thông báo, kết nối với máy chủ / trình phát đa phương tiện và tập lệnh tùy chỉnh",
"CouldntFindAnyResultsForTerm": "Không thể tìm thấy bất kỳ kết quả nào cho '{0}'",
"DownloadClientStatusCheckSingleClientMessage": "Ứng dụng khách tải xuống không khả dụng do lỗi: {0}",
@@ -581,5 +581,8 @@
"ColonReplacement": "Thay thế ruột kết",
"ReplaceWithDash": "Thay thế bằng Dấu gạch ngang",
"ReplaceWithSpaceDash": "Thay thế bằng Dấu gạch ngang",
"ReplaceWithSpaceDashSpace": "Thay thế bằng Space Dash Space"
"ReplaceWithSpaceDashSpace": "Thay thế bằng Space Dash Space",
"BlocklistReleases": "Phát hành danh sách đen",
"ApplicationURL": "URL của ứng dụng",
"ApiKeyValidationHealthCheckMessage": "Hãy cập nhật mã API để dài ít nhất {0} kí tự. Bạn có thể làm điều này trong cài đặt hoặc trong tập config"
}

View File

@@ -5,5 +5,31 @@
"AddingTag": "新增標籤",
"Analytics": "分析",
"AddList": "新增列表",
"ExportCustomFormat": "新增自定義格式"
"ExportCustomFormat": "新增自定義格式",
"Blocklist": "封鎖清單",
"Branch": "分支",
"AppDataLocationHealthCheckMessage": "為了避免在更新過程中刪除AppData將無法進行更新。",
"AppDataDirectory": "AppData 路徑",
"ApiKeyValidationHealthCheckMessage": "請將您的API金鑰更新為至少{0}個字元長。您可以通過設定或配置文件進行此操作。",
"ApplyTags": "套用標籤",
"Authentication": "認證",
"AutoRedownloadFailedHelpText": "自動搜尋並嘗試下載不同的版本",
"Automatic": "自動",
"BackupRetentionHelpText": "超過保留期的自動備份將被自動清理",
"Backups": "備份",
"BindAddress": "綁定地址Bind Address",
"BindAddressHelpText": "有效的IP地址本地主機localhost或者「*」以表示所有介面。",
"Quality": "品質",
"QualityDefinitions": "品質定義",
"BlocklistReleases": "封鎖清單版本",
"ClickToChangeQuality": "點擊以更改品質",
"ApplicationUrlHelpText": "這個應用程式的外部網址包括http(s)://、端口和URL Base。",
"ApplicationURL": "應用程式 URL",
"AlreadyInYourLibrary": "已經在您的資源庫中",
"DeleteQualityProfile": "刪除品質設定檔",
"ApplyTagsHelpTexts3": "移除:刪除輸入的標籤",
"ApplyTagsHelpTexts4": "取代:用輸入的標籤替換現有的標籤(如果不輸入任何標籤,則清除所有標籤)",
"AddListExclusion": "新增排除清單",
"BackupNow": "馬上備份",
"BlocklistRelease": "封鎖清單版本"
}

View File

@@ -22,6 +22,12 @@ namespace Readarr.Api.V1.Health
_healthCheckService = healthCheckService;
}
[NonAction]
public override ActionResult<HealthResource> GetResourceByIdWithErrorHandler(int id)
{
return base.GetResourceByIdWithErrorHandler(id);
}
protected override HealthResource GetResourceById(int id)
{
throw new NotImplementedException();

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using NzbDrone.Core.DecisionEngine;
using Readarr.Http.REST;
@@ -7,6 +8,12 @@ namespace Readarr.Api.V1.Indexers
{
public abstract class ReleaseControllerBase : RestController<ReleaseResource>
{
[NonAction]
public override ActionResult<ReleaseResource> GetResourceByIdWithErrorHandler(int id)
{
return base.GetResourceByIdWithErrorHandler(id);
}
protected override ReleaseResource GetResourceById(int id)
{
throw new NotImplementedException();

View File

@@ -41,6 +41,7 @@ namespace Readarr.Api.V1
}
[HttpGet]
[Produces("application/json")]
public List<TProviderResource> GetAll()
{
var providerDefinitions = _providerFactory.All().OrderBy(p => p.ImplementationName);
@@ -58,6 +59,8 @@ namespace Readarr.Api.V1
}
[RestPostById]
[Consumes("application/json")]
[Produces("application/json")]
public ActionResult<TProviderResource> CreateProvider([FromBody] TProviderResource providerResource, [FromQuery] bool forceSave = false)
{
var providerDefinition = GetDefinition(providerResource, true, !forceSave, false);
@@ -73,6 +76,8 @@ namespace Readarr.Api.V1
}
[RestPutById]
[Consumes("application/json")]
[Produces("application/json")]
public ActionResult<TProviderResource> UpdateProvider([FromBody] TProviderResource providerResource, [FromQuery] bool forceSave = false)
{
var providerDefinition = GetDefinition(providerResource, true, !forceSave, false);
@@ -108,6 +113,7 @@ namespace Readarr.Api.V1
}
[HttpGet("schema")]
[Produces("application/json")]
public List<TProviderResource> GetTemplates()
{
var defaultDefinitions = _providerFactory.GetDefaultDefinitions().OrderBy(p => p.ImplementationName).ToList();
@@ -131,6 +137,7 @@ namespace Readarr.Api.V1
[SkipValidation(true, false)]
[HttpPost("test")]
[Consumes("application/json")]
public object Test([FromBody] TProviderResource providerResource)
{
var providerDefinition = GetDefinition(providerResource, true, true, true);
@@ -141,6 +148,7 @@ namespace Readarr.Api.V1
}
[HttpPost("testall")]
[Produces("application/json")]
public IActionResult TestAll()
{
var providerDefinitions = _providerFactory.All()
@@ -164,6 +172,8 @@ namespace Readarr.Api.V1
[SkipValidation]
[HttpPost("action/{name}")]
[Consumes("application/json")]
[Produces("application/json")]
public IActionResult RequestAction(string name, [FromBody] TProviderResource resource)
{
var providerDefinition = GetDefinition(resource, false, false, false);

View File

@@ -57,6 +57,12 @@ namespace Readarr.Api.V1.Queue
_qualityComparer = new QualityModelComparer(qualityProfileService.GetDefaultProfile(string.Empty));
}
[NonAction]
public override ActionResult<QueueResource> GetResourceByIdWithErrorHandler(int id)
{
return base.GetResourceByIdWithErrorHandler(id);
}
protected override QueueResource GetResourceById(int id)
{
throw new NotImplementedException();

View File

@@ -26,6 +26,12 @@ namespace Readarr.Api.V1.Queue
_pendingReleaseService = pendingReleaseService;
}
[NonAction]
public override ActionResult<QueueResource> GetResourceByIdWithErrorHandler(int id)
{
return base.GetResourceByIdWithErrorHandler(id);
}
protected override QueueResource GetResourceById(int id)
{
throw new NotImplementedException();

View File

@@ -30,6 +30,12 @@ namespace Readarr.Api.V1.Queue
_broadcastDebounce = new Debouncer(BroadcastChange, TimeSpan.FromSeconds(5));
}
[NonAction]
public override ActionResult<QueueStatusResource> GetResourceByIdWithErrorHandler(int id)
{
return base.GetResourceByIdWithErrorHandler(id);
}
protected override QueueStatusResource GetResourceById(int id)
{
throw new NotImplementedException();

View File

@@ -20,7 +20,7 @@ namespace Readarr.Api.V1.System.Backup
private readonly IAppFolderInfo _appFolderInfo;
private readonly IDiskProvider _diskProvider;
private static readonly List<string> ValidExtensions = new List<string> { ".zip", ".db", ".xml" };
private static readonly List<string> ValidExtensions = new () { ".zip", ".db", ".xml" };
public BackupController(IBackupService backupService,
IAppFolderInfo appFolderInfo,
@@ -37,22 +37,28 @@ namespace Readarr.Api.V1.System.Backup
var backups = _backupService.GetBackups();
return backups.Select(b => new BackupResource
{
Id = GetBackupId(b),
Name = b.Name,
Path = $"/backup/{b.Type.ToString().ToLower()}/{b.Name}",
Type = b.Type,
Size = b.Size,
Time = b.Time
})
.OrderByDescending(b => b.Time)
.ToList();
{
Id = GetBackupId(b),
Name = b.Name,
Path = $"/backup/{b.Type.ToString().ToLower()}/{b.Name}",
Type = b.Type,
Size = b.Size,
Time = b.Time
})
.OrderByDescending(b => b.Time)
.ToList();
}
[RestDeleteById]
public void DeleteBackup(int id)
{
var backup = GetBackup(id);
if (backup == null)
{
throw new NotFoundException();
}
var path = GetBackupPath(backup);
if (!_diskProvider.FileExists(path))

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,8 @@ namespace Readarr.Http.REST
}
[RestGetById]
public ActionResult<TResource> GetResourceByIdWithErrorHandler(int id)
[Produces("application/json")]
public virtual ActionResult<TResource> GetResourceByIdWithErrorHandler(int id)
{
try
{