Commit Graph
57 Commits
Author SHA1 Message Date
Cursor Agentandrmcrackan d7a6ef0302 test(pdf): compare paths the way Libation produces them
The two path assertions added with the PDF fix compared a path the test built
itself against one that had been through LongPath, which on Windows prefixes a
drive-rooted path with \\?\ so paths past the 260 character limit work. Linux
adds no prefix, so this only showed up on the Windows job.

Normalising both sides is not just about the false failure. The inequality
assertion guarding 'the PDF was saved loose in the Books directory' compared a
raw temp path against a prefixed one, so on Windows it passed on the prefix
alone and would not have caught the bug it exists to catch.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
2026-08-16 18:01:37 +00:00
Cursor Agentandrmcrackan 8fd3b91858 fix(cli): do not fetch the PDF of a title Audible just refused
A PDF is fetched through the same license request as the audiobook, so following
a refusal with a PDF request reproduced, through the PDF, exactly the per-run
refusal the wait exists to stop. The follow-up pass now skips the titles the
first pass deliberately left alone as well as the ones it attempted.

Also stop a failed PDF download leaving an empty folder in the library: a
PDF-only download is the one case that has to create the book's folder before it
has anything to put in it, so it now removes a folder it created and did not
fill. GetProposedDownloadFilePath goes back to being a pure path computation.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
2026-08-16 17:08:13 +00:00
Cursor Agentandrmcrackan 870b596d3e fix(cli): download the PDFs of titles whose audio is already downloaded
A plain 'libationcli liberate' iterates the titles DownloadDecryptBook selects,
and that step selects on '!AudioExists'. A title needing nothing but its PDF was
therefore never reached by the verb documented as 'book and pdf backups' - only
'liberate --pdf' picked it up. For a library that was liberated before its PDFs
were, that is every title with a PDF.

Give the bulk run an optional second pass and have liberate use it for PDFs, the
way the app's Liberate All always has. Skipped when the first pass stopped early
so a run cut short by its download limit does not carry on doing other work, and
titles the first pass attempted are excluded by product id rather than by asking
Validate again, so a step that just failed is not immediately retried.

Left alone: the Audiobookshelf upload stays tied to a fresh liberation. Its
Validate passes for any liberated title, so including it here would walk the
whole library on the next run. 'abs upload' already exists for that.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
2026-08-16 17:01:29 +00:00
Cursor Agentandrmcrackan 54485c0825 fix(pdf): save a PDF with its book instead of loose in the Books directory
getProposedDownloadFilePath looked for the book's audio file and fell back to
the Books directory itself when it found none. That lookup matches on the
product id appearing in the path, so it finds nothing for a library whose
folder and file templates omit <id>, and nothing for a title marked downloaded
whose files are not on this machine. Those PDFs landed in the library root,
where they also shared one namespace and so could collide with each other.

Fall back to the folder template instead - the same folder the audiobook itself
would go in - and create it, since nothing else does on the PDF-only path.

Also give MockLibraryBook a three-field version: ToVersionString formats to at
least three fields, so the two-field default threw as soon as anything rendered
a naming template for a mock book.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
2026-08-16 17:01:29 +00:00
Cursor Agentandrmcrackan 252decb3ad test(logging): prove the log actually rolls on size
Asserting on the generated JSON alone would pass just as happily with a
misspelled sink argument, which Serilog ignores in silence - and silently not
rolling is the bug. These build a real logger from Libation's own config and
write until it rolls, including a test that pins the old unbounded behaviour so
a future change to the defaults cannot quietly restore it.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
2026-08-16 16:30:23 +00:00
Cursor Agentandrmcrackan 854cb280a0 test: cover the retry backoff, the store and the failure classifier
The classifier's inputs are the actual denials from the log attached to issue
#1947: owned titles on an inactive account, a Plus title no longer in the
catalog, and an unreleased preorder Audible has no audio for.

The backoff tests also caught a real overflow: first * 2^n exceeds a TimeSpan
long before the cap matters.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
2026-08-16 16:23:34 +00:00
Caio Wilson 877912e6e8 test: normalize Windows Audiobookshelf scan paths 2026-08-13 01:37:07 -03:00
Caio Wilson 9ac1f64056 Fix Audiobookshelf CLI upload follow-ups 2026-08-10 18:47:21 -03:00
Caio WilsonandClaude Opus 5 4a5c81b5e6 Add CLI 'upload' verb to send already-liberated books to Audiobookshelf
Auto-upload only fires when a book is liberated. Books liberated before
Audiobookshelf was configured, or while it was disabled, had no path to the
server short of re-downloading the whole library.

'libationcli upload' backfills them from the files already on disk. Bulk or
targeted by ASIN. Nothing is re-downloaded and no local file is deleted.

Also fixes a latent defect this exposes. Validate() reads a database status
(Book.AudioExists) while GetFilesToUpload() read only FilePathCache. A book
liberated long ago passes validation but has no cache entry, so the upload
found no files and returned success having sent nothing. File lookup now uses
AudibleFileStorage.Audio.GetPaths, which unions the cache with a live scan of
the Books directory.

Other changes:
- Validate() now requires LiberatedStatus.Liberated. It previously accepted
  Error too, whose partial files should not be uploaded.
- New OutcomeDetermined event classifies each book as Uploaded, AlreadyExists,
  NoFilesFound or Failed. Failures travel on this event rather than through
  StatusHandler: the GUI process queue treats a non-success StatusHandler as a
  bad book and raises the Abort/Retry/Ignore dialog, and an upload problem must
  never fail a liberation.
