-
Extends the 跳舞直播间 (dance room) system to one independent live room per character, with an operator playback-management/blacklist layer (T39), a "我的作品" page for paid users (T38), a standalone 人衣图生成 admin tool, and a new admin-dance-library.html page for curating the per-character dance clip pool with AI QC. On top of that, dance clips now have an explicit published (上架/下架) status: passing AI QC (or a manual admin override to "correct") auto- publishes a clip, failing it auto-unpublishes it, and only published clips are eligible for a room's random-fill pool — unreviewed/rejected clips stay in the library but no longer autoplay for viewers. Existing already-QC'd "correct" clips are backfilled to published on first boot so the room doesn't go quiet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MvkJsRcQ2qEuaFea31rBY8
-
New db.js opens data.sqlite (node:sqlite's DatabaseSync — a Node 24 built-in, experimental but functional) and creates the users/sessions tables per dressup-dance-room-mvcp.md M.1/M.10. Zero new npm dependency: no bcrypt/argon2 (node:crypto's scryptSync covers password hashing in T19), no better-sqlite3, no package.json needed. Mirrors store.js's ergonomics (create/get/update, plain JS objects in and out — booleans and the oauthProviders array marshalled to/from SQLite's TEXT/INTEGER columns internally) rather than reaching for an ORM. Exports the openDb/createUsersStore/createSessionsStore factories alongside a default singleton so tests can point at an isolated tmp file instead of the real data.sqlite (same pattern dressup-generate.test.js uses for library.json). data.sqlite is gitignored under the secrets section, not the "runtime state" one — unlike library.json it holds real credential material (password hashes, session tokens), not just regenerable content. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Deddn3sM3oQnmvqWSMb4y
-
Same hue-recolor approach as the first 10 (dev-plan.md's exit bar needs >=30 garments given M.7's per-character-garment dedupe), batch generation for the new 20 already submitted to H3. Also stops tracking uploads/ — binary image/video content, not a good git citizen, and this content is explicitly placeholder ("占位旗袍" / "待替换") the user intends to replace wholesale later. The recipe (characters/garments/dance-refs.json) stays tracked; the files they point at don't. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Deddn3sM3oQnmvqWSMb4y -
Same category as live-state.json/dance-state.json: rewritten by ingest.js's periodic sync and by every clip play (playCount/ lastPlayedAt), so every commit touching it was just churn from whoever last had the server running locally. File stays on disk, just untracked going forward. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Deddn3sM3oQnmvqWSMb4y
-
Backend (server.js): - T11: dance.html gets its own schedule/queue state machine, persisted to dance-state.json (gitignored, same as live-state.json). Per MVCP M.8, the schedule stores videoId references rather than inlined clip snapshots like live's does, joining back to library.json at read time. Generalized pickBestIndexByStatus/extracted pickLeastPlayedClip so both channels' schedulers share the same selection logic instead of forking it; live's random-fill pool now excludes channel:"dance" clips (and vice versa) so the two channels' filler picks stay independent, which wasn't true before this (T8's dance clips could have leaked into live.html's filler). - T12: GET /api/dance/wardrobe — public, unauthenticated list of active garments. - T15: POST /api/dance/pick {garmentId, nickname?} — free path, always uses the configured default character, reuses submitGeneration (T8/T9) whole including its M.7 dedupe cache, then hands the result to danceQueue. In-flight generations are reconciled against generationJobs on each schedule tick rather than via a promise chain, so a pick request survives a server restart the same way T8's own jobs do. - T17: separate danceViewers map and POST /api/dance/queue/vote/:id, so viewer counts and votes don't mix with live.html's. - SCHEDULE_TICK_MS env var makes both channels' tick interval configurable so tests don't wait out a real 2s. Frontend: - dance.html (T13/T14/T16): reuses live.html's visual language via live.css, adds dance.css for the 9:16 boxed player and wardrobe grid. Left column is a 衣柜/传衣服/传人 tab set (only 衣柜 is wired up — the other two need accounts/credits, dev-plan-2.md 第三/四期); right column shows the queue with vote buttons instead of live.html's chat. Age-confirmation gate (5.1节) blocks the page on first visit via a cookie, non-dismissable by clicking the backdrop. Tests: dance-channel.test.js spins up a mock H3 Console (same approach as dressup-generate.test.js) to exercise wardrobe listing, pick rejection/happy-path/dedupe, vote, and independent viewer counts end to end. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-
Static video-gen testing tool (MiniMax native API, then fal.ai) that grew into an AI drama live channel backed by an internal H3 Console GPU cluster: shared virtual-playhead live playback, prompt submit/match/generate queue, admin CRUD for the video library, and bilingual (zh/en) semantic clip names. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>