Skip to content

Add a low-level album art table for Engine v2 and v3 - #203

Open
sebasje wants to merge 1 commit into
xsco:mainfrom
sebasje:add-album-art-table
Open

sebasje wants to merge 1 commit into
xsco:mainfrom
sebasje:add-album-art-table

Conversation

@sebasje

@sebasje sebasje commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Adds the AlbumArt table to the Engine v2/v3 low-level API, and documents how Engine stores artwork. Towards #56; details of the format are in a comment there.

Engine does not keep the image in the database. albumArt is always NULL, hash holds a 20-byte binary hash (a blob, though the column is declared TEXT), and the image lives at <Engine library>/Artwork/<hash, base64url, unpadded>.jpg. On a Denon-written stick here, all 87 files under Artwork/ are named by exactly that encoding of their row's hash — which is what album_art_file_name() calculates, checked against all 87.

The same column also holds image://fileart/<path> URIs written by Engine's own rekordbox import, which point outside Artwork/ and are absolute; both forms are documented on the hash field, and the table stores whatever it is given.

What is here:

  • album_art_table in v2, aliased into v3, with add, all_ids, exists, find_id, get, remove, update, following playlist_table.
  • album_art_file_name(), plus ALBUM_ART_DIRECTORY and ALBUM_ART_DEFAULT_EXTENSION.
  • album_art() on both engine_library classes.
  • Tests for v2 and v3 over every supported schema version, including base64url vectors that exercise partial groups and both URL-safe characters.

What is deliberately not here: track_snapshot still has no artwork, and nothing writes or reads the image file. Both need a decision about whether the library should own files beneath the library directory, so they seemed better kept out of this change.

The hash derivation is still unknown. It does not appear to be verified: we write the first 20 bytes of the image's SHA-256, and a Prime 4 displays the covers correctly.

Tested on Ubuntu 24.04 (CMake 3.30.5, GCC 13.3.0): ctest passes 14/14, the two new test targets included.


Thank you for libdjinterop — and for leaving the low-level API in a shape where a new table is a small, obvious addition.

The `AlbumArt` table has had no representation in the low-level API, and
the high-level `album_art` class is still a stub, so a caller wanting to
give a track its cover had no way to do it.  This adds the table itself,
along with what we have been able to work out about how Engine stores
artwork.

Engine does not keep the image in the database.  The `albumArt` column is
always null, the `hash` column holds a 20-byte binary hash -- a blob,
even though the column is declared `TEXT` -- and the image lives at

    <Engine library>/Artwork/<hash, base64url, unpadded>.jpg

On a Denon-written stick here, all 87 files under `Artwork` are named by
exactly that encoding of their row's hash, with no exceptions, which is
what `album_art_file_name()` calculates.

The same table also holds rows whose `hash` is an `image://fileart/...`
URI, written by Engine's own import of a rekordbox library and pointing
into that library's artwork rather than into `Artwork`.  Those are
absolute paths, and so do not survive the medium being mounted
elsewhere; on the stick above, 1469 of the 1557 rows are of that kind.
Both forms are documented on the `hash` field, and the table stores
whatever it is given.

The derivation of the hash itself remains unknown, but it does not appear
to be checked: writing the first 20 bytes of the image's SHA-256, which
is certainly not what Denon computes, gives covers that a Prime 4
displays correctly.  The hash acts as a content-addressing key for the
file name, and any stable, collision-resistant value of that width has
worked so far.

Not attempted here: the high-level API still has no artwork on
`track_snapshot`, and nothing in the library writes or reads the image
file.  Both need decisions about ownership of files beneath the library
directory that are better taken separately.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant