No description
  • Rust 84%
  • TypeScript 11.5%
  • Python 2.5%
  • JavaScript 0.8%
  • Shell 0.7%
  • Other 0.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Conrad Kramer d4d4664815
All checks were successful
deploy-fly / validate (push) Successful in 14m57s
deploy-fly / deploy (push) Has been skipped
Record installed Media upgrade proof
2026-08-23 13:44:46 -07:00
.forgejo/workflows Use active Rust host for wasm archiver 2026-08-23 03:47:16 -07:00
capabilities Harden the web client and cache before production 2026-08-23 03:32:03 -07:00
crates Harden native update trust boundary 2026-08-23 13:27:00 -07:00
design-audit feat: add UIKit runtime and atomic generation outputs 2026-08-12 01:20:34 -07:00
docker Refuse unseeded Fly production starts 2026-08-22 10:21:50 -07:00
docs Record installed Media upgrade proof 2026-08-23 13:44:46 -07:00
examples Complete the Media rename and harden state cutover 2026-08-22 13:07:58 -07:00
migrations Add safe article ingestion and reader 2026-08-22 04:22:55 -07:00
ops/namespace/release-runner Upgrade release runner for Forgejo OIDC 2026-08-23 03:03:12 -07:00
scripts Verify Safari entitlements by signed digest 2026-08-23 03:53:53 -07:00
src Add local-first web client with stream-and-retain media cache 2026-08-23 03:32:03 -07:00
tests Add local-first web client with stream-and-retain media cache 2026-08-23 03:32:03 -07:00
vendor/md-rip Add safe article ingestion and reader 2026-08-22 04:22:55 -07:00
web Retire old hostnames from web fixtures 2026-08-23 13:35:53 -07:00
.dockerignore Add local-first web client with stream-and-retain media cache 2026-08-23 03:32:03 -07:00
.gitignore Integrate native Audible source with FFmpeg lineage 2026-08-02 23:40:32 -07:00
build.rs Add local-first web client with stream-and-retain media cache 2026-08-23 03:32:03 -07:00
Cargo.lock Define signed macOS update manifest boundary 2026-08-23 04:33:53 -07:00
Cargo.toml Add verified SQLite backup export 2026-08-22 18:02:32 -07:00
design-qa.md Rename product surfaces to Media 2026-08-22 03:28:49 -07:00
Dockerfile Harden the web client and cache before production 2026-08-23 03:32:03 -07:00
flake.lock Add catalog, metadata, and media pipeline foundations 2026-08-01 22:42:52 -07:00
flake.nix Finish safe Media product labels 2026-08-22 04:20:04 -07:00
fly.toml Split Garage writer and public endpoints 2026-08-22 18:02:50 -07:00
LICENSE Integrate native Audible source with FFmpeg lineage 2026-08-02 23:40:32 -07:00
README.md Add local-first web client with stream-and-retain media cache 2026-08-23 03:32:03 -07:00
rustfmt.toml Build initial Arrange Media vertical slice 2026-07-26 03:30:56 -07:00
SECURITY.md Harden the content.website cutover gates 2026-08-22 11:39:59 -07:00
THIRD_PARTY_NOTICES.md Finish safe Media product labels 2026-08-22 04:20:04 -07:00

Media

One owned media library, served to the clients you already use.

Media is a Rust, local-first canonical library for ebooks, articles, saved web pages, audiobooks, podcasts, music, films, television, and general video. It imports user-owned or user-authorized media without altering the source, stores durable records in SQLite and immutable bytes in a content-addressed blob store, and projects that shared model through familiar client protocols. The native application is intended to run that canonical core directly; network services synchronize repositories and export protocols rather than sitting between AppKit and its local database.

Media is server-first, not server-only. Its native API is the expressive master interface, compatibility adapters are deliberately bounded projections, and the transport-neutral Rust services are intended to become the core of first-party web, desktop, and mobile clients. The embedded web client at /ui/ is the first of those: a local-first, offline-capable TypeScript shell over the shared Rust core compiled to WebAssembly, with a browser-side SQLite replica, an operation outbox, and the same five presentation projections as the native AppKit shell. See the web client.

Status: this is an active vertical-slice MVP, not a drop-in replacement for every feature of Navidrome, Calibre-Web, Audiobookshelf, Jellyfin, or the other named servers. Compatibility claims below are scoped to the workflows actually tested. “Released client proof” means a released binary exercised that bounded flow; it never means full compatibility.

See the durable product goal, the protocol roadmap, and the machine-readable capability manifests for the exact claim boundary. The Media identity boundary records which legacy keys remain solely to open existing data and linked clients safely.

The optional public server/protocol-export instance is content.website, with browser identity provided by compatible.systems. It is not the native app's database. Protocol clients continue to use the authentication shapes documented for their adapters.

