printhive/test/makerworld.test.js
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

66 lines
3.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// MakerWorld importer helpers (lib/importers/makerworld.js).
const test = require('node:test');
const assert = require('node:assert/strict');
const makerworld = require('../lib/importers/makerworld');
const page = (design) =>
`<html><script id="__NEXT_DATA__" type="application/json">${JSON.stringify({ props: { pageProps: { design } } })}</script></html>`;
test('printable instances and the license are read from the page data', () => {
const html = page({
license: 'Standard Digital File License',
instances: [{ id: 650088, title: 'AMS - 0.4 Nozzle - 0.08 Layer' }, { id: 650089 }],
});
assert.deepEqual(makerworld.parseInstances(html), [
{ id: 650088, title: 'AMS - 0.4 Nozzle - 0.08 Layer' },
{ id: 650089, title: '' },
]);
assert.equal(makerworld.parseLicense(html), 'Standard Digital File License');
assert.deepEqual(makerworld.parseInstances('<html><title>Just a moment...</title></html>'), []);
});
test('a download answer without a link says why, and flags a refused token', () => {
assert.equal(makerworld.downloadProblem({ name: 'bookmarks.3mf', url: 'https://cdn.example/bookmarks.3mf' }), null);
const refused = makerworld.downloadProblem({ code: 1, error: 'Please log in to download models.' });
assert.equal(refused.tokenRejected, true);
assert.match(refused.message, /token \(it has probably expired\)/);
assert.deepEqual(makerworld.downloadProblem({ code: 7, error: 'Model not found' }),
{ message: 'MakerWorld didn’t give a download link: Model not found', tokenRejected: false });
assert.deepEqual(makerworld.downloadProblem(null), { message: 'MakerWorld didn’t give a download link', tokenRejected: false });
});
const collectionPage = (favorite, favoriteDesigns) =>
`<html><script id="__NEXT_DATA__" type="application/json">${JSON.stringify({ props: { pageProps: { favorite, favoriteDesigns } } })}</script></html>`;
test('a collection page gives its models, name and total', () => {
const html = collectionPage(
{ id: 31103374, title: 'markets', designCnt: 3 },
{ total: 3, hits: [
{ id: 719274, slug: 'skeleton-bookmarks', title: 'Skeleton Bookmarks' },
{ id: 926432, slug: 'doomhammer', title: 'Doomhammer' },
{ id: 12345, title: 'No slug' },
] });
const collection = makerworld.parseCollection(html);
assert.equal(collection.id, '31103374');
assert.equal(collection.title, 'markets');
assert.equal(collection.total, 3);
assert.deepEqual(collection.designs.map((d) => d.id), ['719274', '926432', '12345']);
assert.equal(makerworld.designUrl(collection.designs[0]), 'https://makerworld.com/en/models/719274-skeleton-bookmarks');
assert.equal(makerworld.designUrl(collection.designs[2]), 'https://makerworld.com/en/models/12345');
// The page can hold fewer models than the collection does.
const partial = makerworld.parseCollection(collectionPage({ id: 1, title: 'big', designCnt: 120 }, { total: 120, hits: [{ id: 5, slug: 'a', title: 'A' }] }));
assert.equal(partial.total, 120);
assert.equal(partial.designs.length, 1);
});
test('a page without a collection (private, or Cloudflare) parses as nothing', () => {
assert.equal(makerworld.parseCollection('<html><title>Just a moment...</title></html>'), null);
assert.equal(makerworld.parseCollection(collectionPage(null, null)), null);
});
test('collection links are recognised', () => {
assert.equal(makerworld.collectionIdFromUrl('https://makerworld.com/en/collections/31103374-markets'), '31103374');
assert.equal(makerworld.collectionIdFromUrl('https://makerworld.com/collections/31103374'), '31103374');
assert.equal(makerworld.collectionIdFromUrl('https://makerworld.com/en/models/719274-skeleton-bookmarks'), null);
});