mp3-com-meta-browser/README.md

135 lines
6.7 KiB
Markdown

# mp3-com-meta-browser
mp3-com-meta-browser is a static single-page web app for exploring the salvaged mp3.com metadata catalog. All queries run entirely in the browser against a read-only SQLite database compiled to WebAssembly, so the site can be hosted on any static file server.
## Highlights
- Client-side full-text search (FTS5) across track titles, artists, albums, and genres.
- Responsive Bulma-based UI with dedicated views for search, browse (artists, albums, years, genres), and dataset stats.
- Overlay detail panels for artists, albums, and tracks with keyboard navigation support.
- Zero server dependencies beyond serving static assets with HTTP range support.
## Tech Stack
- Bulma (`bulma.min.css`) for layout and components.
- Vanilla JavaScript in `script.js` for SPA state management, view controllers, and data access helpers.
- `sql.js` WASM build (`sql-wasm.js` / `sql-wasm.wasm`) to run SQLite with FTS5 support in the browser.
- Local styling refinements in `site.css`.
- Metadata database delivered as `/assets/mp3com-meta.sqlite`.
## Directory Layout
```
/
├─ index.html # Single-page app shell and HTML templates
├─ bulma.min.css # Bundled Bulma CSS (do not modify upstream file)
├─ site.css # Local overrides and micro-utilities
├─ script.js # Application logic, helpers, and view controllers
├─ README.md # Project overview (this file)
├─ AGENTS.md # Orientation and guardrails for automation agents
└─ assets/
└─ mp3com-meta.sqlite # Read-only metadata database
```
Add future static assets (icons, fonts, etc.) under `assets/`.
## Running Locally
1. Start a static file server from the repository root. Examples:
- `python3 -m http.server 8000`
- `npx http-server -p 8000`
2. Ensure the server sends `Accept-Ranges: bytes` for `/assets/mp3com-meta.sqlite` so the WASM virtual file system can page data on demand.
3. Visit `http://localhost:8000/` in a modern browser.
4. Open the developer console to confirm there are no runtime errors.
## Using the App
- **Search:** Free-text search with 250 ms debounce. Toggle between relevance and alphabetical sorting. Keyboard: `/` focuses search, `Enter` activates the highlighted row.
- **Browse Artists / Albums / Years / Genres:** Paginated listings with quick filters (artists leverage FTS prefix queries for fast prefix matching). Selecting an entry opens the corresponding overlay.
- **Stats:** Summary cards pull from pre-computed counters in `site_stats` and link into browse views with preset filters.
- **Overlays:** Artist, album, and track overlays show detailed metadata. `Esc` closes the top overlay and focus returns to the invoker.
## Keyboard & Accessibility Notes
- Global shortcuts: `/` for search, `Esc` to close overlays.
- Lists expose arrow navigation with `Enter` activation when focused.
- Focus indicators remain visible; async list regions use polite `aria-live` messages.
- Ensure new UI follows Bulma semantics and pairs labels with inputs.
## Database Schema
The bundled database enforces foreign keys and ships with an FTS5 index over key text fields. The current schema is:
```sql
PRAGMA foreign_keys=ON;
CREATE TABLE artists(
id INTEGER PRIMARY KEY,
name TEXT NOT NULL COLLATE NOCASE UNIQUE
);
CREATE TABLE albums(
id INTEGER PRIMARY KEY,
artist_id INTEGER NOT NULL REFERENCES artists(id),
title TEXT COLLATE NOCASE,
year INTEGER,
UNIQUE(artist_id, title, year)
);
CREATE TABLE tracks(
id INTEGER PRIMARY KEY,
artist_id INTEGER NOT NULL REFERENCES artists(id),
album_id INTEGER REFERENCES albums(id),
title TEXT NOT NULL COLLATE NOCASE,
track_no INTEGER,
year INTEGER,
genre TEXT,
duration_sec INTEGER,
bitrate_kbps INTEGER,
samplerate_hz INTEGER,
channels INTEGER,
filesize_bytes INTEGER,
sha1 TEXT,
relpath TEXT NOT NULL
);
CREATE TABLE site_stats (
name TEXT PRIMARY KEY,
value TEXT NOT NULL
);
CREATE VIRTUAL TABLE fts_tracks USING fts5(
title,
artist,
album,
genre,
content='tracks',
content_rowid='id',
tokenize='unicode61 remove_diacritics 2',
prefix='2 3 4'
);
CREATE TABLE 'fts_tracks_data'(id INTEGER PRIMARY KEY, block BLOB);
CREATE TABLE 'fts_tracks_idx'(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID;
CREATE TABLE 'fts_tracks_docsize'(id INTEGER PRIMARY KEY, sz BLOB);
CREATE TABLE 'fts_tracks_config'(k PRIMARY KEY, v) WITHOUT ROWID;
CREATE INDEX idx_tracks_artist_id ON tracks(artist_id);
CREATE INDEX idx_tracks_album_id ON tracks(album_id);
CREATE INDEX idx_tracks_year ON tracks(year);
CREATE INDEX idx_tracks_genre ON tracks(genre);
CREATE INDEX idx_artists_name ON artists(name COLLATE NOCASE);
CREATE INDEX idx_artists_name_nocase ON artists(name COLLATE NOCASE);
```
The `fts_tracks_*` tables are managed by SQLite to back the FTS5 virtual table. `site_stats` stores pre-computed counters that power the stats view. The application issues read-only queries and never mutates the database.
## Development Notes
- Keep the app framework-free; do not introduce bundlers or additional dependencies without discussion.
- Reuse HTML templates in `index.html` through the `instantiateTemplate` helper instead of building large DOM fragments manually.
- Paginate every query (`LIMIT ? OFFSET ?`) and prefer streaming or incremental rendering for large result sets.
- Consolidate shared UI logic (pagination, keyboard handlers, async states) in `script.js` utilities.
- Restrict new CSS to scoped utility classes in `site.css`; otherwise rely on Bulma components.
- Before submitting changes, verify there are no console warnings, layout adapts from mobile to desktop, and keyboard navigation continues to work.
### Debug Instrumentation
- Enable verbose query diagnostics by setting `localStorage.setItem('mp3com.debug', 'true')` and reloading the app (clear the key or set it to `'false'` to disable).
- With DEBUG on, every SQLite statement logs `Query begin` / `Query end` entries that include the originating view, optional label, normalized SQL text, bound parameters, row counts, and execution duration.
- Any statement failure logs `[SQLite error]` details (SQL, params, phase, message, stack) before the exception propagates, making it easier to correlate with UI regressions.
- Pagination helpers emit `[Pagination]` traces whenever user inputs are normalized or clamped (including high-page corrections after a total count comes back smaller than expected).
- Use the `prepareForView(db, VIEW_NAMES.someView, sql, label)` helper when preparing new statements so that console output remains aligned with the feature area generating the query.
## License
Add licensing information here when available.