What works today

  • Non-destructive recursive filesystem discovery and import into one canonical library, including books, articles, saved-page/archive formats, audio, and video. An explicitly television-typed import recognizes a narrow conventional Series[/Season NN]/SNNENN layout, uses a digest of the series directory as a source-scoped identity hint, and never guesses TV during ordinary video scans.
  • BLAKE3-addressed immutable blobs with verified writes, SQLite records, source provenance, visibility/grants, original-versus-derived artifacts, and explicit parent lineage.
  • Rich, attributable metadata for contributors, identifiers, semantic parts, EPUB structure, M4A/M4B chapters, and inspected ISO-BMFF audio/video streams. Embedded lyrics remain attached to the immutable artifact that carried the tag; additive migration 0032 copies eligible earlier item-scoped lyric assertions to that retained artifact while preserving the original rows and raw provenance.
  • Exact MusicBrainz release enrichment with a provider-neutral matching ledger, bounded raw-response evidence in CAS, release-scoped assertions, and Cover Art Archive artwork copied as a provenance-bearing supplement. This path is local-fixture request-tested; no live-provider claim is made.
  • Exact-ISBN Open Library edition/cover discovery, artifact-scoped local Chromaprint generation with durable CAS/SQLite persistence boundaries, and opt-in read-only AcoustID candidate lookup. These are focused request and persistence proofs, not a fuzzy auto-match system or live-provider proof.
  • Provider-neutral, versioned catalog discovery with a bounded public Substack RSS slice that retains articles, podcast audio, video, YouTube presences, and acquisition handoffs without treating remote URLs as owned blobs.
  • Reviewed SQLite invariants for cross-medium entities/works, immutable public, authenticated, or user-export capture versions, and sealed ordered compositions over works, items, artifacts, fragments, and prior revisions. This is persistence substrate, not a capture executor or composition API.
  • Manifest-bound physical-media preservation packages retain exact original bytes separately from MKV/M4B/MP3/CMAF derivatives. Complete source-lineage assertion sets and immutable, tool-fingerprinted validation receipts gate the playback registry: unreceipted legacy rows remain auditable but are excluded from verified_playback_renditions. Receipt facts distinguish exact package objects, coded-packet identity, decoded-essence identity, absent essence, and an honest not-preserved result instead of inferring fidelity from a container name. See preservation packages and receipts.
  • An optional Rust FFmpeg/libavformat/libavcodec boundary for exact build capability reporting, bounded media probes, decoded-audio chunks, and a remux-first AVFoundation planner. A tested in-process stream-copy executor produces and validates fragmented MP4 without encoding compatible tracks; a 256-bit-capability loopback server implements exact GET/HEAD/range delivery for one authorized artifact and backs the native selected-record path. The explicit generate-cmaf pipeline additionally produces one sealed single-file byte-range CMAF bundle with shared representation files, DASH, full HLS, and constrained AVC/AAC HLS. It verifies complete decodes, access-unit identity or audited transforms, exact decoded lossless-audio-bed identity, measured bandwidth, CAS bytes, lineage, and immutable execution and playback receipts before publication. Authenticated native discovery returns only fully available receipt-verified bundles and defaults to constrained; local/high-bandwidth callers can explicitly enter the full master. The two masters have exact, receipt-bound membership and isolate video lanes whose timestamps are not exactly switch-aligned; each currently has one video representation and is a profile-selected entry point, not a proven multi-bitrate Apple ladder. This is an ahead-of-time first-party pipeline, not a background/live transcoder, universal codec claim, released third-party-client proof, or actual AirPlay endpoint. See media engine and CMAF.
  • A bounded synchronized-media path for provenance-qualified generated WebVTT. The pure-Rust media-transcript-core parser accepts only an ordered, non-overlapping, resource-bounded generated-file subset and returns inert cue text with exact millisecond coordinates. LibraryStore exposes a companion only when the caller can read the same item, the VTT is a direct derived child of the exact audio/video artifact, and one succeeded generation run declares an explicit bidirectional arrange-coordinate-map-v1 alignment. The complete VTT object is BLAKE3/length verified before AppKit seals the media pin, transcript pin, map, and generation provenance into one session. Parser validation is 14/14 in the current workspace suite; the playback-proof seeder remains 3/3. The strict-clippy checkpoints predate the structural rename and were not rerun. This is not arbitrary WebVTT/subtitle compatibility.
  • Canonical progress, favorites, ratings, playlists, duplicate-preserving play queues, fragments, and stable bookmark/highlight/note annotations shared by native and compatibility adapters where the wire protocol exposes the corresponding state. The OpenSubsonic bookmark projection and Audiobookshelf user view now share canonical bookmark records instead of protocol-local copies; OpenSubsonic creates are bound to the exact current artifact.
  • Independent canonical Continue Listening/Reading suppression, currently exposed through the Audiobookshelf book/EPUB adapter. Podcast continuation reads are tested, but podcast hide and a native suppression endpoint are not.
  • Exact authorized artifact delivery with GET, HEAD, validators, and bounded byte ranges. Backend paths and blob storage keys do not cross API boundaries.
  • A native authenticated API and an embedded local-first web client (docs/web-client.md), plus the bounded protocol surfaces listed below.
  • A native Rust/AppKit macOS source application with an honest open/loading/empty/error state machine, a default embedded canonical LibraryStore endpoint, and an optional typed native-API client. Local status, browse/detail, exact-artifact progress, and path-free content descriptors do not cross REST. Its persistent AppKitPresentationHost retains one presentation session, exact binding, logical player, and native AVPlayer while View > Presentation exposes Library then all five ViewMode::ALL projections in order: Video with Transcript, Article, Book, Audio, and Audio with Transcript. Only Video with Transcript owns AVPlayerView; the audio surfaces use standard NSButton, NSSlider, and NSTextField controls bound to the same player. The bounded Article surface is a standard selectable/searchable NSTextView with native Cmd-F Find-bar proof; Book uses one retained NSPageController, three in-memory pages, standard Previous/Next Page menu commands, Page Up/Down keys, boundary validation, and page restoration across Book -> Audio -> Book. Outside preview mode, selecting an authorized playable record prepares its exact current original/derived artifact off the main thread, verifies the complete local CAS object, and installs one retained AVPlayerItem through private range delivery. A generated WAV runtime proves explicit-row activation, native play/pause, atomic canonical progress+session checkpointing, a bounded active-playback Quit flush, relaunch restore, resume, and native-end completion. Native rate/time-jump/end notifications, periodic observations, and seek completions from any AVFoundation callback queue are bound to the current generation/item; checkpoint replies are generation/session/item bound. A failed restore preserves the durable cursor until a later explicit native jump succeeds; finite end clamps to exact duration, while unknown-duration end stops without inventing completion. Current exact-artifact progress supersedes a stale native session. Switching A to B pauses/checkpoints/revokes A before B, while any checkpoint failure retains A. A disposable second 12-second WAV proved explicit A-to-B-to-A switching with distinct SQLite rows: B began at 00:00 and A restored exact 00:45. This was not a concurrent-race stress test. Separately, a non-destructively imported 12-second, 1280x720 H.264/AAC MP4 plus a three-cue derived VTT proved real video frames, exact cue taps at 4 and 8 seconds, transcript follow/highlight, atomic 1/3 and 2/3 progress, a View-mode swap, and fresh-process restoration of the exact media/transcript session and search query in an earlier captured ad-hoc run. A pre-structural-rename run then set the native Audio slider to 250,000 and reached exact 3.000-second/25% AVPlayer and canonical progress, user-progress revision 11 and session revision 68. Lifecycle Quit exited zero; fresh-process explicit activation restored exact 0:03/250,000, and View > Video retained exact 3.000 seconds/25% with the opening cue selected while both revisions remained unchanged. This pre-rename capture validates those zero-tolerance seek paths; the current source coverage is the 99-test AppKit suite, and the earlier 3-second-to-about-2.0089-second/17% result is bug evidence. Pre-rename restore proof and the preceding native audio scrub are from the same final bundle. The earlier restored search query had become durable at a later Stop checkpoint; current AppKit does not independently persist every portable mode/search snapshot effect. Earlier exact-cue evidence is the selected closing cue at 8 seconds. The MP4/VTT path does not prove audible AAC output, broad formats, AirPlay, remux/transcode, or released-application evidence; the repository-document proof below is a separate run.
  • A bounded repository-backed EPUB reader slice is implemented, source-tested, and runtime-validated. LibraryStore resolves one exact authorized EPUB for an ebook, article, or saved web page without exposing its CAS path; the document read independently verifies the complete BLAKE3 digest and length before and after its bounded whole-object read. The platform-neutral media-reader-core crate bounds the raw terminal EOCD and central-directory count/location before ZipArchive indexing, then uses rbook to decode only linear XHTML into inert semantic text. The AppKit endpoint installs that text in standard non-editable, selectable native text controls: one searchable scrolling NSTextView for Article and TextKit-measured semantic UTF-16 page containers retained by a standard NSPageController for Book. Both surfaces map their visible position to the exact arrange:epub-spine-utf16-v1 locator. Settled locator-only checkpoints write canonical progress and the exact presentation session atomically; they do not invent time, fraction, completion, or a page number. A page index is derived renderer state and is recomputed after reflow. The current workspace suite passes all 99 AppKit tests plus 13 reader-core unit tests and four reader-core integration tests. Strict clippy was not rerun after the structural rename. The root-library result from this exact tree is 700 passed with four opt-in tests ignored (704 total). An earlier fresh disposable fixture proved native decode/display, Cmd-F Find, an initial top checkpoint, and scrolling followed by lifecycle-Quit persistence at exact UTF-16 locator offset 1206 and revision 2. After a clean exit, the sidebar/content split changed before fresh-process explicit-row activation; a tagged reflow-relative viewport restored line 16 under changed wrapping without a spurious revision advance. The runtime checkpoint proved there is lifecycle Quit, not an independently isolated settled-scroll checkpoint. A pre-structural-rename run used record 064ddeb0-772e-4c0f-8fd2-a45333428a23 and exact 13,653-byte artifact c2b02d5e-c446-4235-99d2-57aa41b6d668. Next Page advanced progress to the newly visible Book location at spine 1 /EPUB/chapter-2.xhtml UTF-16 offset 1277; Book -> Article -> Book, inspector-hidden width reflow, lifecycle Quit, and fresh-process explicit activation then retained that exact locator. Progress remained revision 8; session 019675fc-08ef-4dc3-af20-1bfa356396c0 remained revision 13, surface epoch 3, mode paginated_book, with derived page index 0 under the wide layout and no restore-time revision drift. Current pagination audit. This does not prove EPUB CFI, CSS or image rendering, script/network execution, DRM support, arbitrary-EPUB compatibility, named-client pagination, VoiceOver, or UIKit-family rendering. Current renditions are attempted first; only an exact ebook progress/session pin may intentionally reopen immutable history. A final Stop failure remains sticky and cancels Quit rather than acknowledging termination after losing the final visible position.
  • A pure-Rust media-client-core presentation session for five swappable native modes: video with synchronized text, scrolling article, paginated book, audio-only, and audio with synchronized text. All 26 reducer/host tests pass in the current workspace suite; the strict-clippy checkpoint predates the structural rename. The tests prove numerically exact content-bound coordinates, transactional reduction, pinned bidirectional maps, requested rather than assumed seeks, bounded timed and exact-document checkpoint/snapshot effects, content/host capability intersection, a settled exact DocumentCursorObserved intent and distinct CheckpointDocumentProgress effect, the rule that page/pixel viewport hints never become canonical progress, hardened serialization, and preservation of one player/cursor/search/selection session across mode swaps. The AppKit preview renders all five fixture modes through that boundary. Separately, the repository-backed EPUB path uses both scrolling Article and TextKit-paginated Book surfaces, emits exact document-cursor observations, and connects locator-only checkpoint effects to canonical ProgressService. The page number stays renderer-local while both surfaces share the exact semantic locator. The exact boundary is machine-readable in first-party-presentation-v1.json. The strict transcript and repository-companion boundary is documented in transcript-core.md and transcript-core-v1.json.
  • A real native UIKit-family executable reuses that portable contract. Its first bounded slice is intentionally one bundled Article fixture in a standard safe-area UITextView. Before the structural rename, iOS device/simulator, tvOS Simulator, and visionOS Simulator targets compiled; iOS and visionOS simulator bundles were deterministically packaged and ad-hoc signed; and that visionOS bundle launched, fresh-process relaunched, and visibly reflowed at the largest accessibility text size. The current workspace suite passes 21 UIKit unit tests plus five article-source integration tests, but the cross-target checks, packaging, and runtime were not rerun. This is not repository delivery or proof of the other four modes, iPhone/iPad/tvOS runtime, VoiceOver, or a physical device. See the pre-rename runtime audit and uikit-native-v1.json.
  • An opt-in Manifest V3 Chrome recorder whose normalization and delivery-policy core is Rust/Wasm, plus an all-Rust Chrome native host/AppKit broker and a least-privilege HTTPS fallback. The server fixture proves principal-scoped/idempotent page activity and a generated YouTube-descriptor -> explicit-original -> canonical-progress -> Jellyfin projection across restart. Native framing/host/ACK policy is focused-test validated, but no live Chrome host was installed and no released-browser workflow is claimed.
  • Browser sign-in through the compatible.systems OpenID Connect provider, mapped to a Media-owned hashed, expiring, revocable SQLite session. The deployment permits exactly one configured identity; compatibility protocols retain their own credential shapes and HTTP Basic remains available for native API tooling.
  • A vendored native Rust Audible source with explicit external-browser account authorization, catalog scanning, user-authorized acquisition, retained encrypted originals, and receipt-bound derived M4B import. The Media acquisition path is feature-gated on FFmpeg and records exact original-to-M4B lineage; its current proof is a credential-free 66-record local-catalog dry-run, unit and persistence-lineage tests, and a DRM-free generated-audio native remux/decode test—not a live provider run.
  • Authorized local handoffs for Libation output and exact RSS snapshots with explicitly mapped enclosure files.

