Ready to add F/E
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"exportedAt": "2026-02-17T16:18:44.812Z",
|
"exportedAt": "2026-02-17T16:24:42.403Z",
|
||||||
"count": 32960,
|
"count": 32960,
|
||||||
"rows": [
|
"rows": [
|
||||||
{
|
{
|
||||||
|
|||||||
67
docs/plans/tape-identifier.md
Normal file
67
docs/plans/tape-identifier.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# Plan: Tape Identifier Dropzone on /zxdb
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
We have 32,960 rows in `software_hashes` with MD5, CRC32, size, and inner_path for tape-image contents. This feature exposes that data to users: drop a tape file, get it identified against the ZXDB database.
|
||||||
|
|
||||||
|
Uses RSC (server actions) rather than an API endpoint to make bulk scripted identification harder.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
**Client-side:** Compute MD5 + file size in the browser, then call a server action with just those two values (file never leaves the client).
|
||||||
|
|
||||||
|
**Server-side:** A Next.js Server Action looks up `software_hashes` by MD5 (and optionally size_bytes for disambiguation), joins to `downloads` and `entries` to return the entry title, download details, and a link.
|
||||||
|
|
||||||
|
**Client-side MD5:** Web Crypto doesn't support MD5. Include a small pure-JS MD5 utility (~80 lines, well-known algorithm). No new npm dependencies.
|
||||||
|
|
||||||
|
## Files to Create/Modify
|
||||||
|
|
||||||
|
### 1. `src/utils/md5.ts` — Pure-JS MD5 for browser use
|
||||||
|
- Exports `async function computeMd5(file: File): Promise<string>`
|
||||||
|
- Reads file as ArrayBuffer, computes MD5, returns hex string
|
||||||
|
- Standard MD5 algorithm implementation, typed for TypeScript
|
||||||
|
|
||||||
|
### 2. `src/app/zxdb/actions.ts` — Server Action
|
||||||
|
- `'use server'` directive
|
||||||
|
- `identifyTape(md5: string, sizeBytes: number)`
|
||||||
|
- Queries `software_hashes` JOIN `downloads` JOIN `entries` by MD5
|
||||||
|
- If multiple matches and size_bytes narrows it, filter further
|
||||||
|
- Returns array of `{ downloadId, entryId, entryTitle, innerPath, md5, crc32, sizeBytes }`
|
||||||
|
|
||||||
|
### 3. `src/app/zxdb/TapeIdentifier.tsx` — Client Component
|
||||||
|
- `'use client'`
|
||||||
|
- States: `idle` → `hashing` → `identifying` → `results` / `not-found`
|
||||||
|
- Dropzone UI:
|
||||||
|
- Dashed border card, large tape icon, "Drop a tape file to identify it"
|
||||||
|
- Lists supported formats: `.tap .tzx .pzx .csw .p .o`
|
||||||
|
- Also has a hidden `<input type="file">` with a "or choose file" link
|
||||||
|
- Drag-over highlight state
|
||||||
|
- On file drop/select:
|
||||||
|
- Validate extension against supported list
|
||||||
|
- Show spinner + "Computing hash..."
|
||||||
|
- Compute MD5 + size client-side
|
||||||
|
- Call server action `identifyTape(md5, size)`
|
||||||
|
- Show spinner + "Searching ZXDB..."
|
||||||
|
- Results view (replaces dropzone):
|
||||||
|
- Match found: entry title as link to `/zxdb/entries/{id}`, inner filename, MD5, file size
|
||||||
|
- Multiple matches: list all
|
||||||
|
- No match: "No matching tape found in ZXDB"
|
||||||
|
- "Identify another tape" button to reset
|
||||||
|
|
||||||
|
### 4. `src/app/zxdb/page.tsx` — Add TapeIdentifier section
|
||||||
|
- Insert `<TapeIdentifier />` as a new section between the hero and "Start exploring" grid
|
||||||
|
- Wrap in a card with distinct styling to make it visually prominent
|
||||||
|
|
||||||
|
### 5. `src/server/repo/zxdb.ts` — Add lookup function
|
||||||
|
- `lookupByMd5(md5: string)` — joins `software_hashes` → `downloads` → `entries`
|
||||||
|
- Returns download_id, entry_id, entry title, inner_path, hash details
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- Visit http://localhost:4000/zxdb
|
||||||
|
- Dropzone should be visible and prominent between hero and navigation grid
|
||||||
|
- Drop a known .tap/.tzx file → should show the identified entry with a link
|
||||||
|
- Drop an unknown file → should show "No matching tape found"
|
||||||
|
- Click "Identify another tape" → resets to dropzone
|
||||||
|
- Check file never leaves browser (Network tab: only the server action call with md5 + size)
|
||||||
|
- Verify non-supported extensions are rejected with helpful message
|
||||||
Reference in New Issue
Block a user