Commit Graph

15 Commits

Author SHA1 Message Date
type-two
e8013a4633 feat(shop): DECKS — two-channel preview mixer on release pages (Serato internal-mode vibe)
Pure Web Audio, zero deps (site/decks.js, self-contained UI):
- deck A/B with waveform (client-computed peaks), click-to-seek, play/pause, CUE
- ±8% varispeed pitch (playbackRate — turntable behaviour, deliberately no keylock)
- channel gains + equal-power crossfader, DynamicsCompressor master limiter
- AudioContext lazily created on first load (autoplay policy safe)

Sources:
- local preview MP3s: PREVIEWS_DIR (default ./previews, gitignored) served at
  /previews, discovered via GET /shop/local-previews/{release_id}
  ({release_id}.mp3 / {release_id}-*.mp3|.m4a); on prod bind-mount the collection
- Apple 30s previews: GET /shop/preview-proxy?u= (STRICT whitelist
  *.itunes.apple.com / *.mzstatic.com) — Apple CDN sends no CORS, Web Audio needs it
- YouTube/Beatport/Bandcamp embeds untouched: iframes can never enter a mixer

release.html: A/B load buttons per track preview + local-cut rows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 22:57:47 +10:00
type-two
61601f1067 money: atomic stock claims, amount validation, discount gate (converge with StoreGod twin)
R1 checkout qty clamp to one-row-per-copy; R2 claim-then-charge in
online checkout with release-on-decline and post-charge write guard;
R3 POS create_sale per-sku atomic claim (matches held copies so
hold->counter completion still works) before booking the sale;
R4 take_payment positive-amount check + atomic amount_paid increment;
R5 POS discount gate (admin only, RecordGod role idiom); R6 log +
re-raise if the order write fails after a successful charge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 03:02:30 +10:00
type-two
db1788bfe5 feat(app): payments/packs/discogs-mp/dealgod modules + admin, shop, sales route work
Batch-committing the in-flight app work (all modules compile clean):
- app/payments.py, app/packs.py, app/discogs_mp.py, app/dealgod.py (new)
- admin_routes, main, navigator/sales/shop routes, site/search.html
- customer_woo_sync + disc_sync tweaks; test_dealgod_supply, test_startup_ddl

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 23:07:28 +10:00
type-two
5ad4de1d2c feat(bridge): RecordGod WP bridge plugin (WowPlatter successor) + thumb on browse/release
Thin WordPress/Woo bridge — RecordGod owns catalog/stock/pricing/shipping; the plugin is a storefront
skin + checkout adapter over /shop:
- storefront: SSR /records (browse) + /release/{id} inside the theme, with title/meta/JSON-LD MusicAlbum
- on-the-fly Woo product: /?rg_add=<sku> mints a hidden WC_Product_Simple from /shop/item (the WowPlatter
  trick — 25k catalog, only sold items become Woo products)
- shipping: WC_Shipping_Method quoting /shop/shipping/quote by cart item count (AusPost flat rate)
- orders: order_status_completed -> POST /shop/woo-order (X-Bridge-Key), idempotent, marks SKUs sold
- settings page: base URL + bridge key + store id
Backend: added thumb to /shop/browse + /shop/release so storefront pages have cover art.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 01:43:30 +10:00
type-two
8a3d833986 feat(shop): WP/Woo bridge endpoints — /shop/item, /shop/shipping/quote (public), /shop/woo-order (key-gated)
The thin WP plugin renders from /shop/*, mints Woo products on the fly via /shop/item, quotes
postage publicly, and posts completed orders back to /shop/woo-order (X-Bridge-Key vs vault
bridge_key) — marks SKUs sold + logs the online sale, idempotent on WC-<order#>.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 01:28:34 +10:00
type-two
4c152954b5 fix(shop): key YouTube dead-cache by (release_id, uri) — mirrored video table has no id col
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 23:47:42 +10:00
type-two
988e6437cb feat(shop): per-track Apple previews (lazy iTunes) + jog mini-player + dead-YouTube check
/shop/audio-tracks/{id}: resolves each track's preview from its Apple song id via iTunes lookup
(au), cached in disc_release_track.apple_preview. /shop/audio validates YouTube via oembed (200=live),
caches dead in disc_release_video.dead, returns one live id. release.html + kiosk.html get a per-track
▶ on each tracklist row feeding a mini-player with a jog/seek bar (falls back to a single Listen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 23:44:17 +10:00
type-two
aa56e874ad feat(shop): country-scoped Apple ids in audio — AU-preferred music.apple.com link + clean preview
audio_sync mirrors apple_id ({cc:album_id}) + apple_song_id (kept raw, country preserved).
/shop/audio parses it: AU>US>first → music.apple.com/{cc}/album/{id}, per-track preview array
→ first clean 30s url. Kiosk Listen uses apple_preview + an Apple Music ↗ link.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 23:17:06 +10:00
type-two
7e9d5028b0 fix(shop): apple_preview_url is a JSON array — return the first clean preview URL
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 23:12:39 +10:00
type-two
16c85184cd feat(shop): wire audio/video previews — kiosk Listen (Apple 30s / YouTube / Beatport)
audio_sync.py mirrors WowPlatter disc_release_audio (22.5k; apple_preview_url, beatport_embed,
bandcamp…) + disc_release_video (231k YouTube) into Postgres. /shop/audio/{id} returns playable
sources. Kiosk detail gets a ▶ Listen: Apple 30s preview (instant <audio>), else YouTube embed,
else Beatport/Bandcamp embed; stops on close/idle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 23:10:02 +10:00
type-two
bab0826fea feat(shop): in-store kiosk page — touch browse, locate-in-store, scan-to-buy QR
site/kiosk.html: full-screen themed kiosk (idle attract cover-wall → tap → browse with
big search + genre chips + record grid → detail with tracklist, in-store locator (crate ·
rack) and a QR to buy on the customer's phone). 75s idle returns to attract. /shop/release
copies enriched with crate/rack location (public-safe). Route /kiosk. Better than WowPlatter's
kiosk: locate + phone-QR front and centre. Audio previews deferred (no internal audio yet).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 23:01:54 +10:00
type-two
48f8579bff feat(shop): P4 wantlist — public 'request a record' page + admin queue
Storefront /wantlist form (themed, email-keyed, guest-friendly) posts to
/shop/wantlist → wantlist table (lazy DDL). Release pages deep-link to it
(prefilled; 'not in stock — request this record' when no copies). Admin gets
a Wantlist tab: pending/found/fulfilled queue with one-click status actions.
Default storefront menu → Records + Wanted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 01:29:00 +10:00
type-two
28a46615a5 feat(shop): entity browse pages — artist/label/genre/style storefront views
records.html reads /artist|label|genre|style/{val} from the path, sets the
filter + an entity header (artist/label name via /shop/{kind}/{id}). /shop/browse
gains artist/label EXISTS filters + primary artist_id; release page links
artist→/artist/{id} and genre/style pills→/{kind}/{name}.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 01:18:15 +10:00
type-two
fcc3d7b2ff feat(storefront): P0 — public Browse (faceted release catalog) + Release detail pages + /shop/{browse,facets,release} API; Woo-transacted
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 00:37:04 +10:00
type-two
19e3cb131f feat: clean stub URLs (/builder /shop /admin /dash) + store geometry + storefront 2026-06-21 23:16:57 +10:00