Supported clients

The evidence tier matters as much as the client name.

Client Surface Evidence Validated workflow Important boundary
Calibre calibredb 9.8.0 Calibre CDB Released named-client proof Discovery, list, built-in list_categories, bare-term search, show_metadata, and exact imported EPUB/stored-cover export Principal isolation is proven by the real-TCP fixture; this read-only subset has no custom/user/saved categories and is not the Calibre GUI, Content Server reader, or library mutation API
Amperfy 2.1.0 OpenSubsonic Released named-client proof Login, ID3 album/track browse, generated MP3 identity playback, scrobble, server restart, and incremental refresh Self-only getUser feature negotiation, the canonical legacy folder hierarchy plus legacy search2/getAlbumList/getStarred, randomized and deterministic genre song discovery, exact-current-artifact unsynchronized songLyrics v1, playbackReport/getNowPlaying, bookmarks, playlists, and baseline/index-based play queues are real-TCP request-tested, but were not called in the released run; favorite, rating, podcast, synchronized/enhanced lyrics, offline, download, and transcode workflows remain request-tested or open
Infuse Direct Mode 8.4.8 Jellyfin 10.11.11 shape Released named-client proof Connect; flat film browse/detail; exact generated PNG Primary-artwork fetch/render; generated H.264/AAC range playback; bounded TV Shows -> Series -> Season selector -> Episode detail traversal; artifact-bound progress; and Media restart plus Infuse relaunch with visible 10-second resume The named TV proof is one generated three-season fixture and its exact traversal/play/resume sequence, not broad television compatibility. Artwork transforms/dimensions, ACL/kind-first artifact-pinned Latest semantics, favorite filtering, atomic explicit watched/unwatched, and opt-in UDP discovery remain request-tested; search, Next Up, fabricated missing/upcoming rows, subtitles, real-subnet discovery, remux, transcode, and HLS are not claimed
Prologue 2026.4.23 Audiobookshelf 2.35.1 shape Released named-client proof, partial Login, generated grouped two-file catalog/detail, authenticated ranges from both M4As, file-boundary seek, durable progress, non-destructive successor refresh, native/ABS readback, app/server restart, and exact resume checkpoint Explicitly not a compatibility claim; principal-scoped authorization and predecessor-session pinning are proven separately by request fixtures, not by Prologue; released-client authorization negatives, offline, bookmarks, and second-device gates remain
CrossPoint Reader 1.2.0 OPDS 1.2 + KOSync v1 Official-source simulator plus source-exact request proof Authenticated Atom browse, protected EPUB acquisition with exact bytes, KOSync auth, simulator-tested sampled-content identity, source-exact projected-filename identity, progress GET/PUT, and authorized canonical binding No released firmware or physical X4 proof; filename identity deliberately fails closed across same-name immutable revisions; TLS behavior on hardware remains open
BookShelves 1.0.32 OPDS 1.2 Released-app prerequisite plus client blocker Test Connection sends HTTP Basic and parses the root title; the saved catalog's browse request omits Authorization and receives 401 Released-client saved-profile authentication is blocked in this build before navigation, search, acquisition, or rendering; the traced failure is not a Media protocol incompatibility or a support claim
Readest 0.11.20 OPDS 1.2 + OPDS 2.0 Released named-client proof, bounded generated-media slice Basic-authenticated saved catalogs; OPDS 1 root/books/complete-entry/OpenSearch, protected cover, and exact EPUB acquisition; OPDS 2 root/publications/detail/search; rendered cover, both chapters, and an internal link; offline app restart and post-Media-restart catalog reload Generated ebook only; not article/web page, Digest, PSE, auto-download, generic progress, broad navigation/facet/pagination coverage, or full OPDS compatibility
Media native macOS source app Native AppKit + embedded Media core/SQLite; optional native API v1 endpoint Current source: 99/99 AppKit tests in the workspace suite; native runtime evidence predates the structural rename Explicit native row activation resolves and verifies exact authorized artifacts, retains private range delivery beside one AVPlayerItem, and atomically checkpoints canonical progress plus the sealed session. The generated-WAV run proved pause, bounded active-playback Quit, relaunch/resume, native end, and A-to-B-to-A isolation. A 12-second H.264/AAC MP4 run with a provenance-qualified VTT proved real frames, exact 4s/8s cue taps and follow, 1/3 and 2/3 progress, View swap, and relaunch session/search restoration. The pre-structural-rename bundle set native Audio to exact 3.000s/25%, exited zero, restored exact 0:03 in a fresh process, and retained 3.000s/25% plus the opening cue after View > Video without advancing progress/session revisions. Pre-rename restore proof, native Audio companion, and earlier closing-cue proof. The pre-rename repository EPUB run added TextKit-measured Book pages: Next Page advanced to its newly visible exact locator, which Article/Book swaps, reflow, lifecycle Quit, and fresh-process restoration then preserved. Pagination runtime audit. Current source additionally centers Article/Book text within a 680pt maximum measure, applies native paragraph spacing before TextKit pagination, and adds visible SF Symbol Previous/Next controls plus a derived Page n of m value; this post-runtime polish is source/test-reviewed, not a fresh AppKit capture. Current AppKit does not independently persist every portable mode/search snapshot effect; the earlier search restore depended on a later Stop checkpoint. The synchronized-video runs do not prove audible AAC output, arbitrary codecs/WebVTT, remux/transcode, or AirPlay. The EPUB run does not prove a separately isolated settled-scroll checkpoint, CSS/images/CFI/DRM/arbitrary publications, named-client pagination, or VoiceOver. The UIKit-family slice has a bounded pre-rename visionOS Simulator Article lifecycle, but not repository sync, the other four modes, iPhone/iPad/tvOS runtime, physical-device, Developer ID/notarized installed lifecycle, named-client, or released-app proof. Strict clippy, a standalone Cargo check, packaging, runtime, signing, and notarization were not rerun after the rename.
Media Chrome recorder source bundle Chrome native messaging to AppKit; optional native web-activity HTTPS fallback 14 recorder tests + 11 native-bridge tests in the workspace suite; separate real-TCP server proof Opt-in URL/title/dwell/page/media events; persist-before-send queue; one bounded native batch; exact ordered ACK; same-UID private socket and rotating capability; route-scoped HTTPS fallback; idempotent generated YouTube/Jellyfin progress bridge Revised native extension was not installed or run in Chrome; not Web Store published, automatic acquisition, or released Jellyfin/Prologue handoff proof; earlier Wasm/package acceptance predates the active-identity rename
Media Tauri peer experiment Tauri 2 + iroh arrange.media/info/1 Focused Rust unit and two-endpoint loopback proof Opens an embedded LibraryStore; read-only config/status IPC; data-directory-scoped persistent endpoint identity; bounded transport-authenticated peer-info handshake Not the current native macOS viewer; no signed/installed lifecycle, account enrollment, media/catalog/progress over iroh, separate-process/device or relay proof, social grants, source racing, or BLE
KOReader-shaped independent harness Calibre wireless Request-level simulator proof One-shot exact EPUB push, reconnect, already-present handling, revocation, corruption, wrong-password, and timeout cases Not upstream KOReader and not a released-client result; no discovery or general wireless synchronization
AudioBooth, official Audiobookshelf mobile, Still, Thorium, Pageo, Panels, physical Kobo, and released KOReader Several target surfaces Request-tested or pinned-source prerequisites only Real-TCP fixtures cover bounded request shapes; some installed bundles or pinned sources were inspected No end-to-end named app/device workflow; Panels 3.13.2 gated OPDS configuration behind a subscription before sending any request, so that run provides no Media interoperability result

