No description
| app | ||
| bin | ||
| fake-data | ||
| public | ||
| tests | ||
| .gitignore | ||
| AGENTS.md | ||
| bun.lock | ||
| bunfig.toml | ||
| docker-compose.dev.yml | ||
| docker-compose.prod.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
ROM Loader
Web app for safely managing Wii and GameCube ROMs on backup drives.
Stack
- Runtime: Bun (single monolithic app)
- Server/Frontend: Hono + HTMX + Tailwind CSS v4
- External tools:
wit(Wii WBFS) anddolphin-tool(RVZ conversion) - Deployment: Docker container (dev and prod)
Repository Layout
.
├── app/ # Unified Bun application source
│ ├── server.ts # Hono server, API routes, HTMX fragments
│ ├── client.ts # Browser entry point
│ ├── styles.css # Tailwind CSS source
│ ├── config.ts # Paths and tool resolution
│ ├── scanner.ts # Directory/archive scanning via 7z
│ ├── comparison.ts # ROM matching logic
│ ├── converter.ts # RVZ → ISO conversion
│ ├── wit.ts # wit (WBFS) operations
│ ├── operations.ts # Bulk copy/convert worker
│ ├── drive.ts # Drive type detection
│ ├── logger.ts # In-memory operation log
│ ├── utils.ts # Filename/region normalization
│ └── types.ts # Shared TypeScript types
├── bin/ # Mock tools for dev/test
│ ├── wit
│ └── dolphin-tool
├── public/ # Static assets (built CSS, HTMX, index.html)
├── tests/ # bun:test suite
├── fake-data/ # Example source/target drives
├── Dockerfile
├── docker-compose.yml # Base config (shared)
├── docker-compose.dev.yml # Dev overrides (mock tools, fake data, hot-reload)
└── docker-compose.prod.yml # Prod overrides (real drives, host wit mount)
Features
- Read-only source directory scanning
- Automatic archive extraction (zip, 7z, rar) via streaming
7z - RVZ → ISO → WBFS conversion pipeline (via
dolphin-toolandwit) - Wii WBFS folder structure (
./wbfs) and GameCube Swiss structure (./Games) - Fuzzy name + game ID + region matching against target drive
- Bulk copy/convert operations with integrity checks
- Live operation logs with
[scan]/[operate]progress in container logs - Dark mode UI
- Drive type auto-detection with manual override
Development
Local (no Docker)
bun install
bun run dev
Open http://localhost:3000. Needs 7z installed for archive extraction tests
(brew install p7zip on macOS, apt install p7zip-full on Linux).
Docker dev
docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build
This mounts fake data and mock wit/dolphin-tool scripts from bin/, and
hot-reloads app/ and public/ via volume mounts.
Production
# Create .env with your drive paths:
cat > .env <<EOF
SOURCE_DIR=/mnt/source
TARGET_DIR=/mnt/target
EOF
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
The prod compose file mounts your source drive read-only and your target drive
read-write. Both wit and dolphin-tool are installed inside the container —
wit via apt, dolphin-tool via the npm package. No host binaries needed.
Managing the deployment
# View logs
docker compose -f docker-compose.yml -f docker-compose.prod.yml logs -f
# Restart
docker compose -f docker-compose.yml -f docker-compose.prod.yml restart
# Stop
docker compose -f docker-compose.yml -f docker-compose.prod.yml down
# Update (after pulling new code)
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
Testing
bun test
bun run typecheck
Environment Variables
| Variable | Default | Purpose |
|---|---|---|
SOURCE_DIR |
/data/source |
Read-only source directory |
TARGET_DIR |
/data/target |
Destination drive root |
WIT_PATH |
/usr/bin/wit |
wit binary path inside container |
DOLPHIN_TOOL_PATH |
resolved | dolphin-tool binary override |
TEMP_DIR |
/tmp/rom-loader |
Conversion scratch space |
LOG_LEVEL |
INFO |
Logging level |
PORT |
3000 |
HTTP server port |
HOSTNAME |
0.0.0.0 |
Bind address |
Safety
- Source directory is mounted read-only in Docker.
- File copies are verified by size after write.
- Target structure is created only when necessary.
- Local files are never modified; only target drive receives writes.