Skip to content

Media Library

MZAP includes a SQLite-backed media library that indexes your audio files for quick search and browsing.

Add one or more folders to the library. MZAP will scan them for supported audio files and extract metadata (title, artist, album, duration) from ID3v2, ID3v1, and OGG tags.

Adding or rescanning a folder shows a live, determinate progress bar in the Library view header — scanned/total files, the file currently being processed, and a Cancel button. The folder management panel additionally shows a per-folder X/Y badge with a cancel X.

Scans run on the server in a single-flight queue: one scan executes at a time. If another scan is already in flight for the same folder, the request is rejected with 409 Conflict. When a scan finishes, a toast summarises new / updated / removed counts. Cancelled or failed scans show a persistent toast until you dismiss it.

Watched folders are monitored for changes. When files are added, removed, or modified, the library updates automatically with a short debounce delay.

The search box in the Library tab is backed by a SQLite FTS5 full-text index over title, artist, album, genre, and file path. What you type is sent verbatim as an FTS5 MATCH expression.

SyntaxMatches
pinkAny word that starts with “pink” anywhere across title / artist / album / genre / path — Pink, Pinker, Pinkfloyd
pink*Same prefix match, stated explicitly
"pink floyd"The two words next to each other, in that order
artist:pinkThe word “pink” in the artist field
artist:pink AND album:wallBoth conditions (implicit AND between terms also works)
artist:pink OR artist:queenEither artist
pink NOT title:remix”pink” anywhere, but skip remixes
rock NOT (album:greatest OR album:best)Boolean grouping with parentheses
NEAR(pink wall, 5)The two words within 5 tokens of each other
  • Prefix matching by default. Each plain word you type is matched as a prefix, so ava finds “avave”, “AVAION”, and “Ava Asante”; madon finds “Madonna”; and the mado finds “The Blessed Madonna”. Matching is still by word (not arbitrary substring) — ace won’t match “space”. FTS5 power syntax (artist:madonna, rock OR jazz, "exact phrase", etc.) is detected and honored verbatim, so advanced queries behave exactly as written.
  • NOT is binary, always with a matching term on its left (pink NOT remix, not NOT remix). There is no -word shorthand — - is reserved by FTS5 as a column filter.
  • Accent folding. cafe matches café.
  • Stemming. running matches runs; corrected matches correction (Porter stemmer).
  • No single-character wildcard. FTS5 only supports prefix wildcards (word*). Patterns like P?nk are not supported — search for the variants directly (pink OR p!nk).
  • No partial-match warning. Every query is fully honored. If the syntax is malformed, results come back empty rather than silently dropping parts of the query.
  • Punctuation-friendly fallback. If FTS5 rejects a literal query (for example, apostrophes in Bob's Diner), the backend transparently retries with each whitespace-separated token wrapped as a phrase. Clean inputs are unaffected.

Numeric range filters live in a bar beneath the search box and AND with the FTS5 query:

  • Year — min and max number inputs.
  • Duration — preset dropdown (Under 1 min / 1–3 / 3–5 / 5–10 / Over 10 min) plus a Custom… option that exposes two mm:ss inputs.

A Clear filters button appears when any filter is set, and the bar gains a thin coloured left border to flag the active state.

Search runs against the entire library, not just the rows currently loaded into the page. Sorting by column header (title, artist, album, genre, year, duration, codec, track) also runs server-side, with stable pagination, and the footer shows the real backend count (N of M).

The toolbar Generate Playlist dialog also operates on the whole library: it fetches the full set of tracks matching the current search and filters when it opens, so No limit really means all matching tracks and the track/duration counts are accurate (the dialog briefly shows a “Loading library…” state while the full set loads). The Generate from selection context-menu action is unchanged — it uses exactly the tracks you selected.

Library rows are selectable and right-clickable:

  • Single-click selects a row (replacing the previous selection).
  • Ctrl/Cmd-click toggles a row in or out of the selection.
  • Shift-click range-selects from the previous click.
  • Drag a selected row to drag the whole selection onto a playlist or player.

Selection is pruned automatically when a new search or range filter excludes previously selected rows.

Right-clicking a row opens a context menu. Actions are gated by role:

ActionSelectionRoleNotes
Play on player…SingleOperatorDirect action when only one accessible player exists; otherwise a submenu of player names. Loads and starts playback.
Add to playlist…Single or multiOperatorOpens the playlist picker. Inline “Create new playlist” is also Operator.
Append to player…SingleOperatorSubmenu of accessible players. Items disable when the player has no assigned playlist (tooltip explains).
Generate playlist from selectionSingle or multiOperatorReuses the playlist generator dialog, seeded with the selection.
Show detailsSingleAnyModal with full metadata (title, artist, album, genre, year, track, duration, codec, sample rate, channels, file size) and the file path with a Copy button.
Create jingle from trackSingleAdminPosts to POST /api/jingles with the file path. Default jingle name is the track title (or filename).
Copy path / Copy N pathsSingle or multiAnyNewline-joined paths for multi-selection.

MP3, FLAC, WAV, OGG Vorbis, AAC/M4A, WMA, Opus, AIFF, and APE.