Skip to content
Documentation
Project

Server — App and API

Native client API

Read attributed library projections and local artwork, publish private M3U lists and run catalog-scoped media jobs.

For the graphical server application, its folder controls, HTTPS connection, status and logs, read the Aède App guide. This page documents the native client API used by applications such as Phémios.

Native clients use the existing account bearer authentication, JSON errors and bounded inspection workers. No origin exception or automatic enrichment is added.

Local catalog projection#

GET /api/v1/presentation/artists and GET /api/v1/presentation/albums return ordinary pages (offset, limit 1–200, total, items, scanned_at). Artist rows retain stable references, genre names, trusted origin with attribution, biography with its inseparable URL/language/licence, local image availability, release contributions and tag-derived collaborator links. Album rows retain compilations without inventing an album artist, contributing artists, local cover availability and a search projection of every raw tag field. The projection contains public catalog facts, never account annotations. Fields use snake_case like the existing API. Unknown origins remain null; no download is triggered by GET.

GET /api/v1/artwork?ref=TOKEN&kind=cover|portrait|logo|banner|background|spectrum&size=512 serves only images selected from the catalog or the existing artist artwork location. size is optional, bounded to 1–2048. Entity/kind combinations are validated. This endpoint reuses Subsonic's bounded, confined, opened-descriptor JPEG/PNG checks and response-only thumbnail generation. It never accepts a file path or external URL, writes a source image or redirects. Native transfers retain their admission permit through the actual rendering worker and until the response body is dropped. Cancelling or timing out an HTTP waiter cannot free that slot while its blocking work still runs; worker errors release it when that work finishes. Accounts are rechecked after rendering; missing/changed/unsupported images fail explicitly. Track detail additionally reports spectrum_available.

Artist availability and image reads also recognize the shared cache directories used by enrichment under a trusted MusicBrainz canonical artist ID or its verified merged alias. Local images remain preferred, including after retagging; local tags are never changed. Unreviewed, rejected or conflicting claims cannot supply these additional locations, and provider identifiers remain validated and confined below the artist cache. Ordinary reads stay offline and retain the same account checks, even when the cache is populated.

Own annotations and M3U#

GET /api/me/v1/annotations returns paged current-account annotations for resolved catalog entities; other owners and unresolved targets are excluded. The existing singular GET/PUT endpoint remains the editing contract. Private data stays outside public catalog projection and cache.

POST /api/me/v1/m3u accepts {"release":"TOKEN","name":"My album list"}. A mutable account is required. It selects the catalog release's ordered tracks, creates a private static playlist using the shared personal store, and publishes a new M3U inside data/playlists/OWNER/PLAYLIST-ID.m3u without modifying music folders. Paths and names cannot choose the destination. The response contains id, name, filename and complete content. GET /api/me/v1/m3u pages private playlist summaries; GET /api/me/v1/m3u/{id} renders a complete download for the current owner. Rendering preserves repetitions and fails on missing tracks or newline-bearing paths. Paths refer to the server's music files; portable copy-path mapping remains the copy engine's responsibility. Publication holds the store lock; a failed private-store save removes only the newly created file.

Explicit library:true additionally requires an administrator account and the administrative profile, over HTTPS or local HTTP. The shared CLI folder planner publishes the selected physical album folder and its complete principal-artist folder when that folder is inferable and is not a watched root. Names derive from folders and paths are relative; multiple editions/artists sharing a physical output are combined by the same rules as aede playlist. Destinations must remain under available catalog roots. Only M3U sidecars are regenerated through the shared atomic writer; source audio/tags are untouched. library_files confirms the destinations, and library_m3u_publication advertises the capability. A multi-file failure is explicit; earlier completed files and the private saved playlist may remain. Repeated identical owner/name/track selections reuse their private ID and recreate a missing private export; a different existing private file is never overwritten.

Explicit media jobs#

POST /api/admin/v1/analyze and POST /api/admin/v1/spectrum accept {"release":"TOKEN","force":false,"threads":2}. Administrator sessions may use these routes over HTTPS or local HTTP. release resolves to one catalog folder; arbitrary paths/arguments and unknown fields are refused. threads is optional, 0–64. force repeats cached analysis or redraws existing spectra. They return HTTP 202 with the existing task ID/status URL, and share task admission, polling, cancellation, bounded output and catalog refresh. An accepted task is not a completed task.

