No description
trimesh's 3MF loader re-reads a whole production-extension part file for every component that points into it. A Bambu Studio project with 884 components across four ~50 MB part files grew past 3 GB within seconds and failed both the preview conversion and the geometry fingerprint. - Add tools/threemf_stream.py: parses each part once with lxml iterparse, resolves each component to the single object it names, and returns each mesh once plus its placements. The same project now converts in ~8 s at ~380 MB peak (fingerprinting ~190 MB). - convert_3mf.py and fingerprint.py use it; the GLB stores each object once and instances repeats. Stats are computed per placement (mirrored placements keep a positive volume), without concatenating meshes. - Run sidecar scripts through one queue (lib/python.js) so a preview and background fingerprinting never load big meshes at the same time; previews go first, and 3MFs are fingerprinted one per run. - Surface the converter's JSON error / timeout instead of "Command failed". - Tests with a Bambu-style component fixture (shared part, mirrored placement, decoy object) and STL/3MF fingerprint parity. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| db | ||
| lib | ||
| public | ||
| test | ||
| tools | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| server.js | ||
Printhive
A self-hosted web app for organizing your 3D-printing files (STL, 3MF, OBJ, STEP, GCODE, ZIP) into a searchable library — with in-browser 3D previews, collections, license/commercial-use tracking, and one-paste import from popular model sites.
Features
- Library of models, each owning one or more files; tags, collections, descriptions, print settings.
- Import from URL:
- Thingiverse — downloads files automatically via the official API (needs a free app token).
- Printables — downloads files automatically via its public GraphQL API (no auth needed for free models).
- MakerWorld — downloads files via FlareSolverr (solves Cloudflare) + your account token.
- cubee3d (Hive) and any other URL — imports title/description/preview image; you add the files manually.
- In-browser 3D viewer (Three.js) for STL/OBJ, and for 3MF via a server-side trimesh GLB conversion (handles Bambu/MakerWorld production-extension files the JS loader can't).
- Auto thumbnails rendered from the model; embedded 3MF thumbnails used when present.
- License & commercial-use tracking — captured per source, with a "sellable / non-commercial" indicator (a guide; verify before selling).
- Collections — group models (a model can be in many); rename/delete without losing models.
- Editing — rename/retag, edit print settings, override commercial-use, refresh metadata from source, re-download files, download all files as a zip.
- Notes — free-form notes per model, saved as you type.
- Search, filters & sorting — search across names, descriptions, notes, tags, file names and designers; filter by format, source and license; include or exclude tags (match any/all); sort and group by source or format. Press / to search.
- Duplicate finder — every file gets a SHA-256 content hash plus (for STL/OBJ/3MF) a geometry fingerprint, computed in the background. Models sharing files are grouped as exact copies or same shape (renamed, re-exported, converted — or mirrored, so check those), with a recommended copy to keep. Keeping one merges the others' tags, collections and notes into it and moves them to the trash; groups can be dismissed as "not duplicates".
- Trash — deleting moves a model to the trash; restore it, delete it forever, or empty the trash (only then are files removed from disk).
- Settings — API tokens / FlareSolverr URL stored in the database (with
.envfallback), secrets masked.
Tech stack
- Node.js + Express, vanilla-JS frontend (no build step), PostgreSQL.
- Three.js (viewer) via CDN import map.
- Python + trimesh sidecar for 3MF→GLB conversion, volume, and geometry fingerprints.
- Optional FlareSolverr for Cloudflare-protected sources.
Setup
- Postgres — create a database and point
DATABASE_URLat it. The schema is applied automatically on startup. - Python sidecar (for 3MF previews/volume and shape-based duplicate detection — without it, duplicates are still found by content hash):
python3 -m venv tools/venv tools/venv/bin/pip install trimesh numpy networkx lxml - Install deps and run:
npm install cp .env.example .env # set DATABASE_URL (+ optional tokens) npm start - Open http://localhost:3000
Run the unit tests with npm test.
Configuration
Settings live in the database (editable in the app's Settings menu) and fall back to environment variables:
| Setting | Env var | Purpose |
|---|---|---|
| Thingiverse API token | THINGIVERSE_TOKEN |
Thingiverse auto-download |
| FlareSolverr URL | FLARESOLVERR_URL |
Read Cloudflare-protected sites (MakerWorld) |
| MakerWorld auth token | MAKERWORLD_TOKEN |
MakerWorld downloads (bearer token from your session) |
| Printables auth token | PRINTABLES_TOKEN |
Optional; account-gated Printables files |
Notes
- Auto-download from MakerWorld/Printables relies on their private/session APIs and can break if they change; failed/partial imports can be recovered with "Download files from source".
- The commercial-use badge is a best-effort read of the license — always confirm on the source page before selling.