Move weather endpoints to the server with caching and rate-limiting. Prioritize
3D viewer renders over background thumbnails. Query featured models from database
instead of loading all into memory.
* feat: categorize models with an OpenAI-compatible AI provider
Models can now be sorted into the user's categories by any OpenAI-compatible
chat endpoint (llama.cpp, Ollama, vLLM, OpenAI, OpenRouter...), configured once
by an admin under settings: mode off/suggest/auto, confidence threshold,
categorize on import, concurrency, optional preview image.
Every print now records where its category came from (manual, site rule, AI,
or legacy for rows that predate this). AI never changes a manual choice: runs
and the import hook skip them, and a single-model request needs force. Folders
are never touched. Category changes go through one setPrintCategory path, so
the name check and file relocation stay shared, and AI writes are a
compare-and-set against what was read before the provider call, so an edit
made meanwhile wins.
Users get per-model recategorize, accept/reject of pending suggestions (a
rejected category is not offered again), and a background "recategorize all"
with scope flags, progress and cancel that stops after repeated provider
failures.
* feat: AI categorization settings, suggestions and bulk runs in the UI
Admin settings get an AI categorization section with a connection test and a
privacy note. The model menu offers "Recategorize with AI" (asking before it
overrides a manual category), the side panel shows a pending suggestion with
accept/reject and marks AI-set categories, and the models page has
"Recategorize all with AI" with scope, progress and cancel, plus a pending
suggestions list with bulk accept/reject.
* fix: keep suggestion actions from overlapping the reason
MUI's secondaryAction is absolutely positioned over a fixed padding, so the
two buttons covered a long reason. They now sit in the row, and wrap under
the text on narrow screens.
* fix: put the clear API key action inside the key field
A full-width outlined button under the field read as an empty input in an
error state. It is now a small action at the end of the field, and the
helper text says the key goes away on save once it's clicked.
* refactor: update AI categorization admin part
* refactor: move ai categorization buttons to categories manager modal
* fix: multiple smaller problems with AI categorization
---------
Co-authored-by: Tautvydas Derzinskas <tautvydasuk@gmail.com>
Search engines look for sitemap.xml by default, but @astrojs/sitemap
only generates sitemap-index.xml. Add a build hook to copy the index
file so search engines can find it.
- A MakerWorld CAPTCHA was reported as "No downloadable model file
found". The extension's real-click download looked for a "Download"
button that no longer exists in any language: the downloads sit in the
menu behind the arrow next to "Open in Bambu Studio". It now opens that
menu and clicks "Download 3MF", else "Download STL/CAD" then "Download
All" (a zip), matched in all 12 MakerWorld UI languages. A 418/CAPTCHA
reply is detected by both the extension and the backend, which now
answers 429 with a clear message instead of trying more endpoints.
- A CAPTCHA now pauses the guided import on the same model instead of
ending it. A docked panel leaves MakerWorld's puzzle reachable, and
Resume retries that model. A "Wait between models" choice (5 s to
5 min) paces long unattended runs; the countdown runs on the next
model's page, since the extension background is killed after 30 s idle.
- The collection scan stopped early (e.g. 40 of 56) on localized pages:
the end marker was English-only, so a 4 s no-new-cards timeout ended
the scan on any slow page load. It now stops at the collection's own
model count from the page data, knows the end marker in every
language, and keeps the timeout only as a long fallback.
- The guided import hung every few models with nginx logging 499s:
Chromium kills an extension service worker whose fetch() takes over
30 s to answer. POST /import?async=1 now returns a task id to poll at
GET /import/tasks/:id; an older instance ignores the flag and answers
as before.
- The overlay's "Import next" button was always visible instead of only
after a step looks stuck.
regression/screenshots.mjs signs in to any instance (--url, --email,
THINGPORT_PASSWORD) and captures the README and website screenshots at
1400x790 and 2x scale. The account's theme and Categories/Folders choice
are switched for the shots and restored afterwards.
- A links import with a profile scope counted print profiles against the
number of links ("Imported 11 of 3 links"). Each link now counts as one
model, and the profile totals go in the notification body.
- Opening a model while its import was still downloading images rendered a
3D thumbnail that then stuck as the card image and first gallery image.
Renders are now flagged, imported images replace them, and a late render
no longer overwrites an imported cover. "Update from source" treats a
model with only renders as having no images.
* feat: link queue with retries and update-from-source
Pasting several model links now imports them as one background queue
job (LINKS), one at a time, with an in-place retry for transient
failures and a retry button for whatever still fails. Failed links are
kept per item, so a retry reruns only those.
An imported model can also be refreshed from its source ("Update from
source" in the model menu, "Update model in Thingport" in the
extension). Only empty fields are filled, so an edit always wins and
tags are only added; missing files come in (for MakerWorld, the print
profiles the model doesn't hold yet) and an empty image slot is
filled.
* fix: show the import queue and log its execution
Feedback from testing a mixed batch: the provider chips only showed one
of the pasted links' providers (now every provider in the batch lights
up), the queue had no view while it ran, and the pod's logs said nothing
about what was importing.
The progress bar is now clickable and opens the queue as a list: one row
per link with its status (waiting/importing/imported/failed) and why it
failed. Items carry a RUNNING state so the current link is visible, and
a finished batch with failures shows up in warning colors instead of the
quiet bar. The runner logs each link and the job summary with an
[import] prefix, in the console style the rest of the backend uses.
* feat: admin import queue page with start, pause and retry
Links can now wait in a PAUSED LINKS job until someone starts them. The
new Administration > Import queue page lists every user's batch imports
and starts, pauses, retries and deletes link-list jobs as their owner,
with the owner's saved MakerWorld cookie. Start all and Retry all failed
run jobs one at a time across users, so a bulk run never bursts the
providers from one IP.
POST /import/queue parks one link in the user's paused queue with its
own collection, profile scope and title, keeping a single "N links
waiting" notification up to date. Pausing is cooperative: the runner
finishes the link it is on, then stops, and a job cut off by a restart
can be paused and started again to finish.
* feat(extension): send to queue toggle
A "Send to queue" switch under "Extension enabled" makes the single
model panel add the link to the instance's paused import queue instead
of importing it, keeping the panel's collection and print profile
choice. Choosing files out of a zip still imports directly, since it
needs the download right away.