Details and reproducible evidence are in named-client validation. The first-party source boundary is documented separately in the native macOS application and its capability manifest.

Supported protocols

Every row is a bounded subset. HTTP Basic credentials must travel over HTTPS outside loopback; Media currently expects TLS termination at a trusted reverse proxy.

Surface Authentication Library and byte-delivery scope Progress or mutable user state Evidence
Media native API v1 compatible.systems OIDC to a Media-owned browser session; HTTP Basic retained; route-scoped opaque Bearer only for web-activity ingestion; canonical persisted principal All canonical kinds; status, search/list/detail, upload/import, podcast views, web-activity descriptors, and authorized exact artifact GET/HEAD/range Canonical progress, favorites, ratings, playlists, exact-artifact duplicate-preserving play queues, fragments, append-only annotations, and idempotent page/media activity; duration-matched video activity can write canonical progress Real-TCP request-tested subset, including the browser-activity bridge, plus the focused optional AppKit HTTP-client proof; the native app uses its embedded endpoint by default; OIDC has a loopback integration proof, while live-provider proof is recorded separately
OpenSubsonic 1.16.1 Username plus salted token; legacy clear/enc: password shapes; self-only getUser capability projection Music ID3 browse/search; legacy search2, getAlbumList, and getStarred; principal-scoped getRandomSongs and deterministic getSongsByGenre; a canonical logical artist→album→track hierarchy; exact-current-artifact unsynchronized songLyrics v1; current materialized podcasts; cover art; exact identity stream/download Transactional scrobbles; canonical exact-artifact playbackReport state/progress and principal-scoped getNowPlaying; playlists, favorites, 15 ratings, bookmarks, and baseline plus duplicate-safe indexBasedQueue play queues Named Amperfy identity-stream subset plus bounded request-tested extensions; the legacy trio and both song-discovery methods are independently deserialized by opensubsonic 0.4, but they and the other listed extensions are not yet released-Amperfy runtime claims
OPDS 1.2 HTTP Basic Unified ebook, EPUB-bearing article, and EPUB-bearing web_page navigation/search/entries/covers and authenticated exact acquisition with HEAD and range; capture HTML/WARC is retained but not advertised as a reader acquisition None; OPDS Progression is not implemented Released Readest generated-ebook proof, real-TCP plus CrossPoint source-simulator proof; the multi-kind projection remains request-tested only
OPDS 2.0 HTTP Basic The same unified publication catalog as OPDS 1.2, with JSON publication detail, schema.org EBook/Article/WebPage types, covers, and exact acquisition None; no OPDS Authentication document or Progression Released Readest generated-ebook catalog/browse proof plus multi-kind request proof
KOSync v1 X-Auth-User + client MD5 wire key backed by a separate Argon2id verifier; registration closed by default No catalog or bytes; pair with OPDS Opaque KOReader XPointer, fraction, device, and receipt time; uniquely matched and currently progress-authorized document identities (ebook, article, or web_page) materialize canonical progress, while non-document identities remain opaque external state Real-TCP plus CrossPoint source-simulator proof
Calibre CDB 9.8 HTTP Basic Read-only discovery/list/search/metadata, principal-scoped authors/series/publisher/languages/formats/identifiers categories, and exact selected format/stored-cover export None; category reads do not mutate source media or progress Released calibredb proof
Calibre Content Server 9.8 HTTP Basic; Digest absent Bounded /mobile, book detail, exact EPUB/cover GET/HEAD/range Exact-artifact EPUB CFI/fraction by device plus additive EPUB highlights and exact-title bookmarks mapped to canonical append-only annotations; exact bookmark wire objects pass canonical provenance-shape validation before entering a lexical-LWW intent journal; canonical mutations, projection append, and lifecycle reservation are latest-intent guarded; stable GETs SQL-preflight settled state and recovery walks the complete registry up to 4,096 rows; a full registry rejects a successor-requiring active before journaling; raw title fidelity, race reconciliation, and artifact replacement preserve history Real-TCP request-tested, including pre-persistence NUL-poison rejection, first bounded-GET restart recovery, cleanup-tie safety, user isolation/replacement, and two no-ghost interleaving proofs; direct application proof covers stale-canonical-revision rejection, while control-key and wrapped-node-budget rejection are focused-test evidence; exhaustive 4,096-row cap filling, startup scan, and released-reader validation are not claimed
Calibre wireless 9.8 Dedicated high-entropy password over raw TCP; trusted LAN or authenticated tunnel required Principal-bound one-shot push of one exact EPUB from a verified private spool None Independent request-level harness; no released KOReader proof
Calibre-Web Kobo shape Digest-only bearer capability in the issued URL Local EPUB initialization/snapshot/archive-change sync, metadata, stored cover, and exact original EPUB Principal-scoped archive and reading-state GET/PUT with canonical progress mapping Real-TCP request-tested; no physical Kobo proof
Audiobookshelf 2.35.1 shape Persisted local users with Argon2id password verification; principal-bound opaque expiring Bearer/query access tokens and identity-preserving rotating refresh tokens, not JWT Grant-scoped mixed audiobook/EPUB library, current materialized podcasts, exact per-file/EPUB bytes, ranges, and direct/live/local sessions Transactional actor-scoped audiobook/EPUB/podcast progress; durable book/EPUB continuation suppression; podcast continuation read projection; account-wide in-progress projection, sessions, bookmarks, and per-user Socket.IO rooms with event-time access-lease revalidation Partial released-Prologue two-file/boundary/successor/restart run plus broad real-TCP request proof, including two persisted users; released-client authorization/offline/bookmark/second-device and Socket.IO gates remain open
Jellyfin 10.11.11 shape MediaBrowser device login; opaque MediaBrowser/Emby token Opt-in bounded UDP LAN discovery; flat film/video catalog plus an ACL-scoped TV Shows -> Series -> Season -> Episode hierarchy, including explicit season-zero specials, with parent-scoped /Items and /Shows routes; parent display metadata/search/timestamps are derived only from readable current-artifact episodes; bounded ACL- and exact-kind-first artifact-pinned Latest plus ACL-safe Resume; authorized exact stored Primary artwork; and original-only direct play/range for playable items with bounded ISO-BMFF stream/profile projection Tick-based progress/completion, transactionally exact watched/unwatched and LastPlayedDate, play count, canonical favorites/filtering, readable-current episode rollups on seasons and series, and parent ETags that cover projected metadata, counts, and rollups Named Infuse flat-film, exact Primary-artwork, and bounded generated-TV traversal/play/restart-resume subsets plus broader real-TCP request/loopback-UDP proof; TV search, rollups beyond the observed selector/detail views, transforms, dimensions, discovery, explicit watched/favorite state, and broader shelf semantics remain request-tested or open rather than released-client proof
WebDAV class 1, read-only HTTP Basic Stable canonical paths for every media kind; PROPFIND, exact GET/HEAD, and one byte range None; reads never imply progress Real-TCP request-tested; no OS mount/released client gate

