[add] README.md [add] client/.gitignore [add] client/README.md [add] client/eslint.config.js [add] client/index.html [add] client/package.json [add] client/public/vite.svg [add] client/src/App.css [add] client/src/App.tsx [add] client/src/api.ts [add] client/src/assets/react.svg [add] client/src/components/EntryCard.tsx [add] client/src/components/ItemPanels.tsx [add] client/src/components/QuizRunner.tsx [add] client/src/components/VideoPlayer.tsx [add] client/src/index.css [add] client/src/main.tsx [add] client/src/pages/EntryPage.tsx [add] client/src/pages/OverviewPage.tsx [add] client/src/pages/QuizPage.tsx [add] client/src/types.ts [add] client/tsconfig.app.json [add] client/tsconfig.json [add] client/tsconfig.node.json [add] client/vite.config.ts [add] gemini_replicate_batch.py [add] package.json [add] prompt.txt [add] server/package.json [add] server/src/index.ts [add] server/tsconfig.json
2.3 KiB
2.3 KiB
IG Japanese Quizzer
A full-stack web app for drilling Japanese grammar, vocabulary, and phrases from locally stored Instagram posts. The server indexes every *.mp4 + matching *.json pair under data/ and exposes them to a React/Vite frontend with a quiz wizard.
Quick start
- Install dependencies (root workspace):
npm install - Run both servers (frontend on 5173, backend on 5174):
npm run dev- Vite proxies
/apiand/datato the Express server, so the client can use relative URLs.
- Vite proxies
- Open the app at http://localhost:5173.
Scripts
npm run dev– concurrently runsserver(Express + ts-node-dev) andclient(Vite dev server).npm run build– builds the server TypeScript and Vite client.npm run dev --workspace server/npm run dev --workspace client– run either side individually.
Data layout
Files live under data/ (scanned recursively):
data/<POST_ID>/<FILENAME>.mp4
\_ <FILENAME>.json # quiz payload for that video
- Base filenames must match. Extra sidecars (
.raw.txt,.mp4.json, images) are ignored. - The JSON structure is tolerant but expects keys:
meta,items,quiz,ui_hints(additional fields are ignored). entry_idis the path fromdata/to the mp4 without the.mp4extension (e.g.,C1abc/12345). It is URL-encoded in routes/query params.- Videos are served statically at
/data/...by the backend; JSON is only accessible through the API.
API
GET /api/entries→ list of entries{ id, title, mode, type, counts, video_url }, sorted by title.GET /api/entry?id=<entry_id>→ full entry JSON plus derived fields{ id, title, video_url, counts }.
Frontend features
- Overview grid of all entries with counts and metadata.
- Entry detail page with embedded video and learning panels.
- Quiz Wizard with three modes:
- All entries (random 10 questions)
- Selected entries (checkbox picker)
- Single entry (linked from detail page)
- Quiz types: cloze input, multiple-choice variants, match pairs, and best reply. Wrong answers reveal explanations and the source video.
Notes
- The server prevents path traversal by validating resolved paths against the data root and only serving scanned entries.
- Update or add new posts by dropping files into
data/and restarting the server to rescan.