The CLI callback executes ordinary analyze --json-layout=album --show-results or spectrum with literal arguments. Analyses and spectra may create/update derived sidecars beside the server's music; audio and tags are unchanged. Test executions must use isolated copied music, not the owner's original library. Cancellation follows the existing administrative child-process policy.

Physical desktop playback, output selection and player copying remain separate client/device acceptance work; these read/projection/job endpoints do not implement them.

FlacCompagnon report downloads#

GET /api/v1/analysis/report?ref=TOKEN selects one current catalog track or release. HEAD validates the same selection without returning a body. The JSON response has the original flaccompagnon-report wrapper (format, version, report.root, report.files, report.has_flac) and an attachment filename. A track selects exactly its file entry; a release gathers distinct files in catalog track order, independent of whether original reports were stored per track, album or artist. All retained source-entry fields, including unknown future fields and original paths after relocation, are preserved. The root describes the selected catalog folder. Original sidecars are not reopened, and no scan, enrichment, re-analysis or filesystem write runs.

Each exported entry additionally carries the exact retained measurement date as the decimal string aede_result_at_ns, including "0" for an unknown date. This metadata uses the conclusion's date, even when a legacy source entry lacks it, so a later import does not promote an old result to the download's modification time. Original measurement fields and stored source data are unchanged; the field is added or normalized only in the response and counts toward its final size limit.

The existing account/read authorization and bounded inspection admission apply. Responses are no-store JSON with nosniff; the account is rechecked before returning. Only ref is accepted, for a track or release, never a path. Selection is bounded to 2048 tracks and 16 MiB. Missing entity/analysis returns 404; stale records, legacy records without complete source entries, or an unsupported schema return 409; oversized selections return 413. Albums with missing analyses are refused as incomplete rather than presented as a complete report. Import a complete newer report or explicitly run analysis to fill missing entries. Preserved error entries remain genuine source results; no measurement is invented. A file's validity uses the existing catalog size/mtime rule, not an extra live filesystem check.

Dynamic browsing collections#

A collection can retain a browse-v1: JSON expression with required view (artists, albums, compilations, countries, genres, rated, favourites), mode (none, years, alphabet, both), inclusive years/alphabet pairs, includeUnknownYear and query, plus optional countries (union of sourced origin strings or null), genre/genres, and the rated view’s required ratings pair (inclusive integers 1–5). Rated and favourites views use the current owner’s direct edition annotation or its principal album artist annotation, excluding incidental personnel. Ratings use the stronger value, matching the client; future annotation changes re-evaluate the saved interval. Rating bounds on other views are refused. Alphabet buckets are #=0 and A–Z=1–26. Hidden rails do not filter. Artist views match principal album artists and select their associated editions satisfying the other criteria; album views use album-title initials. Compilation view restricts editions explicitly labelled compilations. All selected editions contribute their complete track order.

The expression remains in the existing saved-query store; evaluation evolves with catalog, trusted origin/prose and current-owner annotations. Browse search folds case and common Western accents/ligatures while retaining punctuation and articles; it covers projected artist/album metadata, local tag names/values and own notes/tags/ratings/favourites. It does not invent countries from release-country tags or fetch enrichment. Unknown keys, invalid bounds/types and oversized expressions fail explicitly. Plain query collections keep their grammar and behavior. Public /query refuses browsing collections because they can read private annotations; the current-owner collection evaluator and CLI use the correct owner.

GET /api/v1/presentation/playback?ref=… exposes server-selected chronological principal discography or one album, including per-album track number and total (4096-item bound). It shares the CLI ordering function and does not start playback. See the route README for authenticated evaluation and confirmed history reset.

The additive m3u_playback_selection capability enables authenticated GET /api/me/v1/m3u-files/{id}/playback and GET /api/me/v1/m3u/{id}/playback. They return the same ordered items and scanned_at projection without starting audio or recording history. Watched files retain the existing roots/exclusions/private-export isolation and identity rechecks. Relative entries resolve against the discovered playlist parent, solely by current catalogue file identity; no entry triggers filesystem or network I/O. A non-file, missing or ambiguous entry refuses the whole selection. Private exports use only the authenticated owner's retained track references. Order and repetitions are preserved, with a 4096-occurrence bound. Both sources reject a file shared by multiple catalogue track placements; one per-request path index resolves private occurrences without rescanning the catalogue for each row. Update and restart older server processes before using this capability.

GET /api/me/v1/collection/albums?name=… evaluates the saved rule for the authenticated owner and returns current release references. DELETE /api/me/v1/history requires { "confirm": true } to clear that owner’s events, scrobbles and counters together, preserving annotations and other owners.