The native API is intentionally richer than any compatibility surface. A client can upload media, inspect canonical provenance and lineage, and use stable annotation/fragment coordinates even where a legacy client protocol has no equivalent operation.

Supported source and catalog adapters

Discovery is deliberately separate from acquisition: a catalog record can be browsed without implying that Media may download, copy, or share its bytes.

Source or catalog Current evidence Implemented boundary Not yet claimed
Local filesystem Integration-tested Non-destructive recursive scan, immutable CAS ingest, provenance, rescan reconciliation; explicit --kind television recognizes only narrow Series[/Season NN]/SNNENN paths and fails closed on mismatches Filesystem watching, broad TV filename guessing, and very-large-library benchmark
Native Audible source Credential-free dry-run of Conrad's current 66-record catalog, fixture/unit and exact-lineage persistence tests, plus a pinned native-FFmpeg feature build and DRM-free generated-audio remux/decode test Vendored Rust account/catalog/acquisition code; external-browser authorization; complete encrypted AAX/AAXC retention; receipt-bound FFmpeg-derived M4B import No live Media login, provider scan, encrypted Audible download/decrypt/remux, or named-client playback proof; the default deployed container excludes the acquisition FFmpeg feature
Libation handoff Fixture/integration-tested Separate read-only import of an external Libation catalog and completed outputs; no account state, license, or decryption handling It does not acquire or convert Audible content
Local RSS + enclosure handoff Fixture/integration-tested Exact feed snapshot and explicit local enclosure map General network podcast downloader
YouTube via explicit yt-dlp Focused Rust proof, 4/4 One credential-free video; strict YouTube identity normalization; direct HTTP(S) representation; concurrently drained output retaining at most 8 MiB metadata/64 KiB diagnostics; typed safe projection; immutable original import; fake-executable reconciliation with an earlier browser descriptor No live-provider run, browser cookies/private access, playlists/channels/live streams, adaptive merge, captions/comments/thumbnails, subprocess timeout/cancellation/total-output governance, scheduler/worker, named-client playback, or terms-policy proof
Substack public publications Local real-TCP request-tested Public /feed discovery for article/web, audio, video, image, and conservative YouTube presences; descriptor-only acquisitions Private feeds, archive pagination, undocumented JSON APIs, authenticated browser capture
MusicBrainz + Cover Art Archive Local real-TCP provider request tests plus in-process application persistence Exact release lookup, bounded evidence, exact-release cover candidate fetch, CAS/provenance Live-provider CI, fuzzy search, complete descriptive-field resolution
Open Library Local real-TCP request-tested Exact ISBN edition evidence and strictly bound cover fetch Application coordinator, bulk catalogs, search, live-provider proof
Chromaprint + AcoustID Local computation, persistence, and real-TCP request tests Exact-artifact fingerprint; official read-only lookup returning unaccepted candidates Live-provider proof, scheduler, submissions, automatic release choice
Project Gutenberg, Standard Ebooks, Internet Archive, Aozora Bunko, Biblioteca Nacional Roadmap only Provider contracts and acquisition/rights rules are documented No backend adapter or compatibility claim yet
Authenticated publishers such as WSJ or The Information Focused real-SQLite persistence and article-ingest tests; Linux-tested Safari source runtime; iOS device-target adapter compile/link harness Typed auth-identity reference; immutable public/authenticated/user-export capture versions; exact source-observation/artifact/blob binding; credential guards; explicit rendered-document handoff through the Safari source runtime or pure-Rust iOS adapter into the fixed article-capture route No automated login, released signed Safari container, installed iOS runtime, WARC writer, paywall bypass, or end-to-end live-site proof

