asChild is a bits-ui v1 prop the icon picker no longer needs -- it already
passes a child snippet. The drop zone set both webkitdirectory and a bare
directory attribute, which no browser implements. The library view seeds its
collection state once by design, so it says so with untrack.
Dead imports and locals removed, each blocks keyed, `any` narrowed to unknown.
Two context setters kept their calls and lost only the unused binding; the
settings redirect no longer awaits a parent whose data it discards. A leading
underscore now marks a binding that only holds a position.
no-unused-expressions is off for Svelte files: a bare `book;` in an $effect
declares a dependency. The URL and Set instances it flagged are local
temporaries, marked individually. The one real finding was visibleApiKeys,
genuine reactive state cloned on every mutation to force an update; it is a
SvelteSet now.
Applies ruff format, ruff check --fix and prettier, so CI can gate on all three.
The surviving unused imports were all re-exports in __init__.py, now covered by a
per-file ignore; the pdf.js viewer and the generated openapi types join the
vendored code that eslint and prettier already skip.
Reads metadata.db and copies the books into a library — from a zip uploaded on
the library settings page, or from a path with `litestar calibre-import`. The
source is never touched, and re-running only picks up what is new.
Also names the formats mimetypes does not know: a Calibre library is full of
MOBI and AZW3, and a null content type used to fail the book endpoint.
A workbench with the folded records in a rail, the survivor's fields live and
editable beside them, and per-field actions chosen by what kind of field it is.
Fields the records agree on stay out of the way. Reachable from a duplicate
group and from the selection toolbar, which is the only way to merge a pair the
detector never proposed.
Adds the per-library review screen, a muted note in the upload tray for a book
that may already be held, and the remote functions behind them. The tray note
is deliberately weaker than the file-level one, which means something stronger.
One request per book instead of one for everything, queued in state above the
dialog so closing it no longer cancels the import. A docked tray reports each
book and offers a retry; it clears itself after a clean run, stays put if
anything failed, and holds while hovered.
Also fixes the dialog overflowing on long filenames — Dialog.Content is a grid
and its body needed min-w-0 to shrink below the content's intrinsic width.
Drops epub.js's 1600-location pre-pass and its localStorage cache: foliate
hands back a CFI and an overall fraction on every relocate, so first open no
longer freezes.
Also fixes resuming (pre-resolves the stored CFI, falling back to the stored
percentage rather than silently resetting to page one), progress saving
(missing Content-Type, and no flush on the way out), and arrow keys inside
the book iframe.
The load function read progress.epub_loc and progress.progress, neither of
which BookProgressRead carries, so resuming never worked and every open
started at page one. Read epub_cfi and percentage instead.
Fail loudly when the book cannot be fetched. The previous version caught
everything and returned {status, error} that nothing consumed, so a missing
book produced a reader sitting on its spinner forever. Check response.ok
before parsing too: fetch resolves on a 404, and arrayBuffer() happily
returns the error page, which only surfaced later as an opaque epub parse
error.
Give the reader a working sidebar, a theme that survives the book's own
CSS, and an error state with a retry. The theme is registered rather than
applied as bare overrides because most EPUBs ship their own body colours
and win otherwise, which is why the page stayed white against a dark UI.
The PDF reader pointed an iframe at the vendored pdf.js viewer and had no
way to report a failure: the viewer renders its own errors inside the
frame, so a missing or unreadable file showed an empty grey panel. Probe
the file with a request first and render an error card with a retry when
that fails, matching the chrome the EPUB reader uses.
Add the missing +page.ts for the PDF route so the tab gets the book title
rather than a bare "Reader".
Drop chapter-sidebar.svelte and its import. It rendered a list of chapters
whose buttons had no click handler, and read/+layout@.svelte imported it
without ever rendering it. The reader's own sidebar replaces it.
The reader and login pages use +layout@ breakouts to escape the (root)
shell, so anything mounted in (root)/+layout.svelte never reaches them.
ModeWatcher was mounted there and duplicated in login/+layout@.svelte,
which left the reader's theme toggle inert: it flipped the store but
nothing wrote .dark onto <html>.
Mount both once at the top-level +layout.svelte instead, which every
route inherits regardless of breakouts.
Updated book progress model in anticipation of the KOReader sync
feature.
Renamed properties:
- renamed "progress" to "percentage"
- renamed "pdf_loc" to "pdf_page"
- renamed "epub_loc" to "epub_cfi"
New properties:
- "epub_xpointer", marks the location of an epub in KOReader
- "device", the device type that updated the progress
- "device_id", the id of the device that updated the progress