Lightweight album tracks and capability negotiation#

Authenticated GET /api/v1/status retains API version 1 and advertises capabilities, including dynamic_browse_collections, dynamic_browse_genres, dynamic_browse_personal, dynamic_browse_tags, collection_rename and album_track_pages. An older running process may expose neither even after its executable has been rebuilt; restart the server to load new code. Clients can refuse unsupported browsing writes before sending a newer saved-query expression.

GET /api/v1/presentation/tracks?ref=RELEASE&offset=0&limit=50 returns {items,total,offset,limit,scanned_at} with 1–200 rows per page in the release's complete catalog track order. Each row contains reference,title,disc_no,track_no,album_position,duration_ms,analysis_available,spectrum_available. album_position is one-based within the complete edition; nullable disc/track numbers preserve unknown metadata. Same-title tracks on different CDs retain distinct references. The endpoint never serializes retained analysis bodies or opens audio, performs no mutations, and shares bounded authenticated inspection. Explicit expansion reads the existing /api/v1/track detail and original-format report download. Invalid/non-release references and unsupported paging parameters fail explicitly.

Complete track catalog and entry dates#

GET /api/v1/presentation/tracks without ref pages every catalog track placement, including tracks outside a release. Optional q (at most 1024 bytes) searches normalized titles, album/artist names, credits and raw tag names/values; page limits remain 1–200. Credit matching uses one bounded catalog-table pass per search, rather than a full credit scan per track. Rows additionally carry nullable release and album_title; album_position is null outside a release. /api/v1/track additionally exposes disc/track numbers, audio properties, raw tags and attributed credits. Playback selection accepts a track reference as a single-item queue, preserving its actual album position/count; an albumless track returns a null release and 1/1, without an invented edition.

Status additionally advertises track_catalog_pages and catalog_added_dates. Album presentation includes nullable added_at, the earliest first-observed catalog timestamp among its files, in Unix seconds. Scans preserve known per-path dates. Files already present in legacy catalogs keep an unknown date, including after forced tag rereads; an album containing any such file remains unknown. New paths are dated on their first successful scan. Removed paths lose their observation; a later re-addition is a new observation. Dates are optional persisted file fields, separate from modification times and release years. No original audio or tags are written.

Dynamic browsing payloads accept an optional bounded genres array. Selected genres form a union, intersected with origin/search/year/alphabet criteria. The legacy genre scalar remains accepted and contributes to the same union. Servers advertise dynamic_browse_genres before clients persist the additive criteria; older saved rules keep their semantics.

Track pages and /api/v1/track additionally expose lyrics_available, a lightweight local presence hint. Bounded nonempty cached tag lyrics or a nonempty regular confined adjacent LRC qualify; browsing opens neither audio nor sidecar text and never starts acquisition. A newly downloaded adjacent LRC is detected without rescanning. Catalogued sidecars retain precedence. The explicit /api/v1/lyrics read validates current audio identity and complete content; a presence hint can become stale or refer to a metadata-only LRC, so clients must handle a null answer or read error. Older servers omit the additive field; absence is unknown, not false.

Retained analysis coverage#

GET /api/v1/presentation/analysis accepts bounded offset, limit (up to 200) and optional q matching album title or principal artist. Additive sort (title, current, missing, stale, failed, spectra) and direction (asc, desc) order the complete matching catalog before pagination, with stable normalized-title/key/id ties. The default is missing counts descending. Unknown values are refused; analysis_coverage_sort advertises this contract. The analysis_coverage capability advertises this additive read. Rows contain release reference/title/artist, track count and disjoint current, stale, failed, missing counts, plus available retained spectra. Counts use only FlacCompagnon records; a current decoding error is failed, and files with only older size/whole-second-mtime evidence are stale. Coverage follows the last catalog scan, not a fresh integrity check. Summary counts partition all catalog files, including albumless files; spectra are checked only in the visible album window unless sorting by spectra, which needs counts for every matching album. No decoding, enrichment, file publication or job launch occurs. Empty and unknown states remain distinct.

Owner-private tag collections#