Catalog/provider scope, authenticated capture rules, work/version identity, and composition are detailed in catalogs, captures, versions, and compositions.

The Audiobookshelf authorization fixture logs two independently persisted users through one real TCP server. It proves identity-preserving refresh, distinct book catalogs and non-disclosing detail/byte denial, readable-only versus progress-capable grants, transactional progress/session/bookmark enforcement, revoked-session byte denial without checkpoint loss, restart persistence, and Socket.IO delivery only to the actor's user room. Cross-principal reuse of an existing local-session ID returns a non-disclosing 404 without mutating progress; the trusted internal store boundary retains an explicit conflict outcome. A change to an actor's item grant participates in that actor's Library.lastUpdate, but Media does not emit an automatic Socket.IO event for the grant change. A separate two-private-episode partial-grant real-TCP negative proves that expanded podcast session payloads retain only the exact authorized episode and omit the ungranted sibling. Neither request-level nor source-simulator evidence is a released Prologue multi-user run. Media still lacks the complete Audiobookshelf roles/library-ACL model and Audiobookshelf-protocol OIDC. A Socket.IO connection retains no raw bearer secret and revalidates its non-secret credential lease before every protected user/progress/session event. Expired or revoked sockets fail closed before receiving the payload; idle periodic expiry cleanup and released-client Socket.IO validation remain open.

Architecture and invariants

The server is fully Rust: Axum at the HTTP edges, SeaORM/SQLite for durable canonical state, and trait-based application and blob-storage boundaries. The native macOS app uses those Rust application/store boundaries in-process; Axum and REST are not between AppKit and its local SQLite repository. Network workers synchronize repositories and expose optional remote/admin or compatibility surfaces. Media separates canonical truth from protocol projections:

  1. Sources and imports discover authorized files or exported provider output and record source identity and provenance.
  2. Blob storage preserves exact bytes in an immutable local BLAKE3 CAS behind a pluggable BlobStore boundary.
  3. Canonical SQLite records model items, metadata, grants, originals, derived artifacts, lineage, presentations, progress, fragments, and annotations.
  4. Application services enforce authorization, idempotency, optimistic revisions, progress semantics, and artifact-safe coordinate mapping.
  5. Adapters translate those records into native HTTP, OpenSubsonic, OPDS, KOSync, Calibre, Audiobookshelf, Jellyfin, and WebDAV shapes.

The invariants are deliberate:

  • Source media is never renamed, moved, retagged, converted in place, or deleted. A rescan can mark a source object unavailable; it does not erase its canonical record, artifact history, or blob.
  • Originals and derived outputs are distinct immutable artifacts. Every derivative retains explicit parentage, recipe/version, and provenance even if a future backend deduplicates storage chunks.
  • Television semantic identity is resolved from series, season, and episode coordinates before byte-level deduplication. Identical bytes at different coordinates are distinct episode records that may share one CAS blob; alternate originals at one proven coordinate are separate artifacts on one episode record.
  • A globally scoped extra.series_identifier = {namespace, value} can join a series across sources; Media canonicalizes and hashes the two-field tuple, so delimiter-bearing namespaces and values remain unambiguous. Without it, a new series identity is deliberately provisional and source-scoped: a hashed source_series_identifier is preferred, then source plus normalized title. Same-title series from independent sources are not silently merged; explicit IDs or a later matching/merge operation are required to establish that equivalence.
  • SQLite is authoritative for identity, relationships, authorization, visibility, progress, and metadata. A blob path is never an access-control decision.
  • Progress is artifact- and presentation-aware. Media does not silently join a coordinate from old bytes to a fraction from a replacement artifact.
  • Protocol IDs, timestamps, locators, and client-specific tombstones remain adapter state unless they can be mapped honestly into the canonical model.
  • Unsupported operations fail explicitly rather than returning persuasive but fake success.

See architecture, metadata, storage, fragments and coordinates, and the shared client-core plan.

Quickstart

Prerequisite: Rust 1.91 or newer. The workspace MSRV follows iroh 1.0.3, which is used by the bounded desktop peer-info transport.

For the optional libav media engine and native Audible derivation path, enter the pinned Nix shell and run its feature suite. The default server build—and the currently deployed thin protocol-export container—does not include system FFmpeg or provider acquisition:

nix develop
cargo check --locked --features ffmpeg
cargo test --locked --features ffmpeg media_engine --lib
cargo test --locked playback_delivery::tests --lib

Import a local library. The source files remain untouched:

cargo run -- import --library /path/to/media

For a television root, opt in explicitly:

cargo run -- import --library /path/to/tv --kind television

That forced mode recognizes conventional Series/Season 02/S02E07 - Title and Series/Series.S03E04.Title paths, including season 00 specials. A season directory that disagrees with the filename, or another ambiguous layout, stays an unstructured television item; an ordinary video scan never guesses a TV hierarchy. The relative series directory becomes source_series_identifier; Media stores only its BLAKE3 digest inside the source-scoped provisional series key. Installations upgraded from before migration 0034 must complete a successful television rescan to populate the hierarchy because the migration does not infer missing parents from existing rows.

The default durable state directory is .arrange/; pass the global --data-dir /path/to/state option before the subcommand to use another location.

Start a loopback server, optionally rescanning roots first:

read -rs -p 'Media password: ' MEDIA_PASSWORD
export MEDIA_PASSWORD
cargo run -- serve \
  --library /path/to/books \
  --library /path/to/music \
  --username conrad \
  --bind 127.0.0.1:3000 \
  --public-base-url http://127.0.0.1:3000

Then open or configure:

  • web UI: http://127.0.0.1:3000/ui/
  • native API: http://127.0.0.1:3000/api/v1/
  • OpenSubsonic/Audiobookshelf/Jellyfin server base: http://127.0.0.1:3000
  • OPDS 1.2: http://127.0.0.1:3000/opds
  • OPDS 2.0: http://127.0.0.1:3000/opds/v2
  • WebDAV: http://127.0.0.1:3000/dav/
  • Calibre CDB remote library: http://127.0.0.1:3000/#arrange

Use the configured username and MEDIA_PASSWORD where the surface uses HTTP Basic or local login. The default bind is loopback. Do not send Basic credentials over non-loopback plain HTTP; terminate HTTPS at a trusted reverse proxy before remote use.

Inspect durable counts:

cargo run -- status

Enrich one already imported, manageable music item that carries exactly one musicbrainz_release identifier. The command uses official read-only endpoints, requires the existing owner's password, and never rewrites the media file or its tags:

read -rs -p 'Existing owner password: ' MEDIA_PASSWORD
export MEDIA_PASSWORD
cargo run -- --data-dir /path/to/media-state \
  match-metadata \
  --item-id ITEM_UUID \
  --username conrad

