fix(download): stop asking Audible for a license it just refused

A license denial left no trace: BookStatus stayed NotLiberated, so every
liberate run asked again. Only the GUI's bad-book dialog could mark a title
Error, and license denials take their own path and never reach that dialog, so
a headless install had no way at all to stop the retries. A cron schedule then
re-requested the same refused licenses every run and printed the same warning
block for each one, which is both wasted API traffic and the log noise reported
in issue #1947.

Record the refusal instead, with a wait that doubles per consecutive failure:
one day for an eligibility denial (up to 30), six hours for a title Audible has
no audio for yet such as an unreleased preorder (up to 7 days), one hour when
the denial names GenericError, which the GUI already reads as an outage
(up to 12). Nothing is permanent - every kind is attempted again on its own.

Only failures attributable to Audible are recorded. A dropped connection, a
decrypt error or a full disk keeps being retried on the next run as before.

Naming a title, --force, and setting a download status all clear the record:
asking for a title explicitly overrides the wait.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
This commit is contained in:
Cursor Agentandrmcrackan committed 2026-08-16 16:13:17 +00:00
1 parent 4d8075927f
commit 824ff10dd9
20 files changed
+2019 -12

No files matched your search

@@ -241,7 +241,9 @@ public class ProcessQueueViewModel : ReactiveObject
}
else
{
var request = BackupRequest.Create(libraryBooks);
// Titles Audible recently refused are left out of a multi-book request but never out of a
// single-title one: picking one title is the user overriding the wait.
var request = BackupRequest.Create(libraryBooks, DownloadDeferrals.Load(DateTimeOffset.Now));
if (request.Queueable.Length == 0)
{
@@ -269,6 +271,9 @@ public class ProcessQueueViewModel : ReactiveObject
request.RequestedCount,
request.BuildSkippedLogSummary());
if (request.Deferred.Count > 0)
AddQueueLogEntry(request.BuildDeferredDetail(DateTimeOffset.Now));
// May no-op when free space is unknown (common on UNC); see DiskSpaceBackupPreflight.
if (!await DiskSpaceBackupPreflight.ConfirmBulkBackupAsync(request.Queueable.Length, config, backupQueueAlreadyRunning: Running))
return false;