Commit graph

16 commits

Author SHA1 Message Date
dlawler489
0df38c83c7 Watch a MakerWorld collection and import models added to it
A watch reads the collection page through FlareSolverr carrying your token, so
private collections work, and imports the models it hasn't seen into a Printhive
collection of the same name (optionally AI-tagging them). Checks run on your
chosen interval, a few models at a time with pauses between, and each design is
remembered so nothing is imported twice. A refused token stops the check and the
Watched page offers to update it; models removed on MakerWorld stay here.

The import endpoint's work moved into importFromUrl() so watches reuse it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 08:53:35 +10:00
dlawler489
4a88d66e90 Ask for a fresh MakerWorld token when MakerWorld refuses it, then retry
When a download fails because MakerWorld refused (or is missing) the auth
token, the error carries reason makerworld_token. The import and "Download
files from source" then open an "Update your MakerWorld token" prompt with
steps to copy the token cookie; saving it retries the download straight away
and says if MakerWorld still refuses it. A missing FlareSolverr URL is reported
separately, since a token alone won't help.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 18:33:10 +10:00
dlawler489
28a95ee330 Say why MakerWorld files didn't download instead of importing silently without them
MakerWorld answers an expired or missing auth token with {"error": "Please log
in to download models."} and no download link, which was skipped without a
word, so imports and "Download files from source" just ended with no files.
Now the reason comes back: missing settings, a refused token (probably expired),
no printable files on the page, or a failed download. The import screen shows
it, and the Settings hint explains where the token comes from.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 18:17:46 +10:00
dlawler489
2506f4dce9 Let AI runs give models with unclear names a clearer one, with undo
A run option asks the AI for a clearer name only when the current one is messy
(file-name leftovers, typos, site boilerplate). The previous name is kept, the
run feed shows what was renamed, and the model page offers Undo. Giving a model
a name yourself clears the undo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 15:26:29 +10:00
dlawler489
0f49fe8c1a AI tags and descriptions, search by meaning, and automatic tags
- AI tagging through any OpenAI-compatible API: DeepSeek by default, or
  OpenRouter, OpenAI, or a local server (Ollama, LM Studio). Settings → AI
  with presets, prices and "Save & test connection"; the key never leaves
  the server except to the provider.
- Runs over untagged models, all models, or one model from its page: live
  progress, tokens and cost, stop/resume (retrying failures), an optional
  spending limit, and paused rather than resumed after a restart. Adapts to
  models without JSON mode or image input; stops on a rejected key or no
  credit. Tags are only added; descriptions filled only where empty unless
  asked.
- Search by meaning: local bge-small-en-v1.5 embeddings (transformers.js),
  indexed in the background whenever a model's text changes; Words/Meaning
  switch on the search box. Stored as REAL[] in Postgres, no pgvector needed.
- Automatic tags: strict whole-word rules (part types, mechanisms, materials,
  techniques) over names, file names and archive contents, plus your own
  word -> tag rules; on/off (optionally removing its tags) and re-apply.
- Tags remember where they came from (user / rule / ai); edits keep that,
  rule and AI passes never touch your own tags, and the model page marks them.
- Docker: ships the embedding model and only Linux onnxruntime binaries.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 11:12:58 +10:00
dlawler489
be1facdec3 Drag out from file tabs, plate chips and a Drag out handle; only offer dragging in Chromium browsers
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 10:26:48 +10:00
dlawler489
f3a69c82ec Open models in your slicer and drag files out
- Settings → Slicer: pick Bambu Studio, OrcaSlicer, PrusaSlicer, Cura, a
  custom open-link template, or plain download (remembered per browser)
- Bambu Studio / OrcaSlicer launch via their URL schemes with a 10-minute
  signed download link (/dl/<token>/<name>) that needs no session cookie
- PrusaSlicer and Cura fall back to a download (they can't open our links)
- 3MF projects report which app saved them; opening one in a different
  slicer asks first
- "slicer" action on every file row and archive entry
- Drag model cards (file, or zip of all files) and file/entry rows out to
  the desktop via Chromium's DownloadURL

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 09:15:37 +10:00
dlawler489
fcb418f119 Show 3MF projects plate by plate in their filament colours
- threemf_stream reads Bambu Studio / OrcaSlicer project metadata: plates
  (name, objects, preview images), filaments, and each part's type and
  extruder. Placements now record which build item and part they belong to.
- convert_3mf.py leaves out negative/modifier/support parts, colours each
  part by its filament (a part's extruder 0 falls back to its object's), and
  takes --plate N. Geometry is still stored once per (part, colour).
- New threemf_info.py lists plates and filaments without loading geometry
  and extracts plate preview images; served via /api/{files,entries}/:id/project.
- /glb?plate=N builds and caches a per-plate preview. Cached GLB names carry
  a converter version, so previews made before colours are rebuilt.
- Model detail: plate chips (with the slicer's plate images) under the
  viewer — multi-plate projects open on plate 1 — plus "All plates", and a
  Filaments section with colour swatches.
- Fingerprints leave out negative/modifier parts, so a project matches the
  model it prints.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 07:49:58 +10:00
dlawler489
d4b7e29348 Browse archives, preview companion files, and view FBX/STEP/3DM/OBJ+MTL
Archives
- ZIP, 7Z, RAR and TAR/.tar.gz uploads are indexed in the background into
  archive_entries (7-Zip compiled to WASM in a worker thread; node-tar for
  tar). macOS/Windows clutter and paths that could escape the extraction
  folder are skipped.
- Models inside archives are extracted once per archive to hash and
  geometry-fingerprint them, so duplicates are found inside packs too.
  Pictures, PDFs and readmes are listed but never matched.
- New routes list an archive's entries and serve/convert a single entry,
  extracted on first use and cached under extracted/.

Viewer
- Model detail lists what's inside each archive with view/download links;
  opening an entry adds a viewer tab.
- New 3D formats: FBX (with sibling textures), OBJ with its MTL and
  textures, STEP/STP via occt-import-js, and Rhino 3DM via rhino3dm — the
  WASM readers are served from node_modules, loaded on first use.
- Pictures, PDFs and text files (jpg/png/gif/webp/bmp/svg, pdf, txt/md)
  can be uploaded and preview in the viewer; a model without an embedded
  3MF preview uses its first picture as the card thumbnail.
- Inline file responses send nosniff, and SVGs are sandboxed.
- GLB conversions write to a temp file and rename, so a half-written
  preview is never served; a later tab can't be overdrawn by a slow load.
- Better 3MF card image: the project thumbnail or plate 1 render, not a
  slicer pick map.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 07:36:47 +10:00
dlawler489
00a4b4ba07 Add duplicate finder, trash, notes, and library search/filters
- Fingerprint every file in the background: SHA-256 for all formats plus a
  trimesh geometry fingerprint for STL/OBJ/3MF, so renamed, re-exported or
  converted copies are still matched. Backfills existing files on startup.
- Duplicates view groups models that share files (exact copies vs same
  shape), recommends which to keep, merges tags/collections/notes into the
  kept model and trashes the rest; groups can be dismissed.
- Deleting now moves models to a restorable trash; files are only removed
  from disk on permanent delete or when the trash is emptied.
- Per-model notes with autosave.
- Search across names, notes, tags, files and designers; filter by format,
  source and license; include/exclude tags with any/all matching; sort and
  group by source or format. Preferences persist per browser.
- Add node:test unit tests for duplicate grouping and fingerprints.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:06:09 +10:00
dlawler489
e141d800c2 Add SVG favicon (hexagon mark)
All checks were successful
build-and-push / docker (push) Successful in 29s
Brand hexagon in amber on the dark graphite, linked as the icon +
apple-touch-icon, plus a theme-color meta.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 13:35:57 +10:00
dlawler489
a2e08ecd03 License rules are the source of truth for sellability
All checks were successful
build-and-push / docker (push) Successful in 28s
- Changing a license policy applies to all models with that license, and
  opening Settings reconciles old imports to current rules (store.reconcileModelsToRules)
- Editing a model's license re-resolves its sellability from the rule
- Removed the per-model commercial-use override (set by license now)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 11:33:38 +10:00
dlawler489
2768a71c63 Add per-license commercial-use rules (settings + auto-register)
- license_rules table (name -> commercial); licenses auto-register on
  import with a best-effort seed, overridable in Settings (applies the
  choice to every model with that license)
- resolveCommercial() replaces ad-hoc inferCommercial across import/refresh
- GET/PUT /api/licenses; "License types" section in Settings
- Fix CC short codes: BY / BY-SA / BY-ND now classed sellable (MakerWorld
  stores e.g. "BY-SA"); NC variants stay non-commercial

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 10:20:28 +10:00
dlawler489
5af88eb5ce Add email/password auth + SMTP password resets
All checks were successful
build-and-push / docker (push) Successful in 29s
- users + password_resets tables; bcrypt hashing; JWT session in an
  httpOnly cookie (auth_secret auto-generated in settings)
- /api gated behind auth (except /api/config and /api/auth/*)
- First-run creates the account (no open registration after that);
  login, logout, forgot/reset-password flows
- SMTP settings (host/port/secure/user/pass/from) in Settings menu;
  nodemailer sends reset links
- Auth screen (sign in / create account / forgot / reset) gates the SPA;
  Sign out button; COOKIE_SECURE=true in compose for HTTPS

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 22:33:11 +10:00
dlawler489
5fb3939bcd Add first-run setup wizard for import sources
All checks were successful
build-and-push / docker (push) Successful in 11s
On a fresh install (no integration settings yet), prompt once for the
Thingiverse/MakerWorld/Printables tokens and FlareSolverr URL, with a
"skip for now" option. /api/config exposes setupComplete (true if any
setting is configured or setup was dismissed); POST /api/setup/complete
records dismissal. DB password stays a deploy-time env var by necessity.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:35:18 +10:00
dlawler489
a37db15a3f Initial commit: Printhive 3D-print file library
Self-hosted Express + Postgres app for organizing STL/3MF/OBJ/etc. with:
- Model/file library, tags, collections, print settings
- URL import: Thingiverse (API), Printables (GraphQL), MakerWorld
  (FlareSolverr + token), cubee3d/other (metadata + manual files)
- In-browser 3D viewer; 3MF rendered via Python/trimesh GLB conversion
- Auto thumbnails, license/commercial-use tracking, in-app editing
- Settings (API tokens / FlareSolverr) stored in DB with .env fallback

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 13:15:17 +10:00