An approved front cover is copied into the immutable CAS and selected only when no manual override or owned embedded/sidecar cover blocks it. See metadata and artwork matching for provider rights, rate, confidence, and roadmap boundaries.

Native Audible source and import handoffs

The audible commands use the vendored Rust provider source directly. Login is an explicit external-browser authorization flow; account state is stored outside the repository in a private, atomically updated local state directory. For example:

cargo run -- audible login --locale us
cargo run -- audible scan
cargo run -- audible import --dry-run
cargo run --features ffmpeg -- audible download --asin B00EXAMPLE

audible import --dry-run is deliberately offline: it parses the non-secret catalog and inventories only completed retained originals/renditions without opening credentials, copying bytes, or modifying source state. A local run parsed all 66 records in Conrad's current catalog and found no completed files in the configured ready directories. Fixture and persistence tests prove that a complete encrypted original and its M4B are imported as separate immutable artifacts with an exact receipt-bound derivation edge. They do not prove a live Media login, provider scan, download, FFmpeg decrypt/remux, or playback in a named client.

When built with --features ffmpeg, the direct Media path passes the provider-issued Audible key/IV or an explicitly supplied classic-AAX activation value to libavformat in-process through an option dictionary; it does not place those values in a child-process argument list. Complete encrypted provider bytes are retained before the derived M4B is published, and neither file replaces the other. The Media path does not automatically obtain classic activation bytes: that value must already be present through an explicit user-authorized account import. This is authorized processing of the user's accessible content, not credential extraction or access-control circumvention.

Import an existing user-authorized Libation output/catalog:

cargo run -- import-libation-handoff \
  --libation-dir "/path/to/Libation support directory"

Add --dry-run to validate the allowlisted schema and print aggregate counts without copying media or creating Media state. Close Libation first: Media rejects direct catalog access while SQLite WAL/journal state could make the snapshot inconsistent. The adapter reads no Libation account credentials, tokens, logs, or licenses.

Import an exact local RSS snapshot and enclosure files already obtained through an authorized handoff:

cargo run -- import-podcast \
  --feed /path/to/feed.xml \
  --enclosure-map /path/to/enclosures.json

The enclosure map is a JSON object from each exact HTTP(S) enclosure URL in the feed to an existing local file. Media does not fetch the network or follow file:// URLs in this path. See podcast import and source adapters.

Explicitly acquire one public, credential-free YouTube video through an absolute trusted yt-dlp executable path:

cargo run -- --data-dir /path/to/media-state import-youtube \
  --url 'https://www.youtube.com/watch?v=VIDEO_ID' \
  --yt-dlp /absolute/path/to/yt-dlp

This is a single-video original import, not a background channel sync. It does not read browser cookies, use a shell, merge adaptive streams, transcode, or claim private/age-gated access. The development shell provides yt-dlp; the thin deployed server image intentionally does not. See source adapters.

Build the opt-in Chrome activity recorder separately:

./crates/web-recorder/build-extension.sh

Native-first delivery additionally requires an explicitly rendered exact-ID host manifest; the repository does not install it into Chrome automatically. An optional HTTPS fallback token can still be issued with media recorder issue; it authorizes only POST /api/v1/web-activity/events and cannot read the catalog or media. Load crates/web-recorder/extension, choose delivery settings, and explicitly enable each origin. Build, privacy, registration, and evidence boundaries are in Chrome recorder.

Run the native Rust/AppKit macOS application against its local canonical repository. Ordinary browse/search is embedded Rust-to-SQLite, with no REST CRUD or local server between AppKit and the database:

cargo run -p media-appkit

The default repository is ~/Library/Application Support/website.content.media. Existing installs use ~/Library/Application Support/media.revisit.arrange only when the canonical path is absent.

Select an explicit repository for development. An optional username must already exist in that repository; it enables authorized progress writes but is never created as a launch side effect:

MEDIA_DATA_DIR=/path/to/media-state \
MEDIA_USERNAME=conrad \
  cargo run -p media-appkit

Run cargo run -p media-appkit -- --preview for an explicitly labelled, no-repository layout fixture. An optional typed HTTP endpoint remains available for remote/admin use, not ordinary native persistence. In normal repository mode, selecting an authorized playable record prepares and retains its exact artifact in AVPlayer; native observations feed canonical progress, and pause/interval/end/lifecycle checkpoints persist progress and the exact presentation session together. Portable mode/search snapshot effects do not independently write SQLite in current AppKit; a crash while paused before a later explicit checkpoint can lose those newest UI-state edits. The hardened runtime proof used only explicit row activation: native pause committed 14.924 seconds, app-menu Quit during active play boundedly flushed exact 35.480997541 seconds, a fresh process plus explicit row activation restored 00:35/79%, and native end committed exact 45 seconds. Preview Article/Book surfaces remain in-memory layout fixtures. In normal repository mode an explicitly selected eligible EPUB is instead authorized and fully verified, boundedly decoded to inert linear text, installed in the standard Article NSTextView, and checkpointed with an exact artifact-bound UTF-16 spine locator. That repository-reader path is presently source-tested and boundedly runtime/relaunch proven: lifecycle Quit persisted the exact locator and session, exited zero, and fresh-process explicit activation restored the same visible line without revision drift. The run did not separately isolate the 400 ms settled-scroll checkpoint. Repository Book remains disabled. Create a deterministic non-destructive development fixture with:

cargo run --example seed-reader-proof -- \
  --data-dir /path/to/media-state \
  --source /path/to/media-reader-proof.epub \
  --username conrad

Supply --password (or MEDIA_PASSWORD) only when the named principal does not already exist. The QA bundle was locally ad-hoc signed. It was not Developer ID signed, notarized, installed as a release, or lifecycle-tested through an installer/update. See the native macOS app and reader core.

Run the separate bounded Tauri peer experiment against its platform data directory, or set MEDIA_DESKTOP_DATA_DIR to an explicit existing/disposable repository:

cargo run -p media-desktop

The current window reads configuration and canonical library counts. Its iroh 1.0 endpoint exposes only the bounded arrange.media/info/1 identity handshake and explicitly reports application_authorization=not_enrolled and media_access=false. A Tauri source build is not a signed, notarized, installed, or auto-updating application. Same-account/passkey enrollment, social grants, media transfer/racing, continuous playback failover, and BLE remain planned; see desktop and peer sharing and the desktop capability manifest.

Media does not extract credentials or perform unauthorized scraping. Remote acquisition must use an explicit user-authorized provider flow, download/export, or local handoff. The native Audible source can process provider-licensed AAX/AAXC bytes only for the authorized local account described above; the separate Libation handoff remains read-only and never opens Libation credentials or licenses.

Protocol setup commands

Issue a Calibre-Web-compatible Kobo endpoint after the server has initialized the user:

cargo run -- kobo issue \
  --username conrad \
  --public-base-url https://media.example

The returned URL contains a bearer capability and must be handled like a password. Save its 64-character token in a private file to revoke it without placing the token in shell history:

cargo run -- kobo revoke \
  --username conrad \
  --token-file /path/to/private-token-file

Calibre wireless transfer is a separate, opt-in raw-TCP listener. Create a secret and then offer one explicitly selected EPUB artifact:

