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>
66 lines
3.6 KiB
JavaScript
66 lines
3.6 KiB
JavaScript
// 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);
|
||
});
|