- The verb prints an end-of-run summary and exits 0, matching other verbs.

No database migration. Duplicate detection already runs server-side inside
UploadBookAsync, so repeat runs are safe without local upload state.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 15:16:34 -03:00
rmcrackan 4bd7796f70 #1872 : Suggest Widevine when ADRM licenserequest fails with Sable acr:null 2026-06-16 11:12:58 -04:00
Michael Bucari-Tovo df531de255 Update Avalonia to v12
Avalonia 12 uses compiled bindings by default. Converted all remaining reflection bindings into compiled bindings,

Fixed binding errors
2026-05-04 21:08:26 -06:00
Michael Bucari-Tovo 3ab1edc076 Code Cleanup
Make fields readonly
Remove unnecessary casts
Format document
Remove unnecessary usings
Sort usings
Use file-level namespaces
Order modifiers
2026-02-05 12:48:44 -07:00
Michael Bucari-Tovo d67692355f Enable project-wide nullable reference types
Added DB migration for nullable types.
2026-02-05 12:43:05 -07:00
MBucari e850465ec1 Add more null safety
Enable project-wide nullable on LibationUiBase and LibationAvalonia

Explicitly parallelize unit tests
2025-12-30 13:17:11 -07:00
Youssef1313 03ed8e6b57 Migrate from VSTest to MTP 2025-12-21 15:03:52 +01:00
MBucari fde78f4167 Update to .NET 10
- Update all project runtime targets
- Update all dependencies
  - NOTE: Using Npgsql.EntityFrameworkCore.PostgreSQL RTM build from MyGet
- Delete unused pubxml files (they were made redundant by recent workflow changes)
- Replace Libation.sln with Libation.slnx
2025-11-20 15:56:47 -07:00
Michael Bucari-Tovo f98adef9e9 Update Dependencies
- Remove package references that are already included transitively
- Change Avalonia.ReactiveUI to ReactiveUI.Avalonia
2025-11-03 09:34:23 -07:00
Michael Bucari-Tovo eda100b7ac Remove FluentAssertions 2025-08-15 10:29:23 -06:00
Michael Bucari-Tovo 05fad01624 Update dependencies 2025-08-14 15:57:35 -06:00
rmcrackan 0045202334 update dependencies 2025-08-13 07:52:13 -04:00
rmcrackan 72f92ec6c0 update dependencies 2025-08-10 11:21:34 -04:00
MBucari 9b1ce8c1d7 Update dependencies 2025-07-14 12:43:53 -06:00
MBucari ece48eb6d7 Add spatial audio support 2025-04-27 14:31:14 -06:00
MBucari 1777dc5a7e Update AAXClean.Codecs and dependencies 2025-04-25 19:52:51 -06:00
Robert McRackan 71afb5c9f4 incr ver 2025-03-18 21:09:27 -04:00
Robert McRackan 614965e1ab incr ver 2025-03-10 19:09:44 -04:00
Robert McRackan 5cb22cfd24 Update AAXClean.Codecs 2025-02-17 20:07:50 -05:00
Robert McRackan c7279574a9 Upgrade avalonia 2025-01-07 08:00:35 -05:00
Robert McRackan 6134becc70 Upgrade to .net9 2024-11-22 16:47:59 -05:00
Robert McRackan 92ee0b2e6d update dependencies 2024-09-11 07:20:54 -04:00
Robert McRackan f9340db90a update references. audible api bugfix 2024-05-15 06:55:25 -04:00
Robert McRackan 93ccc206ef Update dependencies 2024-03-04 14:02:42 -05:00
Robert McRackan b6d1a7e3ba Upgrade to .net8 2023-11-15 19:53:26 -05:00
Michael Bucari-Tovo 59689cb647 Update Dependencies 2023-08-30 11:59:40 -06:00
Robert McRackan f733079a49 remove Moq 2023-08-10 15:24:43 -04:00
Robert McRackan 15ad753fa1 update dependencies 2023-07-14 20:58:26 -04:00
Mbucari 1e40180f0c Fix unit test 2023-07-09 16:42:08 -06:00
Robert McRackan 265794bae0 update dependencies 2023-05-19 11:24:47 -04:00
Robert McRackan 378cf7057e updated to AudibleApi v8 2023-02-24 13:12:18 -05:00
Robert McRackan 73533c58a8 update dependencies 2023-02-13 21:14:56 -05:00
Robert McRackan b668cff0ac Update dependenciesd. Build is broken until the ambiguous ref.s moved into Dinah.Core are resolved 2023-01-24 22:40:08 -05:00
Robert McRackan b8c26b01ad update dependencies 2022-12-30 09:58:51 -05:00
Robert McRackan 4b2387b621 update dependencies 2022-12-07 11:53:10 -05:00
Robert McRackan cf0548aab9 update dependencies 2022-11-16 12:46:12 -05:00
Robert McRackan 90cbf3b7a6 tests => .net7 2022-11-16 11:27:51 -05:00
Robert McRackan 06f8d055fc update dependencies 2022-11-02 16:24:14 -04:00
Robert McRackan 75429f288f update dependencies 2022-09-28 13:25:41 -04:00
Robert McRackan 7ac1fff3a0 update dependencies 2022-09-09 11:53:59 -04:00
Michael Bucari-Tovo 3b739328fb Fix some bugs with user settings. 2022-07-06 13:10:37 -06:00
Michael Bucari-Tovo 3ce1f94f87 Revert preview feature 2022-06-26 10:42:52 -06:00