cargo run -- --data-dir /path/to/media-state \
  calibre-wireless create-secret \
  --secret-file /path/to/media-wireless.secret

cargo run -- --data-dir /path/to/media-state \
  calibre-wireless send \
  --bind 127.0.0.1:9090 \
  --username conrad \
  --secret-file /path/to/media-wireless.secret \
  --item-id ITEM_UUID \
  --artifact-id ARTIFACT_UUID

There is no default wireless bind and no discovery. The protocol has no TLS or server authentication, so use only a trusted LAN or authenticated tunnel. Use the exact 64-character line in the secret file as the client password; it is password text, not hexadecimal data to decode.

For KOSync, temporarily start serve with --enable-kosync-registration, register a unique sync-only password from the client, then restart without the flag. Registration is loopback-only and closed by default. If a reverse proxy can reach that loopback listener, block POST /users/create for the entire registration window.

Deployment

The repository includes a single-Machine, single-encrypted-volume Fly.io deployment scaffold for SQLite plus the Garage/S3-compatible CAS. It is deliberately single writer and fails closed if /data is not a real mounted volume. The document covers app, volume, certificate, Forgejo secret, deployment, health-check, and recovery steps.

The current data-bearing source app remains untouched until its active import and verification finish. content.website is the sole supported public hostname. The empty conrad-media target receives a verified snapshot only under the documented cutover gate. Garage is authoritative for immutable media. Fly uses blob.8914.la for authoritative backend reads and writes; authorized bulk delivery may use short-lived signed blob.direct URLs, whose public Host is bound into the signature, so Fly is not in the media-byte path. The encrypted Fly volume continues to hold SQLite until database replication is independently proven. Do not scale beyond one Machine until writer coordination exists.

The longer-term sync target keeps the canonical Rust core and SQLite materialization in the native app. It does not run Celld locally. Celld may be an optional always-on relay/remote SQLite-LTX materializer, while an independent Media-owned BlobStore carries immutable media and repository objects. Celld is currently alpha, supplies neither Media user authentication nor public TLS, and is not a media object binding, so any deployment requires compatible.systems/TLS ingress, private Celld networking, and separate reviewed bucket credentials. No Media-on-Celld relay, repository synchronization, or direct signed client/object-store transfer has been validated. See repositories and sync.

Development and tests

Create a deterministic synthetic EPUB 3 fixture without personal media:

cargo run --example generate-opds-fixture -- \
  --output /tmp/media-opds-fixture.epub \
  --title 'Media OPDS Fixture' \
  --identifier 'urn:uuid:7c028d11-59df-4cdc-9226-829a905a0f82'

The output path must not already exist.

Run the complete local validation suite:

cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets

Many integration tests bind real loopback TCP listeners and compare delivered bytes with imported originals. Some sandboxed environments therefore require permission to bind a local port. Per-protocol fixtures, negative cases, restart guarantees, and named-client evidence live in the linked protocol docs and capability manifests rather than in this README.

For a credential-safe OPDS/Jellyfin client trace, add --client-trace /new/private/trace.jsonl to serve. Media creates the file once with private Unix permissions and refuses to overwrite it. It excludes bodies, credentials, cookies, arbitrary query values, and arbitrary headers. Dynamic Jellyfin identifiers are replaced by route placeholders; query names are allowlisted. Only bounded canonical enum/bool values for IncludeItemTypes, Recursive, SortBy, and SortOrder may be retained; unknown, conflicting, or private values fail closed and are omitted. Client-controlled or content-fingerprinting header values are recorded only as <present>. The earlier bounded OPDS header/query-name trace contract remains unchanged.

Major gaps

  • No background scheduler, live/in-progress HLS publisher, automatic playback-triggered remux/transcode policy, general subtitle conversion, cover resizing, or broad named-client adaptive-playback proof. The CMAF path is an explicit ahead-of-time CLI pipeline with authenticated first-party delivery; the narrower in-process whole-file fragmented-MP4 copy executor also remains. The selected-record AppKit/AVPlayer proof covers bounded generated WAV and direct H.264/AAC MP4 playback, not every CMAF representation, codec/container, Jellyfin path, or AirPlay route. The separate Audible acquisition worker can decrypt/remux an authorized source to a derived M4B.
  • The durable generation store can now atomically publish a bounded ordered set of verified CAS outputs with complete all-input lineage and exact replay, which is the repository seam later mask/foreground/composition workers need. There is still no video-frame decode or filtergraph executor, SAM/model runtime, segmentation mask generation, transparent-foreground output, compositor, background worker, or live fallback. libavfilter in the loaded engine descriptor reports linked capability; it is not an executed graph.
  • No complete compatibility claim for any target server ecosystem. Several important routes and named-client workflows remain open even where one bounded released-client slice passes.
  • No complete multi-user native authorization/administration, Audiobookshelf roles/library ACLs, LDAP, protocol-specific Audiobookshelf/Jellyfin OIDC, public sharing, offline repository synchronization, or published Rust client SDK. The implemented principal-scoped Audiobookshelf boundary is not an account-administration system. A native AppKit source app, bounded Tauri peer experiment, and Chrome-recorder source bundle exist, but none is a signed/published general media client; AppKit playback/readers, cache/outbox sync, and mobile shells do not exist yet.
  • Garage/S3 publication, verified reuse, and signed direct GETs are implemented and large-object gate-tested. Production database cutover and a real iOS range/seek smoke remain open. No read-through cache, rclone-backed storage, Xet snapshot runtime, proxy internal redirect, or Celld relay/materialization path is operational.
  • No direct Bandcamp acquisition or automatic podcast HTTP acquisition. Native Audible account/acquisition code exists, but its present evidence stops at a credential-free 66-record catalog dry-run, unit/exact-lineage tests, and a DRM-free generated-audio native remux/decode test: there is no live Media login or encrypted Audible download/decrypt proof yet, and the default deployed container intentionally excludes the acquisition FFmpeg feature.
  • Chromaprint computation and durable persistence components, AcoustID lookup, and exact-ISBN Open Library requests exist, but they are not yet one scheduled end-to-end matching job. There is no ShazamKit bridge, fuzzy cross-provider search, AcoustID submission, automatic candidate acceptance, or live-provider CI. The current automatic policy accepts only one exact MusicBrainz release ID.
  • Articles and saved web pages can be imported, and an already-materialized lineage-bearing EPUB rendition on either kind is exported through OPDS and can bind KOSync progress to those exact bytes. The bounded public-URL and explicit rendered-document paths now extract and sanitize derived reading HTML. WARC-to-article, article-to-EPUB, and text-to-audiobook workers remain planned pipelines, not shipped transformations.
  • No OPDS Progression/Auth document, physical Kobo gate, released KOReader wireless gate, Calibre Content Server rendered-book UI, complete Audiobookshelf offline/client gate, broader released-client Jellyfin TV, search, or Next Up gate, or Jellyfin subtitle/remux/transcode stack.

Unsupported behavior is designed and prioritized, not represented by shallow success stubs. See the protocol roadmap and product acceptance boundary.

Documentation

Product and architecture:

Canonical data, storage, and generation:

API and protocol boundaries:

Imports and operations:

License

Media, including the vendored libation-rs source, is licensed under the GNU General Public License version 3 or later. Vendored-source provenance and reviewed reference-code boundaries are recorded in third-party notices.