gandora: moved out of teahubxyz/time ventures/gandora into its own repo

This commit is contained in:
teahubxyz committed 2026-10-20 22:29:58 +00:00
commit 68f8cd1571
5 files changed
+1741

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
# gandora storage contract
The page keeps everything through one object, `db`, in `index.html`. Today it is IndexedDB in the browser; a backend
replaces it by implementing the same four calls and pointing `db` at the new implementation. Nothing else in the page
touches storage (`brain.js` reads through `db.all()` too).
```
db.put(row, store = "tracks") // create or replace, keyed by row.id
db.all(store = "tracks") // every row, newest first (tracks by `made`, stations by `last`)
db.del(id, store = "tracks")
db.open() // internal; a backend adapter can drop it
```
Two stores.
## tracks
```
{
id: "1760998800000-211979153", // spec.made + "-" + hash32(title); stable, made by the page
made: 1760998800000, // ms epoch, when the DJ wrote it
kept: false, // pinned by KEEP (the only pin)
plays: 3, // play starts + loop passes
blob: Blob, // the audio (FLAC from Venice, mp3 from Runware); a backend may return { url } instead
spec: { // the song on paper: enough to re-render it anywhere
title, tags, lyrics, bpm, key, energy, line, // what the DJ wrote (tags = the music prompt, <= 500 chars)
seed, station, stationId, // where it came from
reaction: "🔥 ❤️ \"less snare\" [skipped]", // the listener's reactions, in order; words quoted, skips bracketed
guess: 0.71, // the taste net's prediction when it was cooked (optional)
plays, id, made // mirrored for convenience
}
}
```
## stations
```
{
id: "s-1760998800000-211979153", // "s-" + ms + hash32(seed)
seed: "rainy trains",
name: "Platform Nine", // chosen by the DJ on the first track, then stable
taste: { like: [...], avoid: [...], notes: [...] }, // last 8 of each, in words, fed to the DJ
history: [ { id, title, tags, bpm, key, energy, reaction, made } ], // last 8 tracks, no blobs
made: 1760998800000,
last: 1761002400000, // touched on every play and reaction
played: 23
}
```
## what a backend adds
- identity: rows are per listener; `/user/station/track` links need the listener in the key
- `blob` as a URL the `<audio>` element and the Web Audio analyser can load (same-origin or CORS-enabled)
- sync: the page calls `db.all()` freely (library, taste, play counts), so cache on the client and keep `all()` cheap
## what stays on the page
The taste net (`brain.js`) trains in the browser from `db.all()` rows; it needs only `spec` + `kept` + `plays`.
Share links (`?t=`) carry a spec, not an id, so they work with no backend at all; with one, a link can carry the id
and the backend's audio instead of re-rendering.