The additive tags browsing view requires mode: "none", a bounded tags array (up to 100 nonempty values of at most 256 bytes) and no country/genre filters. Tag choices form a normalized exact union; an empty array selects every tagged target. query narrows tag names, matching the desktop Tags view. Current-owner artist tags contribute only principal discographies, album tags contribute every track in that edition, and track tags contribute only that placement, including albumless tracks. Guest credits never inherit an artist tag. Each evaluation reads current annotations; no tag is assigned to another entity. Unsupported or misplaced criteria fail explicitly. dynamic_browse_tags advertises this saved-rule extension. Collection album projection includes editions containing any selected track; playback preserves the selected tracks only.

Label playback and dynamic selections#

Playback selection also accepts a label reference, selecting only its current associated editions in the shared chronological album order, then each edition's original track order. Per-album positions/counts and the 4096-track limit stay unchanged. label_playback advertises the extension.

A browse-v1: payload with view: "label" requires an original stable label reference of kind Label. Year, title-initial and search filters apply to that label's editions. Other views refuse the field, missing/wrong-kind references fail validation, and a valid removed label evaluates to an empty selection. Future matching editions join on evaluation; no numeric catalog ID is persisted. dynamic_browse_label advertises this extension. Clients capture the originating library/account separately, never persisting application namespaces in the expression.

When administrative fetch is available in a network-enabled build, fetch_discogs advertises the explicit discogs job flag. Ordinary label GET remains local and never launches enrichment.

Label pages additionally accept sort=albums with order=asc|desc, ordering the complete filtered label set by associated release count before pagination. Name/key ties remain deterministic. Other catalog entity lists refuse this sort. label_album_sort advertises it. Label playback and the chronological discography view share the existing server release-order policy.

Cached integrity coverage#

Analysis coverage rows include integrity:{ok,ko,no_hash,unchecked,unsupported,stale,md5,crc}. The first six counts partition album tracks. md5 counts FLAC tracks and reads only applicable retained FlacCompagnon MD5 evidence: Match, Mismatch and NoSignature retain different outcomes. Present/Error/absent verdicts are unverified, and obsolete reports are stale. Ogg tracks use stored ogg-page-crc evidence, counted separately in crc; this is not a decoded-audio MD5. Other formats are unsupported by this projection, rather than healthy by default. Listing never launches a check or opens source audio.

Canonical album M3U lookup#

The additive album_m3u_lookup capability enables GET /api/me/v1/m3u-files?ref=<release-token>&limit=1. It resolves Aède's canonical CLI album-playlist destination, returning the validated release reference and zero or one metadata-only shared-file row. Unrelated playlists in the same folder do not disable publication. No playlist text, private export or source audio is opened or rewritten by lookup. Ordinary file detail/download still uses the opaque file ID.

The release must resolve in the current catalog. Its folder must remain inside permitted watched roots and outside exclusions/private exports. Unavailable folders refuse the read rather than asserting absence. Root, catalog, album alias and current-owner admission are rechecked before publication. Clients on older servers must leave unknown existence distinct from a confirmed missing file.

Artist media also reports the optional logo presence alongside banner, background and portrait. The same confined, read-only artwork endpoint accepts artist kind=logo with its existing bounded thumbnail size. Existing logos are read without external enrichment or original-file changes. Older clients ignore the additive hint; older servers omit it.

Composer album browsing#

Album presentation adds composers, a deduplicated array of {reference} rows carrying stable artist identities with an exact local composer credit on the edition or one of its tracks, recordings or works. A principal artist, performer or lyricist is never inferred to be a composer. The graph index is built once per page/evaluation, without opening audio or fetching external data. This projection uses local graph facts, not unaccepted external claims. An empty array confirms no such credit; older servers omit the field.

dynamic_browse_composers advertises a browse-v1 view composers, requiring a bounded array composers of up to 100 original artist references. An empty selection includes all editions with composer credits. Multiple identities form a union, intersected with ordinary title-initial, year, genre, origin and search filters; matching an edition selects its whole track order. A removed selected identity matches nothing. Other views reject this field. The API and on-disk catalog format remain unchanged; update/restart the engine and explicitly synchronize desktop projections to retain these associations offline.

Original export to portable destinations#

The account-authenticated original_exports capability provides a bounded selected-track plan and original-file stream for desktop transfer clients. It is separate from playback and produces no listening events. See copying for request limits, source stamps and authorization. The engine's normal copy/conversion rules remain authoritative after the client has privately staged an original.

The concrete routes are POST /api/me/v1/exports/plan and GET /api/me/v1/exports/original; the latter requires ref and stamp query parameters. Plans return conservative per-component key values from the same portable copy naming policy, allowing a client to refuse output aliases across selection batches.